xref: /AOO41X/main/svx/source/sdr/properties/attributeproperties.cxx (revision f6e50924346d0b8c0b07c91832a97665dd718b0c)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svx.hxx"
26 #include <svx/sdr/properties/attributeproperties.hxx>
27 #include <svx/sdr/properties/itemsettools.hxx>
28 #include <tools/debug.hxx>
29 #include <svl/itemset.hxx>
30 #include <svl/style.hxx>
31 #include <svl/whiter.hxx>
32 #include <svl/poolitem.hxx>
33 #include <svx/svdobj.hxx>
34 #include <svx/svddef.hxx>
35 #include <svx/xit.hxx>
36 #include <svx/xbtmpit.hxx>
37 #include <svx/xlndsit.hxx>
38 #include <svx/xlnstit.hxx>
39 #include <svx/xlnedit.hxx>
40 #include <svx/xflgrit.hxx>
41 #include <svx/xflftrit.hxx>
42 #include <svx/xflhtit.hxx>
43 #include <svx/xlnasit.hxx>
44 #include <svx/xflasit.hxx>
45 #include <svx/svdmodel.hxx>
46 #include <svx/svdtrans.hxx>
47 #include <svx/svdpage.hxx>
48 
49 // #114265#
50 #include <svl/smplhint.hxx>
51 
52 //////////////////////////////////////////////////////////////////////////////
53 
54 namespace sdr
55 {
56     namespace properties
57     {
ImpAddStyleSheet(SfxStyleSheet * pNewStyleSheet,sal_Bool bDontRemoveHardAttr)58         void AttributeProperties::ImpAddStyleSheet(SfxStyleSheet* pNewStyleSheet, sal_Bool bDontRemoveHardAttr)
59         {
60             // test if old StyleSheet is cleared, else it would be lost
61             // after this method -> memory leak (!)
62             DBG_ASSERT(!mpStyleSheet, "Old style sheet not deleted before setting new one (!)");
63 
64             if(pNewStyleSheet)
65             {
66                 mpStyleSheet = pNewStyleSheet;
67 
68                 // local ItemSet is needed here, force it
69                 GetObjectItemSet();
70 
71                 // register as listener
72                 StartListening(pNewStyleSheet->GetPool());
73                 StartListening(*pNewStyleSheet);
74 
75                 // Delete hard attributes where items are set in the style sheet
76                 if(!bDontRemoveHardAttr)
77                 {
78                     const SfxItemSet& rStyle = pNewStyleSheet->GetItemSet();
79                     SfxWhichIter aIter(rStyle);
80                     sal_uInt16 nWhich = aIter.FirstWhich();
81 
82                     while(nWhich)
83                     {
84                         if(SFX_ITEM_SET == rStyle.GetItemState(nWhich))
85                         {
86                             mpItemSet->ClearItem(nWhich);
87                         }
88 
89                         nWhich = aIter.NextWhich();
90                     }
91                 }
92 
93                 // set new stylesheet as parent
94                 mpItemSet->SetParent(&pNewStyleSheet->GetItemSet());
95             }
96         }
97 
ImpRemoveStyleSheet()98         void AttributeProperties::ImpRemoveStyleSheet()
99         {
100             // Check type since it is destroyed when the type is deleted
101             if(GetStyleSheet() && HAS_BASE(SfxStyleSheet, mpStyleSheet))
102             {
103                 EndListening(*mpStyleSheet);
104                 EndListening(mpStyleSheet->GetPool());
105 
106                 // reset parent of ItemSet
107                 if(mpItemSet)
108                 {
109                     mpItemSet->SetParent(0L);
110                 }
111 
112                 SdrObject& rObj = GetSdrObject();
113                 rObj.SetBoundRectDirty();
114                 rObj.SetRectsDirty(sal_True);
115             }
116 
117             mpStyleSheet = 0L;
118         }
119 
120         // create a new itemset
CreateObjectSpecificItemSet(SfxItemPool & rPool)121         SfxItemSet& AttributeProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
122         {
123             return *(new SfxItemSet(rPool,
124 
125                 // ranges from SdrAttrObj
126                 SDRATTR_START, SDRATTR_SHADOW_LAST,
127                 SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
128                 SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
129 
130                 // end
131                 0, 0));
132         }
133 
AttributeProperties(SdrObject & rObj)134         AttributeProperties::AttributeProperties(SdrObject& rObj)
135         :   DefaultProperties(rObj),
136             mpStyleSheet(0L)
137         {
138         }
139 
AttributeProperties(const AttributeProperties & rProps,SdrObject & rObj)140         AttributeProperties::AttributeProperties(const AttributeProperties& rProps, SdrObject& rObj)
141         :   DefaultProperties(rProps, rObj),
142             mpStyleSheet(0L)
143         {
144             if(rProps.GetStyleSheet())
145             {
146                 ImpAddStyleSheet(rProps.GetStyleSheet(), sal_True);
147             }
148         }
149 
~AttributeProperties()150         AttributeProperties::~AttributeProperties()
151         {
152             ImpRemoveStyleSheet();
153         }
154 
Clone(SdrObject & rObj) const155         BaseProperties& AttributeProperties::Clone(SdrObject& rObj) const
156         {
157             return *(new AttributeProperties(*this, rObj));
158         }
159 
ItemSetChanged(const SfxItemSet &)160         void AttributeProperties::ItemSetChanged(const SfxItemSet& /*rSet*/)
161         {
162             // own modifications
163             SdrObject& rObj = GetSdrObject();
164 
165             rObj.SetBoundRectDirty();
166             rObj.SetRectsDirty(sal_True);
167             rObj.SetChanged();
168         }
169 
ItemChange(const sal_uInt16 nWhich,const SfxPoolItem * pNewItem)170         void AttributeProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem)
171         {
172             if(pNewItem)
173             {
174                 const SfxPoolItem* pItem = pNewItem;
175                 SdrModel* pModel = GetSdrObject().GetModel();
176 
177                 switch( nWhich )
178                 {
179                     case XATTR_FILLBITMAP:
180                     {
181                         pItem = ((XFillBitmapItem*)pItem)->checkForUniqueItem( pModel );
182                         break;
183                     }
184                     case XATTR_LINEDASH:
185                     {
186                         pItem = ((XLineDashItem*)pItem)->checkForUniqueItem( pModel );
187                         break;
188                     }
189                     case XATTR_LINESTART:
190                     {
191                         pItem = ((XLineStartItem*)pItem)->checkForUniqueItem( pModel );
192                         break;
193                     }
194                     case XATTR_LINEEND:
195                     {
196                         pItem = ((XLineEndItem*)pItem)->checkForUniqueItem( pModel );
197                         break;
198                     }
199                     case XATTR_FILLGRADIENT:
200                     {
201                         pItem = ((XFillGradientItem*)pItem)->checkForUniqueItem( pModel );
202                         break;
203                     }
204                     case XATTR_FILLFLOATTRANSPARENCE:
205                     {
206                         // #85953# allow all kinds of XFillFloatTransparenceItem to be set
207                         pItem = ((XFillFloatTransparenceItem*)pItem)->checkForUniqueItem( pModel );
208                         break;
209                     }
210                     case XATTR_FILLHATCH:
211                     {
212                         pItem = ((XFillHatchItem*)pItem)->checkForUniqueItem( pModel );
213                         break;
214                     }
215                 }
216 
217                 // set item
218                 if(pItem)
219                 {
220                     // force ItemSet
221                     GetObjectItemSet();
222                     mpItemSet->Put(*pItem);
223 
224                     // delete item if it was a generated one
225                     if(pItem != pNewItem)
226                     {
227                         delete (SfxPoolItem*)pItem;
228                     }
229                 }
230             }
231             else
232             {
233                 // clear item if ItemSet exists
234                 if(mpItemSet)
235                 {
236                     mpItemSet->ClearItem(nWhich);
237                 }
238             }
239         }
240 
SetStyleSheet(SfxStyleSheet * pNewStyleSheet,sal_Bool bDontRemoveHardAttr)241         void AttributeProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, sal_Bool bDontRemoveHardAttr)
242         {
243             ImpRemoveStyleSheet();
244             ImpAddStyleSheet(pNewStyleSheet, bDontRemoveHardAttr);
245 
246             SdrObject& rObj = GetSdrObject();
247             rObj.SetBoundRectDirty();
248             rObj.SetRectsDirty(sal_True);
249         }
250 
GetStyleSheet() const251         SfxStyleSheet* AttributeProperties::GetStyleSheet() const
252         {
253             return mpStyleSheet;
254         }
255 
MoveToItemPool(SfxItemPool * pSrcPool,SfxItemPool * pDestPool,SdrModel * pNewModel)256         void AttributeProperties::MoveToItemPool(SfxItemPool* pSrcPool, SfxItemPool* pDestPool, SdrModel* pNewModel)
257         {
258             OSL_ASSERT(pNewModel!=NULL);
259 
260             if(pSrcPool && pDestPool && (pSrcPool != pDestPool))
261             {
262                 if(mpItemSet)
263                 {
264                     // migrate ItemSet to new pool. Scaling is NOT necessary
265                     // because this functionality is used by UNDO only. Thus
266                     // objects and ItemSets would be moved back to their original
267                     // pool before usage.
268                     SfxItemSet* pOldSet = mpItemSet;
269                     SfxStyleSheet* pStySheet = GetStyleSheet();
270 
271                     if(pStySheet)
272                     {
273                         ImpRemoveStyleSheet();
274                     }
275 
276                     mpItemSet = mpItemSet->Clone(sal_False, pDestPool);
277                     GetSdrObject().GetModel()->MigrateItemSet(pOldSet, mpItemSet, pNewModel);
278 
279                     // set stylesheet (if used)
280                     if(pStySheet)
281                     {
282                         // #i109515#
283                         SfxItemPool* pStyleSheetPool = &pStySheet->GetPool().GetPool();
284 
285                         if(pStyleSheetPool == pDestPool)
286                         {
287                             // just re-set stylesheet
288                             ImpAddStyleSheet(pStySheet, sal_True);
289                         }
290                         else
291                         {
292                             // StyleSheet is NOT from the correct pool.
293                             // Look one up in the right pool with the same
294                             // name or use the default.
295 
296                             // Look up the style in the new document.
297                             OSL_ASSERT(pNewModel->GetStyleSheetPool() != NULL);
298                             SfxStyleSheet* pNewStyleSheet = dynamic_cast<SfxStyleSheet*>(
299                                 pNewModel->GetStyleSheetPool()->Find(
300                                     pStySheet->GetName(),
301                                     SFX_STYLE_FAMILY_ALL));
302                             if (pNewStyleSheet == NULL
303                                 || &pNewStyleSheet->GetPool().GetPool() != pDestPool)
304                             {
305                                 // There is no copy of the style in the new
306                                 // document.  Use the default as a fallback.
307                                 pNewStyleSheet = pNewModel->GetDefaultStyleSheet();
308                             }
309                             ImpAddStyleSheet(pNewStyleSheet, sal_True);
310                         }
311                     }
312 
313                     delete pOldSet;
314                 }
315             }
316         }
317 
SetModel(SdrModel * pOldModel,SdrModel * pNewModel)318         void AttributeProperties::SetModel(SdrModel* pOldModel, SdrModel* pNewModel)
319         {
320             if(pOldModel != pNewModel && pNewModel && !pNewModel->IsLoading())
321             {
322                 // For a living model move the items from one pool to the other
323                 if(pOldModel)
324                 {
325                     // If metric has changed, scale items.
326                     MapUnit aOldUnit(pOldModel->GetScaleUnit());
327                     MapUnit aNewUnit(pNewModel->GetScaleUnit());
328                     sal_Bool bScaleUnitChanged(aNewUnit != aOldUnit);
329                     Fraction aMetricFactor;
330 
331                     if(bScaleUnitChanged)
332                     {
333                         aMetricFactor = GetMapFactor(aOldUnit, aNewUnit).X();
334                         Scale(aMetricFactor);
335                     }
336 
337                     // Move all styles which are used by the object to the new
338                     // StyleSheet pool
339                     SfxStyleSheet* pOldStyleSheet = GetStyleSheet();
340 
341                     if(pOldStyleSheet)
342                     {
343                         SfxStyleSheetBase* pSheet = pOldStyleSheet;
344                         SfxStyleSheetBasePool* pOldPool = pOldModel->GetStyleSheetPool();
345                         SfxStyleSheetBasePool* pNewPool = pNewModel->GetStyleSheetPool();
346                         DBG_ASSERT(pOldPool, "Properties::SetModel(): Object has StyleSheet but no StyleSheetPool (!)");
347 
348                         if(pOldPool && pNewPool)
349                         {
350                             // build a list of to-be-copied Styles
351                             List aList;
352                             SfxStyleSheetBase* pAnchor = 0L;
353 
354                             while(pSheet)
355                             {
356                                 pAnchor = pNewPool->Find(pSheet->GetName(), pSheet->GetFamily());
357 
358                                 if(!pAnchor)
359                                 {
360                                     aList.Insert(pSheet, LIST_APPEND);
361                                     pSheet = pOldPool->Find(pSheet->GetParent(), pSheet->GetFamily());
362                                 }
363                                 else
364                                 {
365                                     // the style does exist
366                                     pSheet = 0L;
367                                 }
368                             }
369 
370                             // copy and set the parents
371                             pSheet = (SfxStyleSheetBase*)aList.First();
372                             SfxStyleSheetBase* pNewSheet = 0L;
373                             SfxStyleSheetBase* pLastSheet = 0L;
374                             SfxStyleSheetBase* pForThisObject = 0L;
375 
376                             while(pSheet)
377                             {
378                                 pNewSheet = &pNewPool->Make(pSheet->GetName(), pSheet->GetFamily(), pSheet->GetMask());
379                                 pNewSheet->GetItemSet().Put(pSheet->GetItemSet(), sal_False);
380 
381                                 if(bScaleUnitChanged)
382                                 {
383                                     sdr::properties::ScaleItemSet(pNewSheet->GetItemSet(), aMetricFactor);
384                                 }
385 
386                                 if(pLastSheet)
387                                 {
388                                     pLastSheet->SetParent(pNewSheet->GetName());
389                                 }
390 
391                                 if(!pForThisObject)
392                                 {
393                                     pForThisObject = pNewSheet;
394                                 }
395 
396                                 pLastSheet = pNewSheet;
397                                 pSheet = (SfxStyleSheetBase*)aList.Next();
398                             }
399 
400                             // Set link to the Style found in the Pool
401                             if(pAnchor && pLastSheet)
402                             {
403                                 pLastSheet->SetParent(pAnchor->GetName());
404                             }
405 
406                             // if list was empty (all Styles exist in destination pool)
407                             // pForThisObject is not yet set
408                             if(!pForThisObject && pAnchor)
409                             {
410                                 pForThisObject = pAnchor;
411                             }
412 
413                             // De-register at old and register at new Style
414                             if(GetStyleSheet() != pForThisObject)
415                             {
416                                 ImpRemoveStyleSheet();
417                                 ImpAddStyleSheet((SfxStyleSheet*)pForThisObject, sal_True);
418                             }
419                         }
420                         else
421                         {
422                             // there is no StyleSheetPool in the new model, thus set
423                             // all items as hard items in the object
424                             List aList;
425                             const SfxItemSet* pItemSet = &pOldStyleSheet->GetItemSet();
426 
427                             while(pItemSet)
428                             {
429                                 aList.Insert((void*)pItemSet, CONTAINER_APPEND);
430                                 pItemSet = pItemSet->GetParent();
431                             }
432 
433                             SfxItemSet* pNewSet = &CreateObjectSpecificItemSet(pNewModel->GetItemPool());
434                             pItemSet = (SfxItemSet*)aList.Last();
435 
436                             while(pItemSet)
437                             {
438                                 pNewSet->Put(*pItemSet);
439                                 pItemSet = (SfxItemSet*)aList.Prev();
440                             }
441 
442                             // Items which were hard attributes before need to stay
443                             if(mpItemSet)
444                             {
445                                 SfxWhichIter aIter(*mpItemSet);
446                                 sal_uInt16 nWhich = aIter.FirstWhich();
447 
448                                 while(nWhich)
449                                 {
450                                     if(mpItemSet->GetItemState(nWhich, sal_False) == SFX_ITEM_SET)
451                                     {
452                                         pNewSet->Put(mpItemSet->Get(nWhich));
453                                     }
454 
455                                     nWhich = aIter.NextWhich();
456                                 }
457                             }
458 
459                             if(bScaleUnitChanged)
460                             {
461                                 ScaleItemSet(*pNewSet, aMetricFactor);
462                             }
463 
464                             if(mpItemSet)
465                             {
466                                 if(GetStyleSheet())
467                                 {
468                                     ImpRemoveStyleSheet();
469                                 }
470 
471                                 delete mpItemSet;
472                                 mpItemSet = 0L;
473                             }
474 
475                             mpItemSet = pNewSet;
476                         }
477                     }
478                 }
479 
480                 // each object gets the default Style if there is none set yet.
481                 if(!GetStyleSheet() && pNewModel && !pNewModel->IsLoading())
482                 {
483                     GetObjectItemSet(); // #118414# force ItemSet to allow style to be set
484                     SetStyleSheet(pNewModel->GetDefaultStyleSheet(), sal_True);
485                 }
486             }
487         }
488 
ForceStyleToHardAttributes()489         void AttributeProperties::ForceStyleToHardAttributes()
490         {
491             if(GetStyleSheet() && HAS_BASE(SfxStyleSheet, mpStyleSheet))
492             {
493                 // prepare copied, new itemset, but WITHOUT parent
494                 GetObjectItemSet();
495                 SfxItemSet* pDestItemSet = new SfxItemSet(*mpItemSet);
496                 pDestItemSet->SetParent(0L);
497 
498                 // pepare forgetting the current stylesheet like in RemoveStyleSheet()
499                 EndListening(*mpStyleSheet);
500                 EndListening(mpStyleSheet->GetPool());
501 
502                 // prepare the iter; use the mpObjectItemSet which may have less
503                 // WhichIDs than the style.
504                 SfxWhichIter aIter(*pDestItemSet);
505                 sal_uInt16 nWhich(aIter.FirstWhich());
506                 const SfxPoolItem *pItem = NULL;
507 
508                 // now set all hard attributes of the current at the new itemset
509                 while(nWhich)
510                 {
511                     // #i61284# use mpItemSet with parents, makes things easier and reduces to
512                     // one loop
513                     if(SFX_ITEM_SET == mpItemSet->GetItemState(nWhich, true, &pItem))
514                     {
515                         pDestItemSet->Put(*pItem);
516                     }
517 
518                     nWhich = aIter.NextWhich();
519                 }
520 
521                 // replace itemsets
522                 delete mpItemSet;
523                 mpItemSet = pDestItemSet;
524 
525                 // set necessary changes like in RemoveStyleSheet()
526                 GetSdrObject().SetBoundRectDirty();
527                 GetSdrObject().SetRectsDirty(sal_True);
528 
529                 mpStyleSheet = NULL;
530             }
531         }
532 
Notify(SfxBroadcaster & rBC,const SfxHint & rHint)533         void AttributeProperties::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
534         {
535             sal_Bool bHintUsed(sal_False);
536 
537             SfxStyleSheetHint *pStyleHint = PTR_CAST(SfxStyleSheetHint, &rHint);
538 
539             if(pStyleHint && pStyleHint->GetStyleSheet() == GetStyleSheet())
540             {
541                 SdrObject& rObj = GetSdrObject();
542                 //SdrPage* pPage = rObj.GetPage();
543 
544                 switch(pStyleHint->GetHint())
545                 {
546                     case SFX_STYLESHEET_CREATED         :
547                     {
548                         // cannot happen, nothing to do
549                         break;
550                     }
551                     case SFX_STYLESHEET_MODIFIED        :
552                     case SFX_STYLESHEET_CHANGED         :
553                     {
554                         // notify change
555                         break;
556                     }
557                     case SFX_STYLESHEET_ERASED          :
558                     case SFX_STYLESHEET_INDESTRUCTION   :
559                     {
560                         // Style needs to be exchanged
561                         SfxStyleSheet* pNewStSh = 0L;
562                         SdrModel* pModel = rObj.GetModel();
563 
564                         // #111111#
565                         // Do nothing if object is in destruction, else a StyleSheet may be found from
566                         // a StyleSheetPool which is just being deleted itself. and thus it would be fatal
567                         // to register as listener to that new StyleSheet.
568                         if(pModel && !rObj.IsInDestruction())
569                         {
570                             if(HAS_BASE(SfxStyleSheet, GetStyleSheet()))
571                             {
572                                 pNewStSh = (SfxStyleSheet*)pModel->GetStyleSheetPool()->Find(
573                                     GetStyleSheet()->GetParent(), GetStyleSheet()->GetFamily());
574                             }
575 
576                             if(!pNewStSh)
577                             {
578                                 pNewStSh = pModel->GetDefaultStyleSheet();
579                             }
580                         }
581 
582                         // remove used style, it's erased or in destruction
583                         ImpRemoveStyleSheet();
584 
585                         if(pNewStSh)
586                         {
587                             ImpAddStyleSheet(pNewStSh, sal_True);
588                         }
589 
590                         break;
591                     }
592                 }
593 
594                 // Get old BoundRect. Do this after the style change is handled
595                 // in the ItemSet parts because GetBoundRect() may calculate a new
596                 Rectangle aBoundRect = rObj.GetLastBoundRect();
597 
598                 rObj.SetRectsDirty(sal_True);
599 
600                 // tell the object about the change
601                 rObj.SetChanged();
602                 rObj.BroadcastObjectChange();
603 
604                 //if(pPage && pPage->IsInserted())
605                 //{
606                 //  rObj.BroadcastObjectChange();
607                 //}
608 
609                 rObj.SendUserCall(SDRUSERCALL_CHGATTR, aBoundRect);
610 
611                 bHintUsed = sal_True;
612             }
613 
614             if(!bHintUsed)
615             {
616                 // forward to SdrObject ATM. Not sure if this will be necessary
617                 // in the future.
618                 GetSdrObject().Notify(rBC, rHint);
619             }
620         }
621     } // end of namespace properties
622 } // end of namespace sdr
623 
624 //////////////////////////////////////////////////////////////////////////////
625 // eof
626