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_svx.hxx" 30 31 #include "ChildrenManagerImpl.hxx" 32 #include <svx/ShapeTypeHandler.hxx> 33 #include <svx/AccessibleShapeInfo.hxx> 34 #ifndef _COM_SUN_STAR_ACCESSIBLE_ACCESSIBLESTATETYPE_HPP_ 35 #include <com/sun/star/accessibility/AccessibleStateType.hpp> 36 #endif 37 #include <com/sun/star/view/XSelectionSupplier.hpp> 38 #include <com/sun/star/container/XChild.hpp> 39 #include <comphelper/uno3.hxx> 40 #include <com/sun/star/container/XChild.hpp> 41 42 #include <rtl/ustring.hxx> 43 #include <tools/debug.hxx> 44 45 using namespace ::com::sun::star; 46 using namespace ::com::sun::star::accessibility; 47 using ::com::sun::star::uno::Reference; 48 49 50 namespace accessibility { 51 52 namespace 53 { 54 void adjustIndexInParentOfShapes(ChildDescriptorListType& _rList) 55 { 56 ChildDescriptorListType::iterator aEnd = _rList.end(); 57 sal_Int32 i=0; 58 for ( ChildDescriptorListType::iterator aIter = _rList.begin(); aIter != aEnd; ++aIter,++i) 59 aIter->setIndexAtAccessibleShape(i); 60 } 61 } 62 63 //===== AccessibleChildrenManager =========================================== 64 65 ChildrenManagerImpl::ChildrenManagerImpl ( 66 const uno::Reference<XAccessible>& rxParent, 67 const uno::Reference<drawing::XShapes>& rxShapeList, 68 const AccessibleShapeTreeInfo& rShapeTreeInfo, 69 AccessibleContextBase& rContext) 70 : ::cppu::WeakComponentImplHelper2< 71 ::com::sun::star::document::XEventListener, 72 ::com::sun::star::view::XSelectionChangeListener>(maMutex), 73 mxShapeList (rxShapeList), 74 mxParent (rxParent), 75 maShapeTreeInfo (rShapeTreeInfo), 76 mrContext (rContext), 77 mnNewNameIndex(1), 78 mpFocusedShape(NULL) 79 { 80 } 81 82 83 84 85 ChildrenManagerImpl::~ChildrenManagerImpl (void) 86 { 87 DBG_ASSERT (rBHelper.bDisposed || rBHelper.bInDispose, 88 "~AccessibleDrawDocumentView: object has not been disposed"); 89 } 90 91 92 93 94 void ChildrenManagerImpl::Init (void) 95 { 96 // Register as view::XSelectionChangeListener. 97 Reference<frame::XController> xController(maShapeTreeInfo.GetController()); 98 Reference<view::XSelectionSupplier> xSelectionSupplier ( 99 xController, uno::UNO_QUERY); 100 if (xSelectionSupplier.is()) 101 { 102 xController->addEventListener( 103 static_cast<document::XEventListener*>(this)); 104 105 xSelectionSupplier->addSelectionChangeListener ( 106 static_cast<view::XSelectionChangeListener*>(this)); 107 } 108 109 // Register at model as document::XEventListener. 110 if (maShapeTreeInfo.GetModelBroadcaster().is()) 111 maShapeTreeInfo.GetModelBroadcaster()->addEventListener ( 112 static_cast<document::XEventListener*>(this)); 113 } 114 115 116 117 118 long ChildrenManagerImpl::GetChildCount (void) const throw () 119 { 120 return maVisibleChildren.size(); 121 } 122 123 124 125 126 /** Return the requested accessible child object. Create it if it is not 127 yet in the cache. 128 */ 129 uno::Reference<XAccessible> 130 ChildrenManagerImpl::GetChild (long nIndex) 131 throw (::com::sun::star::uno::RuntimeException, 132 ::com::sun::star::lang::IndexOutOfBoundsException) 133 { 134 // Check wether the given index is valid. 135 if (nIndex < 0 || (unsigned long)nIndex >= maVisibleChildren.size()) 136 throw lang::IndexOutOfBoundsException ( 137 ::rtl::OUString::createFromAscii( 138 "no accessible child with index ") + nIndex, 139 mxParent); 140 141 return GetChild (maVisibleChildren[nIndex],nIndex); 142 } 143 144 145 146 147 /** Return the requested accessible child object. Create it if it is not 148 yet in the cache. 149 */ 150 uno::Reference<XAccessible> 151 ChildrenManagerImpl::GetChild (ChildDescriptor& rChildDescriptor,sal_Int32 _nIndex) 152 throw (::com::sun::star::uno::RuntimeException) 153 { 154 if ( ! rChildDescriptor.mxAccessibleShape.is()) 155 { 156 ::osl::MutexGuard aGuard (maMutex); 157 // Make sure that the requested accessible object has not been 158 // created while locking the global mutex. 159 if ( ! rChildDescriptor.mxAccessibleShape.is()) 160 { 161 AccessibleShapeInfo aShapeInfo( 162 rChildDescriptor.mxShape, 163 mxParent, 164 this, 165 mnNewNameIndex++); 166 // Create accessible object that corresponds to the descriptor's 167 // shape. 168 AccessibleShape* pShape = 169 ShapeTypeHandler::Instance().CreateAccessibleObject ( 170 aShapeInfo, 171 maShapeTreeInfo); 172 rChildDescriptor.mxAccessibleShape = uno::Reference<XAccessible> ( 173 static_cast<uno::XWeak*>(pShape), 174 uno::UNO_QUERY); 175 // Now that there is a reference to the new accessible shape we 176 // can safely call its Init() method. 177 if ( pShape != NULL ) 178 { 179 pShape->Init(); 180 pShape->setIndexInParent(_nIndex); 181 } 182 } 183 } 184 185 return rChildDescriptor.mxAccessibleShape; 186 } 187 188 189 190 191 uno::Reference<XAccessible> 192 ChildrenManagerImpl::GetChild (const uno::Reference<drawing::XShape>& xShape) 193 throw (uno::RuntimeException) 194 { 195 ChildDescriptorListType::iterator I, aEnd = maVisibleChildren.end(); 196 for (I = maVisibleChildren.begin(); I != aEnd; ++I) 197 { 198 if ( I->mxShape.get() == xShape.get() ) 199 return I->mxAccessibleShape; 200 } 201 return uno::Reference<XAccessible> (); 202 } 203 204 205 206 207 /** Find all shapes among the specified shapes that lie fully or partially 208 inside the visible area. Put those shapes into the cleared cache. The 209 corresponding accessible objects will be created on demand. 210 211 At the moment, first all accessible objects are removed from the cache 212 and the appropriate listeners are informed of this. Next, the list is 213 created again. This should be optimized in the future to not remove and 214 create objects that will be in the list before and after the update 215 method. 216 */ 217 void ChildrenManagerImpl::Update (bool bCreateNewObjectsOnDemand) 218 { 219 if (maShapeTreeInfo.GetViewForwarder() == NULL) 220 return; 221 Rectangle aVisibleArea = maShapeTreeInfo.GetViewForwarder()->GetVisibleArea(); 222 223 // 1. Create a local list of visible shapes. 224 ChildDescriptorListType aChildList; 225 CreateListOfVisibleShapes (aChildList); 226 227 // 2. Merge the information that is already known about the visible 228 // shapes from the current list into the new list. 229 MergeAccessibilityInformation (aChildList); 230 231 // 3. Replace the current list of visible shapes with the new one. Do 232 // the same with the visible area. 233 { 234 ::osl::MutexGuard aGuard (maMutex); 235 adjustIndexInParentOfShapes(aChildList); 236 237 // Use swap to copy the contents of the new list in constant time. 238 maVisibleChildren.swap (aChildList); 239 240 // aChildList now contains all the old children, while maVisibleChildren 241 // contains all the current children 242 243 // 4. Find all shapes in the old list that are not in the current list, 244 // send appropriate events and remove the accessible shape. 245 // 246 // Do this *after* we have set our new list of children, because 247 // removing a child may cause 248 // 249 // ChildDescriptor::disposeAccessibleObject --> 250 // AccessibleContextBase::CommitChange --> 251 // AtkListener::notifyEvent -> 252 // AtkListener::handleChildRemoved -> 253 // AtkListener::updateChildList 254 // AccessibleDrawDocumentView::getAccessibleChildCount -> 255 // ChildrenManagerImpl::GetChildCount -> 256 // maVisibleChildren.size() 257 // 258 // to be fired, and so the operations will take place on 259 // the list we are trying to replace 260 // 261 RemoveNonVisibleChildren (maVisibleChildren, aChildList); 262 263 aChildList.clear(); 264 265 maVisibleArea = aVisibleArea; 266 } 267 268 // 5. If the visible area has changed then send events that signal a 269 // change of their bounding boxes for all shapes that are members of 270 // both the current and the new list of visible shapes. 271 if (maVisibleArea != aVisibleArea) 272 SendVisibleAreaEvents (maVisibleChildren); 273 274 // 6. If children have to be created immediately and not on demand then 275 // create the missing accessible objects now. 276 if ( ! bCreateNewObjectsOnDemand) 277 CreateAccessibilityObjects (maVisibleChildren); 278 } 279 280 281 282 283 void ChildrenManagerImpl::CreateListOfVisibleShapes ( 284 ChildDescriptorListType& raDescriptorList) 285 { 286 ::osl::MutexGuard aGuard (maMutex); 287 288 OSL_ASSERT (maShapeTreeInfo.GetViewForwarder() != NULL); 289 290 Rectangle aVisibleArea = maShapeTreeInfo.GetViewForwarder()->GetVisibleArea(); 291 292 // Add the visible shapes for wich the accessible objects already exist. 293 AccessibleShapeList::iterator I,aEnd = maAccessibleShapes.end(); 294 for (I=maAccessibleShapes.begin(); I != aEnd; ++I) 295 { 296 if (I->is()) 297 { 298 uno::Reference<XAccessibleComponent> xComponent ( 299 (*I)->getAccessibleContext(), uno::UNO_QUERY); 300 if (xComponent.is()) 301 { 302 // The bounding box of the object already is clipped to the 303 // visible area. The object is therefore visible if the 304 // bounding box has non-zero extensions. 305 awt::Rectangle aPixelBBox (xComponent->getBounds()); 306 if ((aPixelBBox.Width > 0) && (aPixelBBox.Height > 0)) 307 raDescriptorList.push_back (ChildDescriptor (*I)); 308 } 309 } 310 } 311 312 // Add the visible shapes for which only the XShapes exist. 313 uno::Reference<container::XIndexAccess> xShapeAccess (mxShapeList, uno::UNO_QUERY); 314 if (xShapeAccess.is()) 315 { 316 sal_Int32 nShapeCount = xShapeAccess->getCount(); 317 raDescriptorList.reserve( nShapeCount ); 318 awt::Point aPos; 319 awt::Size aSize; 320 Rectangle aBoundingBox; 321 uno::Reference<drawing::XShape> xShape; 322 for (sal_Int32 i=0; i<nShapeCount; ++i) 323 { 324 xShapeAccess->getByIndex(i) >>= xShape; 325 aPos = xShape->getPosition(); 326 aSize = xShape->getSize(); 327 328 aBoundingBox.nLeft = aPos.X; 329 aBoundingBox.nTop = aPos.Y; 330 aBoundingBox.nRight = aPos.X + aSize.Width; 331 aBoundingBox.nBottom = aPos.Y + aSize.Height; 332 333 // Insert shape if it is visible, i.e. its bounding box overlaps 334 // the visible area. 335 if ( aBoundingBox.IsOver (aVisibleArea) ) 336 raDescriptorList.push_back (ChildDescriptor (xShape)); 337 } 338 } 339 } 340 341 342 343 344 void ChildrenManagerImpl::RemoveNonVisibleChildren ( 345 const ChildDescriptorListType& rNewChildList, 346 ChildDescriptorListType& rOldChildList) 347 { 348 // Iterate over list of formerly visible children and remove those that 349 // are not visible anymore, i.e. member of the new list of visible 350 // children. 351 ChildDescriptorListType::iterator I, aEnd = rOldChildList.end(); 352 for (I=rOldChildList.begin(); I != aEnd; ++I) 353 { 354 if (::std::find(rNewChildList.begin(), rNewChildList.end(), *I) == rNewChildList.end()) 355 { 356 // The child is disposed when there is a UNO shape from which 357 // the accessible shape can be created when the shape becomes 358 // visible again. When there is no such UNO shape then simply 359 // reset the descriptor but keep the accessibility object. 360 if (I->mxShape.is()) 361 { 362 UnregisterAsDisposeListener (I->mxShape); 363 I->disposeAccessibleObject (mrContext); 364 } 365 else 366 { 367 AccessibleShape* pAccessibleShape = I->GetAccessibleShape(); 368 pAccessibleShape->ResetState (AccessibleStateType::VISIBLE); 369 I->mxAccessibleShape = NULL; 370 } 371 } 372 } 373 } 374 375 376 377 378 void ChildrenManagerImpl::MergeAccessibilityInformation ( 379 ChildDescriptorListType& raNewChildList) 380 { 381 ChildDescriptorListType::iterator aOldChildDescriptor; 382 ChildDescriptorListType::iterator I, aEnd = raNewChildList.end(); 383 for (I=raNewChildList.begin(); I != aEnd; ++I) 384 { 385 aOldChildDescriptor = ::std::find (maVisibleChildren.begin(), maVisibleChildren.end(), *I); 386 387 // Copy accessible shape if that exists in the old descriptor. 388 bool bRegistrationIsNecessary = true; 389 if (aOldChildDescriptor != maVisibleChildren.end()) 390 if (aOldChildDescriptor->mxAccessibleShape.is()) 391 { 392 I->mxAccessibleShape = aOldChildDescriptor->mxAccessibleShape; 393 I->mbCreateEventPending = false; 394 bRegistrationIsNecessary = false; 395 } 396 if (bRegistrationIsNecessary) 397 RegisterAsDisposeListener (I->mxShape); 398 } 399 } 400 401 402 403 404 void ChildrenManagerImpl::SendVisibleAreaEvents ( 405 ChildDescriptorListType& raNewChildList) 406 { 407 ChildDescriptorListType::iterator I,aEnd = raNewChildList.end(); 408 for (I=raNewChildList.begin(); I != aEnd; ++I) 409 { 410 // Tell shape of changed visible area. To do this, fake a 411 // change of the view forwarder. (Actually we usually get here 412 // as a result of a change of the view forwarder). 413 AccessibleShape* pShape = I->GetAccessibleShape (); 414 if (pShape != NULL) 415 pShape->ViewForwarderChanged ( 416 IAccessibleViewForwarderListener::VISIBLE_AREA, 417 maShapeTreeInfo.GetViewForwarder()); 418 } 419 } 420 421 422 423 424 void ChildrenManagerImpl::CreateAccessibilityObjects ( 425 ChildDescriptorListType& raNewChildList) 426 { 427 ChildDescriptorListType::iterator I, aEnd = raNewChildList.end(); 428 sal_Int32 nPos = 0; 429 for ( I = raNewChildList.begin(); I != aEnd; ++I,++nPos) 430 { 431 // Create the associated accessible object when the flag says so and 432 // it does not yet exist. 433 if ( ! I->mxAccessibleShape.is() ) 434 GetChild (*I,nPos); 435 if (I->mxAccessibleShape.is() && I->mbCreateEventPending) 436 { 437 I->mbCreateEventPending = false; 438 mrContext.CommitChange ( 439 AccessibleEventId::CHILD, 440 uno::makeAny(I->mxAccessibleShape), 441 uno::Any()); 442 } 443 } 444 } 445 446 447 448 449 void ChildrenManagerImpl::AddShape (const Reference<drawing::XShape>& rxShape) 450 { 451 if (rxShape.is()) 452 { 453 ::osl::ClearableMutexGuard aGuard (maMutex); 454 455 // Test visibility of the shape. 456 Rectangle aVisibleArea = maShapeTreeInfo.GetViewForwarder()->GetVisibleArea(); 457 awt::Point aPos = rxShape->getPosition(); 458 awt::Size aSize = rxShape->getSize(); 459 460 Rectangle aBoundingBox ( 461 aPos.X, 462 aPos.Y, 463 aPos.X + aSize.Width, 464 aPos.Y + aSize.Height); 465 466 // Add the shape only when it belongs to the list of shapes stored 467 // in mxShapeList (which is either a page or a group shape). 468 Reference<container::XChild> xChild (rxShape, uno::UNO_QUERY); 469 if (xChild.is()) 470 { 471 Reference<drawing::XShapes> xParent (xChild->getParent(), uno::UNO_QUERY); 472 if (xParent == mxShapeList) 473 if (aBoundingBox.IsOver (aVisibleArea)) 474 { 475 // Add shape to list of visible shapes. 476 maVisibleChildren.push_back (ChildDescriptor (rxShape)); 477 478 // Create accessibility object. 479 ChildDescriptor& rDescriptor = maVisibleChildren.back(); 480 GetChild (rDescriptor, maVisibleChildren.size()-1); 481 482 // Inform listeners about new child. 483 uno::Any aNewShape; 484 aNewShape <<= rDescriptor.mxAccessibleShape; 485 aGuard.clear(); 486 mrContext.CommitChange ( 487 AccessibleEventId::CHILD, 488 aNewShape, 489 uno::Any()); 490 RegisterAsDisposeListener (rDescriptor.mxShape); 491 } 492 } 493 } 494 } 495 496 497 498 499 void ChildrenManagerImpl::RemoveShape (const Reference<drawing::XShape>& rxShape) 500 { 501 if (rxShape.is()) 502 { 503 ::osl::ClearableMutexGuard aGuard (maMutex); 504 505 // Search shape in list of visible children. 506 ChildDescriptorListType::iterator I ( 507 ::std::find (maVisibleChildren.begin(), maVisibleChildren.end(), 508 ChildDescriptor (rxShape))); 509 if (I != maVisibleChildren.end()) 510 { 511 // Remove descriptor from that list. 512 Reference<XAccessible> xAccessibleShape (I->mxAccessibleShape); 513 514 UnregisterAsDisposeListener (I->mxShape); 515 // Dispose the accessible object. 516 I->disposeAccessibleObject (mrContext); 517 518 // Now we can safely remove the child descriptor and thus 519 // invalidate the iterator. 520 maVisibleChildren.erase (I); 521 522 adjustIndexInParentOfShapes(maVisibleChildren); 523 } 524 } 525 } 526 527 528 529 530 void ChildrenManagerImpl::SetShapeList (const ::com::sun::star::uno::Reference< 531 ::com::sun::star::drawing::XShapes>& xShapeList) 532 { 533 mxShapeList = xShapeList; 534 } 535 536 537 538 539 void ChildrenManagerImpl::AddAccessibleShape (std::auto_ptr<AccessibleShape> pShape) 540 { 541 if (pShape.get() != NULL) 542 maAccessibleShapes.push_back (pShape.release()); 543 } 544 545 546 547 548 void ChildrenManagerImpl::ClearAccessibleShapeList (void) 549 { 550 // Copy the list of (visible) shapes to local lists and clear the 551 // originals. 552 ChildDescriptorListType aLocalVisibleChildren; 553 aLocalVisibleChildren.swap(maVisibleChildren); 554 AccessibleShapeList aLocalAccessibleShapes; 555 aLocalAccessibleShapes.swap(maAccessibleShapes); 556 557 // Tell the listeners that all children are gone. 558 mrContext.CommitChange ( 559 AccessibleEventId::INVALIDATE_ALL_CHILDREN, 560 uno::Any(), 561 uno::Any()); 562 563 // There are no accessible shapes left so the index assigned to new 564 // accessible shapes can be reset. 565 mnNewNameIndex = 1; 566 567 // Now the objects in the local lists can be safely disposed without 568 // having problems with callers that want to update their child lists. 569 570 // Clear the list of visible accessible objects. Objects not created on 571 // demand for XShapes are treated below. 572 ChildDescriptorListType::iterator I,aEnd = aLocalVisibleChildren.end(); 573 for (I=aLocalVisibleChildren.begin(); I != aEnd; ++I) 574 if ( I->mxAccessibleShape.is() && I->mxShape.is() ) 575 { 576 ::comphelper::disposeComponent(I->mxAccessibleShape); 577 I->mxAccessibleShape = NULL; 578 } 579 580 // Dispose all objects in the accessible shape list. 581 AccessibleShapeList::iterator J,aEnd2 = aLocalAccessibleShapes.end(); 582 for (J=aLocalAccessibleShapes.begin(); J != aEnd2; ++J) 583 if (J->is()) 584 { 585 // Dispose the object. 586 ::comphelper::disposeComponent(*J); 587 *J = NULL; 588 } 589 } 590 591 592 593 594 /** If the broadcasters change at which this object is registered then 595 unregister at old and register at new broadcasters. 596 */ 597 void ChildrenManagerImpl::SetInfo (const AccessibleShapeTreeInfo& rShapeTreeInfo) 598 { 599 // Remember the current broadcasters and exchange the shape tree info. 600 Reference<document::XEventBroadcaster> xCurrentBroadcaster; 601 Reference<frame::XController> xCurrentController; 602 Reference<view::XSelectionSupplier> xCurrentSelectionSupplier; 603 { 604 ::osl::MutexGuard aGuard (maMutex); 605 xCurrentBroadcaster = maShapeTreeInfo.GetModelBroadcaster(); 606 xCurrentController = maShapeTreeInfo.GetController(); 607 xCurrentSelectionSupplier = Reference<view::XSelectionSupplier> ( 608 xCurrentController, uno::UNO_QUERY); 609 maShapeTreeInfo = rShapeTreeInfo; 610 } 611 612 // Move registration to new model. 613 if (maShapeTreeInfo.GetModelBroadcaster() != xCurrentBroadcaster) 614 { 615 // Register at new broadcaster. 616 if (maShapeTreeInfo.GetModelBroadcaster().is()) 617 maShapeTreeInfo.GetModelBroadcaster()->addEventListener ( 618 static_cast<document::XEventListener*>(this)); 619 620 // Unregister at old broadcaster. 621 if (xCurrentBroadcaster.is()) 622 xCurrentBroadcaster->removeEventListener ( 623 static_cast<document::XEventListener*>(this)); 624 } 625 626 // Move registration to new selection supplier. 627 Reference<frame::XController> xNewController(maShapeTreeInfo.GetController()); 628 Reference<view::XSelectionSupplier> xNewSelectionSupplier ( 629 xNewController, uno::UNO_QUERY); 630 if (xNewSelectionSupplier != xCurrentSelectionSupplier) 631 { 632 // Register at new broadcaster. 633 if (xNewSelectionSupplier.is()) 634 { 635 xNewController->addEventListener( 636 static_cast<document::XEventListener*>(this)); 637 638 xNewSelectionSupplier->addSelectionChangeListener ( 639 static_cast<view::XSelectionChangeListener*>(this)); 640 } 641 642 // Unregister at old broadcaster. 643 if (xCurrentSelectionSupplier.is()) 644 { 645 xCurrentSelectionSupplier->removeSelectionChangeListener ( 646 static_cast<view::XSelectionChangeListener*>(this)); 647 648 xCurrentController->removeEventListener( 649 static_cast<document::XEventListener*>(this)); 650 } 651 } 652 } 653 654 655 656 657 //===== lang::XEventListener ================================================ 658 659 void SAL_CALL 660 ChildrenManagerImpl::disposing (const lang::EventObject& rEventObject) 661 throw (uno::RuntimeException) 662 { 663 if (rEventObject.Source == maShapeTreeInfo.GetModelBroadcaster() 664 || rEventObject.Source == maShapeTreeInfo.GetController()) 665 { 666 impl_dispose(); 667 } 668 669 // Handle disposing UNO shapes. 670 else 671 { 672 Reference<drawing::XShape> xShape (rEventObject.Source, uno::UNO_QUERY); 673 674 // Find the descriptor for the given shape. 675 ChildDescriptorListType::iterator I ( 676 ::std::find (maVisibleChildren.begin(), maVisibleChildren.end(), 677 ChildDescriptor (xShape))); 678 if (I != maVisibleChildren.end()) 679 { 680 // Clear the descriptor. 681 I->disposeAccessibleObject (mrContext); 682 I->mxShape = NULL; 683 } 684 } 685 } 686 687 688 689 690 //===== document::XEventListener ============================================ 691 692 /** Listen for new and removed shapes. 693 */ 694 void SAL_CALL 695 ChildrenManagerImpl::notifyEvent ( 696 const document::EventObject& rEventObject) 697 throw (uno::RuntimeException) 698 { 699 static const ::rtl::OUString sShapeInserted ( 700 RTL_CONSTASCII_USTRINGPARAM("ShapeInserted")); 701 static const ::rtl::OUString sShapeRemoved ( 702 RTL_CONSTASCII_USTRINGPARAM("ShapeRemoved")); 703 704 705 if (rEventObject.EventName.equals (sShapeInserted)) 706 AddShape (Reference<drawing::XShape>(rEventObject.Source, uno::UNO_QUERY)); 707 else if (rEventObject.EventName.equals (sShapeRemoved)) 708 RemoveShape (Reference<drawing::XShape>(rEventObject.Source, uno::UNO_QUERY)); 709 // else ignore unknown event. 710 } 711 712 713 714 715 //===== view::XSelectionChangeListener ====================================== 716 717 void SAL_CALL 718 ChildrenManagerImpl::selectionChanged (const lang::EventObject& /*rEvent*/) 719 throw (uno::RuntimeException) 720 { 721 UpdateSelection (); 722 } 723 724 725 726 727 void ChildrenManagerImpl::impl_dispose (void) 728 { 729 Reference<frame::XController> xController(maShapeTreeInfo.GetController()); 730 // Remove from broadcasters. 731 try 732 { 733 Reference<view::XSelectionSupplier> xSelectionSupplier ( 734 xController, uno::UNO_QUERY); 735 if (xSelectionSupplier.is()) 736 { 737 xSelectionSupplier->removeSelectionChangeListener ( 738 static_cast<view::XSelectionChangeListener*>(this)); 739 } 740 } 741 catch( uno::RuntimeException&) 742 {} 743 744 try 745 { 746 if (xController.is()) 747 xController->removeEventListener( 748 static_cast<document::XEventListener*>(this)); 749 } 750 catch( uno::RuntimeException&) 751 {} 752 753 maShapeTreeInfo.SetController (NULL); 754 755 try 756 { 757 // Remove from broadcaster. 758 if (maShapeTreeInfo.GetModelBroadcaster().is()) 759 maShapeTreeInfo.GetModelBroadcaster()->removeEventListener ( 760 static_cast<document::XEventListener*>(this)); 761 maShapeTreeInfo.SetModelBroadcaster (NULL); 762 } 763 catch( uno::RuntimeException& ) 764 {} 765 766 ClearAccessibleShapeList (); 767 SetShapeList (NULL); 768 } 769 770 771 772 void SAL_CALL ChildrenManagerImpl::disposing (void) 773 { 774 impl_dispose(); 775 } 776 777 778 779 780 // This method is experimental. Use with care. 781 long int ChildrenManagerImpl::GetChildIndex (const ::com::sun::star::uno::Reference< 782 ::com::sun::star::accessibility::XAccessible>& xChild) const 783 throw (::com::sun::star::uno::RuntimeException) 784 { 785 ::osl::MutexGuard aGuard (maMutex); 786 sal_Int32 nCount = maVisibleChildren.size(); 787 for (sal_Int32 i=0; i < nCount; ++i) 788 { 789 // Is this equality comparison valid? 790 if (maVisibleChildren[i].mxAccessibleShape == xChild) 791 return i; 792 } 793 794 return -1; 795 } 796 797 798 799 800 //===== IAccessibleViewForwarderListener ==================================== 801 802 void ChildrenManagerImpl::ViewForwarderChanged (ChangeType aChangeType, 803 const IAccessibleViewForwarder* pViewForwarder) 804 { 805 if (aChangeType == IAccessibleViewForwarderListener::VISIBLE_AREA) 806 Update (false); 807 else 808 { 809 ::osl::MutexGuard aGuard (maMutex); 810 ChildDescriptorListType::iterator I, aEnd = maVisibleChildren.end(); 811 for (I=maVisibleChildren.begin(); I != aEnd; ++I) 812 { 813 AccessibleShape* pShape = I->GetAccessibleShape(); 814 if (pShape != NULL) 815 pShape->ViewForwarderChanged (aChangeType, pViewForwarder); 816 } 817 } 818 } 819 820 821 822 823 //===== IAccessibleParent =================================================== 824 825 sal_Bool ChildrenManagerImpl::ReplaceChild ( 826 AccessibleShape* pCurrentChild, 827 const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& _rxShape, 828 const long _nIndex, 829 const AccessibleShapeTreeInfo& _rShapeTreeInfo) 830 throw (uno::RuntimeException) 831 { 832 AccessibleShapeInfo aShapeInfo( _rxShape, pCurrentChild->getAccessibleParent(), this, _nIndex ); 833 // create the new child 834 AccessibleShape* pNewChild = ShapeTypeHandler::Instance().CreateAccessibleObject ( 835 aShapeInfo, 836 _rShapeTreeInfo 837 ); 838 Reference< XAccessible > xNewChild( pNewChild ); // keep this alive (do this before calling Init!) 839 if ( pNewChild ) 840 pNewChild->Init(); 841 842 sal_Bool bResult = sal_False; 843 844 // Iterate over the visible children. If one of them has an already 845 // created accessible object that matches pCurrentChild then replace 846 // it. Otherwise the child to replace is either not in the list or has 847 // not ye been created (and is therefore not in the list, too) and a 848 // replacement is not necessary. 849 ChildDescriptorListType::iterator I,aEnd = maVisibleChildren.end(); 850 for (I=maVisibleChildren.begin(); I != aEnd; ++I) 851 { 852 if (I->GetAccessibleShape() == pCurrentChild) 853 { 854 // Dispose the current child and send an event about its deletion. 855 pCurrentChild->dispose(); 856 mrContext.CommitChange ( 857 AccessibleEventId::CHILD, 858 uno::Any(), 859 uno::makeAny (I->mxAccessibleShape)); 860 861 // Replace with replacement and send an event about existance 862 // of the new child. 863 I->mxAccessibleShape = pNewChild; 864 mrContext.CommitChange ( 865 AccessibleEventId::CHILD, 866 uno::makeAny (I->mxAccessibleShape), 867 uno::Any()); 868 bResult = sal_True; 869 break; 870 } 871 } 872 873 // When not found among the visible children we have to search the list 874 // of accessible shapes. This is not yet implemented. 875 876 return bResult; 877 } 878 879 880 881 882 /** Update the <const>SELECTED</const> and the <const>FOCUSED</const> state 883 of all visible children. Maybe this should be changed to all children. 884 885 Iterate over all descriptors of visible accessible shapes and look them 886 up in the selection. 887 888 If there is no valid controller then all shapes are deselected and 889 unfocused. If the controller's frame is not active then all shapes are 890 unfocused. 891 */ 892 void ChildrenManagerImpl::UpdateSelection (void) 893 { 894 Reference<frame::XController> xController(maShapeTreeInfo.GetController()); 895 Reference<view::XSelectionSupplier> xSelectionSupplier ( 896 xController, uno::UNO_QUERY); 897 898 // Try to cast the selection both to a multi selection and to a single 899 // selection. 900 Reference<container::XIndexAccess> xSelectedShapeAccess; 901 Reference<drawing::XShape> xSelectedShape; 902 if (xSelectionSupplier.is()) 903 { 904 xSelectedShapeAccess = Reference<container::XIndexAccess> ( 905 xSelectionSupplier->getSelection(), uno::UNO_QUERY); 906 xSelectedShape = Reference<drawing::XShape> ( 907 xSelectionSupplier->getSelection(), uno::UNO_QUERY); 908 } 909 910 // Remember the current and new focused shape. 911 AccessibleShape* pCurrentlyFocusedShape = NULL; 912 AccessibleShape* pNewFocusedShape = NULL; 913 914 ChildDescriptorListType::iterator I, aEnd = maVisibleChildren.end(); 915 for (I=maVisibleChildren.begin(); I != aEnd; ++I) 916 { 917 AccessibleShape* pAccessibleShape = I->GetAccessibleShape(); 918 if (I->mxAccessibleShape.is() && I->mxShape.is() && pAccessibleShape!=NULL) 919 { 920 bool bShapeIsSelected = false; 921 922 // Look up the shape in the (single or multi-) selection. 923 if (xSelectedShape.is()) 924 { 925 if (I->mxShape == xSelectedShape) 926 { 927 bShapeIsSelected = true; 928 pNewFocusedShape = pAccessibleShape; 929 } 930 } 931 else if (xSelectedShapeAccess.is()) 932 { 933 sal_Int32 nCount=xSelectedShapeAccess->getCount(); 934 for (sal_Int32 i=0; i<nCount&&!bShapeIsSelected; i++) 935 if (xSelectedShapeAccess->getByIndex(i) == I->mxShape) 936 { 937 bShapeIsSelected = true; 938 // In a multi-selection no shape has the focus. 939 if (nCount == 1) 940 pNewFocusedShape = pAccessibleShape; 941 } 942 } 943 944 // Set or reset the SELECTED state. 945 if (bShapeIsSelected) 946 pAccessibleShape->SetState (AccessibleStateType::SELECTED); 947 else 948 pAccessibleShape->ResetState (AccessibleStateType::SELECTED); 949 950 // Does the shape have the current selection? 951 if (pAccessibleShape->GetState (AccessibleStateType::FOCUSED)) 952 pCurrentlyFocusedShape = pAccessibleShape; 953 } 954 } 955 956 // Check if the frame we are in is currently active. If not then make 957 // sure to not send a FOCUSED state change. 958 if (xController.is()) 959 { 960 Reference<frame::XFrame> xFrame (xController->getFrame()); 961 if (xFrame.is()) 962 if ( ! xFrame->isActive()) 963 pNewFocusedShape = NULL; 964 } 965 966 // Move focus from current to newly focused shape. 967 if (pCurrentlyFocusedShape != pNewFocusedShape) 968 { 969 if (pCurrentlyFocusedShape != NULL) 970 pCurrentlyFocusedShape->ResetState (AccessibleStateType::FOCUSED); 971 if (pNewFocusedShape != NULL) 972 pNewFocusedShape->SetState (AccessibleStateType::FOCUSED); 973 } 974 975 // Remember whether there is a shape that now has the focus. 976 mpFocusedShape = pNewFocusedShape; 977 } 978 979 980 981 982 bool ChildrenManagerImpl::HasFocus (void) 983 { 984 return mpFocusedShape != NULL; 985 } 986 987 988 989 990 void ChildrenManagerImpl::RemoveFocus (void) 991 { 992 if (mpFocusedShape != NULL) 993 { 994 mpFocusedShape->ResetState (AccessibleStateType::FOCUSED); 995 mpFocusedShape = NULL; 996 } 997 } 998 999 1000 1001 void ChildrenManagerImpl::RegisterAsDisposeListener ( 1002 const Reference<drawing::XShape>& xShape) 1003 { 1004 Reference<lang::XComponent> xComponent (xShape, uno::UNO_QUERY); 1005 if (xComponent.is()) 1006 xComponent->addEventListener ( 1007 static_cast<document::XEventListener*>(this)); 1008 } 1009 1010 1011 1012 1013 void ChildrenManagerImpl::UnregisterAsDisposeListener ( 1014 const Reference<drawing::XShape>& xShape) 1015 { 1016 Reference<lang::XComponent> xComponent (xShape, uno::UNO_QUERY); 1017 if (xComponent.is()) 1018 xComponent->removeEventListener ( 1019 static_cast<document::XEventListener*>(this)); 1020 } 1021 1022 1023 1024 1025 //===== AccessibleChildDescriptor =========================================== 1026 1027 ChildDescriptor::ChildDescriptor (const Reference<drawing::XShape>& xShape) 1028 : mxShape (xShape), 1029 mxAccessibleShape (NULL), 1030 mbCreateEventPending (true) 1031 { 1032 // Empty. 1033 } 1034 1035 1036 1037 1038 ChildDescriptor::ChildDescriptor (const Reference<XAccessible>& rxAccessibleShape) 1039 : mxShape (NULL), 1040 mxAccessibleShape (rxAccessibleShape), 1041 mbCreateEventPending (true) 1042 { 1043 // Make sure that the accessible object has the <const>VISIBLE</const> 1044 // state set. 1045 AccessibleShape* pAccessibleShape = GetAccessibleShape(); 1046 pAccessibleShape->SetState (AccessibleStateType::VISIBLE); 1047 } 1048 1049 1050 1051 1052 ChildDescriptor::~ChildDescriptor (void) 1053 { 1054 } 1055 1056 1057 1058 1059 AccessibleShape* ChildDescriptor::GetAccessibleShape (void) const 1060 { 1061 return static_cast<AccessibleShape*> (mxAccessibleShape.get()); 1062 } 1063 // ----------------------------------------------------------------------------- 1064 void ChildDescriptor::setIndexAtAccessibleShape(sal_Int32 _nIndex) 1065 { 1066 AccessibleShape* pShape = GetAccessibleShape(); 1067 if ( pShape ) 1068 pShape->setIndexInParent(_nIndex); 1069 } 1070 // ----------------------------------------------------------------------------- 1071 1072 1073 1074 1075 void ChildDescriptor::disposeAccessibleObject (AccessibleContextBase& rParent) 1076 { 1077 if (mxAccessibleShape.is()) 1078 { 1079 // Send event that the shape has been removed. 1080 uno::Any aOldValue; 1081 aOldValue <<= mxAccessibleShape; 1082 rParent.CommitChange ( 1083 AccessibleEventId::CHILD, 1084 uno::Any(), 1085 aOldValue); 1086 1087 // Dispose and remove the object. 1088 Reference<lang::XComponent> xComponent (mxAccessibleShape, uno::UNO_QUERY); 1089 if (xComponent.is()) 1090 xComponent->dispose (); 1091 1092 mxAccessibleShape = NULL; 1093 } 1094 } 1095 1096 1097 } // end of namespace accessibility 1098 1099