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