xref: /AOO41X/main/sc/source/ui/Accessibility/AccessiblePageHeader.cxx (revision b3f79822e811ac3493b185030a72c3c5a51f32d8)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26 
27 #include "AccessiblePageHeader.hxx"
28 #include "AccessiblePageHeaderArea.hxx"
29 #include "AccessibilityHints.hxx"
30 #include "prevwsh.hxx"
31 #include "unoguard.hxx"
32 #include "miscuno.hxx"
33 #include "prevloc.hxx"
34 #include "document.hxx"
35 #include "stlpool.hxx"
36 #include "scitems.hxx"
37 #include "attrib.hxx"
38 #include "scresid.hxx"
39 #ifndef SC_SC_HRC
40 #include "sc.hrc"
41 #endif
42 
43 #include <com/sun/star/accessibility/AccessibleRole.hpp>
44 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
45 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
46 
47 #include <vcl/window.hxx>
48 #include <svl/smplhint.hxx>
49 #include <unotools/accessiblestatesethelper.hxx>
50 #include <svl/style.hxx>
51 #include <svl/itempool.hxx>
52 #include <editeng/editobj.hxx>
53 #include <toolkit/helper/convert.hxx>
54 
55 #include <algorithm>
56 
57 using namespace ::com::sun::star;
58 using namespace ::com::sun::star::accessibility;
59 
60 const sal_uInt8     MAX_AREAS = 3;
61 
62 //=====  internal  ============================================================
63 struct Acquire
64 {
operator ()Acquire65     void operator() (ScAccessiblePageHeaderArea* pArea)
66     {
67         if (pArea)
68             pArea->acquire();
69     }
70 };
71 
72 struct Release
73 {
operator ()Release74     void operator() (ScAccessiblePageHeaderArea*& pArea)
75     {
76         if (pArea)
77             pArea->release();
78     }
79 };
80 
81 struct Dispose
82 {
operator ()Dispose83     void operator() (ScAccessiblePageHeaderArea*& pArea)
84     {
85         if (pArea)
86         {
87             pArea->dispose();
88             pArea->release();
89         }
90         pArea = NULL;
91     }
92 };
93 
ScAccessiblePageHeader(const::com::sun::star::uno::Reference<::com::sun::star::accessibility::XAccessible> & rxParent,ScPreviewShell * pViewShell,sal_Bool bHeader,sal_Int32 nIndex)94 ScAccessiblePageHeader::ScAccessiblePageHeader( const ::com::sun::star::uno::Reference<
95                                 ::com::sun::star::accessibility::XAccessible>& rxParent,
96                             ScPreviewShell* pViewShell, sal_Bool bHeader, sal_Int32 nIndex ) :
97 ScAccessibleContextBase( rxParent, bHeader ? AccessibleRole::HEADER : AccessibleRole::FOOTER ),
98     mpViewShell( pViewShell ),
99     mnIndex( nIndex ),
100     mbHeader( bHeader ),
101     maAreas(MAX_AREAS, NULL),
102     mnChildCount(-1)
103 {
104     if (mpViewShell)
105         mpViewShell->AddAccessibilityObject(*this);
106 }
107 
~ScAccessiblePageHeader()108 ScAccessiblePageHeader::~ScAccessiblePageHeader()
109 {
110     if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose)
111     {
112         // increment refcount to prevent double call off dtor
113         osl_incrementInterlockedCount( &m_refCount );
114         dispose();
115     }
116 }
117 
disposing()118 void SAL_CALL ScAccessiblePageHeader::disposing()
119 {
120     ScUnoGuard aGuard;
121     if (mpViewShell)
122     {
123         mpViewShell->RemoveAccessibilityObject(*this);
124         mpViewShell = NULL;
125     }
126     std::for_each(maAreas.begin(), maAreas.end(), Dispose());
127 
128     ScAccessibleContextBase::disposing();
129 }
130 
131 //=====  SfxListener  =====================================================
132 
Notify(SfxBroadcaster & rBC,const SfxHint & rHint)133 void ScAccessiblePageHeader::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
134 {
135     if (rHint.ISA( SfxSimpleHint ) )
136     {
137         const SfxSimpleHint& rRef = (const SfxSimpleHint&)rHint;
138         // only notify if child exist, otherwise it is not necessary
139         if ((rRef.GetId() == SC_HINT_DATACHANGED))
140         {
141             ScHFAreas aOldAreas(maAreas);
142             std::for_each(aOldAreas.begin(), aOldAreas.end(), Acquire());
143             mnChildCount = -1;
144             getAccessibleChildCount();
145             for (sal_uInt8 i = 0; i < MAX_AREAS; ++i)
146             {
147                 if ((aOldAreas[i] && maAreas[i] && !ScGlobal::EETextObjEqual(aOldAreas[i]->GetEditTextObject(), maAreas[i]->GetEditTextObject())) ||
148                     (aOldAreas[i] && !maAreas[i]) || (!aOldAreas[i] && maAreas[i]))
149                 {
150                     if (aOldAreas[i] && aOldAreas[i]->GetEditTextObject())
151                     {
152                         AccessibleEventObject aEvent;
153                         aEvent.EventId = AccessibleEventId::CHILD;
154                         aEvent.Source = uno::Reference< XAccessibleContext >(this);
155                         aEvent.OldValue = uno::makeAny(uno::Reference<XAccessible>(aOldAreas[i]));
156 
157                         CommitChange(aEvent); // child gone - event
158                         aOldAreas[i]->dispose();
159                     }
160                     if (maAreas[i] && maAreas[i]->GetEditTextObject())
161                     {
162                         AccessibleEventObject aEvent;
163                         aEvent.EventId = AccessibleEventId::CHILD;
164                         aEvent.Source = uno::Reference< XAccessibleContext >(this);
165                         aEvent.NewValue = uno::makeAny(uno::Reference<XAccessible>(maAreas[i]));
166 
167                         CommitChange(aEvent); // new child - event
168                     }
169                 }
170             }
171             std::for_each(aOldAreas.begin(), aOldAreas.end(), Release());
172         }
173         else if (rRef.GetId() == SC_HINT_ACC_VISAREACHANGED)
174         {
175             AccessibleEventObject aEvent;
176             aEvent.EventId = AccessibleEventId::VISIBLE_DATA_CHANGED;
177             aEvent.Source = uno::Reference< XAccessibleContext >(this);
178             CommitChange(aEvent);
179         }
180     }
181 
182     ScAccessibleContextBase::Notify(rBC, rHint);
183 }
184 
185 //=====  XAccessibleComponent  ============================================
186 
getAccessibleAtPoint(const awt::Point & aPoint)187 uno::Reference< XAccessible > SAL_CALL ScAccessiblePageHeader::getAccessibleAtPoint( const awt::Point& aPoint )
188                                 throw (uno::RuntimeException)
189 {
190     uno::Reference<XAccessible> xRet;
191 
192     if (containsPoint(aPoint))
193     {
194         ScUnoGuard aGuard;
195         IsObjectValid();
196 
197         sal_Int32 nCount(getAccessibleChildCount()); // fill the areas
198 
199         if (nCount)
200         {
201             // return the first with content, because they have all the same Bounding Box
202             sal_uInt8 i(0);
203             while(!xRet.is() && i < MAX_AREAS)
204             {
205                 if (maAreas[i])
206                     xRet = maAreas[i];
207                 else
208                     ++i;
209             }
210         }
211     }
212 
213     return xRet;
214 }
215 
grabFocus()216 void SAL_CALL ScAccessiblePageHeader::grabFocus() throw (uno::RuntimeException)
217 {
218     ScUnoGuard aGuard;
219     IsObjectValid();
220     if (getAccessibleParent().is())
221     {
222         uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY);
223         if (xAccessibleComponent.is())
224             xAccessibleComponent->grabFocus();
225     }
226 }
227 
228 //=====  XAccessibleContext  ==============================================
229 
getAccessibleChildCount()230 sal_Int32 SAL_CALL ScAccessiblePageHeader::getAccessibleChildCount() throw (uno::RuntimeException)
231 {
232     ScUnoGuard aGuard;
233     IsObjectValid();
234 
235     if((mnChildCount < 0) && mpViewShell)
236     {
237         mnChildCount = 0;
238         ScDocument* pDoc = mpViewShell->GetDocument();
239         if (pDoc)
240         {
241             // find out how many regions (left,center, right) are with content
242 
243             SfxStyleSheetBase* pStyle = pDoc->GetStyleSheetPool()->Find(pDoc->GetPageStyle(mpViewShell->GetLocationData().GetPrintTab()), SFX_STYLE_FAMILY_PAGE);
244             if (pStyle)
245             {
246                 sal_uInt16 nPageWhichId(0);
247                 if (mbHeader)
248                     nPageWhichId = mpViewShell->GetLocationData().IsHeaderLeft() ? ATTR_PAGE_HEADERLEFT : ATTR_PAGE_HEADERRIGHT;
249                 else
250                     nPageWhichId = mpViewShell->GetLocationData().IsFooterLeft() ? ATTR_PAGE_FOOTERLEFT : ATTR_PAGE_FOOTERRIGHT;
251 
252                 const ScPageHFItem& rPageItem = static_cast<const ScPageHFItem&>(pStyle->GetItemSet().Get(nPageWhichId));
253                 AddChild(rPageItem.GetLeftArea(), 0, SVX_ADJUST_LEFT);
254                 AddChild(rPageItem.GetCenterArea(), 1, SVX_ADJUST_CENTER);
255                 AddChild(rPageItem.GetRightArea(), 2, SVX_ADJUST_RIGHT);
256             }
257         }
258     }
259 
260     return mnChildCount;
261 }
262 
getAccessibleChild(sal_Int32 nIndex)263 uno::Reference< XAccessible > SAL_CALL ScAccessiblePageHeader::getAccessibleChild( sal_Int32 nIndex )
264                                 throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
265 {
266     ScUnoGuard aGuard;
267     IsObjectValid();
268 
269     uno::Reference<XAccessible> xRet;
270 
271     if(mnChildCount < 0)
272         getAccessibleChildCount();
273 
274     ScHFAreas::iterator aItr = maAreas.begin();
275     ScHFAreas::iterator aEndItr = maAreas.end();
276     while (!xRet.is() && (nIndex >= 0) && (aItr != aEndItr))
277     {
278         if (*aItr)
279         {
280             if (nIndex == 0)
281                 xRet = *aItr;
282             else
283                 --nIndex;
284         }
285         else
286             ++aItr;
287     }
288 
289     if ( !xRet.is() )
290         throw lang::IndexOutOfBoundsException();
291 
292     return xRet;
293 }
294 
getAccessibleIndexInParent()295 sal_Int32 SAL_CALL ScAccessiblePageHeader::getAccessibleIndexInParent() throw (uno::RuntimeException)
296 {
297     return mnIndex;
298 }
299 
getAccessibleStateSet()300 uno::Reference< XAccessibleStateSet > SAL_CALL ScAccessiblePageHeader::getAccessibleStateSet()
301                                 throw (uno::RuntimeException)
302 {
303     ScUnoGuard aGuard;
304     uno::Reference<XAccessibleStateSet> xParentStates;
305     if (getAccessibleParent().is())
306     {
307         uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
308         xParentStates = xParentContext->getAccessibleStateSet();
309     }
310     utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper();
311     if (IsDefunc(xParentStates))
312         pStateSet->AddState(AccessibleStateType::DEFUNC);
313     else
314     {
315         pStateSet->AddState(AccessibleStateType::ENABLED);
316         pStateSet->AddState(AccessibleStateType::OPAQUE);
317         if (isShowing())
318             pStateSet->AddState(AccessibleStateType::SHOWING);
319         if (isVisible())
320             pStateSet->AddState(AccessibleStateType::VISIBLE);
321     }
322     return pStateSet;
323 }
324 
325 //=====  XServiceInfo  ====================================================
326 
getImplementationName()327 rtl::OUString SAL_CALL ScAccessiblePageHeader::getImplementationName() throw(uno::RuntimeException)
328 {
329     return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ScAccessiblePageHeader"));
330 }
331 
getSupportedServiceNames()332 uno::Sequence<rtl::OUString> SAL_CALL ScAccessiblePageHeader::getSupportedServiceNames()
333                                                     throw(uno::RuntimeException)
334 {
335     uno::Sequence< ::rtl::OUString > aSequence = ScAccessibleContextBase::getSupportedServiceNames();
336     sal_Int32 nOldSize(aSequence.getLength());
337     aSequence.realloc(nOldSize + 1);
338     ::rtl::OUString* pNames = aSequence.getArray();
339 
340     pNames[nOldSize] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.AccessibleHeaderFooterView"));
341 
342     return aSequence;
343 }
344 
345 //====  internal  =========================================================
346 
createAccessibleDescription(void)347 ::rtl::OUString SAL_CALL ScAccessiblePageHeader::createAccessibleDescription(void)
348                     throw (uno::RuntimeException)
349 {
350     String sDesc(ScResId(mbHeader ? STR_ACC_HEADER_DESCR : STR_ACC_FOOTER_DESCR));
351     sDesc.SearchAndReplaceAscii("%1", String(ScResId(SCSTR_UNKNOWN)));
352     return rtl::OUString( sDesc );
353 }
354 
createAccessibleName(void)355 ::rtl::OUString SAL_CALL ScAccessiblePageHeader::createAccessibleName(void)
356                     throw (uno::RuntimeException)
357 {
358     String sName(ScResId(mbHeader ? STR_ACC_HEADER_NAME : STR_ACC_FOOTER_NAME));
359     sName.SearchAndReplaceAscii("%1", String(ScResId(SCSTR_UNKNOWN)));
360     return rtl::OUString( sName );
361 }
362 
GetBoundingBoxOnScreen() const363 Rectangle ScAccessiblePageHeader::GetBoundingBoxOnScreen() const throw (uno::RuntimeException)
364 {
365     Rectangle aCellRect(GetBoundingBox());
366     if (mpViewShell)
367     {
368         Window* pWindow = mpViewShell->GetWindow();
369         if (pWindow)
370         {
371             Rectangle aRect = pWindow->GetWindowExtentsRelative(NULL);
372             aCellRect.setX(aCellRect.getX() + aRect.getX());
373             aCellRect.setY(aCellRect.getY() + aRect.getY());
374         }
375     }
376     return aCellRect;
377 }
378 
GetBoundingBox() const379 Rectangle ScAccessiblePageHeader::GetBoundingBox() const throw (uno::RuntimeException)
380 {
381     Rectangle aRect;
382     if (mpViewShell)
383     {
384         const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
385         if ( mbHeader )
386             rData.GetHeaderPosition( aRect );
387         else
388             rData.GetFooterPosition( aRect );
389 
390         // the Rectangle could contain negative coordinates so it should be cliped
391         Rectangle aClipRect(Point(0, 0), aRect.GetSize());
392         Window* pWindow = mpViewShell->GetWindow();
393         if (pWindow)
394             aClipRect = pWindow->GetWindowExtentsRelative(pWindow->GetAccessibleParentWindow());
395         aRect = aClipRect.GetIntersection(aRect);
396     }
397     if (aRect.IsEmpty())
398         aRect.SetSize(Size(-1, -1));
399 
400     return aRect;
401 }
402 
IsDefunc(const uno::Reference<XAccessibleStateSet> & rxParentStates)403 sal_Bool ScAccessiblePageHeader::IsDefunc( const uno::Reference<XAccessibleStateSet>& rxParentStates )
404 {
405     return ScAccessibleContextBase::IsDefunc() || (mpViewShell == NULL) || !getAccessibleParent().is() ||
406         (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC));
407 }
408 
AddChild(const EditTextObject * pArea,sal_uInt32 nIndex,SvxAdjust eAdjust)409 void ScAccessiblePageHeader::AddChild(const EditTextObject* pArea, sal_uInt32 nIndex, SvxAdjust eAdjust)
410 {
411     if (pArea && (pArea->GetText(0).Len() || (pArea->GetParagraphCount() > 1)))
412     {
413         if (maAreas[nIndex])
414         {
415             if (!ScGlobal::EETextObjEqual(maAreas[nIndex]->GetEditTextObject(), pArea))
416             {
417                 maAreas[nIndex]->release();
418                 maAreas[nIndex] = new ScAccessiblePageHeaderArea(this, mpViewShell, pArea, mbHeader, eAdjust);
419                 maAreas[nIndex]->acquire();
420             }
421         }
422         else
423         {
424             maAreas[nIndex] = new ScAccessiblePageHeaderArea(this, mpViewShell, pArea, mbHeader, eAdjust);
425             maAreas[nIndex]->acquire();
426         }
427         ++mnChildCount;
428     }
429     else
430     {
431         if (maAreas[nIndex])
432         {
433             maAreas[nIndex]->release();
434             maAreas[nIndex] = NULL;
435         }
436     }
437 }
438