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