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