1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <AccessibleDocument.hxx> 21 #include <AccessibleSpreadsheet.hxx> 22 #include <tabvwsh.hxx> 23 #include <AccessibilityHints.hxx> 24 #include <document.hxx> 25 #include <drwlayer.hxx> 26 #include <DrawModelBroadcaster.hxx> 27 #include <drawview.hxx> 28 #include <gridwin.hxx> 29 #include <AccessibleEditObject.hxx> 30 #include <userdat.hxx> 31 #include <scresid.hxx> 32 #include <strings.hrc> 33 #include <strings.hxx> 34 #include <markdata.hxx> 35 36 #include <com/sun/star/accessibility/AccessibleEventId.hpp> 37 #include <com/sun/star/accessibility/AccessibleStateType.hpp> 38 #include <com/sun/star/accessibility/AccessibleRelationType.hpp> 39 #include <com/sun/star/accessibility/AccessibleRole.hpp> 40 #include <com/sun/star/view/XSelectionSupplier.hpp> 41 #include <com/sun/star/drawing/ShapeCollection.hpp> 42 #include <com/sun/star/drawing/XShape.hpp> 43 #include <com/sun/star/drawing/XShapes.hpp> 44 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp> 45 46 #include <unotools/accessiblestatesethelper.hxx> 47 #include <tools/gen.hxx> 48 #include <svx/svdpage.hxx> 49 #include <svx/svdobj.hxx> 50 #include <svx/ShapeTypeHandler.hxx> 51 #include <svx/AccessibleShape.hxx> 52 #include <svx/AccessibleShapeTreeInfo.hxx> 53 #include <svx/AccessibleShapeInfo.hxx> 54 #include <svx/IAccessibleParent.hxx> 55 #include <comphelper/sequence.hxx> 56 #include <sfx2/viewfrm.hxx> 57 #include <sfx2/docfile.hxx> 58 #include <svx/unoshape.hxx> 59 #include <unotools/accessiblerelationsethelper.hxx> 60 #include <toolkit/helper/convert.hxx> 61 #include <vcl/svapp.hxx> 62 63 #include <svx/AccessibleControlShape.hxx> 64 #include <svx/SvxShapeTypes.hxx> 65 #include <sfx2/objsh.hxx> 66 #include <editeng/editview.hxx> 67 #include <editeng/editeng.hxx> 68 #include <comphelper/processfactory.hxx> 69 70 #include <algorithm> 71 72 #include <svx/unoapi.hxx> 73 #include <scmod.hxx> 74 75 #ifdef indices 76 #undef indices 77 #endif 78 79 #ifdef extents 80 #undef extents 81 #endif 82 83 using namespace ::com::sun::star; 84 using namespace ::com::sun::star::accessibility; 85 86 //===== internal ======================================================== 87 88 struct ScAccessibleShapeData 89 { 90 ScAccessibleShapeData() : bSelected(false), bSelectable(true) {} 91 ~ScAccessibleShapeData(); 92 mutable rtl::Reference< ::accessibility::AccessibleShape > pAccShape; 93 mutable boost::optional<ScAddress> xRelationCell; // if it is NULL this shape is anchored on the table 94 css::uno::Reference< css::drawing::XShape > xShape; 95 mutable bool bSelected; 96 bool bSelectable; 97 }; 98 99 ScAccessibleShapeData::~ScAccessibleShapeData() 100 { 101 if (pAccShape.is()) 102 { 103 pAccShape->dispose(); 104 } 105 } 106 107 struct ScShapeDataLess 108 { 109 static constexpr OUStringLiteral gsLayerId = "LayerID"; 110 static constexpr OUStringLiteral gsZOrder = "ZOrder"; 111 112 static void ConvertLayerId(sal_Int16& rLayerID) // changes the number of the LayerId so it the accessibility order 113 { 114 // note: MSVC 2017 ICE's if this is written as "switch" so use "if" 115 if (sal_uInt8(SC_LAYER_FRONT) == rLayerID) 116 { 117 rLayerID = 1; 118 } 119 else if (sal_uInt8(SC_LAYER_BACK) == rLayerID) 120 { 121 rLayerID = 0; 122 } 123 else if (sal_uInt8(SC_LAYER_INTERN) == rLayerID) 124 { 125 rLayerID = 2; 126 } 127 else if (sal_uInt8(SC_LAYER_CONTROLS) == rLayerID) 128 { 129 rLayerID = 3; 130 } 131 } 132 static bool LessThanSheet(const ScAccessibleShapeData* pData) 133 { 134 bool bResult(false); 135 uno::Reference< beans::XPropertySet> xProps(pData->xShape, uno::UNO_QUERY); 136 if (xProps.is()) 137 { 138 uno::Any aPropAny = xProps->getPropertyValue(gsLayerId); 139 sal_Int16 nLayerID = 0; 140 if( aPropAny >>= nLayerID ) 141 { 142 if (SdrLayerID(nLayerID) == SC_LAYER_BACK) 143 bResult = true; 144 } 145 } 146 return bResult; 147 } 148 bool operator()(const ScAccessibleShapeData* pData1, const ScAccessibleShapeData* pData2) const 149 { 150 bool bResult(false); 151 if (pData1 && pData2) 152 { 153 uno::Reference< beans::XPropertySet> xProps1(pData1->xShape, uno::UNO_QUERY); 154 uno::Reference< beans::XPropertySet> xProps2(pData2->xShape, uno::UNO_QUERY); 155 if (xProps1.is() && xProps2.is()) 156 { 157 uno::Any aPropAny1 = xProps1->getPropertyValue(gsLayerId); 158 uno::Any aPropAny2 = xProps2->getPropertyValue(gsLayerId); 159 sal_Int16 nLayerID1(0); 160 sal_Int16 nLayerID2(0); 161 if( (aPropAny1 >>= nLayerID1) && (aPropAny2 >>= nLayerID2) ) 162 { 163 if (nLayerID1 == nLayerID2) 164 { 165 uno::Any aAny1 = xProps1->getPropertyValue(gsZOrder); 166 sal_Int32 nZOrder1 = 0; 167 uno::Any aAny2 = xProps2->getPropertyValue(gsZOrder); 168 sal_Int32 nZOrder2 = 0; 169 if ( (aAny1 >>= nZOrder1) && (aAny2 >>= nZOrder2) ) 170 bResult = (nZOrder1 < nZOrder2); 171 } 172 else 173 { 174 ConvertLayerId(nLayerID1); 175 ConvertLayerId(nLayerID2); 176 bResult = (nLayerID1 < nLayerID2); 177 } 178 } 179 } 180 } 181 else if (pData1 && !pData2) 182 bResult = LessThanSheet(pData1); 183 else if (!pData1 && pData2) 184 bResult = !LessThanSheet(pData2); 185 else 186 bResult = false; 187 return bResult; 188 } 189 }; 190 191 class ScChildrenShapes : public SfxListener, 192 public ::accessibility::IAccessibleParent 193 { 194 public: 195 ScChildrenShapes(ScAccessibleDocument* pAccessibleDocument, ScTabViewShell* pViewShell, ScSplitPos eSplitPos); 196 virtual ~ScChildrenShapes() override; 197 198 ///===== SfxListener ===================================================== 199 200 virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override; 201 202 ///===== IAccessibleParent =============================================== 203 204 virtual bool ReplaceChild ( 205 ::accessibility::AccessibleShape* pCurrentChild, 206 const css::uno::Reference< css::drawing::XShape >& _rxShape, 207 const long _nIndex, 208 const ::accessibility::AccessibleShapeTreeInfo& _rShapeTreeInfo 209 ) override; 210 211 virtual ::accessibility::AccessibleControlShape* GetAccControlShapeFromModel 212 (css::beans::XPropertySet* pSet) override; 213 virtual css::uno::Reference< css::accessibility::XAccessible> 214 GetAccessibleCaption (const css::uno::Reference<css::drawing::XShape>& xShape) override; 215 ///===== Internal ======================================================== 216 void SetDrawBroadcaster(); 217 218 sal_Int32 GetCount() const; 219 uno::Reference< XAccessible > Get(const ScAccessibleShapeData* pData) const; 220 uno::Reference< XAccessible > Get(sal_Int32 nIndex) const; 221 uno::Reference< XAccessible > GetAt(const awt::Point& rPoint) const; 222 223 // gets the index of the shape starting on 0 (without the index of the table) 224 // returns the selected shape 225 bool IsSelected(sal_Int32 nIndex, 226 css::uno::Reference<css::drawing::XShape>& rShape) const; 227 228 bool SelectionChanged(); 229 230 void Select(sal_Int32 nIndex); 231 void DeselectAll(); // deselect also the table 232 void SelectAll(); 233 sal_Int32 GetSelectedCount() const; 234 uno::Reference< XAccessible > GetSelected(sal_Int32 nSelectedChildIndex, bool bTabSelected) const; 235 void Deselect(sal_Int32 nChildIndex); 236 237 SdrPage* GetDrawPage() const; 238 239 utl::AccessibleRelationSetHelper* GetRelationSet(const ScAddress* pAddress) const; 240 241 void VisAreaChanged() const; 242 private: 243 typedef std::vector<ScAccessibleShapeData*> SortedShapes; 244 typedef std::unordered_map<css::uno::Reference< css::drawing::XShape >, ScAccessibleShapeData*> ShapesMap; 245 246 mutable SortedShapes maZOrderedShapes; // a null pointer represents the sheet in the correct order 247 mutable ShapesMap maShapesMap; 248 mutable bool mbShapesNeedSorting; // set if maZOrderedShapes needs sorting 249 250 mutable ::accessibility::AccessibleShapeTreeInfo maShapeTreeInfo; 251 mutable css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier; 252 mutable size_t mnSdrObjCount; 253 mutable sal_uInt32 mnShapesSelected; 254 ScTabViewShell* mpViewShell; 255 ScAccessibleDocument* mpAccessibleDocument; 256 ScSplitPos const meSplitPos; 257 258 void FillShapes(std::vector < uno::Reference < drawing::XShape > >& rShapes) const; 259 bool FindSelectedShapesChanges(const css::uno::Reference<css::drawing::XShapes>& xShapes) const; 260 261 boost::optional<ScAddress> GetAnchor(const uno::Reference<drawing::XShape>& xShape) const; 262 uno::Reference<XAccessibleRelationSet> GetRelationSet(const ScAccessibleShapeData* pData) const; 263 void SetAnchor(const uno::Reference<drawing::XShape>& xShape, ScAccessibleShapeData* pData) const; 264 void AddShape(const uno::Reference<drawing::XShape>& xShape, bool bCommitChange) const; 265 void RemoveShape(const uno::Reference<drawing::XShape>& xShape) const; 266 267 bool FindShape(const uno::Reference<drawing::XShape>& xShape, SortedShapes::iterator& rItr) const; 268 269 static sal_Int8 Compare(const ScAccessibleShapeData* pData1, 270 const ScAccessibleShapeData* pData2); 271 }; 272 273 ScChildrenShapes::ScChildrenShapes(ScAccessibleDocument* pAccessibleDocument, ScTabViewShell* pViewShell, ScSplitPos eSplitPos) 274 : 275 mbShapesNeedSorting(false), 276 mnShapesSelected(0), 277 mpViewShell(pViewShell), 278 mpAccessibleDocument(pAccessibleDocument), 279 meSplitPos(eSplitPos) 280 { 281 if (mpViewShell) 282 { 283 SfxViewFrame* pViewFrame = mpViewShell->GetViewFrame(); 284 if (pViewFrame) 285 { 286 xSelectionSupplier = uno::Reference<view::XSelectionSupplier>(pViewFrame->GetFrame().GetController(), uno::UNO_QUERY); 287 if (xSelectionSupplier.is()) 288 { 289 xSelectionSupplier->addSelectionChangeListener(mpAccessibleDocument); 290 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes()); 291 if (xShapes.is()) 292 mnShapesSelected = xShapes->getCount(); 293 } 294 } 295 } 296 297 maZOrderedShapes.push_back(nullptr); // add an element which represents the table 298 299 GetCount(); // fill list with filtered shapes (no internal shapes) 300 301 if (mnShapesSelected) 302 { 303 //set flag on every selected shape 304 if (!xSelectionSupplier.is()) 305 throw uno::RuntimeException(); 306 307 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes()); 308 if (xShapes.is()) 309 FindSelectedShapesChanges(xShapes); 310 } 311 if (pViewShell) 312 { 313 ScViewData& rViewData = pViewShell->GetViewData(); 314 SfxBroadcaster* pDrawBC = rViewData.GetDocument()->GetDrawBroadcaster(); 315 if (pDrawBC) 316 { 317 StartListening(*pDrawBC); 318 319 maShapeTreeInfo.SetModelBroadcaster( new ScDrawModelBroadcaster(rViewData.GetDocument()->GetDrawLayer()) ); 320 maShapeTreeInfo.SetSdrView(rViewData.GetScDrawView()); 321 maShapeTreeInfo.SetController(nullptr); 322 maShapeTreeInfo.SetDevice(pViewShell->GetWindowByPos(meSplitPos)); 323 maShapeTreeInfo.SetViewForwarder(mpAccessibleDocument); 324 } 325 } 326 } 327 328 ScChildrenShapes::~ScChildrenShapes() 329 { 330 for (ScAccessibleShapeData* pShapeData : maZOrderedShapes) 331 delete pShapeData; 332 if (mpViewShell) 333 { 334 SfxBroadcaster* pDrawBC = mpViewShell->GetViewData().GetDocument()->GetDrawBroadcaster(); 335 if (pDrawBC) 336 EndListening(*pDrawBC); 337 } 338 if (mpAccessibleDocument && xSelectionSupplier.is()) 339 xSelectionSupplier->removeSelectionChangeListener(mpAccessibleDocument); 340 } 341 342 void ScChildrenShapes::SetDrawBroadcaster() 343 { 344 if (mpViewShell) 345 { 346 ScViewData& rViewData = mpViewShell->GetViewData(); 347 SfxBroadcaster* pDrawBC = rViewData.GetDocument()->GetDrawBroadcaster(); 348 if (pDrawBC) 349 { 350 StartListening(*pDrawBC, DuplicateHandling::Prevent); 351 352 maShapeTreeInfo.SetModelBroadcaster( new ScDrawModelBroadcaster(rViewData.GetDocument()->GetDrawLayer()) ); 353 maShapeTreeInfo.SetSdrView(rViewData.GetScDrawView()); 354 maShapeTreeInfo.SetController(nullptr); 355 maShapeTreeInfo.SetDevice(mpViewShell->GetWindowByPos(meSplitPos)); 356 maShapeTreeInfo.SetViewForwarder(mpAccessibleDocument); 357 } 358 } 359 } 360 361 void ScChildrenShapes::Notify(SfxBroadcaster&, const SfxHint& rHint) 362 { 363 if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint) 364 return; 365 const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint); 366 367 SdrObject* pObj = const_cast<SdrObject*>(pSdrHint->GetObject()); 368 if (pObj && /*(pObj->GetLayer() != SC_LAYER_INTERN) && */(pObj->getSdrPageFromSdrObject() == GetDrawPage()) && 369 (pObj->getSdrPageFromSdrObject() == pObj->getParentSdrObjListFromSdrObject()) ) //only do something if the object lies direct on the page 370 { 371 switch (pSdrHint->GetKind()) 372 { 373 case SdrHintKind::ObjectChange : // object changed 374 { 375 uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY); 376 if (xShape.is()) 377 { 378 mbShapesNeedSorting = true; // sort, because the z index or layer could be changed 379 auto it = maShapesMap.find(xShape); 380 if (it != maShapesMap.end()) 381 SetAnchor(xShape, it->second); 382 } 383 } 384 break; 385 case SdrHintKind::ObjectInserted : // new drawing object inserted 386 { 387 uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY); 388 if (xShape.is()) 389 AddShape(xShape, true); 390 } 391 break; 392 case SdrHintKind::ObjectRemoved : // Removed drawing object from list 393 { 394 uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY); 395 if (xShape.is()) 396 RemoveShape(xShape); 397 } 398 break; 399 default : 400 { 401 // other events are not interesting 402 } 403 break; 404 } 405 } 406 } 407 408 bool ScChildrenShapes::ReplaceChild (::accessibility::AccessibleShape* pCurrentChild, 409 const css::uno::Reference< css::drawing::XShape >& _rxShape, 410 const long /*_nIndex*/, const ::accessibility::AccessibleShapeTreeInfo& _rShapeTreeInfo) 411 { 412 // create the new child 413 rtl::Reference< ::accessibility::AccessibleShape > pReplacement(::accessibility::ShapeTypeHandler::Instance().CreateAccessibleObject ( 414 ::accessibility::AccessibleShapeInfo ( _rxShape, pCurrentChild->getAccessibleParent(), this ), 415 _rShapeTreeInfo 416 )); 417 if ( pReplacement.is() ) 418 pReplacement->Init(); 419 420 bool bResult(false); 421 if (pReplacement.is()) 422 { 423 OSL_ENSURE(pCurrentChild->GetXShape().get() == pReplacement->GetXShape().get(), "XShape changes and should be inserted sorted"); 424 auto it = maShapesMap.find(pCurrentChild->GetXShape()); 425 if (it != maShapesMap.end()) 426 { 427 if (it->second->pAccShape.is()) 428 { 429 OSL_ENSURE(it->second->pAccShape == pCurrentChild, "wrong child found"); 430 AccessibleEventObject aEvent; 431 aEvent.EventId = AccessibleEventId::CHILD; 432 aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument); 433 aEvent.OldValue <<= uno::Reference<XAccessible>(pCurrentChild); 434 435 mpAccessibleDocument->CommitChange(aEvent); // child is gone - event 436 437 pCurrentChild->dispose(); 438 } 439 it->second->pAccShape = pReplacement; 440 AccessibleEventObject aEvent; 441 aEvent.EventId = AccessibleEventId::CHILD; 442 aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument); 443 aEvent.NewValue <<= uno::Reference<XAccessible>(pReplacement.get()); 444 445 mpAccessibleDocument->CommitChange(aEvent); // child is new - event 446 bResult = true; 447 } 448 } 449 return bResult; 450 } 451 452 ::accessibility::AccessibleControlShape * ScChildrenShapes::GetAccControlShapeFromModel(css::beans::XPropertySet* pSet) 453 { 454 GetCount(); // populate 455 for (ScAccessibleShapeData* pShape : maZOrderedShapes) 456 { 457 if (pShape) 458 { 459 rtl::Reference< ::accessibility::AccessibleShape > pAccShape(pShape->pAccShape); 460 if (pAccShape.is() && ::accessibility::ShapeTypeHandler::Instance().GetTypeId (pAccShape->GetXShape()) == ::accessibility::DRAWING_CONTROL) 461 { 462 ::accessibility::AccessibleControlShape *pCtlAccShape = static_cast < ::accessibility::AccessibleControlShape* >(pAccShape.get()); 463 if (pCtlAccShape && pCtlAccShape->GetControlModel() == pSet) 464 return pCtlAccShape; 465 } 466 } 467 } 468 return nullptr; 469 } 470 471 css::uno::Reference < css::accessibility::XAccessible > 472 ScChildrenShapes::GetAccessibleCaption (const css::uno::Reference < css::drawing::XShape>& xShape) 473 { 474 GetCount(); // populate 475 auto it = maShapesMap.find(xShape); 476 if (it == maShapesMap.end()) 477 return nullptr; 478 ScAccessibleShapeData* pShape = it->second; 479 css::uno::Reference< css::accessibility::XAccessible > xNewChild( pShape->pAccShape.get() ); 480 if(xNewChild.get()) 481 return xNewChild; 482 return nullptr; 483 } 484 485 sal_Int32 ScChildrenShapes::GetCount() const 486 { 487 SdrPage* pDrawPage = GetDrawPage(); 488 if (pDrawPage && (maZOrderedShapes.size() == 1)) // the table is always in 489 { 490 mnSdrObjCount = pDrawPage->GetObjCount(); 491 maZOrderedShapes.reserve(mnSdrObjCount + 1); // the table is always in 492 for (size_t i = 0; i < mnSdrObjCount; ++i) 493 { 494 SdrObject* pObj = pDrawPage->GetObj(i); 495 if (pObj/* && (pObj->GetLayer() != SC_LAYER_INTERN)*/) 496 { 497 uno::Reference< drawing::XShape > xShape (pObj->getUnoShape(), uno::UNO_QUERY); 498 AddShape(xShape, false); //inserts in the correct order 499 } 500 } 501 } 502 return maZOrderedShapes.size(); 503 } 504 505 uno::Reference< XAccessible > ScChildrenShapes::Get(const ScAccessibleShapeData* pData) const 506 { 507 if (!pData) 508 return nullptr; 509 510 if (!pData->pAccShape.is()) 511 { 512 ::accessibility::ShapeTypeHandler& rShapeHandler = ::accessibility::ShapeTypeHandler::Instance(); 513 ::accessibility::AccessibleShapeInfo aShapeInfo(pData->xShape, mpAccessibleDocument, const_cast<ScChildrenShapes*>(this)); 514 pData->pAccShape = rShapeHandler.CreateAccessibleObject( 515 aShapeInfo, maShapeTreeInfo); 516 if (pData->pAccShape.is()) 517 { 518 pData->pAccShape->Init(); 519 if (pData->bSelected) 520 pData->pAccShape->SetState(AccessibleStateType::SELECTED); 521 if (!pData->bSelectable) 522 pData->pAccShape->ResetState(AccessibleStateType::SELECTABLE); 523 pData->pAccShape->SetRelationSet(GetRelationSet(pData)); 524 } 525 } 526 return pData->pAccShape.get(); 527 } 528 529 uno::Reference< XAccessible > ScChildrenShapes::Get(sal_Int32 nIndex) const 530 { 531 if (maZOrderedShapes.size() <= 1) 532 GetCount(); // fill list with filtered shapes (no internal shapes) 533 534 if (mbShapesNeedSorting) 535 { 536 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess()); 537 mbShapesNeedSorting = false; 538 } 539 540 if (static_cast<sal_uInt32>(nIndex) >= maZOrderedShapes.size()) 541 return nullptr; 542 543 return Get(maZOrderedShapes[nIndex]); 544 } 545 546 uno::Reference< XAccessible > ScChildrenShapes::GetAt(const awt::Point& rPoint) const 547 { 548 uno::Reference<XAccessible> xAccessible; 549 if(mpViewShell) 550 { 551 if (mbShapesNeedSorting) 552 { 553 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess()); 554 mbShapesNeedSorting = false; 555 } 556 557 sal_Int32 i(maZOrderedShapes.size() - 1); 558 bool bFound(false); 559 while (!bFound && i >= 0) 560 { 561 ScAccessibleShapeData* pShape = maZOrderedShapes[i]; 562 if (pShape) 563 { 564 if (!pShape->pAccShape.is()) 565 Get(pShape); 566 567 if (pShape->pAccShape.is()) 568 { 569 Point aPoint(VCLPoint(rPoint)); 570 aPoint -= VCLRectangle(pShape->pAccShape->getBounds()).TopLeft(); 571 if (pShape->pAccShape->containsPoint(AWTPoint(aPoint))) 572 { 573 xAccessible = pShape->pAccShape.get(); 574 bFound = true; 575 } 576 } 577 else 578 { 579 OSL_FAIL("I should have an accessible shape now!"); 580 } 581 } 582 else 583 bFound = true; // this is the sheet and it lies before the rest of the shapes which are background shapes 584 585 --i; 586 } 587 } 588 return xAccessible; 589 } 590 591 bool ScChildrenShapes::IsSelected(sal_Int32 nIndex, 592 uno::Reference<drawing::XShape>& rShape) const 593 { 594 bool bResult (false); 595 if (maZOrderedShapes.size() <= 1) 596 GetCount(); // fill list with filtered shapes (no internal shapes) 597 598 if (!xSelectionSupplier.is()) 599 throw uno::RuntimeException(); 600 601 if (mbShapesNeedSorting) 602 { 603 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess()); 604 mbShapesNeedSorting = false; 605 } 606 607 if (!maZOrderedShapes[nIndex]) 608 return false; 609 610 bResult = maZOrderedShapes[nIndex]->bSelected; 611 rShape = maZOrderedShapes[nIndex]->xShape; 612 613 #if OSL_DEBUG_LEVEL > 0 // test whether it is truly selected by a slower method 614 uno::Reference< drawing::XShape > xReturnShape; 615 bool bDebugResult(false); 616 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes()); 617 618 if (xShapes.is()) 619 { 620 sal_Int32 nCount(xShapes->getCount()); 621 if (nCount) 622 { 623 uno::Reference< drawing::XShape > xShape; 624 uno::Reference< drawing::XShape > xIndexShape = maZOrderedShapes[nIndex]->xShape; 625 sal_Int32 i(0); 626 while (!bDebugResult && (i < nCount)) 627 { 628 xShapes->getByIndex(i) >>= xShape; 629 if (xShape.is() && (xIndexShape.get() == xShape.get())) 630 { 631 bDebugResult = true; 632 xReturnShape = xShape; 633 } 634 else 635 ++i; 636 } 637 } 638 } 639 OSL_ENSURE((bResult == bDebugResult) && ((bResult && (rShape.get() == xReturnShape.get())) || !bResult), "found the wrong shape or result"); 640 #endif 641 642 return bResult; 643 } 644 645 bool ScChildrenShapes::SelectionChanged() 646 { 647 bool bResult(false); 648 if (!xSelectionSupplier.is()) 649 throw uno::RuntimeException(); 650 651 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes()); 652 653 bResult = FindSelectedShapesChanges(xShapes); 654 655 return bResult; 656 } 657 658 void ScChildrenShapes::Select(sal_Int32 nIndex) 659 { 660 if (maZOrderedShapes.size() <= 1) 661 GetCount(); // fill list with filtered shapes (no internal shapes) 662 663 if (!xSelectionSupplier.is()) 664 throw uno::RuntimeException(); 665 666 if (mbShapesNeedSorting) 667 { 668 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess()); 669 mbShapesNeedSorting = false; 670 } 671 672 if (!maZOrderedShapes[nIndex]) 673 return; 674 675 uno::Reference<drawing::XShape> xShape; 676 if (!IsSelected(nIndex, xShape) && maZOrderedShapes[nIndex]->bSelectable) 677 { 678 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes()); 679 680 if (!xShapes.is()) 681 xShapes = drawing::ShapeCollection::create( 682 comphelper::getProcessComponentContext()); 683 684 xShapes->add(maZOrderedShapes[nIndex]->xShape); 685 686 try 687 { 688 xSelectionSupplier->select(uno::makeAny(xShapes)); 689 maZOrderedShapes[nIndex]->bSelected = true; 690 if (maZOrderedShapes[nIndex]->pAccShape.is()) 691 maZOrderedShapes[nIndex]->pAccShape->SetState(AccessibleStateType::SELECTED); 692 } 693 catch (lang::IllegalArgumentException&) 694 { 695 } 696 } 697 } 698 699 void ScChildrenShapes::DeselectAll() 700 { 701 if (!xSelectionSupplier.is()) 702 throw uno::RuntimeException(); 703 704 bool bSomethingSelected(true); 705 try 706 { 707 xSelectionSupplier->select(uno::Any()); //deselects all 708 } 709 catch (lang::IllegalArgumentException&) 710 { 711 OSL_FAIL("nothing selected before"); 712 bSomethingSelected = false; 713 } 714 715 if (bSomethingSelected) 716 for (const ScAccessibleShapeData* pAccShapeData : maZOrderedShapes) 717 if (pAccShapeData) 718 { 719 pAccShapeData->bSelected = false; 720 if (pAccShapeData->pAccShape.is()) 721 pAccShapeData->pAccShape->ResetState(AccessibleStateType::SELECTED); 722 } 723 }; 724 725 726 void ScChildrenShapes::SelectAll() 727 { 728 if (!xSelectionSupplier.is()) 729 throw uno::RuntimeException(); 730 731 if (maZOrderedShapes.size() <= 1) 732 GetCount(); // fill list with filtered shapes (no internal shapes) 733 734 if (maZOrderedShapes.size() > 1) 735 { 736 uno::Reference<drawing::XShapes> xShapes = drawing::ShapeCollection::create( 737 comphelper::getProcessComponentContext()); 738 739 try 740 { 741 for (const ScAccessibleShapeData* pAccShapeData : maZOrderedShapes) 742 { 743 if (pAccShapeData && pAccShapeData->bSelectable) 744 { 745 pAccShapeData->bSelected = true; 746 if (pAccShapeData->pAccShape.is()) 747 pAccShapeData->pAccShape->SetState(AccessibleStateType::SELECTED); 748 if (xShapes.is()) 749 xShapes->add(pAccShapeData->xShape); 750 } 751 } 752 xSelectionSupplier->select(uno::makeAny(xShapes)); 753 } 754 catch (lang::IllegalArgumentException&) 755 { 756 SelectionChanged(); // find all selected shapes and set the flags 757 } 758 } 759 } 760 761 void ScChildrenShapes::FillShapes(std::vector < uno::Reference < drawing::XShape > >& rShapes) const 762 { 763 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes()); 764 if (xShapes.is()) 765 { 766 sal_uInt32 nCount(xShapes->getCount()); 767 for (sal_uInt32 i = 0; i < nCount; ++i) 768 { 769 uno::Reference<drawing::XShape> xShape; 770 xShapes->getByIndex(i) >>= xShape; 771 if (xShape.is()) 772 rShapes.push_back(xShape); 773 } 774 } 775 } 776 777 sal_Int32 ScChildrenShapes::GetSelectedCount() const 778 { 779 if (!xSelectionSupplier.is()) 780 throw uno::RuntimeException(); 781 782 std::vector < uno::Reference < drawing::XShape > > aShapes; 783 FillShapes(aShapes); 784 785 return aShapes.size(); 786 } 787 788 uno::Reference< XAccessible > ScChildrenShapes::GetSelected(sal_Int32 nSelectedChildIndex, bool bTabSelected) const 789 { 790 uno::Reference< XAccessible > xAccessible; 791 792 if (maZOrderedShapes.size() <= 1) 793 GetCount(); // fill list with shapes 794 795 if (!bTabSelected) 796 { 797 std::vector < uno::Reference < drawing::XShape > > aShapes; 798 FillShapes(aShapes); 799 800 if (nSelectedChildIndex < 0 || static_cast<size_t>(nSelectedChildIndex) >= aShapes.size()) 801 return xAccessible; 802 803 SortedShapes::iterator aItr; 804 if (FindShape(aShapes[nSelectedChildIndex], aItr)) 805 xAccessible = Get(*aItr); 806 } 807 else 808 { 809 if (mbShapesNeedSorting) 810 { 811 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess()); 812 mbShapesNeedSorting = false; 813 } 814 for(const auto& rpShape : maZOrderedShapes) 815 { 816 if (!rpShape || rpShape->bSelected) 817 { 818 if (nSelectedChildIndex == 0) 819 { 820 if (rpShape) 821 xAccessible = rpShape->pAccShape.get(); 822 break; 823 } 824 else 825 --nSelectedChildIndex; 826 } 827 } 828 } 829 830 return xAccessible; 831 } 832 833 void ScChildrenShapes::Deselect(sal_Int32 nChildIndex) 834 { 835 uno::Reference<drawing::XShape> xShape; 836 if (IsSelected(nChildIndex, xShape)) // returns false if it is the sheet 837 { 838 if (xShape.is()) 839 { 840 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes()); 841 if (xShapes.is()) 842 xShapes->remove(xShape); 843 844 try 845 { 846 xSelectionSupplier->select(uno::makeAny(xShapes)); 847 } 848 catch (lang::IllegalArgumentException&) 849 { 850 OSL_FAIL("something not selectable"); 851 } 852 853 maZOrderedShapes[nChildIndex]->bSelected = false; 854 if (maZOrderedShapes[nChildIndex]->pAccShape.is()) 855 maZOrderedShapes[nChildIndex]->pAccShape->ResetState(AccessibleStateType::SELECTED); 856 } 857 } 858 } 859 860 SdrPage* ScChildrenShapes::GetDrawPage() const 861 { 862 SCTAB nTab(mpAccessibleDocument->getVisibleTable()); 863 SdrPage* pDrawPage = nullptr; 864 if (mpViewShell) 865 { 866 ScViewData& rViewData = mpViewShell->GetViewData(); 867 ScDocument* pDoc = rViewData.GetDocument(); 868 if (pDoc && pDoc->GetDrawLayer()) 869 { 870 ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer(); 871 if (pDrawLayer->HasObjects() && (pDrawLayer->GetPageCount() > nTab)) 872 pDrawPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(static_cast<sal_Int16>(nTab))); 873 } 874 } 875 return pDrawPage; 876 } 877 878 utl::AccessibleRelationSetHelper* ScChildrenShapes::GetRelationSet(const ScAddress* pAddress) const 879 { 880 utl::AccessibleRelationSetHelper* pRelationSet = nullptr; 881 for (const ScAccessibleShapeData* pAccShapeData : maZOrderedShapes) 882 { 883 if (pAccShapeData && 884 ((!pAccShapeData->xRelationCell && !pAddress) || 885 (pAccShapeData->xRelationCell && pAddress && (*(pAccShapeData->xRelationCell) == *pAddress)))) 886 { 887 if (!pRelationSet) 888 pRelationSet = new utl::AccessibleRelationSetHelper(); 889 890 AccessibleRelation aRelation; 891 aRelation.TargetSet.realloc(1); 892 aRelation.TargetSet[0] = Get(pAccShapeData); 893 aRelation.RelationType = AccessibleRelationType::CONTROLLER_FOR; 894 895 pRelationSet->AddRelation(aRelation); 896 } 897 } 898 return pRelationSet; 899 } 900 901 bool ScChildrenShapes::FindSelectedShapesChanges(const uno::Reference<drawing::XShapes>& xShapes) const 902 { 903 bool bResult(false); 904 SortedShapes aShapesList; 905 if (xShapes.is()) 906 { 907 mnShapesSelected = xShapes->getCount(); 908 for (sal_uInt32 i = 0; i < mnShapesSelected; ++i) 909 { 910 uno::Reference< drawing::XShape > xShape; 911 xShapes->getByIndex(i) >>= xShape; 912 if (xShape.is()) 913 { 914 ScAccessibleShapeData* pShapeData = new ScAccessibleShapeData(); 915 pShapeData->xShape = xShape; 916 aShapesList.push_back(pShapeData); 917 } 918 } 919 } 920 else 921 mnShapesSelected = 0; 922 SdrObject *pFocusedObj = nullptr; 923 if( mnShapesSelected == 1 && aShapesList.size() == 1) 924 { 925 pFocusedObj = GetSdrObjectFromXShape(aShapesList[0]->xShape); 926 } 927 std::sort(aShapesList.begin(), aShapesList.end(), ScShapeDataLess()); 928 SortedShapes vecSelectedShapeAdd; 929 SortedShapes vecSelectedShapeRemove; 930 bool bHasSelect=false; 931 SortedShapes::iterator aXShapesItr(aShapesList.begin()); 932 SortedShapes::const_iterator aXShapesEndItr(aShapesList.end()); 933 SortedShapes::iterator aDataItr(maZOrderedShapes.begin()); 934 SortedShapes::const_iterator aDataEndItr(maZOrderedShapes.end()); 935 SortedShapes::const_iterator aFocusedItr = aDataEndItr; 936 while(aDataItr != aDataEndItr) 937 { 938 if (*aDataItr) // is it really a shape or only the sheet 939 { 940 sal_Int8 nComp(0); 941 if (aXShapesItr == aXShapesEndItr) 942 nComp = -1; // simulate that the Shape is lower, so the selection state will be removed 943 else 944 nComp = Compare(*aDataItr, *aXShapesItr); 945 if (nComp == 0) 946 { 947 if (!(*aDataItr)->bSelected) 948 { 949 (*aDataItr)->bSelected = true; 950 if ((*aDataItr)->pAccShape.is()) 951 { 952 (*aDataItr)->pAccShape->SetState(AccessibleStateType::SELECTED); 953 (*aDataItr)->pAccShape->SetState(AccessibleStateType::FOCUSED); 954 bResult = true; 955 vecSelectedShapeAdd.push_back(*aDataItr); 956 } 957 aFocusedItr = aDataItr; 958 } 959 else 960 { 961 bHasSelect = true; 962 } 963 ++aDataItr; 964 ++aXShapesItr; 965 } 966 else if (nComp < 0) 967 { 968 if ((*aDataItr)->bSelected) 969 { 970 (*aDataItr)->bSelected = false; 971 if ((*aDataItr)->pAccShape.is()) 972 { 973 (*aDataItr)->pAccShape->ResetState(AccessibleStateType::SELECTED); 974 (*aDataItr)->pAccShape->ResetState(AccessibleStateType::FOCUSED); 975 bResult = true; 976 vecSelectedShapeRemove.push_back(*aDataItr); 977 } 978 } 979 ++aDataItr; 980 } 981 else 982 { 983 OSL_FAIL("here is a selected shape which is not in the childlist"); 984 ++aXShapesItr; 985 --mnShapesSelected; 986 } 987 } 988 else 989 ++aDataItr; 990 } 991 bool bWinFocus=false; 992 if (mpViewShell) 993 { 994 ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos)); 995 if (pWin) 996 { 997 bWinFocus = pWin->HasFocus(); 998 } 999 } 1000 const SdrMarkList* pMarkList = nullptr; 1001 SdrObject* pMarkedObj = nullptr; 1002 SdrObject* pUpObj = nullptr; 1003 bool bIsFocuseMarked = true; 1004 if( mpViewShell && mnShapesSelected == 1 && bWinFocus) 1005 { 1006 ScDrawView* pScDrawView = mpViewShell->GetViewData().GetScDrawView(); 1007 if( pScDrawView ) 1008 { 1009 if( pScDrawView->GetMarkedObjectList().GetMarkCount() == 1 ) 1010 { 1011 pMarkList = &(pScDrawView->GetMarkedObjectList()); 1012 pMarkedObj = pMarkList->GetMark(0)->GetMarkedSdrObj(); 1013 uno::Reference< drawing::XShape > xMarkedXShape (pMarkedObj->getUnoShape(), uno::UNO_QUERY); 1014 if( aFocusedItr != aDataEndItr && 1015 (*aFocusedItr)->xShape.is() && 1016 xMarkedXShape.is() && 1017 (*aFocusedItr)->xShape != xMarkedXShape ) 1018 bIsFocuseMarked = false; 1019 } 1020 } 1021 } 1022 //if ((aFocusedItr != aDataEndItr) && (*aFocusedItr)->pAccShape.is() && (mnShapesSelected == 1)) 1023 if ( bIsFocuseMarked && (aFocusedItr != aDataEndItr) && (*aFocusedItr)->pAccShape.is() && (mnShapesSelected == 1) && bWinFocus) 1024 { 1025 (*aFocusedItr)->pAccShape->SetState(AccessibleStateType::FOCUSED); 1026 } 1027 else if( pFocusedObj && bWinFocus && pMarkList && pMarkList->GetMarkCount() == 1 && mnShapesSelected == 1 ) 1028 { 1029 if( pMarkedObj ) 1030 { 1031 uno::Reference< drawing::XShape > xMarkedXShape (pMarkedObj->getUnoShape(), uno::UNO_QUERY); 1032 pUpObj = pMarkedObj->getParentSdrObjectFromSdrObject(); 1033 1034 if( pMarkedObj == pFocusedObj && pUpObj ) 1035 { 1036 uno::Reference< drawing::XShape > xUpGroupXShape (pUpObj->getUnoShape(), uno::UNO_QUERY); 1037 uno::Reference < XAccessible > xAccGroupShape = 1038 const_cast<ScChildrenShapes*>(this)->GetAccessibleCaption( xUpGroupXShape ); 1039 if( xAccGroupShape.is() ) 1040 { 1041 ::accessibility::AccessibleShape* pAccGroupShape = 1042 static_cast< ::accessibility::AccessibleShape* >(xAccGroupShape.get()); 1043 if( pAccGroupShape ) 1044 { 1045 sal_Int32 nCount = pAccGroupShape->getAccessibleChildCount(); 1046 for( sal_Int32 i = 0; i < nCount; i++ ) 1047 { 1048 uno::Reference<XAccessible> xAccShape = pAccGroupShape->getAccessibleChild(i); 1049 if (xAccShape.is()) 1050 { 1051 ::accessibility::AccessibleShape* pChildAccShape = static_cast< ::accessibility::AccessibleShape* >(xAccShape.get()); 1052 uno::Reference< drawing::XShape > xChildShape = pChildAccShape->GetXShape(); 1053 if (xChildShape == xMarkedXShape) 1054 { 1055 pChildAccShape->SetState(AccessibleStateType::FOCUSED); 1056 } 1057 else 1058 { 1059 pChildAccShape->ResetState(AccessibleStateType::FOCUSED); 1060 } 1061 } 1062 } 1063 } 1064 } 1065 } 1066 } 1067 } 1068 if (vecSelectedShapeAdd.size() >= 10 ) 1069 { 1070 AccessibleEventObject aEvent; 1071 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_WITHIN; 1072 aEvent.Source = uno::Reference< XAccessible >(mpAccessibleDocument); 1073 mpAccessibleDocument->CommitChange(aEvent); 1074 } 1075 else 1076 { 1077 for (const auto& rpShape : vecSelectedShapeAdd) 1078 { 1079 AccessibleEventObject aEvent; 1080 if (bHasSelect) 1081 { 1082 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_ADD; 1083 } 1084 else 1085 { 1086 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED; 1087 } 1088 aEvent.Source = uno::Reference< XAccessible >(mpAccessibleDocument); 1089 uno::Reference< XAccessible > xChild( rpShape->pAccShape.get()); 1090 aEvent.NewValue <<= xChild; 1091 mpAccessibleDocument->CommitChange(aEvent); 1092 } 1093 } 1094 for (const auto& rpShape : vecSelectedShapeRemove) 1095 { 1096 AccessibleEventObject aEvent; 1097 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_REMOVE; 1098 aEvent.Source = uno::Reference< XAccessible >(mpAccessibleDocument); 1099 uno::Reference< XAccessible > xChild( rpShape->pAccShape.get()); 1100 aEvent.NewValue <<= xChild; 1101 mpAccessibleDocument->CommitChange(aEvent); 1102 } 1103 for(ScAccessibleShapeData*& pShapeData : aShapesList) 1104 { 1105 delete pShapeData; 1106 pShapeData = nullptr; 1107 } 1108 return bResult; 1109 } 1110 1111 boost::optional<ScAddress> ScChildrenShapes::GetAnchor(const uno::Reference<drawing::XShape>& xShape) const 1112 { 1113 if (mpViewShell) 1114 { 1115 SvxShape* pShapeImp = comphelper::getUnoTunnelImplementation<SvxShape>(xShape); 1116 uno::Reference<beans::XPropertySet> xShapeProp(xShape, uno::UNO_QUERY); 1117 if (pShapeImp && xShapeProp.is()) 1118 { 1119 if (SdrObject *pSdrObj = pShapeImp->GetSdrObject()) 1120 { 1121 if (ScDrawObjData *pAnchor = ScDrawLayer::GetObjData(pSdrObj)) 1122 return boost::optional<ScAddress>(pAnchor->maStart); 1123 } 1124 } 1125 } 1126 1127 return boost::optional<ScAddress>(); 1128 } 1129 1130 uno::Reference<XAccessibleRelationSet> ScChildrenShapes::GetRelationSet(const ScAccessibleShapeData* pData) const 1131 { 1132 utl::AccessibleRelationSetHelper* pRelationSet = new utl::AccessibleRelationSetHelper(); 1133 1134 if (pData && mpAccessibleDocument) 1135 { 1136 uno::Reference<XAccessible> xAccessible = mpAccessibleDocument->GetAccessibleSpreadsheet(); // should be the current table 1137 if (pData->xRelationCell && xAccessible.is()) 1138 { 1139 uno::Reference<XAccessibleTable> xAccTable (xAccessible->getAccessibleContext(), uno::UNO_QUERY); 1140 if (xAccTable.is()) 1141 xAccessible = xAccTable->getAccessibleCellAt(pData->xRelationCell->Row(), pData->xRelationCell->Col()); 1142 } 1143 AccessibleRelation aRelation; 1144 aRelation.TargetSet.realloc(1); 1145 aRelation.TargetSet[0] = xAccessible; 1146 aRelation.RelationType = AccessibleRelationType::CONTROLLED_BY; 1147 pRelationSet->AddRelation(aRelation); 1148 } 1149 1150 return pRelationSet; 1151 } 1152 1153 void ScChildrenShapes::SetAnchor(const uno::Reference<drawing::XShape>& xShape, ScAccessibleShapeData* pData) const 1154 { 1155 if (pData) 1156 { 1157 boost::optional<ScAddress> xAddress = GetAnchor(xShape); 1158 if ((xAddress && pData->xRelationCell && (*xAddress != *(pData->xRelationCell))) || 1159 (!xAddress && pData->xRelationCell) || (xAddress && !pData->xRelationCell)) 1160 { 1161 pData->xRelationCell = xAddress; 1162 if (pData->pAccShape.is()) 1163 pData->pAccShape->SetRelationSet(GetRelationSet(pData)); 1164 } 1165 } 1166 } 1167 1168 void ScChildrenShapes::AddShape(const uno::Reference<drawing::XShape>& xShape, bool bCommitChange) const 1169 { 1170 if (mbShapesNeedSorting) 1171 { 1172 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess()); 1173 mbShapesNeedSorting = false; 1174 } 1175 SortedShapes::iterator aFindItr; 1176 if (!FindShape(xShape, aFindItr)) 1177 { 1178 ScAccessibleShapeData* pShape = new ScAccessibleShapeData(); 1179 pShape->xShape = xShape; 1180 SortedShapes::iterator aNewItr = maZOrderedShapes.insert(aFindItr, pShape); 1181 maShapesMap[xShape] = pShape; 1182 SetAnchor(xShape, pShape); 1183 1184 uno::Reference< beans::XPropertySet > xShapeProp(xShape, uno::UNO_QUERY); 1185 if (xShapeProp.is()) 1186 { 1187 uno::Any aPropAny = xShapeProp->getPropertyValue("LayerID"); 1188 sal_Int16 nLayerID = 0; 1189 if( aPropAny >>= nLayerID ) 1190 { 1191 if( (SdrLayerID(nLayerID) == SC_LAYER_INTERN) || (SdrLayerID(nLayerID) == SC_LAYER_HIDDEN) ) 1192 pShape->bSelectable = false; 1193 else 1194 pShape->bSelectable = true; 1195 } 1196 } 1197 1198 if (!xSelectionSupplier.is()) 1199 throw uno::RuntimeException(); 1200 1201 uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes()); 1202 uno::Reference<container::XEnumerationAccess> xEnumAcc(xShapes, uno::UNO_QUERY); 1203 if (xEnumAcc.is()) 1204 { 1205 uno::Reference<container::XEnumeration> xEnum = xEnumAcc->createEnumeration(); 1206 if (xEnum.is()) 1207 { 1208 uno::Reference<drawing::XShape> xSelectedShape; 1209 bool bFound(false); 1210 while (!bFound && xEnum->hasMoreElements()) 1211 { 1212 xEnum->nextElement() >>= xSelectedShape; 1213 if (xShape.is() && (xShape.get() == xSelectedShape.get())) 1214 { 1215 pShape->bSelected = true; 1216 bFound = true; 1217 } 1218 } 1219 } 1220 } 1221 if (mpAccessibleDocument && bCommitChange) 1222 { 1223 AccessibleEventObject aEvent; 1224 aEvent.EventId = AccessibleEventId::CHILD; 1225 aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument); 1226 aEvent.NewValue <<= Get(*aNewItr); 1227 1228 mpAccessibleDocument->CommitChange(aEvent); // new child - event 1229 } 1230 } 1231 else 1232 { 1233 OSL_FAIL("shape is always in the list"); 1234 } 1235 } 1236 1237 void ScChildrenShapes::RemoveShape(const uno::Reference<drawing::XShape>& xShape) const 1238 { 1239 if (mbShapesNeedSorting) 1240 { 1241 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess()); 1242 mbShapesNeedSorting = false; 1243 } 1244 SortedShapes::iterator aItr; 1245 if (FindShape(xShape, aItr)) 1246 { 1247 if (mpAccessibleDocument) 1248 { 1249 uno::Reference<XAccessible> xOldAccessible (Get(*aItr)); 1250 1251 delete *aItr; 1252 maShapesMap.erase((*aItr)->xShape); 1253 maZOrderedShapes.erase(aItr); 1254 1255 AccessibleEventObject aEvent; 1256 aEvent.EventId = AccessibleEventId::CHILD; 1257 aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument); 1258 aEvent.OldValue <<= xOldAccessible; 1259 1260 mpAccessibleDocument->CommitChange(aEvent); // child is gone - event 1261 } 1262 else 1263 { 1264 delete *aItr; 1265 maShapesMap.erase((*aItr)->xShape); 1266 maZOrderedShapes.erase(aItr); 1267 } 1268 } 1269 else 1270 { 1271 OSL_FAIL("shape was not in internal list"); 1272 } 1273 } 1274 1275 bool ScChildrenShapes::FindShape(const uno::Reference<drawing::XShape>& xShape, ScChildrenShapes::SortedShapes::iterator& rItr) const 1276 { 1277 if (mbShapesNeedSorting) 1278 { 1279 std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess()); 1280 mbShapesNeedSorting = false; 1281 } 1282 bool bResult(false); 1283 ScAccessibleShapeData aShape; 1284 aShape.xShape = xShape; 1285 rItr = std::lower_bound(maZOrderedShapes.begin(), maZOrderedShapes.end(), &aShape, ScShapeDataLess()); 1286 if ((rItr != maZOrderedShapes.end()) && (*rItr != nullptr) && ((*rItr)->xShape.get() == xShape.get())) 1287 bResult = true; // if the shape is found 1288 1289 #if OSL_DEBUG_LEVEL > 0 // test whether it finds truly the correct shape (perhaps it is not really sorted) 1290 SortedShapes::iterator aDebugItr = std::find_if(maZOrderedShapes.begin(), maZOrderedShapes.end(), 1291 [&xShape](const ScAccessibleShapeData* pShape) { return pShape && (pShape->xShape.get() == xShape.get()); }); 1292 bool bResult2 = (aDebugItr != maZOrderedShapes.end()); 1293 OSL_ENSURE((bResult == bResult2) && ((bResult && (rItr == aDebugItr)) || !bResult), "wrong Shape found"); 1294 #endif 1295 return bResult; 1296 } 1297 1298 sal_Int8 ScChildrenShapes::Compare(const ScAccessibleShapeData* pData1, 1299 const ScAccessibleShapeData* pData2) 1300 { 1301 ScShapeDataLess aLess; 1302 1303 bool bResult1(aLess(pData1, pData2)); 1304 bool bResult2(aLess(pData2, pData1)); 1305 1306 sal_Int8 nResult(0); 1307 if (!bResult1 && bResult2) 1308 nResult = 1; 1309 else if (bResult1 && !bResult2) 1310 nResult = -1; 1311 1312 return nResult; 1313 } 1314 1315 void ScChildrenShapes::VisAreaChanged() const 1316 { 1317 for (const ScAccessibleShapeData* pAccShapeData: maZOrderedShapes) 1318 if (pAccShapeData && pAccShapeData->pAccShape.is()) 1319 pAccShapeData->pAccShape->ViewForwarderChanged(); 1320 } 1321 1322 ScAccessibleDocument::ScAccessibleDocument( 1323 const uno::Reference<XAccessible>& rxParent, 1324 ScTabViewShell* pViewShell, 1325 ScSplitPos eSplitPos) 1326 : ScAccessibleDocumentBase(rxParent), 1327 mpViewShell(pViewShell), 1328 meSplitPos(eSplitPos), 1329 mpTempAccEdit(nullptr), 1330 mbCompleteSheetSelected(false) 1331 { 1332 maVisArea = GetVisibleArea_Impl(); 1333 } 1334 1335 void ScAccessibleDocument::PreInit() 1336 { 1337 if (mpViewShell) 1338 { 1339 mpViewShell->AddAccessibilityObject(*this); 1340 vcl::Window *pWin = mpViewShell->GetWindowByPos(meSplitPos); 1341 if( pWin ) 1342 { 1343 pWin->AddChildEventListener( LINK( this, ScAccessibleDocument, WindowChildEventListener )); 1344 sal_uInt16 nCount = pWin->GetChildCount(); 1345 for( sal_uInt16 i=0; i < nCount; ++i ) 1346 { 1347 vcl::Window *pChildWin = pWin->GetChild( i ); 1348 if( pChildWin && 1349 AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() ) 1350 AddChild( pChildWin->GetAccessible(), false ); 1351 } 1352 } 1353 ScViewData& rViewData = mpViewShell->GetViewData(); 1354 if (rViewData.HasEditView(meSplitPos)) 1355 { 1356 uno::Reference<XAccessible> xAcc = new ScAccessibleEditObject(this, rViewData.GetEditView(meSplitPos), 1357 mpViewShell->GetWindowByPos(meSplitPos), GetCurrentCellName(), GetCurrentCellDescription(), 1358 ScAccessibleEditObject::CellInEditMode); 1359 AddChild(xAcc, false); 1360 } 1361 } 1362 } 1363 1364 void ScAccessibleDocument::Init() 1365 { 1366 if(!mpChildrenShapes) 1367 mpChildrenShapes.reset( new ScChildrenShapes(this, mpViewShell, meSplitPos) ); 1368 } 1369 1370 ScAccessibleDocument::~ScAccessibleDocument() 1371 { 1372 if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose) 1373 { 1374 // increment refcount to prevent double call off dtor 1375 osl_atomic_increment( &m_refCount ); 1376 dispose(); 1377 } 1378 } 1379 1380 void SAL_CALL ScAccessibleDocument::disposing() 1381 { 1382 SolarMutexGuard aGuard; 1383 FreeAccessibleSpreadsheet(); 1384 if (mpViewShell) 1385 { 1386 vcl::Window *pWin = mpViewShell->GetWindowByPos(meSplitPos); 1387 if( pWin ) 1388 pWin->RemoveChildEventListener( LINK( this, ScAccessibleDocument, WindowChildEventListener )); 1389 1390 mpViewShell->RemoveAccessibilityObject(*this); 1391 mpViewShell = nullptr; 1392 } 1393 mpChildrenShapes.reset(); 1394 1395 ScAccessibleDocumentBase::disposing(); 1396 } 1397 1398 void SAL_CALL ScAccessibleDocument::disposing( const lang::EventObject& /* Source */ ) 1399 { 1400 disposing(); 1401 } 1402 1403 //===== SfxListener ===================================================== 1404 1405 IMPL_LINK( ScAccessibleDocument, WindowChildEventListener, VclWindowEvent&, rEvent, void ) 1406 { 1407 OSL_ENSURE( rEvent.GetWindow(), "Window???" ); 1408 switch ( rEvent.GetId() ) 1409 { 1410 case VclEventId::WindowShow: // send create on show for direct accessible children 1411 { 1412 vcl::Window* pChildWin = static_cast < vcl::Window * >( rEvent.GetData() ); 1413 if( pChildWin && AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() ) 1414 { 1415 AddChild( pChildWin->GetAccessible(), true ); 1416 } 1417 } 1418 break; 1419 case VclEventId::WindowHide: // send destroy on hide for direct accessible children 1420 { 1421 vcl::Window* pChildWin = static_cast < vcl::Window * >( rEvent.GetData() ); 1422 if( pChildWin && AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() ) 1423 { 1424 RemoveChild( pChildWin->GetAccessible(), true ); 1425 } 1426 } 1427 break; 1428 default: break; 1429 } 1430 } 1431 1432 void ScAccessibleDocument::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) 1433 { 1434 if (dynamic_cast<const ScAccGridWinFocusLostHint*>(&rHint) ) 1435 { 1436 const ScAccGridWinFocusLostHint* pFocusLostHint = static_cast<const ScAccGridWinFocusLostHint *>(&rHint); 1437 if (pFocusLostHint->GetOldGridWin() == meSplitPos) 1438 { 1439 if (mxTempAcc.is() && mpTempAccEdit) 1440 mpTempAccEdit->LostFocus(); 1441 else if (mpAccessibleSpreadsheet.is()) 1442 mpAccessibleSpreadsheet->LostFocus(); 1443 else 1444 CommitFocusLost(); 1445 } 1446 } 1447 else if (dynamic_cast<const ScAccGridWinFocusGotHint*>(&rHint) ) 1448 { 1449 const ScAccGridWinFocusGotHint* pFocusGotHint = static_cast<const ScAccGridWinFocusGotHint*>(&rHint); 1450 if (pFocusGotHint->GetNewGridWin() == meSplitPos) 1451 { 1452 uno::Reference<XAccessible> xAccessible; 1453 if (mpChildrenShapes) 1454 { 1455 bool bTabMarked(IsTableSelected()); 1456 xAccessible = mpChildrenShapes->GetSelected(0, bTabMarked); 1457 } 1458 if( xAccessible.is() ) 1459 { 1460 uno::Any aNewValue; 1461 aNewValue<<=AccessibleStateType::FOCUSED; 1462 static_cast< ::accessibility::AccessibleShape* >(xAccessible.get())-> 1463 CommitChange(AccessibleEventId::STATE_CHANGED, 1464 aNewValue, 1465 uno::Any() ); 1466 } 1467 else 1468 { 1469 if (mxTempAcc.is() && mpTempAccEdit) 1470 mpTempAccEdit->GotFocus(); 1471 else if (mpAccessibleSpreadsheet.is()) 1472 mpAccessibleSpreadsheet->GotFocus(); 1473 else 1474 CommitFocusGained(); 1475 } 1476 } 1477 } 1478 else 1479 { 1480 // only notify if child exist, otherwise it is not necessary 1481 if ((rHint.GetId() == SfxHintId::ScAccTableChanged) && 1482 mpAccessibleSpreadsheet.is()) 1483 { 1484 FreeAccessibleSpreadsheet(); 1485 1486 // Shapes / form controls after reload not accessible, rebuild the 1487 // mpChildrenShapes variable. 1488 mpChildrenShapes.reset( new ScChildrenShapes( this, mpViewShell, meSplitPos ) ); 1489 1490 AccessibleEventObject aEvent; 1491 aEvent.EventId = AccessibleEventId::INVALIDATE_ALL_CHILDREN; 1492 aEvent.Source = uno::Reference< XAccessibleContext >(this); 1493 CommitChange(aEvent); // all children changed 1494 1495 if (mpAccessibleSpreadsheet.is()) 1496 mpAccessibleSpreadsheet->FireFirstCellFocus(); 1497 } 1498 else if (rHint.GetId() == SfxHintId::ScAccMakeDrawLayer) 1499 { 1500 if (mpChildrenShapes) 1501 mpChildrenShapes->SetDrawBroadcaster(); 1502 } 1503 else if (rHint.GetId() == SfxHintId::ScAccEnterEditMode) // this event comes only on creating edit field of a cell 1504 { 1505 if (mpViewShell->GetViewData().GetEditActivePart() == meSplitPos) 1506 { 1507 ScViewData& rViewData = mpViewShell->GetViewData(); 1508 const EditEngine* pEditEng = rViewData.GetEditView(meSplitPos)->GetEditEngine(); 1509 if (pEditEng && pEditEng->GetUpdateMode()) 1510 { 1511 mpTempAccEdit = new ScAccessibleEditObject(this, rViewData.GetEditView(meSplitPos), 1512 mpViewShell->GetWindowByPos(meSplitPos), GetCurrentCellName(), 1513 ScResId(STR_ACC_EDITLINE_DESCR), ScAccessibleEditObject::CellInEditMode); 1514 uno::Reference<XAccessible> xAcc = mpTempAccEdit; 1515 1516 AddChild(xAcc, true); 1517 1518 if (mpAccessibleSpreadsheet.is()) 1519 mpAccessibleSpreadsheet->LostFocus(); 1520 else 1521 CommitFocusLost(); 1522 1523 mpTempAccEdit->GotFocus(); 1524 } 1525 } 1526 } 1527 else if (rHint.GetId() == SfxHintId::ScAccLeaveEditMode) 1528 { 1529 if (mxTempAcc.is()) 1530 { 1531 if (mpTempAccEdit) 1532 { 1533 mpTempAccEdit->LostFocus(); 1534 } 1535 RemoveChild(mxTempAcc, true); 1536 if (mpTempAccEdit) 1537 { 1538 // tdf#125982 a11y use-after-free of editengine by 1539 // ScAccessibleEditObjectTextData living past the 1540 // the editengine of the editview passed in above 1541 // in ScAccEnterEditMode 1542 mpTempAccEdit->dispose(); 1543 mpTempAccEdit = nullptr; 1544 } 1545 if (mpAccessibleSpreadsheet.is() && mpViewShell && mpViewShell->IsActive()) 1546 mpAccessibleSpreadsheet->GotFocus(); 1547 else if( mpViewShell && mpViewShell->IsActive()) 1548 CommitFocusGained(); 1549 } 1550 } 1551 else if ((rHint.GetId() == SfxHintId::ScAccVisAreaChanged) || (rHint.GetId() == SfxHintId::ScAccWindowResized)) 1552 { 1553 tools::Rectangle aOldVisArea(maVisArea); 1554 maVisArea = GetVisibleArea_Impl(); 1555 1556 if (maVisArea != aOldVisArea) 1557 { 1558 if (maVisArea.GetSize() != aOldVisArea.GetSize()) 1559 { 1560 AccessibleEventObject aEvent; 1561 aEvent.EventId = AccessibleEventId::BOUNDRECT_CHANGED; 1562 aEvent.Source = uno::Reference< XAccessibleContext >(this); 1563 1564 CommitChange(aEvent); 1565 1566 if (mpAccessibleSpreadsheet.is()) 1567 mpAccessibleSpreadsheet->BoundingBoxChanged(); 1568 if (mpAccessibleSpreadsheet.is() && mpViewShell && mpViewShell->IsActive()) 1569 mpAccessibleSpreadsheet->FireFirstCellFocus(); 1570 } 1571 else if (mpAccessibleSpreadsheet.is()) 1572 { 1573 mpAccessibleSpreadsheet->VisAreaChanged(); 1574 } 1575 if (mpChildrenShapes) 1576 mpChildrenShapes->VisAreaChanged(); 1577 } 1578 } 1579 } 1580 1581 ScAccessibleDocumentBase::Notify(rBC, rHint); 1582 } 1583 1584 void SAL_CALL ScAccessibleDocument::selectionChanged( const lang::EventObject& /* aEvent */ ) 1585 { 1586 bool bSelectionChanged(false); 1587 if (mpAccessibleSpreadsheet.is()) 1588 { 1589 bool bOldSelected(mbCompleteSheetSelected); 1590 mbCompleteSheetSelected = IsTableSelected(); 1591 if (bOldSelected != mbCompleteSheetSelected) 1592 { 1593 mpAccessibleSpreadsheet->CompleteSelectionChanged(mbCompleteSheetSelected); 1594 bSelectionChanged = true; 1595 } 1596 } 1597 1598 if (mpChildrenShapes && mpChildrenShapes->SelectionChanged()) 1599 bSelectionChanged = true; 1600 1601 if (bSelectionChanged) 1602 { 1603 AccessibleEventObject aEvent; 1604 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED; 1605 aEvent.Source = uno::Reference< XAccessibleContext >(this); 1606 1607 CommitChange(aEvent); 1608 } 1609 } 1610 1611 //===== XInterface ===================================================== 1612 1613 uno::Any SAL_CALL ScAccessibleDocument::queryInterface( uno::Type const & rType ) 1614 { 1615 uno::Any aAnyTmp; 1616 if(rType == cppu::UnoType<XAccessibleGetAccFlowTo>::get()) 1617 { 1618 css::uno::Reference<XAccessibleGetAccFlowTo> AccFromXShape = this; 1619 aAnyTmp <<= AccFromXShape; 1620 return aAnyTmp; 1621 } 1622 uno::Any aAny (ScAccessibleDocumentImpl::queryInterface(rType)); 1623 return aAny.hasValue() ? aAny : ScAccessibleContextBase::queryInterface(rType); 1624 } 1625 1626 void SAL_CALL ScAccessibleDocument::acquire() 1627 throw () 1628 { 1629 ScAccessibleContextBase::acquire(); 1630 } 1631 1632 void SAL_CALL ScAccessibleDocument::release() 1633 throw () 1634 { 1635 ScAccessibleContextBase::release(); 1636 } 1637 1638 //===== XAccessibleComponent ============================================ 1639 1640 uno::Reference< XAccessible > SAL_CALL ScAccessibleDocument::getAccessibleAtPoint( 1641 const awt::Point& rPoint ) 1642 { 1643 uno::Reference<XAccessible> xAccessible; 1644 if (containsPoint(rPoint)) 1645 { 1646 SolarMutexGuard aGuard; 1647 IsObjectValid(); 1648 if (mpChildrenShapes) 1649 xAccessible = mpChildrenShapes->GetAt(rPoint); 1650 if(!xAccessible.is()) 1651 { 1652 if (mxTempAcc.is()) 1653 { 1654 uno::Reference< XAccessibleContext > xCont(mxTempAcc->getAccessibleContext()); 1655 uno::Reference< XAccessibleComponent > xComp(xCont, uno::UNO_QUERY); 1656 if (xComp.is()) 1657 { 1658 tools::Rectangle aBound(VCLRectangle(xComp->getBounds())); 1659 if (aBound.IsInside(VCLPoint(rPoint))) 1660 xAccessible = mxTempAcc; 1661 } 1662 } 1663 if (!xAccessible.is()) 1664 xAccessible = GetAccessibleSpreadsheet(); 1665 } 1666 } 1667 return xAccessible; 1668 } 1669 1670 void SAL_CALL ScAccessibleDocument::grabFocus( ) 1671 { 1672 SolarMutexGuard aGuard; 1673 IsObjectValid(); 1674 if (getAccessibleParent().is()) 1675 { 1676 uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY); 1677 if (xAccessibleComponent.is()) 1678 { 1679 xAccessibleComponent->grabFocus(); 1680 // grab only focus if it does not have the focus and it is not hidden 1681 if (mpViewShell && 1682 (mpViewShell->GetViewData().GetActivePart() != meSplitPos) && 1683 mpViewShell->GetWindowByPos(meSplitPos)->IsVisible()) 1684 { 1685 mpViewShell->ActivatePart(meSplitPos); 1686 } 1687 } 1688 } 1689 } 1690 1691 //===== XAccessibleContext ============================================== 1692 1693 /// Return the number of currently visible children. 1694 sal_Int32 SAL_CALL 1695 ScAccessibleDocument::getAccessibleChildCount() 1696 { 1697 SolarMutexGuard aGuard; 1698 IsObjectValid(); 1699 sal_Int32 nCount(1); 1700 if (mpChildrenShapes) 1701 nCount = mpChildrenShapes->GetCount(); // returns the count of the shapes inclusive the table 1702 1703 if (mxTempAcc.is()) 1704 ++nCount; 1705 1706 return nCount; 1707 } 1708 1709 /// Return the specified child or NULL if index is invalid. 1710 uno::Reference<XAccessible> SAL_CALL 1711 ScAccessibleDocument::getAccessibleChild(sal_Int32 nIndex) 1712 { 1713 SolarMutexGuard aGuard; 1714 IsObjectValid(); 1715 uno::Reference<XAccessible> xAccessible; 1716 if (nIndex >= 0) 1717 { 1718 sal_Int32 nCount(1); 1719 if (mpChildrenShapes) 1720 { 1721 xAccessible = mpChildrenShapes->Get(nIndex); // returns NULL if it is the table or out of range 1722 nCount = mpChildrenShapes->GetCount(); //there is always a table 1723 } 1724 if (!xAccessible.is()) 1725 { 1726 if (nIndex < nCount) 1727 xAccessible = GetAccessibleSpreadsheet(); 1728 else if (nIndex == nCount && mxTempAcc.is()) 1729 xAccessible = mxTempAcc; 1730 } 1731 } 1732 1733 if (!xAccessible.is()) 1734 throw lang::IndexOutOfBoundsException(); 1735 1736 return xAccessible; 1737 } 1738 1739 /// Return the set of current states. 1740 uno::Reference<XAccessibleStateSet> SAL_CALL 1741 ScAccessibleDocument::getAccessibleStateSet() 1742 { 1743 SolarMutexGuard aGuard; 1744 uno::Reference<XAccessibleStateSet> xParentStates; 1745 if (getAccessibleParent().is()) 1746 { 1747 uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext(); 1748 xParentStates = xParentContext->getAccessibleStateSet(); 1749 } 1750 utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper(); 1751 if (IsDefunc(xParentStates)) 1752 pStateSet->AddState(AccessibleStateType::DEFUNC); 1753 else 1754 { 1755 pStateSet->AddState(AccessibleStateType::EDITABLE); 1756 pStateSet->AddState(AccessibleStateType::ENABLED); 1757 pStateSet->AddState(AccessibleStateType::OPAQUE); 1758 if (isShowing()) 1759 pStateSet->AddState(AccessibleStateType::SHOWING); 1760 if (isVisible()) 1761 pStateSet->AddState(AccessibleStateType::VISIBLE); 1762 } 1763 return pStateSet; 1764 } 1765 1766 OUString SAL_CALL 1767 ScAccessibleDocument::getAccessibleName() 1768 { 1769 SolarMutexGuard g; 1770 1771 OUString aName = ScResId(STR_ACC_DOC_SPREADSHEET); 1772 ScDocument* pScDoc = GetDocument(); 1773 if (!pScDoc) 1774 return aName; 1775 1776 SfxObjectShell* pObjSh = pScDoc->GetDocumentShell(); 1777 if (!pObjSh) 1778 return aName; 1779 1780 OUString aFileName; 1781 SfxMedium* pMed = pObjSh->GetMedium(); 1782 if (pMed) 1783 aFileName = pMed->GetName(); 1784 1785 if (aFileName.isEmpty()) 1786 aFileName = pObjSh->GetTitle(SFX_TITLE_APINAME); 1787 1788 if (!aFileName.isEmpty()) 1789 { 1790 OUString aReadOnly; 1791 if (pObjSh->IsReadOnly()) 1792 aReadOnly = ScResId(STR_ACC_DOC_SPREADSHEET_READONLY); 1793 1794 aName = aFileName + aReadOnly + " - " + aName; 1795 } 1796 return aName; 1797 } 1798 1799 ///===== XAccessibleSelection =========================================== 1800 1801 void SAL_CALL 1802 ScAccessibleDocument::selectAccessibleChild( sal_Int32 nChildIndex ) 1803 { 1804 SolarMutexGuard aGuard; 1805 IsObjectValid(); 1806 1807 if (mpChildrenShapes && mpViewShell) 1808 { 1809 sal_Int32 nCount(mpChildrenShapes->GetCount()); // all shapes and the table 1810 if (mxTempAcc.is()) 1811 ++nCount; 1812 if (nChildIndex < 0 || nChildIndex >= nCount) 1813 throw lang::IndexOutOfBoundsException(); 1814 1815 uno::Reference < XAccessible > xAccessible = mpChildrenShapes->Get(nChildIndex); 1816 if (xAccessible.is()) 1817 { 1818 bool bWasTableSelected(IsTableSelected()); 1819 mpChildrenShapes->Select(nChildIndex); // throws no lang::IndexOutOfBoundsException if Index is too high 1820 if (bWasTableSelected) 1821 mpViewShell->SelectAll(); 1822 } 1823 else 1824 { 1825 mpViewShell->SelectAll(); 1826 } 1827 } 1828 } 1829 1830 sal_Bool SAL_CALL 1831 ScAccessibleDocument::isAccessibleChildSelected( sal_Int32 nChildIndex ) 1832 { 1833 SolarMutexGuard aGuard; 1834 IsObjectValid(); 1835 bool bResult(false); 1836 1837 if (mpChildrenShapes) 1838 { 1839 sal_Int32 nCount(mpChildrenShapes->GetCount()); // all shapes and the table 1840 if (mxTempAcc.is()) 1841 ++nCount; 1842 if (nChildIndex < 0 || nChildIndex >= nCount) 1843 throw lang::IndexOutOfBoundsException(); 1844 1845 uno::Reference < XAccessible > xAccessible = mpChildrenShapes->Get(nChildIndex); 1846 if (xAccessible.is()) 1847 { 1848 uno::Reference<drawing::XShape> xShape; 1849 bResult = mpChildrenShapes->IsSelected(nChildIndex, xShape); // throws no lang::IndexOutOfBoundsException if Index is too high 1850 } 1851 else 1852 { 1853 if (mxTempAcc.is() && nChildIndex == nCount) 1854 bResult = true; 1855 else 1856 bResult = IsTableSelected(); 1857 } 1858 } 1859 return bResult; 1860 } 1861 1862 void SAL_CALL 1863 ScAccessibleDocument::clearAccessibleSelection( ) 1864 { 1865 SolarMutexGuard aGuard; 1866 IsObjectValid(); 1867 1868 if (mpChildrenShapes) 1869 mpChildrenShapes->DeselectAll(); //deselects all (also the table) 1870 } 1871 1872 void SAL_CALL 1873 ScAccessibleDocument::selectAllAccessibleChildren( ) 1874 { 1875 SolarMutexGuard aGuard; 1876 IsObjectValid(); 1877 1878 if (mpChildrenShapes) 1879 mpChildrenShapes->SelectAll(); 1880 1881 // select table after shapes, because while selecting shapes the table will be deselected 1882 if (mpViewShell) 1883 { 1884 mpViewShell->SelectAll(); 1885 } 1886 } 1887 1888 sal_Int32 SAL_CALL 1889 ScAccessibleDocument::getSelectedAccessibleChildCount( ) 1890 { 1891 SolarMutexGuard aGuard; 1892 IsObjectValid(); 1893 sal_Int32 nCount(0); 1894 1895 if (mpChildrenShapes) 1896 nCount = mpChildrenShapes->GetSelectedCount(); 1897 1898 if (IsTableSelected()) 1899 ++nCount; 1900 1901 if (mxTempAcc.is()) 1902 ++nCount; 1903 1904 return nCount; 1905 } 1906 1907 uno::Reference<XAccessible > SAL_CALL 1908 ScAccessibleDocument::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) 1909 { 1910 SolarMutexGuard aGuard; 1911 IsObjectValid(); 1912 uno::Reference<XAccessible> xAccessible; 1913 if (mpChildrenShapes) 1914 { 1915 sal_Int32 nCount(getSelectedAccessibleChildCount()); //all shapes and the table 1916 if (nSelectedChildIndex < 0 || nSelectedChildIndex >= nCount) 1917 throw lang::IndexOutOfBoundsException(); 1918 1919 bool bTabMarked(IsTableSelected()); 1920 1921 if (mpChildrenShapes) 1922 xAccessible = mpChildrenShapes->GetSelected(nSelectedChildIndex, bTabMarked); // throws no lang::IndexOutOfBoundsException if Index is too high 1923 if (mxTempAcc.is() && nSelectedChildIndex == nCount - 1) 1924 xAccessible = mxTempAcc; 1925 else if (bTabMarked) 1926 xAccessible = GetAccessibleSpreadsheet(); 1927 } 1928 1929 OSL_ENSURE(xAccessible.is(), "here should always be an accessible object or an exception thrown"); 1930 1931 return xAccessible; 1932 } 1933 1934 void SAL_CALL 1935 ScAccessibleDocument::deselectAccessibleChild( sal_Int32 nChildIndex ) 1936 { 1937 SolarMutexGuard aGuard; 1938 IsObjectValid(); 1939 1940 if (mpChildrenShapes && mpViewShell) 1941 { 1942 sal_Int32 nCount(mpChildrenShapes->GetCount()); // all shapes and the table 1943 if (mxTempAcc.is()) 1944 ++nCount; 1945 if (nChildIndex < 0 || nChildIndex >= nCount) 1946 throw lang::IndexOutOfBoundsException(); 1947 1948 bool bTabMarked(IsTableSelected()); 1949 1950 uno::Reference < XAccessible > xAccessible = mpChildrenShapes->Get(nChildIndex); 1951 if (xAccessible.is()) 1952 { 1953 mpChildrenShapes->Deselect(nChildIndex); // throws no lang::IndexOutOfBoundsException if Index is too high 1954 if (bTabMarked) 1955 mpViewShell->SelectAll(); // select the table again 1956 } 1957 else if (bTabMarked) 1958 mpViewShell->Unmark(); 1959 } 1960 } 1961 1962 //===== XServiceInfo ==================================================== 1963 1964 OUString SAL_CALL 1965 ScAccessibleDocument::getImplementationName() 1966 { 1967 return "ScAccessibleDocument"; 1968 } 1969 1970 uno::Sequence< OUString> SAL_CALL 1971 ScAccessibleDocument::getSupportedServiceNames() 1972 { 1973 uno::Sequence< OUString > aSequence = ScAccessibleContextBase::getSupportedServiceNames(); 1974 sal_Int32 nOldSize(aSequence.getLength()); 1975 aSequence.realloc(nOldSize + 1); 1976 1977 aSequence[nOldSize] = "com.sun.star.AccessibleSpreadsheetDocumentView"; 1978 1979 return aSequence; 1980 } 1981 1982 //===== XTypeProvider ======================================================= 1983 1984 uno::Sequence< uno::Type > SAL_CALL ScAccessibleDocument::getTypes() 1985 { 1986 return comphelper::concatSequences(ScAccessibleDocumentImpl::getTypes(), ScAccessibleContextBase::getTypes()); 1987 } 1988 1989 uno::Sequence<sal_Int8> SAL_CALL 1990 ScAccessibleDocument::getImplementationId() 1991 { 1992 return css::uno::Sequence<sal_Int8>(); 1993 } 1994 1995 ///===== IAccessibleViewForwarder ======================================== 1996 1997 tools::Rectangle ScAccessibleDocument::GetVisibleArea_Impl() const 1998 { 1999 tools::Rectangle aVisRect(GetBoundingBox()); 2000 2001 if (mpViewShell) 2002 { 2003 Point aPoint(mpViewShell->GetViewData().GetPixPos(meSplitPos)); // returns a negative Point 2004 aPoint.setX(-aPoint.getX()); 2005 aPoint.setY(-aPoint.getY()); 2006 aVisRect.SetPos(aPoint); 2007 2008 ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos)); 2009 if (pWin) 2010 aVisRect = pWin->PixelToLogic(aVisRect, pWin->GetDrawMapMode()); 2011 } 2012 2013 return aVisRect; 2014 } 2015 2016 tools::Rectangle ScAccessibleDocument::GetVisibleArea() const 2017 { 2018 SolarMutexGuard aGuard; 2019 IsObjectValid(); 2020 return maVisArea; 2021 } 2022 2023 Point ScAccessibleDocument::LogicToPixel (const Point& rPoint) const 2024 { 2025 SolarMutexGuard aGuard; 2026 IsObjectValid(); 2027 Point aPoint; 2028 ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos)); 2029 if (pWin) 2030 { 2031 aPoint = pWin->LogicToPixel(rPoint, pWin->GetDrawMapMode()); 2032 aPoint += pWin->GetWindowExtentsRelative(nullptr).TopLeft(); 2033 } 2034 return aPoint; 2035 } 2036 2037 Size ScAccessibleDocument::LogicToPixel (const Size& rSize) const 2038 { 2039 SolarMutexGuard aGuard; 2040 IsObjectValid(); 2041 Size aSize; 2042 ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos)); 2043 if (pWin) 2044 aSize = pWin->LogicToPixel(rSize, pWin->GetDrawMapMode()); 2045 return aSize; 2046 } 2047 2048 //===== internal ======================================================== 2049 2050 utl::AccessibleRelationSetHelper* ScAccessibleDocument::GetRelationSet(const ScAddress* pAddress) const 2051 { 2052 utl::AccessibleRelationSetHelper* pRelationSet = nullptr; 2053 if (mpChildrenShapes) 2054 pRelationSet = mpChildrenShapes->GetRelationSet(pAddress); 2055 return pRelationSet; 2056 } 2057 2058 OUString 2059 ScAccessibleDocument::createAccessibleDescription() 2060 { 2061 OUString sDescription = STR_ACC_DOC_DESCR; 2062 return sDescription; 2063 } 2064 2065 OUString 2066 ScAccessibleDocument::createAccessibleName() 2067 { 2068 SolarMutexGuard aGuard; 2069 IsObjectValid(); 2070 OUString sName = ScResId(STR_ACC_DOC_NAME); 2071 sal_Int32 nNumber(sal_Int32(meSplitPos) + 1); 2072 sName += OUString::number(nNumber); 2073 return sName; 2074 } 2075 2076 tools::Rectangle ScAccessibleDocument::GetBoundingBoxOnScreen() const 2077 { 2078 tools::Rectangle aRect; 2079 if (mpViewShell) 2080 { 2081 vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos); 2082 if (pWindow) 2083 aRect = pWindow->GetWindowExtentsRelative(nullptr); 2084 } 2085 return aRect; 2086 } 2087 2088 tools::Rectangle ScAccessibleDocument::GetBoundingBox() const 2089 { 2090 tools::Rectangle aRect; 2091 if (mpViewShell) 2092 { 2093 vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos); 2094 if (pWindow) 2095 aRect = pWindow->GetWindowExtentsRelative(pWindow->GetAccessibleParentWindow()); 2096 } 2097 return aRect; 2098 } 2099 2100 SCTAB ScAccessibleDocument::getVisibleTable() const 2101 { 2102 SCTAB nVisibleTable(0); 2103 if (mpViewShell) 2104 nVisibleTable = mpViewShell->GetViewData().GetTabNo(); 2105 return nVisibleTable; 2106 } 2107 2108 uno::Reference < XAccessible > 2109 ScAccessibleDocument::GetAccessibleSpreadsheet() 2110 { 2111 if (!mpAccessibleSpreadsheet.is() && mpViewShell) 2112 { 2113 mpAccessibleSpreadsheet = new ScAccessibleSpreadsheet(this, mpViewShell, getVisibleTable(), meSplitPos); 2114 mpAccessibleSpreadsheet->Init(); 2115 mbCompleteSheetSelected = IsTableSelected(); 2116 } 2117 return mpAccessibleSpreadsheet.get(); 2118 } 2119 2120 void ScAccessibleDocument::FreeAccessibleSpreadsheet() 2121 { 2122 if (mpAccessibleSpreadsheet.is()) 2123 { 2124 mpAccessibleSpreadsheet->dispose(); 2125 mpAccessibleSpreadsheet.clear(); 2126 } 2127 } 2128 2129 bool ScAccessibleDocument::IsTableSelected() const 2130 { 2131 bool bResult (false); 2132 if(mpViewShell) 2133 { 2134 SCTAB nTab(getVisibleTable()); 2135 //#103800#; use a copy of MarkData 2136 ScMarkData aMarkData(mpViewShell->GetViewData().GetMarkData()); 2137 aMarkData.MarkToMulti(); 2138 if (aMarkData.IsAllMarked( ScRange( 0, 0, nTab, MAXCOL, MAXROW, nTab))) 2139 bResult = true; 2140 } 2141 return bResult; 2142 } 2143 2144 bool ScAccessibleDocument::IsDefunc( 2145 const uno::Reference<XAccessibleStateSet>& rxParentStates) 2146 { 2147 return ScAccessibleContextBase::IsDefunc() || (mpViewShell == nullptr) || !getAccessibleParent().is() || 2148 (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC)); 2149 } 2150 2151 void ScAccessibleDocument::AddChild(const uno::Reference<XAccessible>& xAcc, bool bFireEvent) 2152 { 2153 OSL_ENSURE(!mxTempAcc.is(), "this object should be removed before"); 2154 if (xAcc.is()) 2155 { 2156 mxTempAcc = xAcc; 2157 if( bFireEvent ) 2158 { 2159 AccessibleEventObject aEvent; 2160 aEvent.Source = uno::Reference<XAccessibleContext>(this); 2161 aEvent.EventId = AccessibleEventId::CHILD; 2162 aEvent.NewValue <<= mxTempAcc; 2163 CommitChange( aEvent ); 2164 } 2165 } 2166 } 2167 2168 void ScAccessibleDocument::RemoveChild(const uno::Reference<XAccessible>& xAcc, bool bFireEvent) 2169 { 2170 OSL_ENSURE(mxTempAcc.is(), "this object should be added before"); 2171 if (xAcc.is()) 2172 { 2173 OSL_ENSURE(xAcc.get() == mxTempAcc.get(), "only the same object should be removed"); 2174 if( bFireEvent ) 2175 { 2176 AccessibleEventObject aEvent; 2177 aEvent.Source = uno::Reference<XAccessibleContext>(this); 2178 aEvent.EventId = AccessibleEventId::CHILD; 2179 aEvent.OldValue <<= mxTempAcc; 2180 CommitChange( aEvent ); 2181 } 2182 mxTempAcc = nullptr; 2183 } 2184 } 2185 2186 OUString ScAccessibleDocument::GetCurrentCellName() const 2187 { 2188 OUString sName(ScResId(STR_ACC_CELL_NAME)); 2189 if (mpViewShell) 2190 { 2191 // Document not needed, because only the cell address, but not the tablename is needed 2192 OUString sAddress(mpViewShell->GetViewData().GetCurPos().Format(ScRefFlags::VALID)); 2193 sName = sName.replaceFirst("%1", sAddress); 2194 } 2195 return sName; 2196 } 2197 2198 OUString ScAccessibleDocument::GetCurrentCellDescription() 2199 { 2200 return OUString(); 2201 } 2202 2203 ScDocument *ScAccessibleDocument::GetDocument() const 2204 { 2205 return mpViewShell ? mpViewShell->GetViewData().GetDocument() : nullptr; 2206 } 2207 2208 ScAddress ScAccessibleDocument::GetCurCellAddress() const 2209 { 2210 return mpViewShell ? mpViewShell->GetViewData().GetCurPos() : ScAddress(); 2211 } 2212 2213 uno::Any SAL_CALL ScAccessibleDocument::getExtendedAttributes() 2214 { 2215 SolarMutexGuard g; 2216 2217 uno::Any anyAtrribute; 2218 2219 OUString sName; 2220 OUString sValue; 2221 sal_uInt16 sheetIndex; 2222 OUString sSheetName; 2223 sheetIndex = getVisibleTable(); 2224 if(GetDocument()==nullptr) 2225 return anyAtrribute; 2226 GetDocument()->GetName(sheetIndex,sSheetName); 2227 sName = "page-name:"; 2228 sValue = sName + sSheetName ; 2229 sName = ";page-number:"; 2230 sValue += sName; 2231 sValue += OUString::number(sheetIndex+1) ; 2232 sName = ";total-pages:"; 2233 sValue += sName; 2234 sValue += OUString::number(GetDocument()->GetTableCount()); 2235 sValue += ";"; 2236 anyAtrribute <<= sValue; 2237 return anyAtrribute; 2238 } 2239 2240 css::uno::Sequence< css::uno::Any > ScAccessibleDocument::GetScAccFlowToSequence() 2241 { 2242 if ( getAccessibleChildCount() ) 2243 { 2244 uno::Reference < XAccessible > xSCTableAcc = getAccessibleChild( 0 ); // table 2245 if ( xSCTableAcc.is() ) 2246 { 2247 uno::Reference < XAccessibleSelection > xAccSelection( xSCTableAcc, uno::UNO_QUERY ); 2248 sal_Int32 nSelCount = xAccSelection->getSelectedAccessibleChildCount(); 2249 if( nSelCount ) 2250 { 2251 uno::Reference < XAccessible > xSel = xAccSelection->getSelectedAccessibleChild( 0 ); // selected cell 2252 if ( xSel.is() ) 2253 { 2254 uno::Reference < XAccessibleContext > xSelContext( xSel->getAccessibleContext() ); 2255 if ( xSelContext.is() ) 2256 { 2257 if ( xSelContext->getAccessibleRole() == AccessibleRole::TABLE_CELL ) 2258 { 2259 sal_Int32 nParaCount = 0; 2260 uno::Sequence <uno::Any> aSequence(nSelCount); 2261 for ( sal_Int32 i = 0; i < nSelCount; i++ ) 2262 { 2263 xSel = xAccSelection->getSelectedAccessibleChild( i ) ; 2264 if ( xSel.is() ) 2265 { 2266 xSelContext = xSel->getAccessibleContext(); 2267 if ( xSelContext.is() ) 2268 { 2269 if ( xSelContext->getAccessibleRole() == AccessibleRole::TABLE_CELL ) 2270 { 2271 aSequence[nParaCount] <<= xSel; 2272 nParaCount++; 2273 } 2274 } 2275 } 2276 } 2277 return aSequence; 2278 } 2279 } 2280 } 2281 } 2282 } 2283 } 2284 uno::Sequence <uno::Any> aEmpty; 2285 return aEmpty; 2286 } 2287 2288 css::uno::Sequence< css::uno::Any > 2289 SAL_CALL ScAccessibleDocument::getAccFlowTo(const css::uno::Any& rAny, sal_Int32 nType) 2290 { 2291 SolarMutexGuard g; 2292 2293 const sal_Int32 SPELLCHECKFLOWTO = 1; 2294 const sal_Int32 FINDREPLACEFLOWTO = 2; 2295 if ( nType == SPELLCHECKFLOWTO ) 2296 { 2297 uno::Reference< css::drawing::XShape > xShape; 2298 rAny >>= xShape; 2299 if ( xShape.is() ) 2300 { 2301 uno::Reference < XAccessible > xAcc = mpChildrenShapes->GetAccessibleCaption(xShape); 2302 uno::Reference < XAccessibleSelection > xAccSelection( xAcc, uno::UNO_QUERY ); 2303 if ( xAccSelection.is() ) 2304 { 2305 if ( xAccSelection->getSelectedAccessibleChildCount() ) 2306 { 2307 uno::Reference < XAccessible > xSel = xAccSelection->getSelectedAccessibleChild( 0 ); 2308 if ( xSel.is() ) 2309 { 2310 uno::Reference < XAccessibleContext > xSelContext( xSel->getAccessibleContext() ); 2311 if ( xSelContext.is() ) 2312 { 2313 //if in sw we find the selected paragraph here 2314 if ( xSelContext->getAccessibleRole() == AccessibleRole::PARAGRAPH ) 2315 { 2316 uno::Sequence<uno::Any> aRet( 1 ); 2317 aRet[0] <<= xSel; 2318 return aRet; 2319 } 2320 } 2321 } 2322 } 2323 } 2324 } 2325 else 2326 { 2327 if ( getSelectedAccessibleChildCount() ) 2328 { 2329 uno::Reference < XAccessible > xSel = getSelectedAccessibleChild( 0 ); 2330 if ( xSel.is() ) 2331 { 2332 uno::Reference < XAccessibleContext > xSelContext( xSel->getAccessibleContext() ); 2333 if ( xSelContext.is() ) 2334 { 2335 uno::Reference < XAccessibleSelection > xAccChildSelection( xSel, uno::UNO_QUERY ); 2336 if ( xAccChildSelection.is() ) 2337 { 2338 if ( xAccChildSelection->getSelectedAccessibleChildCount() ) 2339 { 2340 uno::Reference < XAccessible > xChildSel = xAccChildSelection->getSelectedAccessibleChild( 0 ); 2341 if ( xChildSel.is() ) 2342 { 2343 uno::Reference < css::accessibility::XAccessibleContext > xChildSelContext( xChildSel->getAccessibleContext() ); 2344 if ( xChildSelContext.is() && 2345 xChildSelContext->getAccessibleRole() == css::accessibility::AccessibleRole::PARAGRAPH ) 2346 { 2347 uno::Sequence<uno::Any> aRet( 1 ); 2348 aRet[0] <<= xChildSel; 2349 return aRet; 2350 } 2351 } 2352 } 2353 } 2354 } 2355 } 2356 } 2357 } 2358 } 2359 else if ( nType == FINDREPLACEFLOWTO ) 2360 { 2361 bool bSuccess(false); 2362 rAny >>= bSuccess; 2363 if ( bSuccess ) 2364 { 2365 uno::Sequence< uno::Any> aSeq = GetScAccFlowToSequence(); 2366 if ( aSeq.hasElements() ) 2367 { 2368 return aSeq; 2369 } 2370 else if( mpAccessibleSpreadsheet.is() ) 2371 { 2372 uno::Reference < XAccessible > xFindCellAcc = mpAccessibleSpreadsheet->GetActiveCell(); 2373 // add xFindCellAcc to the return the Sequence 2374 uno::Sequence< uno::Any> aSeq2(1); 2375 aSeq2[0] <<= xFindCellAcc; 2376 return aSeq2; 2377 } 2378 } 2379 } 2380 uno::Sequence< uno::Any> aEmpty; 2381 return aEmpty; 2382 } 2383 2384 sal_Int32 SAL_CALL ScAccessibleDocument::getForeground( ) 2385 { 2386 return sal_Int32(COL_BLACK); 2387 } 2388 2389 sal_Int32 SAL_CALL ScAccessibleDocument::getBackground( ) 2390 { 2391 SolarMutexGuard aGuard; 2392 IsObjectValid(); 2393 return sal_Int32(SC_MOD()->GetColorConfig().GetColorValue( ::svtools::DOCCOLOR ).nColor); 2394 } 2395 2396 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 2397
