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