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 #include "precompiled_sd.hxx" 23 24 #include "DocumentHelper.hxx" 25 26 #include "drawdoc.hxx" 27 #include "DrawDocShell.hxx" 28 #include "sdpage.hxx" 29 #include "glob.hxx" 30 #include "unmovss.hxx" 31 #include "strings.hrc" 32 #include "sdresid.hxx" 33 #include "undoback.hxx" 34 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp> 35 #include <com/sun/star/drawing/XDrawPages.hpp> 36 #include <com/sun/star/frame/XComponentLoader.hpp> 37 #include <com/sun/star/container/XIndexAccess.hpp> 38 #include "stlpool.hxx" 39 #include <svx/xfillit0.hxx> 40 #include <tools/diagnose_ex.h> 41 42 using namespace ::com::sun::star; 43 44 namespace sd { namespace sidebar { 45 46 SdPage* DocumentHelper::CopyMasterPageToLocalDocument ( 47 SdDrawDocument& rTargetDocument, 48 SdPage* pMasterPage) 49 { 50 SdPage* pNewMasterPage = NULL; 51 52 do 53 { 54 if (pMasterPage == NULL) 55 break; 56 57 // Check the presence of the source document. 58 SdDrawDocument* pSourceDocument = static_cast<SdDrawDocument*>( 59 pMasterPage->GetModel()); 60 if (pSourceDocument == NULL) 61 break; 62 63 // When the given master page already belongs to the target document 64 // then there is nothing more to do. 65 if (pSourceDocument == &rTargetDocument) 66 { 67 pNewMasterPage = pMasterPage; 68 break; 69 } 70 71 // Test if the master pages of both the slide and its notes page are 72 // present. This is not the case when we are called during the 73 // creation of the slide master page because then the notes master 74 // page is not there. 75 sal_uInt16 nSourceMasterPageCount = pSourceDocument->GetMasterPageCount(); 76 if (nSourceMasterPageCount%2 == 0) 77 // There should be 1 handout page + n slide masters + n notes 78 // masters = 2*n+1. An even value indicates that a new slide 79 // master but not yet the notes master has been inserted. 80 break; 81 sal_uInt16 nIndex = pMasterPage->GetPageNum(); 82 if (nSourceMasterPageCount <= nIndex+1) 83 break; 84 // Get the slide master page. 85 if (pMasterPage != static_cast<SdPage*>( 86 pSourceDocument->GetMasterPage(nIndex))) 87 break; 88 // Get the notes master page. 89 SdPage* pNotesMasterPage = static_cast<SdPage*>( 90 pSourceDocument->GetMasterPage(nIndex+1)); 91 if (pNotesMasterPage == NULL) 92 break; 93 94 95 // Check if a master page with the same name as that of the given 96 // master page already exists. 97 bool bPageExists (false); 98 sal_uInt16 nMasterPageCount(rTargetDocument.GetMasterSdPageCount(PK_STANDARD)); 99 for (sal_uInt16 nMaster=0; nMaster<nMasterPageCount; nMaster++) 100 { 101 SdPage* pCandidate = static_cast<SdPage*>( 102 rTargetDocument.GetMasterSdPage (nMaster, PK_STANDARD)); 103 if (pMasterPage!=NULL 104 && pCandidate->GetName().CompareTo(pMasterPage->GetName())==0) 105 { 106 bPageExists = true; 107 pNewMasterPage = pCandidate; 108 break; 109 } 110 } 111 if (bPageExists) 112 break; 113 114 // Create a new slide (and its notes page.) 115 uno::Reference<drawing::XDrawPagesSupplier> xSlideSupplier ( 116 rTargetDocument.getUnoModel(), uno::UNO_QUERY); 117 if ( ! xSlideSupplier.is()) 118 break; 119 uno::Reference<drawing::XDrawPages> xSlides ( 120 xSlideSupplier->getDrawPages(), uno::UNO_QUERY); 121 if ( ! xSlides.is()) 122 break; 123 xSlides->insertNewByIndex (xSlides->getCount()); 124 125 // Set a layout. 126 SdPage* pSlide = rTargetDocument.GetSdPage( 127 rTargetDocument.GetSdPageCount(PK_STANDARD)-1, 128 PK_STANDARD); 129 if (pSlide == NULL) 130 break; 131 pSlide->SetAutoLayout(AUTOLAYOUT_TITLE, sal_True); 132 133 // Create a copy of the master page and the associated notes 134 // master page and insert them into our document. 135 pNewMasterPage = AddMasterPage(rTargetDocument, pMasterPage); 136 if (pNewMasterPage==NULL) 137 break; 138 SdPage* pNewNotesMasterPage 139 = AddMasterPage(rTargetDocument, pNotesMasterPage); 140 if (pNewNotesMasterPage==NULL) 141 break; 142 143 // Make the connection from the new slide to the master page 144 // (and do the same for the notes page.) 145 rTargetDocument.SetMasterPage ( 146 rTargetDocument.GetSdPageCount(PK_STANDARD)-1, 147 pNewMasterPage->GetName(), 148 &rTargetDocument, 149 sal_False, // Connect the new master page with the new slide but 150 // do not modify other (master) pages. 151 sal_True); 152 } 153 while (false); 154 155 // We are not interested in any automatisms for our modified internal 156 // document. 157 rTargetDocument.SetChanged (sal_False); 158 159 return pNewMasterPage; 160 } 161 162 163 164 165 SdPage* DocumentHelper::GetSlideForMasterPage (SdPage* pMasterPage) 166 { 167 SdPage* pCandidate = NULL; 168 169 SdDrawDocument* pDocument = NULL; 170 if (pMasterPage != NULL) 171 pDocument = dynamic_cast<SdDrawDocument*>(pMasterPage->GetModel()); 172 173 // Iterate over all pages and check if it references the given master 174 // page. 175 if (pDocument!=NULL && pDocument->GetSdPageCount(PK_STANDARD) > 0) 176 { 177 // In most cases a new slide has just been inserted so start with 178 // the last page. 179 sal_uInt16 nPageIndex (pDocument->GetSdPageCount(PK_STANDARD)-1); 180 bool bFound (false); 181 while ( ! bFound) 182 { 183 pCandidate = pDocument->GetSdPage( 184 nPageIndex, 185 PK_STANDARD); 186 if (pCandidate != NULL) 187 { 188 if (static_cast<SdPage*>(&pCandidate->TRG_GetMasterPage()) 189 == pMasterPage) 190 { 191 bFound = true; 192 break; 193 } 194 } 195 196 if (nPageIndex == 0) 197 break; 198 else 199 nPageIndex --; 200 } 201 202 // If no page was found that refernced the given master page reset 203 // the pointer that is returned. 204 if ( ! bFound) 205 pCandidate = NULL; 206 } 207 208 return pCandidate; 209 } 210 211 212 213 214 SdPage* DocumentHelper::AddMasterPage ( 215 SdDrawDocument& rTargetDocument, 216 SdPage* pMasterPage) 217 { 218 SdPage* pClonedMasterPage = NULL; 219 220 if (pMasterPage!=NULL) 221 { 222 try 223 { 224 // Duplicate the master page. 225 pClonedMasterPage = static_cast<SdPage*>(pMasterPage->Clone()); 226 227 // Copy the necessary styles. 228 SdDrawDocument* pSourceDocument 229 = static_cast<SdDrawDocument*>(pMasterPage->GetModel()); 230 if (pSourceDocument != NULL) 231 ProvideStyles (*pSourceDocument, rTargetDocument, pClonedMasterPage); 232 233 // Copy the precious flag. 234 pClonedMasterPage->SetPrecious(pMasterPage->IsPrecious()); 235 236 // Now that the styles are available we can insert the cloned 237 // master page. 238 rTargetDocument.InsertMasterPage (pClonedMasterPage); 239 } 240 catch (uno::Exception& rException) 241 { 242 pClonedMasterPage = NULL; 243 DBG_UNHANDLED_EXCEPTION(); 244 } 245 catch (::std::exception rException) 246 { 247 pClonedMasterPage = NULL; 248 OSL_TRACE ("caught general exception"); 249 } 250 catch (...) 251 { 252 pClonedMasterPage = NULL; 253 OSL_TRACE ("caught general exception"); 254 } 255 } 256 257 return pClonedMasterPage; 258 } 259 260 261 262 263 void DocumentHelper::ProvideStyles ( 264 SdDrawDocument& rSourceDocument, 265 SdDrawDocument& rTargetDocument, 266 SdPage* pPage) 267 { 268 // Get the layout name of the given page. 269 String sLayoutName (pPage->GetLayoutName()); 270 sLayoutName.Erase (sLayoutName.SearchAscii (SD_LT_SEPARATOR)); 271 272 // Copy the style sheet from source to target document. 273 SdStyleSheetPool* pSourceStyleSheetPool = 274 static_cast<SdStyleSheetPool*>(rSourceDocument.GetStyleSheetPool()); 275 SdStyleSheetPool* pTargetStyleSheetPool = 276 static_cast<SdStyleSheetPool*>(rTargetDocument.GetStyleSheetPool()); 277 SdStyleSheetVector aCreatedStyles; 278 pTargetStyleSheetPool->CopyLayoutSheets ( 279 sLayoutName, 280 *pSourceStyleSheetPool, 281 aCreatedStyles); 282 283 // Add an undo action for the copied style sheets. 284 if( !aCreatedStyles.empty() ) 285 { 286 ::svl::IUndoManager* pUndoManager = rTargetDocument.GetDocSh()->GetUndoManager(); 287 if (pUndoManager != NULL) 288 { 289 SdMoveStyleSheetsUndoAction* pMovStyles = 290 new SdMoveStyleSheetsUndoAction ( 291 &rTargetDocument, 292 aCreatedStyles, 293 sal_True); 294 pUndoManager->AddUndoAction (pMovStyles); 295 } 296 } 297 } 298 299 300 301 302 void DocumentHelper::AssignMasterPageToPageList ( 303 SdDrawDocument& rTargetDocument, 304 SdPage* pMasterPage, 305 const ::boost::shared_ptr<std::vector<SdPage*> >& rpPageList) 306 { 307 do 308 { 309 if (pMasterPage == NULL && pMasterPage->IsMasterPage()) 310 break; 311 312 // Make the layout name by stripping ouf the layout postfix from the 313 // layout name of the given master page. 314 String sFullLayoutName (pMasterPage->GetLayoutName()); 315 String sBaseLayoutName (sFullLayoutName); 316 sBaseLayoutName.Erase (sBaseLayoutName.SearchAscii (SD_LT_SEPARATOR)); 317 318 if (rpPageList->empty()) 319 break; 320 321 // Create a second list that contains only the valid pointers to 322 // pages for which an assignment is necessary. 323 ::std::vector<SdPage*>::const_iterator iPage; 324 ::std::vector<SdPage*> aCleanedList; 325 for (iPage=rpPageList->begin(); iPage!=rpPageList->end(); ++iPage) 326 { 327 OSL_ASSERT(*iPage!=NULL && (*iPage)->GetModel() == &rTargetDocument); 328 if (*iPage != NULL 329 && (*iPage)->GetLayoutName().CompareTo(sFullLayoutName)!=0) 330 { 331 aCleanedList.push_back(*iPage); 332 } 333 } 334 if (aCleanedList.empty() ) 335 break; 336 337 ::svl::IUndoManager* pUndoMgr = rTargetDocument.GetDocSh()->GetUndoManager(); 338 if( pUndoMgr ) 339 pUndoMgr->EnterListAction(String(SdResId(STR_UNDO_SET_PRESLAYOUT)), String()); 340 341 SdPage* pMasterPageInDocument = ProvideMasterPage(rTargetDocument,pMasterPage,rpPageList); 342 if (pMasterPageInDocument == NULL) 343 break; 344 345 // Assign the master pages to the given list of pages. 346 for (iPage=aCleanedList.begin(); 347 iPage!=aCleanedList.end(); 348 ++iPage) 349 { 350 AssignMasterPageToPage ( 351 pMasterPageInDocument, 352 sBaseLayoutName, 353 *iPage); 354 } 355 356 if( pUndoMgr ) 357 pUndoMgr->LeaveListAction(); 358 } 359 while (false); 360 } 361 362 363 364 365 SdPage* DocumentHelper::AddMasterPage ( 366 SdDrawDocument& rTargetDocument, 367 SdPage* pMasterPage, 368 sal_uInt16 nInsertionIndex) 369 { 370 SdPage* pClonedMasterPage = NULL; 371 372 if (pMasterPage!=NULL) 373 { 374 // Duplicate the master page. 375 pClonedMasterPage = static_cast<SdPage*>(pMasterPage->Clone()); 376 377 // Copy the precious flag. 378 pClonedMasterPage->SetPrecious(pMasterPage->IsPrecious()); 379 380 // Copy the necessary styles. 381 SdDrawDocument* pSourceDocument 382 = static_cast<SdDrawDocument*>(pMasterPage->GetModel()); 383 if (pSourceDocument != NULL) 384 { 385 ProvideStyles (*pSourceDocument, rTargetDocument, pClonedMasterPage); 386 387 // Now that the styles are available we can insert the cloned 388 // master page. 389 rTargetDocument.InsertMasterPage (pClonedMasterPage, nInsertionIndex); 390 391 // Adapt the size of the new master page to that of the pages in 392 // the document. 393 Size aNewSize (rTargetDocument.GetSdPage(0, pMasterPage->GetPageKind())->GetSize()); 394 Rectangle aBorders ( 395 pClonedMasterPage->GetLftBorder(), 396 pClonedMasterPage->GetUppBorder(), 397 pClonedMasterPage->GetRgtBorder(), 398 pClonedMasterPage->GetLwrBorder()); 399 pClonedMasterPage->ScaleObjects(aNewSize, aBorders, sal_True); 400 pClonedMasterPage->SetSize(aNewSize); 401 pClonedMasterPage->CreateTitleAndLayout(sal_True); 402 } 403 } 404 405 return pClonedMasterPage; 406 } 407 408 409 410 411 /** In here we have to handle three cases: 412 1. pPage is a normal slide. We can use SetMasterPage to assign the 413 master pages to it. 414 2. pPage is a master page that is used by at least one slide. We can 415 assign the master page to these slides. 416 3. pPage is a master page that is currently not used by any slide. 417 We can delete that page and add copies of the given master pages 418 instead. 419 420 For points 2 and 3 where one master page A is assigned to another B we have 421 to keep in mind that the master page that page A has already been 422 inserted into the target document. 423 */ 424 void DocumentHelper::AssignMasterPageToPage ( 425 SdPage* pMasterPage, 426 const String& rsBaseLayoutName, 427 SdPage* pPage) 428 { 429 // Leave early when the parameters are invalid. 430 if (pPage == NULL || pMasterPage == NULL) 431 return; 432 SdDrawDocument* pDocument = dynamic_cast<SdDrawDocument*>(pPage->GetModel()); 433 if (pDocument == NULL) 434 return; 435 436 if ( ! pPage->IsMasterPage()) 437 { 438 // 1. Remove the background object (so that that, if it exists, does 439 // not override the new master page) and assign the master page to 440 // the regular slide. 441 pDocument->GetDocSh()->GetUndoManager()->AddUndoAction( 442 new SdBackgroundObjUndoAction( 443 *pDocument, *pPage, pPage->getSdrPageProperties().GetItemSet()), 444 sal_True); 445 pPage->getSdrPageProperties().PutItem(XFillStyleItem(XFILL_NONE)); 446 447 pDocument->SetMasterPage ( 448 (pPage->GetPageNum()-1)/2, 449 rsBaseLayoutName, 450 pDocument, 451 sal_False, 452 sal_False); 453 } 454 else 455 { 456 // Find first slide that uses the master page. 457 SdPage* pSlide = NULL; 458 sal_uInt16 nPageCount = pDocument->GetSdPageCount(PK_STANDARD); 459 for (sal_uInt16 nPage=0; nPage<nPageCount&&pSlide==NULL; nPage++) 460 { 461 SdrPage* pCandidate = pDocument->GetSdPage(nPage,PK_STANDARD); 462 if (pCandidate != NULL 463 && pCandidate->TRG_HasMasterPage() 464 && &(pCandidate->TRG_GetMasterPage()) == pPage) 465 { 466 pSlide = static_cast<SdPage*>(pCandidate); 467 } 468 } 469 470 if (pSlide != NULL) 471 { 472 // 2. Assign the given master pages to the first slide that was 473 // found above that uses the master page. 474 pDocument->SetMasterPage ( 475 (pSlide->GetPageNum()-1)/2, 476 rsBaseLayoutName, 477 pDocument, 478 sal_False, 479 sal_False); 480 } 481 else 482 { 483 // 3. Replace the master page A by a copy of the given master 484 // page B. 485 pDocument->RemoveUnnecessaryMasterPages ( 486 pPage, sal_False); 487 } 488 } 489 } 490 491 492 493 494 SdPage* DocumentHelper::ProvideMasterPage ( 495 SdDrawDocument& rTargetDocument, 496 SdPage* pMasterPage, 497 const ::boost::shared_ptr<std::vector<SdPage*> >& rpPageList) 498 { 499 // Make sure that both the master page and its notes master exist 500 // in the source document. If one is missing then return without 501 // making any changes. 502 if (pMasterPage == NULL) 503 { 504 // The caller should make sure that the master page is valid. 505 OSL_ASSERT(pMasterPage != NULL); 506 return NULL; 507 } 508 SdDrawDocument* pSourceDocument = static_cast<SdDrawDocument*>(pMasterPage->GetModel()); 509 if (pSourceDocument == NULL) 510 return NULL; 511 SdPage* pNotesMasterPage = static_cast<SdPage*>( 512 pSourceDocument->GetMasterPage(pMasterPage->GetPageNum()+1)); 513 if (pNotesMasterPage == NULL) 514 { 515 // The model is not in a valid state. Maybe a new master page 516 // is being (not finished yet) created? Return without making 517 // any changes. 518 return NULL; 519 } 520 521 SdPage* pMasterPageInDocument = NULL; 522 // Search for a master page with the same name as the given one in 523 // the target document. 524 const XubString sMasterPageLayoutName (pMasterPage->GetLayoutName()); 525 for (sal_uInt16 nIndex=0,nCount=rTargetDocument.GetMasterPageCount(); nIndex<nCount; ++nIndex) 526 { 527 SdPage* pCandidate = static_cast<SdPage*>(rTargetDocument.GetMasterPage(nIndex)); 528 if (pCandidate!=NULL 529 && sMasterPageLayoutName==pCandidate->GetLayoutName()) 530 { 531 // The requested master page does already exist in the 532 // target document, return it. 533 return pCandidate; 534 } 535 } 536 537 // The given master page does not already belong to the target 538 // document so we have to create copies and insert them into the 539 // targer document. 540 541 // Determine the position where the new master pages are inserted. 542 // By default they are inserted at the end. When we assign to a 543 // master page then insert after the last of the (selected) pages. 544 sal_uInt16 nInsertionIndex = rTargetDocument.GetMasterPageCount(); 545 if (rpPageList->front()->IsMasterPage()) 546 { 547 nInsertionIndex = rpPageList->back()->GetPageNum(); 548 } 549 550 // Clone the master page. 551 if (pMasterPage->GetModel() != &rTargetDocument) 552 { 553 pMasterPageInDocument = AddMasterPage (rTargetDocument, pMasterPage, nInsertionIndex); 554 if( rTargetDocument.IsUndoEnabled() ) 555 rTargetDocument.AddUndo( 556 rTargetDocument.GetSdrUndoFactory().CreateUndoNewPage(*pMasterPageInDocument)); 557 } 558 else 559 pMasterPageInDocument = pMasterPage; 560 561 // Clone the notes master. 562 if (pNotesMasterPage->GetModel() != &rTargetDocument) 563 { 564 SdPage* pClonedNotesMasterPage 565 = AddMasterPage (rTargetDocument, pNotesMasterPage, nInsertionIndex+1); 566 if( rTargetDocument.IsUndoEnabled() ) 567 rTargetDocument.AddUndo( 568 rTargetDocument.GetSdrUndoFactory().CreateUndoNewPage(*pClonedNotesMasterPage)); 569 } 570 571 return pMasterPageInDocument; 572 } 573 574 575 576 577 578 } } // end of namespace sd::sidebar 579