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 
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 
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 wich have a weak reference to this object
106 		dispose();
107 	}
108 }
109 
110 void SAL_CALL ScAccessibleEditObject::disposing()
111 {
112     ScUnoGuard aGuard;
113 	if (mpTextHelper)
114 		DELETEZ(mpTextHelper);
115 
116 	ScAccessibleContextBase::disposing();
117 }
118 
119 void ScAccessibleEditObject::LostFocus()
120 {
121     mbHasFocus = sal_False;
122     if (mpTextHelper)
123         mpTextHelper->SetFocus(sal_False);
124     CommitFocusLost();
125 }
126 
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
138     ScAccessibleEditObject::queryInterface (const com::sun::star::uno::Type & rType)
139     throw (::com::sun::star::uno::RuntimeException)
140 {
141     ::com::sun::star::uno::Any aReturn = ScAccessibleContextBase::queryInterface (rType);
142     if ( ! aReturn.hasValue())
143         aReturn = ::cppu::queryInterface (rType,
144             static_cast< ::com::sun::star::accessibility::XAccessibleSelection* >(this)
145             );
146     return aReturn;
147 }
148 void SAL_CALL
149     ScAccessibleEditObject::acquire (void)
150     throw ()
151 {
152     ScAccessibleContextBase::acquire ();
153 }
154 void SAL_CALL
155     ScAccessibleEditObject::release (void)
156     throw ()
157 {
158     ScAccessibleContextBase::release ();
159 }
160 	//=====  XAccessibleComponent  ============================================
161 
162 uno::Reference< XAccessible > SAL_CALL ScAccessibleEditObject::getAccessibleAtPoint(
163 		const awt::Point& rPoint )
164 		throw (uno::RuntimeException)
165 {
166     uno::Reference<XAccessible> xRet;
167     if (containsPoint(rPoint))
168     {
169  	    ScUnoGuard aGuard;
170         IsObjectValid();
171 
172     	if(!mpTextHelper)
173 	    	CreateTextHelper();
174 
175         xRet = mpTextHelper->GetAt(rPoint);
176     }
177 
178     return xRet;
179 }
180 
181 Rectangle ScAccessibleEditObject::GetBoundingBoxOnScreen(void) const
182 		throw (uno::RuntimeException)
183 {
184     Rectangle aScreenBounds;
185 
186     if ( mpWindow )
187     {
188         if ( meObjectType == CellInEditMode )
189         {
190             if ( mpEditView && mpEditView->GetEditEngine() )
191             {
192                 MapMode aMapMode( mpEditView->GetEditEngine()->GetRefMapMode() );
193                 aScreenBounds = mpWindow->LogicToPixel( mpEditView->GetOutputArea(), aMapMode );
194                 Point aCellLoc = aScreenBounds.TopLeft();
195                 Rectangle aWindowRect = mpWindow->GetWindowExtentsRelative( NULL );
196                 Point aWindowLoc = aWindowRect.TopLeft();
197                 Point aPos( aCellLoc.getX() + aWindowLoc.getX(), aCellLoc.getY() + aWindowLoc.getY() );
198                 aScreenBounds.SetPos( aPos );
199             }
200         }
201         else
202         {
203             aScreenBounds = mpWindow->GetWindowExtentsRelative( NULL );
204         }
205     }
206 
207 	return aScreenBounds;
208 }
209 
210 Rectangle ScAccessibleEditObject::GetBoundingBox(void) const
211 		throw (uno::RuntimeException)
212 {
213     Rectangle aBounds( GetBoundingBoxOnScreen() );
214 
215     if ( mpWindow )
216     {
217         uno::Reference< XAccessible > xThis( mpWindow->GetAccessible() );
218         if ( xThis.is() )
219         {
220             uno::Reference< XAccessibleContext > xContext( xThis->getAccessibleContext() );
221             if ( xContext.is() )
222             {
223                 uno::Reference< XAccessible > xParent( xContext->getAccessibleParent() );
224                 if ( xParent.is() )
225                 {
226                     uno::Reference< XAccessibleComponent > xParentComponent( xParent->getAccessibleContext(), uno::UNO_QUERY );
227 		            if ( xParentComponent.is() )
228 		            {
229                         Point aScreenLoc = aBounds.TopLeft();
230 			            awt::Point aParentScreenLoc = xParentComponent->getLocationOnScreen();
231                         Point aPos( aScreenLoc.getX() - aParentScreenLoc.X, aScreenLoc.getY() - aParentScreenLoc.Y );
232 			            aBounds.SetPos( aPos );
233 		            }
234                 }
235             }
236         }
237     }
238 
239 	return aBounds;
240 }
241 
242 	//=====  XAccessibleContext  ==============================================
243 
244 sal_Int32 SAL_CALL
245 	ScAccessibleEditObject::getAccessibleChildCount(void)
246     				throw (uno::RuntimeException)
247 {
248 	ScUnoGuard aGuard;
249     IsObjectValid();
250 	if (!mpTextHelper)
251 		CreateTextHelper();
252 	return mpTextHelper->GetChildCount();
253 }
254 
255 uno::Reference< XAccessible > SAL_CALL
256 	ScAccessibleEditObject::getAccessibleChild(sal_Int32 nIndex)
257         throw (uno::RuntimeException,
258 		lang::IndexOutOfBoundsException)
259 {
260 	ScUnoGuard aGuard;
261     IsObjectValid();
262 	if (!mpTextHelper)
263 		CreateTextHelper();
264 	return mpTextHelper->GetChild(nIndex);
265 }
266 
267 uno::Reference<XAccessibleStateSet> SAL_CALL
268 	ScAccessibleEditObject::getAccessibleStateSet(void)
269     throw (uno::RuntimeException)
270 {
271 	ScUnoGuard aGuard;
272 	uno::Reference<XAccessibleStateSet> xParentStates;
273 	if (getAccessibleParent().is())
274 	{
275 		uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
276 		xParentStates = xParentContext->getAccessibleStateSet();
277 	}
278 	utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper();
279 	if (IsDefunc(xParentStates))
280 		pStateSet->AddState(AccessibleStateType::DEFUNC);
281     else
282     {
283         // all states are const, because this object exists only in one state
284 		pStateSet->AddState(AccessibleStateType::EDITABLE);
285 	    pStateSet->AddState(AccessibleStateType::ENABLED);
286         pStateSet->AddState(AccessibleStateType::SENSITIVE);
287 	    pStateSet->AddState(AccessibleStateType::MULTI_LINE);
288 	    pStateSet->AddState(AccessibleStateType::MULTI_SELECTABLE);
289 		pStateSet->AddState(AccessibleStateType::SHOWING);
290 		pStateSet->AddState(AccessibleStateType::VISIBLE);
291     }
292 	return pStateSet;
293 }
294 
295 ::rtl::OUString SAL_CALL
296     ScAccessibleEditObject::createAccessibleDescription(void)
297     throw (uno::RuntimeException)
298 {
299 //    DBG_ERRORFILE("Should never be called, because is set in the constructor.")
300     return rtl::OUString();
301 }
302 
303 ::rtl::OUString SAL_CALL
304     ScAccessibleEditObject::createAccessibleName(void)
305     throw (uno::RuntimeException)
306 {
307     DBG_ERRORFILE("Should never be called, because is set in the constructor.");
308     return rtl::OUString();
309 }
310 
311 	///=====  XAccessibleEventBroadcaster  =====================================
312 
313 void SAL_CALL
314     ScAccessibleEditObject::addEventListener(const uno::Reference<XAccessibleEventListener>& xListener)
315         throw (uno::RuntimeException)
316 {
317     if (!mpTextHelper)
318         CreateTextHelper();
319 
320     mpTextHelper->AddEventListener(xListener);
321 
322     ScAccessibleContextBase::addEventListener(xListener);
323 }
324 
325 void SAL_CALL
326     ScAccessibleEditObject::removeEventListener(const uno::Reference<XAccessibleEventListener>& xListener)
327         throw (uno::RuntimeException)
328 {
329     if (!mpTextHelper)
330         CreateTextHelper();
331 
332     mpTextHelper->RemoveEventListener(xListener);
333 
334     ScAccessibleContextBase::removeEventListener(xListener);
335 }
336 
337     //=====  XServiceInfo  ====================================================
338 
339 ::rtl::OUString SAL_CALL ScAccessibleEditObject::getImplementationName(void)
340         throw (uno::RuntimeException)
341 {
342 	return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleEditObject"));
343 }
344 
345 //=====  XTypeProvider  =======================================================
346 
347 uno::Sequence<sal_Int8> SAL_CALL
348 	ScAccessibleEditObject::getImplementationId(void)
349     throw (uno::RuntimeException)
350 {
351     ScUnoGuard aGuard;
352     IsObjectValid();
353 	static uno::Sequence<sal_Int8> aId;
354 	if (aId.getLength() == 0)
355 	{
356 		aId.realloc (16);
357 		rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True);
358 	}
359 	return aId;
360 }
361 
362 	//====  internal  =========================================================
363 
364 sal_Bool ScAccessibleEditObject::IsDefunc(
365 	const uno::Reference<XAccessibleStateSet>& rxParentStates)
366 {
367 	return ScAccessibleContextBase::IsDefunc() || !getAccessibleParent().is() ||
368 		 (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC));
369 }
370 
371 void ScAccessibleEditObject::CreateTextHelper()
372 {
373 	if (!mpTextHelper)
374 	{
375         ::std::auto_ptr < ScAccessibleTextData > pAccessibleTextData;
376         if (meObjectType == CellInEditMode || meObjectType == EditControl)
377         {
378             pAccessibleTextData.reset
379 			    (new ScAccessibleEditObjectTextData(mpEditView, mpWindow));
380         }
381         else
382         {
383             pAccessibleTextData.reset
384 			    (new ScAccessibleEditLineTextData(NULL, mpWindow));
385         }
386 
387         ::std::auto_ptr< SvxEditSource > pEditSource (new ScAccessibilityEditSource(pAccessibleTextData));
388         mpTextHelper = new ::accessibility::AccessibleTextHelper(pEditSource );
389         mpTextHelper->SetEventSource(this);
390         mpTextHelper->SetFocus(mbHasFocus);
391 
392         // #i54814# activate cell in edit mode
393         if( meObjectType == CellInEditMode )
394         {
395             // do not activate cell object, if top edit line is active
396             const ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl();
397             if( pInputHdl && !pInputHdl->IsTopMode() )
398             {
399                 SdrHint aHint( HINT_BEGEDIT );
400                 mpTextHelper->GetEditSource().GetBroadcaster().Broadcast( aHint );
401             }
402         }
403     }
404 }
405 sal_Int32 SAL_CALL ScAccessibleEditObject::getForeground(  )
406         throw (::com::sun::star::uno::RuntimeException)
407 {
408 	return GetFgBgColor(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_CCOLOR)));
409 }
410 
411 sal_Int32 SAL_CALL ScAccessibleEditObject::getBackground(  )
412         throw (::com::sun::star::uno::RuntimeException)
413 {
414 	return GetFgBgColor(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_CELLBACK)));
415 }
416 sal_Int32 ScAccessibleEditObject::GetFgBgColor( const rtl::OUString &strPropColor)
417 {
418     ScUnoGuard aGuard;
419     sal_Int32 nColor(0);
420     if (m_pScDoc)
421     {
422         SfxObjectShell* pObjSh = m_pScDoc->GetDocumentShell();
423         if ( pObjSh )
424         {
425             uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( pObjSh->GetModel(), uno::UNO_QUERY );
426             if ( xSpreadDoc.is() )
427             {
428                 uno::Reference<sheet::XSpreadsheets> xSheets = xSpreadDoc->getSheets();
429                 uno::Reference<container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY );
430                 if ( xIndex.is() )
431                 {
432                     uno::Any aTable = xIndex->getByIndex(m_curCellAddress.Tab());
433                     uno::Reference<sheet::XSpreadsheet> xTable;
434                     if (aTable>>=xTable)
435                     {
436                         uno::Reference<table::XCell> xCell = xTable->getCellByPosition(m_curCellAddress.Col(), m_curCellAddress.Row());
437                         if (xCell.is())
438                         {
439                             uno::Reference<beans::XPropertySet> xCellProps(xCell, uno::UNO_QUERY);
440                             if (xCellProps.is())
441                             {
442                                 uno::Any aAny = xCellProps->getPropertyValue(strPropColor);
443                                 aAny >>= nColor;
444                             }
445                         }
446                     }
447                 }
448             }
449         }
450     }
451     return nColor;
452 }
453 //=====  XAccessibleSelection  ============================================
454 //--------------------------------------------------------------------------------
455 void SAL_CALL ScAccessibleEditObject::selectAccessibleChild( sal_Int32 )
456 throw ( IndexOutOfBoundsException, RuntimeException )
457 {
458 }
459 //----------------------------------------------------------------------------------
460 sal_Bool SAL_CALL ScAccessibleEditObject::isAccessibleChildSelected( sal_Int32 nChildIndex )
461 throw ( IndexOutOfBoundsException,
462 	   RuntimeException )
463 {
464 	uno::Reference<XAccessible> xAcc = getAccessibleChild( nChildIndex );
465 	uno::Reference<XAccessibleContext> xContext;
466 	if( xAcc.is() )
467 		xContext = xAcc->getAccessibleContext();
468 	if( xContext.is() )
469 	{
470 		if( xContext->getAccessibleRole() == AccessibleRole::PARAGRAPH )
471 		{
472 			uno::Reference< ::com::sun::star::accessibility::XAccessibleText >
473 				xText(xAcc, uno::UNO_QUERY);
474 			if( xText.is() )
475 			{
476 				if( xText->getSelectionStart() >= 0 ) return sal_True;
477 			}
478 		}
479 	}
480 	return sal_False;
481 }
482 //---------------------------------------------------------------------
483 void SAL_CALL ScAccessibleEditObject::clearAccessibleSelection(  )
484 throw ( RuntimeException )
485 {
486 }
487 //-------------------------------------------------------------------------
488 void SAL_CALL ScAccessibleEditObject::selectAllAccessibleChildren(  )
489 throw ( RuntimeException )
490 {
491 }
492 //----------------------------------------------------------------------------
493 sal_Int32 SAL_CALL ScAccessibleEditObject::getSelectedAccessibleChildCount()
494 throw ( RuntimeException )
495 {
496 	sal_Int32 nCount = 0;
497 	sal_Int32 TotalCount = getAccessibleChildCount();
498 	for( sal_Int32 i = 0; i < TotalCount; i++ )
499 		if( isAccessibleChildSelected(i) ) nCount++;
500 	return nCount;
501 }
502 //--------------------------------------------------------------------------------------
503 uno::Reference<XAccessible> SAL_CALL ScAccessibleEditObject::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex )
504 throw ( IndexOutOfBoundsException, RuntimeException)
505 {
506 	if ( nSelectedChildIndex > getSelectedAccessibleChildCount() )
507 		throw IndexOutOfBoundsException();
508 	sal_Int32 i1, i2;
509 	for( i1 = 0, i2 = 0; i1 < getAccessibleChildCount(); i1++ )
510 		if( isAccessibleChildSelected(i1) )
511 		{
512 			if( i2 == nSelectedChildIndex )
513 				return getAccessibleChild( i1 );
514 			i2++;
515 		}
516 	return uno::Reference<XAccessible>();
517 }
518 //----------------------------------------------------------------------------------
519 void SAL_CALL ScAccessibleEditObject::deselectAccessibleChild(
520 															sal_Int32 )
521 															throw ( IndexOutOfBoundsException,
522 															RuntimeException )
523 {
524 }
525 uno::Reference< XAccessibleRelationSet > ScAccessibleEditObject::getAccessibleRelationSet(  )
526     throw (uno::RuntimeException)
527 {
528        ScUnoGuard aGuard;
529 	Window* pWindow = mpWindow;
530 	utl::AccessibleRelationSetHelper* rRelationSet = new utl::AccessibleRelationSetHelper;
531 	uno::Reference< XAccessibleRelationSet > rSet = rRelationSet;
532 	if ( pWindow )
533 	{
534 		Window *pLabeledBy = pWindow->GetAccessibleRelationLabeledBy();
535 		if ( pLabeledBy && pLabeledBy != pWindow )
536 		{
537 			uno::Sequence< uno::Reference< uno::XInterface > > aSequence(1);
538 			aSequence[0] = pLabeledBy->GetAccessible();
539 			rRelationSet->AddRelation( AccessibleRelation( AccessibleRelationType::LABELED_BY, aSequence ) );
540 		}
541 		Window* pMemberOf = pWindow->GetAccessibleRelationMemberOf();
542 		if ( pMemberOf && pMemberOf != pWindow )
543 		{
544 			uno::Sequence< uno::Reference< uno::XInterface > > aSequence(1);
545 			aSequence[0] = pMemberOf->GetAccessible();
546 			rRelationSet->AddRelation( AccessibleRelation( AccessibleRelationType::MEMBER_OF, aSequence ) );
547 		}
548 		return rSet;
549 	}
550 	return uno::Reference< XAccessibleRelationSet >();
551 }
552 
553