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