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