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 <svx/svdobj.hxx> 21 #include <config_features.h> 22 23 #include <sal/config.h> 24 #include <sal/log.hxx> 25 #include <rtl/ustrbuf.hxx> 26 27 #include <com/sun/star/lang/XComponent.hpp> 28 #include <com/sun/star/text/RelOrientation.hpp> 29 #include <com/sun/star/frame/XTerminateListener.hpp> 30 #include <com/sun/star/frame/Desktop.hpp> 31 32 #include <basegfx/matrix/b2dhommatrix.hxx> 33 #include <basegfx/matrix/b2dhommatrixtools.hxx> 34 #include <basegfx/polygon/b2dpolygon.hxx> 35 #include <basegfx/polygon/b2dpolygontools.hxx> 36 #include <basegfx/polygon/b2dpolypolygoncutter.hxx> 37 #include <basegfx/polygon/b2dpolypolygontools.hxx> 38 #include <basegfx/range/b2drange.hxx> 39 #include <drawinglayer/processor2d/contourextractor2d.hxx> 40 #include <drawinglayer/processor2d/linegeometryextractor2d.hxx> 41 #include <comphelper/processfactory.hxx> 42 #include <editeng/editeng.hxx> 43 #include <editeng/outlobj.hxx> 44 #include <o3tl/deleter.hxx> 45 #include <math.h> 46 #include <svl/grabbagitem.hxx> 47 #include <tools/bigint.hxx> 48 #include <tools/diagnose_ex.h> 49 #include <tools/helpers.hxx> 50 #include <unotools/configmgr.hxx> 51 #include <vcl/canvastools.hxx> 52 #include <vcl/ptrstyle.hxx> 53 #include <vector> 54 55 #include <svx/shapepropertynotifier.hxx> 56 #include <svx/svdotable.hxx> 57 58 #include <svx/sdr/contact/displayinfo.hxx> 59 #include <sdr/contact/objectcontactofobjlistpainter.hxx> 60 #include <svx/sdr/contact/viewcontactofsdrobj.hxx> 61 #include <sdr/properties/emptyproperties.hxx> 62 #include <svx/sdrhittesthelper.hxx> 63 #include <svx/sdrobjectuser.hxx> 64 #include <svx/sdrobjectfilter.hxx> 65 #include <svx/svddrag.hxx> 66 #include <svx/svdetc.hxx> 67 #include <svx/svdhdl.hxx> 68 #include <svx/svditer.hxx> 69 #include <svx/svdmodel.hxx> 70 #include <svx/svdoashp.hxx> 71 #include <svx/svdocapt.hxx> 72 #include <svx/svdocirc.hxx> 73 #include <svx/svdoedge.hxx> 74 #include <svx/svdograf.hxx> 75 #include <svx/svdogrp.hxx> 76 #include <svx/svdomeas.hxx> 77 #include <svx/svdomedia.hxx> 78 #include <svx/svdoole2.hxx> 79 #include <svx/svdopage.hxx> 80 #include <svx/svdopath.hxx> 81 #include <svx/svdorect.hxx> 82 #include <svx/svdotext.hxx> 83 #include <svx/svdouno.hxx> 84 #include <svx/svdovirt.hxx> 85 #include <svx/svdpage.hxx> 86 #include <svx/svdpool.hxx> 87 #include <svx/strings.hrc> 88 #include <svx/dialmgr.hxx> 89 #include <svx/svdtrans.hxx> 90 #include <svx/svdundo.hxx> 91 #include <svx/svdview.hxx> 92 #include <sxlayitm.hxx> 93 #include <sxlogitm.hxx> 94 #include <sxmovitm.hxx> 95 #include <sxoneitm.hxx> 96 #include <sxopitm.hxx> 97 #include <sxreoitm.hxx> 98 #include <sxrooitm.hxx> 99 #include <sxsaitm.hxx> 100 #include <sxsoitm.hxx> 101 #include <sxtraitm.hxx> 102 #include <svx/unopage.hxx> 103 #include <svx/unoshape.hxx> 104 #include <svx/xfillit0.hxx> 105 #include <svx/xflclit.hxx> 106 #include <svx/xfltrit.hxx> 107 #include <svx/xlineit0.hxx> 108 #include <svx/xlnclit.hxx> 109 #include <svx/xlnedwit.hxx> 110 #include <svx/xlnstwit.hxx> 111 #include <svx/xlntrit.hxx> 112 #include <svx/xlnwtit.hxx> 113 #include <svx/svdglue.hxx> 114 #include <svx/svdsob.hxx> 115 #include <svdobjplusdata.hxx> 116 #include <svdobjuserdatalist.hxx> 117 118 #include <unordered_set> 119 120 #include <optional> 121 #include <libxml/xmlwriter.h> 122 #include <memory> 123 124 #include <svx/scene3d.hxx> 125 #include <rtl/character.hxx> 126 127 using namespace ::com::sun::star; 128 129 130 SdrObjUserCall::~SdrObjUserCall() 131 { 132 } 133 134 void SdrObjUserCall::Changed(const SdrObject& /*rObj*/, SdrUserCallType /*eType*/, const tools::Rectangle& /*rOldBoundRect*/) 135 { 136 } 137 138 SdrObjMacroHitRec::SdrObjMacroHitRec() : 139 pVisiLayer(nullptr), 140 pPageView(nullptr), 141 nTol(0) {} 142 143 144 SdrObjUserData::SdrObjUserData(SdrInventor nInv, sal_uInt16 nId) : 145 nInventor(nInv), 146 nIdentifier(nId) {} 147 148 SdrObjUserData::SdrObjUserData(const SdrObjUserData& rData) : 149 nInventor(rData.nInventor), 150 nIdentifier(rData.nIdentifier) {} 151 152 SdrObjUserData::~SdrObjUserData() {} 153 154 SdrObjGeoData::SdrObjGeoData(): 155 bMovProt(false), 156 bSizProt(false), 157 bNoPrint(false), 158 bClosedObj(false), 159 mbVisible(true), 160 mnLayerID(0) 161 { 162 } 163 164 SdrObjGeoData::~SdrObjGeoData() 165 { 166 } 167 168 SdrObjTransformInfoRec::SdrObjTransformInfoRec() : 169 bMoveAllowed(true), 170 bResizeFreeAllowed(true), 171 bResizePropAllowed(true), 172 bRotateFreeAllowed(true), 173 bRotate90Allowed(true), 174 bMirrorFreeAllowed(true), 175 bMirror45Allowed(true), 176 bMirror90Allowed(true), 177 bTransparenceAllowed(true), 178 bShearAllowed(true), 179 bEdgeRadiusAllowed(true), 180 bNoOrthoDesired(true), 181 bNoContortion(true), 182 bCanConvToPath(true), 183 bCanConvToPoly(true), 184 bCanConvToContour(false), 185 bCanConvToPathLineToArea(true), 186 bCanConvToPolyLineToArea(true) {} 187 188 struct SdrObject::Impl 189 { 190 sdr::ObjectUserVector maObjectUsers; 191 std::shared_ptr<DiagramDataInterface> mpDiagramData; 192 std::optional<double> mnRelativeWidth; 193 std::optional<double> mnRelativeHeight; 194 sal_Int16 meRelativeWidthRelation; 195 sal_Int16 meRelativeHeightRelation; 196 197 Impl() : 198 meRelativeWidthRelation(text::RelOrientation::PAGE_FRAME), 199 meRelativeHeightRelation(text::RelOrientation::PAGE_FRAME) {} 200 }; 201 202 203 // BaseProperties section 204 205 std::unique_ptr<sdr::properties::BaseProperties> SdrObject::CreateObjectSpecificProperties() 206 { 207 return std::make_unique<sdr::properties::EmptyProperties>(*this); 208 } 209 210 sdr::properties::BaseProperties& SdrObject::GetProperties() const 211 { 212 if(!mpProperties) 213 { 214 // CAUTION(!) Do *not* call this during SdrObject construction, 215 // that will lead to wrong type-casts (dependent on constructor-level) 216 // and thus eventually create the wrong sdr::properties (!). Is there 217 // a way to check if on the stack is a SdrObject-constructor (?) 218 const_cast< SdrObject* >(this)->mpProperties = 219 const_cast< SdrObject* >(this)->CreateObjectSpecificProperties(); 220 } 221 222 return *mpProperties; 223 } 224 225 226 // ObjectUser section 227 228 void SdrObject::AddObjectUser(sdr::ObjectUser& rNewUser) 229 { 230 mpImpl->maObjectUsers.push_back(&rNewUser); 231 } 232 233 void SdrObject::RemoveObjectUser(sdr::ObjectUser& rOldUser) 234 { 235 const sdr::ObjectUserVector::iterator aFindResult = 236 std::find(mpImpl->maObjectUsers.begin(), mpImpl->maObjectUsers.end(), &rOldUser); 237 if (aFindResult != mpImpl->maObjectUsers.end()) 238 { 239 mpImpl->maObjectUsers.erase(aFindResult); 240 } 241 } 242 243 244 // DrawContact section 245 246 std::unique_ptr<sdr::contact::ViewContact> SdrObject::CreateObjectSpecificViewContact() 247 { 248 return std::make_unique<sdr::contact::ViewContactOfSdrObj>(*this); 249 } 250 251 sdr::contact::ViewContact& SdrObject::GetViewContact() const 252 { 253 if(!mpViewContact) 254 { 255 const_cast< SdrObject* >(this)->mpViewContact = 256 const_cast< SdrObject* >(this)->CreateObjectSpecificViewContact(); 257 } 258 259 return *mpViewContact; 260 } 261 262 // DrawContact support: Methods for handling Object changes 263 void SdrObject::ActionChanged() const 264 { 265 // Do necessary ViewContact actions 266 GetViewContact().ActionChanged(); 267 } 268 269 SdrPage* SdrObject::getSdrPageFromSdrObject() const 270 { 271 if(getParentSdrObjListFromSdrObject()) 272 { 273 return getParentSdrObjListFromSdrObject()->getSdrPageFromSdrObjList(); 274 } 275 276 return nullptr; 277 } 278 279 SdrModel& SdrObject::getSdrModelFromSdrObject() const 280 { 281 return mrSdrModelFromSdrObject; 282 } 283 284 void SdrObject::setParentOfSdrObject(SdrObjList* pNewObjList) 285 { 286 if(getParentSdrObjListFromSdrObject() == pNewObjList) 287 return; 288 289 // remember current page 290 SdrPage* pOldPage(getSdrPageFromSdrObject()); 291 292 // set new parent 293 mpParentOfSdrObject = pNewObjList; 294 295 // get new page 296 SdrPage* pNewPage(getSdrPageFromSdrObject()); 297 298 // broadcast page change over objects if needed 299 if(pOldPage != pNewPage) 300 { 301 handlePageChange(pOldPage, pNewPage); 302 } 303 } 304 305 SdrObjList* SdrObject::getParentSdrObjListFromSdrObject() const 306 { 307 return mpParentOfSdrObject; 308 } 309 310 SdrObjList* SdrObject::getChildrenOfSdrObject() const 311 { 312 // default has no children 313 return nullptr; 314 } 315 316 void SdrObject::SetBoundRectDirty() 317 { 318 m_aOutRect = tools::Rectangle(); 319 } 320 321 #ifdef DBG_UTIL 322 // SdrObjectLifetimeWatchDog: 323 void impAddIncarnatedSdrObjectToSdrModel(const SdrObject& rSdrObject, SdrModel& rSdrModel) 324 { 325 rSdrModel.maAllIncarnatedObjects.insert(&rSdrObject); 326 } 327 void impRemoveIncarnatedSdrObjectToSdrModel(const SdrObject& rSdrObject, SdrModel& rSdrModel) 328 { 329 if(!rSdrModel.maAllIncarnatedObjects.erase(&rSdrObject)) 330 { 331 SAL_WARN("svx","SdrObject::~SdrObject: Destructed incarnation of SdrObject not member of this SdrModel (!)"); 332 } 333 } 334 #endif 335 336 SdrObject::SdrObject(SdrModel& rSdrModel) 337 : mpFillGeometryDefiningShape(nullptr) 338 ,mrSdrModelFromSdrObject(rSdrModel) 339 ,m_pUserCall(nullptr) 340 ,mpImpl(new Impl) 341 ,mpParentOfSdrObject(nullptr) 342 ,m_nOrdNum(0) 343 ,mnNavigationPosition(SAL_MAX_UINT32) 344 ,mnLayerID(0) 345 ,mpSvxShape( nullptr ) 346 ,maWeakUnoShape() 347 ,mbDoNotInsertIntoPageAutomatically(false) 348 { 349 m_bVirtObj =false; 350 m_bSnapRectDirty =true; 351 m_bMovProt =false; 352 m_bSizProt =false; 353 m_bNoPrint =false; 354 m_bEmptyPresObj =false; 355 m_bNotVisibleAsMaster=false; 356 m_bClosedObj =false; 357 mbVisible = true; 358 359 // #i25616# 360 mbLineIsOutsideGeometry = false; 361 362 // #i25616# 363 mbSupportTextIndentingOnLineWidthChange = false; 364 365 m_bIsEdge=false; 366 m_bIs3DObj=false; 367 m_bMarkProt=false; 368 m_bIsUnoObj=false; 369 #ifdef DBG_UTIL 370 // SdrObjectLifetimeWatchDog: 371 impAddIncarnatedSdrObjectToSdrModel(*this, getSdrModelFromSdrObject()); 372 #endif 373 } 374 375 SdrObject::SdrObject(SdrModel& rSdrModel, SdrObject const & rSource) 376 : mpFillGeometryDefiningShape(nullptr) 377 ,mrSdrModelFromSdrObject(rSdrModel) 378 ,m_pUserCall(nullptr) 379 ,mpImpl(new Impl) 380 ,mpParentOfSdrObject(nullptr) 381 ,m_nOrdNum(0) 382 ,mnNavigationPosition(SAL_MAX_UINT32) 383 ,mnLayerID(0) 384 ,mpSvxShape( nullptr ) 385 ,maWeakUnoShape() 386 ,mbDoNotInsertIntoPageAutomatically(false) 387 { 388 m_bVirtObj =false; 389 m_bSnapRectDirty =true; 390 m_bMovProt =false; 391 m_bSizProt =false; 392 m_bNoPrint =false; 393 m_bEmptyPresObj =false; 394 m_bNotVisibleAsMaster=false; 395 m_bClosedObj =false; 396 mbVisible = true; 397 398 // #i25616# 399 mbLineIsOutsideGeometry = false; 400 401 // #i25616# 402 mbSupportTextIndentingOnLineWidthChange = false; 403 404 m_bIsEdge=false; 405 m_bIs3DObj=false; 406 m_bMarkProt=false; 407 m_bIsUnoObj=false; 408 #ifdef DBG_UTIL 409 // SdrObjectLifetimeWatchDog: 410 impAddIncarnatedSdrObjectToSdrModel(*this, getSdrModelFromSdrObject()); 411 #endif 412 413 mpProperties.reset(); 414 mpViewContact.reset(); 415 416 // The CloneSdrObject() method uses the local copy constructor from the individual 417 // sdr::properties::BaseProperties class. Since the target class maybe for another 418 // draw object, an SdrObject needs to be provided, as in the normal constructor. 419 mpProperties = rSource.GetProperties().Clone(*this); 420 421 m_aOutRect=rSource.m_aOutRect; 422 mnLayerID = rSource.mnLayerID; 423 m_aAnchor =rSource.m_aAnchor; 424 m_bVirtObj=rSource.m_bVirtObj; 425 m_bSizProt=rSource.m_bSizProt; 426 m_bMovProt=rSource.m_bMovProt; 427 m_bNoPrint=rSource.m_bNoPrint; 428 mbVisible=rSource.mbVisible; 429 m_bMarkProt=rSource.m_bMarkProt; 430 m_bEmptyPresObj =rSource.m_bEmptyPresObj; 431 m_bNotVisibleAsMaster=rSource.m_bNotVisibleAsMaster; 432 m_bSnapRectDirty=true; 433 m_pPlusData.reset(); 434 if (rSource.m_pPlusData!=nullptr) { 435 m_pPlusData.reset(rSource.m_pPlusData->Clone(this)); 436 } 437 if (m_pPlusData!=nullptr && m_pPlusData->pBroadcast!=nullptr) { 438 m_pPlusData->pBroadcast.reset(); // broadcaster isn't copied 439 } 440 441 m_pGrabBagItem.reset(); 442 if (rSource.m_pGrabBagItem!=nullptr) 443 m_pGrabBagItem.reset(rSource.m_pGrabBagItem->Clone()); 444 } 445 446 SdrObject::~SdrObject() 447 { 448 // Tell all the registered ObjectUsers that the page is in destruction. 449 // And clear the vector. This means that user do not need to call RemoveObjectUser() 450 // when they get called from ObjectInDestruction(). 451 sdr::ObjectUserVector aList; 452 aList.swap(mpImpl->maObjectUsers); 453 for(sdr::ObjectUser* pObjectUser : aList) 454 { 455 DBG_ASSERT(pObjectUser, "SdrObject::~SdrObject: corrupt ObjectUser list (!)"); 456 pObjectUser->ObjectInDestruction(*this); 457 } 458 459 // UserCall 460 SendUserCall(SdrUserCallType::Delete, GetLastBoundRect()); 461 o3tl::reset_preserve_ptr_during(m_pPlusData); 462 463 m_pGrabBagItem.reset(); 464 mpProperties.reset(); 465 mpViewContact.reset(); 466 467 #ifdef DBG_UTIL 468 // SdrObjectLifetimeWatchDog: 469 impRemoveIncarnatedSdrObjectToSdrModel(*this, getSdrModelFromSdrObject()); 470 #endif 471 } 472 473 void SdrObject::Free( SdrObject*& _rpObject ) 474 { 475 SdrObject* pObject = _rpObject; _rpObject = nullptr; 476 477 if(nullptr == pObject) 478 { 479 // nothing to do 480 return; 481 } 482 483 SvxShape* pShape(pObject->getSvxShape()); 484 485 if(pShape) 486 { 487 if(pShape->HasSdrObjectOwnership()) 488 { 489 // only the SvxShape is allowed to delete me, and will reset 490 // the ownership before doing so 491 return; 492 } 493 else 494 { 495 // not only delete pObject, but also need to dispose uno shape 496 try 497 { 498 pShape->InvalidateSdrObject(); 499 uno::Reference< lang::XComponent > xShapeComp( pObject->getWeakUnoShape(), uno::UNO_QUERY_THROW ); 500 xShapeComp->dispose(); 501 } 502 catch( const uno::Exception& ) 503 { 504 DBG_UNHANDLED_EXCEPTION("svx"); 505 } 506 } 507 } 508 509 delete pObject; 510 } 511 512 void SdrObject::SetBoundAndSnapRectsDirty(bool bNotMyself, bool bRecursive) 513 { 514 if (!bNotMyself) 515 { 516 SetBoundRectDirty(); 517 m_bSnapRectDirty=true; 518 } 519 520 if (bRecursive && nullptr != getParentSdrObjListFromSdrObject()) 521 { 522 getParentSdrObjListFromSdrObject()->SetSdrObjListRectsDirty(); 523 } 524 } 525 526 void SdrObject::handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage) 527 { 528 // The creation of the UNO shape in SdrObject::getUnoShape is influenced 529 // by pPage, so when the page changes we need to discard the cached UNO 530 // shape so that a new one will be created. 531 // If the page is changing to another page with the same model, we 532 // assume they create compatible UNO shape objects so we shouldn't have 533 // to invalidate. 534 // TTTT: This causes quite some problems in SvxDrawPage::add when used 535 // e.g. from Writer - the SdrObject may be cloned to target model, and 536 // the xShape was added to it by purpose (see there). Thus it will be 537 // good to think about if this is really needed - it *seems* to be intended 538 // for a xShape being a on-demand-creatable resource - with the argument that 539 // the SdrPage/UnoPage used influences the SvxShape creation. This uses 540 // resources and would be nice to get rid of anyways. 541 if(nullptr == pOldPage || nullptr == pNewPage) 542 { 543 SvxShape* const pShape(getSvxShape()); 544 545 if (pShape && !pShape->HasSdrObjectOwnership()) 546 { 547 setUnoShape(nullptr); 548 } 549 } 550 } 551 552 553 // global static ItemPool for not-yet-inserted items 554 static rtl::Reference<SdrItemPool> mpGlobalItemPool; 555 556 /** If we let the libc runtime clean us up, we trigger a crash */ 557 namespace 558 { 559 class TerminateListener : public ::cppu::WeakImplHelper< css::frame::XTerminateListener > 560 { 561 void SAL_CALL queryTermination( const lang::EventObject& ) override 562 {} 563 void SAL_CALL notifyTermination( const lang::EventObject& ) override 564 { 565 mpGlobalItemPool.clear(); 566 } 567 virtual void SAL_CALL disposing( const ::css::lang::EventObject& ) override 568 {} 569 }; 570 }; 571 572 // init global static itempool 573 SdrItemPool& SdrObject::GetGlobalDrawObjectItemPool() 574 { 575 if(!mpGlobalItemPool) 576 { 577 mpGlobalItemPool = new SdrItemPool(); 578 rtl::Reference<SfxItemPool> pGlobalOutlPool = EditEngine::CreatePool(); 579 mpGlobalItemPool->SetSecondaryPool(pGlobalOutlPool.get()); 580 mpGlobalItemPool->SetDefaultMetric(SdrEngineDefaults::GetMapUnit()); 581 mpGlobalItemPool->FreezeIdRanges(); 582 if (utl::ConfigManager::IsFuzzing()) 583 mpGlobalItemPool->acquire(); 584 else 585 { 586 uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create(comphelper::getProcessComponentContext()); 587 uno::Reference< frame::XTerminateListener > xListener( new TerminateListener ); 588 xDesktop->addTerminateListener( xListener ); 589 } 590 } 591 592 return *mpGlobalItemPool; 593 } 594 595 void SdrObject::SetRelativeWidth( double nValue ) 596 { 597 mpImpl->mnRelativeWidth = nValue; 598 } 599 600 void SdrObject::SetRelativeWidthRelation( sal_Int16 eValue ) 601 { 602 mpImpl->meRelativeWidthRelation = eValue; 603 } 604 605 void SdrObject::SetRelativeHeight( double nValue ) 606 { 607 mpImpl->mnRelativeHeight = nValue; 608 } 609 610 void SdrObject::SetRelativeHeightRelation( sal_Int16 eValue ) 611 { 612 mpImpl->meRelativeHeightRelation = eValue; 613 } 614 615 const double* SdrObject::GetRelativeWidth( ) const 616 { 617 if (!mpImpl->mnRelativeWidth) 618 return nullptr; 619 620 return &*mpImpl->mnRelativeWidth; 621 } 622 623 sal_Int16 SdrObject::GetRelativeWidthRelation() const 624 { 625 return mpImpl->meRelativeWidthRelation; 626 } 627 628 const double* SdrObject::GetRelativeHeight( ) const 629 { 630 if (!mpImpl->mnRelativeHeight) 631 return nullptr; 632 633 return &*mpImpl->mnRelativeHeight; 634 } 635 636 sal_Int16 SdrObject::GetRelativeHeightRelation() const 637 { 638 return mpImpl->meRelativeHeightRelation; 639 } 640 641 void SdrObject::SetDiagramData(std::shared_ptr<DiagramDataInterface> pDiagramData) 642 { 643 mpImpl->mpDiagramData = pDiagramData; 644 } 645 646 const std::shared_ptr<DiagramDataInterface> & SdrObject::GetDiagramData() const 647 { 648 return mpImpl->mpDiagramData; 649 } 650 651 SfxItemPool& SdrObject::GetObjectItemPool() const 652 { 653 return getSdrModelFromSdrObject().GetItemPool(); 654 } 655 656 SdrInventor SdrObject::GetObjInventor() const 657 { 658 return SdrInventor::Default; 659 } 660 661 SdrObjKind SdrObject::GetObjIdentifier() const 662 { 663 return OBJ_NONE; 664 } 665 666 void SdrObject::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const 667 { 668 rInfo.bRotateFreeAllowed=false; 669 rInfo.bMirrorFreeAllowed=false; 670 rInfo.bTransparenceAllowed = false; 671 rInfo.bShearAllowed =false; 672 rInfo.bEdgeRadiusAllowed=false; 673 rInfo.bCanConvToPath =false; 674 rInfo.bCanConvToPoly =false; 675 rInfo.bCanConvToContour = false; 676 rInfo.bCanConvToPathLineToArea=false; 677 rInfo.bCanConvToPolyLineToArea=false; 678 } 679 680 SdrLayerID SdrObject::GetLayer() const 681 { 682 return mnLayerID; 683 } 684 685 void SdrObject::getMergedHierarchySdrLayerIDSet(SdrLayerIDSet& rSet) const 686 { 687 rSet.Set(GetLayer()); 688 SdrObjList* pOL=GetSubList(); 689 if (pOL!=nullptr) { 690 const size_t nObjCount = pOL->GetObjCount(); 691 for (size_t nObjNum = 0; nObjNum<nObjCount; ++nObjNum) { 692 pOL->GetObj(nObjNum)->getMergedHierarchySdrLayerIDSet(rSet); 693 } 694 } 695 } 696 697 void SdrObject::NbcSetLayer(SdrLayerID nLayer) 698 { 699 mnLayerID = nLayer; 700 } 701 702 void SdrObject::SetLayer(SdrLayerID nLayer) 703 { 704 NbcSetLayer(nLayer); 705 SetChanged(); 706 BroadcastObjectChange(); 707 } 708 709 void SdrObject::AddListener(SfxListener& rListener) 710 { 711 ImpForcePlusData(); 712 if (m_pPlusData->pBroadcast==nullptr) m_pPlusData->pBroadcast.reset(new SfxBroadcaster); 713 714 // SdrEdgeObj may be connected to same SdrObject on both ends so allow it 715 // to listen twice 716 SdrEdgeObj const*const pEdge(dynamic_cast<SdrEdgeObj const*>(&rListener)); 717 rListener.StartListening(*m_pPlusData->pBroadcast, pEdge ? DuplicateHandling::Allow : DuplicateHandling::Unexpected); 718 } 719 720 void SdrObject::RemoveListener(SfxListener& rListener) 721 { 722 if (m_pPlusData!=nullptr && m_pPlusData->pBroadcast!=nullptr) { 723 rListener.EndListening(*m_pPlusData->pBroadcast); 724 if (!m_pPlusData->pBroadcast->HasListeners()) { 725 m_pPlusData->pBroadcast.reset(); 726 } 727 } 728 } 729 730 const SfxBroadcaster* SdrObject::GetBroadcaster() const 731 { 732 return m_pPlusData!=nullptr ? m_pPlusData->pBroadcast.get() : nullptr; 733 } 734 735 void SdrObject::AddReference(SdrVirtObj& rVrtObj) 736 { 737 AddListener(rVrtObj); 738 } 739 740 void SdrObject::DelReference(SdrVirtObj& rVrtObj) 741 { 742 RemoveListener(rVrtObj); 743 } 744 745 bool SdrObject::IsGroupObject() const 746 { 747 return GetSubList()!=nullptr; 748 } 749 750 SdrObjList* SdrObject::GetSubList() const 751 { 752 return nullptr; 753 } 754 755 SdrObject* SdrObject::getParentSdrObjectFromSdrObject() const 756 { 757 SdrObjList* pParent(getParentSdrObjListFromSdrObject()); 758 759 if(nullptr == pParent) 760 { 761 return nullptr; 762 } 763 764 return pParent->getSdrObjectFromSdrObjList(); 765 } 766 767 void SdrObject::SetName(const OUString& rStr, const bool bSetChanged) 768 { 769 if (!rStr.isEmpty() && !m_pPlusData) 770 { 771 ImpForcePlusData(); 772 } 773 774 if(!(m_pPlusData && m_pPlusData->aObjName != rStr)) 775 return; 776 777 // Undo/Redo for setting object's name (#i73249#) 778 bool bUndo( false ); 779 if ( getSdrModelFromSdrObject().IsUndoEnabled() ) 780 { 781 bUndo = true; 782 std::unique_ptr<SdrUndoAction> pUndoAction = 783 SdrUndoFactory::CreateUndoObjectStrAttr( 784 *this, 785 SdrUndoObjStrAttr::ObjStrAttrType::Name, 786 GetName(), 787 rStr ); 788 getSdrModelFromSdrObject().BegUndo( pUndoAction->GetComment() ); 789 getSdrModelFromSdrObject().AddUndo( std::move(pUndoAction) ); 790 } 791 m_pPlusData->aObjName = rStr; 792 // Undo/Redo for setting object's name (#i73249#) 793 if ( bUndo ) 794 { 795 getSdrModelFromSdrObject().EndUndo(); 796 } 797 if (bSetChanged) 798 { 799 SetChanged(); 800 BroadcastObjectChange(); 801 } 802 } 803 804 OUString SdrObject::GetName() const 805 { 806 if(m_pPlusData) 807 { 808 return m_pPlusData->aObjName; 809 } 810 811 return OUString(); 812 } 813 814 void SdrObject::SetTitle(const OUString& rStr) 815 { 816 if (!rStr.isEmpty() && !m_pPlusData) 817 { 818 ImpForcePlusData(); 819 } 820 821 if(!(m_pPlusData && m_pPlusData->aObjTitle != rStr)) 822 return; 823 824 // Undo/Redo for setting object's title (#i73249#) 825 bool bUndo( false ); 826 if ( getSdrModelFromSdrObject().IsUndoEnabled() ) 827 { 828 bUndo = true; 829 std::unique_ptr<SdrUndoAction> pUndoAction = 830 SdrUndoFactory::CreateUndoObjectStrAttr( 831 *this, 832 SdrUndoObjStrAttr::ObjStrAttrType::Title, 833 GetTitle(), 834 rStr ); 835 getSdrModelFromSdrObject().BegUndo( pUndoAction->GetComment() ); 836 getSdrModelFromSdrObject().AddUndo( std::move(pUndoAction) ); 837 } 838 m_pPlusData->aObjTitle = rStr; 839 // Undo/Redo for setting object's title (#i73249#) 840 if ( bUndo ) 841 { 842 getSdrModelFromSdrObject().EndUndo(); 843 } 844 SetChanged(); 845 BroadcastObjectChange(); 846 } 847 848 OUString SdrObject::GetTitle() const 849 { 850 if(m_pPlusData) 851 { 852 return m_pPlusData->aObjTitle; 853 } 854 855 return OUString(); 856 } 857 858 void SdrObject::SetDescription(const OUString& rStr) 859 { 860 if (!rStr.isEmpty() && !m_pPlusData) 861 { 862 ImpForcePlusData(); 863 } 864 865 if(!(m_pPlusData && m_pPlusData->aObjDescription != rStr)) 866 return; 867 868 // Undo/Redo for setting object's description (#i73249#) 869 bool bUndo( false ); 870 if ( getSdrModelFromSdrObject().IsUndoEnabled() ) 871 { 872 bUndo = true; 873 std::unique_ptr<SdrUndoAction> pUndoAction = 874 SdrUndoFactory::CreateUndoObjectStrAttr( 875 *this, 876 SdrUndoObjStrAttr::ObjStrAttrType::Description, 877 GetDescription(), 878 rStr ); 879 getSdrModelFromSdrObject().BegUndo( pUndoAction->GetComment() ); 880 getSdrModelFromSdrObject().AddUndo( std::move(pUndoAction) ); 881 } 882 m_pPlusData->aObjDescription = rStr; 883 // Undo/Redo for setting object's description (#i73249#) 884 if ( bUndo ) 885 { 886 getSdrModelFromSdrObject().EndUndo(); 887 } 888 SetChanged(); 889 BroadcastObjectChange(); 890 } 891 892 OUString SdrObject::GetDescription() const 893 { 894 if(m_pPlusData) 895 { 896 return m_pPlusData->aObjDescription; 897 } 898 899 return OUString(); 900 } 901 902 sal_uInt32 SdrObject::GetOrdNum() const 903 { 904 if (nullptr != getParentSdrObjListFromSdrObject()) 905 { 906 if (getParentSdrObjListFromSdrObject()->IsObjOrdNumsDirty()) 907 { 908 getParentSdrObjListFromSdrObject()->RecalcObjOrdNums(); 909 } 910 } else const_cast<SdrObject*>(this)->m_nOrdNum=0; 911 return m_nOrdNum; 912 } 913 914 915 void SdrObject::SetOrdNum(sal_uInt32 nNum) 916 { 917 m_nOrdNum = nNum; 918 } 919 920 void SdrObject::GetGrabBagItem(css::uno::Any& rVal) const 921 { 922 if (m_pGrabBagItem != nullptr) 923 m_pGrabBagItem->QueryValue(rVal); 924 else 925 rVal <<= uno::Sequence<beans::PropertyValue>(); 926 } 927 928 void SdrObject::SetGrabBagItem(const css::uno::Any& rVal) 929 { 930 if (m_pGrabBagItem == nullptr) 931 m_pGrabBagItem.reset(new SfxGrabBagItem); 932 933 m_pGrabBagItem->PutValue(rVal, 0); 934 935 SetChanged(); 936 BroadcastObjectChange(); 937 } 938 939 sal_uInt32 SdrObject::GetNavigationPosition() const 940 { 941 if (nullptr != getParentSdrObjListFromSdrObject() && getParentSdrObjListFromSdrObject()->RecalcNavigationPositions()) 942 { 943 return mnNavigationPosition; 944 } 945 else 946 return GetOrdNum(); 947 } 948 949 950 void SdrObject::SetNavigationPosition (const sal_uInt32 nNewPosition) 951 { 952 mnNavigationPosition = nNewPosition; 953 } 954 955 956 // To make clearer that this method may trigger RecalcBoundRect and thus may be 957 // expensive and sometimes problematic (inside a bigger object change you will get 958 // non-useful BoundRects sometimes) I rename that method from GetBoundRect() to 959 // GetCurrentBoundRect(). 960 const tools::Rectangle& SdrObject::GetCurrentBoundRect() const 961 { 962 if(m_aOutRect.IsEmpty()) 963 { 964 const_cast< SdrObject* >(this)->RecalcBoundRect(); 965 } 966 967 return m_aOutRect; 968 } 969 970 // To have a possibility to get the last calculated BoundRect e.g for producing 971 // the first rectangle for repaints (old and new need to be used) without forcing 972 // a RecalcBoundRect (which may be problematical and expensive sometimes) I add here 973 // a new method for accessing the last BoundRect. 974 const tools::Rectangle& SdrObject::GetLastBoundRect() const 975 { 976 return m_aOutRect; 977 } 978 979 void SdrObject::RecalcBoundRect() 980 { 981 // #i101680# suppress BoundRect calculations on import(s) 982 if ((getSdrModelFromSdrObject().isLocked()) || utl::ConfigManager::IsFuzzing()) 983 return; 984 985 // central new method which will calculate the BoundRect using primitive geometry 986 if(!m_aOutRect.IsEmpty()) 987 return; 988 989 // Use view-independent data - we do not want any connections 990 // to e.g. GridOffset in SdrObject-level 991 const drawinglayer::primitive2d::Primitive2DContainer& xPrimitives(GetViewContact().getViewIndependentPrimitive2DContainer()); 992 993 if(xPrimitives.empty()) 994 return; 995 996 // use neutral ViewInformation and get the range of the primitives 997 const drawinglayer::geometry::ViewInformation2D aViewInformation2D; 998 const basegfx::B2DRange aRange(xPrimitives.getB2DRange(aViewInformation2D)); 999 1000 if(!aRange.isEmpty()) 1001 { 1002 m_aOutRect = tools::Rectangle( 1003 static_cast<tools::Long>(floor(aRange.getMinX())), 1004 static_cast<tools::Long>(floor(aRange.getMinY())), 1005 static_cast<tools::Long>(ceil(aRange.getMaxX())), 1006 static_cast<tools::Long>(ceil(aRange.getMaxY()))); 1007 return; 1008 } 1009 } 1010 1011 void SdrObject::BroadcastObjectChange() const 1012 { 1013 if ((getSdrModelFromSdrObject().isLocked()) || utl::ConfigManager::IsFuzzing()) 1014 return; 1015 1016 bool bPlusDataBroadcast(m_pPlusData && m_pPlusData->pBroadcast); 1017 bool bObjectChange(IsInserted()); 1018 1019 if(!(bPlusDataBroadcast || bObjectChange)) 1020 return; 1021 1022 SdrHint aHint(SdrHintKind::ObjectChange, *this); 1023 1024 if(bPlusDataBroadcast) 1025 { 1026 m_pPlusData->pBroadcast->Broadcast(aHint); 1027 } 1028 1029 if(bObjectChange) 1030 { 1031 getSdrModelFromSdrObject().Broadcast(aHint); 1032 } 1033 } 1034 1035 void SdrObject::SetChanged() 1036 { 1037 // For testing purposes, use the new ViewContact for change 1038 // notification now. 1039 ActionChanged(); 1040 1041 // TTTT Need to check meaning/usage of IsInserted in one 1042 // of the next changes. It should not mean to have a SdrModel 1043 // set (this is guaranteed now), but should be connected to 1044 // being added to a SdrPage (?) 1045 // TTTT tdf#120066 Indeed - This triggers e.g. by CustomShape 1046 // geometry-presenting SdrObjects that are in a SdrObjGroup, 1047 // but the SdrObjGroup is *by purpose* not inserted. 1048 // Need to check deeper and maybe identify all ::IsInserted() 1049 // calls by rename and let the compiler work... 1050 if(nullptr != getSdrPageFromSdrObject()) 1051 { 1052 getSdrModelFromSdrObject().SetChanged(); 1053 } 1054 } 1055 1056 // tooling for painting a single object to an OutputDevice. 1057 void SdrObject::SingleObjectPainter(OutputDevice& rOut) const 1058 { 1059 sdr::contact::SdrObjectVector aObjectVector; 1060 aObjectVector.push_back(const_cast< SdrObject* >(this)); 1061 1062 sdr::contact::ObjectContactOfObjListPainter aPainter(rOut, aObjectVector, getSdrPageFromSdrObject()); 1063 sdr::contact::DisplayInfo aDisplayInfo; 1064 1065 aPainter.ProcessDisplay(aDisplayInfo); 1066 } 1067 1068 bool SdrObject::LineGeometryUsageIsNecessary() const 1069 { 1070 drawing::LineStyle eXLS = GetMergedItem(XATTR_LINESTYLE).GetValue(); 1071 return (eXLS != drawing::LineStyle_NONE); 1072 } 1073 1074 bool SdrObject::HasLimitedRotation() const 1075 { 1076 // RotGrfFlyFrame: Default is false, support full rotation 1077 return false; 1078 } 1079 1080 SdrObject* SdrObject::CloneSdrObject(SdrModel& rTargetModel) const 1081 { 1082 return new SdrObject(rTargetModel, *this); 1083 } 1084 1085 OUString SdrObject::TakeObjNameSingul() const 1086 { 1087 OUString sName(SvxResId(STR_ObjNameSingulNONE)); 1088 1089 OUString aName(GetName()); 1090 if (!aName.isEmpty()) 1091 sName += " '" + aName + "'"; 1092 return sName; 1093 } 1094 1095 OUString SdrObject::TakeObjNamePlural() const 1096 { 1097 return SvxResId(STR_ObjNamePluralNONE); 1098 } 1099 1100 OUString SdrObject::ImpGetDescriptionStr(TranslateId pStrCacheID) const 1101 { 1102 OUString aStr = SvxResId(pStrCacheID); 1103 sal_Int32 nPos = aStr.indexOf("%1"); 1104 if (nPos >= 0) 1105 { 1106 // Replace '%1' with the object name. 1107 OUString aObjName(TakeObjNameSingul()); 1108 aStr = aStr.replaceAt(nPos, 2, aObjName); 1109 } 1110 1111 nPos = aStr.indexOf("%2"); 1112 if (nPos >= 0) 1113 // Replace '%2' with the passed value. 1114 aStr = aStr.replaceAt(nPos, 2, "0"); 1115 return aStr; 1116 } 1117 1118 void SdrObject::ImpForcePlusData() 1119 { 1120 if (!m_pPlusData) 1121 m_pPlusData.reset( new SdrObjPlusData ); 1122 } 1123 1124 OUString SdrObject::GetMetrStr(tools::Long nVal) const 1125 { 1126 return getSdrModelFromSdrObject().GetMetricString(nVal); 1127 } 1128 1129 basegfx::B2DPolyPolygon SdrObject::TakeXorPoly() const 1130 { 1131 basegfx::B2DPolyPolygon aRetval; 1132 const tools::Rectangle aR(GetCurrentBoundRect()); 1133 aRetval.append(basegfx::utils::createPolygonFromRect(vcl::unotools::b2DRectangleFromRectangle(aR))); 1134 1135 return aRetval; 1136 } 1137 1138 basegfx::B2DPolyPolygon SdrObject::TakeContour() const 1139 { 1140 basegfx::B2DPolyPolygon aRetval; 1141 1142 // create cloned object without text, but with drawing::LineStyle_SOLID, 1143 // COL_BLACK as line color and drawing::FillStyle_NONE 1144 SdrObject* pClone(CloneSdrObject(getSdrModelFromSdrObject())); 1145 1146 if(pClone) 1147 { 1148 const SdrTextObj* pTextObj = dynamic_cast< const SdrTextObj* >(this); 1149 1150 if(pTextObj) 1151 { 1152 // no text and no text animation 1153 pClone->SetMergedItem(SdrTextAniKindItem(SdrTextAniKind::NONE)); 1154 pClone->SetOutlinerParaObject(std::nullopt); 1155 } 1156 1157 const SdrEdgeObj* pEdgeObj = dynamic_cast< const SdrEdgeObj* >(this); 1158 1159 if(pEdgeObj) 1160 { 1161 // create connections if connector, will be cleaned up when 1162 // deleting the connector again 1163 SdrObject* pLeft = pEdgeObj->GetConnectedNode(true); 1164 SdrObject* pRight = pEdgeObj->GetConnectedNode(false); 1165 1166 if(pLeft) 1167 { 1168 pClone->ConnectToNode(true, pLeft); 1169 } 1170 1171 if(pRight) 1172 { 1173 pClone->ConnectToNode(false, pRight); 1174 } 1175 } 1176 1177 SfxItemSet aNewSet(GetObjectItemPool()); 1178 1179 // #i101980# ignore LineWidth; that's what the old implementation 1180 // did. With line width, the result may be huge due to fat/thick 1181 // line decompositions 1182 aNewSet.Put(XLineWidthItem(0)); 1183 1184 // solid black lines and no fill 1185 aNewSet.Put(XLineStyleItem(drawing::LineStyle_SOLID)); 1186 aNewSet.Put(XLineColorItem(OUString(), COL_BLACK)); 1187 aNewSet.Put(XFillStyleItem(drawing::FillStyle_NONE)); 1188 pClone->SetMergedItemSet(aNewSet); 1189 1190 // get sequence from clone 1191 const sdr::contact::ViewContact& rVC(pClone->GetViewContact()); 1192 const drawinglayer::primitive2d::Primitive2DContainer& xSequence(rVC.getViewIndependentPrimitive2DContainer()); 1193 1194 if(!xSequence.empty()) 1195 { 1196 // use neutral ViewInformation 1197 const drawinglayer::geometry::ViewInformation2D aViewInformation2D; 1198 1199 // create extractor, process and get result (with hairlines as opened polygons) 1200 drawinglayer::processor2d::ContourExtractor2D aExtractor(aViewInformation2D, false); 1201 aExtractor.process(xSequence); 1202 const basegfx::B2DPolyPolygonVector& rResult(aExtractor.getExtractedContour()); 1203 const sal_uInt32 nSize(rResult.size()); 1204 1205 // when count is one, it is implied that the object has only its normal 1206 // contour anyways and TakeContour() is to return an empty PolyPolygon 1207 // (see old implementation for historical reasons) 1208 if(nSize > 1) 1209 { 1210 // the topology for contour is correctly a vector of PolyPolygons; for 1211 // historical reasons cut it back to a single tools::PolyPolygon here 1212 for(sal_uInt32 a(0); a < nSize; a++) 1213 { 1214 aRetval.append(rResult[a]); 1215 } 1216 } 1217 } 1218 1219 // Always use SdrObject::Free to delete SdrObjects (!) 1220 SdrObject::Free(pClone); 1221 } 1222 1223 return aRetval; 1224 } 1225 1226 sal_uInt32 SdrObject::GetHdlCount() const 1227 { 1228 return 8; 1229 } 1230 1231 void SdrObject::AddToHdlList(SdrHdlList& rHdlList) const 1232 { 1233 const tools::Rectangle& rR=GetSnapRect(); 1234 for (sal_uInt32 nHdlNum=0; nHdlNum<8; ++nHdlNum) 1235 { 1236 std::unique_ptr<SdrHdl> pH; 1237 switch (nHdlNum) { 1238 case 0: pH.reset(new SdrHdl(rR.TopLeft(), SdrHdlKind::UpperLeft)); break; 1239 case 1: pH.reset(new SdrHdl(rR.TopCenter(), SdrHdlKind::Upper)); break; 1240 case 2: pH.reset(new SdrHdl(rR.TopRight(), SdrHdlKind::UpperRight)); break; 1241 case 3: pH.reset(new SdrHdl(rR.LeftCenter(), SdrHdlKind::Left )); break; 1242 case 4: pH.reset(new SdrHdl(rR.RightCenter(), SdrHdlKind::Right)); break; 1243 case 5: pH.reset(new SdrHdl(rR.BottomLeft(), SdrHdlKind::LowerLeft)); break; 1244 case 6: pH.reset(new SdrHdl(rR.BottomCenter(),SdrHdlKind::Lower)); break; 1245 case 7: pH.reset(new SdrHdl(rR.BottomRight(), SdrHdlKind::LowerRight)); break; 1246 } 1247 rHdlList.AddHdl(std::move(pH)); 1248 } 1249 } 1250 1251 void SdrObject::AddToPlusHdlList(SdrHdlList&, SdrHdl&) const 1252 { 1253 } 1254 1255 void SdrObject::addCropHandles(SdrHdlList& /*rTarget*/) const 1256 { 1257 // Default implementation, does nothing. Overloaded in 1258 // SdrGrafObj and SwVirtFlyDrawObj 1259 } 1260 1261 tools::Rectangle SdrObject::ImpDragCalcRect(const SdrDragStat& rDrag) const 1262 { 1263 tools::Rectangle aTmpRect(GetSnapRect()); 1264 tools::Rectangle aRect(aTmpRect); 1265 const SdrHdl* pHdl=rDrag.GetHdl(); 1266 SdrHdlKind eHdl=pHdl==nullptr ? SdrHdlKind::Move : pHdl->GetKind(); 1267 bool bEcke=(eHdl==SdrHdlKind::UpperLeft || eHdl==SdrHdlKind::UpperRight || eHdl==SdrHdlKind::LowerLeft || eHdl==SdrHdlKind::LowerRight); 1268 bool bOrtho=rDrag.GetView()!=nullptr && rDrag.GetView()->IsOrtho(); 1269 bool bBigOrtho=bEcke && bOrtho && rDrag.GetView()->IsBigOrtho(); 1270 Point aPos(rDrag.GetNow()); 1271 bool bLft=(eHdl==SdrHdlKind::UpperLeft || eHdl==SdrHdlKind::Left || eHdl==SdrHdlKind::LowerLeft); 1272 bool bRgt=(eHdl==SdrHdlKind::UpperRight || eHdl==SdrHdlKind::Right || eHdl==SdrHdlKind::LowerRight); 1273 bool bTop=(eHdl==SdrHdlKind::UpperRight || eHdl==SdrHdlKind::Upper || eHdl==SdrHdlKind::UpperLeft); 1274 bool bBtm=(eHdl==SdrHdlKind::LowerRight || eHdl==SdrHdlKind::Lower || eHdl==SdrHdlKind::LowerLeft); 1275 if (bLft) aTmpRect.SetLeft(aPos.X() ); 1276 if (bRgt) aTmpRect.SetRight(aPos.X() ); 1277 if (bTop) aTmpRect.SetTop(aPos.Y() ); 1278 if (bBtm) aTmpRect.SetBottom(aPos.Y() ); 1279 if (bOrtho) { // Ortho 1280 tools::Long nWdt0=aRect.Right() -aRect.Left(); 1281 tools::Long nHgt0=aRect.Bottom()-aRect.Top(); 1282 tools::Long nXMul=aTmpRect.Right() -aTmpRect.Left(); 1283 tools::Long nYMul=aTmpRect.Bottom()-aTmpRect.Top(); 1284 tools::Long nXDiv=nWdt0; 1285 tools::Long nYDiv=nHgt0; 1286 bool bXNeg=(nXMul<0)!=(nXDiv<0); 1287 bool bYNeg=(nYMul<0)!=(nYDiv<0); 1288 nXMul=std::abs(nXMul); 1289 nYMul=std::abs(nYMul); 1290 nXDiv=std::abs(nXDiv); 1291 nYDiv=std::abs(nYDiv); 1292 Fraction aXFact(nXMul,nXDiv); // fractions for canceling 1293 Fraction aYFact(nYMul,nYDiv); // and for comparing 1294 nXMul=aXFact.GetNumerator(); 1295 nYMul=aYFact.GetNumerator(); 1296 nXDiv=aXFact.GetDenominator(); 1297 nYDiv=aYFact.GetDenominator(); 1298 if (bEcke) { // corner point handles 1299 bool bUseX=(aXFact<aYFact) != bBigOrtho; 1300 if (bUseX) { 1301 tools::Long nNeed=tools::Long(BigInt(nHgt0)*BigInt(nXMul)/BigInt(nXDiv)); 1302 if (bYNeg) nNeed=-nNeed; 1303 if (bTop) aTmpRect.SetTop(aTmpRect.Bottom()-nNeed ); 1304 if (bBtm) aTmpRect.SetBottom(aTmpRect.Top()+nNeed ); 1305 } else { 1306 tools::Long nNeed=tools::Long(BigInt(nWdt0)*BigInt(nYMul)/BigInt(nYDiv)); 1307 if (bXNeg) nNeed=-nNeed; 1308 if (bLft) aTmpRect.SetLeft(aTmpRect.Right()-nNeed ); 1309 if (bRgt) aTmpRect.SetRight(aTmpRect.Left()+nNeed ); 1310 } 1311 } else { // apex handles 1312 if ((bLft || bRgt) && nXDiv!=0) { 1313 tools::Long nHgt0b=aRect.Bottom()-aRect.Top(); 1314 tools::Long nNeed=tools::Long(BigInt(nHgt0b)*BigInt(nXMul)/BigInt(nXDiv)); 1315 aTmpRect.AdjustTop( -((nNeed-nHgt0b)/2) ); 1316 aTmpRect.SetBottom(aTmpRect.Top()+nNeed ); 1317 } 1318 if ((bTop || bBtm) && nYDiv!=0) { 1319 tools::Long nWdt0b=aRect.Right()-aRect.Left(); 1320 tools::Long nNeed=tools::Long(BigInt(nWdt0b)*BigInt(nYMul)/BigInt(nYDiv)); 1321 aTmpRect.AdjustLeft( -((nNeed-nWdt0b)/2) ); 1322 aTmpRect.SetRight(aTmpRect.Left()+nNeed ); 1323 } 1324 } 1325 } 1326 aTmpRect.Justify(); 1327 return aTmpRect; 1328 } 1329 1330 1331 bool SdrObject::hasSpecialDrag() const 1332 { 1333 return false; 1334 } 1335 1336 bool SdrObject::supportsFullDrag() const 1337 { 1338 return true; 1339 } 1340 1341 SdrObjectUniquePtr SdrObject::getFullDragClone() const 1342 { 1343 // default uses simple clone 1344 return SdrObjectUniquePtr(CloneSdrObject(getSdrModelFromSdrObject())); 1345 } 1346 1347 bool SdrObject::beginSpecialDrag(SdrDragStat& rDrag) const 1348 { 1349 const SdrHdl* pHdl = rDrag.GetHdl(); 1350 1351 SdrHdlKind eHdl = (pHdl == nullptr) ? SdrHdlKind::Move : pHdl->GetKind(); 1352 1353 return eHdl==SdrHdlKind::UpperLeft || eHdl==SdrHdlKind::Upper || eHdl==SdrHdlKind::UpperRight || 1354 eHdl==SdrHdlKind::Left || eHdl==SdrHdlKind::Right || eHdl==SdrHdlKind::LowerLeft || 1355 eHdl==SdrHdlKind::Lower || eHdl==SdrHdlKind::LowerRight; 1356 } 1357 1358 bool SdrObject::applySpecialDrag(SdrDragStat& rDrag) 1359 { 1360 tools::Rectangle aNewRect(ImpDragCalcRect(rDrag)); 1361 1362 if(aNewRect != GetSnapRect()) 1363 { 1364 NbcSetSnapRect(aNewRect); 1365 } 1366 1367 return true; 1368 } 1369 1370 OUString SdrObject::getSpecialDragComment(const SdrDragStat& /*rDrag*/) const 1371 { 1372 return OUString(); 1373 } 1374 1375 basegfx::B2DPolyPolygon SdrObject::getSpecialDragPoly(const SdrDragStat& /*rDrag*/) const 1376 { 1377 // default has nothing to add 1378 return basegfx::B2DPolyPolygon(); 1379 } 1380 1381 1382 // Create 1383 bool SdrObject::BegCreate(SdrDragStat& rStat) 1384 { 1385 rStat.SetOrtho4Possible(); 1386 tools::Rectangle aRect1(rStat.GetStart(), rStat.GetNow()); 1387 aRect1.Justify(); 1388 rStat.SetActionRect(aRect1); 1389 m_aOutRect = aRect1; 1390 return true; 1391 } 1392 1393 bool SdrObject::MovCreate(SdrDragStat& rStat) 1394 { 1395 rStat.TakeCreateRect(m_aOutRect); 1396 rStat.SetActionRect(m_aOutRect); 1397 m_aOutRect.Justify(); 1398 1399 return true; 1400 } 1401 1402 bool SdrObject::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd) 1403 { 1404 rStat.TakeCreateRect(m_aOutRect); 1405 m_aOutRect.Justify(); 1406 1407 return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2); 1408 } 1409 1410 void SdrObject::BrkCreate(SdrDragStat& /*rStat*/) 1411 { 1412 } 1413 1414 bool SdrObject::BckCreate(SdrDragStat& /*rStat*/) 1415 { 1416 return false; 1417 } 1418 1419 basegfx::B2DPolyPolygon SdrObject::TakeCreatePoly(const SdrDragStat& rDrag) const 1420 { 1421 tools::Rectangle aRect1; 1422 rDrag.TakeCreateRect(aRect1); 1423 aRect1.Justify(); 1424 1425 basegfx::B2DPolyPolygon aRetval; 1426 aRetval.append(basegfx::utils::createPolygonFromRect(vcl::unotools::b2DRectangleFromRectangle(aRect1))); 1427 return aRetval; 1428 } 1429 1430 PointerStyle SdrObject::GetCreatePointer() const 1431 { 1432 return PointerStyle::Cross; 1433 } 1434 1435 // transformations 1436 void SdrObject::NbcMove(const Size& rSiz) 1437 { 1438 m_aOutRect.Move(rSiz); 1439 SetBoundAndSnapRectsDirty(); 1440 } 1441 1442 void SdrObject::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact) 1443 { 1444 bool bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0); 1445 bool bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0); 1446 if (bXMirr || bYMirr) { 1447 Point aRef1(GetSnapRect().Center()); 1448 if (bXMirr) { 1449 Point aRef2(aRef1); 1450 aRef2.AdjustY( 1 ); 1451 NbcMirrorGluePoints(aRef1,aRef2); 1452 } 1453 if (bYMirr) { 1454 Point aRef2(aRef1); 1455 aRef2.AdjustX( 1 ); 1456 NbcMirrorGluePoints(aRef1,aRef2); 1457 } 1458 } 1459 ResizeRect(m_aOutRect,rRef,xFact,yFact); 1460 SetBoundAndSnapRectsDirty(); 1461 } 1462 1463 void SdrObject::NbcRotate(const Point& rRef, Degree100 nAngle) 1464 { 1465 if (nAngle) 1466 { 1467 double a = nAngle.get() * F_PI18000; 1468 NbcRotate( rRef, nAngle, sin( a ), cos( a ) ); 1469 } 1470 } 1471 1472 void SdrObject::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs) 1473 { 1474 SetGlueReallyAbsolute(true); 1475 m_aOutRect.Move(-rRef.X(),-rRef.Y()); 1476 tools::Rectangle R(m_aOutRect); 1477 if (sn==1.0 && cs==0.0) { // 90deg 1478 m_aOutRect.SetLeft(-R.Bottom() ); 1479 m_aOutRect.SetRight(-R.Top() ); 1480 m_aOutRect.SetTop(R.Left() ); 1481 m_aOutRect.SetBottom(R.Right() ); 1482 } else if (sn==0.0 && cs==-1.0) { // 180deg 1483 m_aOutRect.SetLeft(-R.Right() ); 1484 m_aOutRect.SetRight(-R.Left() ); 1485 m_aOutRect.SetTop(-R.Bottom() ); 1486 m_aOutRect.SetBottom(-R.Top() ); 1487 } else if (sn==-1.0 && cs==0.0) { // 270deg 1488 m_aOutRect.SetLeft(R.Top() ); 1489 m_aOutRect.SetRight(R.Bottom() ); 1490 m_aOutRect.SetTop(-R.Right() ); 1491 m_aOutRect.SetBottom(-R.Left() ); 1492 } 1493 m_aOutRect.Move(rRef.X(),rRef.Y()); 1494 m_aOutRect.Justify(); // just in case 1495 SetBoundAndSnapRectsDirty(); 1496 NbcRotateGluePoints(rRef,nAngle,sn,cs); 1497 SetGlueReallyAbsolute(false); 1498 } 1499 1500 void SdrObject::NbcMirror(const Point& rRef1, const Point& rRef2) 1501 { 1502 SetGlueReallyAbsolute(true); 1503 m_aOutRect.Move(-rRef1.X(),-rRef1.Y()); 1504 tools::Rectangle R(m_aOutRect); 1505 tools::Long dx=rRef2.X()-rRef1.X(); 1506 tools::Long dy=rRef2.Y()-rRef1.Y(); 1507 if (dx==0) { // vertical axis 1508 m_aOutRect.SetLeft(-R.Right() ); 1509 m_aOutRect.SetRight(-R.Left() ); 1510 } else if (dy==0) { // horizontal axis 1511 m_aOutRect.SetTop(-R.Bottom() ); 1512 m_aOutRect.SetBottom(-R.Top() ); 1513 } else if (dx==dy) { // 45deg axis 1514 m_aOutRect.SetLeft(R.Top() ); 1515 m_aOutRect.SetRight(R.Bottom() ); 1516 m_aOutRect.SetTop(R.Left() ); 1517 m_aOutRect.SetBottom(R.Right() ); 1518 } else if (dx==-dy) { // 45deg axis 1519 m_aOutRect.SetLeft(-R.Bottom() ); 1520 m_aOutRect.SetRight(-R.Top() ); 1521 m_aOutRect.SetTop(-R.Right() ); 1522 m_aOutRect.SetBottom(-R.Left() ); 1523 } 1524 m_aOutRect.Move(rRef1.X(),rRef1.Y()); 1525 m_aOutRect.Justify(); // just in case 1526 SetBoundAndSnapRectsDirty(); 1527 NbcMirrorGluePoints(rRef1,rRef2); 1528 SetGlueReallyAbsolute(false); 1529 } 1530 1531 void SdrObject::NbcShear(const Point& rRef, Degree100 /*nAngle*/, double tn, bool bVShear) 1532 { 1533 SetGlueReallyAbsolute(true); 1534 NbcShearGluePoints(rRef,tn,bVShear); 1535 SetGlueReallyAbsolute(false); 1536 } 1537 1538 void SdrObject::Move(const Size& rSiz) 1539 { 1540 if (rSiz.Width()!=0 || rSiz.Height()!=0) { 1541 tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect(); 1542 NbcMove(rSiz); 1543 SetChanged(); 1544 BroadcastObjectChange(); 1545 SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0); 1546 } 1547 } 1548 1549 void SdrObject::NbcCrop(const basegfx::B2DPoint& /*aRef*/, double /*fxFact*/, double /*fyFact*/) 1550 { 1551 // Default: does nothing. Real behaviour in SwVirtFlyDrawObj and SdrDragCrop::EndSdrDrag. 1552 // Where SwVirtFlyDrawObj is the only real user of it to do something local 1553 } 1554 1555 void SdrObject::Resize(const Point& rRef, const Fraction& xFact, const Fraction& yFact, bool bUnsetRelative) 1556 { 1557 if (xFact.GetNumerator() == xFact.GetDenominator() && yFact.GetNumerator() == yFact.GetDenominator()) 1558 return; 1559 1560 if (bUnsetRelative) 1561 { 1562 mpImpl->mnRelativeWidth.reset(); 1563 mpImpl->meRelativeWidthRelation = text::RelOrientation::PAGE_FRAME; 1564 mpImpl->meRelativeHeightRelation = text::RelOrientation::PAGE_FRAME; 1565 mpImpl->mnRelativeHeight.reset(); 1566 } 1567 tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect(); 1568 NbcResize(rRef,xFact,yFact); 1569 SetChanged(); 1570 BroadcastObjectChange(); 1571 SendUserCall(SdrUserCallType::Resize,aBoundRect0); 1572 } 1573 1574 void SdrObject::Crop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact) 1575 { 1576 tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect(); 1577 NbcCrop(rRef, fxFact, fyFact); 1578 SetChanged(); 1579 BroadcastObjectChange(); 1580 SendUserCall(SdrUserCallType::Resize,aBoundRect0); 1581 } 1582 1583 void SdrObject::Rotate(const Point& rRef, Degree100 nAngle, double sn, double cs) 1584 { 1585 if (nAngle) { 1586 tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect(); 1587 NbcRotate(rRef,nAngle,sn,cs); 1588 SetChanged(); 1589 BroadcastObjectChange(); 1590 SendUserCall(SdrUserCallType::Resize,aBoundRect0); 1591 } 1592 } 1593 1594 void SdrObject::Mirror(const Point& rRef1, const Point& rRef2) 1595 { 1596 tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect(); 1597 NbcMirror(rRef1,rRef2); 1598 SetChanged(); 1599 BroadcastObjectChange(); 1600 SendUserCall(SdrUserCallType::Resize,aBoundRect0); 1601 } 1602 1603 void SdrObject::Shear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear) 1604 { 1605 if (nAngle) { 1606 tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect(); 1607 NbcShear(rRef,nAngle,tn,bVShear); 1608 SetChanged(); 1609 BroadcastObjectChange(); 1610 SendUserCall(SdrUserCallType::Resize,aBoundRect0); 1611 } 1612 } 1613 1614 void SdrObject::NbcSetRelativePos(const Point& rPnt) 1615 { 1616 Point aRelPos0(GetSnapRect().TopLeft()-m_aAnchor); 1617 Size aSiz(rPnt.X()-aRelPos0.X(),rPnt.Y()-aRelPos0.Y()); 1618 NbcMove(aSiz); // This also calls SetRectsDirty() 1619 } 1620 1621 void SdrObject::SetRelativePos(const Point& rPnt) 1622 { 1623 if (rPnt!=GetRelativePos()) { 1624 tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect(); 1625 NbcSetRelativePos(rPnt); 1626 SetChanged(); 1627 BroadcastObjectChange(); 1628 SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0); 1629 } 1630 } 1631 1632 Point SdrObject::GetRelativePos() const 1633 { 1634 return GetSnapRect().TopLeft()-m_aAnchor; 1635 } 1636 1637 void SdrObject::ImpSetAnchorPos(const Point& rPnt) 1638 { 1639 m_aAnchor = rPnt; 1640 } 1641 1642 void SdrObject::NbcSetAnchorPos(const Point& rPnt) 1643 { 1644 Size aSiz(rPnt.X()-m_aAnchor.X(),rPnt.Y()-m_aAnchor.Y()); 1645 m_aAnchor=rPnt; 1646 NbcMove(aSiz); // This also calls SetRectsDirty() 1647 } 1648 1649 void SdrObject::SetAnchorPos(const Point& rPnt) 1650 { 1651 if (rPnt!=m_aAnchor) { 1652 tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect(); 1653 NbcSetAnchorPos(rPnt); 1654 SetChanged(); 1655 BroadcastObjectChange(); 1656 SendUserCall(SdrUserCallType::MoveOnly,aBoundRect0); 1657 } 1658 } 1659 1660 const Point& SdrObject::GetAnchorPos() const 1661 { 1662 return m_aAnchor; 1663 } 1664 1665 void SdrObject::RecalcSnapRect() 1666 { 1667 } 1668 1669 const tools::Rectangle& SdrObject::GetSnapRect() const 1670 { 1671 return m_aOutRect; 1672 } 1673 1674 void SdrObject::NbcSetSnapRect(const tools::Rectangle& rRect) 1675 { 1676 m_aOutRect=rRect; 1677 } 1678 1679 const tools::Rectangle& SdrObject::GetLogicRect() const 1680 { 1681 return GetSnapRect(); 1682 } 1683 1684 void SdrObject::NbcSetLogicRect(const tools::Rectangle& rRect) 1685 { 1686 NbcSetSnapRect(rRect); 1687 } 1688 1689 void SdrObject::AdjustToMaxRect( const tools::Rectangle& rMaxRect, bool /* bShrinkOnly = false */ ) 1690 { 1691 SetLogicRect( rMaxRect ); 1692 } 1693 1694 void SdrObject::SetSnapRect(const tools::Rectangle& rRect) 1695 { 1696 tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect(); 1697 NbcSetSnapRect(rRect); 1698 SetChanged(); 1699 BroadcastObjectChange(); 1700 SendUserCall(SdrUserCallType::Resize,aBoundRect0); 1701 } 1702 1703 void SdrObject::SetLogicRect(const tools::Rectangle& rRect) 1704 { 1705 tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect(); 1706 NbcSetLogicRect(rRect); 1707 SetChanged(); 1708 BroadcastObjectChange(); 1709 SendUserCall(SdrUserCallType::Resize,aBoundRect0); 1710 } 1711 1712 Degree100 SdrObject::GetRotateAngle() const 1713 { 1714 return 0_deg100; 1715 } 1716 1717 Degree100 SdrObject::GetShearAngle(bool /*bVertical*/) const 1718 { 1719 return 0_deg100; 1720 } 1721 1722 sal_uInt32 SdrObject::GetSnapPointCount() const 1723 { 1724 return GetPointCount(); 1725 } 1726 1727 Point SdrObject::GetSnapPoint(sal_uInt32 i) const 1728 { 1729 return GetPoint(i); 1730 } 1731 1732 bool SdrObject::IsPolyObj() const 1733 { 1734 return false; 1735 } 1736 1737 sal_uInt32 SdrObject::GetPointCount() const 1738 { 1739 return 0; 1740 } 1741 1742 Point SdrObject::GetPoint(sal_uInt32 /*i*/) const 1743 { 1744 return Point(); 1745 } 1746 1747 void SdrObject::SetPoint(const Point& rPnt, sal_uInt32 i) 1748 { 1749 tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect(); 1750 NbcSetPoint(rPnt, i); 1751 SetChanged(); 1752 BroadcastObjectChange(); 1753 SendUserCall(SdrUserCallType::Resize,aBoundRect0); 1754 } 1755 1756 void SdrObject::NbcSetPoint(const Point& /*rPnt*/, sal_uInt32 /*i*/) 1757 { 1758 } 1759 1760 bool SdrObject::HasTextEdit() const 1761 { 1762 return false; 1763 } 1764 1765 bool SdrObject::Equals(const SdrObject& rOtherObj) const 1766 { 1767 return (m_aAnchor.X() == rOtherObj.m_aAnchor.X() && m_aAnchor.Y() == rOtherObj.m_aAnchor.Y() && 1768 m_nOrdNum == rOtherObj.m_nOrdNum && mnNavigationPosition == rOtherObj.mnNavigationPosition && 1769 mbSupportTextIndentingOnLineWidthChange == rOtherObj.mbSupportTextIndentingOnLineWidthChange && 1770 mbLineIsOutsideGeometry == rOtherObj.mbLineIsOutsideGeometry && m_bMarkProt == rOtherObj.m_bMarkProt && 1771 m_bIs3DObj == rOtherObj.m_bIs3DObj && m_bIsEdge == rOtherObj.m_bIsEdge && m_bClosedObj == rOtherObj.m_bClosedObj && 1772 m_bNotVisibleAsMaster == rOtherObj.m_bNotVisibleAsMaster && m_bEmptyPresObj == rOtherObj.m_bEmptyPresObj && 1773 mbVisible == rOtherObj.mbVisible && m_bNoPrint == rOtherObj.m_bNoPrint && m_bSizProt == rOtherObj.m_bSizProt && 1774 m_bMovProt == rOtherObj.m_bMovProt && m_bVirtObj == rOtherObj.m_bVirtObj && 1775 mnLayerID == rOtherObj.mnLayerID && GetMergedItemSet().Equals(rOtherObj.GetMergedItemSet(), false) ); 1776 } 1777 1778 void SdrObject::dumpAsXml(xmlTextWriterPtr pWriter) const 1779 { 1780 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrObject")); 1781 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this); 1782 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("symbol"), "%s", BAD_CAST(typeid(*this).name())); 1783 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("name"), "%s", BAD_CAST(GetName().toUtf8().getStr())); 1784 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("title"), "%s", BAD_CAST(GetTitle().toUtf8().getStr())); 1785 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("description"), "%s", BAD_CAST(GetDescription().toUtf8().getStr())); 1786 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("nOrdNum"), "%" SAL_PRIuUINT32, GetOrdNumDirect()); 1787 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("aOutRect"), BAD_CAST(m_aOutRect.toString().getStr())); 1788 1789 if (m_pGrabBagItem) 1790 { 1791 m_pGrabBagItem->dumpAsXml(pWriter); 1792 } 1793 1794 if (mpProperties) 1795 { 1796 mpProperties->dumpAsXml(pWriter); 1797 } 1798 1799 if (const OutlinerParaObject* pOutliner = GetOutlinerParaObject()) 1800 pOutliner->dumpAsXml(pWriter); 1801 1802 (void)xmlTextWriterEndElement(pWriter); 1803 } 1804 1805 void SdrObject::SetOutlinerParaObject(std::optional<OutlinerParaObject> pTextObject) 1806 { 1807 tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect(); 1808 NbcSetOutlinerParaObject(std::move(pTextObject)); 1809 SetChanged(); 1810 BroadcastObjectChange(); 1811 if (GetCurrentBoundRect()!=aBoundRect0) { 1812 SendUserCall(SdrUserCallType::Resize,aBoundRect0); 1813 } 1814 1815 if (!getSdrModelFromSdrObject().IsUndoEnabled()) 1816 return; 1817 1818 // Don't do this during import. 1819 SdrObject* pTopGroupObj = nullptr; 1820 if (getParentSdrObjectFromSdrObject()) 1821 { 1822 pTopGroupObj = getParentSdrObjectFromSdrObject(); 1823 while (pTopGroupObj->getParentSdrObjectFromSdrObject()) 1824 { 1825 pTopGroupObj = pTopGroupObj->getParentSdrObjectFromSdrObject(); 1826 } 1827 } 1828 if (pTopGroupObj) 1829 { 1830 // A shape was modified, which is in a group shape. Empty the group shape's grab-bag, 1831 // which potentially contains the old text of the shapes in case of diagrams. 1832 pTopGroupObj->SetGrabBagItem(uno::makeAny(uno::Sequence<beans::PropertyValue>())); 1833 } 1834 } 1835 1836 void SdrObject::NbcSetOutlinerParaObject(std::optional<OutlinerParaObject> /*pTextObject*/) 1837 { 1838 } 1839 1840 OutlinerParaObject* SdrObject::GetOutlinerParaObject() const 1841 { 1842 return nullptr; 1843 } 1844 1845 void SdrObject::NbcReformatText() 1846 { 1847 } 1848 1849 void SdrObject::BurnInStyleSheetAttributes() 1850 { 1851 GetProperties().ForceStyleToHardAttributes(); 1852 } 1853 1854 bool SdrObject::HasMacro() const 1855 { 1856 return false; 1857 } 1858 1859 SdrObject* SdrObject::CheckMacroHit(const SdrObjMacroHitRec& rRec) const 1860 { 1861 if(rRec.pPageView) 1862 { 1863 return SdrObjectPrimitiveHit(*this, rRec.aPos, rRec.nTol, *rRec.pPageView, rRec.pVisiLayer, false); 1864 } 1865 1866 return nullptr; 1867 } 1868 1869 PointerStyle SdrObject::GetMacroPointer(const SdrObjMacroHitRec&) const 1870 { 1871 return PointerStyle::RefHand; 1872 } 1873 1874 void SdrObject::PaintMacro(OutputDevice& rOut, const tools::Rectangle& , const SdrObjMacroHitRec& ) const 1875 { 1876 const RasterOp eRop(rOut.GetRasterOp()); 1877 const basegfx::B2DPolyPolygon aPolyPolygon(TakeXorPoly()); 1878 1879 rOut.SetLineColor(COL_BLACK); 1880 rOut.SetFillColor(); 1881 rOut.SetRasterOp(RasterOp::Invert); 1882 1883 for(auto const& rPolygon : aPolyPolygon) 1884 { 1885 rOut.DrawPolyLine(rPolygon); 1886 } 1887 1888 rOut.SetRasterOp(eRop); 1889 } 1890 1891 bool SdrObject::DoMacro(const SdrObjMacroHitRec&) 1892 { 1893 return false; 1894 } 1895 1896 bool SdrObject::IsMacroHit(const SdrObjMacroHitRec& rRec) const 1897 { 1898 return CheckMacroHit(rRec) != nullptr; 1899 } 1900 1901 1902 std::unique_ptr<SdrObjGeoData> SdrObject::NewGeoData() const 1903 { 1904 return std::make_unique<SdrObjGeoData>(); 1905 } 1906 1907 void SdrObject::SaveGeoData(SdrObjGeoData& rGeo) const 1908 { 1909 rGeo.aBoundRect =GetCurrentBoundRect(); 1910 rGeo.aAnchor =m_aAnchor ; 1911 rGeo.bMovProt =m_bMovProt ; 1912 rGeo.bSizProt =m_bSizProt ; 1913 rGeo.bNoPrint =m_bNoPrint ; 1914 rGeo.mbVisible =mbVisible ; 1915 rGeo.bClosedObj =m_bClosedObj ; 1916 rGeo.mnLayerID = mnLayerID; 1917 1918 // user-defined glue points 1919 if (m_pPlusData!=nullptr && m_pPlusData->pGluePoints!=nullptr) { 1920 if (rGeo.pGPL!=nullptr) { 1921 *rGeo.pGPL=*m_pPlusData->pGluePoints; 1922 } else { 1923 rGeo.pGPL.reset( new SdrGluePointList(*m_pPlusData->pGluePoints) ); 1924 } 1925 } else { 1926 rGeo.pGPL.reset(); 1927 } 1928 } 1929 1930 void SdrObject::RestoreGeoData(const SdrObjGeoData& rGeo) 1931 { 1932 SetBoundAndSnapRectsDirty(); 1933 m_aOutRect =rGeo.aBoundRect ; 1934 m_aAnchor =rGeo.aAnchor ; 1935 m_bMovProt =rGeo.bMovProt ; 1936 m_bSizProt =rGeo.bSizProt ; 1937 m_bNoPrint =rGeo.bNoPrint ; 1938 mbVisible =rGeo.mbVisible ; 1939 m_bClosedObj =rGeo.bClosedObj ; 1940 mnLayerID = rGeo.mnLayerID; 1941 1942 // user-defined glue points 1943 if (rGeo.pGPL!=nullptr) { 1944 ImpForcePlusData(); 1945 if (m_pPlusData->pGluePoints!=nullptr) { 1946 *m_pPlusData->pGluePoints=*rGeo.pGPL; 1947 } else { 1948 m_pPlusData->pGluePoints.reset(new SdrGluePointList(*rGeo.pGPL)); 1949 } 1950 } else { 1951 if (m_pPlusData!=nullptr && m_pPlusData->pGluePoints!=nullptr) { 1952 m_pPlusData->pGluePoints.reset(); 1953 } 1954 } 1955 } 1956 1957 std::unique_ptr<SdrObjGeoData> SdrObject::GetGeoData() const 1958 { 1959 std::unique_ptr<SdrObjGeoData> pGeo = NewGeoData(); 1960 SaveGeoData(*pGeo); 1961 return pGeo; 1962 } 1963 1964 void SdrObject::SetGeoData(const SdrObjGeoData& rGeo) 1965 { 1966 tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect(); 1967 RestoreGeoData(rGeo); 1968 SetChanged(); 1969 BroadcastObjectChange(); 1970 SendUserCall(SdrUserCallType::Resize,aBoundRect0); 1971 } 1972 1973 1974 // ItemSet access 1975 1976 const SfxItemSet& SdrObject::GetObjectItemSet() const 1977 { 1978 return GetProperties().GetObjectItemSet(); 1979 } 1980 1981 const SfxItemSet& SdrObject::GetMergedItemSet() const 1982 { 1983 return GetProperties().GetMergedItemSet(); 1984 } 1985 1986 void SdrObject::SetObjectItem(const SfxPoolItem& rItem) 1987 { 1988 GetProperties().SetObjectItem(rItem); 1989 } 1990 1991 void SdrObject::SetMergedItem(const SfxPoolItem& rItem) 1992 { 1993 GetProperties().SetMergedItem(rItem); 1994 } 1995 1996 void SdrObject::ClearMergedItem(const sal_uInt16 nWhich) 1997 { 1998 GetProperties().ClearMergedItem(nWhich); 1999 } 2000 2001 void SdrObject::SetObjectItemSet(const SfxItemSet& rSet) 2002 { 2003 GetProperties().SetObjectItemSet(rSet); 2004 } 2005 2006 void SdrObject::SetMergedItemSet(const SfxItemSet& rSet, bool bClearAllItems) 2007 { 2008 GetProperties().SetMergedItemSet(rSet, bClearAllItems); 2009 } 2010 2011 const SfxPoolItem& SdrObject::GetObjectItem(const sal_uInt16 nWhich) const 2012 { 2013 return GetObjectItemSet().Get(nWhich); 2014 } 2015 2016 const SfxPoolItem& SdrObject::GetMergedItem(const sal_uInt16 nWhich) const 2017 { 2018 return GetMergedItemSet().Get(nWhich); 2019 } 2020 2021 void SdrObject::SetMergedItemSetAndBroadcast(const SfxItemSet& rSet, bool bClearAllItems) 2022 { 2023 GetProperties().SetMergedItemSetAndBroadcast(rSet, bClearAllItems); 2024 } 2025 2026 void SdrObject::ApplyNotPersistAttr(const SfxItemSet& rAttr) 2027 { 2028 tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetLastBoundRect(); 2029 NbcApplyNotPersistAttr(rAttr); 2030 SetChanged(); 2031 BroadcastObjectChange(); 2032 SendUserCall(SdrUserCallType::Resize,aBoundRect0); 2033 } 2034 2035 void SdrObject::NbcApplyNotPersistAttr(const SfxItemSet& rAttr) 2036 { 2037 const tools::Rectangle& rSnap=GetSnapRect(); 2038 const tools::Rectangle& rLogic=GetLogicRect(); 2039 Point aRef1(rSnap.Center()); 2040 const SfxPoolItem *pPoolItem=nullptr; 2041 if (rAttr.GetItemState(SDRATTR_TRANSFORMREF1X,true,&pPoolItem)==SfxItemState::SET) { 2042 aRef1.setX(static_cast<const SdrTransformRef1XItem*>(pPoolItem)->GetValue() ); 2043 } 2044 if (rAttr.GetItemState(SDRATTR_TRANSFORMREF1Y,true,&pPoolItem)==SfxItemState::SET) { 2045 aRef1.setY(static_cast<const SdrTransformRef1YItem*>(pPoolItem)->GetValue() ); 2046 } 2047 2048 tools::Rectangle aNewSnap(rSnap); 2049 if (rAttr.GetItemState(SDRATTR_MOVEX,true,&pPoolItem)==SfxItemState::SET) { 2050 tools::Long n=static_cast<const SdrMoveXItem*>(pPoolItem)->GetValue(); 2051 aNewSnap.Move(n,0); 2052 } 2053 if (rAttr.GetItemState(SDRATTR_MOVEY,true,&pPoolItem)==SfxItemState::SET) { 2054 tools::Long n=static_cast<const SdrMoveYItem*>(pPoolItem)->GetValue(); 2055 aNewSnap.Move(0,n); 2056 } 2057 if (rAttr.GetItemState(SDRATTR_ONEPOSITIONX,true,&pPoolItem)==SfxItemState::SET) { 2058 tools::Long n=static_cast<const SdrOnePositionXItem*>(pPoolItem)->GetValue(); 2059 aNewSnap.Move(n-aNewSnap.Left(),0); 2060 } 2061 if (rAttr.GetItemState(SDRATTR_ONEPOSITIONY,true,&pPoolItem)==SfxItemState::SET) { 2062 tools::Long n=static_cast<const SdrOnePositionYItem*>(pPoolItem)->GetValue(); 2063 aNewSnap.Move(0,n-aNewSnap.Top()); 2064 } 2065 if (rAttr.GetItemState(SDRATTR_ONESIZEWIDTH,true,&pPoolItem)==SfxItemState::SET) { 2066 tools::Long n=static_cast<const SdrOneSizeWidthItem*>(pPoolItem)->GetValue(); 2067 aNewSnap.SetRight(aNewSnap.Left()+n ); 2068 } 2069 if (rAttr.GetItemState(SDRATTR_ONESIZEHEIGHT,true,&pPoolItem)==SfxItemState::SET) { 2070 tools::Long n=static_cast<const SdrOneSizeHeightItem*>(pPoolItem)->GetValue(); 2071 aNewSnap.SetBottom(aNewSnap.Top()+n ); 2072 } 2073 if (aNewSnap!=rSnap) { 2074 if (aNewSnap.GetSize()==rSnap.GetSize()) { 2075 NbcMove(Size(aNewSnap.Left()-rSnap.Left(),aNewSnap.Top()-rSnap.Top())); 2076 } else { 2077 NbcSetSnapRect(aNewSnap); 2078 } 2079 } 2080 2081 if (rAttr.GetItemState(SDRATTR_SHEARANGLE,true,&pPoolItem)==SfxItemState::SET) { 2082 Degree100 n=static_cast<const SdrShearAngleItem*>(pPoolItem)->GetValue(); 2083 n-=GetShearAngle(); 2084 if (n) { 2085 double nTan = tan(n.get() * F_PI18000); 2086 NbcShear(aRef1,n,nTan,false); 2087 } 2088 } 2089 if (rAttr.GetItemState(SDRATTR_ROTATEANGLE,true,&pPoolItem)==SfxItemState::SET) { 2090 Degree100 n=static_cast<const SdrAngleItem*>(pPoolItem)->GetValue(); 2091 n-=GetRotateAngle(); 2092 if (n) { 2093 NbcRotate(aRef1,n); 2094 } 2095 } 2096 if (rAttr.GetItemState(SDRATTR_ROTATEONE,true,&pPoolItem)==SfxItemState::SET) { 2097 Degree100 n=static_cast<const SdrRotateOneItem*>(pPoolItem)->GetValue(); 2098 NbcRotate(aRef1,n); 2099 } 2100 if (rAttr.GetItemState(SDRATTR_HORZSHEARONE,true,&pPoolItem)==SfxItemState::SET) { 2101 Degree100 n=static_cast<const SdrHorzShearOneItem*>(pPoolItem)->GetValue(); 2102 double nTan = tan(n.get() * F_PI18000); 2103 NbcShear(aRef1,n,nTan,false); 2104 } 2105 if (rAttr.GetItemState(SDRATTR_VERTSHEARONE,true,&pPoolItem)==SfxItemState::SET) { 2106 Degree100 n=static_cast<const SdrVertShearOneItem*>(pPoolItem)->GetValue(); 2107 double nTan = tan(n.get() * F_PI18000); 2108 NbcShear(aRef1,n,nTan,true); 2109 } 2110 2111 if (rAttr.GetItemState(SDRATTR_OBJMOVEPROTECT,true,&pPoolItem)==SfxItemState::SET) { 2112 bool b=static_cast<const SdrYesNoItem*>(pPoolItem)->GetValue(); 2113 SetMoveProtect(b); 2114 } 2115 if (rAttr.GetItemState(SDRATTR_OBJSIZEPROTECT,true,&pPoolItem)==SfxItemState::SET) { 2116 bool b=static_cast<const SdrYesNoItem*>(pPoolItem)->GetValue(); 2117 SetResizeProtect(b); 2118 } 2119 2120 /* move protect always sets size protect */ 2121 if( IsMoveProtect() ) 2122 SetResizeProtect( true ); 2123 2124 if (rAttr.GetItemState(SDRATTR_OBJPRINTABLE,true,&pPoolItem)==SfxItemState::SET) { 2125 bool b=static_cast<const SdrObjPrintableItem*>(pPoolItem)->GetValue(); 2126 SetPrintable(b); 2127 } 2128 2129 if (rAttr.GetItemState(SDRATTR_OBJVISIBLE,true,&pPoolItem)==SfxItemState::SET) { 2130 bool b=static_cast<const SdrObjVisibleItem*>(pPoolItem)->GetValue(); 2131 SetVisible(b); 2132 } 2133 2134 SdrLayerID nLayer=SDRLAYER_NOTFOUND; 2135 if (rAttr.GetItemState(SDRATTR_LAYERID,true,&pPoolItem)==SfxItemState::SET) { 2136 nLayer=static_cast<const SdrLayerIdItem*>(pPoolItem)->GetValue(); 2137 } 2138 if (rAttr.GetItemState(SDRATTR_LAYERNAME,true,&pPoolItem)==SfxItemState::SET) 2139 { 2140 OUString aLayerName = static_cast<const SdrLayerNameItem*>(pPoolItem)->GetValue(); 2141 const SdrLayerAdmin& rLayAd(nullptr != getSdrPageFromSdrObject() 2142 ? getSdrPageFromSdrObject()->GetLayerAdmin() 2143 : getSdrModelFromSdrObject().GetLayerAdmin()); 2144 const SdrLayer* pLayer = rLayAd.GetLayer(aLayerName); 2145 2146 if(nullptr != pLayer) 2147 { 2148 nLayer=pLayer->GetID(); 2149 } 2150 } 2151 if (nLayer!=SDRLAYER_NOTFOUND) { 2152 NbcSetLayer(nLayer); 2153 } 2154 2155 if (rAttr.GetItemState(SDRATTR_OBJECTNAME,true,&pPoolItem)==SfxItemState::SET) { 2156 OUString aName=static_cast<const SfxStringItem*>(pPoolItem)->GetValue(); 2157 SetName(aName); 2158 } 2159 tools::Rectangle aNewLogic(rLogic); 2160 if (rAttr.GetItemState(SDRATTR_LOGICSIZEWIDTH,true,&pPoolItem)==SfxItemState::SET) { 2161 tools::Long n=static_cast<const SdrLogicSizeWidthItem*>(pPoolItem)->GetValue(); 2162 aNewLogic.SetRight(aNewLogic.Left()+n ); 2163 } 2164 if (rAttr.GetItemState(SDRATTR_LOGICSIZEHEIGHT,true,&pPoolItem)==SfxItemState::SET) { 2165 tools::Long n=static_cast<const SdrLogicSizeHeightItem*>(pPoolItem)->GetValue(); 2166 aNewLogic.SetBottom(aNewLogic.Top()+n ); 2167 } 2168 if (aNewLogic!=rLogic) { 2169 NbcSetLogicRect(aNewLogic); 2170 } 2171 Fraction aResizeX(1,1); 2172 Fraction aResizeY(1,1); 2173 if (rAttr.GetItemState(SDRATTR_RESIZEXONE,true,&pPoolItem)==SfxItemState::SET) { 2174 aResizeX*=static_cast<const SdrResizeXOneItem*>(pPoolItem)->GetValue(); 2175 } 2176 if (rAttr.GetItemState(SDRATTR_RESIZEYONE,true,&pPoolItem)==SfxItemState::SET) { 2177 aResizeY*=static_cast<const SdrResizeYOneItem*>(pPoolItem)->GetValue(); 2178 } 2179 if (aResizeX!=Fraction(1,1) || aResizeY!=Fraction(1,1)) { 2180 NbcResize(aRef1,aResizeX,aResizeY); 2181 } 2182 } 2183 2184 void SdrObject::TakeNotPersistAttr(SfxItemSet& rAttr) const 2185 { 2186 const tools::Rectangle& rSnap=GetSnapRect(); 2187 const tools::Rectangle& rLogic=GetLogicRect(); 2188 rAttr.Put(SdrYesNoItem(SDRATTR_OBJMOVEPROTECT, IsMoveProtect())); 2189 rAttr.Put(SdrYesNoItem(SDRATTR_OBJSIZEPROTECT, IsResizeProtect())); 2190 rAttr.Put(SdrObjPrintableItem(IsPrintable())); 2191 rAttr.Put(SdrObjVisibleItem(IsVisible())); 2192 rAttr.Put(SdrAngleItem(SDRATTR_ROTATEANGLE, GetRotateAngle())); 2193 rAttr.Put(SdrShearAngleItem(GetShearAngle())); 2194 rAttr.Put(SdrOneSizeWidthItem(rSnap.GetWidth()-1)); 2195 rAttr.Put(SdrOneSizeHeightItem(rSnap.GetHeight()-1)); 2196 rAttr.Put(SdrOnePositionXItem(rSnap.Left())); 2197 rAttr.Put(SdrOnePositionYItem(rSnap.Top())); 2198 if (rLogic.GetWidth()!=rSnap.GetWidth()) { 2199 rAttr.Put(SdrLogicSizeWidthItem(rLogic.GetWidth()-1)); 2200 } 2201 if (rLogic.GetHeight()!=rSnap.GetHeight()) { 2202 rAttr.Put(SdrLogicSizeHeightItem(rLogic.GetHeight()-1)); 2203 } 2204 OUString aName(GetName()); 2205 2206 if (!aName.isEmpty()) 2207 { 2208 rAttr.Put(SfxStringItem(SDRATTR_OBJECTNAME, aName)); 2209 } 2210 2211 rAttr.Put(SdrLayerIdItem(GetLayer())); 2212 const SdrLayerAdmin& rLayAd(nullptr != getSdrPageFromSdrObject() 2213 ? getSdrPageFromSdrObject()->GetLayerAdmin() 2214 : getSdrModelFromSdrObject().GetLayerAdmin()); 2215 const SdrLayer* pLayer = rLayAd.GetLayerPerID(GetLayer()); 2216 if(nullptr != pLayer) 2217 { 2218 rAttr.Put(SdrLayerNameItem(pLayer->GetName())); 2219 } 2220 Point aRef1(rSnap.Center()); 2221 Point aRef2(aRef1); aRef2.AdjustY( 1 ); 2222 rAttr.Put(SdrTransformRef1XItem(aRef1.X())); 2223 rAttr.Put(SdrTransformRef1YItem(aRef1.Y())); 2224 rAttr.Put(SdrTransformRef2XItem(aRef2.X())); 2225 rAttr.Put(SdrTransformRef2YItem(aRef2.Y())); 2226 } 2227 2228 SfxStyleSheet* SdrObject::GetStyleSheet() const 2229 { 2230 return GetProperties().GetStyleSheet(); 2231 } 2232 2233 void SdrObject::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr) 2234 { 2235 tools::Rectangle aBoundRect0; 2236 2237 if(m_pUserCall) 2238 aBoundRect0 = GetLastBoundRect(); 2239 2240 NbcSetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr); 2241 SetChanged(); 2242 BroadcastObjectChange(); 2243 SendUserCall(SdrUserCallType::ChangeAttr, aBoundRect0); 2244 } 2245 2246 void SdrObject::NbcSetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr) 2247 { 2248 GetProperties().SetStyleSheet(pNewStyleSheet, bDontRemoveHardAttr); 2249 } 2250 2251 // Broadcasting while setting attributes is managed by the AttrObj. 2252 2253 2254 SdrGluePoint SdrObject::GetVertexGluePoint(sal_uInt16 nPosNum) const 2255 { 2256 // #i41936# Use SnapRect for default GluePoints 2257 const tools::Rectangle aR(GetSnapRect()); 2258 Point aPt; 2259 2260 switch(nPosNum) 2261 { 2262 case 0 : aPt = aR.TopCenter(); break; 2263 case 1 : aPt = aR.RightCenter(); break; 2264 case 2 : aPt = aR.BottomCenter(); break; 2265 case 3 : aPt = aR.LeftCenter(); break; 2266 } 2267 2268 aPt -= aR.Center(); 2269 SdrGluePoint aGP(aPt); 2270 aGP.SetPercent(false); 2271 2272 return aGP; 2273 } 2274 2275 SdrGluePoint SdrObject::GetCornerGluePoint(sal_uInt16 nPosNum) const 2276 { 2277 tools::Rectangle aR(GetCurrentBoundRect()); 2278 Point aPt; 2279 switch (nPosNum) { 2280 case 0 : aPt=aR.TopLeft(); break; 2281 case 1 : aPt=aR.TopRight(); break; 2282 case 2 : aPt=aR.BottomRight(); break; 2283 case 3 : aPt=aR.BottomLeft(); break; 2284 } 2285 aPt-=GetSnapRect().Center(); 2286 SdrGluePoint aGP(aPt); 2287 aGP.SetPercent(false); 2288 return aGP; 2289 } 2290 2291 const SdrGluePointList* SdrObject::GetGluePointList() const 2292 { 2293 if (m_pPlusData!=nullptr) return m_pPlusData->pGluePoints.get(); 2294 return nullptr; 2295 } 2296 2297 2298 SdrGluePointList* SdrObject::ForceGluePointList() 2299 { 2300 ImpForcePlusData(); 2301 if (m_pPlusData->pGluePoints==nullptr) { 2302 m_pPlusData->pGluePoints.reset(new SdrGluePointList); 2303 } 2304 return m_pPlusData->pGluePoints.get(); 2305 } 2306 2307 void SdrObject::SetGlueReallyAbsolute(bool bOn) 2308 { 2309 // First a const call to see whether there are any glue points. 2310 // Force const call! 2311 if (GetGluePointList()!=nullptr) { 2312 SdrGluePointList* pGPL=ForceGluePointList(); 2313 pGPL->SetReallyAbsolute(bOn,*this); 2314 } 2315 } 2316 2317 void SdrObject::NbcRotateGluePoints(const Point& rRef, Degree100 nAngle, double sn, double cs) 2318 { 2319 // First a const call to see whether there are any glue points. 2320 // Force const call! 2321 if (GetGluePointList()!=nullptr) { 2322 SdrGluePointList* pGPL=ForceGluePointList(); 2323 pGPL->Rotate(rRef,nAngle,sn,cs,this); 2324 } 2325 } 2326 2327 void SdrObject::NbcMirrorGluePoints(const Point& rRef1, const Point& rRef2) 2328 { 2329 // First a const call to see whether there are any glue points. 2330 // Force const call! 2331 if (GetGluePointList()!=nullptr) { 2332 SdrGluePointList* pGPL=ForceGluePointList(); 2333 pGPL->Mirror(rRef1,rRef2,this); 2334 } 2335 } 2336 2337 void SdrObject::NbcShearGluePoints(const Point& rRef, double tn, bool bVShear) 2338 { 2339 // First a const call to see whether there are any glue points. 2340 // Force const call! 2341 if (GetGluePointList()!=nullptr) { 2342 SdrGluePointList* pGPL=ForceGluePointList(); 2343 pGPL->Shear(rRef,tn,bVShear,this); 2344 } 2345 } 2346 2347 void SdrObject::ConnectToNode(bool /*bTail1*/, SdrObject* /*pObj*/) 2348 { 2349 } 2350 2351 void SdrObject::DisconnectFromNode(bool /*bTail1*/) 2352 { 2353 } 2354 2355 SdrObject* SdrObject::GetConnectedNode(bool /*bTail1*/) const 2356 { 2357 return nullptr; 2358 } 2359 2360 2361 static void extractLineContourFromPrimitive2DSequence( 2362 const drawinglayer::primitive2d::Primitive2DContainer& rxSequence, 2363 basegfx::B2DPolygonVector& rExtractedHairlines, 2364 basegfx::B2DPolyPolygonVector& rExtractedLineFills) 2365 { 2366 rExtractedHairlines.clear(); 2367 rExtractedLineFills.clear(); 2368 2369 if(rxSequence.empty()) 2370 return; 2371 2372 // use neutral ViewInformation 2373 const drawinglayer::geometry::ViewInformation2D aViewInformation2D; 2374 2375 // create extractor, process and get result 2376 drawinglayer::processor2d::LineGeometryExtractor2D aExtractor(aViewInformation2D); 2377 aExtractor.process(rxSequence); 2378 2379 // copy line results 2380 rExtractedHairlines = aExtractor.getExtractedHairlines(); 2381 2382 // copy fill rsults 2383 rExtractedLineFills = aExtractor.getExtractedLineFills(); 2384 } 2385 2386 2387 SdrObject* SdrObject::ImpConvertToContourObj(bool bForceLineDash) 2388 { 2389 SdrObject* pRetval(nullptr); 2390 2391 if(LineGeometryUsageIsNecessary()) 2392 { 2393 basegfx::B2DPolyPolygon aMergedLineFillPolyPolygon; 2394 basegfx::B2DPolyPolygon aMergedHairlinePolyPolygon; 2395 const drawinglayer::primitive2d::Primitive2DContainer & xSequence(GetViewContact().getViewIndependentPrimitive2DContainer()); 2396 2397 if(!xSequence.empty()) 2398 { 2399 basegfx::B2DPolygonVector aExtractedHairlines; 2400 basegfx::B2DPolyPolygonVector aExtractedLineFills; 2401 2402 extractLineContourFromPrimitive2DSequence(xSequence, aExtractedHairlines, aExtractedLineFills); 2403 2404 // for SdrObject creation, just copy all to a single Hairline-PolyPolygon 2405 for(const basegfx::B2DPolygon & rExtractedHairline : aExtractedHairlines) 2406 { 2407 aMergedHairlinePolyPolygon.append(rExtractedHairline); 2408 } 2409 2410 // check for fill rsults 2411 if (!aExtractedLineFills.empty() && !utl::ConfigManager::IsFuzzing()) 2412 { 2413 // merge to a single tools::PolyPolygon (OR) 2414 aMergedLineFillPolyPolygon = basegfx::utils::mergeToSinglePolyPolygon(aExtractedLineFills); 2415 } 2416 } 2417 2418 if(aMergedLineFillPolyPolygon.count() || (bForceLineDash && aMergedHairlinePolyPolygon.count())) 2419 { 2420 SfxItemSet aSet(GetMergedItemSet()); 2421 drawing::FillStyle eOldFillStyle = aSet.Get(XATTR_FILLSTYLE).GetValue(); 2422 SdrPathObj* aLinePolygonPart = nullptr; 2423 SdrPathObj* aLineHairlinePart = nullptr; 2424 bool bBuildGroup(false); 2425 2426 if(aMergedLineFillPolyPolygon.count()) 2427 { 2428 // create SdrObject for filled line geometry 2429 aLinePolygonPart = new SdrPathObj( 2430 getSdrModelFromSdrObject(), 2431 OBJ_PATHFILL, 2432 aMergedLineFillPolyPolygon); 2433 2434 // correct item properties 2435 aSet.Put(XLineWidthItem(0)); 2436 aSet.Put(XLineStyleItem(drawing::LineStyle_NONE)); 2437 Color aColorLine = aSet.Get(XATTR_LINECOLOR).GetColorValue(); 2438 sal_uInt16 nTransLine = aSet.Get(XATTR_LINETRANSPARENCE).GetValue(); 2439 aSet.Put(XFillColorItem(OUString(), aColorLine)); 2440 aSet.Put(XFillStyleItem(drawing::FillStyle_SOLID)); 2441 aSet.Put(XFillTransparenceItem(nTransLine)); 2442 2443 aLinePolygonPart->SetMergedItemSet(aSet); 2444 } 2445 2446 if(aMergedHairlinePolyPolygon.count()) 2447 { 2448 // create SdrObject for hairline geometry 2449 // OBJ_PATHLINE is necessary here, not OBJ_PATHFILL. This is intended 2450 // to get a non-filled object. If the poly is closed, the PathObj takes care for 2451 // the correct closed state. 2452 aLineHairlinePart = new SdrPathObj( 2453 getSdrModelFromSdrObject(), 2454 OBJ_PATHLINE, 2455 aMergedHairlinePolyPolygon); 2456 2457 aSet.Put(XLineWidthItem(0)); 2458 aSet.Put(XFillStyleItem(drawing::FillStyle_NONE)); 2459 aSet.Put(XLineStyleItem(drawing::LineStyle_SOLID)); 2460 2461 // it is also necessary to switch off line start and ends here 2462 aSet.Put(XLineStartWidthItem(0)); 2463 aSet.Put(XLineEndWidthItem(0)); 2464 2465 aLineHairlinePart->SetMergedItemSet(aSet); 2466 2467 if(aLinePolygonPart) 2468 { 2469 bBuildGroup = true; 2470 } 2471 } 2472 2473 // check if original geometry should be added (e.g. filled and closed) 2474 bool bAddOriginalGeometry(false); 2475 SdrPathObj* pPath = dynamic_cast<SdrPathObj*>(this); 2476 2477 if(pPath && pPath->IsClosed()) 2478 { 2479 if(eOldFillStyle != drawing::FillStyle_NONE) 2480 { 2481 bAddOriginalGeometry = true; 2482 } 2483 } 2484 2485 // do we need a group? 2486 if(bBuildGroup || bAddOriginalGeometry) 2487 { 2488 SdrObject* pGroup = new SdrObjGroup(getSdrModelFromSdrObject()); 2489 2490 if(bAddOriginalGeometry) 2491 { 2492 // Add a clone of the original geometry. 2493 aSet.ClearItem(); 2494 aSet.Put(GetMergedItemSet()); 2495 aSet.Put(XLineStyleItem(drawing::LineStyle_NONE)); 2496 aSet.Put(XLineWidthItem(0)); 2497 2498 SdrObject* pClone(CloneSdrObject(getSdrModelFromSdrObject())); 2499 pClone->SetMergedItemSet(aSet); 2500 2501 pGroup->GetSubList()->NbcInsertObject(pClone); 2502 } 2503 2504 if(aLinePolygonPart) 2505 { 2506 pGroup->GetSubList()->NbcInsertObject(aLinePolygonPart); 2507 } 2508 2509 if(aLineHairlinePart) 2510 { 2511 pGroup->GetSubList()->NbcInsertObject(aLineHairlinePart); 2512 } 2513 2514 pRetval = pGroup; 2515 } 2516 else 2517 { 2518 if(aLinePolygonPart) 2519 { 2520 pRetval = aLinePolygonPart; 2521 } 2522 else if(aLineHairlinePart) 2523 { 2524 pRetval = aLineHairlinePart; 2525 } 2526 } 2527 } 2528 } 2529 2530 if(nullptr == pRetval) 2531 { 2532 // due to current method usage, create and return a clone when nothing has changed 2533 SdrObject* pClone(CloneSdrObject(getSdrModelFromSdrObject())); 2534 pRetval = pClone; 2535 } 2536 2537 return pRetval; 2538 } 2539 2540 2541 void SdrObject::SetMarkProtect(bool bProt) 2542 { 2543 m_bMarkProt = bProt; 2544 } 2545 2546 2547 void SdrObject::SetEmptyPresObj(bool bEpt) 2548 { 2549 m_bEmptyPresObj = bEpt; 2550 } 2551 2552 2553 void SdrObject::SetNotVisibleAsMaster(bool bFlg) 2554 { 2555 m_bNotVisibleAsMaster=bFlg; 2556 } 2557 2558 2559 // convert this path object to contour object, even when it is a group 2560 SdrObject* SdrObject::ConvertToContourObj(SdrObject* pRet, bool bForceLineDash) const 2561 { 2562 if(dynamic_cast<const SdrObjGroup*>( pRet) != nullptr) 2563 { 2564 SdrObjList* pObjList2 = pRet->GetSubList(); 2565 SdrObject* pGroup = new SdrObjGroup(getSdrModelFromSdrObject()); 2566 2567 for(size_t a=0; a<pObjList2->GetObjCount(); ++a) 2568 { 2569 SdrObject* pIterObj = pObjList2->GetObj(a); 2570 pGroup->GetSubList()->NbcInsertObject(ConvertToContourObj(pIterObj, bForceLineDash)); 2571 } 2572 2573 pRet = pGroup; 2574 } 2575 else 2576 { 2577 if (SdrPathObj *pPathObj = dynamic_cast<SdrPathObj*>(pRet)) 2578 { 2579 // bezier geometry got created, even for straight edges since the given 2580 // object is a result of DoConvertToPolyObj. For conversion to contour 2581 // this is not really needed and can be reduced again AFAP 2582 pPathObj->SetPathPoly(basegfx::utils::simplifyCurveSegments(pPathObj->GetPathPoly())); 2583 } 2584 2585 pRet = pRet->ImpConvertToContourObj(bForceLineDash); 2586 } 2587 2588 // #i73441# preserve LayerID 2589 if(pRet && pRet->GetLayer() != GetLayer()) 2590 { 2591 pRet->SetLayer(GetLayer()); 2592 } 2593 2594 return pRet; 2595 } 2596 2597 2598 SdrObjectUniquePtr SdrObject::ConvertToPolyObj(bool bBezier, bool bLineToArea) const 2599 { 2600 SdrObjectUniquePtr pRet = DoConvertToPolyObj(bBezier, true); 2601 2602 if(pRet && bLineToArea) 2603 { 2604 SdrObject* pNewRet = ConvertToContourObj(pRet.get()); 2605 pRet.reset(pNewRet); 2606 } 2607 2608 // #i73441# preserve LayerID 2609 if(pRet && pRet->GetLayer() != GetLayer()) 2610 { 2611 pRet->SetLayer(GetLayer()); 2612 } 2613 2614 return pRet; 2615 } 2616 2617 2618 SdrObjectUniquePtr SdrObject::DoConvertToPolyObj(bool /*bBezier*/, bool /*bAddText*/) const 2619 { 2620 return nullptr; 2621 } 2622 2623 2624 void SdrObject::InsertedStateChange() 2625 { 2626 const bool bIsInserted(nullptr != getParentSdrObjListFromSdrObject()); 2627 const tools::Rectangle aBoundRect0(GetLastBoundRect()); 2628 2629 if(bIsInserted) 2630 { 2631 SendUserCall(SdrUserCallType::Inserted, aBoundRect0); 2632 } 2633 else 2634 { 2635 SendUserCall(SdrUserCallType::Removed, aBoundRect0); 2636 } 2637 2638 if(nullptr != m_pPlusData && nullptr != m_pPlusData->pBroadcast) 2639 { 2640 SdrHint aHint(bIsInserted ? SdrHintKind::ObjectInserted : SdrHintKind::ObjectRemoved, *this); 2641 m_pPlusData->pBroadcast->Broadcast(aHint); 2642 } 2643 } 2644 2645 void SdrObject::SetMoveProtect(bool bProt) 2646 { 2647 if(IsMoveProtect() != bProt) 2648 { 2649 // #i77187# secured and simplified 2650 m_bMovProt = bProt; 2651 SetChanged(); 2652 BroadcastObjectChange(); 2653 } 2654 } 2655 2656 void SdrObject::SetResizeProtect(bool bProt) 2657 { 2658 if(IsResizeProtect() != bProt) 2659 { 2660 // #i77187# secured and simplified 2661 m_bSizProt = bProt; 2662 SetChanged(); 2663 BroadcastObjectChange(); 2664 } 2665 } 2666 2667 void SdrObject::SetPrintable(bool bPrn) 2668 { 2669 if( bPrn == m_bNoPrint ) 2670 { 2671 m_bNoPrint=!bPrn; 2672 SetChanged(); 2673 if (IsInserted()) 2674 { 2675 SdrHint aHint(SdrHintKind::ObjectChange, *this); 2676 getSdrModelFromSdrObject().Broadcast(aHint); 2677 } 2678 } 2679 } 2680 2681 void SdrObject::SetVisible(bool bVisible) 2682 { 2683 if( bVisible != mbVisible ) 2684 { 2685 mbVisible = bVisible; 2686 SetChanged(); 2687 if (IsInserted()) 2688 { 2689 SdrHint aHint(SdrHintKind::ObjectChange, *this); 2690 getSdrModelFromSdrObject().Broadcast(aHint); 2691 } 2692 } 2693 } 2694 2695 2696 sal_uInt16 SdrObject::GetUserDataCount() const 2697 { 2698 if (m_pPlusData==nullptr || m_pPlusData->pUserDataList==nullptr) return 0; 2699 return m_pPlusData->pUserDataList->GetUserDataCount(); 2700 } 2701 2702 SdrObjUserData* SdrObject::GetUserData(sal_uInt16 nNum) const 2703 { 2704 if (m_pPlusData==nullptr || m_pPlusData->pUserDataList==nullptr) return nullptr; 2705 return &m_pPlusData->pUserDataList->GetUserData(nNum); 2706 } 2707 2708 void SdrObject::AppendUserData(std::unique_ptr<SdrObjUserData> pData) 2709 { 2710 if (!pData) 2711 { 2712 OSL_FAIL("SdrObject::AppendUserData(): pData is NULL pointer."); 2713 return; 2714 } 2715 2716 ImpForcePlusData(); 2717 if (!m_pPlusData->pUserDataList) 2718 m_pPlusData->pUserDataList.reset( new SdrObjUserDataList ); 2719 2720 m_pPlusData->pUserDataList->AppendUserData(std::move(pData)); 2721 } 2722 2723 void SdrObject::DeleteUserData(sal_uInt16 nNum) 2724 { 2725 sal_uInt16 nCount=GetUserDataCount(); 2726 if (nNum<nCount) { 2727 m_pPlusData->pUserDataList->DeleteUserData(nNum); 2728 if (nCount==1) { 2729 m_pPlusData->pUserDataList.reset(); 2730 } 2731 } else { 2732 OSL_FAIL("SdrObject::DeleteUserData(): Invalid Index."); 2733 } 2734 } 2735 2736 void SdrObject::SetUserCall(SdrObjUserCall* pUser) 2737 { 2738 m_pUserCall = pUser; 2739 } 2740 2741 2742 void SdrObject::SendUserCall(SdrUserCallType eUserCall, const tools::Rectangle& rBoundRect) const 2743 { 2744 SdrObject* pGroup(getParentSdrObjectFromSdrObject()); 2745 2746 if ( m_pUserCall ) 2747 { 2748 m_pUserCall->Changed( *this, eUserCall, rBoundRect ); 2749 } 2750 2751 if(nullptr != pGroup && pGroup->GetUserCall()) 2752 { 2753 // broadcast to group 2754 SdrUserCallType eChildUserType = SdrUserCallType::ChildChangeAttr; 2755 2756 switch( eUserCall ) 2757 { 2758 case SdrUserCallType::MoveOnly: 2759 eChildUserType = SdrUserCallType::ChildMoveOnly; 2760 break; 2761 2762 case SdrUserCallType::Resize: 2763 eChildUserType = SdrUserCallType::ChildResize; 2764 break; 2765 2766 case SdrUserCallType::ChangeAttr: 2767 eChildUserType = SdrUserCallType::ChildChangeAttr; 2768 break; 2769 2770 case SdrUserCallType::Delete: 2771 eChildUserType = SdrUserCallType::ChildDelete; 2772 break; 2773 2774 case SdrUserCallType::Inserted: 2775 eChildUserType = SdrUserCallType::ChildInserted; 2776 break; 2777 2778 case SdrUserCallType::Removed: 2779 eChildUserType = SdrUserCallType::ChildRemoved; 2780 break; 2781 2782 default: break; 2783 } 2784 2785 pGroup->GetUserCall()->Changed( *this, eChildUserType, rBoundRect ); 2786 } 2787 2788 // notify our UNO shape listeners 2789 switch ( eUserCall ) 2790 { 2791 case SdrUserCallType::Resize: 2792 notifyShapePropertyChange( svx::ShapeProperty::Size ); 2793 [[fallthrough]]; // RESIZE might also imply a change of the position 2794 case SdrUserCallType::MoveOnly: 2795 notifyShapePropertyChange( svx::ShapeProperty::Position ); 2796 break; 2797 default: 2798 // not interested in 2799 break; 2800 } 2801 } 2802 2803 void SdrObject::impl_setUnoShape( const uno::Reference< uno::XInterface >& _rxUnoShape ) 2804 { 2805 const uno::Reference< uno::XInterface>& xOldUnoShape( maWeakUnoShape ); 2806 // the UNO shape would be gutted by the following code; return early 2807 if ( _rxUnoShape == xOldUnoShape ) 2808 { 2809 if ( !xOldUnoShape.is() ) 2810 { 2811 // make sure there is no stale impl. pointer if the UNO 2812 // shape was destroyed meanwhile (remember we only hold weak 2813 // reference to it!) 2814 mpSvxShape = nullptr; 2815 } 2816 return; 2817 } 2818 2819 bool bTransferOwnership( false ); 2820 if ( xOldUnoShape.is() ) 2821 { 2822 bTransferOwnership = mpSvxShape->HasSdrObjectOwnership(); 2823 // Remove yourself from the current UNO shape. Its destructor 2824 // will reset our UNO shape otherwise. 2825 mpSvxShape->InvalidateSdrObject(); 2826 } 2827 2828 maWeakUnoShape = _rxUnoShape; 2829 mpSvxShape = comphelper::getUnoTunnelImplementation<SvxShape>( _rxUnoShape ); 2830 2831 // I think this may never happen... But I am not sure enough .-) 2832 if ( bTransferOwnership ) 2833 { 2834 if (mpSvxShape) 2835 mpSvxShape->TakeSdrObjectOwnership(); 2836 SAL_WARN( "svx.uno", "a UNO shape took over an SdrObject previously owned by another UNO shape!"); 2837 } 2838 } 2839 2840 /** only for internal use! */ 2841 SvxShape* SdrObject::getSvxShape() 2842 { 2843 DBG_TESTSOLARMUTEX(); 2844 // retrieving the impl pointer and subsequently using it is not thread-safe, of course, so it needs to be 2845 // guarded by the SolarMutex 2846 2847 uno::Reference< uno::XInterface > xShape( maWeakUnoShape ); 2848 #if OSL_DEBUG_LEVEL > 0 2849 OSL_ENSURE( !( !xShape.is() && mpSvxShape ), 2850 "SdrObject::getSvxShape: still having IMPL-Pointer to dead object!" ); 2851 #endif 2852 //#113608#, make sure mpSvxShape is always synchronized with maWeakUnoShape 2853 if ( mpSvxShape && !xShape.is() ) 2854 mpSvxShape = nullptr; 2855 2856 return mpSvxShape; 2857 } 2858 2859 css::uno::Reference< css::uno::XInterface > SdrObject::getUnoShape() 2860 { 2861 // try weak reference first 2862 uno::Reference< uno::XInterface > xShape( getWeakUnoShape() ); 2863 if( xShape ) 2864 return xShape; 2865 2866 OSL_ENSURE( mpSvxShape == nullptr, "SdrObject::getUnoShape: XShape already dead, but still an IMPL pointer!" ); 2867 2868 // try to access SdrPage from this SdrObject. This will only exist if the SdrObject is 2869 // inserted in a SdrObjList (page/group/3dScene) 2870 SdrPage* pPageCandidate(getSdrPageFromSdrObject()); 2871 2872 // tdf#12152, tdf#120728 2873 // 2874 // With the paradigm change to only get a SdrPage for a SdrObject when the SdrObject 2875 // is *inserted*, the functionality for creating 1:1 associated UNO API implementation 2876 // SvxShapes was partially broken: The used ::CreateShape relies on the SvxPage being 2877 // derived and the CreateShape method overloaded, implementing additional SdrInventor 2878 // types as needed. 2879 // 2880 // The fallback to use SvxDrawPage::CreateShapeByTypeAndInventor is a trap: It's only 2881 // a static fallback that handles the SdrInventor types SdrInventor::E3d and 2882 // SdrInventor::Default. Due to that, e.g. the ReportDesigner broke in various conditions. 2883 // 2884 // That again has to do with the ReportDesigner being implemented using the UNO API 2885 // aspects of SdrObjects early during their construction, not just after these are 2886 // inserted to a SdrPage - but that is not illegal or wrong, the SdrObject exists already. 2887 // 2888 // As a current solution, use the (now always available) SdrModel and any of the 2889 // existing SdrPages. The only important thing is to get a SdrPage where ::CreateShape is 2890 // overloaded and implemented as needed. 2891 // 2892 // Note for the future: 2893 // In a more ideal world there would be only one factory method for creating SdrObjects (not 2894 // ::CreateShape and ::CreateShapeByTypeAndInventor). This also would not be placed at 2895 // SdrPage/SvxPage at all, but at the Model where it belongs - where else would you expect 2896 // objects for the current Model to be constructed? To have this at the Page only would make 2897 // sense if different shapes would need to be constructed for different Pages in the same Model 2898 // - this is never the case. 2899 // At that Model extended functionality for that factory (or overloads and implementations) 2900 // should be placed. But to be realistic, migrating the factories to Model now is too much 2901 // work - maybe over time when melting SdrObject/SvxObject one day... 2902 if(nullptr == pPageCandidate) 2903 { 2904 // If not inserted, alternatively access a SdrPage using the SdrModel. There is 2905 // no reason not to create and return a UNO API XShape when the SdrObject is not 2906 // inserted - it may be in construction. Main paradigm is that it exists. 2907 if(0 != getSdrModelFromSdrObject().GetPageCount()) 2908 { 2909 // Take 1st SdrPage. That may be e.g. a special page (in SD), but the 2910 // to-be-used method ::CreateShape will be correctly overloaded in 2911 // all cases 2912 pPageCandidate = getSdrModelFromSdrObject().GetPage(0); 2913 } 2914 } 2915 2916 if(nullptr != pPageCandidate) 2917 { 2918 uno::Reference< uno::XInterface > xPage(pPageCandidate->getUnoPage()); 2919 if( xPage.is() ) 2920 { 2921 SvxDrawPage* pDrawPage = comphelper::getUnoTunnelImplementation<SvxDrawPage>(xPage); 2922 if( pDrawPage ) 2923 { 2924 // create one 2925 xShape = pDrawPage->CreateShape( this ); 2926 impl_setUnoShape( xShape ); 2927 } 2928 } 2929 } 2930 else 2931 { 2932 // Fallback to static base functionality. CAUTION: This will only support 2933 // the most basic stuff like SdrInventor::E3d and SdrInventor::Default. All 2934 // the other SdrInventor enum entries are from overloads and are *not accessible* 2935 // using this fallback (!) - what a bad trap 2936 rtl::Reference<SvxShape> xNewShape = SvxDrawPage::CreateShapeByTypeAndInventor( GetObjIdentifier(), GetObjInventor(), this ); 2937 mpSvxShape = xNewShape.get(); 2938 maWeakUnoShape = xShape = static_cast< ::cppu::OWeakObject* >( mpSvxShape ); 2939 } 2940 2941 return xShape; 2942 } 2943 2944 void SdrObject::setUnoShape(const uno::Reference<uno::XInterface >& _rxUnoShape) 2945 { 2946 impl_setUnoShape( _rxUnoShape ); 2947 } 2948 2949 svx::PropertyChangeNotifier& SdrObject::getShapePropertyChangeNotifier() 2950 { 2951 DBG_TESTSOLARMUTEX(); 2952 2953 SvxShape* pSvxShape = getSvxShape(); 2954 ENSURE_OR_THROW( pSvxShape, "no SvxShape, yet!" ); 2955 return pSvxShape->getShapePropertyChangeNotifier(); 2956 } 2957 2958 void SdrObject::notifyShapePropertyChange( const svx::ShapeProperty _eProperty ) const 2959 { 2960 DBG_TESTSOLARMUTEX(); 2961 2962 SvxShape* pSvxShape = const_cast< SdrObject* >( this )->getSvxShape(); 2963 if ( pSvxShape ) 2964 return pSvxShape->getShapePropertyChangeNotifier().notifyPropertyChange( _eProperty ); 2965 } 2966 2967 2968 // transformation interface for StarOfficeAPI. This implements support for 2969 // homogeneous 3x3 matrices containing the transformation of the SdrObject. At the 2970 // moment it contains a shearX, rotation and translation, but for setting all linear 2971 // transforms like Scale, ShearX, ShearY, Rotate and Translate are supported. 2972 2973 2974 // gets base transformation and rectangle of object. If it's an SdrPathObj it fills the PolyPolygon 2975 // with the base geometry and returns TRUE. Otherwise it returns FALSE. 2976 bool SdrObject::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& /*rPolyPolygon*/) const 2977 { 2978 // any kind of SdrObject, just use SnapRect 2979 tools::Rectangle aRectangle(GetSnapRect()); 2980 2981 // convert to transformation values 2982 basegfx::B2DTuple aScale(aRectangle.GetWidth(), aRectangle.GetHeight()); 2983 basegfx::B2DTuple aTranslate(aRectangle.Left(), aRectangle.Top()); 2984 2985 // position maybe relative to anchorpos, convert 2986 if(getSdrModelFromSdrObject().IsWriter()) 2987 { 2988 if(GetAnchorPos().X() || GetAnchorPos().Y()) 2989 { 2990 aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y()); 2991 } 2992 } 2993 2994 // build matrix 2995 rMatrix = basegfx::utils::createScaleTranslateB2DHomMatrix(aScale, aTranslate); 2996 2997 return false; 2998 } 2999 3000 // sets the base geometry of the object using infos contained in the homogeneous 3x3 matrix. 3001 // If it's an SdrPathObj it will use the provided geometry information. The Polygon has 3002 // to use (0,0) as upper left and will be scaled to the given size in the matrix. 3003 void SdrObject::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/) 3004 { 3005 // break up matrix 3006 basegfx::B2DTuple aScale; 3007 basegfx::B2DTuple aTranslate; 3008 double fRotate, fShearX; 3009 rMatrix.decompose(aScale, aTranslate, fRotate, fShearX); 3010 3011 // #i75086# Old DrawingLayer (GeoStat and geometry) does not support holding negative scalings 3012 // in X and Y which equal a 180 degree rotation. Recognize it and react accordingly 3013 if(basegfx::fTools::less(aScale.getX(), 0.0) && basegfx::fTools::less(aScale.getY(), 0.0)) 3014 { 3015 aScale.setX(fabs(aScale.getX())); 3016 aScale.setY(fabs(aScale.getY())); 3017 } 3018 3019 // if anchor is used, make position relative to it 3020 if(getSdrModelFromSdrObject().IsWriter()) 3021 { 3022 if(GetAnchorPos().X() || GetAnchorPos().Y()) 3023 { 3024 aTranslate += basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y()); 3025 } 3026 } 3027 3028 // build BaseRect 3029 Point aPoint(FRound(aTranslate.getX()), FRound(aTranslate.getY())); 3030 tools::Rectangle aBaseRect(aPoint, Size(FRound(aScale.getX()), FRound(aScale.getY()))); 3031 3032 // set BaseRect 3033 SetSnapRect(aBaseRect); 3034 } 3035 3036 // Give info if object is in destruction 3037 bool SdrObject::IsInDestruction() const 3038 { 3039 return getSdrModelFromSdrObject().IsInDestruction(); 3040 } 3041 3042 // return if fill is != drawing::FillStyle_NONE 3043 bool SdrObject::HasFillStyle() const 3044 { 3045 return GetObjectItem(XATTR_FILLSTYLE).GetValue() != drawing::FillStyle_NONE; 3046 } 3047 3048 bool SdrObject::HasLineStyle() const 3049 { 3050 return GetObjectItem(XATTR_LINESTYLE).GetValue() != drawing::LineStyle_NONE; 3051 } 3052 3053 3054 // #i52224# 3055 // on import of OLE object from MS documents the BLIP size might be retrieved, 3056 // the following four methods are used to control it; 3057 // usually this data makes no sense after the import is finished, since the object 3058 // might be resized 3059 3060 3061 void SdrObject::SetBLIPSizeRectangle( const tools::Rectangle& aRect ) 3062 { 3063 maBLIPSizeRectangle = aRect; 3064 } 3065 3066 void SdrObject::SetContextWritingMode( const sal_Int16 /*_nContextWritingMode*/ ) 3067 { 3068 // this base class does not support different writing modes, so ignore the call 3069 } 3070 3071 void SdrObject::SetDoNotInsertIntoPageAutomatically(const bool bSet) 3072 { 3073 mbDoNotInsertIntoPageAutomatically = bSet; 3074 } 3075 3076 3077 // #i121917# 3078 bool SdrObject::HasText() const 3079 { 3080 return false; 3081 } 3082 3083 bool SdrObject::IsTextBox() const 3084 { 3085 return false; 3086 } 3087 3088 void SdrObject::MakeNameUnique() 3089 { 3090 if (GetName().isEmpty()) 3091 { 3092 if (const E3dScene* pE3dObj = dynamic_cast<const E3dScene*>(this)) 3093 { 3094 SdrObjList* pObjList = pE3dObj->GetSubList(); 3095 if (pObjList) 3096 { 3097 SdrObject* pObj0 = pObjList->GetObj(0); 3098 if (pObj0) 3099 SetName(pObj0->TakeObjNameSingul()); 3100 } 3101 } 3102 else 3103 SetName(TakeObjNameSingul()); 3104 } 3105 3106 std::unordered_set<OUString> aNameSet; 3107 MakeNameUnique(aNameSet); 3108 } 3109 3110 void SdrObject::MakeNameUnique(std::unordered_set<OUString>& rNameSet) 3111 { 3112 if (GetName().isEmpty()) 3113 return; 3114 3115 if (rNameSet.empty()) 3116 { 3117 SdrPage* pPage; 3118 SdrObject* pObj; 3119 for (sal_uInt16 nPage(0); nPage < mrSdrModelFromSdrObject.GetPageCount(); ++nPage) 3120 { 3121 pPage = mrSdrModelFromSdrObject.GetPage(nPage); 3122 SdrObjListIter aIter(pPage, SdrIterMode::DeepWithGroups); 3123 while (aIter.IsMore()) 3124 { 3125 pObj = aIter.Next(); 3126 if (pObj != this) 3127 rNameSet.insert(pObj->GetName()); 3128 } 3129 } 3130 } 3131 3132 OUString sName(GetName().trim()); 3133 OUString sRootName(sName); 3134 3135 if (!sName.isEmpty() && rtl::isAsciiDigit(sName[sName.getLength() - 1])) 3136 { 3137 sal_Int32 nPos(sName.getLength() - 1); 3138 while (nPos > 0 && rtl::isAsciiDigit(sName[--nPos])); 3139 sRootName = sName.copy(0, nPos + 1).trim(); 3140 } 3141 else 3142 sName += " 1"; 3143 3144 for (sal_uInt32 n = 1; rNameSet.find(sName) != rNameSet.end(); n++) 3145 sName = sRootName + " " + OUString::number(n); 3146 rNameSet.insert(sName); 3147 3148 SetName(sName); 3149 } 3150 3151 SdrObject* SdrObjFactory::CreateObjectFromFactory(SdrModel& rSdrModel, SdrInventor nInventor, SdrObjKind nObjIdentifier) 3152 { 3153 SdrObjCreatorParams aParams { nInventor, nObjIdentifier, rSdrModel }; 3154 for (const auto & i : ImpGetUserMakeObjHdl()) { 3155 SdrObject* pObj = i.Call(aParams); 3156 if (pObj) { 3157 return pObj; 3158 } 3159 } 3160 return nullptr; 3161 } 3162 3163 SdrObject* SdrObjFactory::MakeNewObject( 3164 SdrModel& rSdrModel, 3165 SdrInventor nInventor, 3166 SdrObjKind nIdentifier, 3167 const tools::Rectangle* pSnapRect) 3168 { 3169 SdrObject* pObj(nullptr); 3170 bool bSetSnapRect(nullptr != pSnapRect); 3171 3172 if (nInventor == SdrInventor::Default) 3173 { 3174 switch (nIdentifier) 3175 { 3176 case OBJ_MEASURE: 3177 { 3178 if(nullptr != pSnapRect) 3179 { 3180 pObj = new SdrMeasureObj( 3181 rSdrModel, 3182 pSnapRect->TopLeft(), 3183 pSnapRect->BottomRight()); 3184 } 3185 else 3186 { 3187 pObj = new SdrMeasureObj(rSdrModel); 3188 } 3189 } 3190 break; 3191 case OBJ_LINE: 3192 { 3193 if(nullptr != pSnapRect) 3194 { 3195 basegfx::B2DPolygon aPoly; 3196 3197 aPoly.append( 3198 basegfx::B2DPoint( 3199 pSnapRect->Left(), 3200 pSnapRect->Top())); 3201 aPoly.append( 3202 basegfx::B2DPoint( 3203 pSnapRect->Right(), 3204 pSnapRect->Bottom())); 3205 pObj = new SdrPathObj( 3206 rSdrModel, 3207 OBJ_LINE, 3208 basegfx::B2DPolyPolygon(aPoly)); 3209 } 3210 else 3211 { 3212 pObj = new SdrPathObj( 3213 rSdrModel, 3214 OBJ_LINE); 3215 } 3216 } 3217 break; 3218 case OBJ_TEXT: 3219 case OBJ_TITLETEXT: 3220 case OBJ_OUTLINETEXT: 3221 { 3222 if(nullptr != pSnapRect) 3223 { 3224 pObj = new SdrRectObj( 3225 rSdrModel, 3226 nIdentifier, 3227 *pSnapRect); 3228 bSetSnapRect = false; 3229 } 3230 else 3231 { 3232 pObj = new SdrRectObj( 3233 rSdrModel, 3234 nIdentifier); 3235 } 3236 } 3237 break; 3238 case OBJ_CIRC: 3239 case OBJ_SECT: 3240 case OBJ_CARC: 3241 case OBJ_CCUT: 3242 { 3243 SdrCircKind eCircKind = ToSdrCircKind(nIdentifier); 3244 if(nullptr != pSnapRect) 3245 { 3246 pObj = new SdrCircObj(rSdrModel, eCircKind, *pSnapRect); 3247 bSetSnapRect = false; 3248 } 3249 else 3250 { 3251 pObj = new SdrCircObj(rSdrModel, eCircKind); 3252 } 3253 } 3254 break; 3255 case OBJ_NONE : pObj=new SdrObject(rSdrModel); break; 3256 case OBJ_GRUP : pObj=new SdrObjGroup(rSdrModel); break; 3257 case OBJ_POLY : pObj=new SdrPathObj(rSdrModel, OBJ_POLY ); break; 3258 case OBJ_PLIN : pObj=new SdrPathObj(rSdrModel, OBJ_PLIN ); break; 3259 case OBJ_PATHLINE : pObj=new SdrPathObj(rSdrModel, OBJ_PATHLINE ); break; 3260 case OBJ_PATHFILL : pObj=new SdrPathObj(rSdrModel, OBJ_PATHFILL ); break; 3261 case OBJ_FREELINE : pObj=new SdrPathObj(rSdrModel, OBJ_FREELINE ); break; 3262 case OBJ_FREEFILL : pObj=new SdrPathObj(rSdrModel, OBJ_FREEFILL ); break; 3263 case OBJ_PATHPOLY : pObj=new SdrPathObj(rSdrModel, OBJ_POLY ); break; 3264 case OBJ_PATHPLIN : pObj=new SdrPathObj(rSdrModel, OBJ_PLIN ); break; 3265 case OBJ_EDGE : pObj=new SdrEdgeObj(rSdrModel); break; 3266 case OBJ_RECT : pObj=new SdrRectObj(rSdrModel); break; 3267 case OBJ_GRAF : pObj=new SdrGrafObj(rSdrModel); break; 3268 case OBJ_OLE2 : pObj=new SdrOle2Obj(rSdrModel); break; 3269 case OBJ_FRAME : pObj=new SdrOle2Obj(rSdrModel, true); break; 3270 case OBJ_CAPTION : pObj=new SdrCaptionObj(rSdrModel); break; 3271 case OBJ_PAGE : pObj=new SdrPageObj(rSdrModel); break; 3272 case OBJ_UNO : pObj=new SdrUnoObj(rSdrModel, OUString()); break; 3273 case OBJ_CUSTOMSHAPE: pObj=new SdrObjCustomShape(rSdrModel); break; 3274 #if HAVE_FEATURE_AVMEDIA 3275 case OBJ_MEDIA : pObj=new SdrMediaObj(rSdrModel); break; 3276 #endif 3277 case OBJ_TABLE : pObj=new sdr::table::SdrTableObj(rSdrModel); break; 3278 default: break; 3279 } 3280 } 3281 3282 if (!pObj) 3283 { 3284 pObj = CreateObjectFromFactory(rSdrModel, nInventor, nIdentifier); 3285 } 3286 3287 if (!pObj) 3288 { 3289 // Well, if no one wants it... 3290 return nullptr; 3291 } 3292 3293 if(bSetSnapRect && nullptr != pSnapRect) 3294 { 3295 pObj->SetSnapRect(*pSnapRect); 3296 } 3297 3298 return pObj; 3299 } 3300 3301 void SdrObjFactory::InsertMakeObjectHdl(Link<SdrObjCreatorParams, SdrObject*> const & rLink) 3302 { 3303 std::vector<Link<SdrObjCreatorParams, SdrObject*>>& rLL=ImpGetUserMakeObjHdl(); 3304 auto it = std::find(rLL.begin(), rLL.end(), rLink); 3305 if (it != rLL.end()) { 3306 OSL_FAIL("SdrObjFactory::InsertMakeObjectHdl(): Link already in place."); 3307 } else { 3308 rLL.push_back(rLink); 3309 } 3310 } 3311 3312 void SdrObjFactory::RemoveMakeObjectHdl(Link<SdrObjCreatorParams, SdrObject*> const & rLink) 3313 { 3314 std::vector<Link<SdrObjCreatorParams, SdrObject*>>& rLL=ImpGetUserMakeObjHdl(); 3315 auto it = std::find(rLL.begin(), rLL.end(), rLink); 3316 if (it != rLL.end()) 3317 rLL.erase(it); 3318 } 3319 3320 namespace svx 3321 { 3322 ISdrObjectFilter::~ISdrObjectFilter() 3323 { 3324 } 3325 } 3326 3327 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 3328
