bump product version to 7.2.5.1
[LibreOffice.git] / svx / source / sdr / properties / attributeproperties.cxx
blob2dfd9e8199819e681cf719a83524d98e6229b4f7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <sdr/properties/attributeproperties.hxx>
23 #include <tools/debug.hxx>
24 #include <svl/itemset.hxx>
25 #include <svl/style.hxx>
26 #include <svl/whiter.hxx>
27 #include <svl/poolitem.hxx>
28 #include <svx/svdobj.hxx>
29 #include <svx/svddef.hxx>
30 #include <svx/xbtmpit.hxx>
31 #include <svx/xlndsit.hxx>
32 #include <svx/xlnstit.hxx>
33 #include <svx/xlnedit.hxx>
34 #include <svx/xflgrit.hxx>
35 #include <svx/xflftrit.hxx>
36 #include <svx/xflhtit.hxx>
37 #include <svx/svdmodel.hxx>
38 #include <svx/svdpage.hxx>
39 #include <osl/diagnose.h>
41 namespace sdr::properties
43 void AttributeProperties::ImpSetParentAtSfxItemSet(bool bDontRemoveHardAttr)
45 if(HasSfxItemSet() && mpStyleSheet)
47 // Delete hard attributes where items are set in the style sheet
48 if(!bDontRemoveHardAttr)
50 const SfxItemSet& rStyle = mpStyleSheet->GetItemSet();
51 SfxWhichIter aIter(rStyle);
52 sal_uInt16 nWhich = aIter.FirstWhich();
54 while(nWhich)
56 if(SfxItemState::SET == rStyle.GetItemState(nWhich))
58 mxItemSet->ClearItem(nWhich);
61 nWhich = aIter.NextWhich();
65 // set new stylesheet as parent
66 mxItemSet->SetParent(&mpStyleSheet->GetItemSet());
68 else
70 OSL_ENSURE(false, "ImpSetParentAtSfxItemSet called without SfxItemSet/SfxStyleSheet (!)");
74 void AttributeProperties::ImpAddStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr)
76 // test if old StyleSheet is cleared, else it would be lost
77 // after this method -> memory leak (!)
78 DBG_ASSERT(!mpStyleSheet, "Old style sheet not deleted before setting new one (!)");
80 if(!pNewStyleSheet)
81 return;
83 // local remember
84 mpStyleSheet = pNewStyleSheet;
86 if(HasSfxItemSet())
88 // register as listener
89 StartListening(*pNewStyleSheet->GetPool());
90 StartListening(*pNewStyleSheet);
92 // only apply the following when we have an SfxItemSet already, else
93 if(GetStyleSheet())
95 ImpSetParentAtSfxItemSet(bDontRemoveHardAttr);
100 void AttributeProperties::ImpRemoveStyleSheet()
102 // Check type since it is destroyed when the type is deleted
103 if(GetStyleSheet() && mpStyleSheet)
105 EndListening(*mpStyleSheet);
106 if (auto const pool = mpStyleSheet->GetPool()) { // TTTT
107 EndListening(*pool);
110 // reset parent of ItemSet
111 if(HasSfxItemSet())
113 mxItemSet->SetParent(nullptr);
116 SdrObject& rObj = GetSdrObject();
117 rObj.SetBoundRectDirty();
118 rObj.SetRectsDirty(true);
121 mpStyleSheet = nullptr;
124 // create a new itemset
125 SfxItemSet AttributeProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
127 return SfxItemSet(rPool,
129 // ranges from SdrAttrObj
130 svl::Items<SDRATTR_START, SDRATTR_SHADOW_LAST,
131 SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
132 SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
133 SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST>{});
136 AttributeProperties::AttributeProperties(SdrObject& rObj)
137 : DefaultProperties(rObj),
138 mpStyleSheet(nullptr)
140 // Do nothing else, esp. do *not* try to get and set
141 // a default SfxStyle sheet. Nothing is allowed to be done
142 // that may lead to calls to virtual functions like
143 // CreateObjectSpecificItemSet - these would go *wrong*.
144 // Thus the rest is lazy-init from here.
147 AttributeProperties::AttributeProperties(const AttributeProperties& rProps, SdrObject& rObj)
148 : DefaultProperties(rProps, rObj),
149 mpStyleSheet(nullptr)
151 SfxStyleSheet* pTargetStyleSheet(rProps.GetStyleSheet());
153 if(pTargetStyleSheet)
155 const bool bModelChange(&rObj.getSdrModelFromSdrObject() != &rProps.GetSdrObject().getSdrModelFromSdrObject());
157 if(bModelChange)
159 // tdf#117506
160 // The error shows that it is definitely necessary to solve this problem.
161 // Interestingly I already had a note here for 'work needed'.
162 // Checked in libreoffice-6-0 what happened there. In principle, the whole
163 // ::Clone of SdrPage and SdrObject happened in the same SdrModel, only
164 // afterwards a ::SetModel was used at the cloned SdrPage which went through
165 // all layers. The StyleSheet-problem was solved in
166 // AttributeProperties::MoveToItemPool at the end. There, a StyleSheet with the
167 // same name was searched for in the target-SdrModel.
168 // Start by resetting the current TargetStyleSheet so that nothing goes wrong
169 // when we do not find a fitting TargetStyleSheet.
170 // Note: The test for SdrModelChange above was wrong (compared the already set
171 // new SdrObject), so this never triggered and pTargetStyleSheet was never set to
172 // nullptr before. This means that a StyleSheet from another SdrModel was used
173 // what of course is very dangerous. Interestingly did not crash since when that
174 // other SdrModel was destroyed the ::Notify mechanism still worked reliably
175 // and de-connected this Properties successfully from the alien-StyleSheet.
176 pTargetStyleSheet = nullptr;
178 // Check if we have a TargetStyleSheetPool at the target-SdrModel. This *should*
179 // be the case already (SdrModel::Merge and SdDrawDocument::InsertBookmarkAsPage
180 // have already cloned the StyleSheets to the target-SdrModel when used in Draw/impress).
181 // If none is found, ImpGetDefaultStyleSheet will be used to set a 'default'
182 // StyleSheet as StyleSheet implicitly later (that's what happened in the task,
183 // thus the FillStyle changed to the 'default' Blue).
184 // Note: It *may* be necessary to do more for StyleSheets, e.g. clone/copy the
185 // StyleSheet Hierarchy from the source SdrModel and/or add the Items from there
186 // as hard attributes. If needed, have a look at the older AttributeProperties::SetModel
187 // implementation from e.g. libreoffice-6-0.
188 SfxStyleSheetBasePool* pTargetStyleSheetPool(rObj.getSdrModelFromSdrObject().GetStyleSheetPool());
190 if(nullptr != pTargetStyleSheetPool)
192 // If we have a TargetStyleSheetPool, search for the used StyleSheet
193 // in the target SdrModel using the Name from the original StyleSheet
194 // in the source-SdrModel.
195 pTargetStyleSheet = dynamic_cast< SfxStyleSheet* >(
196 pTargetStyleSheetPool->Find(
197 rProps.GetStyleSheet()->GetName(),
198 SfxStyleFamily::All));
203 if(!pTargetStyleSheet)
204 return;
206 if(HasSfxItemSet())
208 // The SfxItemSet has been cloned and exists,
209 // we can directly set the SfxStyleSheet at it
210 ImpAddStyleSheet(pTargetStyleSheet, true);
212 else
214 // No SfxItemSet exists yet (there is none in
215 // the source, so none was cloned). Remember the
216 // SfxStyleSheet to set it when the SfxItemSet
217 // got constructed on-demand
218 mpStyleSheet = pTargetStyleSheet;
222 AttributeProperties::~AttributeProperties()
224 ImpRemoveStyleSheet();
227 std::unique_ptr<BaseProperties> AttributeProperties::Clone(SdrObject& rObj) const
229 return std::unique_ptr<BaseProperties>(new AttributeProperties(*this, rObj));
232 const SfxItemSet& AttributeProperties::GetObjectItemSet() const
234 // remember if we had a SfxItemSet already
235 const bool bHadSfxItemSet(HasSfxItemSet());
237 // call parent - this will guarantee SfxItemSet existence
238 DefaultProperties::GetObjectItemSet();
240 if(!bHadSfxItemSet)
242 // need to take care for SfxStyleSheet for newly
243 // created SfxItemSet
244 if(nullptr == mpStyleSheet)
246 // Set missing defaults without removal of hard attributes.
247 // This is more complicated historically than I first thought:
248 // Originally for GetDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj
249 // SetStyleSheet(..., false) was used, while for GetDefaultStyleSheet
250 // SetStyleSheet(..., true) was used. Thus, for SdrGrafObj and SdrOle2Obj
251 // bDontRemoveHardAttr == false -> *do* delete hard attributes was used.
252 // This was probably not done by purpose, adding the method
253 // GetDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj additionally to
254 // GetDefaultStyleSheet was an enhancement to allow for SdrGrafObj/SdrOle2Obj
255 // with full AttributeSet (adding e.g. FillAttributes). To stay as compatible
256 // as possible these SdrObjects got a new default-StyleSheet.
257 // There is no reason to delete the HardAttributes and it anyways has only
258 // AFAIK effects on a single Item - the SdrTextHorzAdjustItem. To get things
259 // unified I will stay with not deleting the HardAttributes and adapt the
260 // UnitTests in CppunitTest_sd_import_tests accordingly.
261 const_cast< AttributeProperties* >(this)->applyDefaultStyleSheetFromSdrModel();
263 else
265 // Late-Init of setting parent to SfxStyleSheet after
266 // it's creation. Can only happen from copy-constructor
267 // (where creation of SfxItemSet is avoided due to the
268 // problem with constructors and virtual functions in C++),
269 // thus DontRemoveHardAttr is not needed.
270 const_cast< AttributeProperties* >(this)->SetStyleSheet(
271 mpStyleSheet,
272 true);
276 return *mxItemSet;
279 void AttributeProperties::ItemSetChanged(const SfxItemSet& /*rSet*/)
281 // own modifications
282 SdrObject& rObj = GetSdrObject();
284 rObj.SetBoundRectDirty();
285 rObj.SetRectsDirty(true);
286 rObj.SetChanged();
289 void AttributeProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem)
291 if(pNewItem)
293 std::unique_ptr<SfxPoolItem> pResultItem;
294 SdrModel& rModel(GetSdrObject().getSdrModelFromSdrObject());
296 switch( nWhich )
298 case XATTR_FILLBITMAP:
300 // TTTT checkForUniqueItem should use SdrModel&
301 pResultItem = static_cast<const XFillBitmapItem*>(pNewItem)->checkForUniqueItem( &rModel );
302 break;
304 case XATTR_LINEDASH:
306 pResultItem = static_cast<const XLineDashItem*>(pNewItem)->checkForUniqueItem( &rModel );
307 break;
309 case XATTR_LINESTART:
311 pResultItem = static_cast<const XLineStartItem*>(pNewItem)->checkForUniqueItem( &rModel );
312 break;
314 case XATTR_LINEEND:
316 pResultItem = static_cast<const XLineEndItem*>(pNewItem)->checkForUniqueItem( &rModel );
317 break;
319 case XATTR_FILLGRADIENT:
321 pResultItem = static_cast<const XFillGradientItem*>(pNewItem)->checkForUniqueItem( &rModel );
322 break;
324 case XATTR_FILLFLOATTRANSPARENCE:
326 // #85953# allow all kinds of XFillFloatTransparenceItem to be set
327 pResultItem = static_cast<const XFillFloatTransparenceItem*>(pNewItem)->checkForUniqueItem( &rModel );
328 break;
330 case XATTR_FILLHATCH:
332 pResultItem = static_cast<const XFillHatchItem*>(pNewItem)->checkForUniqueItem( &rModel );
333 break;
337 // guarantee SfxItemSet existence
338 GetObjectItemSet();
340 if(pResultItem)
342 // force ItemSet
343 mxItemSet->Put(*pResultItem);
345 // delete item if it was a generated one
346 pResultItem.reset();
348 else
350 mxItemSet->Put(*pNewItem);
353 else
355 // clear item if ItemSet exists
356 if(HasSfxItemSet())
358 mxItemSet->ClearItem(nWhich);
363 void AttributeProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr)
365 // guarantee SfxItemSet existence
366 GetObjectItemSet();
368 ImpRemoveStyleSheet();
369 ImpAddStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
371 SdrObject& rObj = GetSdrObject();
372 rObj.SetBoundRectDirty();
373 rObj.SetRectsDirty(true);
376 SfxStyleSheet* AttributeProperties::GetStyleSheet() const
378 return mpStyleSheet;
381 void AttributeProperties::ForceStyleToHardAttributes()
383 if(!GetStyleSheet() || mpStyleSheet == nullptr)
384 return;
386 // guarantee SfxItemSet existence
387 GetObjectItemSet();
389 // prepare copied, new itemset, but WITHOUT parent
390 SfxItemSet aDestItemSet(*mxItemSet);
391 aDestItemSet.SetParent(nullptr);
393 // prepare forgetting the current stylesheet like in RemoveStyleSheet()
394 EndListening(*mpStyleSheet);
395 EndListening(*mpStyleSheet->GetPool());
397 // prepare the iter; use the mpObjectItemSet which may have less
398 // WhichIDs than the style.
399 SfxWhichIter aIter(aDestItemSet);
400 sal_uInt16 nWhich(aIter.FirstWhich());
401 const SfxPoolItem *pItem = nullptr;
403 // now set all hard attributes of the current at the new itemset
404 while(nWhich)
406 // #i61284# use mpItemSet with parents, makes things easier and reduces to
407 // one loop
408 if(SfxItemState::SET == mxItemSet->GetItemState(nWhich, true, &pItem))
410 aDestItemSet.Put(*pItem);
413 nWhich = aIter.NextWhich();
416 // replace itemsets
417 mxItemSet.emplace(std::move(aDestItemSet));
419 // set necessary changes like in RemoveStyleSheet()
420 GetSdrObject().SetBoundRectDirty();
421 GetSdrObject().SetRectsDirty(true);
423 mpStyleSheet = nullptr;
426 void AttributeProperties::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
428 bool bHintUsed(false);
430 const SfxStyleSheetHint* pStyleHint = dynamic_cast<const SfxStyleSheetHint*>(&rHint);
432 if(pStyleHint && pStyleHint->GetStyleSheet() == GetStyleSheet())
434 SdrObject& rObj = GetSdrObject();
435 //SdrPage* pPage = rObj.GetPage();
437 switch(pStyleHint->GetId())
439 case SfxHintId::StyleSheetCreated :
441 // cannot happen, nothing to do
442 break;
444 case SfxHintId::StyleSheetModified :
445 case SfxHintId::StyleSheetChanged :
447 // notify change
448 break;
450 case SfxHintId::StyleSheetErased :
451 case SfxHintId::StyleSheetInDestruction :
453 // Style needs to be exchanged
454 SfxStyleSheet* pNewStSh = nullptr;
455 SdrModel& rModel(rObj.getSdrModelFromSdrObject());
457 // Do nothing if object is in destruction, else a StyleSheet may be found from
458 // a StyleSheetPool which is just being deleted itself. and thus it would be fatal
459 // to register as listener to that new StyleSheet.
460 if(!rObj.IsInDestruction())
462 if(SfxStyleSheet* pStyleSheet = GetStyleSheet())
464 pNewStSh = static_cast<SfxStyleSheet*>(rModel.GetStyleSheetPool()->Find(
465 pStyleSheet->GetParent(), pStyleSheet->GetFamily()));
468 if(!pNewStSh)
470 pNewStSh = rModel.GetDefaultStyleSheet();
474 // remove used style, it's erased or in destruction
475 ImpRemoveStyleSheet();
477 if(pNewStSh)
479 ImpAddStyleSheet(pNewStSh, true);
482 break;
484 default: break;
487 // Get old BoundRect. Do this after the style change is handled
488 // in the ItemSet parts because GetBoundRect() may calculate a new
489 tools::Rectangle aBoundRect = rObj.GetLastBoundRect();
491 rObj.SetRectsDirty(true);
493 // tell the object about the change
494 rObj.SetChanged();
495 rObj.BroadcastObjectChange();
497 //if(pPage && pPage->IsInserted())
499 // rObj.BroadcastObjectChange();
502 rObj.SendUserCall(SdrUserCallType::ChangeAttr, aBoundRect);
504 bHintUsed = true;
507 if(!bHintUsed)
509 // forward to SdrObject ATM. Not sure if this will be necessary
510 // in the future.
511 GetSdrObject().Notify(rBC, rHint);
515 bool AttributeProperties::isUsedByModel() const
517 const SdrObject& rObj(GetSdrObject());
518 if (rObj.IsInserted())
520 const SdrPage* const pPage(rObj.getSdrPageFromSdrObject());
521 if (pPage && pPage->IsInserted())
522 return true;
524 return false;
526 } // end of namespace
528 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */