1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 #include "AccessibleEditObject.hxx"
31 #include "scitems.hxx"
32 #include <editeng/eeitem.hxx>
33 #include "unoguard.hxx"
34 #include "AccessibleText.hxx"
35 #include "editsrc.hxx"
36 #include "scmod.hxx"
37 #include "inputhdl.hxx"
38 
39 #ifndef _UTL_ACCESSIBLESTATESETHELPER_HXX
40 #include <unotools/accessiblestatesethelper.hxx>
41 #endif
42 #ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEROLE_HPP_
43 #include <com/sun/star/accessibility/AccessibleRole.hpp>
44 #endif
45 #ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLESTATETYPE_HPP_
46 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
47 #endif
48 #include <rtl/uuid.h>
49 #include <tools/debug.hxx>
50 #include <svx/AccessibleTextHelper.hxx>
51 #include <editeng/editview.hxx>
52 #include <editeng/editeng.hxx>
53 #include <svx/svdmodel.hxx>
54 
55 using namespace	::com::sun::star;
56 using namespace	::com::sun::star::accessibility;
57 
58 //=====  internal  ============================================================
59 
60 ScAccessibleEditObject::ScAccessibleEditObject(
61         const uno::Reference<XAccessible>& rxParent,
62         EditView* pEditView, Window* pWin, const rtl::OUString& rName,
63         const rtl::OUString& rDescription, EditObjectType eObjectType)
64 	:
65     ScAccessibleContextBase(rxParent, AccessibleRole::TEXT_FRAME),
66 	mpTextHelper(NULL),
67     mpEditView(pEditView),
68     mpWindow(pWin),
69     meObjectType(eObjectType),
70     mbHasFocus(sal_False)
71 {
72     CreateTextHelper();
73     SetName(rName);
74     SetDescription(rDescription);
75 }
76 
77 ScAccessibleEditObject::~ScAccessibleEditObject()
78 {
79 	if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose)
80 	{
81 		// increment refcount to prevent double call off dtor
82 		osl_incrementInterlockedCount( &m_refCount );
83 		// call dispose to inform object wich have a weak reference to this object
84 		dispose();
85 	}
86 }
87 
88 void SAL_CALL ScAccessibleEditObject::disposing()
89 {
90     ScUnoGuard aGuard;
91 	if (mpTextHelper)
92 		DELETEZ(mpTextHelper);
93 
94 	ScAccessibleContextBase::disposing();
95 }
96 
97 void ScAccessibleEditObject::LostFocus()
98 {
99     mbHasFocus = sal_False;
100     if (mpTextHelper)
101         mpTextHelper->SetFocus(sal_False);
102     CommitFocusLost();
103 }
104 
105 void ScAccessibleEditObject::GotFocus()
106 {
107     mbHasFocus = sal_True;
108     CommitFocusGained();
109     if (mpTextHelper)
110         mpTextHelper->SetFocus(sal_True);
111 }
112 
113 	//=====  XAccessibleComponent  ============================================
114 
115 uno::Reference< XAccessible > SAL_CALL ScAccessibleEditObject::getAccessibleAtPoint(
116 		const awt::Point& rPoint )
117 		throw (uno::RuntimeException)
118 {
119     uno::Reference<XAccessible> xRet;
120     if (containsPoint(rPoint))
121     {
122  	    ScUnoGuard aGuard;
123         IsObjectValid();
124 
125     	if(!mpTextHelper)
126 	    	CreateTextHelper();
127 
128         xRet = mpTextHelper->GetAt(rPoint);
129     }
130 
131     return xRet;
132 }
133 
134 Rectangle ScAccessibleEditObject::GetBoundingBoxOnScreen(void) const
135 		throw (uno::RuntimeException)
136 {
137     Rectangle aScreenBounds;
138 
139     if ( mpWindow )
140     {
141         if ( meObjectType == CellInEditMode )
142         {
143             if ( mpEditView && mpEditView->GetEditEngine() )
144             {
145                 MapMode aMapMode( mpEditView->GetEditEngine()->GetRefMapMode() );
146                 aScreenBounds = mpWindow->LogicToPixel( mpEditView->GetOutputArea(), aMapMode );
147                 Point aCellLoc = aScreenBounds.TopLeft();
148                 Rectangle aWindowRect = mpWindow->GetWindowExtentsRelative( NULL );
149                 Point aWindowLoc = aWindowRect.TopLeft();
150                 Point aPos( aCellLoc.getX() + aWindowLoc.getX(), aCellLoc.getY() + aWindowLoc.getY() );
151                 aScreenBounds.SetPos( aPos );
152             }
153         }
154         else
155         {
156             aScreenBounds = mpWindow->GetWindowExtentsRelative( NULL );
157         }
158     }
159 
160 	return aScreenBounds;
161 }
162 
163 Rectangle ScAccessibleEditObject::GetBoundingBox(void) const
164 		throw (uno::RuntimeException)
165 {
166     Rectangle aBounds( GetBoundingBoxOnScreen() );
167 
168     if ( mpWindow )
169     {
170         uno::Reference< XAccessible > xThis( mpWindow->GetAccessible() );
171         if ( xThis.is() )
172         {
173             uno::Reference< XAccessibleContext > xContext( xThis->getAccessibleContext() );
174             if ( xContext.is() )
175             {
176                 uno::Reference< XAccessible > xParent( xContext->getAccessibleParent() );
177                 if ( xParent.is() )
178                 {
179                     uno::Reference< XAccessibleComponent > xParentComponent( xParent->getAccessibleContext(), uno::UNO_QUERY );
180 		            if ( xParentComponent.is() )
181 		            {
182                         Point aScreenLoc = aBounds.TopLeft();
183 			            awt::Point aParentScreenLoc = xParentComponent->getLocationOnScreen();
184                         Point aPos( aScreenLoc.getX() - aParentScreenLoc.X, aScreenLoc.getY() - aParentScreenLoc.Y );
185 			            aBounds.SetPos( aPos );
186 		            }
187                 }
188             }
189         }
190     }
191 
192 	return aBounds;
193 }
194 
195 	//=====  XAccessibleContext  ==============================================
196 
197 sal_Int32 SAL_CALL
198 	ScAccessibleEditObject::getAccessibleChildCount(void)
199     				throw (uno::RuntimeException)
200 {
201 	ScUnoGuard aGuard;
202     IsObjectValid();
203 	if (!mpTextHelper)
204 		CreateTextHelper();
205 	return mpTextHelper->GetChildCount();
206 }
207 
208 uno::Reference< XAccessible > SAL_CALL
209 	ScAccessibleEditObject::getAccessibleChild(sal_Int32 nIndex)
210         throw (uno::RuntimeException,
211 		lang::IndexOutOfBoundsException)
212 {
213 	ScUnoGuard aGuard;
214     IsObjectValid();
215 	if (!mpTextHelper)
216 		CreateTextHelper();
217 	return mpTextHelper->GetChild(nIndex);
218 }
219 
220 uno::Reference<XAccessibleStateSet> SAL_CALL
221 	ScAccessibleEditObject::getAccessibleStateSet(void)
222     throw (uno::RuntimeException)
223 {
224 	ScUnoGuard aGuard;
225 	uno::Reference<XAccessibleStateSet> xParentStates;
226 	if (getAccessibleParent().is())
227 	{
228 		uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
229 		xParentStates = xParentContext->getAccessibleStateSet();
230 	}
231 	utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper();
232 	if (IsDefunc(xParentStates))
233 		pStateSet->AddState(AccessibleStateType::DEFUNC);
234     else
235     {
236         // all states are const, because this object exists only in one state
237 		pStateSet->AddState(AccessibleStateType::EDITABLE);
238 	    pStateSet->AddState(AccessibleStateType::ENABLED);
239         pStateSet->AddState(AccessibleStateType::SENSITIVE);
240 	    pStateSet->AddState(AccessibleStateType::MULTI_LINE);
241 	    pStateSet->AddState(AccessibleStateType::MULTI_SELECTABLE);
242 		pStateSet->AddState(AccessibleStateType::SHOWING);
243 		pStateSet->AddState(AccessibleStateType::VISIBLE);
244     }
245 	return pStateSet;
246 }
247 
248 ::rtl::OUString SAL_CALL
249     ScAccessibleEditObject::createAccessibleDescription(void)
250     throw (uno::RuntimeException)
251 {
252 //    DBG_ERRORFILE("Should never be called, because is set in the constructor.")
253     return rtl::OUString();
254 }
255 
256 ::rtl::OUString SAL_CALL
257     ScAccessibleEditObject::createAccessibleName(void)
258     throw (uno::RuntimeException)
259 {
260     DBG_ERRORFILE("Should never be called, because is set in the constructor.");
261     return rtl::OUString();
262 }
263 
264 	///=====  XAccessibleEventBroadcaster  =====================================
265 
266 void SAL_CALL
267     ScAccessibleEditObject::addEventListener(const uno::Reference<XAccessibleEventListener>& xListener)
268         throw (uno::RuntimeException)
269 {
270     if (!mpTextHelper)
271         CreateTextHelper();
272 
273     mpTextHelper->AddEventListener(xListener);
274 
275     ScAccessibleContextBase::addEventListener(xListener);
276 }
277 
278 void SAL_CALL
279     ScAccessibleEditObject::removeEventListener(const uno::Reference<XAccessibleEventListener>& xListener)
280         throw (uno::RuntimeException)
281 {
282     if (!mpTextHelper)
283         CreateTextHelper();
284 
285     mpTextHelper->RemoveEventListener(xListener);
286 
287     ScAccessibleContextBase::removeEventListener(xListener);
288 }
289 
290     //=====  XServiceInfo  ====================================================
291 
292 ::rtl::OUString SAL_CALL ScAccessibleEditObject::getImplementationName(void)
293         throw (uno::RuntimeException)
294 {
295 	return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleEditObject"));
296 }
297 
298 //=====  XTypeProvider  =======================================================
299 
300 uno::Sequence<sal_Int8> SAL_CALL
301 	ScAccessibleEditObject::getImplementationId(void)
302     throw (uno::RuntimeException)
303 {
304     ScUnoGuard aGuard;
305     IsObjectValid();
306 	static uno::Sequence<sal_Int8> aId;
307 	if (aId.getLength() == 0)
308 	{
309 		aId.realloc (16);
310 		rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True);
311 	}
312 	return aId;
313 }
314 
315 	//====  internal  =========================================================
316 
317 sal_Bool ScAccessibleEditObject::IsDefunc(
318 	const uno::Reference<XAccessibleStateSet>& rxParentStates)
319 {
320 	return ScAccessibleContextBase::IsDefunc() || !getAccessibleParent().is() ||
321 		 (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC));
322 }
323 
324 void ScAccessibleEditObject::CreateTextHelper()
325 {
326 	if (!mpTextHelper)
327 	{
328         ::std::auto_ptr < ScAccessibleTextData > pAccessibleTextData;
329         if (meObjectType == CellInEditMode || meObjectType == EditControl)
330         {
331             pAccessibleTextData.reset
332 			    (new ScAccessibleEditObjectTextData(mpEditView, mpWindow));
333         }
334         else
335         {
336             pAccessibleTextData.reset
337 			    (new ScAccessibleEditLineTextData(NULL, mpWindow));
338         }
339 
340         ::std::auto_ptr< SvxEditSource > pEditSource (new ScAccessibilityEditSource(pAccessibleTextData));
341         mpTextHelper = new ::accessibility::AccessibleTextHelper(pEditSource );
342         mpTextHelper->SetEventSource(this);
343         mpTextHelper->SetFocus(mbHasFocus);
344 
345         // #i54814# activate cell in edit mode
346         if( meObjectType == CellInEditMode )
347         {
348             // do not activate cell object, if top edit line is active
349             const ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl();
350             if( pInputHdl && !pInputHdl->IsTopMode() )
351             {
352                 SdrHint aHint( HINT_BEGEDIT );
353                 mpTextHelper->GetEditSource().GetBroadcaster().Broadcast( aHint );
354             }
355         }
356     }
357 }
358 
359