xref: /trunk/main/sw/source/core/access/acccell.cxx (revision ca62e2c2083b5d0995f1245bad6c2edfb455fbec)
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