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
48 {
49  namespace properties
50  {
51  void AttributeProperties::ImpSetParentAtSfxItemSet(bool bDontRemoveHardAttr)
52  {
54  {
55  // Delete hard attributes where items are set in the style sheet
56  if(!bDontRemoveHardAttr)
57  {
58  const SfxItemSet& rStyle = mpStyleSheet->GetItemSet();
59  SfxWhichIter aIter(rStyle);
60  sal_uInt16 nWhich = aIter.FirstWhich();
61 
62  while(nWhich)
63  {
64  if(SfxItemState::SET == rStyle.GetItemState(nWhich))
65  {
66  mpItemSet->ClearItem(nWhich);
67  }
68 
69  nWhich = aIter.NextWhich();
70  }
71  }
72 
73  // set new stylesheet as parent
74  mpItemSet->SetParent(&mpStyleSheet->GetItemSet());
75  }
76  else
77  {
78  OSL_ENSURE(false, "ImpSetParentAtSfxItemSet called without SfxItemSet/SfxStyleSheet (!)");
79  }
80  }
81 
82  void AttributeProperties::ImpAddStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr)
83  {
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 (!)");
87 
88  if(pNewStyleSheet)
89  {
90  // local remember
91  mpStyleSheet = pNewStyleSheet;
92 
93  if(HasSfxItemSet())
94  {
95  // register as listener
96  StartListening(*pNewStyleSheet->GetPool());
97  StartListening(*pNewStyleSheet);
98 
99  // only apply the following when we have an SfxItemSet already, else
100  if(GetStyleSheet())
101  {
102  ImpSetParentAtSfxItemSet(bDontRemoveHardAttr);
103  }
104  }
105  }
106  }
107 
109  {
110  // Check type since it is destroyed when the type is deleted
111  if(GetStyleSheet() && dynamic_cast<const SfxStyleSheet *>(mpStyleSheet) != nullptr)
112  {
114  if (auto const pool = mpStyleSheet->GetPool()) { // TTTT
115  EndListening(*pool);
116  }
117 
118  // reset parent of ItemSet
119  if(HasSfxItemSet())
120  {
121  mpItemSet->SetParent(nullptr);
122  }
123 
124  SdrObject& rObj = GetSdrObject();
125  rObj.SetBoundRectDirty();
126  rObj.SetRectsDirty(true);
127  }
128 
129  mpStyleSheet = nullptr;
130  }
131 
132  // create a new itemset
134  {
135  return std::make_unique<SfxItemSet>(rPool,
136 
137  // ranges from SdrAttrObj
140  SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION>{});
141  }
142 
144  : DefaultProperties(rObj),
145  mpStyleSheet(nullptr)
146  {
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.
152  }
153 
155  : DefaultProperties(rProps, rObj),
156  mpStyleSheet(nullptr)
157  {
158  SfxStyleSheet* pTargetStyleSheet(rProps.GetStyleSheet());
159 
160  if(pTargetStyleSheet)
161  {
162  const bool bModelChange(&rObj.getSdrModelFromSdrObject() != &rProps.GetSdrObject().getSdrModelFromSdrObject());
163 
164  if(bModelChange)
165  {
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;
184 
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());
196 
197  if(nullptr != pTargetStyleSheetPool)
198  {
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));
206  }
207  }
208  }
209 
210  if(pTargetStyleSheet)
211  {
212  if(HasSfxItemSet())
213  {
214  // The SfxItemSet has been cloned and exists,
215  // we can directly set the SfxStyleSheet at it
216  ImpAddStyleSheet(pTargetStyleSheet, true);
217  }
218  else
219  {
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;
225  }
226  }
227  }
228 
230  {
232  }
233 
234  std::unique_ptr<BaseProperties> AttributeProperties::Clone(SdrObject& rObj) const
235  {
236  return std::unique_ptr<BaseProperties>(new AttributeProperties(*this, rObj));
237  }
238 
240  {
241  // remember if we had a SfxItemSet already
242  const bool bHadSfxItemSet(HasSfxItemSet());
243 
244  // call parent - this will guarantee SfxItemSet existence
246 
247  if(!bHadSfxItemSet)
248  {
249  // need to take care for SfxStyleSheet for newly
250  // created SfxItemSet
251  if(nullptr == mpStyleSheet)
252  {
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.
269  }
270  else
271  {
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);
280  }
281  }
282 
283  return *mpItemSet;
284  }
285 
287  {
288  // own modifications
289  SdrObject& rObj = GetSdrObject();
290 
291  rObj.SetBoundRectDirty();
292  rObj.SetRectsDirty(true);
293  rObj.SetChanged();
294  }
295 
296  void AttributeProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem)
297  {
298  if(pNewItem)
299  {
300  std::unique_ptr<SfxPoolItem> pResultItem;
301  SdrModel& rModel(GetSdrObject().getSdrModelFromSdrObject());
302 
303  switch( nWhich )
304  {
305  case XATTR_FILLBITMAP:
306  {
307  // TTTT checkForUniqueItem should use SdrModel&
308  pResultItem = static_cast<const XFillBitmapItem*>(pNewItem)->checkForUniqueItem( &rModel );
309  break;
310  }
311  case XATTR_LINEDASH:
312  {
313  pResultItem = static_cast<const XLineDashItem*>(pNewItem)->checkForUniqueItem( &rModel );
314  break;
315  }
316  case XATTR_LINESTART:
317  {
318  pResultItem = static_cast<const XLineStartItem*>(pNewItem)->checkForUniqueItem( &rModel );
319  break;
320  }
321  case XATTR_LINEEND:
322  {
323  pResultItem = static_cast<const XLineEndItem*>(pNewItem)->checkForUniqueItem( &rModel );
324  break;
325  }
326  case XATTR_FILLGRADIENT:
327  {
328  pResultItem = static_cast<const XFillGradientItem*>(pNewItem)->checkForUniqueItem( &rModel );
329  break;
330  }
332  {
333  // #85953# allow all kinds of XFillFloatTransparenceItem to be set
334  pResultItem = static_cast<const XFillFloatTransparenceItem*>(pNewItem)->checkForUniqueItem( &rModel );
335  break;
336  }
337  case XATTR_FILLHATCH:
338  {
339  pResultItem = static_cast<const XFillHatchItem*>(pNewItem)->checkForUniqueItem( &rModel );
340  break;
341  }
342  }
343 
344  // guarantee SfxItemSet existence
346 
347  if(pResultItem)
348  {
349  // force ItemSet
350  mpItemSet->Put(*pResultItem);
351 
352  // delete item if it was a generated one
353  pResultItem.reset();
354  }
355  else
356  {
357  mpItemSet->Put(*pNewItem);
358  }
359  }
360  else
361  {
362  // clear item if ItemSet exists
363  if(HasSfxItemSet())
364  {
365  mpItemSet->ClearItem(nWhich);
366  }
367  }
368  }
369 
370  void AttributeProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr)
371  {
372  // guarantee SfxItemSet existence
374 
376  ImpAddStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
377 
378  SdrObject& rObj = GetSdrObject();
379  rObj.SetBoundRectDirty();
380  rObj.SetRectsDirty(true);
381  }
382 
384  {
385  return mpStyleSheet;
386  }
387 
389  {
390  if(!GetStyleSheet() || dynamic_cast<const SfxStyleSheet *>(mpStyleSheet) == nullptr)
391  return;
392 
393  // guarantee SfxItemSet existence
395 
396  // prepare copied, new itemset, but WITHOUT parent
397  SfxItemSet* pDestItemSet = new SfxItemSet(*mpItemSet);
398  pDestItemSet->SetParent(nullptr);
399 
400  // prepare forgetting the current stylesheet like in RemoveStyleSheet()
403 
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;
409 
410  // now set all hard attributes of the current at the new itemset
411  while(nWhich)
412  {
413  // #i61284# use mpItemSet with parents, makes things easier and reduces to
414  // one loop
415  if(SfxItemState::SET == mpItemSet->GetItemState(nWhich, true, &pItem))
416  {
417  pDestItemSet->Put(*pItem);
418  }
419 
420  nWhich = aIter.NextWhich();
421  }
422 
423  // replace itemsets
424  mpItemSet.reset(pDestItemSet);
425 
426  // set necessary changes like in RemoveStyleSheet()
428  GetSdrObject().SetRectsDirty(true);
429 
430  mpStyleSheet = nullptr;
431  }
432 
434  {
435  bool bHintUsed(false);
436 
437  const SfxStyleSheetHint* pStyleHint = dynamic_cast<const SfxStyleSheetHint*>(&rHint);
438 
439  if(pStyleHint && pStyleHint->GetStyleSheet() == GetStyleSheet())
440  {
441  SdrObject& rObj = GetSdrObject();
442  //SdrPage* pPage = rObj.GetPage();
443 
444  switch(pStyleHint->GetId())
445  {
446  case SfxHintId::StyleSheetCreated :
447  {
448  // cannot happen, nothing to do
449  break;
450  }
451  case SfxHintId::StyleSheetModified :
452  case SfxHintId::StyleSheetChanged :
453  {
454  // notify change
455  break;
456  }
457  case SfxHintId::StyleSheetErased :
458  case SfxHintId::StyleSheetInDestruction :
459  {
460  // Style needs to be exchanged
461  SfxStyleSheet* pNewStSh = nullptr;
462  SdrModel& rModel(rObj.getSdrModelFromSdrObject());
463 
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())
468  {
469  if(dynamic_cast<const SfxStyleSheet *>(GetStyleSheet()) != nullptr)
470  {
471  pNewStSh = static_cast<SfxStyleSheet*>(rModel.GetStyleSheetPool()->Find(
472  GetStyleSheet()->GetParent(), GetStyleSheet()->GetFamily()));
473  }
474 
475  if(!pNewStSh)
476  {
477  pNewStSh = rModel.GetDefaultStyleSheet();
478  }
479  }
480 
481  // remove used style, it's erased or in destruction
483 
484  if(pNewStSh)
485  {
486  ImpAddStyleSheet(pNewStSh, true);
487  }
488 
489  break;
490  }
491  default: break;
492  }
493 
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();
497 
498  rObj.SetRectsDirty(true);
499 
500  // tell the object about the change
501  rObj.SetChanged();
502  rObj.BroadcastObjectChange();
503 
504  //if(pPage && pPage->IsInserted())
505  //{
506  // rObj.BroadcastObjectChange();
507  //}
508 
509  rObj.SendUserCall(SdrUserCallType::ChangeAttr, aBoundRect);
510 
511  bHintUsed = true;
512  }
513 
514  if(!bHintUsed)
515  {
516  // forward to SdrObject ATM. Not sure if this will be necessary
517  // in the future.
518  GetSdrObject().Notify(rBC, rHint);
519  }
520  }
521 
523  {
524  const SdrObject& rObj(GetSdrObject());
525  if (rObj.IsInserted())
526  {
527  const SdrPage* const pPage(rObj.getSdrPageFromSdrObject());
528  if (pPage && pPage->IsInserted())
529  return true;
530  }
531  return false;
532  }
533  } // end of namespace properties
534 } // end of namespace sdr
535 
536 /* 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:2970
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:336
#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:289
#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:932
#define SDRATTR_MISC_FIRST
Definition: svddef.hxx:193
SdrModel & getSdrModelFromSdrObject() const
Definition: svdobj.cxx:299
#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:47
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
void SetParent(const SfxItemSet *pNew)
virtual const tools::Rectangle & GetLastBoundRect() const
Definition: svdobj.cxx:895
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:462
#define XATTR_FILLBITMAP
Definition: xdef.hxx:111
const SdrObject & GetSdrObject() const
Definition: properties.cxx:62
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:956
virtual void ItemChange(const sal_uInt16 nWhich, const SfxPoolItem *pNewItem=nullptr) override
void SendUserCall(SdrUserCallType eUserCall, const tools::Rectangle &rBoundRect) const
Definition: svdobj.cxx:2676
#define XATTR_LINESTART
Definition: xdef.hxx:94