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