| /************************************************************** |
| * |
| * 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 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_svx.hxx" |
| #include <svx/sdr/properties/attributeproperties.hxx> |
| #include <svx/sdr/properties/itemsettools.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/xit.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/xlnasit.hxx> |
| #include <svx/xflasit.hxx> |
| #include <svx/svdmodel.hxx> |
| #include <svx/svdtrans.hxx> |
| #include <svx/svdpage.hxx> |
| |
| // #114265# |
| #include <svl/smplhint.hxx> |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| namespace sdr |
| { |
| namespace properties |
| { |
| void AttributeProperties::ImpAddStyleSheet(SfxStyleSheet* pNewStyleSheet, sal_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) |
| { |
| mpStyleSheet = pNewStyleSheet; |
| |
| // local ItemSet is needed here, force it |
| GetObjectItemSet(); |
| |
| // register as listener |
| StartListening(pNewStyleSheet->GetPool()); |
| StartListening(*pNewStyleSheet); |
| |
| // Delete hard attributes where items are set in the style sheet |
| if(!bDontRemoveHardAttr) |
| { |
| const SfxItemSet& rStyle = pNewStyleSheet->GetItemSet(); |
| SfxWhichIter aIter(rStyle); |
| sal_uInt16 nWhich = aIter.FirstWhich(); |
| |
| while(nWhich) |
| { |
| if(SFX_ITEM_SET == rStyle.GetItemState(nWhich)) |
| { |
| mpItemSet->ClearItem(nWhich); |
| } |
| |
| nWhich = aIter.NextWhich(); |
| } |
| } |
| |
| // set new stylesheet as parent |
| mpItemSet->SetParent(&pNewStyleSheet->GetItemSet()); |
| } |
| } |
| |
| void AttributeProperties::ImpRemoveStyleSheet() |
| { |
| // Check type since it is destroyed when the type is deleted |
| if(GetStyleSheet() && HAS_BASE(SfxStyleSheet, mpStyleSheet)) |
| { |
| EndListening(*mpStyleSheet); |
| EndListening(mpStyleSheet->GetPool()); |
| |
| // reset parent of ItemSet |
| if(mpItemSet) |
| { |
| mpItemSet->SetParent(0L); |
| } |
| |
| SdrObject& rObj = GetSdrObject(); |
| rObj.SetBoundRectDirty(); |
| rObj.SetRectsDirty(sal_True); |
| } |
| |
| mpStyleSheet = 0L; |
| } |
| |
| // create a new itemset |
| SfxItemSet& AttributeProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool) |
| { |
| return *(new SfxItemSet(rPool, |
| |
| // ranges from SdrAttrObj |
| SDRATTR_START, SDRATTR_SHADOW_LAST, |
| SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST, |
| SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION, |
| |
| // end |
| 0, 0)); |
| } |
| |
| AttributeProperties::AttributeProperties(SdrObject& rObj) |
| : DefaultProperties(rObj), |
| mpStyleSheet(0L) |
| { |
| } |
| |
| AttributeProperties::AttributeProperties(const AttributeProperties& rProps, SdrObject& rObj) |
| : DefaultProperties(rProps, rObj), |
| mpStyleSheet(0L) |
| { |
| if(rProps.GetStyleSheet()) |
| { |
| ImpAddStyleSheet(rProps.GetStyleSheet(), sal_True); |
| } |
| } |
| |
| AttributeProperties::~AttributeProperties() |
| { |
| ImpRemoveStyleSheet(); |
| } |
| |
| BaseProperties& AttributeProperties::Clone(SdrObject& rObj) const |
| { |
| return *(new AttributeProperties(*this, rObj)); |
| } |
| |
| void AttributeProperties::ItemSetChanged(const SfxItemSet& /*rSet*/) |
| { |
| // own modifications |
| SdrObject& rObj = GetSdrObject(); |
| |
| rObj.SetBoundRectDirty(); |
| rObj.SetRectsDirty(sal_True); |
| rObj.SetChanged(); |
| } |
| |
| void AttributeProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem) |
| { |
| if(pNewItem) |
| { |
| const SfxPoolItem* pItem = pNewItem; |
| SdrModel* pModel = GetSdrObject().GetModel(); |
| |
| switch( nWhich ) |
| { |
| case XATTR_FILLBITMAP: |
| { |
| pItem = ((XFillBitmapItem*)pItem)->checkForUniqueItem( pModel ); |
| break; |
| } |
| case XATTR_LINEDASH: |
| { |
| pItem = ((XLineDashItem*)pItem)->checkForUniqueItem( pModel ); |
| break; |
| } |
| case XATTR_LINESTART: |
| { |
| pItem = ((XLineStartItem*)pItem)->checkForUniqueItem( pModel ); |
| break; |
| } |
| case XATTR_LINEEND: |
| { |
| pItem = ((XLineEndItem*)pItem)->checkForUniqueItem( pModel ); |
| break; |
| } |
| case XATTR_FILLGRADIENT: |
| { |
| pItem = ((XFillGradientItem*)pItem)->checkForUniqueItem( pModel ); |
| break; |
| } |
| case XATTR_FILLFLOATTRANSPARENCE: |
| { |
| // #85953# allow all kinds of XFillFloatTransparenceItem to be set |
| pItem = ((XFillFloatTransparenceItem*)pItem)->checkForUniqueItem( pModel ); |
| break; |
| } |
| case XATTR_FILLHATCH: |
| { |
| pItem = ((XFillHatchItem*)pItem)->checkForUniqueItem( pModel ); |
| break; |
| } |
| } |
| |
| // set item |
| if(pItem) |
| { |
| // force ItemSet |
| GetObjectItemSet(); |
| mpItemSet->Put(*pItem); |
| |
| // delete item if it was a generated one |
| if(pItem != pNewItem) |
| { |
| delete (SfxPoolItem*)pItem; |
| } |
| } |
| } |
| else |
| { |
| // clear item if ItemSet exists |
| if(mpItemSet) |
| { |
| mpItemSet->ClearItem(nWhich); |
| } |
| } |
| } |
| |
| void AttributeProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, sal_Bool bDontRemoveHardAttr) |
| { |
| ImpRemoveStyleSheet(); |
| ImpAddStyleSheet(pNewStyleSheet, bDontRemoveHardAttr); |
| |
| SdrObject& rObj = GetSdrObject(); |
| rObj.SetBoundRectDirty(); |
| rObj.SetRectsDirty(sal_True); |
| } |
| |
| SfxStyleSheet* AttributeProperties::GetStyleSheet() const |
| { |
| return mpStyleSheet; |
| } |
| |
| void AttributeProperties::MoveToItemPool(SfxItemPool* pSrcPool, SfxItemPool* pDestPool, SdrModel* pNewModel) |
| { |
| OSL_ASSERT(pNewModel!=NULL); |
| |
| if(pSrcPool && pDestPool && (pSrcPool != pDestPool)) |
| { |
| if(mpItemSet) |
| { |
| // migrate ItemSet to new pool. Scaling is NOT necessary |
| // because this functionality is used by UNDO only. Thus |
| // objects and ItemSets would be moved back to their original |
| // pool before usage. |
| SfxItemSet* pOldSet = mpItemSet; |
| SfxStyleSheet* pStySheet = GetStyleSheet(); |
| |
| if(pStySheet) |
| { |
| ImpRemoveStyleSheet(); |
| } |
| |
| mpItemSet = mpItemSet->Clone(sal_False, pDestPool); |
| GetSdrObject().GetModel()->MigrateItemSet(pOldSet, mpItemSet, pNewModel); |
| |
| // set stylesheet (if used) |
| if(pStySheet) |
| { |
| // #i109515# |
| SfxItemPool* pStyleSheetPool = &pStySheet->GetPool().GetPool(); |
| |
| if(pStyleSheetPool == pDestPool) |
| { |
| // just re-set stylesheet |
| ImpAddStyleSheet(pStySheet, sal_True); |
| } |
| else |
| { |
| // StyleSheet is NOT from the correct pool. |
| // Look one up in the right pool with the same |
| // name or use the default. |
| |
| // Look up the style in the new document. |
| OSL_ASSERT(pNewModel->GetStyleSheetPool() != NULL); |
| SfxStyleSheet* pNewStyleSheet = dynamic_cast<SfxStyleSheet*>( |
| pNewModel->GetStyleSheetPool()->Find( |
| pStySheet->GetName(), |
| SFX_STYLE_FAMILY_ALL)); |
| if (pNewStyleSheet == NULL |
| || &pNewStyleSheet->GetPool().GetPool() != pDestPool) |
| { |
| // There is no copy of the style in the new |
| // document. Use the default as a fallback. |
| pNewStyleSheet = pNewModel->GetDefaultStyleSheet(); |
| } |
| ImpAddStyleSheet(pNewStyleSheet, sal_True); |
| } |
| } |
| |
| delete pOldSet; |
| } |
| } |
| } |
| |
| void AttributeProperties::SetModel(SdrModel* pOldModel, SdrModel* pNewModel) |
| { |
| if(pOldModel != pNewModel && pNewModel && !pNewModel->IsLoading()) |
| { |
| // For a living model move the items from one pool to the other |
| if(pOldModel) |
| { |
| // If metric has changed, scale items. |
| MapUnit aOldUnit(pOldModel->GetScaleUnit()); |
| MapUnit aNewUnit(pNewModel->GetScaleUnit()); |
| sal_Bool bScaleUnitChanged(aNewUnit != aOldUnit); |
| Fraction aMetricFactor; |
| |
| if(bScaleUnitChanged) |
| { |
| aMetricFactor = GetMapFactor(aOldUnit, aNewUnit).X(); |
| Scale(aMetricFactor); |
| } |
| |
| // Move all styles which are used by the object to the new |
| // StyleSheet pool |
| SfxStyleSheet* pOldStyleSheet = GetStyleSheet(); |
| |
| if(pOldStyleSheet) |
| { |
| SfxStyleSheetBase* pSheet = pOldStyleSheet; |
| SfxStyleSheetBasePool* pOldPool = pOldModel->GetStyleSheetPool(); |
| SfxStyleSheetBasePool* pNewPool = pNewModel->GetStyleSheetPool(); |
| DBG_ASSERT(pOldPool, "Properties::SetModel(): Object has StyleSheet but no StyleSheetPool (!)"); |
| |
| if(pOldPool && pNewPool) |
| { |
| // build a list of to-be-copied Styles |
| List aList; |
| SfxStyleSheetBase* pAnchor = 0L; |
| |
| while(pSheet) |
| { |
| pAnchor = pNewPool->Find(pSheet->GetName(), pSheet->GetFamily()); |
| |
| if(!pAnchor) |
| { |
| aList.Insert(pSheet, LIST_APPEND); |
| pSheet = pOldPool->Find(pSheet->GetParent(), pSheet->GetFamily()); |
| } |
| else |
| { |
| // the style does exist |
| pSheet = 0L; |
| } |
| } |
| |
| // copy and set the parents |
| pSheet = (SfxStyleSheetBase*)aList.First(); |
| SfxStyleSheetBase* pNewSheet = 0L; |
| SfxStyleSheetBase* pLastSheet = 0L; |
| SfxStyleSheetBase* pForThisObject = 0L; |
| |
| while(pSheet) |
| { |
| pNewSheet = &pNewPool->Make(pSheet->GetName(), pSheet->GetFamily(), pSheet->GetMask()); |
| pNewSheet->GetItemSet().Put(pSheet->GetItemSet(), sal_False); |
| |
| if(bScaleUnitChanged) |
| { |
| sdr::properties::ScaleItemSet(pNewSheet->GetItemSet(), aMetricFactor); |
| } |
| |
| if(pLastSheet) |
| { |
| pLastSheet->SetParent(pNewSheet->GetName()); |
| } |
| |
| if(!pForThisObject) |
| { |
| pForThisObject = pNewSheet; |
| } |
| |
| pLastSheet = pNewSheet; |
| pSheet = (SfxStyleSheetBase*)aList.Next(); |
| } |
| |
| // Set link to the Style found in the Pool |
| if(pAnchor && pLastSheet) |
| { |
| pLastSheet->SetParent(pAnchor->GetName()); |
| } |
| |
| // if list was empty (all Styles exist in destination pool) |
| // pForThisObject is not yet set |
| if(!pForThisObject && pAnchor) |
| { |
| pForThisObject = pAnchor; |
| } |
| |
| // De-register at old and register at new Style |
| if(GetStyleSheet() != pForThisObject) |
| { |
| ImpRemoveStyleSheet(); |
| ImpAddStyleSheet((SfxStyleSheet*)pForThisObject, sal_True); |
| } |
| } |
| else |
| { |
| // there is no StyleSheetPool in the new model, thus set |
| // all items as hard items in the object |
| List aList; |
| const SfxItemSet* pItemSet = &pOldStyleSheet->GetItemSet(); |
| |
| while(pItemSet) |
| { |
| aList.Insert((void*)pItemSet, CONTAINER_APPEND); |
| pItemSet = pItemSet->GetParent(); |
| } |
| |
| SfxItemSet* pNewSet = &CreateObjectSpecificItemSet(pNewModel->GetItemPool()); |
| pItemSet = (SfxItemSet*)aList.Last(); |
| |
| while(pItemSet) |
| { |
| pNewSet->Put(*pItemSet); |
| pItemSet = (SfxItemSet*)aList.Prev(); |
| } |
| |
| // Items which were hard attributes before need to stay |
| if(mpItemSet) |
| { |
| SfxWhichIter aIter(*mpItemSet); |
| sal_uInt16 nWhich = aIter.FirstWhich(); |
| |
| while(nWhich) |
| { |
| if(mpItemSet->GetItemState(nWhich, sal_False) == SFX_ITEM_SET) |
| { |
| pNewSet->Put(mpItemSet->Get(nWhich)); |
| } |
| |
| nWhich = aIter.NextWhich(); |
| } |
| } |
| |
| if(bScaleUnitChanged) |
| { |
| ScaleItemSet(*pNewSet, aMetricFactor); |
| } |
| |
| if(mpItemSet) |
| { |
| if(GetStyleSheet()) |
| { |
| ImpRemoveStyleSheet(); |
| } |
| |
| delete mpItemSet; |
| mpItemSet = 0L; |
| } |
| |
| mpItemSet = pNewSet; |
| } |
| } |
| } |
| |
| // each object gets the default Style if there is none set yet. |
| if(!GetStyleSheet() && pNewModel && !pNewModel->IsLoading()) |
| { |
| GetObjectItemSet(); // #118414# force ItemSet to allow style to be set |
| SetStyleSheet(pNewModel->GetDefaultStyleSheet(), sal_True); |
| } |
| } |
| } |
| |
| void AttributeProperties::ForceStyleToHardAttributes() |
| { |
| if(GetStyleSheet() && HAS_BASE(SfxStyleSheet, mpStyleSheet)) |
| { |
| // prepare copied, new itemset, but WITHOUT parent |
| GetObjectItemSet(); |
| SfxItemSet* pDestItemSet = new SfxItemSet(*mpItemSet); |
| pDestItemSet->SetParent(0L); |
| |
| // pepare 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(*pDestItemSet); |
| sal_uInt16 nWhich(aIter.FirstWhich()); |
| const SfxPoolItem *pItem = NULL; |
| |
| // 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(SFX_ITEM_SET == mpItemSet->GetItemState(nWhich, true, &pItem)) |
| { |
| pDestItemSet->Put(*pItem); |
| } |
| |
| nWhich = aIter.NextWhich(); |
| } |
| |
| // replace itemsets |
| delete mpItemSet; |
| mpItemSet = pDestItemSet; |
| |
| // set necessary changes like in RemoveStyleSheet() |
| GetSdrObject().SetBoundRectDirty(); |
| GetSdrObject().SetRectsDirty(sal_True); |
| |
| mpStyleSheet = NULL; |
| } |
| } |
| |
| void AttributeProperties::Notify(SfxBroadcaster& rBC, const SfxHint& rHint) |
| { |
| sal_Bool bHintUsed(sal_False); |
| |
| SfxStyleSheetHint *pStyleHint = PTR_CAST(SfxStyleSheetHint, &rHint); |
| |
| if(pStyleHint && pStyleHint->GetStyleSheet() == GetStyleSheet()) |
| { |
| SdrObject& rObj = GetSdrObject(); |
| //SdrPage* pPage = rObj.GetPage(); |
| |
| switch(pStyleHint->GetHint()) |
| { |
| case SFX_STYLESHEET_CREATED : |
| { |
| // cannot happen, nothing to do |
| break; |
| } |
| case SFX_STYLESHEET_MODIFIED : |
| case SFX_STYLESHEET_CHANGED : |
| { |
| // notify change |
| break; |
| } |
| case SFX_STYLESHEET_ERASED : |
| case SFX_STYLESHEET_INDESTRUCTION : |
| { |
| // Style needs to be exchanged |
| SfxStyleSheet* pNewStSh = 0L; |
| SdrModel* pModel = rObj.GetModel(); |
| |
| // #111111# |
| // 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(pModel && !rObj.IsInDestruction()) |
| { |
| if(HAS_BASE(SfxStyleSheet, GetStyleSheet())) |
| { |
| pNewStSh = (SfxStyleSheet*)pModel->GetStyleSheetPool()->Find( |
| GetStyleSheet()->GetParent(), GetStyleSheet()->GetFamily()); |
| } |
| |
| if(!pNewStSh) |
| { |
| pNewStSh = pModel->GetDefaultStyleSheet(); |
| } |
| } |
| |
| // remove used style, it's erased or in destruction |
| ImpRemoveStyleSheet(); |
| |
| if(pNewStSh) |
| { |
| ImpAddStyleSheet(pNewStSh, sal_True); |
| } |
| |
| break; |
| } |
| } |
| |
| // Get old BoundRect. Do this after the style change is handled |
| // in the ItemSet parts because GetBoundRect() may calculate a new |
| Rectangle aBoundRect = rObj.GetLastBoundRect(); |
| |
| rObj.SetRectsDirty(sal_True); |
| |
| // tell the object about the change |
| rObj.SetChanged(); |
| rObj.BroadcastObjectChange(); |
| |
| //if(pPage && pPage->IsInserted()) |
| //{ |
| // rObj.BroadcastObjectChange(); |
| //} |
| |
| rObj.SendUserCall(SDRUSERCALL_CHGATTR, aBoundRect); |
| |
| bHintUsed = sal_True; |
| } |
| |
| if(!bHintUsed) |
| { |
| // forward to SdrObject ATM. Not sure if this will be necessary |
| // in the future. |
| GetSdrObject().Notify(rBC, rHint); |
| } |
| } |
| } // end of namespace properties |
| } // end of namespace sdr |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| // eof |