xref: /trunk/main/sc/source/ui/Accessibility/AccessibleEditObject.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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_sc.hxx"
26 #include "AccessibleEditObject.hxx"
27 #include "scitems.hxx"
28 #include <editeng/eeitem.hxx>
29 #include "unoguard.hxx"
30 #include "AccessibleText.hxx"
31 #include "editsrc.hxx"
32 #include "scmod.hxx"
33 #include "inputhdl.hxx"
34 
35 #ifndef _UTL_ACCESSIBLESTATESETHELPER_HXX
36 #include <unotools/accessiblestatesethelper.hxx>
37 #endif
38 #ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEROLE_HPP_
39 #include <com/sun/star/accessibility/AccessibleRole.hpp>
40 #endif
41 #ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLESTATETYPE_HPP_
42 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
43 #endif
44 #include <rtl/uuid.h>
45 #include <tools/debug.hxx>
46 #include <svx/AccessibleTextHelper.hxx>
47 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
48 #include <com/sun/star/sheet/XSpreadsheet.hpp>
49 #include <editeng/editview.hxx>
50 #include <editeng/editeng.hxx>
51 #include <svx/svdmodel.hxx>
52 #include <sfx2/objsh.hxx>
53 
54 #include "unonames.hxx"
55 #include "document.hxx"
56 #include "AccessibleDocument.hxx"
57 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
58 #include <unotools/accessiblerelationsethelper.hxx>
59 #include <com/sun/star/accessibility/XAccessibleText.hpp>
60 using ::com::sun::star::lang::IndexOutOfBoundsException;
61 using ::com::sun::star::uno::RuntimeException;
62 using namespace ::com::sun::star;
63 using namespace ::com::sun::star::accessibility;
64 
65 //=====  internal  ============================================================
66 
ScAccessibleEditObject(const uno::Reference<XAccessible> & rxParent,EditView * pEditView,Window * pWin,const rtl::OUString & rName,const rtl::OUString & rDescription,EditObjectType eObjectType)67 ScAccessibleEditObject::ScAccessibleEditObject(
68         const uno::Reference<XAccessible>& rxParent,
69         EditView* pEditView, Window* pWin, const rtl::OUString& rName,
70         const rtl::OUString& rDescription, EditObjectType eObjectType)
71     :
72     ScAccessibleContextBase(rxParent, AccessibleRole::TEXT_FRAME),
73     mpTextHelper(NULL),
74     mpEditView(pEditView),
75     mpWindow(pWin),
76     meObjectType(eObjectType),
77     mbHasFocus(sal_False)
78 {
79     CreateTextHelper();
80     SetName(rName);
81     SetDescription(rDescription);
82     if( meObjectType == CellInEditMode)
83     {
84         const ScAccessibleDocument *pAccDoc = const_cast<ScAccessibleDocument*>(static_cast<ScAccessibleDocument*>(rxParent.get())) ;
85         if (pAccDoc)
86         {
87             m_pScDoc = pAccDoc->GetDocument();
88             m_curCellAddress =pAccDoc->GetCurCellAddress();
89         }
90         else
91         {
92             m_pScDoc=NULL;
93         }
94     }
95     else
96         m_pScDoc=NULL;
97 }
98 
~ScAccessibleEditObject()99 ScAccessibleEditObject::~ScAccessibleEditObject()
100 {
101     if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose)
102     {
103         // increment refcount to prevent double call off dtor
104         osl_incrementInterlockedCount( &m_refCount );
105         // call dispose to inform object which have a weak reference to this object
106         dispose();
107     }
108 }
109 
disposing()110 void SAL_CALL ScAccessibleEditObject::disposing()
111 {
112     ScUnoGuard aGuard;
113     if (mpTextHelper)
114         DELETEZ(mpTextHelper);
115 
116     ScAccessibleContextBase::disposing();
117 }
118 
LostFocus()119 void ScAccessibleEditObject::LostFocus()
120 {
121     mbHasFocus = sal_False;
122     if (mpTextHelper)
123         mpTextHelper->SetFocus(sal_False);
124     CommitFocusLost();
125 }
126 
GotFocus()127 void ScAccessibleEditObject::GotFocus()
128 {
129     mbHasFocus = sal_True;
130     CommitFocusGained();
131     if (mpTextHelper)
132         mpTextHelper->SetFocus(sal_True);
133 }
134 
135 //=====  XInterface  ==========================================================
136 
137 com::sun::star::uno::Any SAL_CALL
queryInterface(const com::sun::star::uno::Type & rType)138     ScAccessibleEditObject::queryInterface (const com::sun::star::uno::Type & rType)
139 {
140     ::com::sun::star::uno::Any aReturn = ScAccessibleContextBase::queryInterface (rType);
141     if ( ! aReturn.hasValue())
142         aReturn = ::cppu::queryInterface (rType,
143             static_cast< ::com::sun::star::accessibility::XAccessibleSelection* >(this)
144             );
145     return aReturn;
146 }
147 void SAL_CALL
acquire(void)148     ScAccessibleEditObject::acquire (void)
149     throw ()
150 {
151     ScAccessibleContextBase::acquire ();
152 }
153 void SAL_CALL
release(void)154     ScAccessibleEditObject::release (void)
155     throw ()
156 {
157     ScAccessibleContextBase::release ();
158 }
159     //=====  XAccessibleComponent  ============================================
160 
getAccessibleAtPoint(const awt::Point & rPoint)161 uno::Reference< XAccessible > SAL_CALL ScAccessibleEditObject::getAccessibleAtPoint(
162         const awt::Point& rPoint )
163 {
164     uno::Reference<XAccessible> xRet;
165     if (containsPoint(rPoint))
166     {
167         ScUnoGuard aGuard;
168         IsObjectValid();
169 
170         if(!mpTextHelper)
171             CreateTextHelper();
172 
173         xRet = mpTextHelper->GetAt(rPoint);
174     }
175 
176     return xRet;
177 }
178 
GetBoundingBoxOnScreen(void) const179 Rectangle ScAccessibleEditObject::GetBoundingBoxOnScreen(void) const
180 {
181     Rectangle aScreenBounds;
182 
183     if ( mpWindow )
184     {
185         if ( meObjectType == CellInEditMode )
186         {
187             if ( mpEditView && mpEditView->GetEditEngine() )
188             {
189                 MapMode aMapMode( mpEditView->GetEditEngine()->GetRefMapMode() );
190                 aScreenBounds = mpWindow->LogicToPixel( mpEditView->GetOutputArea(), aMapMode );
191                 Point aCellLoc = aScreenBounds.TopLeft();
192                 Rectangle aWindowRect = mpWindow->GetWindowExtentsRelative( NULL );
193                 Point aWindowLoc = aWindowRect.TopLeft();
194                 Point aPos( aCellLoc.getX() + aWindowLoc.getX(), aCellLoc.getY() + aWindowLoc.getY() );
195                 aScreenBounds.SetPos( aPos );
196             }
197         }
198         else
199         {
200             aScreenBounds = mpWindow->GetWindowExtentsRelative( NULL );
201         }
202     }
203 
204     return aScreenBounds;
205 }
206 
GetBoundingBox(void) const207 Rectangle ScAccessibleEditObject::GetBoundingBox(void) const
208 {
209     Rectangle aBounds( GetBoundingBoxOnScreen() );
210 
211     if ( mpWindow )
212     {
213         uno::Reference< XAccessible > xThis( mpWindow->GetAccessible() );
214         if ( xThis.is() )
215         {
216             uno::Reference< XAccessibleContext > xContext( xThis->getAccessibleContext() );
217             if ( xContext.is() )
218             {
219                 uno::Reference< XAccessible > xParent( xContext->getAccessibleParent() );
220                 if ( xParent.is() )
221                 {
222                     uno::Reference< XAccessibleComponent > xParentComponent( xParent->getAccessibleContext(), uno::UNO_QUERY );
223                     if ( xParentComponent.is() )
224                     {
225                         Point aScreenLoc = aBounds.TopLeft();
226                         awt::Point aParentScreenLoc = xParentComponent->getLocationOnScreen();
227                         Point aPos( aScreenLoc.getX() - aParentScreenLoc.X, aScreenLoc.getY() - aParentScreenLoc.Y );
228                         aBounds.SetPos( aPos );
229                     }
230                 }
231             }
232         }
233     }
234 
235     return aBounds;
236 }
237 
238     //=====  XAccessibleContext  ==============================================
239 
240 sal_Int32 SAL_CALL
getAccessibleChildCount(void)241     ScAccessibleEditObject::getAccessibleChildCount(void)
242 {
243     ScUnoGuard aGuard;
244     IsObjectValid();
245     if (!mpTextHelper)
246         CreateTextHelper();
247     return mpTextHelper->GetChildCount();
248 }
249 
250 uno::Reference< XAccessible > SAL_CALL
getAccessibleChild(sal_Int32 nIndex)251     ScAccessibleEditObject::getAccessibleChild(sal_Int32 nIndex)
252 {
253     ScUnoGuard aGuard;
254     IsObjectValid();
255     if (!mpTextHelper)
256         CreateTextHelper();
257     return mpTextHelper->GetChild(nIndex);
258 }
259 
260 uno::Reference<XAccessibleStateSet> SAL_CALL
getAccessibleStateSet(void)261     ScAccessibleEditObject::getAccessibleStateSet(void)
262 {
263     ScUnoGuard aGuard;
264     uno::Reference<XAccessibleStateSet> xParentStates;
265     if (getAccessibleParent().is())
266     {
267         uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
268         xParentStates = xParentContext->getAccessibleStateSet();
269     }
270     utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper();
271     if (IsDefunc(xParentStates))
272         pStateSet->AddState(AccessibleStateType::DEFUNC);
273     else
274     {
275         // all states are const, because this object exists only in one state
276         pStateSet->AddState(AccessibleStateType::EDITABLE);
277         pStateSet->AddState(AccessibleStateType::ENABLED);
278         pStateSet->AddState(AccessibleStateType::SENSITIVE);
279         pStateSet->AddState(AccessibleStateType::MULTI_LINE);
280         pStateSet->AddState(AccessibleStateType::MULTI_SELECTABLE);
281         pStateSet->AddState(AccessibleStateType::SHOWING);
282         pStateSet->AddState(AccessibleStateType::VISIBLE);
283     }
284     return pStateSet;
285 }
286 
287 ::rtl::OUString SAL_CALL
createAccessibleDescription(void)288     ScAccessibleEditObject::createAccessibleDescription(void)
289 {
290 //    DBG_ERRORFILE("Should never be called, because is set in the constructor.")
291     return rtl::OUString();
292 }
293 
294 ::rtl::OUString SAL_CALL
createAccessibleName(void)295     ScAccessibleEditObject::createAccessibleName(void)
296 {
297     DBG_ERRORFILE("Should never be called, because is set in the constructor.");
298     return rtl::OUString();
299 }
300 
301     ///=====  XAccessibleEventBroadcaster  =====================================
302 
303 void SAL_CALL
addEventListener(const uno::Reference<XAccessibleEventListener> & xListener)304     ScAccessibleEditObject::addEventListener(const uno::Reference<XAccessibleEventListener>& xListener)
305 {
306     if (!mpTextHelper)
307         CreateTextHelper();
308 
309     mpTextHelper->AddEventListener(xListener);
310 
311     ScAccessibleContextBase::addEventListener(xListener);
312 }
313 
314 void SAL_CALL
removeEventListener(const uno::Reference<XAccessibleEventListener> & xListener)315     ScAccessibleEditObject::removeEventListener(const uno::Reference<XAccessibleEventListener>& xListener)
316 {
317     if (!mpTextHelper)
318         CreateTextHelper();
319 
320     mpTextHelper->RemoveEventListener(xListener);
321 
322     ScAccessibleContextBase::removeEventListener(xListener);
323 }
324 
325     //=====  XServiceInfo  ====================================================
326 
getImplementationName(void)327 ::rtl::OUString SAL_CALL ScAccessibleEditObject::getImplementationName(void)
328 {
329     return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleEditObject"));
330 }
331 
332 //=====  XTypeProvider  =======================================================
333 
334 uno::Sequence<sal_Int8> SAL_CALL
getImplementationId(void)335     ScAccessibleEditObject::getImplementationId(void)
336 {
337     ScUnoGuard aGuard;
338     IsObjectValid();
339     static uno::Sequence<sal_Int8> aId;
340     if (aId.getLength() == 0)
341     {
342         aId.realloc (16);
343         rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True);
344     }
345     return aId;
346 }
347 
348     //====  internal  =========================================================
349 
IsDefunc(const uno::Reference<XAccessibleStateSet> & rxParentStates)350 sal_Bool ScAccessibleEditObject::IsDefunc(
351     const uno::Reference<XAccessibleStateSet>& rxParentStates)
352 {
353     return ScAccessibleContextBase::IsDefunc() || !getAccessibleParent().is() ||
354          (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC));
355 }
356 
CreateTextHelper()357 void ScAccessibleEditObject::CreateTextHelper()
358 {
359     if (!mpTextHelper)
360     {
361         ::std::auto_ptr < ScAccessibleTextData > pAccessibleTextData;
362         if (meObjectType == CellInEditMode || meObjectType == EditControl)
363         {
364             pAccessibleTextData.reset
365                 (new ScAccessibleEditObjectTextData(mpEditView, mpWindow));
366         }
367         else
368         {
369             pAccessibleTextData.reset
370                 (new ScAccessibleEditLineTextData(NULL, mpWindow));
371         }
372 
373         ::std::auto_ptr< SvxEditSource > pEditSource (new ScAccessibilityEditSource(pAccessibleTextData));
374         mpTextHelper = new ::accessibility::AccessibleTextHelper(pEditSource );
375         mpTextHelper->SetEventSource(this);
376         mpTextHelper->SetFocus(mbHasFocus);
377 
378         // #i54814# activate cell in edit mode
379         if( meObjectType == CellInEditMode )
380         {
381             // do not activate cell object, if top edit line is active
382             const ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl();
383             if( pInputHdl && !pInputHdl->IsTopMode() )
384             {
385                 SdrHint aHint( HINT_BEGEDIT );
386                 mpTextHelper->GetEditSource().GetBroadcaster().Broadcast( aHint );
387             }
388         }
389     }
390 }
getForeground()391 sal_Int32 SAL_CALL ScAccessibleEditObject::getForeground(  )
392 {
393     return GetFgBgColor(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_CCOLOR)));
394 }
395 
getBackground()396 sal_Int32 SAL_CALL ScAccessibleEditObject::getBackground(  )
397 {
398     return GetFgBgColor(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_CELLBACK)));
399 }
GetFgBgColor(const rtl::OUString & strPropColor)400 sal_Int32 ScAccessibleEditObject::GetFgBgColor( const rtl::OUString &strPropColor)
401 {
402     ScUnoGuard aGuard;
403     sal_Int32 nColor(0);
404     if (m_pScDoc)
405     {
406         SfxObjectShell* pObjSh = m_pScDoc->GetDocumentShell();
407         if ( pObjSh )
408         {
409             uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( pObjSh->GetModel(), uno::UNO_QUERY );
410             if ( xSpreadDoc.is() )
411             {
412                 uno::Reference<sheet::XSpreadsheets> xSheets = xSpreadDoc->getSheets();
413                 uno::Reference<container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY );
414                 if ( xIndex.is() )
415                 {
416                     uno::Any aTable = xIndex->getByIndex(m_curCellAddress.Tab());
417                     uno::Reference<sheet::XSpreadsheet> xTable;
418                     if (aTable>>=xTable)
419                     {
420                         uno::Reference<table::XCell> xCell = xTable->getCellByPosition(m_curCellAddress.Col(), m_curCellAddress.Row());
421                         if (xCell.is())
422                         {
423                             uno::Reference<beans::XPropertySet> xCellProps(xCell, uno::UNO_QUERY);
424                             if (xCellProps.is())
425                             {
426                                 uno::Any aAny = xCellProps->getPropertyValue(strPropColor);
427                                 aAny >>= nColor;
428                             }
429                         }
430                     }
431                 }
432             }
433         }
434     }
435     return nColor;
436 }
437 //=====  XAccessibleSelection  ============================================
438 //--------------------------------------------------------------------------------
selectAccessibleChild(sal_Int32)439 void SAL_CALL ScAccessibleEditObject::selectAccessibleChild( sal_Int32 )
440 {
441 }
442 //----------------------------------------------------------------------------------
isAccessibleChildSelected(sal_Int32 nChildIndex)443 sal_Bool SAL_CALL ScAccessibleEditObject::isAccessibleChildSelected( sal_Int32 nChildIndex )
444 {
445     uno::Reference<XAccessible> xAcc = getAccessibleChild( nChildIndex );
446     uno::Reference<XAccessibleContext> xContext;
447     if( xAcc.is() )
448         xContext = xAcc->getAccessibleContext();
449     if( xContext.is() )
450     {
451         if( xContext->getAccessibleRole() == AccessibleRole::PARAGRAPH )
452         {
453             uno::Reference< ::com::sun::star::accessibility::XAccessibleText >
454                 xText(xAcc, uno::UNO_QUERY);
455             if( xText.is() )
456             {
457                 if( xText->getSelectionStart() >= 0 ) return sal_True;
458             }
459         }
460     }
461     return sal_False;
462 }
463 //---------------------------------------------------------------------
clearAccessibleSelection()464 void SAL_CALL ScAccessibleEditObject::clearAccessibleSelection(  )
465 {
466 }
467 //-------------------------------------------------------------------------
selectAllAccessibleChildren()468 void SAL_CALL ScAccessibleEditObject::selectAllAccessibleChildren(  )
469 {
470 }
471 //----------------------------------------------------------------------------
getSelectedAccessibleChildCount()472 sal_Int32 SAL_CALL ScAccessibleEditObject::getSelectedAccessibleChildCount()
473 {
474     sal_Int32 nCount = 0;
475     sal_Int32 TotalCount = getAccessibleChildCount();
476     for( sal_Int32 i = 0; i < TotalCount; i++ )
477         if( isAccessibleChildSelected(i) ) nCount++;
478     return nCount;
479 }
480 //--------------------------------------------------------------------------------------
getSelectedAccessibleChild(sal_Int32 nSelectedChildIndex)481 uno::Reference<XAccessible> SAL_CALL ScAccessibleEditObject::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex )
482 {
483     if ( nSelectedChildIndex > getSelectedAccessibleChildCount() )
484         throw IndexOutOfBoundsException();
485     sal_Int32 i1, i2;
486     for( i1 = 0, i2 = 0; i1 < getAccessibleChildCount(); i1++ )
487         if( isAccessibleChildSelected(i1) )
488         {
489             if( i2 == nSelectedChildIndex )
490                 return getAccessibleChild( i1 );
491             i2++;
492         }
493     return uno::Reference<XAccessible>();
494 }
495 //----------------------------------------------------------------------------------
deselectAccessibleChild(sal_Int32)496 void SAL_CALL ScAccessibleEditObject::deselectAccessibleChild(
497                                                             sal_Int32 )
498 {
499 }
getAccessibleRelationSet()500 uno::Reference< XAccessibleRelationSet > ScAccessibleEditObject::getAccessibleRelationSet(  )
501 {
502        ScUnoGuard aGuard;
503     Window* pWindow = mpWindow;
504     utl::AccessibleRelationSetHelper* rRelationSet = new utl::AccessibleRelationSetHelper;
505     uno::Reference< XAccessibleRelationSet > rSet = rRelationSet;
506     if ( pWindow )
507     {
508         Window *pLabeledBy = pWindow->GetAccessibleRelationLabeledBy();
509         if ( pLabeledBy && pLabeledBy != pWindow )
510         {
511             uno::Sequence< uno::Reference< uno::XInterface > > aSequence(1);
512             aSequence[0] = pLabeledBy->GetAccessible();
513             rRelationSet->AddRelation( AccessibleRelation( AccessibleRelationType::LABELED_BY, aSequence ) );
514         }
515         Window* pMemberOf = pWindow->GetAccessibleRelationMemberOf();
516         if ( pMemberOf && pMemberOf != pWindow )
517         {
518             uno::Sequence< uno::Reference< uno::XInterface > > aSequence(1);
519             aSequence[0] = pMemberOf->GetAccessible();
520             rRelationSet->AddRelation( AccessibleRelation( AccessibleRelationType::MEMBER_OF, aSequence ) );
521         }
522         return rSet;
523     }
524     return uno::Reference< XAccessibleRelationSet >();
525 }
526