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