LibreOffice Module svx (master)  1
attributeproperties.cxx
Go to the documentation of this file.
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 <sal/config.h>
21 
22 #include <utility>
23 
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>
46 
47 namespace sdr::properties
48 {
49  void AttributeProperties::ImpSetParentAtSfxItemSet(bool bDontRemoveHardAttr)
50  {
52  {
53  // Delete hard attributes where items are set in the style sheet
54  if(!bDontRemoveHardAttr)
55  {
56  const SfxItemSet& rStyle = mpStyleSheet->GetItemSet();
57  SfxWhichIter aIter(rStyle);
58  sal_uInt16 nWhich = aIter.FirstWhich();
59 
60  while(nWhich)
61  {
62  if(SfxItemState::SET == rStyle.GetItemState(nWhich))
63  {
64  mpItemSet->ClearItem(nWhich);
65  }
66 
67  nWhich = aIter.NextWhich();
68  }
69  }
70 
71  // set new stylesheet as parent
72  mpItemSet->SetParent(&mpStyleSheet->GetItemSet());
73  }
74  else
75  {
76  OSL_ENSURE(false, "ImpSetParentAtSfxItemSet called without SfxItemSet/SfxStyleSheet (!)");
77  }
78  }
79 
80  void AttributeProperties::ImpAddStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr)
81  {
82  // test if old StyleSheet is cleared, else it would be lost
83  // after this method -> memory leak (!)
84  DBG_ASSERT(!mpStyleSheet, "Old style sheet not deleted before setting new one (!)");
85 
86  if(pNewStyleSheet)
87  {
88  // local remember
89  mpStyleSheet = pNewStyleSheet;
90 
91  if(HasSfxItemSet())
92  {
93  // register as listener
94  StartListening(*pNewStyleSheet->GetPool());
95  StartListening(*pNewStyleSheet);
96 
97  // only apply the following when we have an SfxItemSet already, else
98  if(GetStyleSheet())
99  {
100  ImpSetParentAtSfxItemSet(bDontRemoveHardAttr);
101  }
102  }
103  }
104  }
105 
107  {
108  // Check type since it is destroyed when the type is deleted
109  if(GetStyleSheet() && dynamic_cast<const SfxStyleSheet *>(mpStyleSheet) != nullptr)
110  {
112  if (auto const pool = mpStyleSheet->GetPool()) { // TTTT
113  EndListening(*pool);
114  }
115 
116  // reset parent of ItemSet
117  if(HasSfxItemSet())
118  {
119  mpItemSet->SetParent(nullptr);
120  }
121 
122  SdrObject& rObj = GetSdrObject();
123  rObj.SetBoundRectDirty();
124  rObj.SetRectsDirty(true);
125  }
126 
127  mpStyleSheet = nullptr;
128  }
129 
130  // create a new itemset
132  {
133  return std::make_unique<SfxItemSet>(rPool,
134 
135  // ranges from SdrAttrObj
138  SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION>{});
139  }
140 
142  : DefaultProperties(rObj),
143  mpStyleSheet(nullptr)
144  {
145  // Do nothing else, esp. do *not* try to get and set
146  // a default SfxStyle sheet. Nothing is allowed to be done
147  // that may lead to calls to virtual functions like
148  // CreateObjectSpecificItemSet - these would go *wrong*.
149  // Thus the rest is lazy-init from here.
150  }
151 
153  : DefaultProperties(rProps, rObj),
154  mpStyleSheet(nullptr)
155  {
156  SfxStyleSheet* pTargetStyleSheet(rProps.GetStyleSheet());
157 
158  if(pTargetStyleSheet)
159  {
160  const bool bModelChange(&rObj.getSdrModelFromSdrObject() != &rProps.GetSdrObject().getSdrModelFromSdrObject());
161 
162  if(bModelChange)
163  {
164  // tdf#117506
165  // The error shows that it is definitely necessary to solve this problem.
166  // Interestingly I already had a note here for 'work needed'.
167  // Checked in libreoffice-6-0 what happened there. In principle, the whole
168  // ::Clone of SdrPage and SdrObject happened in the same SdrModel, only
169  // afterwards a ::SetModel was used at the cloned SdrPage which went through
170  // all layers. The StyleSheet-problem was solved in
171  // AttributeProperties::MoveToItemPool at the end. There, a StyleSheet with the
172  // same name was searched for in the target-SdrModel.
173  // Start by resetting the current TargetStyleSheet so that nothing goes wrong
174  // when we do not find a fitting TargetStyleSheet.
175  // Note: The test for SdrModelChange above was wrong (compared the already set
176  // new SdrObject), so this never triggered and pTargetStyleSheet was never set to
177  // nullptr before. This means that a StyleSheet from another SdrModel was used
178  // what of course is very dangerous. Interestingly did not crash since when that
179  // other SdrModel was destroyed the ::Notify mechanism still worked reliably
180  // and de-connected this Properties successfully from the alien-StyleSheet.
181  pTargetStyleSheet = nullptr;
182 
183  // Check if we have a TargetStyleSheetPool at the target-SdrModel. This *should*
184  // be the case already (SdrModel::Merge and SdDrawDocument::InsertBookmarkAsPage
185  // have already cloned the StyleSheets to the target-SdrModel when used in Draw/impress).
186  // If none is found, ImpGetDefaultStyleSheet will be used to set a 'default'
187  // StyleSheet as StyleSheet implicitly later (that's what happened in the task,
188  // thus the FillStyle changed to the 'default' Blue).
189  // Note: It *may* be necessary to do more for StyleSheets, e.g. clone/copy the
190  // StyleSheet Hierarchy from the source SdrModel and/or add the Items from there
191  // as hard attributes. If needed, have a look at the older AttributeProperties::SetModel
192  // implementation from e.g. libreoffice-6-0.
193  SfxStyleSheetBasePool* pTargetStyleSheetPool(rObj.getSdrModelFromSdrObject().GetStyleSheetPool());
194 
195  if(nullptr != pTargetStyleSheetPool)
196  {
197  // If we have a TargetStyleSheetPool, search for the used StyleSheet
198  // in the target SdrModel using the Name from the original StyleSheet
199  // in the source-SdrModel.
200  pTargetStyleSheet = dynamic_cast< SfxStyleSheet* >(
201  pTargetStyleSheetPool->Find(
202  rProps.GetStyleSheet()->GetName(),
203  SfxStyleFamily::All));
204  }
205  }
206  }
207 
208  if(pTargetStyleSheet)
209  {
210  if(HasSfxItemSet())
211  {
212  // The SfxItemSet has been cloned and exists,
213  // we can directly set the SfxStyleSheet at it
214  ImpAddStyleSheet(pTargetStyleSheet, true);
215  }
216  else
217  {
218  // No SfxItemSet exists yet (there is none in
219  // the source, so none was cloned). Remember the
220  // SfxStyleSheet to set it when the SfxItemSet
221  // got constructed on-demand
222  mpStyleSheet = pTargetStyleSheet;
223  }
224  }
225  }
226 
228  {
230  }
231 
232  std::unique_ptr<BaseProperties> AttributeProperties::Clone(SdrObject& rObj) const
233  {
234  return std::unique_ptr<BaseProperties>(new AttributeProperties(*this, rObj));
235  }
236 
238  {
239  // remember if we had a SfxItemSet already
240  const bool bHadSfxItemSet(HasSfxItemSet());
241 
242  // call parent - this will guarantee SfxItemSet existence
244 
245  if(!bHadSfxItemSet)
246  {
247  // need to take care for SfxStyleSheet for newly
248  // created SfxItemSet
249  if(nullptr == mpStyleSheet)
250  {
251  // Set missing defaults without removal of hard attributes.
252  // This is more complicated historically than I first thought:
253  // Originally for GetDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj
254  // SetStyleSheet(..., false) was used, while for GetDefaultStyleSheet
255  // SetStyleSheet(..., true) was used. Thus, for SdrGrafObj and SdrOle2Obj
256  // bDontRemoveHardAttr == false -> *do* delete hard attributes was used.
257  // This was probably not done by purpose, adding the method
258  // GetDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj additionally to
259  // GetDefaultStyleSheet was an enhancement to allow for SdrGrafObj/SdrOle2Obj
260  // with full AttributeSet (adding e.g. FillAttributes). To stay as compatible
261  // as possible these SdrObjects got a new default-StyleSheet.
262  // There is no reason to delete the HardAttributes and it anyways has only
263  // AFAIK effects on a single Item - the SdrTextHorzAdjustItem. To get things
264  // unified I will stay with not deleting the HardAttributes and adapt the
265  // UnitTests in CppunitTest_sd_import_tests accordingly.
267  }
268  else
269  {
270  // Late-Init of setting parent to SfxStyleSheet after
271  // it's creation. Can only happen from copy-constructor
272  // (where creation of SfxItemSet is avoided due to the
273  // problem with constructors and virtual functions in C++),
274  // thus DontRemoveHardAttr is not needed.
275  const_cast< AttributeProperties* >(this)->SetStyleSheet(
276  mpStyleSheet,
277  true);
278  }
279  }
280 
281  return *mpItemSet;
282  }
283 
285  {
286  // own modifications
287  SdrObject& rObj = GetSdrObject();
288 
289  rObj.SetBoundRectDirty();
290  rObj.SetRectsDirty(true);
291  rObj.SetChanged();
292  }
293 
294  void AttributeProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem)
295  {
296  if(pNewItem)
297  {
298  std::unique_ptr<SfxPoolItem> pResultItem;
299  SdrModel& rModel(GetSdrObject().getSdrModelFromSdrObject());
300 
301  switch( nWhich )
302  {
303  case XATTR_FILLBITMAP:
304  {
305  // TTTT checkForUniqueItem should use SdrModel&
306  pResultItem = static_cast<const XFillBitmapItem*>(pNewItem)->checkForUniqueItem( &rModel );
307  break;
308  }
309  case XATTR_LINEDASH:
310  {
311  pResultItem = static_cast<const XLineDashItem*>(pNewItem)->checkForUniqueItem( &rModel );
312  break;
313  }
314  case XATTR_LINESTART:
315  {
316  pResultItem = static_cast<const XLineStartItem*>(pNewItem)->checkForUniqueItem( &rModel );
317  break;
318  }
319  case XATTR_LINEEND:
320  {
321  pResultItem = static_cast<const XLineEndItem*>(pNewItem)->checkForUniqueItem( &rModel );
322  break;
323  }
324  case XATTR_FILLGRADIENT:
325  {
326  pResultItem = static_cast<const XFillGradientItem*>(pNewItem)->checkForUniqueItem( &rModel );
327  break;
328  }
330  {
331  // #85953# allow all kinds of XFillFloatTransparenceItem to be set
332  pResultItem = static_cast<const XFillFloatTransparenceItem*>(pNewItem)->checkForUniqueItem( &rModel );
333  break;
334  }
335  case XATTR_FILLHATCH:
336  {
337  pResultItem = static_cast<const XFillHatchItem*>(pNewItem)->checkForUniqueItem( &rModel );
338  break;
339  }
340  }
341 
342  // guarantee SfxItemSet existence
344 
345  if(pResultItem)
346  {
347  // force ItemSet
348  mpItemSet->Put(*pResultItem);
349 
350  // delete item if it was a generated one
351  pResultItem.reset();
352  }
353  else
354  {
355  mpItemSet->Put(*pNewItem);
356  }
357  }
358  else
359  {
360  // clear item if ItemSet exists
361  if(HasSfxItemSet())
362  {
363  mpItemSet->ClearItem(nWhich);
364  }
365  }
366  }
367 
368  void AttributeProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr)
369  {
370  // guarantee SfxItemSet existence
372 
374  ImpAddStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
375 
376  SdrObject& rObj = GetSdrObject();
377  rObj.SetBoundRectDirty();
378  rObj.SetRectsDirty(true);
379  }
380 
382  {
383  return mpStyleSheet;
384  }
385 
387  {
388  if(!GetStyleSheet() || dynamic_cast<const SfxStyleSheet *>(mpStyleSheet) == nullptr)
389  return;
390 
391  // guarantee SfxItemSet existence
393 
394  // prepare copied, new itemset, but WITHOUT parent
395  SfxItemSet* pDestItemSet = new SfxItemSet(*mpItemSet);
396  pDestItemSet->SetParent(nullptr);
397 
398  // prepare forgetting the current stylesheet like in RemoveStyleSheet()
401 
402  // prepare the iter; use the mpObjectItemSet which may have less
403  // WhichIDs than the style.
404  SfxWhichIter aIter(*pDestItemSet);
405  sal_uInt16 nWhich(aIter.FirstWhich());
406  const SfxPoolItem *pItem = nullptr;
407 
408  // now set all hard attributes of the current at the new itemset
409  while(nWhich)
410  {
411  // #i61284# use mpItemSet with parents, makes things easier and reduces to
412  // one loop
413  if(SfxItemState::SET == mpItemSet->GetItemState(nWhich, true, &pItem))
414  {
415  pDestItemSet->Put(*pItem);
416  }
417 
418  nWhich = aIter.NextWhich();
419  }
420 
421  // replace itemsets
422  mpItemSet.reset(pDestItemSet);
423 
424  // set necessary changes like in RemoveStyleSheet()
426  GetSdrObject().SetRectsDirty(true);
427 
428  mpStyleSheet = nullptr;
429  }
430 
432  {
433  bool bHintUsed(false);
434 
435  const SfxStyleSheetHint* pStyleHint = dynamic_cast<const SfxStyleSheetHint*>(&rHint);
436 
437  if(pStyleHint && pStyleHint->GetStyleSheet() == GetStyleSheet())
438  {
439  SdrObject& rObj = GetSdrObject();
440  //SdrPage* pPage = rObj.GetPage();
441 
442  switch(pStyleHint->GetId())
443  {
444  case SfxHintId::StyleSheetCreated :
445  {
446  // cannot happen, nothing to do
447  break;
448  }
449  case SfxHintId::StyleSheetModified :
450  case SfxHintId::StyleSheetChanged :
451  {
452  // notify change
453  break;
454  }
455  case SfxHintId::StyleSheetErased :
456  case SfxHintId::StyleSheetInDestruction :
457  {
458  // Style needs to be exchanged
459  SfxStyleSheet* pNewStSh = nullptr;
460  SdrModel& rModel(rObj.getSdrModelFromSdrObject());
461 
462  // Do nothing if object is in destruction, else a StyleSheet may be found from
463  // a StyleSheetPool which is just being deleted itself. and thus it would be fatal
464  // to register as listener to that new StyleSheet.
465  if(!rObj.IsInDestruction())
466  {
467  if(dynamic_cast<const SfxStyleSheet *>(GetStyleSheet()) != nullptr)
468  {
469  pNewStSh = static_cast<SfxStyleSheet*>(rModel.GetStyleSheetPool()->Find(
470  GetStyleSheet()->GetParent(), GetStyleSheet()->GetFamily()));
471  }
472 
473  if(!pNewStSh)
474  {
475  pNewStSh = rModel.GetDefaultStyleSheet();
476  }
477  }
478 
479  // remove used style, it's erased or in destruction
481 
482  if(pNewStSh)
483  {
484  ImpAddStyleSheet(pNewStSh, true);
485  }
486 
487  break;
488  }
489  default: break;
490  }
491 
492  // Get old BoundRect. Do this after the style change is handled
493  // in the ItemSet parts because GetBoundRect() may calculate a new
494  tools::Rectangle aBoundRect = rObj.GetLastBoundRect();
495 
496  rObj.SetRectsDirty(true);
497 
498  // tell the object about the change
499  rObj.SetChanged();
500  rObj.BroadcastObjectChange();
501 
502  //if(pPage && pPage->IsInserted())
503  //{
504  // rObj.BroadcastObjectChange();
505  //}
506 
507  rObj.SendUserCall(SdrUserCallType::ChangeAttr, aBoundRect);
508 
509  bHintUsed = true;
510  }
511 
512  if(!bHintUsed)
513  {
514  // forward to SdrObject ATM. Not sure if this will be necessary
515  // in the future.
516  GetSdrObject().Notify(rBC, rHint);
517  }
518  }
519 
521  {
522  const SdrObject& rObj(GetSdrObject());
523  if (rObj.IsInserted())
524  {
525  const SdrPage* const pPage(rObj.getSdrPageFromSdrObject());
526  if (pPage && pPage->IsInserted())
527  return true;
528  }
529  return false;
530  }
531 } // end of namespace
532 
533 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual SfxStyleSheet * GetStyleSheet() const override
#define XATTR_FILLHATCH
Definition: xdef.hxx:110
bool IsInDestruction() const
Definition: svdobj.cxx:2967
virtual bool isUsedByModel() const override
virtual const SfxItemSet & GetObjectItemSet() const override
#define XATTR_FILLGRADIENT
Definition: xdef.hxx:109
bool IsInserted() const
Definition: svdobj.hxx:792
virtual void SetBoundRectDirty()
Definition: svdobj.cxx:334
#define XATTR_FILLFLOATTRANSPARENCE
Definition: xdef.hxx:118
sal_uInt16 FirstWhich()
virtual const SfxItemSet & GetObjectItemSet() const override
#define SDRATTR_MISC_LAST
Definition: svddef.hxx:220
virtual SfxItemSet & GetItemSet()
std::unique_ptr< SfxItemSet > mpItemSet
SfxHintId GetId() const
sal_uInt16 NextWhich()
SfxStyleSheetBase * GetStyleSheet() const
const OUString & GetName() const
void ImpAddStyleSheet(SfxStyleSheet *pNewStyleSheet, bool bDontRemoveHardAttr)
SdrPage * getSdrPageFromSdrObject() const
Definition: svdobj.cxx:287
#define SDRATTR_SHADOW_LAST
Definition: svddef.hxx:178
virtual void SetStyleSheet(SfxStyleSheet *pNewStyleSheet, bool bDontRemoveHardAttr) override
SfxStyleSheetBasePool * GetPool()
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
#define DBG_ASSERT(sCon, aError)
void BroadcastObjectChange() const
Definition: svdobj.cxx:929
#define SDRATTR_MISC_FIRST
Definition: svddef.hxx:193
SdrModel & getSdrModelFromSdrObject() const
Definition: svdobj.cxx:297
#define SDRATTR_TEXTDIRECTION
Definition: svddef.hxx:302
virtual std::unique_ptr< BaseProperties > Clone(SdrObject &rObj) const override
#define SDRATTR_START
Definition: svddef.hxx:168
void StartListening(SfxBroadcaster &rBroadcaster, DuplicateHandling eDuplicateHanding=DuplicateHandling::Unexpected)
Abstract DrawObject.
Definition: svdobj.hxx:312
#define XATTR_LINEDASH
Definition: xdef.hxx:91
virtual void ItemSetChanged(const SfxItemSet &rSet) override
virtual void applyDefaultStyleSheetFromSdrModel()
Definition: properties.cxx:45
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
void SetParent(const SfxItemSet *pNew)
virtual const tools::Rectangle & GetLastBoundRect() const
Definition: svdobj.cxx:892
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint)
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
virtual void ForceStyleToHardAttributes() override
virtual std::unique_ptr< SfxItemSet > CreateObjectSpecificItemSet(SfxItemPool &pPool) override
#define XATTR_LINEEND
Definition: xdef.hxx:95
SfxStyleSheetBasePool * GetStyleSheetPool() const
Definition: svdmodel.hxx:538
void EndListening(SfxBroadcaster &rBroadcaster, bool bRemoveAllDuplicates=false)
virtual void SetRectsDirty(bool bNotMyself=false, bool bRecursive=true)
Definition: svdobj.cxx:459
#define XATTR_FILLBITMAP
Definition: xdef.hxx:111
const SdrObject & GetSdrObject() const
Definition: properties.cxx:60
A SdrPage contains exactly one SdrObjList and a description of the physical page dimensions (size / m...
Definition: svdpage.hxx:366
void ImpSetParentAtSfxItemSet(bool bDontRemoveHardAttr)
virtual void SetChanged()
Definition: svdobj.cxx:953
virtual void ItemChange(const sal_uInt16 nWhich, const SfxPoolItem *pNewItem=nullptr) override
void SendUserCall(SdrUserCallType eUserCall, const tools::Rectangle &rBoundRect) const
Definition: svdobj.cxx:2673
#define XATTR_LINESTART
Definition: xdef.hxx:94