xref: /trunk/main/sc/source/ui/Accessibility/AccessiblePageHeader.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 {
189     uno::Reference<XAccessible> xRet;
190 
191     if (containsPoint(aPoint))
192     {
193         ScUnoGuard aGuard;
194         IsObjectValid();
195 
196         sal_Int32 nCount(getAccessibleChildCount()); // fill the areas
197 
198         if (nCount)
199         {
200             // return the first with content, because they have all the same Bounding Box
201             sal_uInt8 i(0);
202             while(!xRet.is() && i < MAX_AREAS)
203             {
204                 if (maAreas[i])
205                     xRet = maAreas[i];
206                 else
207                     ++i;
208             }
209         }
210     }
211 
212     return xRet;
213 }
214 
grabFocus()215 void SAL_CALL ScAccessiblePageHeader::grabFocus()
216 {
217     ScUnoGuard aGuard;
218     IsObjectValid();
219     if (getAccessibleParent().is())
220     {
221         uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY);
222         if (xAccessibleComponent.is())
223             xAccessibleComponent->grabFocus();
224     }
225 }
226 
227 //=====  XAccessibleContext  ==============================================
228 
getAccessibleChildCount()229 sal_Int32 SAL_CALL ScAccessiblePageHeader::getAccessibleChildCount()
230 {
231     ScUnoGuard aGuard;
232     IsObjectValid();
233 
234     if((mnChildCount < 0) && mpViewShell)
235     {
236         mnChildCount = 0;
237         ScDocument* pDoc = mpViewShell->GetDocument();
238         if (pDoc)
239         {
240             // find out how many regions (left,center, right) are with content
241 
242             SfxStyleSheetBase* pStyle = pDoc->GetStyleSheetPool()->Find(pDoc->GetPageStyle(mpViewShell->GetLocationData().GetPrintTab()), SFX_STYLE_FAMILY_PAGE);
243             if (pStyle)
244             {
245                 sal_uInt16 nPageWhichId(0);
246                 if (mbHeader)
247                     nPageWhichId = mpViewShell->GetLocationData().IsHeaderLeft() ? ATTR_PAGE_HEADERLEFT : ATTR_PAGE_HEADERRIGHT;
248                 else
249                     nPageWhichId = mpViewShell->GetLocationData().IsFooterLeft() ? ATTR_PAGE_FOOTERLEFT : ATTR_PAGE_FOOTERRIGHT;
250 
251                 const ScPageHFItem& rPageItem = static_cast<const ScPageHFItem&>(pStyle->GetItemSet().Get(nPageWhichId));
252                 AddChild(rPageItem.GetLeftArea(), 0, SVX_ADJUST_LEFT);
253                 AddChild(rPageItem.GetCenterArea(), 1, SVX_ADJUST_CENTER);
254                 AddChild(rPageItem.GetRightArea(), 2, SVX_ADJUST_RIGHT);
255             }
256         }
257     }
258 
259     return mnChildCount;
260 }
261 
getAccessibleChild(sal_Int32 nIndex)262 uno::Reference< XAccessible > SAL_CALL ScAccessiblePageHeader::getAccessibleChild( sal_Int32 nIndex )
263 {
264     ScUnoGuard aGuard;
265     IsObjectValid();
266 
267     uno::Reference<XAccessible> xRet;
268 
269     if(mnChildCount < 0)
270         getAccessibleChildCount();
271 
272     ScHFAreas::iterator aItr = maAreas.begin();
273     ScHFAreas::iterator aEndItr = maAreas.end();
274     while (!xRet.is() && (nIndex >= 0) && (aItr != aEndItr))
275     {
276         if (*aItr)
277         {
278             if (nIndex == 0)
279                 xRet = *aItr;
280             else
281                 --nIndex;
282         }
283         else
284             ++aItr;
285     }
286 
287     if ( !xRet.is() )
288         throw lang::IndexOutOfBoundsException();
289 
290     return xRet;
291 }
292 
getAccessibleIndexInParent()293 sal_Int32 SAL_CALL ScAccessiblePageHeader::getAccessibleIndexInParent()
294 {
295     return mnIndex;
296 }
297 
getAccessibleStateSet()298 uno::Reference< XAccessibleStateSet > SAL_CALL ScAccessiblePageHeader::getAccessibleStateSet()
299 {
300     ScUnoGuard aGuard;
301     uno::Reference<XAccessibleStateSet> xParentStates;
302     if (getAccessibleParent().is())
303     {
304         uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
305         xParentStates = xParentContext->getAccessibleStateSet();
306     }
307     utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper();
308     if (IsDefunc(xParentStates))
309         pStateSet->AddState(AccessibleStateType::DEFUNC);
310     else
311     {
312         pStateSet->AddState(AccessibleStateType::ENABLED);
313         pStateSet->AddState(AccessibleStateType::OPAQUE);
314         if (isShowing())
315             pStateSet->AddState(AccessibleStateType::SHOWING);
316         if (isVisible())
317             pStateSet->AddState(AccessibleStateType::VISIBLE);
318     }
319     return pStateSet;
320 }
321 
322 //=====  XServiceInfo  ====================================================
323 
getImplementationName()324 rtl::OUString SAL_CALL ScAccessiblePageHeader::getImplementationName()
325 {
326     return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ScAccessiblePageHeader"));
327 }
328 
getSupportedServiceNames()329 uno::Sequence<rtl::OUString> SAL_CALL ScAccessiblePageHeader::getSupportedServiceNames()
330 {
331     uno::Sequence< ::rtl::OUString > aSequence = ScAccessibleContextBase::getSupportedServiceNames();
332     sal_Int32 nOldSize(aSequence.getLength());
333     aSequence.realloc(nOldSize + 1);
334     ::rtl::OUString* pNames = aSequence.getArray();
335 
336     pNames[nOldSize] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.AccessibleHeaderFooterView"));
337 
338     return aSequence;
339 }
340 
341 //====  internal  =========================================================
342 
createAccessibleDescription(void)343 ::rtl::OUString SAL_CALL ScAccessiblePageHeader::createAccessibleDescription(void)
344 {
345     String sDesc(ScResId(mbHeader ? STR_ACC_HEADER_DESCR : STR_ACC_FOOTER_DESCR));
346     sDesc.SearchAndReplaceAscii("%1", String(ScResId(SCSTR_UNKNOWN)));
347     return rtl::OUString( sDesc );
348 }
349 
createAccessibleName(void)350 ::rtl::OUString SAL_CALL ScAccessiblePageHeader::createAccessibleName(void)
351 {
352     String sName(ScResId(mbHeader ? STR_ACC_HEADER_NAME : STR_ACC_FOOTER_NAME));
353     sName.SearchAndReplaceAscii("%1", String(ScResId(SCSTR_UNKNOWN)));
354     return rtl::OUString( sName );
355 }
356 
GetBoundingBoxOnScreen() const357 Rectangle ScAccessiblePageHeader::GetBoundingBoxOnScreen() const
358 {
359     Rectangle aCellRect(GetBoundingBox());
360     if (mpViewShell)
361     {
362         Window* pWindow = mpViewShell->GetWindow();
363         if (pWindow)
364         {
365             Rectangle aRect = pWindow->GetWindowExtentsRelative(NULL);
366             aCellRect.setX(aCellRect.getX() + aRect.getX());
367             aCellRect.setY(aCellRect.getY() + aRect.getY());
368         }
369     }
370     return aCellRect;
371 }
372 
GetBoundingBox() const373 Rectangle ScAccessiblePageHeader::GetBoundingBox() const
374 {
375     Rectangle aRect;
376     if (mpViewShell)
377     {
378         const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
379         if ( mbHeader )
380             rData.GetHeaderPosition( aRect );
381         else
382             rData.GetFooterPosition( aRect );
383 
384         // the Rectangle could contain negative coordinates so it should be cliped
385         Rectangle aClipRect(Point(0, 0), aRect.GetSize());
386         Window* pWindow = mpViewShell->GetWindow();
387         if (pWindow)
388             aClipRect = pWindow->GetWindowExtentsRelative(pWindow->GetAccessibleParentWindow());
389         aRect = aClipRect.GetIntersection(aRect);
390     }
391     if (aRect.IsEmpty())
392         aRect.SetSize(Size(-1, -1));
393 
394     return aRect;
395 }
396 
IsDefunc(const uno::Reference<XAccessibleStateSet> & rxParentStates)397 sal_Bool ScAccessiblePageHeader::IsDefunc( const uno::Reference<XAccessibleStateSet>& rxParentStates )
398 {
399     return ScAccessibleContextBase::IsDefunc() || (mpViewShell == NULL) || !getAccessibleParent().is() ||
400         (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC));
401 }
402 
AddChild(const EditTextObject * pArea,sal_uInt32 nIndex,SvxAdjust eAdjust)403 void ScAccessiblePageHeader::AddChild(const EditTextObject* pArea, sal_uInt32 nIndex, SvxAdjust eAdjust)
404 {
405     if (pArea && (pArea->GetText(0).Len() || (pArea->GetParagraphCount() > 1)))
406     {
407         if (maAreas[nIndex])
408         {
409             if (!ScGlobal::EETextObjEqual(maAreas[nIndex]->GetEditTextObject(), pArea))
410             {
411                 maAreas[nIndex]->release();
412                 maAreas[nIndex] = new ScAccessiblePageHeaderArea(this, mpViewShell, pArea, mbHeader, eAdjust);
413                 maAreas[nIndex]->acquire();
414             }
415         }
416         else
417         {
418             maAreas[nIndex] = new ScAccessiblePageHeaderArea(this, mpViewShell, pArea, mbHeader, eAdjust);
419             maAreas[nIndex]->acquire();
420         }
421         ++mnChildCount;
422     }
423     else
424     {
425         if (maAreas[nIndex])
426         {
427             maAreas[nIndex]->release();
428             maAreas[nIndex] = NULL;
429         }
430     }
431 }
432