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