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