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 "MasterPageContainer.hxx"
25 
26 #include "MasterPageDescriptor.hxx"
27 #include "MasterPageContainerFiller.hxx"
28 #include "MasterPageContainerQueue.hxx"
29 #include "TemplateScanner.hxx"
30 #include "tools/AsynchronousTask.hxx"
31 #include "strings.hrc"
32 #include <algorithm>
33 #include <list>
34 #include <set>
35 
36 #include "unomodel.hxx"
37 #include <com/sun/star/frame/XComponentLoader.hpp>
38 #include <com/sun/star/io/XStream.hpp>
39 #include <com/sun/star/io/XInputStream.hpp>
40 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
41 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
42 #include <com/sun/star/uno/Reference.hxx>
43 #include <com/sun/star/uno/Any.hxx>
44 #include <com/sun/star/uno/Sequence.hxx>
45 #include <com/sun/star/util/XCloseable.hpp>
46 #include <comphelper/processfactory.hxx>
47 #include <tools/urlobj.hxx>
48 #include <sfx2/app.hxx>
49 #include <svx/svdpage.hxx>
50 #include "DrawDocShell.hxx"
51 #include "drawdoc.hxx"
52 #include "sdpage.hxx"
53 #include <svl/itemset.hxx>
54 #include <svl/eitem.hxx>
55 #include "sdresid.hxx"
56 #include "tools/TimerBasedTaskExecution.hxx"
57 #include "pres.hxx"
58 #include <osl/mutex.hxx>
59 #include <boost/weak_ptr.hpp>
60 
61 using namespace ::com::sun::star;
62 using namespace ::com::sun::star::uno;
63 
64 namespace {
65 
66 typedef ::std::vector<sd::sidebar::SharedMasterPageDescriptor> MasterPageContainerType;
67 
68 } // end of anonymous namespace
69 
70 
71 namespace sd { namespace sidebar {
72 
73 
74 /** Inner implementation class of the MasterPageContainer.
75 */
76 class MasterPageContainer::Implementation
77     : public SdGlobalResource,
78       public MasterPageContainerFiller::ContainerAdapter,
79       public MasterPageContainerQueue::ContainerAdapter
80 {
81 public:
82     mutable ::osl::Mutex maMutex;
83 
84     static ::boost::weak_ptr<Implementation> mpInstance;
85     MasterPageContainerType maContainer;
86 
87     static ::boost::shared_ptr<Implementation> Instance (void);
88 
89     void LateInit (void);
90     void AddChangeListener (const Link& rLink);
91     void RemoveChangeListener (const Link& rLink);
92     void UpdatePreviewSizePixel (void);
93     Size GetPreviewSizePixel (PreviewSize eSize) const;
94 
95     bool HasToken (Token aToken) const;
96     const SharedMasterPageDescriptor GetDescriptor (MasterPageContainer::Token aToken) const;
97     SharedMasterPageDescriptor GetDescriptor (MasterPageContainer::Token aToken);
98     virtual Token PutMasterPage (const SharedMasterPageDescriptor& rDescriptor);
99     void InvalidatePreview (Token aToken);
100     Image GetPreviewForToken (
101         Token aToken,
102         PreviewSize ePreviewSize);
103     PreviewState GetPreviewState (Token aToken) const;
104     bool RequestPreview (Token aToken);
105 
106     Reference<frame::XModel> GetModel (void);
107     SdDrawDocument* GetDocument (void);
108 
109     void FireContainerChange (
110         MasterPageContainerChangeEvent::EventType eType,
111         Token aToken,
112         bool bNotifyAsynchronously = false);
113 
114     virtual bool UpdateDescriptor (
115         const SharedMasterPageDescriptor& rpDescriptor,
116         bool bForcePageObject,
117         bool bForcePreview,
118         bool bSendEvents);
119 
120     void ReleaseDescriptor (Token aToken);
121 
122     /** Called by the MasterPageContainerFiller to notify that all master
123         pages from template documents have been added.
124     */
125     virtual void FillingDone (void);
126 
127 private:
128     Implementation (void);
129     virtual ~Implementation (void);
130 
131     class Deleter { public:
132         void operator() (Implementation* pObject) { delete pObject; }
133     };
134     friend class Deleter;
135 
136     enum InitializationState { NOT_INITIALIZED, INITIALIZING, INITIALIZED } meInitializationState;
137 
138     ::boost::scoped_ptr<MasterPageContainerQueue> mpRequestQueue;
139     ::com::sun::star::uno::Reference<com::sun::star::frame::XModel> mxModel;
140     SdDrawDocument* mpDocument;
141     PreviewRenderer maPreviewRenderer;
142     /** Remember whether the first page object has already been used to
143         determine the correct size ratio.
144     */
145     bool mbFirstPageObjectSeen;
146 
147     // The widths for the previews contain two pixels for the border that is
148     // painted arround the preview.
149     static const int SMALL_PREVIEW_WIDTH = 72 + 2;
150     static const int LARGE_PREVIEW_WIDTH = 2*72 + 2;
151 
152     /** This substition of page preview shows "Preparing preview" and is
153         shown as long as the actual previews are not being present.
154     */
155     Image maLargePreviewBeingCreated;
156     Image maSmallPreviewBeingCreated;
157 
158     /** This substition of page preview is shown when a preview can not be
159         created and thus is not available.
160     */
161     Image maLargePreviewNotAvailable;
162     Image maSmallPreviewNotAvailable;
163 
164     ::std::vector<Link> maChangeListeners;
165 
166     // We have to remember the tasks for initialization and filling in case
167     // a MasterPageContainer object is destroyed before these tasks have
168     // been completed.
169     ::boost::weak_ptr<sd::tools::TimerBasedTaskExecution> mpFillerTask;
170 
171     Size maSmallPreviewSizePixel;
172     Size maLargePreviewSizePixel;
173     bool mbPageRatioKnown;
174 
175     bool mbContainerCleaningPending;
176 
177     typedef ::std::pair<MasterPageContainerChangeEvent::EventType,Token> EventData;
178     DECL_LINK(AsynchronousNotifyCallback, EventData*);
179     ::sd::DrawDocShell* LoadDocument (
180         const String& sFileName,
181         SfxObjectShellLock& rxDocumentShell);
182 
183     Image GetPreviewSubstitution (sal_uInt16 nId, PreviewSize ePreviewSize);
184 
185     void CleanContainer (void);
186 };
187 
188 
189 
190 
191 //===== MasterPageContainer ===================================================
192 
193 ::boost::weak_ptr<MasterPageContainer::Implementation>
194     MasterPageContainer::Implementation::mpInstance;
195 static const MasterPageContainer::Token NIL_TOKEN (-1);
196 
197 
198 
199 
200 ::boost::shared_ptr<MasterPageContainer::Implementation>
201     MasterPageContainer::Implementation::Instance (void)
202 {
203     ::boost::shared_ptr<MasterPageContainer::Implementation> pInstance;
204 
205     if (Implementation::mpInstance.expired())
206     {
207         ::osl::GetGlobalMutex aMutexFunctor;
208         ::osl::MutexGuard aGuard (aMutexFunctor());
209         if (Implementation::mpInstance.expired())
210         {
211             OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
212             pInstance = ::boost::shared_ptr<MasterPageContainer::Implementation>(
213                 new MasterPageContainer::Implementation(),
214                 MasterPageContainer::Implementation::Deleter());
215             SdGlobalResourceContainer::Instance().AddResource(pInstance);
216             Implementation::mpInstance = pInstance;
217         }
218         else
219             pInstance = ::boost::shared_ptr<MasterPageContainer::Implementation>(
220                 Implementation::mpInstance);
221     }
222     else
223     {
224         OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
225         pInstance = ::boost::shared_ptr<MasterPageContainer::Implementation>(
226             Implementation::mpInstance);
227     }
228 
229     DBG_ASSERT (pInstance.get()!=NULL,
230         "MasterPageContainer::Implementation::Instance(): instance is NULL");
231     return pInstance;
232 }
233 
234 
235 
236 
237 MasterPageContainer::MasterPageContainer (void)
238     : mpImpl(Implementation::Instance()),
239       mePreviewSize(SMALL)
240 {
241     mpImpl->LateInit();
242 }
243 
244 
245 
246 
247 MasterPageContainer::~MasterPageContainer (void)
248 {
249 }
250 
251 
252 
253 
254 void MasterPageContainer::AddChangeListener (const Link& rLink)
255 {
256     mpImpl->AddChangeListener(rLink);
257 }
258 
259 
260 
261 
262 void MasterPageContainer::RemoveChangeListener (const Link& rLink)
263 {
264     mpImpl->RemoveChangeListener(rLink);
265 }
266 
267 
268 
269 
270 void MasterPageContainer::SetPreviewSize (PreviewSize eSize)
271 {
272     mePreviewSize = eSize;
273     mpImpl->FireContainerChange(
274         MasterPageContainerChangeEvent::SIZE_CHANGED,
275         NIL_TOKEN);
276 }
277 
278 
279 
280 
281 MasterPageContainer::PreviewSize MasterPageContainer::GetPreviewSize (void) const
282 {
283     return mePreviewSize;
284 }
285 
286 
287 
288 
289 Size MasterPageContainer::GetPreviewSizePixel (void) const
290 {
291     return mpImpl->GetPreviewSizePixel(mePreviewSize);
292 }
293 
294 
295 
296 
297 MasterPageContainer::Token MasterPageContainer::PutMasterPage (
298     const SharedMasterPageDescriptor& rDescriptor)
299 {
300     return mpImpl->PutMasterPage(rDescriptor);
301 }
302 
303 
304 
305 
306 void MasterPageContainer::AcquireToken (Token aToken)
307 {
308     SharedMasterPageDescriptor pDescriptor = mpImpl->GetDescriptor(aToken);
309     if (pDescriptor.get() != NULL)
310     {
311         ++pDescriptor->mnUseCount;
312     }
313 }
314 
315 
316 
317 
318 void MasterPageContainer::ReleaseToken (Token aToken)
319 {
320     SharedMasterPageDescriptor pDescriptor = mpImpl->GetDescriptor(aToken);
321     if (pDescriptor.get() != NULL)
322     {
323         OSL_ASSERT(pDescriptor->mnUseCount>0);
324         --pDescriptor->mnUseCount;
325         if (pDescriptor->mnUseCount <= 0)
326         {
327             switch (pDescriptor->meOrigin)
328             {
329                 case DEFAULT:
330                 case TEMPLATE:
331                 default:
332                     break;
333 
334                 case MASTERPAGE:
335                     mpImpl->ReleaseDescriptor(aToken);
336                     break;
337             }
338         }
339     }
340 }
341 
342 
343 
344 
345 int MasterPageContainer::GetTokenCount (void) const
346 {
347     const ::osl::MutexGuard aGuard (mpImpl->maMutex);
348 
349     return mpImpl->maContainer.size();
350 }
351 
352 
353 
354 
355 bool MasterPageContainer::HasToken (Token aToken) const
356 {
357     const ::osl::MutexGuard aGuard (mpImpl->maMutex);
358 
359     return mpImpl->HasToken(aToken);
360 }
361 
362 
363 
364 
365 MasterPageContainer::Token MasterPageContainer::GetTokenForIndex (int nIndex)
366 {
367     const ::osl::MutexGuard aGuard (mpImpl->maMutex);
368 
369     Token aResult (NIL_TOKEN);
370     if (HasToken(nIndex))
371         aResult = mpImpl->maContainer[nIndex]->maToken;
372     return aResult;
373 }
374 
375 
376 
377 
378 MasterPageContainer::Token MasterPageContainer::GetTokenForURL (
379     const String& sURL)
380 {
381     const ::osl::MutexGuard aGuard (mpImpl->maMutex);
382 
383     Token aResult (NIL_TOKEN);
384     if (sURL.Len() > 0)
385     {
386         MasterPageContainerType::iterator iEntry (
387             ::std::find_if (
388                 mpImpl->maContainer.begin(),
389                 mpImpl->maContainer.end(),
390                 MasterPageDescriptor::URLComparator(sURL)));
391         if (iEntry != mpImpl->maContainer.end())
392             aResult = (*iEntry)->maToken;
393     }
394     return aResult;
395 }
396 
397 
398 
399 
400 MasterPageContainer::Token MasterPageContainer::GetTokenForStyleName (const String& sStyleName)
401 {
402     const ::osl::MutexGuard aGuard (mpImpl->maMutex);
403 
404     Token aResult (NIL_TOKEN);
405     if (sStyleName.Len() > 0)
406     {
407         MasterPageContainerType::iterator iEntry (
408             ::std::find_if (
409                 mpImpl->maContainer.begin(),
410                 mpImpl->maContainer.end(),
411                 MasterPageDescriptor::StyleNameComparator(sStyleName)));
412         if (iEntry != mpImpl->maContainer.end())
413             aResult = (*iEntry)->maToken;
414     }
415     return aResult;
416 }
417 
418 
419 
420 
421 MasterPageContainer::Token MasterPageContainer::GetTokenForPageObject (
422     const SdPage* pPage)
423 {
424     const ::osl::MutexGuard aGuard (mpImpl->maMutex);
425 
426     Token aResult (NIL_TOKEN);
427     if (pPage != NULL)
428     {
429         MasterPageContainerType::iterator iEntry (
430             ::std::find_if (
431                 mpImpl->maContainer.begin(),
432                 mpImpl->maContainer.end(),
433                 MasterPageDescriptor::PageObjectComparator(pPage)));
434         if (iEntry != mpImpl->maContainer.end())
435             aResult = (*iEntry)->maToken;
436     }
437     return aResult;
438 }
439 
440 
441 
442 
443 String MasterPageContainer::GetURLForToken (
444     MasterPageContainer::Token aToken)
445 {
446     const ::osl::MutexGuard aGuard (mpImpl->maMutex);
447 
448     SharedMasterPageDescriptor pDescriptor = mpImpl->GetDescriptor(aToken);
449     if (pDescriptor.get() != NULL)
450         return pDescriptor->msURL;
451     else
452         return String();
453 }
454 
455 
456 
457 
458 String MasterPageContainer::GetPageNameForToken (
459     MasterPageContainer::Token aToken)
460 {
461     const ::osl::MutexGuard aGuard (mpImpl->maMutex);
462 
463     SharedMasterPageDescriptor pDescriptor = mpImpl->GetDescriptor(aToken);
464     if (pDescriptor.get() != NULL)
465         return pDescriptor->msPageName;
466     else
467         return String();
468 }
469 
470 
471 
472 
473 String MasterPageContainer::GetStyleNameForToken (
474     MasterPageContainer::Token aToken)
475 {
476     const ::osl::MutexGuard aGuard (mpImpl->maMutex);
477 
478     SharedMasterPageDescriptor pDescriptor = mpImpl->GetDescriptor(aToken);
479     if (pDescriptor.get() != NULL)
480         return pDescriptor->msStyleName;
481     else
482         return String();
483 }
484 
485 
486 
487 
488 SdPage* MasterPageContainer::GetPageObjectForToken (
489     MasterPageContainer::Token aToken,
490     bool bLoad)
491 {
492     const ::osl::MutexGuard aGuard (mpImpl->maMutex);
493 
494     SdPage* pPageObject = NULL;
495     SharedMasterPageDescriptor pDescriptor = mpImpl->GetDescriptor(aToken);
496     if (pDescriptor.get() != NULL)
497     {
498         pPageObject = pDescriptor->mpMasterPage;
499         if (pPageObject == NULL)
500         {
501             // The page object is not (yet) present.  Call
502             // UpdateDescriptor() to trigger the PageObjectProvider() to
503             // provide it.
504             if (bLoad)
505                 mpImpl->GetModel();
506             if (mpImpl->UpdateDescriptor(pDescriptor,bLoad,false, true))
507                 pPageObject = pDescriptor->mpMasterPage;
508         }
509     }
510     return pPageObject;
511 }
512 
513 
514 
515 
516 MasterPageContainer::Origin MasterPageContainer::GetOriginForToken (Token aToken)
517 {
518     const ::osl::MutexGuard aGuard (mpImpl->maMutex);
519 
520     SharedMasterPageDescriptor pDescriptor = mpImpl->GetDescriptor(aToken);
521     if (pDescriptor.get() != NULL)
522         return pDescriptor->meOrigin;
523     else
524         return UNKNOWN;
525 }
526 
527 
528 
529 
530 sal_Int32 MasterPageContainer::GetTemplateIndexForToken (Token aToken)
531 {
532     const ::osl::MutexGuard aGuard (mpImpl->maMutex);
533 
534     SharedMasterPageDescriptor pDescriptor = mpImpl->GetDescriptor(aToken);
535     if (pDescriptor.get() != NULL)
536         return pDescriptor->mnTemplateIndex;
537     else
538         return -1;
539 }
540 
541 
542 
543 
544 SharedMasterPageDescriptor MasterPageContainer::GetDescriptorForToken (
545     MasterPageContainer::Token aToken)
546 {
547     const ::osl::MutexGuard aGuard (mpImpl->maMutex);
548 
549     return mpImpl->GetDescriptor(aToken);
550 }
551 
552 
553 
554 void MasterPageContainer::InvalidatePreview (MasterPageContainer::Token aToken)
555 {
556     mpImpl->InvalidatePreview(aToken);
557 }
558 
559 
560 
561 
562 Image MasterPageContainer::GetPreviewForToken (MasterPageContainer::Token aToken)
563 {
564     return mpImpl->GetPreviewForToken(aToken,mePreviewSize);
565 }
566 
567 
568 
569 
570 MasterPageContainer::PreviewState MasterPageContainer::GetPreviewState (Token aToken)
571 {
572     return mpImpl->GetPreviewState(aToken);
573 }
574 
575 
576 
577 
578 bool MasterPageContainer::RequestPreview (Token aToken)
579 {
580     return mpImpl->RequestPreview(aToken);
581 }
582 
583 
584 
585 
586 //==== Implementation ================================================
587 
588 MasterPageContainer::Implementation::Implementation (void)
589     : maMutex(),
590       maContainer(),
591 	  meInitializationState(NOT_INITIALIZED),
592       mpRequestQueue(NULL),
593       mxModel(NULL),
594       mpDocument(NULL),
595       maPreviewRenderer(),
596       mbFirstPageObjectSeen(false),
597       maLargePreviewBeingCreated(),
598       maSmallPreviewBeingCreated(),
599       maLargePreviewNotAvailable(),
600       maSmallPreviewNotAvailable(),
601       maChangeListeners(),
602       maSmallPreviewSizePixel(),
603       maLargePreviewSizePixel(),
604       mbPageRatioKnown(false),
605       mbContainerCleaningPending(true)
606 
607 {
608     UpdatePreviewSizePixel();
609 }
610 
611 
612 
613 
614 MasterPageContainer::Implementation::~Implementation (void)
615 {
616     // When the initializer or filler tasks are still running then we have
617     // to stop them now in order to prevent them from calling us back.
618     tools::TimerBasedTaskExecution::ReleaseTask(mpFillerTask);
619 
620     mpRequestQueue.reset();
621 
622     uno::Reference<util::XCloseable> xCloseable (mxModel, uno::UNO_QUERY);
623     if (xCloseable.is())
624     {
625         try
626         {
627             xCloseable->close(true);
628         }
629         catch (::com::sun::star::util::CloseVetoException aException)
630         {
631         }
632     }
633     mxModel = NULL;
634 }
635 
636 
637 
638 
639 void MasterPageContainer::Implementation::LateInit (void)
640 {
641     const ::osl::MutexGuard aGuard (maMutex);
642 
643     if (meInitializationState == NOT_INITIALIZED)
644     {
645         meInitializationState = INITIALIZING;
646 
647         OSL_ASSERT(Instance().get()==this);
648         mpRequestQueue.reset(MasterPageContainerQueue::Create(
649             ::boost::shared_ptr<MasterPageContainerQueue::ContainerAdapter>(Instance())));
650 
651         mpFillerTask = ::sd::tools::TimerBasedTaskExecution::Create(
652             ::boost::shared_ptr<tools::AsynchronousTask>(new MasterPageContainerFiller(*this)),
653             5,
654             50);
655 
656         meInitializationState = INITIALIZED;
657     }
658 }
659 
660 
661 
662 
663 void MasterPageContainer::Implementation::AddChangeListener (const Link& rLink)
664 {
665     const ::osl::MutexGuard aGuard (maMutex);
666 
667     ::std::vector<Link>::iterator iListener (
668         ::std::find(maChangeListeners.begin(),maChangeListeners.end(),rLink));
669     if (iListener == maChangeListeners.end())
670         maChangeListeners.push_back(rLink);
671 
672 }
673 
674 
675 
676 
677 void MasterPageContainer::Implementation::RemoveChangeListener (const Link& rLink)
678 {
679     const ::osl::MutexGuard aGuard (maMutex);
680 
681     ::std::vector<Link>::iterator iListener (
682         ::std::find(maChangeListeners.begin(),maChangeListeners.end(),rLink));
683     if (iListener != maChangeListeners.end())
684         maChangeListeners.erase(iListener);
685 }
686 
687 
688 
689 
690 void MasterPageContainer::Implementation::UpdatePreviewSizePixel (void)
691 {
692     const ::osl::MutexGuard aGuard (maMutex);
693 
694     // The default aspect ratio is 4:3
695     int nWidth (4);
696     int nHeight (3);
697 
698     // Search for the first entry with an existing master page.
699     MasterPageContainerType::const_iterator iDescriptor;
700     MasterPageContainerType::const_iterator iContainerEnd(maContainer.end());
701     for (iDescriptor=maContainer.begin(); iDescriptor!=iContainerEnd; ++iDescriptor)
702         if (*iDescriptor!=NULL && (*iDescriptor)->mpMasterPage != NULL)
703         {
704             Size aPageSize ((*iDescriptor)->mpMasterPage->GetSize());
705             nWidth = aPageSize.Width();
706             nHeight = aPageSize.Height();
707             mbFirstPageObjectSeen = true;
708             break;
709         }
710 
711     maSmallPreviewSizePixel.Width() = SMALL_PREVIEW_WIDTH;
712     maLargePreviewSizePixel.Width() = LARGE_PREVIEW_WIDTH;
713 
714     int nNewSmallHeight ((maSmallPreviewSizePixel.Width()-2) * nHeight / nWidth + 2);
715     int nNewLargeHeight ((maLargePreviewSizePixel.Width()-2) * nHeight / nWidth + 2);
716 
717     if (nNewSmallHeight!=maSmallPreviewSizePixel.Height()
718         || nNewLargeHeight!=maLargePreviewSizePixel.Height())
719     {
720         maSmallPreviewSizePixel.Height() = nNewSmallHeight;
721         maLargePreviewSizePixel.Height() = nNewLargeHeight;
722         FireContainerChange(
723             MasterPageContainerChangeEvent::SIZE_CHANGED,
724             NIL_TOKEN);
725     }
726 }
727 
728 
729 
730 
731 Size MasterPageContainer::Implementation::GetPreviewSizePixel (PreviewSize eSize) const
732 {
733     if (eSize == SMALL)
734         return maSmallPreviewSizePixel;
735     else
736         return maLargePreviewSizePixel;
737 }
738 
739 
740 
741 
742 IMPL_LINK(MasterPageContainer::Implementation,AsynchronousNotifyCallback, EventData*, pData)
743 {
744     const ::osl::MutexGuard aGuard (maMutex);
745 
746     if (pData != NULL)
747     {
748         FireContainerChange(pData->first, pData->second, false);
749         delete pData;
750     }
751 
752     return 0;
753 }
754 
755 
756 
757 
758 MasterPageContainer::Token MasterPageContainer::Implementation::PutMasterPage (
759     const SharedMasterPageDescriptor& rpDescriptor)
760 {
761     const ::osl::MutexGuard aGuard (maMutex);
762 
763     Token aResult (NIL_TOKEN);
764 
765     // Get page object and preview when that is inexpensive.
766     UpdateDescriptor(rpDescriptor,false,false, false);
767 
768     // Look up the new MasterPageDescriptor and either insert it or update
769     // an already existing one.
770     MasterPageContainerType::iterator aEntry (
771         ::std::find_if (
772             maContainer.begin(),
773             maContainer.end(),
774             MasterPageDescriptor::AllComparator(rpDescriptor)));
775     if (aEntry == maContainer.end())
776     {
777         // Insert a new MasterPageDescriptor.
778         bool bIgnore (rpDescriptor->mpPageObjectProvider.get()==NULL
779             && rpDescriptor->msURL.getLength()==0);
780 
781         if ( ! bIgnore)
782         {
783             if (mbContainerCleaningPending)
784                 CleanContainer();
785 
786             aResult = maContainer.size();
787             rpDescriptor->SetToken(aResult);
788 
789             // Templates are precious, i.e. we lock them so that they will
790             // not be destroyed when (temporarily) no one references them.
791             // They will only be deleted when the container is destroyed.
792             switch (rpDescriptor->meOrigin)
793             {
794                 case TEMPLATE:
795                 case DEFAULT:
796                     ++rpDescriptor->mnUseCount;
797                     break;
798 
799                 default:
800                     break;
801             }
802 
803             maContainer.push_back(rpDescriptor);
804             aEntry = maContainer.end()-1;
805 
806             FireContainerChange(MasterPageContainerChangeEvent::CHILD_ADDED,aResult);
807         }
808     }
809     else
810     {
811         // Update an existing MasterPageDescriptor.
812         aResult = (*aEntry)->maToken;
813         ::std::auto_ptr<std::vector<MasterPageContainerChangeEvent::EventType> > pEventTypes(
814             (*aEntry)->Update(*rpDescriptor));
815         if (pEventTypes.get()!=NULL && pEventTypes->size()>0)
816         {
817             // One or more aspects of the descriptor have changed.  Send
818             // appropriate events to the listeners.
819             UpdateDescriptor(*aEntry,false,false, true);
820 
821             std::vector<MasterPageContainerChangeEvent::EventType>::const_iterator iEventType;
822             for (iEventType=pEventTypes->begin(); iEventType!=pEventTypes->end(); ++iEventType)
823             {
824                 FireContainerChange(
825                     *iEventType,
826                     (*aEntry)->maToken,
827                     false);
828             }
829         }
830     }
831 
832     return aResult;
833 }
834 
835 
836 
837 
838 bool MasterPageContainer::Implementation::HasToken (Token aToken) const
839 {
840     return aToken>=0
841         && (unsigned)aToken<maContainer.size()
842         && maContainer[aToken].get()!=NULL;
843 }
844 
845 
846 
847 
848 const SharedMasterPageDescriptor MasterPageContainer::Implementation::GetDescriptor (
849     Token aToken) const
850 {
851     if (aToken>=0 && (unsigned)aToken<maContainer.size())
852         return maContainer[aToken];
853     else
854         return SharedMasterPageDescriptor();
855 }
856 
857 
858 
859 
860 SharedMasterPageDescriptor MasterPageContainer::Implementation::GetDescriptor (Token aToken)
861 {
862     if (aToken>=0 && (unsigned)aToken<maContainer.size())
863         return maContainer[aToken];
864     else
865         return SharedMasterPageDescriptor();
866 }
867 
868 
869 
870 
871 void MasterPageContainer::Implementation::InvalidatePreview (Token aToken)
872 {
873     const ::osl::MutexGuard aGuard (maMutex);
874 
875     SharedMasterPageDescriptor pDescriptor (GetDescriptor(aToken));
876     if (pDescriptor.get() != NULL)
877     {
878         pDescriptor->maSmallPreview = Image();
879         pDescriptor->maLargePreview = Image();
880         RequestPreview(aToken);
881     }
882 }
883 
884 
885 
886 
887 Image MasterPageContainer::Implementation::GetPreviewForToken (
888     MasterPageContainer::Token aToken,
889     PreviewSize ePreviewSize)
890 {
891     const ::osl::MutexGuard aGuard (maMutex);
892 
893     Image aPreview;
894     PreviewState ePreviewState (GetPreviewState(aToken));
895 
896     SharedMasterPageDescriptor pDescriptor = GetDescriptor(aToken);
897 
898     // When the preview is missing but inexpensively creatable then do that
899     // now.
900     if (pDescriptor.get()!=NULL)
901     {
902         if (ePreviewState == PS_CREATABLE)
903             if (UpdateDescriptor(pDescriptor, false,false, true))
904                 if (pDescriptor->maLargePreview.GetSizePixel().Width() != 0)
905                     ePreviewState = PS_AVAILABLE;
906 
907         switch (ePreviewState)
908         {
909             case PS_AVAILABLE:
910                 aPreview = pDescriptor->GetPreview(ePreviewSize);
911                 break;
912 
913             case PS_PREPARING:
914                 aPreview = GetPreviewSubstitution(
915                     STR_TASKPANEL_PREPARING_PREVIEW_SUBSTITUTION,
916                     ePreviewSize);
917                 break;
918 
919             case PS_CREATABLE:
920                 aPreview = GetPreviewSubstitution(
921                     STR_TASKPANEL_PREPARING_PREVIEW_SUBSTITUTION,
922                     ePreviewSize);
923                 break;
924 
925             case PS_NOT_AVAILABLE:
926                 aPreview = GetPreviewSubstitution(
927                     STR_TASKPANEL_NOT_AVAILABLE_SUBSTITUTION,
928                     ePreviewSize);
929                 if (ePreviewSize == SMALL)
930                     pDescriptor->maSmallPreview = aPreview;
931                 else
932                     pDescriptor->maLargePreview = aPreview;
933                 break;
934         }
935     }
936 
937     return aPreview;
938 }
939 
940 
941 
942 
943 MasterPageContainer::PreviewState MasterPageContainer::Implementation::GetPreviewState (
944     Token aToken) const
945 {
946     const ::osl::MutexGuard aGuard (maMutex);
947 
948     PreviewState eState (PS_NOT_AVAILABLE);
949 
950     SharedMasterPageDescriptor pDescriptor = GetDescriptor(aToken);
951     if (pDescriptor.get() != NULL)
952     {
953         if (pDescriptor->maLargePreview.GetSizePixel().Width() != 0)
954             eState = PS_AVAILABLE;
955         else if (pDescriptor->mpPreviewProvider.get() != NULL)
956         {
957             // The preview does not exist but can be created.  When that is
958             // not expensive then do it at once.
959             if (mpRequestQueue->HasRequest(aToken))
960                 eState = PS_PREPARING;
961             else
962                 eState = PS_CREATABLE;
963         }
964         else
965             eState = PS_NOT_AVAILABLE;
966     }
967 
968     return eState;
969 }
970 
971 
972 
973 
974 bool MasterPageContainer::Implementation::RequestPreview (Token aToken)
975 {
976     SharedMasterPageDescriptor pDescriptor = GetDescriptor(aToken);
977     if (pDescriptor.get() != NULL)
978         return mpRequestQueue->RequestPreview(pDescriptor);
979     else
980         return false;
981 }
982 
983 
984 
985 
986 Reference<frame::XModel> MasterPageContainer::Implementation::GetModel (void)
987 {
988     const ::osl::MutexGuard aGuard (maMutex);
989 
990     if ( ! mxModel.is())
991     {
992         // Get the desktop a s service factory.
993         ::rtl::OUString sDesktopServiceName (
994             RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop"));
995         uno::Reference<frame::XComponentLoader> xDesktop (
996             ::comphelper::getProcessServiceFactory()->createInstance(
997                 sDesktopServiceName),
998             uno::UNO_QUERY);
999 
1000         // Create a new model.
1001         ::rtl::OUString sModelServiceName (
1002             RTL_CONSTASCII_USTRINGPARAM(
1003                 "com.sun.star.presentation.PresentationDocument"));
1004         mxModel = uno::Reference<frame::XModel>(
1005             ::comphelper::getProcessServiceFactory()->createInstance(
1006                 sModelServiceName),
1007             uno::UNO_QUERY);
1008 
1009         // Initialize the model.
1010         uno::Reference<frame::XLoadable> xLoadable (mxModel,uno::UNO_QUERY);
1011         if (xLoadable.is())
1012             xLoadable->initNew();
1013 
1014         // Use its tunnel to get a pointer to its core implementation.
1015         uno::Reference<lang::XUnoTunnel> xUnoTunnel (mxModel, uno::UNO_QUERY);
1016         if (xUnoTunnel.is())
1017         {
1018             mpDocument = reinterpret_cast<SdXImpressDocument*>(
1019                 xUnoTunnel->getSomething(
1020                     SdXImpressDocument::getUnoTunnelId()))->GetDoc();
1021         }
1022 
1023         // Create a default page.
1024         uno::Reference<drawing::XDrawPagesSupplier> xSlideSupplier (mxModel, uno::UNO_QUERY);
1025         if (xSlideSupplier.is())
1026         {
1027             uno::Reference<drawing::XDrawPages> xSlides (
1028                 xSlideSupplier->getDrawPages(), uno::UNO_QUERY);
1029             if (xSlides.is())
1030             {
1031                 sal_Int32 nIndex (0);
1032                 uno::Reference<drawing::XDrawPage> xNewPage (xSlides->insertNewByIndex(nIndex));
1033                 uno::Reference<beans::XPropertySet> xProperties(xNewPage, uno::UNO_QUERY);
1034                 if (xProperties.is())
1035                     xProperties->setPropertyValue(
1036                         rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Layout")),
1037                         makeAny((sal_Int16)AUTOLAYOUT_TITLE));
1038             }
1039         }
1040     }
1041     return mxModel;
1042 }
1043 
1044 
1045 
1046 
1047 SdDrawDocument* MasterPageContainer::Implementation::GetDocument (void)
1048 {
1049     GetModel();
1050     return mpDocument;
1051 }
1052 
1053 
1054 
1055 
1056 Image MasterPageContainer::Implementation::GetPreviewSubstitution (
1057     sal_uInt16 nId,
1058     PreviewSize ePreviewSize)
1059 {
1060     const ::osl::MutexGuard aGuard (maMutex);
1061 
1062     Image aPreview;
1063 
1064     switch (nId)
1065     {
1066         case STR_TASKPANEL_PREPARING_PREVIEW_SUBSTITUTION:
1067         {
1068             Image& rPreview (ePreviewSize==SMALL
1069                 ? maSmallPreviewBeingCreated
1070                 : maLargePreviewBeingCreated);
1071             if (rPreview.GetSizePixel().Width() == 0)
1072             {
1073                 rPreview = maPreviewRenderer.RenderSubstitution(
1074                     ePreviewSize==SMALL ? maSmallPreviewSizePixel : maLargePreviewSizePixel,
1075                     SdResId(STR_TASKPANEL_PREPARING_PREVIEW_SUBSTITUTION));
1076             }
1077             aPreview = rPreview;
1078         }
1079         break;
1080 
1081         case STR_TASKPANEL_NOT_AVAILABLE_SUBSTITUTION:
1082         {
1083             Image& rPreview (ePreviewSize==SMALL
1084                 ? maSmallPreviewNotAvailable
1085                 : maLargePreviewNotAvailable);
1086             if (rPreview.GetSizePixel().Width() == 0)
1087             {
1088                 rPreview = maPreviewRenderer.RenderSubstitution(
1089                     ePreviewSize==SMALL ? maSmallPreviewSizePixel : maLargePreviewSizePixel,
1090                     SdResId(STR_TASKPANEL_NOT_AVAILABLE_SUBSTITUTION));
1091             }
1092             aPreview = rPreview;
1093         }
1094         break;
1095     }
1096 
1097     return aPreview;
1098 }
1099 
1100 
1101 
1102 
1103 void MasterPageContainer::Implementation::CleanContainer (void)
1104 {
1105     // Remove the empty elements at the end of the container.  The empty
1106     // elements in the middle can not be removed because that would
1107     // invalidate the references still held by others.
1108     int nIndex (maContainer.size()-1);
1109     while (nIndex>=0 && maContainer[nIndex].get()==NULL)
1110         --nIndex;
1111     maContainer.resize(++nIndex);
1112 }
1113 
1114 
1115 
1116 
1117 void MasterPageContainer::Implementation::FireContainerChange (
1118     MasterPageContainerChangeEvent::EventType eType,
1119     Token aToken,
1120     bool bNotifyAsynchronously)
1121 {
1122     if (bNotifyAsynchronously)
1123     {
1124         Application::PostUserEvent(
1125             LINK(this,Implementation,AsynchronousNotifyCallback),
1126             new EventData(eType,aToken));
1127     }
1128     else
1129     {
1130         ::std::vector<Link> aCopy(maChangeListeners.begin(),maChangeListeners.end());
1131         ::std::vector<Link>::iterator iListener;
1132         MasterPageContainerChangeEvent aEvent;
1133         aEvent.meEventType = eType;
1134         aEvent.maChildToken = aToken;
1135         for (iListener=aCopy.begin(); iListener!=aCopy.end(); ++iListener)
1136             iListener->Call(&aEvent);
1137     }
1138 }
1139 
1140 
1141 
1142 
1143 bool MasterPageContainer::Implementation::UpdateDescriptor (
1144     const SharedMasterPageDescriptor& rpDescriptor,
1145     bool bForcePageObject,
1146     bool bForcePreview,
1147     bool bSendEvents)
1148 {
1149     const ::osl::MutexGuard aGuard (maMutex);
1150 
1151     // We have to create the page object when the preview provider needs it
1152     // and the caller needs the preview.
1153     bForcePageObject |= (bForcePreview
1154         && rpDescriptor->mpPreviewProvider->NeedsPageObject()
1155         && rpDescriptor->mpMasterPage==NULL);
1156 
1157     // Define a cost threshold so that an update or page object or preview
1158     // that is at least this cost are made at once. Updates with higher cost
1159     // are scheduled for later.
1160     sal_Int32 nCostThreshold (mpRequestQueue->IsEmpty() ? 5 : 0);
1161 
1162     // Update the page object (which may be used for the preview update).
1163     if (bForcePageObject)
1164         GetDocument();
1165     bool bPageObjectModified (rpDescriptor->UpdatePageObject(
1166         (bForcePageObject ? -1 : nCostThreshold),
1167         mpDocument));
1168     if (bPageObjectModified && bSendEvents)
1169         FireContainerChange(
1170             MasterPageContainerChangeEvent::DATA_CHANGED,
1171             rpDescriptor->maToken);
1172     if (bPageObjectModified && ! mbFirstPageObjectSeen)
1173         UpdatePreviewSizePixel();
1174 
1175     // Update the preview.
1176     bool bPreviewModified (rpDescriptor->UpdatePreview(
1177         (bForcePreview ? -1 : nCostThreshold),
1178         maSmallPreviewSizePixel,
1179         maLargePreviewSizePixel,
1180         maPreviewRenderer));
1181 
1182     if (bPreviewModified && bSendEvents)
1183         FireContainerChange(
1184             MasterPageContainerChangeEvent::PREVIEW_CHANGED,
1185             rpDescriptor->maToken);
1186 
1187     return bPageObjectModified || bPreviewModified;
1188 }
1189 
1190 
1191 
1192 
1193 void MasterPageContainer::Implementation::ReleaseDescriptor (Token aToken)
1194 {
1195     if (aToken>=0 && (unsigned)aToken<maContainer.size())
1196     {
1197         maContainer[aToken].reset();
1198         mbContainerCleaningPending = true;
1199     }
1200 }
1201 
1202 
1203 
1204 
1205 void MasterPageContainer::Implementation::FillingDone (void)
1206 {
1207     mpRequestQueue->ProcessAllRequests();
1208 }
1209 
1210 
1211 
1212 } } // end of namespace sd::sidebar
1213