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