summaryrefslogtreecommitdiffstats
path: root/svx/source/sdr/properties/attributeproperties.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'svx/source/sdr/properties/attributeproperties.cxx')
-rw-r--r--svx/source/sdr/properties/attributeproperties.cxx541
1 files changed, 541 insertions, 0 deletions
diff --git a/svx/source/sdr/properties/attributeproperties.cxx b/svx/source/sdr/properties/attributeproperties.cxx
new file mode 100644
index 000000000..7f141b8f6
--- /dev/null
+++ b/svx/source/sdr/properties/attributeproperties.cxx
@@ -0,0 +1,541 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sdr/properties/attributeproperties.hxx>
+#include <tools/debug.hxx>
+#include <svl/itemset.hxx>
+#include <svl/style.hxx>
+#include <svl/whiter.hxx>
+#include <svl/poolitem.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svddef.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xlndsit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/xflftrit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <osl/diagnose.h>
+
+namespace sdr::properties
+{
+ void AttributeProperties::ImpSetParentAtSfxItemSet(bool bDontRemoveHardAttr)
+ {
+ if(HasSfxItemSet() && mpStyleSheet)
+ {
+ // Delete hard attributes where items are set in the style sheet
+ if(!bDontRemoveHardAttr)
+ {
+ const SfxItemSet& rStyle = mpStyleSheet->GetItemSet();
+ SfxWhichIter aIter(rStyle);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+
+ while(nWhich)
+ {
+ if(SfxItemState::SET == aIter.GetItemState())
+ {
+ mxItemSet->ClearItem(nWhich);
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+ }
+
+ // set new stylesheet as parent
+ mxItemSet->SetParent(&mpStyleSheet->GetItemSet());
+ }
+ else
+ {
+ OSL_ENSURE(false, "ImpSetParentAtSfxItemSet called without SfxItemSet/SfxStyleSheet (!)");
+ }
+ }
+
+ void AttributeProperties::ImpAddStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr)
+ {
+ // test if old StyleSheet is cleared, else it would be lost
+ // after this method -> memory leak (!)
+ DBG_ASSERT(!mpStyleSheet, "Old style sheet not deleted before setting new one (!)");
+
+ if(!pNewStyleSheet)
+ return;
+
+ // local remember
+ mpStyleSheet = pNewStyleSheet;
+
+ if(HasSfxItemSet())
+ {
+ // register as listener
+ StartListening(*pNewStyleSheet->GetPool());
+ StartListening(*pNewStyleSheet);
+
+ // only apply the following when we have an SfxItemSet already, else
+ if(GetStyleSheet())
+ {
+ ImpSetParentAtSfxItemSet(bDontRemoveHardAttr);
+ }
+ }
+ }
+
+ void AttributeProperties::ImpRemoveStyleSheet()
+ {
+ // Check type since it is destroyed when the type is deleted
+ if(GetStyleSheet() && mpStyleSheet)
+ {
+ EndListening(*mpStyleSheet);
+ if (auto const pool = mpStyleSheet->GetPool()) { // TTTT
+ EndListening(*pool);
+ }
+
+ // reset parent of ItemSet
+ if(HasSfxItemSet())
+ {
+ mxItemSet->SetParent(nullptr);
+ }
+
+ SdrObject& rObj = GetSdrObject();
+ rObj.SetBoundRectDirty();
+ rObj.SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
+ }
+
+ mpStyleSheet = nullptr;
+ }
+
+ // create a new itemset
+ SfxItemSet AttributeProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
+ {
+ return SfxItemSet(rPool,
+
+ // ranges from SdrAttrObj
+ svl::Items<SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
+ SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+ SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST>);
+ }
+
+ AttributeProperties::AttributeProperties(SdrObject& rObj)
+ : DefaultProperties(rObj),
+ mpStyleSheet(nullptr)
+ {
+ // Do nothing else, esp. do *not* try to get and set
+ // a default SfxStyle sheet. Nothing is allowed to be done
+ // that may lead to calls to virtual functions like
+ // CreateObjectSpecificItemSet - these would go *wrong*.
+ // Thus the rest is lazy-init from here.
+ }
+
+ AttributeProperties::AttributeProperties(const AttributeProperties& rProps, SdrObject& rObj)
+ : DefaultProperties(rProps, rObj),
+ mpStyleSheet(nullptr)
+ {
+ SfxStyleSheet* pTargetStyleSheet(rProps.GetStyleSheet());
+
+ if(pTargetStyleSheet)
+ {
+ const bool bModelChange(&rObj.getSdrModelFromSdrObject() != &rProps.GetSdrObject().getSdrModelFromSdrObject());
+
+ if(bModelChange)
+ {
+ // tdf#117506
+ // The error shows that it is definitely necessary to solve this problem.
+ // Interestingly I already had a note here for 'work needed'.
+ // Checked in libreoffice-6-0 what happened there. In principle, the whole
+ // ::Clone of SdrPage and SdrObject happened in the same SdrModel, only
+ // afterwards a ::SetModel was used at the cloned SdrPage which went through
+ // all layers. The StyleSheet-problem was solved in
+ // AttributeProperties::MoveToItemPool at the end. There, a StyleSheet with the
+ // same name was searched for in the target-SdrModel.
+ // Start by resetting the current TargetStyleSheet so that nothing goes wrong
+ // when we do not find a fitting TargetStyleSheet.
+ // Note: The test for SdrModelChange above was wrong (compared the already set
+ // new SdrObject), so this never triggered and pTargetStyleSheet was never set to
+ // nullptr before. This means that a StyleSheet from another SdrModel was used
+ // what of course is very dangerous. Interestingly did not crash since when that
+ // other SdrModel was destroyed the ::Notify mechanism still worked reliably
+ // and de-connected this Properties successfully from the alien-StyleSheet.
+ pTargetStyleSheet = nullptr;
+
+ // Check if we have a TargetStyleSheetPool at the target-SdrModel. This *should*
+ // be the case already (SdrModel::Merge and SdDrawDocument::InsertBookmarkAsPage
+ // have already cloned the StyleSheets to the target-SdrModel when used in Draw/impress).
+ // If none is found, ImpGetDefaultStyleSheet will be used to set a 'default'
+ // StyleSheet as StyleSheet implicitly later (that's what happened in the task,
+ // thus the FillStyle changed to the 'default' Blue).
+ // Note: It *may* be necessary to do more for StyleSheets, e.g. clone/copy the
+ // StyleSheet Hierarchy from the source SdrModel and/or add the Items from there
+ // as hard attributes. If needed, have a look at the older AttributeProperties::SetModel
+ // implementation from e.g. libreoffice-6-0.
+ SfxStyleSheetBasePool* pTargetStyleSheetPool(rObj.getSdrModelFromSdrObject().GetStyleSheetPool());
+
+ if(nullptr != pTargetStyleSheetPool)
+ {
+ // If we have a TargetStyleSheetPool, search for the used StyleSheet
+ // in the target SdrModel using the Name from the original StyleSheet
+ // in the source-SdrModel.
+ pTargetStyleSheet = dynamic_cast< SfxStyleSheet* >(
+ pTargetStyleSheetPool->Find(
+ rProps.GetStyleSheet()->GetName(),
+ SfxStyleFamily::All));
+ }
+ }
+ }
+
+ if(!pTargetStyleSheet)
+ return;
+
+ if(HasSfxItemSet())
+ {
+ // The SfxItemSet has been cloned and exists,
+ // we can directly set the SfxStyleSheet at it
+ ImpAddStyleSheet(pTargetStyleSheet, true);
+ }
+ else
+ {
+ // No SfxItemSet exists yet (there is none in
+ // the source, so none was cloned). Remember the
+ // SfxStyleSheet to set it when the SfxItemSet
+ // got constructed on-demand
+ mpStyleSheet = pTargetStyleSheet;
+ }
+ }
+
+ AttributeProperties::~AttributeProperties()
+ {
+ ImpRemoveStyleSheet();
+ }
+
+ std::unique_ptr<BaseProperties> AttributeProperties::Clone(SdrObject& rObj) const
+ {
+ return std::unique_ptr<BaseProperties>(new AttributeProperties(*this, rObj));
+ }
+
+ const SfxItemSet& AttributeProperties::GetObjectItemSet() const
+ {
+ // remember if we had a SfxItemSet already
+ const bool bHadSfxItemSet(HasSfxItemSet());
+
+ // call parent - this will guarantee SfxItemSet existence
+ DefaultProperties::GetObjectItemSet();
+
+ if(!bHadSfxItemSet)
+ {
+ // need to take care for SfxStyleSheet for newly
+ // created SfxItemSet
+ if(nullptr == mpStyleSheet)
+ {
+ // Set missing defaults without removal of hard attributes.
+ // This is more complicated historically than I first thought:
+ // Originally for GetDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj
+ // SetStyleSheet(..., false) was used, while for GetDefaultStyleSheet
+ // SetStyleSheet(..., true) was used. Thus, for SdrGrafObj and SdrOle2Obj
+ // bDontRemoveHardAttr == false -> *do* delete hard attributes was used.
+ // This was probably not done by purpose, adding the method
+ // GetDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj additionally to
+ // GetDefaultStyleSheet was an enhancement to allow for SdrGrafObj/SdrOle2Obj
+ // with full AttributeSet (adding e.g. FillAttributes). To stay as compatible
+ // as possible these SdrObjects got a new default-StyleSheet.
+ // There is no reason to delete the HardAttributes and it anyways has only
+ // AFAIK effects on a single Item - the SdrTextHorzAdjustItem. To get things
+ // unified I will stay with not deleting the HardAttributes and adapt the
+ // UnitTests in CppunitTest_sd_import_tests accordingly.
+ const_cast< AttributeProperties* >(this)->applyDefaultStyleSheetFromSdrModel();
+ }
+ else
+ {
+ // Late-Init of setting parent to SfxStyleSheet after
+ // it's creation. Can only happen from copy-constructor
+ // (where creation of SfxItemSet is avoided due to the
+ // problem with constructors and virtual functions in C++),
+ // thus DontRemoveHardAttr is not needed.
+ const_cast< AttributeProperties* >(this)->SetStyleSheet(
+ mpStyleSheet, true, true);
+ }
+ }
+
+ return *mxItemSet;
+ }
+
+ void AttributeProperties::ItemSetChanged(o3tl::span< const SfxPoolItem* const > /*aChangedItems*/, sal_uInt16 /*nDeletedWhich*/)
+ {
+ // own modifications
+ SdrObject& rObj = GetSdrObject();
+
+ rObj.SetBoundRectDirty();
+ rObj.SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
+ rObj.SetChanged();
+ }
+
+ void AttributeProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem)
+ {
+ if(pNewItem)
+ {
+ std::unique_ptr<SfxPoolItem> pResultItem;
+ SdrModel& rModel(GetSdrObject().getSdrModelFromSdrObject());
+
+ switch( nWhich )
+ {
+ case XATTR_FILLBITMAP:
+ {
+ // TTTT checkForUniqueItem should use SdrModel&
+ pResultItem = static_cast<const XFillBitmapItem*>(pNewItem)->checkForUniqueItem( &rModel );
+ break;
+ }
+ case XATTR_LINEDASH:
+ {
+ pResultItem = static_cast<const XLineDashItem*>(pNewItem)->checkForUniqueItem( &rModel );
+ break;
+ }
+ case XATTR_LINESTART:
+ {
+ pResultItem = static_cast<const XLineStartItem*>(pNewItem)->checkForUniqueItem( &rModel );
+ break;
+ }
+ case XATTR_LINEEND:
+ {
+ pResultItem = static_cast<const XLineEndItem*>(pNewItem)->checkForUniqueItem( &rModel );
+ break;
+ }
+ case XATTR_FILLGRADIENT:
+ {
+ pResultItem = static_cast<const XFillGradientItem*>(pNewItem)->checkForUniqueItem( &rModel );
+ break;
+ }
+ case XATTR_FILLFLOATTRANSPARENCE:
+ {
+ // #85953# allow all kinds of XFillFloatTransparenceItem to be set
+ pResultItem = static_cast<const XFillFloatTransparenceItem*>(pNewItem)->checkForUniqueItem( &rModel );
+ break;
+ }
+ case XATTR_FILLHATCH:
+ {
+ pResultItem = static_cast<const XFillHatchItem*>(pNewItem)->checkForUniqueItem( &rModel );
+ break;
+ }
+ }
+
+ // guarantee SfxItemSet existence
+ GetObjectItemSet();
+
+ if(pResultItem)
+ {
+ // force ItemSet
+ mxItemSet->Put(std::move(pResultItem));
+ }
+ else
+ {
+ mxItemSet->Put(*pNewItem);
+ }
+ }
+ else
+ {
+ // clear item if ItemSet exists
+ if(HasSfxItemSet())
+ {
+ mxItemSet->ClearItem(nWhich);
+ }
+ }
+ }
+
+ void AttributeProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, bool bDontRemoveHardAttr,
+ bool /*bBroadcast*/)
+ {
+ // guarantee SfxItemSet existence
+ GetObjectItemSet();
+
+ ImpRemoveStyleSheet();
+ ImpAddStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
+
+ SdrObject& rObj = GetSdrObject();
+ rObj.SetBoundRectDirty();
+ rObj.SetBoundAndSnapRectsDirty(true);
+ }
+
+ SfxStyleSheet* AttributeProperties::GetStyleSheet() const
+ {
+ return mpStyleSheet;
+ }
+
+ void AttributeProperties::ForceStyleToHardAttributes()
+ {
+ if(!GetStyleSheet() || mpStyleSheet == nullptr)
+ return;
+
+ // guarantee SfxItemSet existence
+ GetObjectItemSet();
+
+ // prepare copied, new itemset, but WITHOUT parent
+ SfxItemSet aDestItemSet(*mxItemSet);
+ aDestItemSet.SetParent(nullptr);
+
+ // prepare forgetting the current stylesheet like in RemoveStyleSheet()
+ EndListening(*mpStyleSheet);
+ EndListening(*mpStyleSheet->GetPool());
+
+ // prepare the iter; use the mpObjectItemSet which may have less
+ // WhichIDs than the style.
+ SfxWhichIter aIter(aDestItemSet);
+ sal_uInt16 nWhich(aIter.FirstWhich());
+ const SfxPoolItem *pItem = nullptr;
+
+ // now set all hard attributes of the current at the new itemset
+ while(nWhich)
+ {
+ // #i61284# use mpItemSet with parents, makes things easier and reduces to
+ // one loop
+ if(SfxItemState::SET == mxItemSet->GetItemState(nWhich, true, &pItem))
+ {
+ aDestItemSet.Put(*pItem);
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+
+ // replace itemsets
+ mxItemSet.emplace(std::move(aDestItemSet));
+
+ // set necessary changes like in RemoveStyleSheet()
+ GetSdrObject().SetBoundRectDirty();
+ GetSdrObject().SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
+
+ mpStyleSheet = nullptr;
+ }
+
+ void AttributeProperties::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
+ {
+ bool bHintUsed(false);
+
+ const SfxStyleSheetHint* pStyleHint = dynamic_cast<const SfxStyleSheetHint*>(&rHint);
+
+ if(pStyleHint && pStyleHint->GetStyleSheet() == GetStyleSheet())
+ {
+ SdrObject& rObj = GetSdrObject();
+ //SdrPage* pPage = rObj.GetPage();
+
+ switch(pStyleHint->GetId())
+ {
+ case SfxHintId::StyleSheetCreated :
+ {
+ // cannot happen, nothing to do
+ break;
+ }
+ case SfxHintId::StyleSheetModified :
+ case SfxHintId::StyleSheetChanged :
+ {
+ // notify change
+ break;
+ }
+ case SfxHintId::StyleSheetErased :
+ case SfxHintId::StyleSheetInDestruction :
+ {
+ // Style needs to be exchanged
+ SfxStyleSheet* pNewStSh = nullptr;
+ SdrModel& rModel(rObj.getSdrModelFromSdrObject());
+
+ // Do nothing if object is in destruction, else a StyleSheet may be found from
+ // a StyleSheetPool which is just being deleted itself. and thus it would be fatal
+ // to register as listener to that new StyleSheet.
+ if(!rObj.IsInDestruction())
+ {
+ if(SfxStyleSheet* pStyleSheet = GetStyleSheet())
+ {
+ pNewStSh = static_cast<SfxStyleSheet*>(rModel.GetStyleSheetPool()->Find(
+ pStyleSheet->GetParent(), pStyleSheet->GetFamily()));
+ }
+
+ if(!pNewStSh)
+ {
+ pNewStSh = rModel.GetDefaultStyleSheet();
+ }
+ }
+
+ // remove used style, it's erased or in destruction
+ ImpRemoveStyleSheet();
+
+ if(pNewStSh)
+ {
+ ImpAddStyleSheet(pNewStSh, true);
+ }
+
+ break;
+ }
+ default: break;
+ }
+
+ // Get old BoundRect. Do this after the style change is handled
+ // in the ItemSet parts because GetBoundRect() may calculate a new
+ tools::Rectangle aBoundRect = rObj.GetLastBoundRect();
+
+ rObj.SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
+
+ // tell the object about the change
+ rObj.SetChanged();
+ rObj.BroadcastObjectChange();
+
+ //if(pPage && pPage->IsInserted())
+ //{
+ // rObj.BroadcastObjectChange();
+ //}
+
+ rObj.SendUserCall(SdrUserCallType::ChangeAttr, aBoundRect);
+
+ bHintUsed = true;
+ }
+
+ if(!bHintUsed)
+ {
+ // forward to SdrObject ATM. Not sure if this will be necessary
+ // in the future.
+ GetSdrObject().Notify(rBC, rHint);
+ }
+ }
+
+ bool AttributeProperties::isUsedByModel() const
+ {
+ const SdrObject& rObj(GetSdrObject());
+ if (rObj.IsInserted())
+ {
+ const SdrPage* const pPage(rObj.getSdrPageFromSdrObject());
+ if (pPage && pPage->IsInserted())
+ return true;
+ }
+ return false;
+ }
+
+ void AttributeProperties::applyDefaultStyleSheetFromSdrModel()
+ {
+ SfxStyleSheet* pDefaultStyleSheet(GetSdrObject().getSdrModelFromSdrObject().GetDefaultStyleSheet());
+
+ // tdf#118139 Only do this when StyleSheet really differs. It may e.g.
+ // be the case that nullptr == pDefaultStyleSheet and there is none set yet,
+ // so indeed no need to set it (needed for some strange old MSWord2003
+ // documents with CustomShape-'Group' and added Text-Frames, see task description)
+ if(pDefaultStyleSheet != GetStyleSheet())
+ {
+ // do not delete hard attributes when setting dsefault Style
+ SetStyleSheet(pDefaultStyleSheet, true, true);
+ }
+ }
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */