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 // necessary 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 {
264 return GetName();
265 }
266
getImplementationName()267 OUString SAL_CALL SwAccessibleCell::getImplementationName()
268 {
269 return OUString(RTL_CONSTASCII_USTRINGPARAM(sImplementationName));
270 }
271
supportsService(const::rtl::OUString & sTestServiceName)272 sal_Bool SAL_CALL SwAccessibleCell::supportsService(
273 const ::rtl::OUString& sTestServiceName)
274 {
275 return sTestServiceName.equalsAsciiL( sServiceName,
276 sizeof(sServiceName)-1 ) ||
277 sTestServiceName.equalsAsciiL( sAccessibleServiceName,
278 sizeof(sAccessibleServiceName)-1 );
279 }
280
getSupportedServiceNames()281 uno::Sequence< OUString > SAL_CALL SwAccessibleCell::getSupportedServiceNames()
282 {
283 uno::Sequence< OUString > aRet(2);
284 OUString* pArray = aRet.getArray();
285 pArray[0] = OUString( RTL_CONSTASCII_USTRINGPARAM(sServiceName) );
286 pArray[1] = OUString( RTL_CONSTASCII_USTRINGPARAM(sAccessibleServiceName) );
287 return aRet;
288 }
289
Dispose(sal_Bool bRecursive)290 void SwAccessibleCell::Dispose( sal_Bool bRecursive )
291 {
292 const SwFrm *pParent = GetParent( SwAccessibleChild(GetFrm()), IsInPagePreview() );
293 ::vos::ORef< SwAccessibleContext > xAccImpl(
294 GetMap()->GetContextImpl( pParent, sal_False ) );
295 if( xAccImpl.isValid() )
296 xAccImpl->DisposeChild( SwAccessibleChild(GetFrm()), bRecursive );
297 SwAccessibleContext::Dispose( bRecursive );
298 }
299
InvalidatePosOrSize(const SwRect & rOldBox)300 void SwAccessibleCell::InvalidatePosOrSize( const SwRect& rOldBox )
301 {
302 const SwFrm *pParent = GetParent( SwAccessibleChild(GetFrm()), IsInPagePreview() );
303 ::vos::ORef< SwAccessibleContext > xAccImpl(
304 GetMap()->GetContextImpl( pParent, sal_False ) );
305 if( xAccImpl.isValid() )
306 xAccImpl->InvalidateChildPosOrSize( SwAccessibleChild(GetFrm()), rOldBox );
307 SwAccessibleContext::InvalidatePosOrSize( rOldBox );
308 }
309
310
311 // ===== XAccessibleInterface ===========================================
312
queryInterface(const uno::Type & rType)313 uno::Any SwAccessibleCell::queryInterface( const uno::Type& rType )
314 {
315 if (rType == ::getCppuType((const uno::Reference<XAccessibleExtendedAttributes>*)0))
316 {
317 uno::Any aR;
318 aR <<= uno::Reference<XAccessibleExtendedAttributes>(this);
319 return aR;
320 }
321
322 if (rType == ::getCppuType((const uno::Reference<XAccessibleSelection>*)0))
323 {
324 uno::Any aR;
325 aR <<= uno::Reference<XAccessibleSelection>(this);
326 return aR;
327 }
328 if ( rType == ::getCppuType( static_cast< uno::Reference< XAccessibleValue > * >( 0 ) ) )
329 {
330 uno::Reference<XAccessibleValue> xValue = this;
331 uno::Any aRet;
332 aRet <<= xValue;
333 return aRet;
334 }
335 else
336 {
337 return SwAccessibleContext::queryInterface( rType );
338 }
339 }
340
341 //====== XTypeProvider ====================================================
getTypes()342 uno::Sequence< uno::Type > SAL_CALL SwAccessibleCell::getTypes()
343 {
344 uno::Sequence< uno::Type > aTypes( SwAccessibleContext::getTypes() );
345
346 sal_Int32 nIndex = aTypes.getLength();
347 aTypes.realloc( nIndex + 1 );
348
349 uno::Type* pTypes = aTypes.getArray();
350 pTypes[nIndex] = ::getCppuType( static_cast< uno::Reference< XAccessibleValue > * >( 0 ) );
351
352 return aTypes;
353 }
354
getImplementationId()355 uno::Sequence< sal_Int8 > SAL_CALL SwAccessibleCell::getImplementationId()
356 {
357 vos::OGuard aGuard(Application::GetSolarMutex());
358 static uno::Sequence< sal_Int8 > aId( 16 );
359 static sal_Bool bInit = sal_False;
360 if(!bInit)
361 {
362 rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True );
363 bInit = sal_True;
364 }
365 return aId;
366 }
367
368 // ===== XAccessibleValue ===============================================
369
GetTblBoxFormat() const370 SwFrmFmt* SwAccessibleCell::GetTblBoxFormat() const
371 {
372 DBG_ASSERT( GetFrm() != NULL, "no frame?" );
373 DBG_ASSERT( GetFrm()->IsCellFrm(), "no cell frame?" );
374
375 const SwCellFrm* pCellFrm = static_cast<const SwCellFrm*>( GetFrm() );
376 return pCellFrm->GetTabBox()->GetFrmFmt();
377 }
378
379 //Implement TableCell currentValue
getCurrentValue()380 uno::Any SwAccessibleCell::getCurrentValue( )
381 {
382 vos::OGuard aGuard(Application::GetSolarMutex());
383 CHECK_FOR_DEFUNC( XAccessibleValue );
384
385 uno::Any aAny;
386
387 const SwCellFrm* pCellFrm = static_cast<const SwCellFrm*>( GetFrm() );
388 const SwStartNode *pSttNd = pCellFrm->GetTabBox()->GetSttNd();
389 if( pSttNd )
390 {
391 ::rtl::OUString strRet;
392 SwNodeIndex aCntntIdx( *pSttNd, 0 );
393 SwCntntNode* pCNd=NULL;
394 for(int nIndex = 0 ;
395 0 != ( pCNd = pSttNd->GetNodes().GoNext( &aCntntIdx ) ) &&
396 aCntntIdx.GetIndex() < pSttNd->EndOfSectionIndex();
397 ++nIndex )
398 {
399 if(pCNd && pCNd->IsTxtNode())
400 {
401 if (0 != nIndex)
402 {
403 strRet += ::rtl::OUString::createFromAscii(" ");
404 }
405 strRet +=((SwTxtNode*)pCNd)->GetTxt();
406 }
407 }
408 aAny <<= strRet;
409 }
410 return aAny;
411 }
412
setCurrentValue(const uno::Any & aNumber)413 sal_Bool SwAccessibleCell::setCurrentValue( const uno::Any& aNumber )
414 {
415 vos::OGuard aGuard(Application::GetSolarMutex());
416 CHECK_FOR_DEFUNC( XAccessibleValue );
417
418 double fValue = 0;
419 sal_Bool bValid = (aNumber >>= fValue);
420 if( bValid )
421 {
422 SwTblBoxValue aValue( fValue );
423 GetTblBoxFormat()->SetFmtAttr( aValue );
424 }
425 return bValid;
426 }
427
getMaximumValue()428 uno::Any SwAccessibleCell::getMaximumValue( )
429 {
430 uno::Any aAny;
431 aAny <<= DBL_MAX;
432 return aAny;
433 }
434
getMinimumValue()435 uno::Any SwAccessibleCell::getMinimumValue( )
436 {
437 uno::Any aAny;
438 aAny <<= -DBL_MAX;
439 return aAny;
440 }
441
ReplaceOneChar(::rtl::OUString oldOUString,::rtl::OUString replacedChar,::rtl::OUString replaceStr)442 ::rtl::OUString ReplaceOneChar(::rtl::OUString oldOUString, ::rtl::OUString replacedChar, ::rtl::OUString replaceStr)
443 {
444 int iReplace = -1;
445 iReplace = oldOUString.lastIndexOf(replacedChar);
446 if (iReplace > -1)
447 {
448 for(;iReplace>-1;)
449 {
450 oldOUString = oldOUString.replaceAt(iReplace,1, replaceStr);
451 iReplace=oldOUString.lastIndexOf(replacedChar,iReplace);
452 }
453 }
454 return oldOUString;
455 }
ReplaceFourChar(::rtl::OUString oldOUString)456 ::rtl::OUString ReplaceFourChar(::rtl::OUString oldOUString)
457 {
458 oldOUString = ReplaceOneChar(oldOUString,OUString::createFromAscii("\\"),OUString::createFromAscii("\\\\"));
459 oldOUString = ReplaceOneChar(oldOUString,::rtl::OUString::createFromAscii(";"),::rtl::OUString::createFromAscii("\\;"));
460 oldOUString = ReplaceOneChar(oldOUString,::rtl::OUString::createFromAscii("="),::rtl::OUString::createFromAscii("\\="));
461 oldOUString = ReplaceOneChar(oldOUString,::rtl::OUString::createFromAscii(","),::rtl::OUString::createFromAscii("\\,"));
462 oldOUString = ReplaceOneChar(oldOUString,::rtl::OUString::createFromAscii(":"),::rtl::OUString::createFromAscii("\\:"));
463 return oldOUString;
464 }
465
getExtendedAttributes()466 ::com::sun::star::uno::Any SAL_CALL SwAccessibleCell::getExtendedAttributes()
467 {
468 ::com::sun::star::uno::Any strRet;
469 SwFrmFmt *pFrmFmt = GetTblBoxFormat();
470 DBG_ASSERT(pFrmFmt,"Must be Valid");
471
472 const SwTblBoxFormula& tbl_formula = pFrmFmt->GetTblBoxFormula();
473
474 ::rtl::OUString strFormula = ReplaceFourChar(tbl_formula.GetFormula());
475 ::rtl::OUString strFor = ::rtl::OUString::createFromAscii("Formula:");
476 strFor += strFormula;
477 strFor += ::rtl::OUString::createFromAscii(";") ;
478 strRet <<= strFor;
479
480 return strRet;
481 }
482
getBackground()483 sal_Int32 SAL_CALL SwAccessibleCell::getBackground()
484 {
485 const SvxBrushItem &rBack = GetFrm()->GetAttrSet()->GetBackground();
486 sal_uInt32 crBack = rBack.GetColor().GetColor();
487
488 if (COL_AUTO == crBack)
489 {
490 uno::Reference<XAccessible> xAccDoc = getAccessibleParent();
491 if (xAccDoc.is())
492 {
493 uno::Reference<XAccessibleComponent> xCompoentDoc(xAccDoc, uno::UNO_QUERY);
494 if (xCompoentDoc.is())
495 {
496 crBack = (sal_uInt32)xCompoentDoc->getBackground();
497 }
498 }
499 }
500 return crBack;
501 }
502
503 //===== XAccessibleSelection ============================================
selectAccessibleChild(sal_Int32 nChildIndex)504 void SwAccessibleCell::selectAccessibleChild(
505 sal_Int32 nChildIndex )
506 {
507 aSelectionHelper.selectAccessibleChild(nChildIndex);
508 }
509
isAccessibleChildSelected(sal_Int32 nChildIndex)510 sal_Bool SwAccessibleCell::isAccessibleChildSelected(
511 sal_Int32 nChildIndex )
512 {
513 return aSelectionHelper.isAccessibleChildSelected(nChildIndex);
514 }
515
clearAccessibleSelection()516 void SwAccessibleCell::clearAccessibleSelection( )
517 {
518 aSelectionHelper.clearAccessibleSelection();
519 }
520
selectAllAccessibleChildren()521 void SwAccessibleCell::selectAllAccessibleChildren( )
522 {
523 aSelectionHelper.selectAllAccessibleChildren();
524 }
525
getSelectedAccessibleChildCount()526 sal_Int32 SwAccessibleCell::getSelectedAccessibleChildCount( )
527 {
528 return aSelectionHelper.getSelectedAccessibleChildCount();
529 }
530
getSelectedAccessibleChild(sal_Int32 nSelectedChildIndex)531 uno::Reference<XAccessible> SwAccessibleCell::getSelectedAccessibleChild(
532 sal_Int32 nSelectedChildIndex )
533 {
534 return aSelectionHelper.getSelectedAccessibleChild(nSelectedChildIndex);
535 }
536
deselectAccessibleChild(sal_Int32 nSelectedChildIndex)537 void SwAccessibleCell::deselectAccessibleChild(
538 sal_Int32 nSelectedChildIndex )
539 {
540 aSelectionHelper.deselectAccessibleChild(nSelectedChildIndex);
541 }
542