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