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