tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / svx / source / sdr / properties / attributeproperties.cxx
blob3094eb01a1de6d594f80a4b583050c29d9a51fc8
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/xbtmpit.hxx>
30 #include <svx/xlndsit.hxx>
31 #include <svx/xlnstit.hxx>
32 #include <svx/xlnedit.hxx>
33 #include <svx/xflgrit.hxx>
34 #include <svx/xflftrit.hxx>
35 #include <svx/xflhtit.hxx>
36 #include <svx/svdmodel.hxx>
37 #include <svx/svdpage.hxx>
38 #include <osl/diagnose.h>
40 namespace sdr::properties
42 void AttributeProperties::ImpSetParentAtSfxItemSet(bool bDontRemoveHardAttr)
44 if(HasSfxItemSet() && mpStyleSheet)
46 // Delete hard attributes where items are set in the style sheet
47 if(!bDontRemoveHardAttr)
49 const SfxItemSet& rStyle = mpStyleSheet->GetItemSet();
50 SfxWhichIter aIter(rStyle);
51 sal_uInt16 nWhich = aIter.FirstWhich();
53 while(nWhich)
55 if(SfxItemState::SET == aIter.GetItemState())
57 moItemSet->ClearItem(nWhich);
60 nWhich = aIter.NextWhich();
64 // set new stylesheet as parent
65 moItemSet->SetParent(&mpStyleSheet->GetItemSet());
67 else
69 OSL_ENSURE(false, "ImpSetParentAtSfxItemSet called without SfxItemSet/SfxStyleSheet (!)");
73 void AttributeProperties::ImpAddStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr)
75 // test if old StyleSheet is cleared, else it would be lost
76 // after this method -> memory leak (!)
77 DBG_ASSERT(!mpStyleSheet, "Old style sheet not deleted before setting new one (!)");
79 if(!pNewStyleSheet)
80 return;
82 // local remember
83 mpStyleSheet = pNewStyleSheet;
85 if(HasSfxItemSet())
87 // register as listener
88 StartListening(*pNewStyleSheet->GetPool());
89 StartListening(*pNewStyleSheet);
91 // only apply the following when we have an SfxItemSet already, else
92 if(GetStyleSheet())
94 ImpSetParentAtSfxItemSet(bDontRemoveHardAttr);
99 void AttributeProperties::ImpRemoveStyleSheet()
101 // Check type since it is destroyed when the type is deleted
102 if(GetStyleSheet() && mpStyleSheet)
104 EndListening(*mpStyleSheet);
105 if (auto const pool = mpStyleSheet->GetPool()) { // TTTT
106 EndListening(*pool);
109 // reset parent of ItemSet
110 if(HasSfxItemSet())
112 moItemSet->SetParent(nullptr);
115 SdrObject& rObj = GetSdrObject();
116 rObj.SetBoundRectDirty();
117 rObj.SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
120 mpStyleSheet = nullptr;
123 // create a new itemset
124 SfxItemSet AttributeProperties::CreateObjectSpecificItemSet(SfxItemPool&)
126 assert(false && "this class is effectively abstract, should only be instantiating subclasses");
127 abort();
130 AttributeProperties::AttributeProperties(SdrObject& rObj)
131 : DefaultProperties(rObj),
132 mpStyleSheet(nullptr)
134 // Do nothing else, esp. do *not* try to get and set
135 // a default SfxStyle sheet. Nothing is allowed to be done
136 // that may lead to calls to virtual functions like
137 // CreateObjectSpecificItemSet - these would go *wrong*.
138 // Thus the rest is lazy-init from here.
141 AttributeProperties::AttributeProperties(const AttributeProperties& rProps, SdrObject& rObj)
142 : DefaultProperties(rProps, rObj),
143 mpStyleSheet(nullptr)
145 SfxStyleSheet* pTargetStyleSheet(rProps.GetStyleSheet());
147 if(pTargetStyleSheet)
149 const bool bModelChange(&rObj.getSdrModelFromSdrObject() != &rProps.GetSdrObject().getSdrModelFromSdrObject());
151 if(bModelChange)
153 // tdf#117506
154 // The error shows that it is definitely necessary to solve this problem.
155 // Interestingly I already had a note here for 'work needed'.
156 // Checked in libreoffice-6-0 what happened there. In principle, the whole
157 // ::Clone of SdrPage and SdrObject happened in the same SdrModel, only
158 // afterwards a ::SetModel was used at the cloned SdrPage which went through
159 // all layers. The StyleSheet-problem was solved in
160 // AttributeProperties::MoveToItemPool at the end. There, a StyleSheet with the
161 // same name was searched for in the target-SdrModel.
162 // Start by resetting the current TargetStyleSheet so that nothing goes wrong
163 // when we do not find a fitting TargetStyleSheet.
164 // Note: The test for SdrModelChange above was wrong (compared the already set
165 // new SdrObject), so this never triggered and pTargetStyleSheet was never set to
166 // nullptr before. This means that a StyleSheet from another SdrModel was used
167 // what of course is very dangerous. Interestingly did not crash since when that
168 // other SdrModel was destroyed the ::Notify mechanism still worked reliably
169 // and de-connected this Properties successfully from the alien-StyleSheet.
170 pTargetStyleSheet = nullptr;
172 // Check if we have a TargetStyleSheetPool at the target-SdrModel. This *should*
173 // be the case already (SdrModel::Merge and SdDrawDocument::InsertBookmarkAsPage
174 // have already cloned the StyleSheets to the target-SdrModel when used in Draw/impress).
175 // If none is found, ImpGetDefaultStyleSheet will be used to set a 'default'
176 // StyleSheet as StyleSheet implicitly later (that's what happened in the task,
177 // thus the FillStyle changed to the 'default' Blue).
178 // Note: It *may* be necessary to do more for StyleSheets, e.g. clone/copy the
179 // StyleSheet Hierarchy from the source SdrModel and/or add the Items from there
180 // as hard attributes. If needed, have a look at the older AttributeProperties::SetModel
181 // implementation from e.g. libreoffice-6-0.
182 SfxStyleSheetBasePool* pTargetStyleSheetPool(rObj.getSdrModelFromSdrObject().GetStyleSheetPool());
184 if(nullptr != pTargetStyleSheetPool)
186 // If we have a TargetStyleSheetPool, search for the used StyleSheet
187 // in the target SdrModel using the Name from the original StyleSheet
188 // in the source-SdrModel.
189 pTargetStyleSheet = dynamic_cast< SfxStyleSheet* >(
190 pTargetStyleSheetPool->Find(
191 rProps.GetStyleSheet()->GetName(),
192 rProps.GetStyleSheet()->GetFamily()));
197 if(!pTargetStyleSheet)
198 return;
200 if(HasSfxItemSet())
202 // The SfxItemSet has been cloned and exists,
203 // we can directly set the SfxStyleSheet at it
204 ImpAddStyleSheet(pTargetStyleSheet, true);
206 else
208 // No SfxItemSet exists yet (there is none in
209 // the source, so none was cloned). Remember the
210 // SfxStyleSheet to set it when the SfxItemSet
211 // got constructed on-demand
212 mpStyleSheet = pTargetStyleSheet;
216 AttributeProperties::~AttributeProperties()
218 ImpRemoveStyleSheet();
221 std::unique_ptr<BaseProperties> AttributeProperties::Clone(SdrObject&) const
223 assert(false && "this class is effectively abstract, should only be instantiating subclasses");
224 abort();
227 const SfxItemSet& AttributeProperties::GetObjectItemSet() const
229 // remember if we had a SfxItemSet already
230 const bool bHadSfxItemSet(HasSfxItemSet());
232 // call parent - this will guarantee SfxItemSet existence
233 DefaultProperties::GetObjectItemSet();
235 if(!bHadSfxItemSet)
237 // need to take care for SfxStyleSheet for newly
238 // created SfxItemSet
239 if(nullptr == mpStyleSheet)
241 // Set missing defaults without removal of hard attributes.
242 // This is more complicated historically than I first thought:
243 // Originally for GetDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj
244 // SetStyleSheet(..., false) was used, while for GetDefaultStyleSheet
245 // SetStyleSheet(..., true) was used. Thus, for SdrGrafObj and SdrOle2Obj
246 // bDontRemoveHardAttr == false -> *do* delete hard attributes was used.
247 // This was probably not done by purpose, adding the method
248 // GetDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj additionally to
249 // GetDefaultStyleSheet was an enhancement to allow for SdrGrafObj/SdrOle2Obj
250 // with full AttributeSet (adding e.g. FillAttributes). To stay as compatible
251 // as possible these SdrObjects got a new default-StyleSheet.
252 // There is no reason to delete the HardAttributes and it anyways has only
253 // AFAIK effects on a single Item - the SdrTextHorzAdjustItem. To get things
254 // unified I will stay with not deleting the HardAttributes and adapt the
255 // UnitTests in CppunitTest_sd_import_tests accordingly.
256 const_cast< AttributeProperties* >(this)->applyDefaultStyleSheetFromSdrModel();
258 else
260 // Late-Init of setting parent to SfxStyleSheet after
261 // it's creation. Can only happen from copy-constructor
262 // (where creation of SfxItemSet is avoided due to the
263 // problem with constructors and virtual functions in C++),
264 // thus DontRemoveHardAttr is not needed.
265 const_cast< AttributeProperties* >(this)->SetStyleSheet(
266 mpStyleSheet, true, true);
270 return *moItemSet;
273 void AttributeProperties::ItemSetChanged(std::span< const SfxPoolItem* const > /*aChangedItems*/, sal_uInt16 /*nDeletedWhich*/, bool /*bAdjustTextFrameWidthAndHeight*/)
275 // own modifications
276 SdrObject& rObj = GetSdrObject();
278 rObj.SetBoundRectDirty();
279 rObj.SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
280 rObj.SetChanged();
283 void AttributeProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem)
285 if(pNewItem)
287 std::unique_ptr<SfxPoolItem> pResultItem;
288 SdrModel& rModel(GetSdrObject().getSdrModelFromSdrObject());
290 switch( nWhich )
292 case XATTR_FILLBITMAP:
294 pResultItem = static_cast<const XFillBitmapItem*>(pNewItem)->checkForUniqueItem( rModel );
295 break;
297 case XATTR_LINEDASH:
299 pResultItem = static_cast<const XLineDashItem*>(pNewItem)->checkForUniqueItem( rModel );
300 break;
302 case XATTR_LINESTART:
304 pResultItem = static_cast<const XLineStartItem*>(pNewItem)->checkForUniqueItem( rModel );
305 break;
307 case XATTR_LINEEND:
309 pResultItem = static_cast<const XLineEndItem*>(pNewItem)->checkForUniqueItem( rModel );
310 break;
312 case XATTR_FILLGRADIENT:
314 pResultItem = static_cast<const XFillGradientItem*>(pNewItem)->checkForUniqueItem( rModel );
315 break;
317 case XATTR_FILLFLOATTRANSPARENCE:
319 // #85953# allow all kinds of XFillFloatTransparenceItem to be set
320 pResultItem = static_cast<const XFillFloatTransparenceItem*>(pNewItem)->checkForUniqueItem( rModel );
321 break;
323 case XATTR_FILLHATCH:
325 pResultItem = static_cast<const XFillHatchItem*>(pNewItem)->checkForUniqueItem( rModel );
326 break;
330 // guarantee SfxItemSet existence
331 GetObjectItemSet();
333 if(pResultItem)
335 // force ItemSet
336 moItemSet->Put(std::move(pResultItem));
338 else
340 moItemSet->Put(*pNewItem);
343 else
345 // clear item if ItemSet exists
346 if(HasSfxItemSet())
348 moItemSet->ClearItem(nWhich);
353 void AttributeProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
354 bool /*bBroadcast*/, bool /*bAdjustTextFrameWidthAndHeight*/)
356 // guarantee SfxItemSet existence
357 GetObjectItemSet();
359 ImpRemoveStyleSheet();
360 ImpAddStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
362 SdrObject& rObj = GetSdrObject();
363 rObj.SetBoundRectDirty();
364 rObj.SetBoundAndSnapRectsDirty(true);
367 SfxStyleSheet* AttributeProperties::GetStyleSheet() const
369 return mpStyleSheet;
372 void AttributeProperties::ForceStyleToHardAttributes()
374 if(!GetStyleSheet() || mpStyleSheet == nullptr)
375 return;
377 // guarantee SfxItemSet existence
378 GetObjectItemSet();
380 // prepare copied, new itemset, but WITHOUT parent
381 SfxItemSet aDestItemSet(*moItemSet);
382 aDestItemSet.SetParent(nullptr);
384 // prepare forgetting the current stylesheet like in RemoveStyleSheet()
385 EndListening(*mpStyleSheet);
386 EndListening(*mpStyleSheet->GetPool());
388 // prepare the iter; use the mpObjectItemSet which may have less
389 // WhichIDs than the style.
390 SfxWhichIter aIter(aDestItemSet);
391 sal_uInt16 nWhich(aIter.FirstWhich());
392 const SfxPoolItem *pItem = nullptr;
394 // now set all hard attributes of the current at the new itemset
395 while(nWhich)
397 // #i61284# use mpItemSet with parents, makes things easier and reduces to
398 // one loop
399 if(SfxItemState::SET == moItemSet->GetItemState(nWhich, true, &pItem))
401 aDestItemSet.Put(*pItem);
404 nWhich = aIter.NextWhich();
407 // replace itemsets
408 moItemSet.emplace(std::move(aDestItemSet));
410 // set necessary changes like in RemoveStyleSheet()
411 GetSdrObject().SetBoundRectDirty();
412 GetSdrObject().SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
414 mpStyleSheet = nullptr;
417 void AttributeProperties::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
419 bool bHintUsed(false);
421 SfxHintId id = rHint.GetId();
422 if (id == SfxHintId::StyleSheetChanged
423 || id == SfxHintId::StyleSheetErased
424 || id == SfxHintId::StyleSheetModified
425 || id == SfxHintId::StyleSheetInDestruction
426 || id == SfxHintId::StyleSheetModifiedExtended)
428 const SfxStyleSheetHint* pStyleHint = static_cast<const SfxStyleSheetHint*>(&rHint);
430 if(pStyleHint->GetStyleSheet() == GetStyleSheet())
432 SdrObject& rObj = GetSdrObject();
433 //SdrPage* pPage = rObj.GetPage();
435 switch(id)
437 case SfxHintId::StyleSheetModified :
438 case SfxHintId::StyleSheetModifiedExtended:
439 case SfxHintId::StyleSheetChanged :
441 // notify change
442 break;
444 case SfxHintId::StyleSheetErased :
445 case SfxHintId::StyleSheetInDestruction :
447 // Style needs to be exchanged
448 SfxStyleSheet* pNewStSh = nullptr;
449 SdrModel& rModel(rObj.getSdrModelFromSdrObject());
451 // Do nothing if object is in destruction, else a StyleSheet may be found from
452 // a StyleSheetPool which is just being deleted itself. and thus it would be fatal
453 // to register as listener to that new StyleSheet.
454 if(!rObj.IsInDestruction())
456 if(SfxStyleSheet* pStyleSheet = GetStyleSheet())
458 pNewStSh = static_cast<SfxStyleSheet*>(rModel.GetStyleSheetPool()->Find(
459 pStyleSheet->GetParent(), pStyleSheet->GetFamily()));
462 if(!pNewStSh)
464 pNewStSh = rModel.GetDefaultStyleSheet();
468 // remove used style, it's erased or in destruction
469 ImpRemoveStyleSheet();
471 if(pNewStSh)
473 ImpAddStyleSheet(pNewStSh, true);
476 break;
478 default: break;
481 // Get old BoundRect. Do this after the style change is handled
482 // in the ItemSet parts because GetBoundRect() may calculate a new
483 tools::Rectangle aBoundRect = rObj.GetLastBoundRect();
485 rObj.SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
487 // tell the object about the change
488 rObj.SetChanged();
489 rObj.BroadcastObjectChange();
491 //if(pPage && pPage->IsInserted())
493 // rObj.BroadcastObjectChange();
496 rObj.SendUserCall(SdrUserCallType::ChangeAttr, aBoundRect);
498 bHintUsed = true;
501 if(!bHintUsed)
503 // forward to SdrObject ATM. Not sure if this will be necessary
504 // in the future.
505 GetSdrObject().Notify(rBC, rHint);
509 bool AttributeProperties::isUsedByModel() const
511 const SdrObject& rObj(GetSdrObject());
512 if (rObj.IsInserted())
514 const SdrPage* const pPage(rObj.getSdrPageFromSdrObject());
515 if (pPage && pPage->IsInserted())
516 return true;
518 return false;
521 void AttributeProperties::applyDefaultStyleSheetFromSdrModel()
523 SfxStyleSheet* pDefaultStyleSheet(GetSdrObject().getSdrModelFromSdrObject().GetDefaultStyleSheet());
525 // tdf#118139 Only do this when StyleSheet really differs. It may e.g.
526 // be the case that nullptr == pDefaultStyleSheet and there is none set yet,
527 // so indeed no need to set it (needed for some strange old MSWord2003
528 // documents with CustomShape-'Group' and added Text-Frames, see task description)
529 if(pDefaultStyleSheet != GetStyleSheet())
531 // do not delete hard attributes when setting dsefault Style
532 SetStyleSheet(pDefaultStyleSheet, true, true);
536 } // end of namespace
538 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */