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