xref: /aoo4110/main/sw/source/core/access/acccell.cxx (revision b1cdbd2c)
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 
28 #include <vos/mutex.hxx>
29 #include <com/sun/star/accessibility/AccessibleRole.hpp>
30 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
31 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
32 #include <unotools/accessiblestatesethelper.hxx>
33 #include <rtl/uuid.h>
34 #include <vcl/svapp.hxx>
35 #include <cellfrm.hxx>
36 #include <tabfrm.hxx>
37 #include <swtable.hxx>
38 #include "crsrsh.hxx"
39 #include "viscrs.hxx"
40 #include <accfrmobj.hxx>
41 #include <accfrmobjslist.hxx>
42 #include "frmfmt.hxx"
43 #include "cellatr.hxx"
44 #include "accmap.hxx"
45 #include <acccell.hxx>
46 
47 #ifndef _STLP_CFLOAT
48 #include <cfloat>
49 #endif
50 
51 #include <limits.h>
52 
53 #include <ndtxt.hxx>
54 #include <editeng/brshitem.hxx>
55 #include <swatrset.hxx>
56 #include <frmatr.hxx>
57 #include "acctable.hxx"
58 
59 using namespace ::com::sun::star;
60 using namespace ::com::sun::star::accessibility;
61 using ::rtl::OUString;
62 using namespace sw::access;
63 
64 const sal_Char sServiceName[] = "com.sun.star.table.AccessibleCellView";
65 const sal_Char sImplementationName[] = "com.sun.star.comp.Writer.SwAccessibleCellView";
66 
IsSelected()67 sal_Bool SwAccessibleCell::IsSelected()
68 {
69 	sal_Bool bRet = sal_False;
70 
71     DBG_ASSERT( GetMap(), "no map?" );
72 	const ViewShell *pVSh = GetMap()->GetShell();
73     DBG_ASSERT( pVSh, "no shell?" );
74 	if( pVSh->ISA( SwCrsrShell ) )
75 	{
76 		const SwCrsrShell *pCSh = static_cast< const SwCrsrShell * >( pVSh );
77 		if( pCSh->IsTableMode() )
78 		{
79 			const SwCellFrm *pCFrm =
80 				static_cast< const SwCellFrm * >( GetFrm() );
81 			SwTableBox *pBox =
82 				const_cast< SwTableBox *>( pCFrm->GetTabBox() ); //SVPtrArr!
83 			bRet = pCSh->GetTableCrsr()->GetBoxes().Seek_Entry( pBox );
84 		}
85 	}
86 
87 	return bRet;
88 }
89 
GetStates(::utl::AccessibleStateSetHelper & rStateSet)90 void SwAccessibleCell::GetStates( ::utl::AccessibleStateSetHelper& rStateSet )
91 {
92 	SwAccessibleContext::GetStates( rStateSet );
93 
94 	// SELECTABLE
95 	const ViewShell *pVSh = GetMap()->GetShell();
96     DBG_ASSERT( pVSh, "no shell?" );
97 	if( pVSh->ISA( SwCrsrShell ) )
98 		rStateSet.AddState( AccessibleStateType::SELECTABLE );
99 	//Solution:Add resizable state to table cell.
100 	rStateSet.AddState( AccessibleStateType::RESIZABLE );
101 
102 	// SELECTED
103 	if( IsSelected() )
104 	{
105 		rStateSet.AddState( AccessibleStateType::SELECTED );
106 		ASSERT( bIsSelected, "bSelected out of sync" );
107 		::vos::ORef < SwAccessibleContext > xThis( this );
108 		GetMap()->SetCursorContext( xThis );
109 	}
110 }
111 
SwAccessibleCell(SwAccessibleMap * pInitMap,const SwCellFrm * pCellFrm)112 SwAccessibleCell::SwAccessibleCell( SwAccessibleMap *pInitMap,
113                                     const SwCellFrm *pCellFrm )
114     : SwAccessibleContext( pInitMap, AccessibleRole::TABLE_CELL, pCellFrm )
115     , aSelectionHelper( *this )
116     , bIsSelected( sal_False )
117     , m_xTableReference( NULL )
118     , m_pAccTable( NULL )
119 {
120     vos::OGuard aGuard( Application::GetSolarMutex() );
121     OUString sBoxName( pCellFrm->GetTabBox()->GetName() );
122     SetName( sBoxName );
123 
124     bIsSelected = IsSelected();
125 
126     m_xTableReference = getAccessibleParent();
127 #if OSL_DEBUG_LEVEL > 1
128     uno::Reference< XAccessibleContext > xContextTable( m_xTableReference, uno::UNO_QUERY );
129     OSL_ASSERT( xContextTable.is() && xContextTable->getAccessibleRole() == AccessibleRole::TABLE );
130 #endif
131     m_pAccTable = static_cast< SwAccessibleTable * >( m_xTableReference.get() );
132 }
133 
_InvalidateMyCursorPos()134 sal_Bool SwAccessibleCell::_InvalidateMyCursorPos()
135 {
136 	sal_Bool bNew = IsSelected();
137 	sal_Bool bOld;
138 	{
139 		vos::OGuard aGuard( aMutex );
140 		bOld = bIsSelected;
141 		bIsSelected = bNew;
142 	}
143 	if( bNew )
144 	{
145 		// remember that object as the one that has the caret. This is
146 		// neccessary to notify that object if the cursor leaves it.
147 		::vos::ORef < SwAccessibleContext > xThis( this );
148 		GetMap()->SetCursorContext( xThis );
149 	}
150 
151 	sal_Bool bChanged = bOld != bNew;
152 	if( bChanged )
153 	{
154 		FireStateChangedEvent( AccessibleStateType::SELECTED, bNew );
155 		if (m_pAccTable)
156 		{
157 			m_pAccTable->AddSelectionCell(this,bNew);
158 		}
159 	}
160 	return bChanged;
161 }
162 
_InvalidateChildrenCursorPos(const SwFrm * pFrm)163 sal_Bool SwAccessibleCell::_InvalidateChildrenCursorPos( const SwFrm *pFrm )
164 {
165 	sal_Bool bChanged = sal_False;
166 
167     const SwAccessibleChildSList aVisList( GetVisArea(), *pFrm, *GetMap() );
168     SwAccessibleChildSList::const_iterator aIter( aVisList.begin() );
169 	while( aIter != aVisList.end() )
170 	{
171         const SwAccessibleChild& rLower = *aIter;
172 		const SwFrm *pLower = rLower.GetSwFrm();
173 		if( pLower )
174 		{
175 			if( rLower.IsAccessible( GetMap()->GetShell()->IsPreView() )  )
176 			{
177 				::vos::ORef< SwAccessibleContext > xAccImpl(
178 					GetMap()->GetContextImpl( pLower, sal_False ) );
179 				if( xAccImpl.isValid() )
180 				{
181 					ASSERT( xAccImpl->GetFrm()->IsCellFrm(),
182 						 	"table child is not a cell frame" )
183 					bChanged = static_cast< SwAccessibleCell *>(
184 							xAccImpl.getBodyPtr() )->_InvalidateMyCursorPos();
185 				}
186 				else
187 					bChanged = sal_True; // If the context is not know we
188 										 // don't know whether the selection
189 										 // changed or not.
190 			}
191 			else
192 			{
193 				// This is a box with sub rows.
194 				bChanged |= _InvalidateChildrenCursorPos( pLower );
195 			}
196 		}
197 		++aIter;
198 	}
199 
200 	return bChanged;
201 }
202 
_InvalidateCursorPos()203 void SwAccessibleCell::_InvalidateCursorPos()
204 {
205 	if (IsSelected())
206 	{
207 		const SwAccessibleChild aChild( GetChild( *(GetMap()), 0 ) );
208 		if( aChild.IsValid()  && aChild.GetSwFrm() )
209 		{
210 			::vos::ORef < SwAccessibleContext > xChildImpl(	GetMap()->GetContextImpl( aChild.GetSwFrm())  );
211 			if(xChildImpl.isValid())
212 			{
213 				AccessibleEventObject aEvent;
214 				aEvent.EventId = AccessibleEventId::STATE_CHANGED;
215 				aEvent.NewValue<<=AccessibleStateType::FOCUSED;
216 				xChildImpl->FireAccessibleEvent( aEvent );
217 			}
218 		}
219 	}
220 
221     const SwFrm *pParent = GetParent( SwAccessibleChild(GetFrm()), IsInPagePreview() );
222 	ASSERT( pParent->IsTabFrm(), "parent is not a tab frame" );
223 	const SwTabFrm *pTabFrm = static_cast< const SwTabFrm * >( pParent );
224 	if( pTabFrm->IsFollow() )
225 		pTabFrm = pTabFrm->FindMaster();
226 
227 	while( pTabFrm )
228 	{
229                 _InvalidateChildrenCursorPos( pTabFrm );
230 /*
231 		sal_Bool bChanged = _InvalidateChildrenCursorPos( pTabFrm );
232 		if( bChanged )
233 		{
234 			::vos::ORef< SwAccessibleContext > xAccImpl(
235 				GetMap()->GetContextImpl( pTabFrm, sal_False ) );
236 			if( xAccImpl.isValid() )
237 			{
238 				AccessibleEventObject aEvent;
239 				aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
240 				xAccImpl->FireAccessibleEvent( aEvent );
241 			}
242 		}
243 */
244 		pTabFrm = pTabFrm->GetFollow();
245 	}
246 	if (m_pAccTable)
247 	{
248 		m_pAccTable->FireSelectionEvent();
249 	}
250 }
251 
HasCursor()252 sal_Bool SwAccessibleCell::HasCursor()
253 {
254 	vos::OGuard aGuard( aMutex );
255 	return bIsSelected;
256 }
257 
~SwAccessibleCell()258 SwAccessibleCell::~SwAccessibleCell()
259 {
260 }
261 
getAccessibleDescription(void)262 OUString SAL_CALL SwAccessibleCell::getAccessibleDescription (void)
263         throw (uno::RuntimeException)
264 {
265 	return GetName();
266 }
267 
getImplementationName()268 OUString SAL_CALL SwAccessibleCell::getImplementationName()
269         throw( uno::RuntimeException )
270 {
271 	return OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationName));
272 }
273 
supportsService(const::rtl::OUString & sTestServiceName)274 sal_Bool SAL_CALL SwAccessibleCell::supportsService(
275 		const ::rtl::OUString& sTestServiceName)
276 	throw (uno::RuntimeException)
277 {
278 	return sTestServiceName.equalsAsciiL( sServiceName,
279 										  sizeof(sServiceName)-1 ) ||
280 		   sTestServiceName.equalsAsciiL( sAccessibleServiceName,
281 				   						  sizeof(sAccessibleServiceName)-1 );
282 }
283 
getSupportedServiceNames()284 uno::Sequence< OUString > SAL_CALL SwAccessibleCell::getSupportedServiceNames()
285 		throw( uno::RuntimeException )
286 {
287 	uno::Sequence< OUString > aRet(2);
288 	OUString* pArray = aRet.getArray();
289 	pArray[0] = OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceName) );
290 	pArray[1] = OUString( RTL_CONSTASCII_USTRINGPARAM(sAccessibleServiceName) );
291 	return aRet;
292 }
293 
Dispose(sal_Bool bRecursive)294 void SwAccessibleCell::Dispose( sal_Bool bRecursive )
295 {
296     const SwFrm *pParent = GetParent( SwAccessibleChild(GetFrm()), IsInPagePreview() );
297 	::vos::ORef< SwAccessibleContext > xAccImpl(
298 			GetMap()->GetContextImpl( pParent, sal_False ) );
299 	if( xAccImpl.isValid() )
300         xAccImpl->DisposeChild( SwAccessibleChild(GetFrm()), bRecursive );
301 	SwAccessibleContext::Dispose( bRecursive );
302 }
303 
InvalidatePosOrSize(const SwRect & rOldBox)304 void SwAccessibleCell::InvalidatePosOrSize( const SwRect& rOldBox )
305 {
306     const SwFrm *pParent = GetParent( SwAccessibleChild(GetFrm()), IsInPagePreview() );
307 	::vos::ORef< SwAccessibleContext > xAccImpl(
308 			GetMap()->GetContextImpl( pParent, sal_False ) );
309 	if( xAccImpl.isValid() )
310         xAccImpl->InvalidateChildPosOrSize( SwAccessibleChild(GetFrm()), rOldBox );
311 	SwAccessibleContext::InvalidatePosOrSize( rOldBox );
312 }
313 
314 
315 // =====  XAccessibleInterface  ===========================================
316 
queryInterface(const uno::Type & rType)317 uno::Any SwAccessibleCell::queryInterface( const uno::Type& rType )
318     throw( uno::RuntimeException )
319 {
320 	if (rType == ::getCppuType((const uno::Reference<XAccessibleExtendedAttributes>*)0))
321 	{
322 		uno::Any aR;
323 		aR <<= uno::Reference<XAccessibleExtendedAttributes>(this);
324 		return aR;
325 	}
326 
327 	if (rType == ::getCppuType((const uno::Reference<XAccessibleSelection>*)0))
328 	{
329 		uno::Any aR;
330 		aR <<= uno::Reference<XAccessibleSelection>(this);
331 		return aR;
332 	}
333     if ( rType == ::getCppuType( static_cast< uno::Reference< XAccessibleValue > * >( 0 ) ) )
334     {
335         uno::Reference<XAccessibleValue> xValue = this;
336         uno::Any aRet;
337         aRet <<= xValue;
338         return aRet;
339     }
340     else
341     {
342         return SwAccessibleContext::queryInterface( rType );
343     }
344 }
345 
346 //====== XTypeProvider ====================================================
getTypes()347 uno::Sequence< uno::Type > SAL_CALL SwAccessibleCell::getTypes()
348     throw(uno::RuntimeException)
349 {
350 	uno::Sequence< uno::Type > aTypes( SwAccessibleContext::getTypes() );
351 
352 	sal_Int32 nIndex = aTypes.getLength();
353 	aTypes.realloc( nIndex + 1 );
354 
355 	uno::Type* pTypes = aTypes.getArray();
356 	pTypes[nIndex] = ::getCppuType( static_cast< uno::Reference< XAccessibleValue > * >( 0 ) );
357 
358 	return aTypes;
359 }
360 
getImplementationId()361 uno::Sequence< sal_Int8 > SAL_CALL SwAccessibleCell::getImplementationId()
362 		throw(uno::RuntimeException)
363 {
364     vos::OGuard aGuard(Application::GetSolarMutex());
365     static uno::Sequence< sal_Int8 > aId( 16 );
366     static sal_Bool bInit = sal_False;
367     if(!bInit)
368     {
369         rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True );
370         bInit = sal_True;
371     }
372     return aId;
373 }
374 
375 // =====  XAccessibleValue  ===============================================
376 
GetTblBoxFormat() const377 SwFrmFmt* SwAccessibleCell::GetTblBoxFormat() const
378 {
379     DBG_ASSERT( GetFrm() != NULL, "no frame?" );
380     DBG_ASSERT( GetFrm()->IsCellFrm(), "no cell frame?" );
381 
382     const SwCellFrm* pCellFrm = static_cast<const SwCellFrm*>( GetFrm() );
383     return pCellFrm->GetTabBox()->GetFrmFmt();
384 }
385 
386 //Implement TableCell currentValue
getCurrentValue()387 uno::Any SwAccessibleCell::getCurrentValue( )
388     throw( uno::RuntimeException )
389 {
390 	vos::OGuard aGuard(Application::GetSolarMutex());
391 	CHECK_FOR_DEFUNC( XAccessibleValue );
392 
393     uno::Any aAny;
394 
395     const SwCellFrm* pCellFrm = static_cast<const SwCellFrm*>( GetFrm() );
396     const SwStartNode *pSttNd = pCellFrm->GetTabBox()->GetSttNd();
397 	if( pSttNd )
398 	{
399 		::rtl::OUString strRet;
400 		SwNodeIndex aCntntIdx( *pSttNd, 0 );
401 		SwCntntNode* pCNd=NULL;
402 		for(int nIndex = 0 ;
403 			0 != ( pCNd = pSttNd->GetNodes().GoNext( &aCntntIdx ) ) &&
404 			aCntntIdx.GetIndex() < pSttNd->EndOfSectionIndex();
405 			++nIndex )
406 		{
407 			if(pCNd && pCNd->IsTxtNode())
408 			{
409 				if (0 != nIndex)
410 				{
411 					strRet += ::rtl::OUString::createFromAscii(" ");
412 				}
413 				strRet +=((SwTxtNode*)pCNd)->GetTxt();
414 			}
415 		}
416 		aAny <<= strRet;
417 	}
418     return aAny;
419 }
420 
setCurrentValue(const uno::Any & aNumber)421 sal_Bool SwAccessibleCell::setCurrentValue( const uno::Any& aNumber )
422     throw( uno::RuntimeException )
423 {
424 	vos::OGuard aGuard(Application::GetSolarMutex());
425 	CHECK_FOR_DEFUNC( XAccessibleValue );
426 
427     double fValue = 0;
428     sal_Bool bValid = (aNumber >>= fValue);
429     if( bValid )
430     {
431         SwTblBoxValue aValue( fValue );
432         GetTblBoxFormat()->SetFmtAttr( aValue );
433     }
434     return bValid;
435 }
436 
getMaximumValue()437 uno::Any SwAccessibleCell::getMaximumValue( )
438     throw( uno::RuntimeException )
439 {
440     uno::Any aAny;
441     aAny <<= DBL_MAX;
442     return aAny;
443 }
444 
getMinimumValue()445 uno::Any SwAccessibleCell::getMinimumValue(  )
446     throw( uno::RuntimeException )
447 {
448     uno::Any aAny;
449     aAny <<= -DBL_MAX;
450     return aAny;
451 }
452 
ReplaceOneChar(::rtl::OUString oldOUString,::rtl::OUString replacedChar,::rtl::OUString replaceStr)453 ::rtl::OUString ReplaceOneChar(::rtl::OUString oldOUString, ::rtl::OUString replacedChar, ::rtl::OUString replaceStr)
454 {
455 	int iReplace = -1;
456 	iReplace = oldOUString.lastIndexOf(replacedChar);
457 	if (iReplace > -1)
458 	{
459 		for(;iReplace>-1;)
460 		{
461 			oldOUString = oldOUString.replaceAt(iReplace,1, replaceStr);
462 			iReplace=oldOUString.lastIndexOf(replacedChar,iReplace);
463 		}
464 	}
465 	return oldOUString;
466 }
ReplaceFourChar(::rtl::OUString oldOUString)467 ::rtl::OUString ReplaceFourChar(::rtl::OUString oldOUString)
468 {
469 	oldOUString = ReplaceOneChar(oldOUString,OUString::createFromAscii("\\"),OUString::createFromAscii("\\\\"));
470 	oldOUString = ReplaceOneChar(oldOUString,::rtl::OUString::createFromAscii(";"),::rtl::OUString::createFromAscii("\\;"));
471 	oldOUString = ReplaceOneChar(oldOUString,::rtl::OUString::createFromAscii("="),::rtl::OUString::createFromAscii("\\="));
472 	oldOUString = ReplaceOneChar(oldOUString,::rtl::OUString::createFromAscii(","),::rtl::OUString::createFromAscii("\\,"));
473 	oldOUString = ReplaceOneChar(oldOUString,::rtl::OUString::createFromAscii(":"),::rtl::OUString::createFromAscii("\\:"));
474 	return oldOUString;
475 }
476 
getExtendedAttributes()477 ::com::sun::star::uno::Any SAL_CALL SwAccessibleCell::getExtendedAttributes()
478 		throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException)
479 {
480 	::com::sun::star::uno::Any strRet;
481     SwFrmFmt *pFrmFmt = GetTblBoxFormat();
482 	DBG_ASSERT(pFrmFmt,"Must be Valid");
483 
484 	const SwTblBoxFormula& tbl_formula = pFrmFmt->GetTblBoxFormula();
485 
486 	::rtl::OUString strFormula = ReplaceFourChar(tbl_formula.GetFormula());
487 	::rtl::OUString strFor = ::rtl::OUString::createFromAscii("Formula:");
488 	strFor += strFormula;
489 	strFor += ::rtl::OUString::createFromAscii(";") ;
490 	strRet <<= strFor;
491 
492 	return strRet;
493 }
494 
getBackground()495 sal_Int32 SAL_CALL SwAccessibleCell::getBackground()
496 		throw (::com::sun::star::uno::RuntimeException)
497 {
498 	const SvxBrushItem &rBack = GetFrm()->GetAttrSet()->GetBackground();
499 	sal_uInt32 crBack = rBack.GetColor().GetColor();
500 
501 	if (COL_AUTO == crBack)
502 	{
503 		uno::Reference<XAccessible> xAccDoc = getAccessibleParent();
504 		if (xAccDoc.is())
505 		{
506 			uno::Reference<XAccessibleComponent> xCompoentDoc(xAccDoc, uno::UNO_QUERY);
507 			if (xCompoentDoc.is())
508 			{
509 				crBack = (sal_uInt32)xCompoentDoc->getBackground();
510 			}
511 		}
512 	}
513 	return crBack;
514 }
515 
516 //=====  XAccessibleSelection  ============================================
selectAccessibleChild(sal_Int32 nChildIndex)517 void SwAccessibleCell::selectAccessibleChild(
518     sal_Int32 nChildIndex )
519 	throw ( lang::IndexOutOfBoundsException, uno::RuntimeException )
520 {
521     aSelectionHelper.selectAccessibleChild(nChildIndex);
522 }
523 
isAccessibleChildSelected(sal_Int32 nChildIndex)524 sal_Bool SwAccessibleCell::isAccessibleChildSelected(
525     sal_Int32 nChildIndex )
526 	throw ( lang::IndexOutOfBoundsException, uno::RuntimeException )
527 {
528     return aSelectionHelper.isAccessibleChildSelected(nChildIndex);
529 }
530 
clearAccessibleSelection()531 void SwAccessibleCell::clearAccessibleSelection(  )
532 	throw ( uno::RuntimeException )
533 {
534     aSelectionHelper.clearAccessibleSelection();
535 }
536 
selectAllAccessibleChildren()537 void SwAccessibleCell::selectAllAccessibleChildren(  )
538     throw ( uno::RuntimeException )
539 {
540     aSelectionHelper.selectAllAccessibleChildren();
541 }
542 
getSelectedAccessibleChildCount()543 sal_Int32 SwAccessibleCell::getSelectedAccessibleChildCount(  )
544     throw ( uno::RuntimeException )
545 {
546     return aSelectionHelper.getSelectedAccessibleChildCount();
547 }
548 
getSelectedAccessibleChild(sal_Int32 nSelectedChildIndex)549 uno::Reference<XAccessible> SwAccessibleCell::getSelectedAccessibleChild(
550     sal_Int32 nSelectedChildIndex )
551 	throw ( lang::IndexOutOfBoundsException, uno::RuntimeException)
552 {
553     return aSelectionHelper.getSelectedAccessibleChild(nSelectedChildIndex);
554 }
555 
deselectAccessibleChild(sal_Int32 nSelectedChildIndex)556 void SwAccessibleCell::deselectAccessibleChild(
557     sal_Int32 nSelectedChildIndex )
558 	throw ( lang::IndexOutOfBoundsException, uno::RuntimeException )
559 {
560     aSelectionHelper.deselectAccessibleChild(nSelectedChildIndex);
561 }
562 
563