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