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_sw.hxx"
26 
27 #include <com/sun/star/accessibility/XAccessibleContext.hpp>
28 #include <rtl/uuid.h>
29 #include <vos/mutex.hxx>
30 #include <vcl/svapp.hxx>
31 #include <com/sun/star/accessibility/AccessibleRole.hpp>
32 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
33 #include <com/sun/star/accessibility/AccessibleRelation.hpp>
34 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
35 #include <com/sun/star/accessibility/XAccessibleRelationSet.hpp>
36 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
37 #include <unotools/accessiblestatesethelper.hxx>
38 #include <frmfmt.hxx>
39 #include <flyfrm.hxx>
40 #include <accmap.hxx>
41 #include <unotools/accessiblerelationsethelper.hxx>
42 // --> OD 2009-07-14 #i73249#
43 #include <hints.hxx>
44 // <--
45 #include "acctextframe.hxx"
46 
47 #ifndef _DOC_HXX
48 #include <doc.hxx>
49 #endif
50 using namespace ::com::sun::star;
51 using namespace ::com::sun::star::accessibility;
52 using ::rtl::OUString;
53 
54 using utl::AccessibleRelationSetHelper;
55 using ::com::sun::star::accessibility::XAccessibleContext;
56 
57 const sal_Char sServiceName[] = "com.sun.star.text.AccessibleTextFrameView";
58 const sal_Char sImplementationName[] = "com.sun.star.comp.Writer.SwAccessibleTextFrameView";
59 
SwAccessibleTextFrame(SwAccessibleMap * pInitMap,const SwFlyFrm * pFlyFrm)60 SwAccessibleTextFrame::SwAccessibleTextFrame(
61         SwAccessibleMap* pInitMap,
62         const SwFlyFrm* pFlyFrm  ) :
63     SwAccessibleFrameBase( pInitMap, AccessibleRole::TEXT_FRAME, pFlyFrm ),
64     msTitle(),
65     msDesc()
66 {
67     if ( pFlyFrm )
68     {
69         const SwFlyFrmFmt* pFlyFrmFmt =
70                         dynamic_cast<const SwFlyFrmFmt*>( pFlyFrm->GetFmt() );
71         msTitle = pFlyFrmFmt->GetObjTitle();
72 
73         msDesc = pFlyFrmFmt->GetObjDescription();
74         if ( msDesc.getLength() == 0 &&
75              msTitle != GetName() )
76         {
77             msDesc = msTitle;
78         }
79     }
80 }
81 
~SwAccessibleTextFrame()82 SwAccessibleTextFrame::~SwAccessibleTextFrame()
83 {
84 }
85 
Modify(const SfxPoolItem * pOld,const SfxPoolItem * pNew)86 void SwAccessibleTextFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew)
87 {
88     const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0 ;
89     // --> OD 2009-07-14 #i73249#
90     // suppress handling of RES_NAME_CHANGED in case that attribute Title is
91     // used as the accessible name.
92     if ( nWhich != RES_NAME_CHANGED ||
93          msTitle.getLength() == 0 )
94     {
95         SwAccessibleFrameBase::Modify( pOld, pNew );
96     }
97 
98     const SwFlyFrm *pFlyFrm = static_cast< const SwFlyFrm * >( GetFrm() );
99 	switch( nWhich )
100 	{
101         // --> OD 2009-07-14 #i73249#
102         case RES_TITLE_CHANGED:
103         {
104             const String& sOldTitle(
105                         dynamic_cast<const SwStringMsgPoolItem*>(pOld)->GetString() );
106             const String& sNewTitle(
107                         dynamic_cast<const SwStringMsgPoolItem*>(pNew)->GetString() );
108             if ( sOldTitle == sNewTitle )
109             {
110                 break;
111             }
112             msTitle = sNewTitle;
113             AccessibleEventObject aEvent;
114             aEvent.EventId = AccessibleEventId::NAME_CHANGED;
115             aEvent.OldValue <<= OUString( sOldTitle );
116             aEvent.NewValue <<= msTitle;
117             FireAccessibleEvent( aEvent );
118 
119             const SwFlyFrmFmt* pFlyFrmFmt =
120                             dynamic_cast<const SwFlyFrmFmt*>( pFlyFrm->GetFmt() );
121             if ( pFlyFrmFmt->GetObjDescription().Len() != 0 )
122             {
123                 break;
124             }
125         }
126         // intentional no break here
127         case RES_DESCRIPTION_CHANGED:
128         {
129             if ( pFlyFrm )
130             {
131                 const OUString sOldDesc( msDesc );
132 
133                 const SwFlyFrmFmt* pFlyFrmFmt =
134                                 dynamic_cast<const SwFlyFrmFmt*>( pFlyFrm->GetFmt() );
135                 const String& rDesc = pFlyFrmFmt->GetObjDescription();
136                 msDesc = rDesc;
137                 if ( msDesc.getLength() == 0 &&
138                      msTitle != GetName() )
139                 {
140                     msDesc = msTitle;
141                 }
142 
143                 if ( msDesc != sOldDesc )
144                 {
145                     AccessibleEventObject aEvent;
146                     aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED;
147                     aEvent.OldValue <<= sOldDesc;
148                     aEvent.NewValue <<= msDesc;
149                     FireAccessibleEvent( aEvent );
150                 }
151             }
152         }
153         break;
154         // <--
155 	}
156 }
157 
158 //=====  XInterface  ==========================================================
159 
160 com::sun::star::uno::Any SAL_CALL
queryInterface(const com::sun::star::uno::Type & rType)161     SwAccessibleTextFrame::queryInterface (const com::sun::star::uno::Type & rType)
162     throw (::com::sun::star::uno::RuntimeException)
163 {
164     ::com::sun::star::uno::Any aReturn = SwAccessibleContext::queryInterface (rType);
165     if ( ! aReturn.hasValue())
166         aReturn = ::cppu::queryInterface (rType,
167             static_cast< ::com::sun::star::accessibility::XAccessibleSelection* >(this)
168             );
169     return aReturn;
170 }
171 
172 
173 
174 
175 void SAL_CALL
acquire(void)176     SwAccessibleTextFrame::acquire (void)
177     throw ()
178 {
179     SwAccessibleContext::acquire ();
180 }
181 
182 void SAL_CALL
release(void)183     SwAccessibleTextFrame::release (void)
184     throw ()
185 {
186     SwAccessibleContext::release ();
187 }
188 
189 //
190 //=====  XAccessibleSelection  ============================================
191 //
192 
193 //--------------------------------------------------------------------------------
selectAccessibleChild(sal_Int32)194 void SAL_CALL SwAccessibleTextFrame::selectAccessibleChild( sal_Int32 )
195 	throw ( lang::IndexOutOfBoundsException, uno::RuntimeException )
196 {
197     DBG_ASSERT( false, "<SwAccessibleTextFrame::selectAccessibleChild( sal_Int32 )> - missing implementation" );
198 }
199 
200 //----------------------------------------------------------------------------------
isAccessibleChildSelected(sal_Int32 nChildIndex)201 sal_Bool SAL_CALL SwAccessibleTextFrame::isAccessibleChildSelected( sal_Int32 nChildIndex )
202 	throw (lang::IndexOutOfBoundsException, uno::RuntimeException )
203 {
204 	uno::Reference<XAccessible> xAcc = getAccessibleChild( nChildIndex );
205 	uno::Reference<XAccessibleContext> xContext;
206 	if( xAcc.is() )
207 		xContext = xAcc->getAccessibleContext();
208 
209 	if( xContext.is() )
210 	{
211 		if( xContext->getAccessibleRole() == AccessibleRole::PARAGRAPH )
212 		{
213 			uno::Reference< ::com::sun::star::accessibility::XAccessibleText >
214 				xText(xAcc, uno::UNO_QUERY);
215 			if( xText.is() )
216 			{
217 				if( xText->getSelectionStart() >= 0 ) return sal_True;
218 			}
219 		}
220 	}
221 
222 	return sal_False;
223 }
224 
225 //---------------------------------------------------------------------
clearAccessibleSelection()226 void SAL_CALL SwAccessibleTextFrame::clearAccessibleSelection(  )
227 	throw ( uno::RuntimeException )
228 {
229     DBG_ASSERT( false, "<SwAccessibleTextFrame::clearAccessibleSelection(  )> - missing implementation" );
230 }
231 
232 //-------------------------------------------------------------------------
selectAllAccessibleChildren()233 void SAL_CALL SwAccessibleTextFrame::selectAllAccessibleChildren(  )
234 	throw ( uno::RuntimeException )
235 {
236     DBG_ASSERT( false, "<SwAccessibleTextFrame::selectAllAccessibleChildren(  )> - missing implementation" );
237 }
238 
239 //----------------------------------------------------------------------------
getSelectedAccessibleChildCount()240 sal_Int32 SAL_CALL SwAccessibleTextFrame::getSelectedAccessibleChildCount()
241 	throw ( uno::RuntimeException )
242 {
243 	sal_Int32 nCount = 0;
244 	sal_Int32 TotalCount = getAccessibleChildCount();
245 	for( sal_Int32 i = 0; i < TotalCount; i++ )
246 		if( isAccessibleChildSelected(i) ) nCount++;
247 
248 	return nCount;
249 }
250 
251 //--------------------------------------------------------------------------------------
getSelectedAccessibleChild(sal_Int32 nSelectedChildIndex)252 uno::Reference<XAccessible> SAL_CALL SwAccessibleTextFrame::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex )
253 	throw ( lang::IndexOutOfBoundsException, uno::RuntimeException)
254 {
255 	if ( nSelectedChildIndex > getSelectedAccessibleChildCount() )
256 		throw lang::IndexOutOfBoundsException();
257 	sal_Int32 i1, i2;
258 	for( i1 = 0, i2 = 0; i1 < getAccessibleChildCount(); i1++ )
259 		if( isAccessibleChildSelected(i1) )
260 		{
261 			if( i2 == nSelectedChildIndex )
262 				return getAccessibleChild( i1 );
263 			i2++;
264 		}
265 	return uno::Reference<XAccessible>();
266 }
267 
268 //----------------------------------------------------------------------------------
deselectAccessibleChild(sal_Int32)269 void SAL_CALL SwAccessibleTextFrame::deselectAccessibleChild( sal_Int32 )
270 	throw ( lang::IndexOutOfBoundsException, uno::RuntimeException )
271 {
272     DBG_ASSERT( false, "<SwAccessibleTextFrame::selectAllAccessibleChildren( sal_Int32 )> - missing implementation" );
273 }
274 
275 // --> OD 2009-07-14 #i73249#
getAccessibleName(void)276 OUString SAL_CALL SwAccessibleTextFrame::getAccessibleName (void)
277         throw (uno::RuntimeException)
278 {
279     vos::OGuard aGuard(Application::GetSolarMutex());
280 
281     CHECK_FOR_DEFUNC( XAccessibleContext )
282 
283     if ( msTitle.getLength() != 0 )
284     {
285         return msTitle;
286     }
287 
288     return SwAccessibleFrameBase::getAccessibleName();
289 }
290 // <--
291 
getAccessibleDescription(void)292 OUString SAL_CALL SwAccessibleTextFrame::getAccessibleDescription (void)
293         throw (uno::RuntimeException)
294 {
295 	vos::OGuard aGuard(Application::GetSolarMutex());
296 
297     CHECK_FOR_DEFUNC( XAccessibleContext )
298 	/* MT: I guess msDesc is correct noadays?
299 	OUString longDesc;
300 	const SwFlyFrmFmt* pFlyFmt = GetShell()->GetDoc()->FindFlyByName( GetName(), 0);
301 	if( pFlyFmt )
302 	{
303 		longDesc = OUString( pFlyFmt->GetDescription() );
304 	}
305 	if( longDesc.getLength() > 0 )
306 		return GetName() + OUString(' ') + longDesc;
307 	else
308 		return GetName();
309 	*/
310 
311     return msDesc;
312 }
313 
getImplementationName()314 OUString SAL_CALL SwAccessibleTextFrame::getImplementationName()
315         throw( uno::RuntimeException )
316 {
317 	return OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationName));
318 }
319 
supportsService(const OUString & sTestServiceName)320 sal_Bool SAL_CALL SwAccessibleTextFrame::supportsService(
321         const OUString& sTestServiceName)
322     throw (uno::RuntimeException)
323 {
324 	return sTestServiceName.equalsAsciiL( sServiceName,
325 										  sizeof(sServiceName)-1 ) ||
326 		   sTestServiceName.equalsAsciiL( sAccessibleServiceName,
327 				   						  sizeof(sAccessibleServiceName)-1 );
328 }
329 
getSupportedServiceNames()330 uno::Sequence< OUString > SAL_CALL SwAccessibleTextFrame::getSupportedServiceNames()
331 		throw( uno::RuntimeException )
332 {
333 	uno::Sequence< OUString > aRet(2);
334 	OUString* pArray = aRet.getArray();
335 	pArray[0] = OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceName) );
336 	pArray[1] = OUString( RTL_CONSTASCII_USTRINGPARAM(sAccessibleServiceName) );
337 	return aRet;
338 }
339 
getImplementationId()340 uno::Sequence< sal_Int8 > SAL_CALL SwAccessibleTextFrame::getImplementationId()
341 		throw(uno::RuntimeException)
342 {
343     vos::OGuard aGuard(Application::GetSolarMutex());
344     static uno::Sequence< sal_Int8 > aId( 16 );
345     static sal_Bool bInit = sal_False;
346     if(!bInit)
347     {
348         rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True );
349         bInit = sal_True;
350     }
351     return aId;
352 }
353 
354 
355 //
356 // XAccessibleRelationSet
357 //
358 
359 
getFlyFrm() const360 SwFlyFrm* SwAccessibleTextFrame::getFlyFrm() const
361 {
362 	SwFlyFrm* pFlyFrm = NULL;
363 
364 	const SwFrm* pFrm = GetFrm();
365 	DBG_ASSERT( pFrm != NULL, "frame expected" );
366 	if( pFrm->IsFlyFrm() )
367 	{
368 		pFlyFrm = static_cast<SwFlyFrm*>( const_cast<SwFrm*>( pFrm ) );
369 	}
370 
371 	return pFlyFrm;
372 }
373 
makeRelation(sal_Int16 nType,const SwFlyFrm * pFrm)374 AccessibleRelation SwAccessibleTextFrame::makeRelation( sal_Int16 nType, const SwFlyFrm* pFrm )
375 {
376     uno::Sequence<uno::Reference<XInterface> > aSequence(1);
377     aSequence[0] = GetMap()->GetContext( pFrm );
378 	return AccessibleRelation( nType, aSequence );
379 }
380 
381 
getAccessibleRelationSet()382 uno::Reference<XAccessibleRelationSet> SAL_CALL SwAccessibleTextFrame::getAccessibleRelationSet( )
383     throw ( uno::RuntimeException )
384 {
385 	vos::OGuard aGuard(Application::GetSolarMutex());
386     CHECK_FOR_DEFUNC( XAccessibleContext );
387 
388     // get the frame, and insert prev/next relations into helper
389 
390     AccessibleRelationSetHelper* pHelper = new AccessibleRelationSetHelper();
391 
392 	SwFlyFrm* pFlyFrm = getFlyFrm();
393 	DBG_ASSERT( pFlyFrm != NULL, "fly frame expected" );
394 
395 	const SwFlyFrm* pPrevFrm = pFlyFrm->GetPrevLink();
396     if( pPrevFrm != NULL )
397         pHelper->AddRelation( makeRelation(
398             AccessibleRelationType::CONTENT_FLOWS_FROM, pPrevFrm ) );
399 
400 	const SwFlyFrm* pNextFrm = pFlyFrm->GetNextLink();
401     if( pNextFrm != NULL )
402         pHelper->AddRelation( makeRelation(
403             AccessibleRelationType::CONTENT_FLOWS_TO, pNextFrm ) );
404 
405 	return pHelper;
406 }
407