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_sd.hxx" 30 31 #include "MasterPageObserver.hxx" 32 33 #include <algorithm> 34 #include "drawdoc.hxx" 35 #include "sdpage.hxx" 36 #include <hash_map> 37 #include <set> 38 #include <vector> 39 #include <svl/lstner.hxx> 40 #include <osl/doublecheckedlocking.h> 41 #include <osl/getglobalmutex.hxx> 42 43 44 namespace sd { 45 46 class MasterPageObserver::Implementation 47 : public SfxListener 48 { 49 public: 50 /** The single instance of this class. It is created on demand when 51 Instance() is called for the first time. 52 */ 53 static MasterPageObserver* mpInstance; 54 55 /** The master page observer will listen to events of this document and 56 detect changes of the use of master pages. 57 */ 58 void RegisterDocument (SdDrawDocument& rDocument); 59 60 /** The master page observer will stop to listen to events of this 61 document. 62 */ 63 void UnregisterDocument (SdDrawDocument& rDocument); 64 65 /** Add a listener that is informed of master pages that are newly 66 assigned to slides or become unassigned. 67 @param rEventListener 68 The event listener to call for future events. Call 69 RemoveEventListener() before the listener is destroyed. 70 */ 71 void AddEventListener (const Link& rEventListener); 72 73 /** Remove the given listener from the list of listeners. 74 @param rEventListener 75 After this method returns the given listener is not called back 76 from this object. Passing a listener that has not 77 been registered before is safe and is silently ignored. 78 */ 79 void RemoveEventListener (const Link& rEventListener); 80 81 /** Return a set of the names of master pages for the given document. 82 This convenience method exists because this set is part of the 83 internal data structure and thus takes no time to create. 84 */ 85 inline MasterPageObserver::MasterPageNameSet GetMasterPageNames ( 86 SdDrawDocument& rDocument); 87 88 private: 89 ::std::vector<Link> maListeners; 90 91 struct DrawDocHash { 92 size_t operator()(SdDrawDocument* argument) const 93 { return reinterpret_cast<unsigned long>(argument); } 94 }; 95 typedef ::std::hash_map<SdDrawDocument*, 96 MasterPageObserver::MasterPageNameSet, 97 DrawDocHash> 98 MasterPageContainer; 99 MasterPageContainer maUsedMasterPages; 100 101 virtual void Notify( 102 SfxBroadcaster& rBroadcaster, 103 const SfxHint& rHint); 104 105 void AnalyzeUsedMasterPages (SdDrawDocument& rDocument); 106 107 void SendEvent (MasterPageObserverEvent& rEvent); 108 }; 109 110 MasterPageObserver* MasterPageObserver::Implementation::mpInstance = NULL; 111 112 113 114 //===== MasterPageObserver ==================================================== 115 116 MasterPageObserver& MasterPageObserver::Instance (void) 117 { 118 if (Implementation::mpInstance == NULL) 119 { 120 ::osl::GetGlobalMutex aMutexFunctor; 121 ::osl::MutexGuard aGuard (aMutexFunctor()); 122 if (Implementation::mpInstance == NULL) 123 { 124 MasterPageObserver* pInstance = new MasterPageObserver (); 125 SdGlobalResourceContainer::Instance().AddResource ( 126 ::std::auto_ptr<SdGlobalResource>(pInstance)); 127 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); 128 Implementation::mpInstance = pInstance; 129 } 130 } 131 else 132 { 133 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); 134 } 135 136 DBG_ASSERT(Implementation::mpInstance!=NULL, 137 "MasterPageObserver::Instance(): instance is NULL"); 138 return *Implementation::mpInstance; 139 } 140 141 142 143 144 void MasterPageObserver::RegisterDocument (SdDrawDocument& rDocument) 145 { 146 mpImpl->RegisterDocument (rDocument); 147 } 148 149 150 151 152 void MasterPageObserver::UnregisterDocument (SdDrawDocument& rDocument) 153 { 154 mpImpl->UnregisterDocument (rDocument); 155 } 156 157 158 159 160 void MasterPageObserver::AddEventListener (const Link& rEventListener) 161 { 162 163 mpImpl->AddEventListener (rEventListener); 164 } 165 166 167 168 169 void MasterPageObserver::RemoveEventListener (const Link& rEventListener) 170 { 171 mpImpl->RemoveEventListener (rEventListener); 172 } 173 174 175 176 177 MasterPageObserver::MasterPageObserver (void) 178 : mpImpl (new Implementation()) 179 {} 180 181 182 183 184 MasterPageObserver::~MasterPageObserver (void) 185 {} 186 187 188 189 190 //===== MasterPageObserver::Implementation ==================================== 191 192 void MasterPageObserver::Implementation::RegisterDocument ( 193 SdDrawDocument& rDocument) 194 { 195 // Gather the names of all the master pages in the given document. 196 MasterPageContainer::data_type aMasterPageSet; 197 sal_uInt16 nMasterPageCount = rDocument.GetMasterSdPageCount(PK_STANDARD); 198 for (sal_uInt16 nIndex=0; nIndex<nMasterPageCount; nIndex++) 199 { 200 SdPage* pMasterPage = rDocument.GetMasterSdPage (nIndex, PK_STANDARD); 201 if (pMasterPage != NULL) 202 aMasterPageSet.insert (pMasterPage->GetName()); 203 } 204 205 maUsedMasterPages[&rDocument] = aMasterPageSet; 206 207 StartListening (rDocument); 208 } 209 210 211 212 213 void MasterPageObserver::Implementation::UnregisterDocument ( 214 SdDrawDocument& rDocument) 215 { 216 EndListening (rDocument); 217 218 MasterPageContainer::iterator aMasterPageDescriptor(maUsedMasterPages.find(&rDocument)); 219 if(aMasterPageDescriptor != maUsedMasterPages.end()) 220 maUsedMasterPages.erase(aMasterPageDescriptor); 221 } 222 223 224 225 226 void MasterPageObserver::Implementation::AddEventListener ( 227 const Link& rEventListener) 228 { 229 if (::std::find ( 230 maListeners.begin(), 231 maListeners.end(), 232 rEventListener) == maListeners.end()) 233 { 234 maListeners.push_back (rEventListener); 235 236 // Tell the new listener about all the master pages that are 237 // currently in use. 238 typedef ::std::vector<String> StringList; 239 StringList aNewMasterPages; 240 StringList aRemovedMasterPages; 241 MasterPageContainer::iterator aDocumentIterator; 242 for (aDocumentIterator=maUsedMasterPages.begin(); 243 aDocumentIterator!=maUsedMasterPages.end(); 244 ++aDocumentIterator) 245 { 246 ::std::set<String>::reverse_iterator aNameIterator; 247 for (aNameIterator=aDocumentIterator->second.rbegin(); 248 aNameIterator!=aDocumentIterator->second.rend(); 249 ++aNameIterator) 250 { 251 MasterPageObserverEvent aEvent ( 252 MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS, 253 *aDocumentIterator->first, 254 *aNameIterator); 255 SendEvent (aEvent); 256 } 257 } 258 } 259 } 260 261 262 263 264 void MasterPageObserver::Implementation::RemoveEventListener ( 265 const Link& rEventListener) 266 { 267 maListeners.erase ( 268 ::std::find ( 269 maListeners.begin(), 270 maListeners.end(), 271 rEventListener)); 272 } 273 274 275 276 277 MasterPageObserver::MasterPageNameSet 278 MasterPageObserver::Implementation::GetMasterPageNames ( 279 SdDrawDocument& rDocument) 280 { 281 MasterPageContainer::iterator aMasterPageDescriptor ( 282 maUsedMasterPages.find(&rDocument)); 283 if (aMasterPageDescriptor != maUsedMasterPages.end()) 284 return aMasterPageDescriptor->second; 285 else 286 // Not found so return an empty set. 287 return MasterPageObserver::MasterPageNameSet(); 288 } 289 290 291 292 293 void MasterPageObserver::Implementation::Notify( 294 SfxBroadcaster& rBroadcaster, 295 const SfxHint& rHint) 296 { 297 if (rHint.ISA(SdrHint)) 298 { 299 SdrHint& rSdrHint (*PTR_CAST(SdrHint,&rHint)); 300 switch (rSdrHint.GetKind()) 301 { 302 case HINT_PAGEORDERCHG: 303 // Process the modified set of pages only when the number of 304 // standard and notes master pages are equal. This test 305 // filters out events that are sent in between the insertion 306 // of a new standard master page and a new notes master 307 // page. 308 if (rBroadcaster.ISA(SdDrawDocument)) 309 { 310 SdDrawDocument& rDocument ( 311 static_cast<SdDrawDocument&>(rBroadcaster)); 312 if (rDocument.GetMasterSdPageCount(PK_STANDARD) 313 == rDocument.GetMasterSdPageCount(PK_NOTES)) 314 { 315 AnalyzeUsedMasterPages (rDocument); 316 } 317 } 318 break; 319 320 default: 321 break; 322 } 323 } 324 } 325 326 327 328 329 void MasterPageObserver::Implementation::AnalyzeUsedMasterPages ( 330 SdDrawDocument& rDocument) 331 { 332 // Create a set of names of the master pages used by the given document. 333 sal_uInt16 nMasterPageCount = rDocument.GetMasterSdPageCount(PK_STANDARD); 334 ::std::set<String> aCurrentMasterPages; 335 for (sal_uInt16 nIndex=0; nIndex<nMasterPageCount; nIndex++) 336 { 337 SdPage* pMasterPage = rDocument.GetMasterSdPage (nIndex, PK_STANDARD); 338 if (pMasterPage != NULL) 339 aCurrentMasterPages.insert (pMasterPage->GetName()); 340 OSL_TRACE("currently used master page %d is %s", 341 nIndex, 342 ::rtl::OUStringToOString(pMasterPage->GetName(), 343 RTL_TEXTENCODING_UTF8).getStr()); 344 } 345 346 typedef ::std::vector<String> StringList; 347 StringList aNewMasterPages; 348 StringList aRemovedMasterPages; 349 MasterPageContainer::iterator aOldMasterPagesDescriptor ( 350 maUsedMasterPages.find(&rDocument)); 351 if (aOldMasterPagesDescriptor != maUsedMasterPages.end()) 352 { 353 StringList::iterator I; 354 355 ::std::set<String>::iterator J; 356 int i=0; 357 for (J=aOldMasterPagesDescriptor->second.begin(); 358 J!=aOldMasterPagesDescriptor->second.end(); 359 ++J) 360 OSL_TRACE("old used master page %d is %s", 361 i++, 362 ::rtl::OUStringToOString(*J, 363 RTL_TEXTENCODING_UTF8).getStr()); 364 365 // Send events about the newly used master pages. 366 ::std::set_difference ( 367 aCurrentMasterPages.begin(), 368 aCurrentMasterPages.end(), 369 aOldMasterPagesDescriptor->second.begin(), 370 aOldMasterPagesDescriptor->second.end(), 371 ::std::back_insert_iterator<StringList>(aNewMasterPages)); 372 for (I=aNewMasterPages.begin(); I!=aNewMasterPages.end(); ++I) 373 { 374 OSL_TRACE(" added master page %s", 375 ::rtl::OUStringToOString(*I, 376 RTL_TEXTENCODING_UTF8).getStr()); 377 378 MasterPageObserverEvent aEvent ( 379 MasterPageObserverEvent::ET_MASTER_PAGE_ADDED, 380 rDocument, 381 *I); 382 SendEvent (aEvent); 383 } 384 385 // Send events about master pages that are not used any longer. 386 ::std::set_difference ( 387 aOldMasterPagesDescriptor->second.begin(), 388 aOldMasterPagesDescriptor->second.end(), 389 aCurrentMasterPages.begin(), 390 aCurrentMasterPages.end(), 391 ::std::back_insert_iterator<StringList>(aRemovedMasterPages)); 392 for (I=aRemovedMasterPages.begin(); I!=aRemovedMasterPages.end(); ++I) 393 { 394 OSL_TRACE(" removed master page %s", 395 ::rtl::OUStringToOString(*I, 396 RTL_TEXTENCODING_UTF8).getStr()); 397 398 MasterPageObserverEvent aEvent ( 399 MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED, 400 rDocument, 401 *I); 402 SendEvent (aEvent); 403 } 404 405 // Store the new list of master pages. 406 aOldMasterPagesDescriptor->second = aCurrentMasterPages; 407 } 408 } 409 410 411 412 413 void MasterPageObserver::Implementation::SendEvent ( 414 MasterPageObserverEvent& rEvent) 415 { 416 ::std::vector<Link>::iterator aLink (maListeners.begin()); 417 ::std::vector<Link>::iterator aEnd (maListeners.end()); 418 while (aLink!=aEnd) 419 { 420 aLink->Call (&rEvent); 421 ++aLink; 422 } 423 } 424 425 426 } // end of namespace sd 427