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