Bump version to 6.4-15
[LibreOffice.git] / svx / source / sdr / properties / attributeproperties.cxx
blob7e9d500d87190861f518e96a210e79cf98add248
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 <utility>
24 #include <sdr/properties/attributeproperties.hxx>
25 #include <sdr/properties/itemsettools.hxx>
26 #include <tools/debug.hxx>
27 #include <svl/itemset.hxx>
28 #include <svl/style.hxx>
29 #include <svl/whiter.hxx>
30 #include <svl/poolitem.hxx>
31 #include <svx/svdobj.hxx>
32 #include <svx/svddef.hxx>
33 #include <svx/xit.hxx>
34 #include <svx/xbtmpit.hxx>
35 #include <svx/xlndsit.hxx>
36 #include <svx/xlnstit.hxx>
37 #include <svx/xlnedit.hxx>
38 #include <svx/xflgrit.hxx>
39 #include <svx/xflftrit.hxx>
40 #include <svx/xflhtit.hxx>
41 #include <svx/xlnasit.hxx>
42 #include <svx/xflasit.hxx>
43 #include <svx/svdmodel.hxx>
44 #include <svx/svdtrans.hxx>
45 #include <svx/svdpage.hxx>
47 namespace sdr
49 namespace properties
51 void AttributeProperties::ImpSetParentAtSfxItemSet(bool bDontRemoveHardAttr)
53 if(HasSfxItemSet() && mpStyleSheet)
55 // Delete hard attributes where items are set in the style sheet
56 if(!bDontRemoveHardAttr)
58 const SfxItemSet& rStyle = mpStyleSheet->GetItemSet();
59 SfxWhichIter aIter(rStyle);
60 sal_uInt16 nWhich = aIter.FirstWhich();
62 while(nWhich)
64 if(SfxItemState::SET == rStyle.GetItemState(nWhich))
66 mpItemSet->ClearItem(nWhich);
69 nWhich = aIter.NextWhich();
73 // set new stylesheet as parent
74 mpItemSet->SetParent(&mpStyleSheet->GetItemSet());
76 else
78 OSL_ENSURE(false, "ImpSetParentAtSfxItemSet called without SfxItemSet/SfxStyleSheet (!)");
82 void AttributeProperties::ImpAddStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr)
84 // test if old StyleSheet is cleared, else it would be lost
85 // after this method -> memory leak (!)
86 DBG_ASSERT(!mpStyleSheet, "Old style sheet not deleted before setting new one (!)");
88 if(pNewStyleSheet)
90 // local remember
91 mpStyleSheet = pNewStyleSheet;
93 if(HasSfxItemSet())
95 // register as listener
96 StartListening(*pNewStyleSheet->GetPool());
97 StartListening(*pNewStyleSheet);
99 // only apply the following when we have an SfxItemSet already, else
100 if(GetStyleSheet())
102 ImpSetParentAtSfxItemSet(bDontRemoveHardAttr);
108 void AttributeProperties::ImpRemoveStyleSheet()
110 // Check type since it is destroyed when the type is deleted
111 if(GetStyleSheet() && dynamic_cast<const SfxStyleSheet *>(mpStyleSheet) != nullptr)
113 EndListening(*mpStyleSheet);
114 if (auto const pool = mpStyleSheet->GetPool()) { // TTTT
115 EndListening(*pool);
118 // reset parent of ItemSet
119 if(HasSfxItemSet())
121 mpItemSet->SetParent(nullptr);
124 SdrObject& rObj = GetSdrObject();
125 rObj.SetBoundRectDirty();
126 rObj.SetRectsDirty(true);
129 mpStyleSheet = nullptr;
132 // create a new itemset
133 std::unique_ptr<SfxItemSet> AttributeProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
135 return std::make_unique<SfxItemSet>(rPool,
137 // ranges from SdrAttrObj
138 svl::Items<SDRATTR_START, SDRATTR_SHADOW_LAST,
139 SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
140 SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION>{});
143 AttributeProperties::AttributeProperties(SdrObject& rObj)
144 : DefaultProperties(rObj),
145 mpStyleSheet(nullptr)
147 // Do nothing else, esp. do *not* try to get and set
148 // a default SfxStyle sheet. Nothing is allowed to be done
149 // that may lead to calls to virtual functions like
150 // CreateObjectSpecificItemSet - these would go *wrong*.
151 // Thus the rest is lazy-init from here.
154 AttributeProperties::AttributeProperties(const AttributeProperties& rProps, SdrObject& rObj)
155 : DefaultProperties(rProps, rObj),
156 mpStyleSheet(nullptr)
158 SfxStyleSheet* pTargetStyleSheet(rProps.GetStyleSheet());
160 if(pTargetStyleSheet)
162 const bool bModelChange(&rObj.getSdrModelFromSdrObject() != &rProps.GetSdrObject().getSdrModelFromSdrObject());
164 if(bModelChange)
166 // tdf#117506
167 // The error shows that it is definitely necessary to solve this problem.
168 // Interestingly I already had a note here for 'work needed'.
169 // Checked in libreoffice-6-0 what happened there. In principle, the whole
170 // ::Clone of SdrPage and SdrObject happened in the same SdrModel, only
171 // afterwards a ::SetModel was used at the cloned SdrPage which went through
172 // all layers. The StyleSheet-problem was solved in
173 // AttributeProperties::MoveToItemPool at the end. There, a StyleSheet with the
174 // same name was searched for in the target-SdrModel.
175 // Start by resetting the current TargetStyleSheet so that nothing goes wrong
176 // when we do not find a fitting TargetStyleSheet.
177 // Note: The test for SdrModelChange above was wrong (compared the already set
178 // new SdrObject), so this never triggered and pTargetStyleSheet was never set to
179 // nullptr before. This means that a StyleSheet from another SdrModel was used
180 // what of course is very dangerous. Interestingly did not crash since when that
181 // other SdrModel was destroyed the ::Notify mechanism still worked reliably
182 // and de-connected this Properties successfully from the alien-StyleSheet.
183 pTargetStyleSheet = nullptr;
185 // Check if we have a TargetStyleSheetPool at the target-SdrModel. This *should*
186 // be the case already (SdrModel::Merge and SdDrawDocument::InsertBookmarkAsPage
187 // have already cloned the StyleSheets to the target-SdrModel when used in Draw/impress).
188 // If none is found, ImpGetDefaultStyleSheet will be used to set a 'default'
189 // StyleSheet as StyleSheet implicitly later (that's what happened in the task,
190 // thus the FillStyle changed to the 'default' Blue).
191 // Note: It *may* be necessary to do more for StyleSheets, e.g. clone/copy the
192 // StyleSheet Hierarchy from the source SdrModel and/or add the Items from there
193 // as hard attributes. If needed, have a look at the older AttributeProperties::SetModel
194 // implementation from e.g. libreoffice-6-0.
195 SfxStyleSheetBasePool* pTargetStyleSheetPool(rObj.getSdrModelFromSdrObject().GetStyleSheetPool());
197 if(nullptr != pTargetStyleSheetPool)
199 // If we have a TargetStyleSheetPool, search for the used StyleSheet
200 // in the target SdrModel using the Name from the original StyleSheet
201 // in the source-SdrModel.
202 pTargetStyleSheet = dynamic_cast< SfxStyleSheet* >(
203 pTargetStyleSheetPool->Find(
204 rProps.GetStyleSheet()->GetName(),
205 SfxStyleFamily::All));
210 if(pTargetStyleSheet)
212 if(HasSfxItemSet())
214 // The SfxItemSet has been cloned and exists,
215 // we can directly set the SfxStyleSheet at it
216 ImpAddStyleSheet(pTargetStyleSheet, true);
218 else
220 // No SfxItemSet exists yet (there is none in
221 // the source, so none was cloned). Remember the
222 // SfxStyleSheet to set it when the SfxItemSet
223 // got constructed on-demand
224 mpStyleSheet = pTargetStyleSheet;
229 AttributeProperties::~AttributeProperties()
231 ImpRemoveStyleSheet();
234 std::unique_ptr<BaseProperties> AttributeProperties::Clone(SdrObject& rObj) const
236 return std::unique_ptr<BaseProperties>(new AttributeProperties(*this, rObj));
239 const SfxItemSet& AttributeProperties::GetObjectItemSet() const
241 // remember if we had a SfxItemSet already
242 const bool bHadSfxItemSet(HasSfxItemSet());
244 // call parent - this will guarantee SfxItemSet existence
245 DefaultProperties::GetObjectItemSet();
247 if(!bHadSfxItemSet)
249 // need to take care for SfxStyleSheet for newly
250 // created SfxItemSet
251 if(nullptr == mpStyleSheet)
253 // Set missing defaults without removal of hard attributes.
254 // This is more complicated historically than I first thought:
255 // Originally for GetDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj
256 // SetStyleSheet(..., false) was used, while for GetDefaultStyleSheet
257 // SetStyleSheet(..., true) was used. Thus, for SdrGrafObj and SdrOle2Obj
258 // bDontRemoveHardAttr == false -> *do* delete hard attributes was used.
259 // This was probably not done by purpose, adding the method
260 // GetDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj additionally to
261 // GetDefaultStyleSheet was an enhancement to allow for SdrGrafObj/SdrOle2Obj
262 // with full AttributeSet (adding e.g. FillAttributes). To stay as compatible
263 // as possible these SdrObjects got a new default-StyleSheet.
264 // There is no reason to delete the HardAttributes and it anyways has only
265 // AFAIK effects on a single Item - the SdrTextHorzAdjustItem. To get things
266 // unified I will stay with not deleting the HardAttributes and adapt the
267 // UnitTests in CppunitTest_sd_import_tests accordingly.
268 const_cast< AttributeProperties* >(this)->applyDefaultStyleSheetFromSdrModel();
270 else
272 // Late-Init of setting parent to SfxStyleSheet after
273 // it's creation. Can only happen from copy-constructor
274 // (where creation of SfxItemSet is avoided due to the
275 // problem with constructors and virtual functions in C++),
276 // thus DontRemoveHardAttr is not needed.
277 const_cast< AttributeProperties* >(this)->SetStyleSheet(
278 mpStyleSheet,
279 true);
283 return *mpItemSet;
286 void AttributeProperties::ItemSetChanged(const SfxItemSet& /*rSet*/)
288 // own modifications
289 SdrObject& rObj = GetSdrObject();
291 rObj.SetBoundRectDirty();
292 rObj.SetRectsDirty(true);
293 rObj.SetChanged();
296 void AttributeProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem)
298 if(pNewItem)
300 std::unique_ptr<SfxPoolItem> pResultItem;
301 SdrModel& rModel(GetSdrObject().getSdrModelFromSdrObject());
303 switch( nWhich )
305 case XATTR_FILLBITMAP:
307 // TTTT checkForUniqueItem should use SdrModel&
308 pResultItem = static_cast<const XFillBitmapItem*>(pNewItem)->checkForUniqueItem( &rModel );
309 break;
311 case XATTR_LINEDASH:
313 pResultItem = static_cast<const XLineDashItem*>(pNewItem)->checkForUniqueItem( &rModel );
314 break;
316 case XATTR_LINESTART:
318 pResultItem = static_cast<const XLineStartItem*>(pNewItem)->checkForUniqueItem( &rModel );
319 break;
321 case XATTR_LINEEND:
323 pResultItem = static_cast<const XLineEndItem*>(pNewItem)->checkForUniqueItem( &rModel );
324 break;
326 case XATTR_FILLGRADIENT:
328 pResultItem = static_cast<const XFillGradientItem*>(pNewItem)->checkForUniqueItem( &rModel );
329 break;
331 case XATTR_FILLFLOATTRANSPARENCE:
333 // #85953# allow all kinds of XFillFloatTransparenceItem to be set
334 pResultItem = static_cast<const XFillFloatTransparenceItem*>(pNewItem)->checkForUniqueItem( &rModel );
335 break;
337 case XATTR_FILLHATCH:
339 pResultItem = static_cast<const XFillHatchItem*>(pNewItem)->checkForUniqueItem( &rModel );
340 break;
344 // guarantee SfxItemSet existence
345 GetObjectItemSet();
347 if(pResultItem)
349 // force ItemSet
350 mpItemSet->Put(*pResultItem);
352 // delete item if it was a generated one
353 pResultItem.reset();
355 else
357 mpItemSet->Put(*pNewItem);
360 else
362 // clear item if ItemSet exists
363 if(HasSfxItemSet())
365 mpItemSet->ClearItem(nWhich);
370 void AttributeProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr)
372 // guarantee SfxItemSet existence
373 GetObjectItemSet();
375 ImpRemoveStyleSheet();
376 ImpAddStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
378 SdrObject& rObj = GetSdrObject();
379 rObj.SetBoundRectDirty();
380 rObj.SetRectsDirty(true);
383 SfxStyleSheet* AttributeProperties::GetStyleSheet() const
385 return mpStyleSheet;
388 void AttributeProperties::ForceStyleToHardAttributes()
390 if(!GetStyleSheet() || dynamic_cast<const SfxStyleSheet *>(mpStyleSheet) == nullptr)
391 return;
393 // guarantee SfxItemSet existence
394 GetObjectItemSet();
396 // prepare copied, new itemset, but WITHOUT parent
397 SfxItemSet* pDestItemSet = new SfxItemSet(*mpItemSet);
398 pDestItemSet->SetParent(nullptr);
400 // prepare forgetting the current stylesheet like in RemoveStyleSheet()
401 EndListening(*mpStyleSheet);
402 EndListening(*mpStyleSheet->GetPool());
404 // prepare the iter; use the mpObjectItemSet which may have less
405 // WhichIDs than the style.
406 SfxWhichIter aIter(*pDestItemSet);
407 sal_uInt16 nWhich(aIter.FirstWhich());
408 const SfxPoolItem *pItem = nullptr;
410 // now set all hard attributes of the current at the new itemset
411 while(nWhich)
413 // #i61284# use mpItemSet with parents, makes things easier and reduces to
414 // one loop
415 if(SfxItemState::SET == mpItemSet->GetItemState(nWhich, true, &pItem))
417 pDestItemSet->Put(*pItem);
420 nWhich = aIter.NextWhich();
423 // replace itemsets
424 mpItemSet.reset(pDestItemSet);
426 // set necessary changes like in RemoveStyleSheet()
427 GetSdrObject().SetBoundRectDirty();
428 GetSdrObject().SetRectsDirty(true);
430 mpStyleSheet = nullptr;
433 void AttributeProperties::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
435 bool bHintUsed(false);
437 const SfxStyleSheetHint* pStyleHint = dynamic_cast<const SfxStyleSheetHint*>(&rHint);
439 if(pStyleHint && pStyleHint->GetStyleSheet() == GetStyleSheet())
441 SdrObject& rObj = GetSdrObject();
442 //SdrPage* pPage = rObj.GetPage();
444 switch(pStyleHint->GetId())
446 case SfxHintId::StyleSheetCreated :
448 // cannot happen, nothing to do
449 break;
451 case SfxHintId::StyleSheetModified :
452 case SfxHintId::StyleSheetChanged :
454 // notify change
455 break;
457 case SfxHintId::StyleSheetErased :
458 case SfxHintId::StyleSheetInDestruction :
460 // Style needs to be exchanged
461 SfxStyleSheet* pNewStSh = nullptr;
462 SdrModel& rModel(rObj.getSdrModelFromSdrObject());
464 // Do nothing if object is in destruction, else a StyleSheet may be found from
465 // a StyleSheetPool which is just being deleted itself. and thus it would be fatal
466 // to register as listener to that new StyleSheet.
467 if(!rObj.IsInDestruction())
469 if(dynamic_cast<const SfxStyleSheet *>(GetStyleSheet()) != nullptr)
471 pNewStSh = static_cast<SfxStyleSheet*>(rModel.GetStyleSheetPool()->Find(
472 GetStyleSheet()->GetParent(), GetStyleSheet()->GetFamily()));
475 if(!pNewStSh)
477 pNewStSh = rModel.GetDefaultStyleSheet();
481 // remove used style, it's erased or in destruction
482 ImpRemoveStyleSheet();
484 if(pNewStSh)
486 ImpAddStyleSheet(pNewStSh, true);
489 break;
491 default: break;
494 // Get old BoundRect. Do this after the style change is handled
495 // in the ItemSet parts because GetBoundRect() may calculate a new
496 tools::Rectangle aBoundRect = rObj.GetLastBoundRect();
498 rObj.SetRectsDirty(true);
500 // tell the object about the change
501 rObj.SetChanged();
502 rObj.BroadcastObjectChange();
504 //if(pPage && pPage->IsInserted())
506 // rObj.BroadcastObjectChange();
509 rObj.SendUserCall(SdrUserCallType::ChangeAttr, aBoundRect);
511 bHintUsed = true;
514 if(!bHintUsed)
516 // forward to SdrObject ATM. Not sure if this will be necessary
517 // in the future.
518 GetSdrObject().Notify(rBC, rHint);
522 bool AttributeProperties::isUsedByModel() const
524 const SdrObject& rObj(GetSdrObject());
525 if (rObj.IsInserted())
527 const SdrPage* const pPage(rObj.getSdrPageFromSdrObject());
528 if (pPage && pPage->IsInserted())
529 return true;
531 return false;
533 } // end of namespace properties
534 } // end of namespace sdr
536 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */