Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <osl/mutex.hxx>
21 : #include <com/sun/star/accessibility/AccessibleRole.hpp>
22 : #include <com/sun/star/accessibility/AccessibleStateType.hpp>
23 : #include <com/sun/star/accessibility/AccessibleEventId.hpp>
24 : #include <unotools/accessiblestatesethelper.hxx>
25 : #include <comphelper/servicehelper.hxx>
26 : #include <cppuhelper/supportsservice.hxx>
27 : #include <vcl/svapp.hxx>
28 : #include <cellfrm.hxx>
29 : #include <tabfrm.hxx>
30 : #include <swtable.hxx>
31 : #include "crsrsh.hxx"
32 : #include "viscrs.hxx"
33 : #include <accfrmobj.hxx>
34 : #include <accfrmobjslist.hxx>
35 : #include "frmfmt.hxx"
36 : #include "cellatr.hxx"
37 : #include "accmap.hxx"
38 : #include <acccell.hxx>
39 :
40 : #include <cfloat>
41 : #include <limits.h>
42 :
43 : #include <ndtxt.hxx>
44 : #include <editeng/brushitem.hxx>
45 : #include <swatrset.hxx>
46 : #include <frmatr.hxx>
47 : #include "acctable.hxx"
48 :
49 : using namespace ::com::sun::star;
50 : using namespace ::com::sun::star::accessibility;
51 : using namespace sw::access;
52 :
53 : const sal_Char sServiceName[] = "com.sun.star.table.AccessibleCellView";
54 : const sal_Char sImplementationName[] = "com.sun.star.comp.Writer.SwAccessibleCellView";
55 :
56 45 : bool SwAccessibleCell::IsSelected()
57 : {
58 45 : bool bRet = false;
59 :
60 : assert(GetMap());
61 45 : const SwViewShell *pVSh = GetMap()->GetShell();
62 : assert(pVSh);
63 45 : if( pVSh->ISA( SwCrsrShell ) )
64 : {
65 45 : const SwCrsrShell *pCSh = static_cast< const SwCrsrShell * >( pVSh );
66 45 : if( pCSh->IsTableMode() )
67 : {
68 : const SwCellFrm *pCFrm =
69 35 : static_cast< const SwCellFrm * >( GetFrm() );
70 : SwTableBox *pBox =
71 35 : const_cast< SwTableBox *>( pCFrm->GetTabBox() );
72 35 : SwSelBoxes const& rBoxes(pCSh->GetTableCrsr()->GetSelectedBoxes());
73 35 : bRet = rBoxes.find(pBox) != rBoxes.end();
74 : }
75 : }
76 :
77 45 : return bRet;
78 : }
79 :
80 4 : void SwAccessibleCell::GetStates( ::utl::AccessibleStateSetHelper& rStateSet )
81 : {
82 4 : SwAccessibleContext::GetStates( rStateSet );
83 :
84 : // SELECTABLE
85 4 : const SwViewShell *pVSh = GetMap()->GetShell();
86 : assert(pVSh);
87 4 : if( pVSh->ISA( SwCrsrShell ) )
88 4 : rStateSet.AddState( AccessibleStateType::SELECTABLE );
89 : //Add resizable state to table cell.
90 4 : rStateSet.AddState( AccessibleStateType::RESIZABLE );
91 :
92 : // SELECTED
93 4 : if( IsSelected() )
94 : {
95 0 : rStateSet.AddState( AccessibleStateType::SELECTED );
96 : assert(bIsSelected && "bSelected out of sync");
97 0 : ::rtl::Reference < SwAccessibleContext > xThis( this );
98 0 : GetMap()->SetCursorContext( xThis );
99 : }
100 4 : }
101 :
102 16 : SwAccessibleCell::SwAccessibleCell( SwAccessibleMap *pInitMap,
103 : const SwCellFrm *pCellFrm )
104 : : SwAccessibleContext( pInitMap, AccessibleRole::TABLE_CELL, pCellFrm )
105 : , aSelectionHelper( *this )
106 16 : , bIsSelected( false )
107 : {
108 16 : SolarMutexGuard aGuard;
109 32 : OUString sBoxName( pCellFrm->GetTabBox()->GetName() );
110 16 : SetName( sBoxName );
111 :
112 16 : bIsSelected = IsSelected();
113 :
114 : css::uno::Reference<css::accessibility::XAccessible> xTableReference(
115 32 : getAccessibleParent());
116 : css::uno::Reference<css::accessibility::XAccessibleContext> xContextTable(
117 32 : xTableReference, css::uno::UNO_QUERY);
118 : SAL_WARN_IF(
119 : (!xContextTable.is()
120 : || xContextTable->getAccessibleRole() != AccessibleRole::TABLE),
121 : "sw.core", "bad accessible context");
122 32 : m_pAccTable = static_cast<SwAccessibleTable *>(xTableReference.get());
123 16 : }
124 :
125 15 : bool SwAccessibleCell::_InvalidateMyCursorPos()
126 : {
127 15 : bool bNew = IsSelected();
128 : bool bOld;
129 : {
130 15 : osl::MutexGuard aGuard( m_Mutex );
131 15 : bOld = bIsSelected;
132 15 : bIsSelected = bNew;
133 : }
134 15 : if( bNew )
135 : {
136 : // remember that object as the one that has the caret. This is
137 : // necessary to notify that object if the cursor leaves it.
138 13 : ::rtl::Reference < SwAccessibleContext > xThis( this );
139 13 : GetMap()->SetCursorContext( xThis );
140 : }
141 :
142 15 : bool bChanged = bOld != bNew;
143 15 : if( bChanged )
144 : {
145 5 : FireStateChangedEvent( AccessibleStateType::SELECTED, bNew );
146 5 : if (m_pAccTable.is())
147 : {
148 5 : m_pAccTable->AddSelectionCell(this,bNew);
149 : }
150 : }
151 15 : return bChanged;
152 : }
153 :
154 30 : bool SwAccessibleCell::_InvalidateChildrenCursorPos( const SwFrm *pFrm )
155 : {
156 30 : bool bChanged = false;
157 :
158 30 : const SwAccessibleChildSList aVisList( GetVisArea(), *pFrm, *GetMap() );
159 30 : SwAccessibleChildSList::const_iterator aIter( aVisList.begin() );
160 120 : while( aIter != aVisList.end() )
161 : {
162 60 : const SwAccessibleChild& rLower = *aIter;
163 60 : const SwFrm *pLower = rLower.GetSwFrm();
164 60 : if( pLower )
165 : {
166 60 : if( rLower.IsAccessible( GetMap()->GetShell()->IsPreview() ) )
167 : {
168 : ::rtl::Reference< SwAccessibleContext > xAccImpl(
169 40 : GetMap()->GetContextImpl( pLower, false ) );
170 40 : if( xAccImpl.is() )
171 : {
172 : assert(xAccImpl->GetFrm()->IsCellFrm());
173 : bChanged = static_cast< SwAccessibleCell *>(
174 15 : xAccImpl.get() )->_InvalidateMyCursorPos();
175 : }
176 : else
177 25 : bChanged = true; // If the context is not know we
178 : // don't know whether the selection
179 : // changed or not.
180 : }
181 : else
182 : {
183 : // This is a box with sub rows.
184 20 : bChanged |= _InvalidateChildrenCursorPos( pLower );
185 : }
186 : }
187 60 : ++aIter;
188 : }
189 :
190 30 : return bChanged;
191 : }
192 :
193 10 : void SwAccessibleCell::_InvalidateCursorPos()
194 : {
195 10 : if (IsSelected())
196 : {
197 8 : const SwAccessibleChild aChild( GetChild( *(GetMap()), 0 ) );
198 8 : if( aChild.IsValid() && aChild.GetSwFrm() )
199 : {
200 8 : ::rtl::Reference < SwAccessibleContext > xChildImpl( GetMap()->GetContextImpl( aChild.GetSwFrm()) );
201 8 : if (xChildImpl.is())
202 : {
203 8 : AccessibleEventObject aEvent;
204 8 : aEvent.EventId = AccessibleEventId::STATE_CHANGED;
205 8 : aEvent.NewValue <<= AccessibleStateType::FOCUSED;
206 8 : xChildImpl->FireAccessibleEvent( aEvent );
207 8 : }
208 8 : }
209 : }
210 :
211 10 : const SwFrm *pParent = GetParent( SwAccessibleChild(GetFrm()), IsInPagePreview() );
212 : assert(pParent->IsTabFrm());
213 10 : const SwTabFrm *pTabFrm = static_cast< const SwTabFrm * >( pParent );
214 10 : if( pTabFrm->IsFollow() )
215 0 : pTabFrm = pTabFrm->FindMaster();
216 :
217 30 : while( pTabFrm )
218 : {
219 10 : _InvalidateChildrenCursorPos( pTabFrm );
220 10 : pTabFrm = pTabFrm->GetFollow();
221 : }
222 10 : if (m_pAccTable.is())
223 : {
224 10 : m_pAccTable->FireSelectionEvent();
225 : }
226 10 : }
227 :
228 16 : bool SwAccessibleCell::HasCursor()
229 : {
230 16 : osl::MutexGuard aGuard( m_Mutex );
231 16 : return bIsSelected;
232 : }
233 :
234 32 : SwAccessibleCell::~SwAccessibleCell()
235 : {
236 32 : }
237 :
238 7 : OUString SAL_CALL SwAccessibleCell::getAccessibleDescription()
239 : throw (uno::RuntimeException, std::exception)
240 : {
241 7 : return GetName();
242 : }
243 :
244 3 : OUString SAL_CALL SwAccessibleCell::getImplementationName()
245 : throw( uno::RuntimeException, std::exception )
246 : {
247 3 : return OUString(sImplementationName);
248 : }
249 :
250 0 : sal_Bool SAL_CALL SwAccessibleCell::supportsService(const OUString& sTestServiceName)
251 : throw (uno::RuntimeException, std::exception)
252 : {
253 0 : return cppu::supportsService(this, sTestServiceName);
254 : }
255 :
256 0 : uno::Sequence< OUString > SAL_CALL SwAccessibleCell::getSupportedServiceNames()
257 : throw( uno::RuntimeException, std::exception )
258 : {
259 0 : uno::Sequence< OUString > aRet(2);
260 0 : OUString* pArray = aRet.getArray();
261 0 : pArray[0] = sServiceName;
262 0 : pArray[1] = sAccessibleServiceName;
263 0 : return aRet;
264 : }
265 :
266 2 : void SwAccessibleCell::Dispose( bool bRecursive )
267 : {
268 2 : const SwFrm *pParent = GetParent( SwAccessibleChild(GetFrm()), IsInPagePreview() );
269 : ::rtl::Reference< SwAccessibleContext > xAccImpl(
270 2 : GetMap()->GetContextImpl( pParent, false ) );
271 2 : if( xAccImpl.is() )
272 2 : xAccImpl->DisposeChild( SwAccessibleChild(GetFrm()), bRecursive );
273 2 : SwAccessibleContext::Dispose( bRecursive );
274 2 : }
275 :
276 0 : void SwAccessibleCell::InvalidatePosOrSize( const SwRect& rOldBox )
277 : {
278 0 : const SwFrm *pParent = GetParent( SwAccessibleChild(GetFrm()), IsInPagePreview() );
279 : ::rtl::Reference< SwAccessibleContext > xAccImpl(
280 0 : GetMap()->GetContextImpl( pParent, false ) );
281 0 : if( xAccImpl.is() )
282 0 : xAccImpl->InvalidateChildPosOrSize( SwAccessibleChild(GetFrm()), rOldBox );
283 0 : SwAccessibleContext::InvalidatePosOrSize( rOldBox );
284 0 : }
285 :
286 : // XAccessibleInterface
287 :
288 178 : uno::Any SwAccessibleCell::queryInterface( const uno::Type& rType )
289 : throw( uno::RuntimeException, std::exception )
290 : {
291 178 : if (rType == cppu::UnoType<XAccessibleExtendedAttributes>::get())
292 : {
293 0 : uno::Any aR;
294 0 : aR <<= uno::Reference<XAccessibleExtendedAttributes>(this);
295 0 : return aR;
296 : }
297 :
298 178 : if (rType == cppu::UnoType<XAccessibleSelection>::get())
299 : {
300 9 : uno::Any aR;
301 9 : aR <<= uno::Reference<XAccessibleSelection>(this);
302 9 : return aR;
303 : }
304 169 : if ( rType == ::cppu::UnoType<XAccessibleValue>::get() )
305 : {
306 1 : uno::Reference<XAccessibleValue> xValue = this;
307 2 : uno::Any aRet;
308 1 : aRet <<= xValue;
309 2 : return aRet;
310 : }
311 : else
312 : {
313 168 : return SwAccessibleContext::queryInterface( rType );
314 : }
315 : }
316 :
317 : // XTypeProvider
318 0 : uno::Sequence< uno::Type > SAL_CALL SwAccessibleCell::getTypes()
319 : throw(uno::RuntimeException, std::exception)
320 : {
321 0 : uno::Sequence< uno::Type > aTypes( SwAccessibleContext::getTypes() );
322 :
323 0 : sal_Int32 nIndex = aTypes.getLength();
324 0 : aTypes.realloc( nIndex + 1 );
325 :
326 0 : uno::Type* pTypes = aTypes.getArray();
327 0 : pTypes[nIndex] = ::cppu::UnoType<XAccessibleValue>::get();
328 :
329 0 : return aTypes;
330 : }
331 :
332 0 : uno::Sequence< sal_Int8 > SAL_CALL SwAccessibleCell::getImplementationId()
333 : throw(uno::RuntimeException, std::exception)
334 : {
335 0 : return css::uno::Sequence<sal_Int8>();
336 : }
337 :
338 : // XAccessibleValue
339 :
340 11 : SwFrameFormat* SwAccessibleCell::GetTableBoxFormat() const
341 : {
342 : assert(GetFrm());
343 : assert(GetFrm()->IsCellFrm());
344 :
345 11 : const SwCellFrm* pCellFrm = static_cast<const SwCellFrm*>( GetFrm() );
346 11 : return pCellFrm->GetTabBox()->GetFrameFormat();
347 : }
348 :
349 : //Implement TableCell currentValue
350 6 : uno::Any SwAccessibleCell::getCurrentValue( )
351 : throw( uno::RuntimeException, std::exception )
352 : {
353 6 : SolarMutexGuard aGuard;
354 6 : CHECK_FOR_DEFUNC( XAccessibleValue );
355 :
356 6 : uno::Any aAny;
357 6 : aAny <<= GetTableBoxFormat()->GetTableBoxValue().GetValue();
358 6 : return aAny;
359 : }
360 :
361 5 : sal_Bool SwAccessibleCell::setCurrentValue( const uno::Any& aNumber )
362 : throw( uno::RuntimeException, std::exception )
363 : {
364 5 : SolarMutexGuard aGuard;
365 5 : CHECK_FOR_DEFUNC( XAccessibleValue );
366 :
367 5 : double fValue = 0;
368 5 : bool bValid = (aNumber >>= fValue);
369 5 : if( bValid )
370 : {
371 5 : SwTableBoxValue aValue( fValue );
372 5 : GetTableBoxFormat()->SetFormatAttr( aValue );
373 : }
374 5 : return bValid;
375 : }
376 :
377 1 : uno::Any SwAccessibleCell::getMaximumValue( )
378 : throw( uno::RuntimeException, std::exception )
379 : {
380 1 : uno::Any aAny;
381 1 : aAny <<= DBL_MAX;
382 1 : return aAny;
383 : }
384 :
385 1 : uno::Any SwAccessibleCell::getMinimumValue( )
386 : throw( uno::RuntimeException, std::exception )
387 : {
388 1 : uno::Any aAny;
389 1 : aAny <<= -DBL_MAX;
390 1 : return aAny;
391 : }
392 :
393 0 : static OUString ReplaceOneChar(const OUString& oldOUString, const OUString& replacedChar, const OUString& replaceStr)
394 : {
395 0 : int iReplace = oldOUString.lastIndexOf(replacedChar);
396 0 : OUString aRet = oldOUString;
397 0 : while(iReplace > -1)
398 : {
399 0 : aRet = aRet.replaceAt(iReplace,1, replaceStr);
400 0 : iReplace = aRet.lastIndexOf(replacedChar,iReplace);
401 : }
402 0 : return aRet;
403 : }
404 :
405 0 : static OUString ReplaceFourChar(const OUString& oldOUString)
406 : {
407 0 : OUString aRet = ReplaceOneChar(oldOUString,OUString("\\"),OUString("\\\\"));
408 0 : aRet = ReplaceOneChar(aRet,OUString(";"),OUString("\\;"));
409 0 : aRet = ReplaceOneChar(aRet,OUString("="),OUString("\\="));
410 0 : aRet = ReplaceOneChar(aRet,OUString(","),OUString("\\,"));
411 0 : aRet = ReplaceOneChar(aRet,OUString(":"),OUString("\\:"));
412 0 : return aRet;
413 : }
414 :
415 0 : ::com::sun::star::uno::Any SAL_CALL SwAccessibleCell::getExtendedAttributes()
416 : throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException, std::exception)
417 : {
418 0 : SolarMutexGuard g;
419 :
420 0 : ::com::sun::star::uno::Any strRet;
421 0 : SwFrameFormat *pFrameFormat = GetTableBoxFormat();
422 : assert(pFrameFormat);
423 :
424 0 : const SwTableBoxFormula& tbl_formula = pFrameFormat->GetTableBoxFormula();
425 :
426 0 : OUString strFormula = ReplaceFourChar(tbl_formula.GetFormula());
427 0 : OUString strFor("Formula:");
428 0 : strFor += strFormula;
429 0 : strFor += ";" ;
430 0 : strRet <<= strFor;
431 :
432 0 : return strRet;
433 : }
434 :
435 1 : sal_Int32 SAL_CALL SwAccessibleCell::getBackground()
436 : throw (::com::sun::star::uno::RuntimeException, std::exception)
437 : {
438 1 : SolarMutexGuard g;
439 :
440 1 : const SvxBrushItem &rBack = GetFrm()->GetAttrSet()->GetBackground();
441 1 : sal_uInt32 crBack = rBack.GetColor().GetColor();
442 :
443 1 : if (COL_AUTO == crBack)
444 : {
445 1 : uno::Reference<XAccessible> xAccDoc = getAccessibleParent();
446 1 : if (xAccDoc.is())
447 : {
448 1 : uno::Reference<XAccessibleComponent> xCompoentDoc(xAccDoc, uno::UNO_QUERY);
449 1 : if (xCompoentDoc.is())
450 : {
451 1 : crBack = (sal_uInt32)xCompoentDoc->getBackground();
452 1 : }
453 1 : }
454 : }
455 1 : return crBack;
456 : }
457 :
458 : // XAccessibleSelection
459 2 : void SwAccessibleCell::selectAccessibleChild(
460 : sal_Int32 nChildIndex )
461 : throw ( lang::IndexOutOfBoundsException, uno::RuntimeException, std::exception )
462 : {
463 2 : aSelectionHelper.selectAccessibleChild(nChildIndex);
464 0 : }
465 :
466 3 : sal_Bool SwAccessibleCell::isAccessibleChildSelected(
467 : sal_Int32 nChildIndex )
468 : throw ( lang::IndexOutOfBoundsException, uno::RuntimeException, std::exception )
469 : {
470 3 : return aSelectionHelper.isAccessibleChildSelected(nChildIndex);
471 : }
472 :
473 2 : void SwAccessibleCell::clearAccessibleSelection( )
474 : throw ( uno::RuntimeException, std::exception )
475 : {
476 2 : }
477 :
478 3 : void SwAccessibleCell::selectAllAccessibleChildren( )
479 : throw ( uno::RuntimeException, std::exception )
480 : {
481 3 : aSelectionHelper.selectAllAccessibleChildren();
482 3 : }
483 :
484 5 : sal_Int32 SwAccessibleCell::getSelectedAccessibleChildCount( )
485 : throw ( uno::RuntimeException, std::exception )
486 : {
487 5 : return aSelectionHelper.getSelectedAccessibleChildCount();
488 : }
489 :
490 2 : uno::Reference<XAccessible> SwAccessibleCell::getSelectedAccessibleChild(
491 : sal_Int32 nSelectedChildIndex )
492 : throw ( lang::IndexOutOfBoundsException, uno::RuntimeException, std::exception)
493 : {
494 2 : return aSelectionHelper.getSelectedAccessibleChild(nSelectedChildIndex);
495 : }
496 :
497 2 : void SwAccessibleCell::deselectAccessibleChild(
498 : sal_Int32 nSelectedChildIndex )
499 : throw ( lang::IndexOutOfBoundsException, uno::RuntimeException, std::exception )
500 : {
501 2 : aSelectionHelper.deselectAccessibleChild(nSelectedChildIndex);
502 177 : }
503 :
504 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|