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