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
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>
40
41namespace sdr::properties
42{
43 void AttributeProperties::ImpSetParentAtSfxItemSet(bool bDontRemoveHardAttr)
44 {
46 {
47 // Delete hard attributes where items are set in the style sheet
48 if(!bDontRemoveHardAttr)
49 {
50 const SfxItemSet& rStyle = mpStyleSheet->GetItemSet();
51 SfxWhichIter aIter(rStyle);
52 sal_uInt16 nWhich = aIter.FirstWhich();
53
54 while(nWhich)
55 {
56 if(SfxItemState::SET == aIter.GetItemState())
57 {
58 mxItemSet->ClearItem(nWhich);
59 }
60
61 nWhich = aIter.NextWhich();
62 }
63 }
64
65 // set new stylesheet as parent
66 mxItemSet->SetParent(&mpStyleSheet->GetItemSet());
67 }
68 else
69 {
70 OSL_ENSURE(false, "ImpSetParentAtSfxItemSet called without SfxItemSet/SfxStyleSheet (!)");
71 }
72 }
73
74 void AttributeProperties::ImpAddStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr)
75 {
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 (!)");
79
80 if(!pNewStyleSheet)
81 return;
82
83 // local remember
84 mpStyleSheet = pNewStyleSheet;
85
86 if(HasSfxItemSet())
87 {
88 // register as listener
89 StartListening(*pNewStyleSheet->GetPool());
90 StartListening(*pNewStyleSheet);
91
92 // only apply the following when we have an SfxItemSet already, else
93 if(GetStyleSheet())
94 {
95 ImpSetParentAtSfxItemSet(bDontRemoveHardAttr);
96 }
97 }
98 }
99
101 {
102 // Check type since it is destroyed when the type is deleted
104 {
106 if (auto const pool = mpStyleSheet->GetPool()) { // TTTT
107 EndListening(*pool);
108 }
109
110 // reset parent of ItemSet
111 if(HasSfxItemSet())
112 {
113 mxItemSet->SetParent(nullptr);
114 }
115
116 SdrObject& rObj = GetSdrObject();
117 rObj.SetBoundRectDirty();
118 rObj.SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
119 }
120
121 mpStyleSheet = nullptr;
122 }
123
124 // create a new itemset
126 {
127 return SfxItemSet(rPool,
128
129 // ranges from SdrAttrObj
134 }
135
137 : DefaultProperties(rObj),
138 mpStyleSheet(nullptr)
139 {
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.
145 }
146
148 : DefaultProperties(rProps, rObj),
149 mpStyleSheet(nullptr)
150 {
151 SfxStyleSheet* pTargetStyleSheet(rProps.GetStyleSheet());
152
153 if(pTargetStyleSheet)
154 {
155 const bool bModelChange(&rObj.getSdrModelFromSdrObject() != &rProps.GetSdrObject().getSdrModelFromSdrObject());
156
157 if(bModelChange)
158 {
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;
177
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.
189
190 if(nullptr != pTargetStyleSheetPool)
191 {
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));
199 }
200 }
201 }
202
203 if(!pTargetStyleSheet)
204 return;
205
206 if(HasSfxItemSet())
207 {
208 // The SfxItemSet has been cloned and exists,
209 // we can directly set the SfxStyleSheet at it
210 ImpAddStyleSheet(pTargetStyleSheet, true);
211 }
212 else
213 {
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;
219 }
220 }
221
223 {
225 }
226
227 std::unique_ptr<BaseProperties> AttributeProperties::Clone(SdrObject& rObj) const
228 {
229 return std::unique_ptr<BaseProperties>(new AttributeProperties(*this, rObj));
230 }
231
233 {
234 // remember if we had a SfxItemSet already
235 const bool bHadSfxItemSet(HasSfxItemSet());
236
237 // call parent - this will guarantee SfxItemSet existence
239
240 if(!bHadSfxItemSet)
241 {
242 // need to take care for SfxStyleSheet for newly
243 // created SfxItemSet
244 if(nullptr == mpStyleSheet)
245 {
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.
262 }
263 else
264 {
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, true, true);
272 }
273 }
274
275 return *mxItemSet;
276 }
277
278 void AttributeProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > /*aChangedItems*/, sal_uInt16 /*nDeletedWhich*/)
279 {
280 // own modifications
281 SdrObject& rObj = GetSdrObject();
282
283 rObj.SetBoundRectDirty();
284 rObj.SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
285 rObj.SetChanged();
286 }
287
288 void AttributeProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem)
289 {
290 if(pNewItem)
291 {
292 std::unique_ptr<SfxPoolItem> pResultItem;
293 SdrModel& rModel(GetSdrObject().getSdrModelFromSdrObject());
294
295 switch( nWhich )
296 {
297 case XATTR_FILLBITMAP:
298 {
299 // TTTT checkForUniqueItem should use SdrModel&
300 pResultItem = static_cast<const XFillBitmapItem*>(pNewItem)->checkForUniqueItem( &rModel );
301 break;
302 }
303 case XATTR_LINEDASH:
304 {
305 pResultItem = static_cast<const XLineDashItem*>(pNewItem)->checkForUniqueItem( &rModel );
306 break;
307 }
308 case XATTR_LINESTART:
309 {
310 pResultItem = static_cast<const XLineStartItem*>(pNewItem)->checkForUniqueItem( &rModel );
311 break;
312 }
313 case XATTR_LINEEND:
314 {
315 pResultItem = static_cast<const XLineEndItem*>(pNewItem)->checkForUniqueItem( &rModel );
316 break;
317 }
319 {
320 pResultItem = static_cast<const XFillGradientItem*>(pNewItem)->checkForUniqueItem( &rModel );
321 break;
322 }
324 {
325 // #85953# allow all kinds of XFillFloatTransparenceItem to be set
326 pResultItem = static_cast<const XFillFloatTransparenceItem*>(pNewItem)->checkForUniqueItem( &rModel );
327 break;
328 }
329 case XATTR_FILLHATCH:
330 {
331 pResultItem = static_cast<const XFillHatchItem*>(pNewItem)->checkForUniqueItem( &rModel );
332 break;
333 }
334 }
335
336 // guarantee SfxItemSet existence
338
339 if(pResultItem)
340 {
341 // force ItemSet
342 mxItemSet->Put(std::move(pResultItem));
343 }
344 else
345 {
346 mxItemSet->Put(*pNewItem);
347 }
348 }
349 else
350 {
351 // clear item if ItemSet exists
352 if(HasSfxItemSet())
353 {
354 mxItemSet->ClearItem(nWhich);
355 }
356 }
357 }
358
359 void AttributeProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
360 bool /*bBroadcast*/)
361 {
362 // guarantee SfxItemSet existence
364
366 ImpAddStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
367
368 SdrObject& rObj = GetSdrObject();
369 rObj.SetBoundRectDirty();
370 rObj.SetBoundAndSnapRectsDirty(true);
371 }
372
374 {
375 return mpStyleSheet;
376 }
377
379 {
380 if(!GetStyleSheet() || mpStyleSheet == nullptr)
381 return;
382
383 // guarantee SfxItemSet existence
385
386 // prepare copied, new itemset, but WITHOUT parent
387 SfxItemSet aDestItemSet(*mxItemSet);
388 aDestItemSet.SetParent(nullptr);
389
390 // prepare forgetting the current stylesheet like in RemoveStyleSheet()
393
394 // prepare the iter; use the mpObjectItemSet which may have less
395 // WhichIDs than the style.
396 SfxWhichIter aIter(aDestItemSet);
397 sal_uInt16 nWhich(aIter.FirstWhich());
398 const SfxPoolItem *pItem = nullptr;
399
400 // now set all hard attributes of the current at the new itemset
401 while(nWhich)
402 {
403 // #i61284# use mpItemSet with parents, makes things easier and reduces to
404 // one loop
405 if(SfxItemState::SET == mxItemSet->GetItemState(nWhich, true, &pItem))
406 {
407 aDestItemSet.Put(*pItem);
408 }
409
410 nWhich = aIter.NextWhich();
411 }
412
413 // replace itemsets
414 mxItemSet.emplace(std::move(aDestItemSet));
415
416 // set necessary changes like in RemoveStyleSheet()
418 GetSdrObject().SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
419
420 mpStyleSheet = nullptr;
421 }
422
424 {
425 bool bHintUsed(false);
426
427 const SfxStyleSheetHint* pStyleHint = dynamic_cast<const SfxStyleSheetHint*>(&rHint);
428
429 if(pStyleHint && pStyleHint->GetStyleSheet() == GetStyleSheet())
430 {
431 SdrObject& rObj = GetSdrObject();
432 //SdrPage* pPage = rObj.GetPage();
433
434 switch(pStyleHint->GetId())
435 {
436 case SfxHintId::StyleSheetCreated :
437 {
438 // cannot happen, nothing to do
439 break;
440 }
441 case SfxHintId::StyleSheetModified :
442 case SfxHintId::StyleSheetChanged :
443 {
444 // notify change
445 break;
446 }
447 case SfxHintId::StyleSheetErased :
448 case SfxHintId::StyleSheetInDestruction :
449 {
450 // Style needs to be exchanged
451 SfxStyleSheet* pNewStSh = nullptr;
452 SdrModel& rModel(rObj.getSdrModelFromSdrObject());
453
454 // Do nothing if object is in destruction, else a StyleSheet may be found from
455 // a StyleSheetPool which is just being deleted itself. and thus it would be fatal
456 // to register as listener to that new StyleSheet.
457 if(!rObj.IsInDestruction())
458 {
459 if(SfxStyleSheet* pStyleSheet = GetStyleSheet())
460 {
461 pNewStSh = static_cast<SfxStyleSheet*>(rModel.GetStyleSheetPool()->Find(
462 pStyleSheet->GetParent(), pStyleSheet->GetFamily()));
463 }
464
465 if(!pNewStSh)
466 {
467 pNewStSh = rModel.GetDefaultStyleSheet();
468 }
469 }
470
471 // remove used style, it's erased or in destruction
473
474 if(pNewStSh)
475 {
476 ImpAddStyleSheet(pNewStSh, true);
477 }
478
479 break;
480 }
481 default: break;
482 }
483
484 // Get old BoundRect. Do this after the style change is handled
485 // in the ItemSet parts because GetBoundRect() may calculate a new
486 tools::Rectangle aBoundRect = rObj.GetLastBoundRect();
487
488 rObj.SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
489
490 // tell the object about the change
491 rObj.SetChanged();
493
494 //if(pPage && pPage->IsInserted())
495 //{
496 // rObj.BroadcastObjectChange();
497 //}
498
500
501 bHintUsed = true;
502 }
503
504 if(!bHintUsed)
505 {
506 // forward to SdrObject ATM. Not sure if this will be necessary
507 // in the future.
508 GetSdrObject().Notify(rBC, rHint);
509 }
510 }
511
513 {
514 const SdrObject& rObj(GetSdrObject());
515 if (rObj.IsInserted())
516 {
517 const SdrPage* const pPage(rObj.getSdrPageFromSdrObject());
518 if (pPage && pPage->IsInserted())
519 return true;
520 }
521 return false;
522 }
523
525 {
526 SfxStyleSheet* pDefaultStyleSheet(GetSdrObject().getSdrModelFromSdrObject().GetDefaultStyleSheet());
527
528 // tdf#118139 Only do this when StyleSheet really differs. It may e.g.
529 // be the case that nullptr == pDefaultStyleSheet and there is none set yet,
530 // so indeed no need to set it (needed for some strange old MSWord2003
531 // documents with CustomShape-'Group' and added Text-Frames, see task description)
532 if(pDefaultStyleSheet != GetStyleSheet())
533 {
534 // do not delete hard attributes when setting dsefault Style
535 SetStyleSheet(pDefaultStyleSheet, true, true);
536 }
537 }
538
539} // end of namespace
540
541/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SfxStyleSheet * GetDefaultStyleSheet() const
Definition: svdmodel.hxx:345
SfxStyleSheetBasePool * GetStyleSheetPool() const
Definition: svdmodel.hxx:542
Abstract DrawObject.
Definition: svdobj.hxx:261
void BroadcastObjectChange() const
Definition: svdobj.cxx:978
SdrModel & getSdrModelFromSdrObject() const
Definition: svdobj.cxx:289
void SendUserCall(SdrUserCallType eUserCall, const tools::Rectangle &rBoundRect) const
Definition: svdobj.cxx:2766
virtual void SetChanged()
Definition: svdobj.cxx:1002
virtual const tools::Rectangle & GetLastBoundRect() const
Definition: svdobj.cxx:940
SdrPage * getSdrPageFromSdrObject() const
Definition: svdobj.cxx:279
bool IsInserted() const
Definition: svdobj.hxx:750
bool IsInDestruction() const
Definition: svdobj.cxx:3047
virtual void SetBoundRectDirty()
Definition: svdobj.cxx:329
virtual void SetBoundAndSnapRectsDirty(bool bNotMyself=false, bool bRecursive=true)
Definition: svdobj.cxx:509
A SdrPage contains exactly one SdrObjList and a description of the physical page dimensions (size / m...
Definition: svdpage.hxx:377
bool IsInserted() const
Definition: svdpage.hxx:464
SfxHintId GetId() const
void SetParent(const SfxItemSet *pNew)
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
void StartListening(SfxBroadcaster &rBroadcaster, DuplicateHandling eDuplicateHanding=DuplicateHandling::Unexpected)
void EndListening(SfxBroadcaster &rBroadcaster, bool bRemoveAllDuplicates=false)
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint)
virtual SfxStyleSheetBase * Find(const OUString &, SfxStyleFamily eFam, SfxStyleSearchBits n=SfxStyleSearchBits::All) const
const OUString & GetName() const
virtual SfxItemSet & GetItemSet()
SfxStyleSheetBasePool * GetPool()
SfxStyleSheetBase * GetStyleSheet() const
sal_uInt16 FirstWhich()
SfxItemState GetItemState(bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
sal_uInt16 NextWhich()
void ImpSetParentAtSfxItemSet(bool bDontRemoveHardAttr)
virtual void ItemSetChanged(o3tl::span< const SfxPoolItem *const > aChangedItems, sal_uInt16 nDeletedWhich) override
virtual SfxItemSet CreateObjectSpecificItemSet(SfxItemPool &pPool) override
void ImpAddStyleSheet(SfxStyleSheet *pNewStyleSheet, bool bDontRemoveHardAttr)
virtual std::unique_ptr< BaseProperties > Clone(SdrObject &rObj) const override
virtual void ItemChange(const sal_uInt16 nWhich, const SfxPoolItem *pNewItem=nullptr) override
virtual void ForceStyleToHardAttributes() override
virtual const SfxItemSet & GetObjectItemSet() const override
virtual void SetStyleSheet(SfxStyleSheet *pNewStyleSheet, bool bDontRemoveHardAttr, bool bBroadcast) override
virtual SfxStyleSheet * GetStyleSheet() const override
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
virtual bool isUsedByModel() const override
const SdrObject & GetSdrObject() const
Definition: properties.cxx:43
std::optional< SfxItemSet > mxItemSet
virtual const SfxItemSet & GetObjectItemSet() const override
#define DBG_ASSERT(sCon, aError)
static constexpr auto Items
constexpr sal_uInt16 SDRATTR_START(XATTR_START)
constexpr sal_uInt16 SDRATTR_TEXTCOLUMNS_FIRST(SDRATTR_SOFTEDGE_LAST+1)
constexpr sal_uInt16 SDRATTR_MISC_FIRST(SDRATTR_CAPTION_LAST+1)
constexpr sal_uInt16 SDRATTR_SHADOW_LAST(SDRATTR_SHADOWBLUR)
constexpr sal_uInt16 SDRATTR_MISC_LAST(SDRATTR_TEXT_CHAINNEXTNAME)
constexpr sal_uInt16 SDRATTR_TEXTCOLUMNS_LAST(SDRATTR_TEXTCOLUMNS_SPACING)
constexpr TypedWhichId< SvxWritingModeItem > SDRATTR_TEXTDIRECTION(SDRATTR_NOTPERSIST_FIRST+34)
constexpr TypedWhichId< XLineDashItem > XATTR_LINEDASH(XATTR_LINE_FIRST+1)
constexpr TypedWhichId< XLineEndItem > XATTR_LINEEND(XATTR_LINE_FIRST+5)
constexpr TypedWhichId< XLineStartItem > XATTR_LINESTART(XATTR_LINE_FIRST+4)
constexpr TypedWhichId< XFillHatchItem > XATTR_FILLHATCH(XATTR_FILL_FIRST+3)
constexpr TypedWhichId< XFillBitmapItem > XATTR_FILLBITMAP(XATTR_FILL_FIRST+4)
constexpr TypedWhichId< XFillFloatTransparenceItem > XATTR_FILLFLOATTRANSPARENCE(XATTR_FILL_FIRST+11)
constexpr TypedWhichId< XFillGradientItem > XATTR_FILLGRADIENT(XATTR_FILL_FIRST+2)