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 <svx/AccessibleShape.hxx>
21 : #include "svx/DescriptionGenerator.hxx"
22 : #include <svx/AccessibleShapeInfo.hxx>
23 : #include <com/sun/star/view/XSelectionSupplier.hpp>
24 : #include <com/sun/star/accessibility/AccessibleRole.hpp>
25 : #include <com/sun/star/accessibility/AccessibleStateType.hpp>
26 : #include <com/sun/star/beans/XPropertySet.hpp>
27 : #include <com/sun/star/container/XChild.hpp>
28 : #include <com/sun/star/drawing/XShapes.hpp>
29 : #include <com/sun/star/drawing/XShapeDescriptor.hpp>
30 : #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
31 : #include <com/sun/star/drawing/FillStyle.hpp>
32 : #include <com/sun/star/text/XText.hpp>
33 : #include <editeng/outlobj.hxx>
34 : #include <rtl/ref.hxx>
35 : #include <editeng/unoedsrc.hxx>
36 : #include <svx/unoshtxt.hxx>
37 : #include <svx/svdobj.hxx>
38 : #include <svx/svdmodel.hxx>
39 : #include "svx/unoapi.hxx"
40 : #include <com/sun/star/uno/Exception.hpp>
41 : #include <svx/ShapeTypeHandler.hxx>
42 : #include <svx/SvxShapeTypes.hxx>
43 :
44 : #include "accessibility.hrc"
45 : #include "svx/svdstr.hrc"
46 : #include <svx/dialmgr.hxx>
47 : #include <vcl/svapp.hxx>
48 : #include <unotools/accessiblestatesethelper.hxx>
49 : #include <svx/svdview.hxx>
50 : #include <comphelper/servicehelper.hxx>
51 : #include "AccessibleEmptyEditSource.hxx"
52 :
53 : using namespace ::com::sun::star;
54 : using namespace ::com::sun::star::accessibility;
55 : using ::com::sun::star::uno::Reference;
56 : using ::rtl::OUString;
57 :
58 : namespace accessibility {
59 :
60 : namespace {
61 :
62 0 : OUString GetOptionalProperty (
63 : const Reference<beans::XPropertySet>& rxSet,
64 : const OUString& rsPropertyName)
65 : {
66 0 : OUString sValue;
67 :
68 0 : if (rxSet.is())
69 : {
70 0 : const Reference<beans::XPropertySetInfo> xInfo (rxSet->getPropertySetInfo());
71 0 : if ( ! xInfo.is() || xInfo->hasPropertyByName(rsPropertyName))
72 : {
73 : try
74 : {
75 0 : rxSet->getPropertyValue(rsPropertyName) >>= sValue;
76 : }
77 0 : catch (beans::UnknownPropertyException&)
78 : {
79 : // This exception should only be thrown when the property
80 : // does not exits (of course) and the XPropertySetInfo is
81 : // not available.
82 : }
83 0 : }
84 : }
85 0 : return sValue;
86 : }
87 :
88 : } // end of anonymous namespace
89 :
90 :
91 :
92 :
93 : //===== internal ============================================================
94 :
95 0 : AccessibleShape::AccessibleShape (
96 : const AccessibleShapeInfo& rShapeInfo,
97 : const AccessibleShapeTreeInfo& rShapeTreeInfo)
98 : : AccessibleContextBase (rShapeInfo.mxParent,AccessibleRole::LIST_ITEM),
99 : mpChildrenManager(NULL),
100 : mxShape (rShapeInfo.mxShape),
101 : maShapeTreeInfo (rShapeTreeInfo),
102 : mnIndex (rShapeInfo.mnIndex),
103 : m_nIndexInParent(-1),
104 : mpText (NULL),
105 0 : mpParent (rShapeInfo.mpChildrenManager)
106 : {
107 0 : m_pShape = GetSdrObjectFromXShape(mxShape);
108 0 : UpdateNameAndDescription();
109 0 : }
110 :
111 :
112 :
113 :
114 0 : AccessibleShape::~AccessibleShape (void)
115 : {
116 0 : if (mpChildrenManager != NULL)
117 0 : delete mpChildrenManager;
118 0 : if (mpText != NULL)
119 0 : delete mpText;
120 : OSL_TRACE ("~AccessibleShape");
121 :
122 : // Unregistering from the various broadcasters should be unnecessary
123 : // since this destructor would not have been called if one of the
124 : // broadcasters would still hold a strong reference to this object.
125 0 : }
126 :
127 :
128 :
129 :
130 0 : void AccessibleShape::Init (void)
131 : {
132 : // Update the OPAQUE and SELECTED shape.
133 0 : UpdateStates ();
134 :
135 : // Create a children manager when this shape has children of its own.
136 0 : Reference<drawing::XShapes> xShapes (mxShape, uno::UNO_QUERY);
137 0 : if (xShapes.is() && xShapes->getCount() > 0)
138 : mpChildrenManager = new ChildrenManager (
139 0 : this, xShapes, maShapeTreeInfo, *this);
140 0 : if (mpChildrenManager != NULL)
141 0 : mpChildrenManager->Update();
142 :
143 : // Register at model as document::XEventListener.
144 0 : if (maShapeTreeInfo.GetModelBroadcaster().is())
145 0 : maShapeTreeInfo.GetModelBroadcaster()->addEventListener (
146 0 : static_cast<document::XEventListener*>(this));
147 :
148 : // Beware! Here we leave the paths of the UNO API and descend into the
149 : // depths of the core. Necessary for makeing the edit engine
150 : // accessible.
151 0 : Reference<text::XText> xText (mxShape, uno::UNO_QUERY);
152 0 : if (xText.is())
153 : {
154 0 : SdrView* pView = maShapeTreeInfo.GetSdrView ();
155 0 : const Window* pWindow = maShapeTreeInfo.GetWindow ();
156 0 : if (pView != NULL && pWindow != NULL && mxShape.is())
157 : {
158 : // #107948# Determine whether shape text is empty
159 0 : SdrObject* pSdrObject = GetSdrObjectFromXShape(mxShape);
160 0 : if( pSdrObject )
161 : {
162 0 : SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, pSdrObject );
163 0 : OutlinerParaObject* pOutlinerParaObject = NULL;
164 :
165 0 : if( pTextObj )
166 0 : pOutlinerParaObject = pTextObj->GetEditOutlinerParaObject(); // Get the OutlinerParaObject if text edit is active
167 :
168 0 : bool bOwnParaObj = pOutlinerParaObject != NULL;
169 :
170 0 : if( !pOutlinerParaObject && pSdrObject )
171 0 : pOutlinerParaObject = pSdrObject->GetOutlinerParaObject();
172 :
173 : // create AccessibleTextHelper to handle this shape's text
174 0 : if( !pOutlinerParaObject )
175 : {
176 : // empty text -> use proxy edit source to delay creation of EditEngine
177 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
178 0 : ::std::auto_ptr<SvxEditSource> pEditSource( new AccessibleEmptyEditSource ( *pSdrObject, *pView, *pWindow) );
179 : SAL_WNODEPRECATED_DECLARATIONS_POP
180 0 : mpText = new AccessibleTextHelper( pEditSource );
181 : }
182 : else
183 : {
184 : // non-empty text -> use full-fledged edit source right away
185 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
186 0 : ::std::auto_ptr<SvxEditSource> pEditSource( new SvxTextEditSource ( *pSdrObject, 0, *pView, *pWindow) );
187 : SAL_WNODEPRECATED_DECLARATIONS_POP
188 0 : mpText = new AccessibleTextHelper( pEditSource );
189 : }
190 :
191 0 : if( bOwnParaObj )
192 0 : delete pOutlinerParaObject;
193 :
194 0 : mpText->SetEventSource(this);
195 : }
196 : }
197 0 : }
198 0 : }
199 :
200 :
201 :
202 :
203 0 : void AccessibleShape::UpdateStates (void)
204 : {
205 : ::utl::AccessibleStateSetHelper* pStateSet =
206 0 : static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
207 0 : if (pStateSet == NULL)
208 0 : return;
209 :
210 : // Set the opaque state for certain shape types when their fill style is
211 : // solid.
212 0 : bool bShapeIsOpaque = false;
213 0 : switch (ShapeTypeHandler::Instance().GetTypeId (mxShape))
214 : {
215 : case DRAWING_PAGE:
216 : case DRAWING_RECTANGLE:
217 : case DRAWING_TEXT:
218 : {
219 0 : uno::Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY);
220 0 : if (xSet.is())
221 : {
222 : try
223 : {
224 : drawing::FillStyle aFillStyle;
225 0 : bShapeIsOpaque = ( xSet->getPropertyValue (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("FillStyle"))) >>= aFillStyle)
226 0 : && aFillStyle == drawing::FillStyle_SOLID;
227 : }
228 0 : catch (::com::sun::star::beans::UnknownPropertyException&)
229 : {
230 : // Ignore.
231 : }
232 0 : }
233 : }
234 : }
235 0 : if (bShapeIsOpaque)
236 0 : pStateSet->AddState (AccessibleStateType::OPAQUE);
237 : else
238 0 : pStateSet->RemoveState (AccessibleStateType::OPAQUE);
239 :
240 : // Set the selected state.
241 0 : bool bShapeIsSelected = false;
242 : // XXX fix_me this has to be done with an extra interface later on
243 0 : if ( m_pShape && maShapeTreeInfo.GetSdrView() )
244 : {
245 0 : bShapeIsSelected = maShapeTreeInfo.GetSdrView()->IsObjMarked(m_pShape) == sal_True;
246 : }
247 :
248 0 : if (bShapeIsSelected)
249 0 : pStateSet->AddState (AccessibleStateType::SELECTED);
250 : else
251 0 : pStateSet->RemoveState (AccessibleStateType::SELECTED);
252 : }
253 :
254 :
255 :
256 :
257 0 : bool AccessibleShape::operator== (const AccessibleShape& rShape)
258 : {
259 0 : return this==&rShape;
260 : }
261 :
262 :
263 :
264 :
265 0 : sal_Bool AccessibleShape::SetState (sal_Int16 aState)
266 : {
267 0 : sal_Bool bStateHasChanged = sal_False;
268 :
269 0 : if (aState == AccessibleStateType::FOCUSED && mpText != NULL)
270 : {
271 : // Offer FOCUSED state to edit engine and detect whether the state
272 : // changes.
273 0 : sal_Bool bIsFocused = mpText->HaveFocus ();
274 0 : mpText->SetFocus (sal_True);
275 0 : bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
276 : }
277 : else
278 0 : bStateHasChanged = AccessibleContextBase::SetState (aState);
279 :
280 0 : return bStateHasChanged;
281 : }
282 :
283 :
284 :
285 :
286 0 : sal_Bool AccessibleShape::ResetState (sal_Int16 aState)
287 : {
288 0 : sal_Bool bStateHasChanged = sal_False;
289 :
290 0 : if (aState == AccessibleStateType::FOCUSED && mpText != NULL)
291 : {
292 : // Try to remove FOCUSED state from the edit engine and detect
293 : // whether the state changes.
294 0 : sal_Bool bIsFocused = mpText->HaveFocus ();
295 0 : mpText->SetFocus (sal_False);
296 0 : bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
297 : }
298 : else
299 0 : bStateHasChanged = AccessibleContextBase::ResetState (aState);
300 :
301 0 : return bStateHasChanged;
302 : }
303 :
304 :
305 :
306 :
307 0 : sal_Bool AccessibleShape::GetState (sal_Int16 aState)
308 : {
309 0 : if (aState == AccessibleStateType::FOCUSED && mpText != NULL)
310 : {
311 : // Just delegate the call to the edit engine. The state is not
312 : // merged into the state set.
313 0 : return mpText->HaveFocus();
314 : }
315 : else
316 0 : return AccessibleContextBase::GetState (aState);
317 : }
318 :
319 :
320 :
321 :
322 : //===== XAccessibleContext ==================================================
323 :
324 : /** The children of this shape come from two sources: The children from
325 : group or scene shapes and the paragraphs of text.
326 : */
327 : sal_Int32 SAL_CALL
328 0 : AccessibleShape::getAccessibleChildCount ()
329 : throw (::com::sun::star::uno::RuntimeException)
330 : {
331 0 : ThrowIfDisposed ();
332 0 : sal_Int32 nChildCount = 0;
333 :
334 : // Add the number of shapes that are children of this shape.
335 0 : if (mpChildrenManager != NULL)
336 0 : nChildCount += mpChildrenManager->GetChildCount ();
337 : // Add the number text paragraphs.
338 0 : if (mpText != NULL)
339 0 : nChildCount += mpText->GetChildCount ();
340 :
341 0 : return nChildCount;
342 : }
343 :
344 :
345 :
346 :
347 : /** Forward the request to the shape. Return the requested shape or throw
348 : an exception for a wrong index.
349 : */
350 : uno::Reference<XAccessible> SAL_CALL
351 0 : AccessibleShape::getAccessibleChild (sal_Int32 nIndex)
352 : throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException)
353 : {
354 0 : ThrowIfDisposed ();
355 :
356 0 : uno::Reference<XAccessible> xChild;
357 :
358 : // Depending on the index decide whether to delegate this call to the
359 : // children manager or the edit engine.
360 0 : if ((mpChildrenManager != NULL)
361 0 : && (nIndex < mpChildrenManager->GetChildCount()))
362 : {
363 0 : xChild = mpChildrenManager->GetChild (nIndex);
364 : }
365 0 : else if (mpText != NULL)
366 : {
367 0 : sal_Int32 nI = nIndex;
368 0 : if (mpChildrenManager != NULL)
369 0 : nI -= mpChildrenManager->GetChildCount();
370 0 : xChild = mpText->GetChild (nI);
371 : }
372 : else
373 : throw lang::IndexOutOfBoundsException (
374 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("shape has no child with index "))
375 0 : + rtl::OUString::valueOf(nIndex),
376 0 : static_cast<uno::XWeak*>(this));
377 :
378 0 : return xChild;
379 : }
380 :
381 :
382 :
383 :
384 : /** Return a copy of the state set.
385 : Possible states are:
386 : ENABLED
387 : SHOWING
388 : VISIBLE
389 : */
390 : uno::Reference<XAccessibleStateSet> SAL_CALL
391 0 : AccessibleShape::getAccessibleStateSet (void)
392 : throw (::com::sun::star::uno::RuntimeException)
393 : {
394 0 : ::osl::MutexGuard aGuard (maMutex);
395 0 : Reference<XAccessibleStateSet> xStateSet;
396 :
397 0 : if (rBHelper.bDisposed || mpText == NULL)
398 : // Return a minimal state set that only contains the DEFUNC state.
399 0 : xStateSet = AccessibleContextBase::getAccessibleStateSet ();
400 : else
401 : {
402 : ::utl::AccessibleStateSetHelper* pStateSet =
403 0 : static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
404 :
405 0 : if (pStateSet != NULL)
406 : {
407 : // Merge current FOCUSED state from edit engine.
408 0 : if (mpText != NULL)
409 : {
410 0 : if (mpText->HaveFocus())
411 0 : pStateSet->AddState (AccessibleStateType::FOCUSED);
412 : else
413 0 : pStateSet->RemoveState (AccessibleStateType::FOCUSED);
414 : }
415 :
416 : // Create a copy of the state set that may be modified by the
417 : // caller without affecting the current state set.
418 : xStateSet = Reference<XAccessibleStateSet>(
419 0 : new ::utl::AccessibleStateSetHelper (*pStateSet));
420 : }
421 : }
422 :
423 0 : return xStateSet;
424 : }
425 :
426 :
427 :
428 :
429 : //===== XAccessibleComponent ================================================
430 :
431 : /** The implementation below is at the moment straightforward. It iterates
432 : over all children (and thereby instances all children which have not
433 : been already instatiated) until a child covering the specifed point is
434 : found.
435 : This leaves room for improvement. For instance, first iterate only over
436 : the already instantiated children and only if no match is found
437 : instantiate the remaining ones.
438 : */
439 : uno::Reference<XAccessible > SAL_CALL
440 0 : AccessibleShape::getAccessibleAtPoint (
441 : const awt::Point& aPoint)
442 : throw (uno::RuntimeException)
443 : {
444 0 : ::osl::MutexGuard aGuard (maMutex);
445 :
446 0 : sal_Int32 nChildCount = getAccessibleChildCount ();
447 0 : for (sal_Int32 i=0; i<nChildCount; ++i)
448 : {
449 0 : Reference<XAccessible> xChild (getAccessibleChild (i));
450 0 : if (xChild.is())
451 : {
452 : Reference<XAccessibleComponent> xChildComponent (
453 0 : xChild->getAccessibleContext(), uno::UNO_QUERY);
454 0 : if (xChildComponent.is())
455 : {
456 0 : awt::Rectangle aBBox (xChildComponent->getBounds());
457 0 : if ( (aPoint.X >= aBBox.X)
458 : && (aPoint.Y >= aBBox.Y)
459 : && (aPoint.X < aBBox.X+aBBox.Width)
460 : && (aPoint.Y < aBBox.Y+aBBox.Height) )
461 0 : return xChild;
462 0 : }
463 : }
464 0 : }
465 :
466 : // Have not found a child under the given point. Returning empty
467 : // reference to indicate this.
468 0 : return uno::Reference<XAccessible>();
469 : }
470 :
471 :
472 :
473 :
474 0 : awt::Rectangle SAL_CALL AccessibleShape::getBounds (void)
475 : throw (::com::sun::star::uno::RuntimeException)
476 : {
477 0 : SolarMutexGuard aSolarGuard;
478 0 : ::osl::MutexGuard aGuard (maMutex);
479 :
480 0 : ThrowIfDisposed ();
481 0 : awt::Rectangle aBoundingBox;
482 0 : if ( mxShape.is() )
483 : {
484 :
485 : static const OUString sBoundRectName (
486 0 : RTL_CONSTASCII_USTRINGPARAM("BoundRect"));
487 : static const OUString sAnchorPositionName (
488 0 : RTL_CONSTASCII_USTRINGPARAM("AnchorPosition"));
489 :
490 : // Get the shape's bounding box in internal coordinates (in 100th of
491 : // mm). Use the property BoundRect. Only if that is not supported ask
492 : // the shape for its position and size directly.
493 0 : Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY);
494 0 : Reference<beans::XPropertySetInfo> xSetInfo;
495 0 : bool bFoundBoundRect = false;
496 0 : if (xSet.is())
497 : {
498 0 : xSetInfo = xSet->getPropertySetInfo ();
499 0 : if (xSetInfo.is())
500 : {
501 0 : if (xSetInfo->hasPropertyByName (sBoundRectName))
502 : {
503 : try
504 : {
505 0 : uno::Any aValue = xSet->getPropertyValue (sBoundRectName);
506 0 : aValue >>= aBoundingBox;
507 0 : bFoundBoundRect = true;
508 : }
509 0 : catch (beans::UnknownPropertyException const&)
510 : {
511 : // Handled below (bFoundBoundRect stays false).
512 : }
513 : }
514 : else
515 : OSL_TRACE (" no property BoundRect");
516 : }
517 : }
518 :
519 : // Fallback when there is no BoundRect Property.
520 0 : if ( ! bFoundBoundRect )
521 : {
522 0 : awt::Point aPosition (mxShape->getPosition());
523 0 : awt::Size aSize (mxShape->getSize());
524 : aBoundingBox = awt::Rectangle (
525 : aPosition.X, aPosition.Y,
526 0 : aSize.Width, aSize.Height);
527 :
528 : // While BoundRects have absolute positions, the position returned
529 : // by XPosition::getPosition is relative. Get the anchor position
530 : // (usually not (0,0) for Writer shapes).
531 0 : if (xSetInfo.is())
532 : {
533 0 : if (xSetInfo->hasPropertyByName (sAnchorPositionName))
534 : {
535 0 : uno::Any aPos = xSet->getPropertyValue (sAnchorPositionName);
536 0 : awt::Point aAnchorPosition;
537 0 : aPos >>= aAnchorPosition;
538 0 : aBoundingBox.X += aAnchorPosition.X;
539 0 : aBoundingBox.Y += aAnchorPosition.Y;
540 : }
541 : }
542 : }
543 :
544 : // Transform coordinates from internal to pixel.
545 0 : if (maShapeTreeInfo.GetViewForwarder() == NULL)
546 : throw uno::RuntimeException (::rtl::OUString (
547 : RTL_CONSTASCII_USTRINGPARAM(
548 : "AccessibleShape has no valid view forwarder")),
549 0 : static_cast<uno::XWeak*>(this));
550 0 : ::Size aPixelSize = maShapeTreeInfo.GetViewForwarder()->LogicToPixel (
551 0 : ::Size (aBoundingBox.Width, aBoundingBox.Height));
552 0 : ::Point aPixelPosition = maShapeTreeInfo.GetViewForwarder()->LogicToPixel (
553 0 : ::Point (aBoundingBox.X, aBoundingBox.Y));
554 :
555 : // Clip the shape's bounding box with the bounding box of its parent.
556 : Reference<XAccessibleComponent> xParentComponent (
557 0 : getAccessibleParent(), uno::UNO_QUERY);
558 0 : if (xParentComponent.is())
559 : {
560 : // Make the coordinates relative to the parent.
561 0 : awt::Point aParentLocation (xParentComponent->getLocationOnScreen());
562 0 : int x = aPixelPosition.getX() - aParentLocation.X;
563 0 : int y = aPixelPosition.getY() - aParentLocation.Y;
564 :
565 : // Clip with parent (with coordinates relative to itself).
566 : ::Rectangle aBBox (
567 0 : x, y, x + aPixelSize.getWidth(), y + aPixelSize.getHeight());
568 0 : awt::Size aParentSize (xParentComponent->getSize());
569 0 : ::Rectangle aParentBBox (0,0, aParentSize.Width, aParentSize.Height);
570 0 : aBBox = aBBox.GetIntersection (aParentBBox);
571 : aBoundingBox = awt::Rectangle (
572 0 : aBBox.getX(),
573 0 : aBBox.getY(),
574 0 : aBBox.getWidth(),
575 0 : aBBox.getHeight());
576 : }
577 : else
578 : {
579 : OSL_TRACE ("parent does not support component");
580 : aBoundingBox = awt::Rectangle (
581 0 : aPixelPosition.getX(), aPixelPosition.getY(),
582 0 : aPixelSize.getWidth(), aPixelSize.getHeight());
583 0 : }
584 : }
585 :
586 0 : return aBoundingBox;
587 : }
588 :
589 :
590 :
591 :
592 0 : awt::Point SAL_CALL AccessibleShape::getLocation (void)
593 : throw (::com::sun::star::uno::RuntimeException)
594 : {
595 0 : ThrowIfDisposed ();
596 0 : awt::Rectangle aBoundingBox (getBounds());
597 0 : return awt::Point (aBoundingBox.X, aBoundingBox.Y);
598 : }
599 :
600 :
601 :
602 :
603 0 : awt::Point SAL_CALL AccessibleShape::getLocationOnScreen (void)
604 : throw (::com::sun::star::uno::RuntimeException)
605 : {
606 0 : ThrowIfDisposed ();
607 :
608 : // Get relative position...
609 0 : awt::Point aLocation (getLocation ());
610 :
611 : // ... and add absolute position of the parent.
612 : uno::Reference<XAccessibleComponent> xParentComponent (
613 0 : getAccessibleParent(), uno::UNO_QUERY);
614 0 : if (xParentComponent.is())
615 : {
616 0 : awt::Point aParentLocation (xParentComponent->getLocationOnScreen());
617 0 : aLocation.X += aParentLocation.X;
618 0 : aLocation.Y += aParentLocation.Y;
619 : }
620 : else
621 : OSL_TRACE ("getLocation: parent does not support XAccessibleComponent");
622 0 : return aLocation;
623 : }
624 :
625 :
626 :
627 :
628 0 : awt::Size SAL_CALL AccessibleShape::getSize (void)
629 : throw (uno::RuntimeException)
630 : {
631 0 : ThrowIfDisposed ();
632 0 : awt::Rectangle aBoundingBox (getBounds());
633 0 : return awt::Size (aBoundingBox.Width, aBoundingBox.Height);
634 : }
635 :
636 :
637 :
638 :
639 0 : sal_Int32 SAL_CALL AccessibleShape::getForeground (void)
640 : throw (::com::sun::star::uno::RuntimeException)
641 : {
642 0 : ThrowIfDisposed ();
643 0 : sal_Int32 nColor (0x0ffffffL);
644 :
645 : try
646 : {
647 0 : uno::Reference<beans::XPropertySet> aSet (mxShape, uno::UNO_QUERY);
648 0 : if (aSet.is())
649 : {
650 0 : uno::Any aColor;
651 0 : aColor = aSet->getPropertyValue (OUString(RTL_CONSTASCII_USTRINGPARAM("LineColor")) );
652 0 : aColor >>= nColor;
653 0 : }
654 : }
655 0 : catch (const ::com::sun::star::beans::UnknownPropertyException &)
656 : {
657 : // Ignore exception and return default color.
658 : }
659 0 : return nColor;
660 : }
661 :
662 :
663 :
664 :
665 0 : sal_Int32 SAL_CALL AccessibleShape::getBackground (void)
666 : throw (::com::sun::star::uno::RuntimeException)
667 : {
668 0 : ThrowIfDisposed ();
669 0 : sal_Int32 nColor (0L);
670 :
671 : try
672 : {
673 0 : uno::Reference<beans::XPropertySet> aSet (mxShape, uno::UNO_QUERY);
674 0 : if (aSet.is())
675 : {
676 0 : uno::Any aColor;
677 0 : aColor = aSet->getPropertyValue (OUString(RTL_CONSTASCII_USTRINGPARAM("FillColor")) );
678 0 : aColor >>= nColor;
679 0 : }
680 : }
681 0 : catch (const ::com::sun::star::beans::UnknownPropertyException &)
682 : {
683 : // Ignore exception and return default color.
684 : }
685 0 : return nColor;
686 : }
687 :
688 :
689 :
690 :
691 : //===== XAccessibleEventBroadcaster =========================================
692 :
693 0 : void SAL_CALL AccessibleShape::addAccessibleEventListener (
694 : const Reference<XAccessibleEventListener >& rxListener)
695 : throw (uno::RuntimeException)
696 : {
697 0 : if (rBHelper.bDisposed || rBHelper.bInDispose)
698 : {
699 : uno::Reference<uno::XInterface> xThis (
700 0 : (lang::XComponent *)this, uno::UNO_QUERY);
701 0 : rxListener->disposing (lang::EventObject (xThis));
702 : }
703 : else
704 : {
705 0 : AccessibleContextBase::addAccessibleEventListener (rxListener);
706 0 : if (mpText != NULL)
707 0 : mpText->AddEventListener (rxListener);
708 : }
709 0 : }
710 :
711 :
712 :
713 :
714 0 : void SAL_CALL AccessibleShape::removeAccessibleEventListener (
715 : const Reference<XAccessibleEventListener >& rxListener)
716 : throw (uno::RuntimeException)
717 : {
718 0 : AccessibleContextBase::removeAccessibleEventListener (rxListener);
719 0 : if (mpText != NULL)
720 0 : mpText->RemoveEventListener (rxListener);
721 0 : }
722 :
723 :
724 :
725 :
726 : //===== XInterface ==========================================================
727 :
728 : com::sun::star::uno::Any SAL_CALL
729 0 : AccessibleShape::queryInterface (const com::sun::star::uno::Type & rType)
730 : throw (::com::sun::star::uno::RuntimeException)
731 : {
732 0 : ::com::sun::star::uno::Any aReturn = AccessibleContextBase::queryInterface (rType);
733 0 : if ( ! aReturn.hasValue())
734 : aReturn = ::cppu::queryInterface (rType,
735 : static_cast<XAccessibleComponent*>(this),
736 : static_cast<XAccessibleExtendedComponent*>(this),
737 : static_cast<lang::XEventListener*>(this),
738 : static_cast<document::XEventListener*>(this),
739 : static_cast<lang::XUnoTunnel*>(this)
740 0 : );
741 0 : return aReturn;
742 : }
743 :
744 :
745 :
746 :
747 : void SAL_CALL
748 0 : AccessibleShape::acquire (void)
749 : throw ()
750 : {
751 0 : AccessibleContextBase::acquire ();
752 0 : }
753 :
754 :
755 :
756 :
757 : void SAL_CALL
758 0 : AccessibleShape::release (void)
759 : throw ()
760 : {
761 0 : AccessibleContextBase::release ();
762 0 : }
763 :
764 :
765 :
766 :
767 : //===== XServiceInfo ========================================================
768 :
769 : ::rtl::OUString SAL_CALL
770 0 : AccessibleShape::getImplementationName (void)
771 : throw (::com::sun::star::uno::RuntimeException)
772 : {
773 0 : return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleShape"));
774 : }
775 :
776 :
777 :
778 :
779 : uno::Sequence<OUString> SAL_CALL
780 0 : AccessibleShape::getSupportedServiceNames (void)
781 : throw (::com::sun::star::uno::RuntimeException)
782 : {
783 0 : ThrowIfDisposed ();
784 : // Get list of supported service names from base class...
785 : uno::Sequence<OUString> aServiceNames =
786 0 : AccessibleContextBase::getSupportedServiceNames();
787 0 : sal_Int32 nCount (aServiceNames.getLength());
788 :
789 : // ...and add additional names.
790 0 : aServiceNames.realloc (nCount + 1);
791 : static const OUString sAdditionalServiceName (RTL_CONSTASCII_USTRINGPARAM(
792 0 : "com.sun.star.drawing.AccessibleShape"));
793 0 : aServiceNames[nCount] = sAdditionalServiceName;
794 :
795 0 : return aServiceNames;
796 : }
797 :
798 :
799 :
800 :
801 :
802 : //===== XTypeProvider ===================================================
803 :
804 : uno::Sequence<uno::Type> SAL_CALL
805 0 : AccessibleShape::getTypes (void)
806 : throw (uno::RuntimeException)
807 : {
808 0 : ThrowIfDisposed ();
809 : // Get list of types from the context base implementation, ...
810 0 : uno::Sequence<uno::Type> aTypeList (AccessibleContextBase::getTypes());
811 : // ... get list of types from component base implementation, ...
812 0 : uno::Sequence<uno::Type> aComponentTypeList (AccessibleComponentBase::getTypes());
813 : // ... define local types, ...
814 : const uno::Type aLangEventListenerType =
815 0 : ::getCppuType((const uno::Reference<lang::XEventListener>*)0);
816 : const uno::Type aDocumentEventListenerType =
817 0 : ::getCppuType((const uno::Reference<document::XEventListener>*)0);
818 : const uno::Type aUnoTunnelType =
819 0 : ::getCppuType((const uno::Reference<lang::XUnoTunnel>*)0);
820 :
821 : // ... and merge them all into one list.
822 0 : sal_Int32 nTypeCount (aTypeList.getLength()),
823 0 : nComponentTypeCount (aComponentTypeList.getLength());
824 : int i;
825 :
826 0 : aTypeList.realloc (nTypeCount + nComponentTypeCount + 3);
827 :
828 0 : for (i=0; i<nComponentTypeCount; i++)
829 0 : aTypeList[nTypeCount + i] = aComponentTypeList[i];
830 :
831 0 : aTypeList[nTypeCount + i++ ] = aLangEventListenerType;
832 0 : aTypeList[nTypeCount + i++ ] = aDocumentEventListenerType;
833 0 : aTypeList[nTypeCount + i ] = aUnoTunnelType;
834 :
835 0 : return aTypeList;
836 : }
837 :
838 :
839 :
840 :
841 : //===== lang::XEventListener ================================================
842 :
843 : /** Disposing calls are accepted only from the model: Just reset the
844 : reference to the model in the shape tree info. Otherwise this object
845 : remains functional.
846 : */
847 : void SAL_CALL
848 0 : AccessibleShape::disposing (const lang::EventObject& aEvent)
849 : throw (uno::RuntimeException)
850 : {
851 0 : SolarMutexGuard aSolarGuard;
852 0 : ::osl::MutexGuard aGuard (maMutex);
853 :
854 : try
855 : {
856 0 : if (aEvent.Source == maShapeTreeInfo.GetModelBroadcaster())
857 : {
858 : // Remove reference to model broadcaster to allow it to pass
859 : // away.
860 0 : maShapeTreeInfo.SetModelBroadcaster(NULL);
861 : }
862 :
863 : }
864 0 : catch (uno::RuntimeException const&)
865 : {
866 : OSL_TRACE ("caught exception while disposing");
867 0 : }
868 0 : }
869 :
870 :
871 :
872 :
873 : //===== document::XEventListener ============================================
874 :
875 : void SAL_CALL
876 0 : AccessibleShape::notifyEvent (const document::EventObject& rEventObject)
877 : throw (uno::RuntimeException)
878 : {
879 : static const OUString sShapeModified (
880 0 : RTL_CONSTASCII_USTRINGPARAM("ShapeModified"));
881 :
882 : // First check if the event is for us.
883 : uno::Reference<drawing::XShape> xShape (
884 0 : rEventObject.Source, uno::UNO_QUERY);
885 0 : if ( xShape.get() == mxShape.get() )
886 : {
887 0 : if (rEventObject.EventName.equals (sShapeModified))
888 : {
889 : // Some property of a shape has been modified. Send an event
890 : // that indicates a change of the visible data to all listeners.
891 : CommitChange (
892 : AccessibleEventId::VISIBLE_DATA_CHANGED,
893 : uno::Any(),
894 0 : uno::Any());
895 :
896 : // Name and Description may have changed. Update the local
897 : // values accordingly.
898 0 : UpdateNameAndDescription();
899 : }
900 0 : }
901 0 : }
902 :
903 : //===== lang::XUnoTunnel ================================================
904 :
905 : namespace
906 : {
907 : class theAccessibleShapeImplementationId : public rtl::Static< UnoTunnelIdInit, theAccessibleShapeImplementationId > {};
908 : }
909 :
910 : const uno::Sequence< sal_Int8 >&
911 0 : AccessibleShape::getUnoTunnelImplementationId()
912 : throw()
913 : {
914 0 : return theAccessibleShapeImplementationId::get().getSeq();
915 : }
916 :
917 : //------------------------------------------------------------------------------
918 : AccessibleShape*
919 0 : AccessibleShape::getImplementation( const uno::Reference< uno::XInterface >& rxIFace )
920 : throw()
921 : {
922 0 : uno::Reference< lang::XUnoTunnel > xTunnel( rxIFace, uno::UNO_QUERY );
923 0 : AccessibleShape* pReturn = NULL;
924 :
925 0 : if( xTunnel.is() )
926 0 : pReturn = reinterpret_cast< AccessibleShape* >( xTunnel->getSomething( getUnoTunnelImplementationId() ) );
927 :
928 0 : return( pReturn );
929 : }
930 :
931 : //------------------------------------------------------------------------------
932 : sal_Int64 SAL_CALL
933 0 : AccessibleShape::getSomething( const uno::Sequence< sal_Int8 >& rIdentifier )
934 : throw(uno::RuntimeException)
935 : {
936 0 : sal_Int64 nReturn( 0 );
937 :
938 0 : if( ( rIdentifier.getLength() == 16 ) && ( 0 == memcmp( getUnoTunnelImplementationId().getConstArray(), rIdentifier.getConstArray(), 16 ) ) )
939 0 : nReturn = reinterpret_cast< sal_Int64 >( this );
940 :
941 0 : return( nReturn );
942 : }
943 :
944 : //===== IAccessibleViewForwarderListener ====================================
945 :
946 0 : void AccessibleShape::ViewForwarderChanged (ChangeType aChangeType,
947 : const IAccessibleViewForwarder* pViewForwarder)
948 : {
949 : // Inform all listeners that the graphical representation (i.e. size
950 : // and/or position) of the shape has changed.
951 : CommitChange (AccessibleEventId::VISIBLE_DATA_CHANGED,
952 : uno::Any(),
953 0 : uno::Any());
954 :
955 : // Tell children manager of the modified view forwarder.
956 0 : if (mpChildrenManager != NULL)
957 0 : mpChildrenManager->ViewForwarderChanged (aChangeType, pViewForwarder);
958 :
959 : // update our children that our screen position might have changed
960 0 : if( mpText )
961 0 : mpText->UpdateChildren();
962 0 : }
963 :
964 :
965 :
966 :
967 : //===== protected internal ==================================================
968 : /// Set this object's name if is different to the current name.
969 : ::rtl::OUString
970 0 : AccessibleShape::CreateAccessibleBaseName (void)
971 : throw (::com::sun::star::uno::RuntimeException)
972 : {
973 0 : return ShapeTypeHandler::CreateAccessibleBaseName( mxShape );
974 : }
975 :
976 :
977 : ::rtl::OUString
978 0 : AccessibleShape::CreateAccessibleName (void)
979 : throw (::com::sun::star::uno::RuntimeException)
980 : {
981 0 : OUString sName (CreateAccessibleBaseName());
982 :
983 : // Append the shape's index to the name to disambiguate between shapes
984 : // of the same type. If such an index where not given to the
985 : // constructor then use the z-order instead. If even that does not exist
986 : // we throw an exception.
987 0 : long nIndex = mnIndex;
988 0 : if (nIndex == -1)
989 : {
990 : try
991 : {
992 0 : uno::Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY);
993 0 : if (xSet.is())
994 : {
995 0 : uno::Any aZOrder (xSet->getPropertyValue (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ZOrder")) ));
996 0 : aZOrder >>= nIndex;
997 :
998 : // Add one to be not zero based.
999 0 : nIndex += 1;
1000 0 : }
1001 : }
1002 0 : catch (const beans::UnknownPropertyException &)
1003 : {
1004 : // We throw our own exception that is a bit more informative.
1005 : throw uno::RuntimeException (::rtl::OUString (
1006 : RTL_CONSTASCII_USTRINGPARAM("AccessibleShape has invalid index and no ZOrder property")),
1007 0 : static_cast<uno::XWeak*>(this));
1008 : }
1009 :
1010 : }
1011 :
1012 : // Put a space between name and index because of Gnopernicus othewise
1013 : // spells the name.
1014 0 : sName += OUString (RTL_CONSTASCII_USTRINGPARAM(" ")) + OUString::valueOf (nIndex);
1015 :
1016 0 : return sName;
1017 : }
1018 :
1019 :
1020 :
1021 :
1022 : ::rtl::OUString
1023 0 : AccessibleShape::CreateAccessibleDescription (void)
1024 : throw (::com::sun::star::uno::RuntimeException)
1025 : {
1026 0 : DescriptionGenerator aDG (mxShape);
1027 0 : aDG.Initialize (CreateAccessibleBaseName());
1028 0 : switch (ShapeTypeHandler::Instance().GetTypeId (mxShape))
1029 : {
1030 : case DRAWING_3D_CUBE:
1031 : case DRAWING_3D_EXTRUDE:
1032 : case DRAWING_3D_LATHE:
1033 : case DRAWING_3D_SPHERE:
1034 0 : aDG.Add3DProperties ();
1035 : break;
1036 :
1037 : case DRAWING_3D_SCENE:
1038 : case DRAWING_GROUP:
1039 : case DRAWING_PAGE:
1040 : // No further information is appended.
1041 : break;
1042 :
1043 : case DRAWING_CAPTION:
1044 : case DRAWING_CLOSED_BEZIER:
1045 : case DRAWING_CLOSED_FREEHAND:
1046 : case DRAWING_ELLIPSE:
1047 : case DRAWING_POLY_POLYGON:
1048 : case DRAWING_POLY_POLYGON_PATH:
1049 : case DRAWING_RECTANGLE:
1050 0 : aDG.AddLineProperties ();
1051 0 : aDG.AddFillProperties ();
1052 : break;
1053 :
1054 : case DRAWING_CONNECTOR:
1055 : case DRAWING_LINE:
1056 : case DRAWING_MEASURE:
1057 : case DRAWING_OPEN_BEZIER:
1058 : case DRAWING_OPEN_FREEHAND:
1059 : case DRAWING_POLY_LINE:
1060 : case DRAWING_POLY_LINE_PATH:
1061 0 : aDG.AddLineProperties ();
1062 : break;
1063 :
1064 : case DRAWING_CONTROL:
1065 : aDG.AddProperty (OUString(RTL_CONSTASCII_USTRINGPARAM("ControlBackground")),
1066 : DescriptionGenerator::COLOR,
1067 0 : OUString());
1068 : aDG.AddProperty (OUString(RTL_CONSTASCII_USTRINGPARAM("ControlBorder")),
1069 : DescriptionGenerator::INTEGER,
1070 0 : OUString());
1071 : break;
1072 :
1073 : case DRAWING_TEXT:
1074 0 : aDG.AddTextProperties ();
1075 : break;
1076 :
1077 : default:
1078 : aDG.Initialize (::rtl::OUString (
1079 0 : RTL_CONSTASCII_USTRINGPARAM("Unknown accessible shape")));
1080 0 : uno::Reference<drawing::XShapeDescriptor> xDescriptor (mxShape, uno::UNO_QUERY);
1081 0 : if (xDescriptor.is())
1082 : {
1083 0 : aDG.AppendString (::rtl::OUString (RTL_CONSTASCII_USTRINGPARAM("service name=")));
1084 0 : aDG.AppendString (xDescriptor->getShapeType());
1085 0 : }
1086 : }
1087 :
1088 0 : return aDG();
1089 : }
1090 :
1091 :
1092 :
1093 :
1094 0 : uno::Reference< drawing::XShape > AccessibleShape::GetXShape()
1095 : {
1096 0 : return( mxShape );
1097 : }
1098 :
1099 :
1100 :
1101 : // protected
1102 0 : void AccessibleShape::disposing (void)
1103 : {
1104 0 : SolarMutexGuard aSolarGuard;
1105 0 : ::osl::MutexGuard aGuard (maMutex);
1106 :
1107 : // Make sure to send an event that this object looses the focus in the
1108 : // case that it has the focus.
1109 : ::utl::AccessibleStateSetHelper* pStateSet =
1110 0 : static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
1111 0 : if (pStateSet != NULL)
1112 0 : pStateSet->RemoveState (AccessibleStateType::FOCUSED);
1113 :
1114 : // Unregister from broadcasters.
1115 0 : Reference<lang::XComponent> xComponent (mxShape, uno::UNO_QUERY);
1116 0 : if (xComponent.is())
1117 0 : xComponent->removeEventListener (this);
1118 :
1119 : // Unregister from model.
1120 0 : if (maShapeTreeInfo.GetModelBroadcaster().is())
1121 0 : maShapeTreeInfo.GetModelBroadcaster()->removeEventListener (
1122 0 : static_cast<document::XEventListener*>(this));
1123 :
1124 : // Release the child containers.
1125 0 : if (mpChildrenManager != NULL)
1126 : {
1127 0 : delete mpChildrenManager;
1128 0 : mpChildrenManager = NULL;
1129 : }
1130 0 : if (mpText != NULL)
1131 : {
1132 0 : mpText->Dispose();
1133 0 : delete mpText;
1134 0 : mpText = NULL;
1135 : }
1136 :
1137 : // Cleanup. Remove references to objects to allow them to be
1138 : // destroyed.
1139 0 : mxShape = NULL;
1140 0 : maShapeTreeInfo = AccessibleShapeTreeInfo();
1141 :
1142 : // Call base classes.
1143 0 : AccessibleContextBase::dispose ();
1144 0 : }
1145 :
1146 : sal_Int32 SAL_CALL
1147 0 : AccessibleShape::getAccessibleIndexInParent (void)
1148 : throw (::com::sun::star::uno::RuntimeException)
1149 : {
1150 0 : ThrowIfDisposed ();
1151 : // Use a simple but slow solution for now. Optimize later.
1152 :
1153 0 : sal_Int32 nIndex = m_nIndexInParent;
1154 0 : if ( -1 == nIndex )
1155 0 : nIndex = AccessibleContextBase::getAccessibleIndexInParent();
1156 0 : return nIndex;
1157 : }
1158 :
1159 :
1160 :
1161 :
1162 0 : void AccessibleShape::UpdateNameAndDescription (void)
1163 : {
1164 : // Ignore missing title, name, or description. There are fallbacks for
1165 : // them.
1166 : try
1167 : {
1168 0 : Reference<beans::XPropertySet> xSet (mxShape, uno::UNO_QUERY_THROW);
1169 0 : OUString sString;
1170 :
1171 : // Get the accessible name.
1172 0 : sString = GetOptionalProperty(xSet, OUString(RTL_CONSTASCII_USTRINGPARAM("Title")));
1173 0 : if (!sString.isEmpty())
1174 : {
1175 0 : SetAccessibleName(sString, AccessibleContextBase::FromShape);
1176 : }
1177 : else
1178 : {
1179 0 : sString = GetOptionalProperty(xSet, OUString(RTL_CONSTASCII_USTRINGPARAM("Name")));
1180 0 : if (!sString.isEmpty())
1181 0 : SetAccessibleName(sString, AccessibleContextBase::FromShape);
1182 : }
1183 :
1184 : // Get the accessible description.
1185 0 : sString = GetOptionalProperty(xSet, OUString(RTL_CONSTASCII_USTRINGPARAM("Description")));
1186 0 : if (!sString.isEmpty())
1187 0 : SetAccessibleDescription(sString, AccessibleContextBase::FromShape);
1188 : }
1189 0 : catch (uno::RuntimeException&)
1190 : {
1191 : }
1192 0 : }
1193 :
1194 :
1195 :
1196 :
1197 : } // end of namespace accessibility
1198 :
1199 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|