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