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 // MARKER(update_precomp.py): autogen include statement, do not remove
24 #include "precompiled_sd.hxx"
25 
26 #include "precompiled_sd.hxx"
27 
28 #include "PresenterPreviewCache.hxx"
29 
30 #include "cache/SlsCacheContext.hxx"
31 #include "tools/IdleDetection.hxx"
32 #include "sdpage.hxx"
33 #include <cppcanvas/vclfactory.hxx>
34 #include <com/sun/star/drawing/XDrawPage.hpp>
35 #include <com/sun/star/rendering/XBitmapCanvas.hpp>
36 
37 using namespace ::com::sun::star;
38 using namespace ::com::sun::star::uno;
39 using namespace ::sd::slidesorter::cache;
40 using ::rtl::OUString;
41 
42 namespace sd { namespace presenter {
43 
44 
45 class PresenterPreviewCache::PresenterCacheContext : public CacheContext
46 {
47 public:
48     PresenterCacheContext (void);
49     virtual ~PresenterCacheContext (void);
50 
51     void SetDocumentSlides (
52         const Reference<container::XIndexAccess>& rxSlides,
53         const Reference<XInterface>& rxDocument);
54     void SetVisibleSlideRange (
55         const sal_Int32 nFirstVisibleSlideIndex,
56         const sal_Int32 nLastVisibleSlideIndex);
57     const SdrPage* GetPage (const sal_Int32 nSlideIndex) const;
58     void AddPreviewCreationNotifyListener (const Reference<drawing::XSlidePreviewCacheListener>& rxListener);
59     void RemovePreviewCreationNotifyListener (const Reference<drawing::XSlidePreviewCacheListener>& rxListener);
60 
61     // CacheContext
62     virtual void NotifyPreviewCreation (
63         CacheKey aKey,
64         const Bitmap& rPreview);
65     virtual bool IsIdle (void);
66     virtual bool IsVisible (CacheKey aKey);
67     virtual const SdrPage* GetPage (CacheKey aKey);
68     virtual ::boost::shared_ptr<std::vector<CacheKey> > GetEntryList (bool bVisible);
69     virtual sal_Int32 GetPriority (CacheKey aKey);
70     virtual ::com::sun::star::uno::Reference<com::sun::star::uno::XInterface> GetModel (void);
71 
72 private:
73     Reference<container::XIndexAccess> mxSlides;
74     Reference<XInterface> mxDocument;
75     sal_Int32 mnFirstVisibleSlideIndex;
76     sal_Int32 mnLastVisibleSlideIndex;
77     typedef ::std::vector<css::uno::Reference<css::drawing::XSlidePreviewCacheListener> > ListenerContainer;
78     ListenerContainer maListeners;
79 
80     void CallListeners (const sal_Int32 nSlideIndex);
81 };
82 
83 
84 
85 
86 //===== Service ===============================================================
87 
88 Reference<XInterface> SAL_CALL PresenterPreviewCache_createInstance (
89     const Reference<XComponentContext>& rxContext)
90 {
91     return Reference<XInterface>(static_cast<XWeak*>(new PresenterPreviewCache(rxContext)));
92 }
93 
94 
95 
96 
97 ::rtl::OUString PresenterPreviewCache_getImplementationName (void) throw(RuntimeException)
98 {
99     return OUString::createFromAscii("com.sun.star.comp.Draw.PresenterPreviewCache");
100 }
101 
102 
103 
104 
105 Sequence<rtl::OUString> SAL_CALL PresenterPreviewCache_getSupportedServiceNames (void)
106     throw (RuntimeException)
107 {
108 	static const ::rtl::OUString sServiceName(
109         ::rtl::OUString::createFromAscii("com.sun.star.drawing.PresenterPreviewCache"));
110 	return Sequence<rtl::OUString>(&sServiceName, 1);
111 }
112 
113 
114 
115 
116 //===== PresenterPreviewCache =================================================
117 
118 PresenterPreviewCache::PresenterPreviewCache (const Reference<XComponentContext>& rxContext)
119     : PresenterPreviewCacheInterfaceBase(m_aMutex),
120       maPreviewSize(Size(200,200)),
121       mpCacheContext(new PresenterCacheContext()),
122       mpCache(new PageCache(maPreviewSize, false, mpCacheContext))
123 {
124     (void)rxContext;
125 }
126 
127 
128 
129 
130 PresenterPreviewCache::~PresenterPreviewCache (void)
131 {
132 }
133 
134 
135 
136 
137 //----- XInitialize -----------------------------------------------------------
138 
139 void SAL_CALL PresenterPreviewCache::initialize (const Sequence<Any>& rArguments)
140     throw(Exception, RuntimeException)
141 {
142     if (rArguments.getLength() != 0)
143         throw RuntimeException();
144 }
145 
146 
147 
148 
149 //----- XSlidePreviewCache ----------------------------------------------------
150 
151 void SAL_CALL PresenterPreviewCache::setDocumentSlides (
152     const Reference<container::XIndexAccess>& rxSlides,
153     const Reference<XInterface>& rxDocument)
154     throw (RuntimeException)
155 {
156     ThrowIfDisposed();
157     OSL_ASSERT(mpCacheContext.get()!=NULL);
158 
159     mpCacheContext->SetDocumentSlides(rxSlides, rxDocument);
160 }
161 
162 
163 
164 
165 void SAL_CALL PresenterPreviewCache::setVisibleRange (
166     sal_Int32 nFirstVisibleSlideIndex,
167     sal_Int32 nLastVisibleSlideIndex)
168     throw (css::uno::RuntimeException)
169 {
170     ThrowIfDisposed();
171     OSL_ASSERT(mpCacheContext.get()!=NULL);
172 
173     mpCacheContext->SetVisibleSlideRange (nFirstVisibleSlideIndex, nLastVisibleSlideIndex);
174 }
175 
176 
177 
178 
179 void SAL_CALL PresenterPreviewCache::setPreviewSize (
180     const css::geometry::IntegerSize2D& rSize)
181     throw (css::uno::RuntimeException)
182 {
183     ThrowIfDisposed();
184     OSL_ASSERT(mpCache.get()!=NULL);
185 
186     maPreviewSize = Size(rSize.Width, rSize.Height);
187     mpCache->ChangeSize(maPreviewSize, false);
188 }
189 
190 
191 
192 
193 Reference<rendering::XBitmap> SAL_CALL PresenterPreviewCache::getSlidePreview (
194     sal_Int32 nSlideIndex,
195     const Reference<rendering::XCanvas>& rxCanvas)
196     throw (css::uno::RuntimeException)
197 {
198     ThrowIfDisposed();
199     OSL_ASSERT(mpCacheContext.get()!=NULL);
200 
201     cppcanvas::BitmapCanvasSharedPtr pCanvas (
202         cppcanvas::VCLFactory::getInstance().createCanvas(
203             Reference<rendering::XBitmapCanvas>(rxCanvas, UNO_QUERY)));
204 
205     const SdrPage* pPage = mpCacheContext->GetPage(nSlideIndex);
206     if (pPage == NULL)
207         throw RuntimeException();
208 
209     const BitmapEx aPreview (mpCache->GetPreviewBitmap(pPage,true));
210     if (aPreview.IsEmpty())
211         return NULL;
212     else
213         return cppcanvas::VCLFactory::getInstance().createBitmap(
214             pCanvas,
215             aPreview)->getUNOBitmap();
216 }
217 
218 
219 
220 
221 void SAL_CALL PresenterPreviewCache::addPreviewCreationNotifyListener (
222     const Reference<drawing::XSlidePreviewCacheListener>& rxListener)
223     throw (css::uno::RuntimeException)
224 {
225 	if (rBHelper.bDisposed || rBHelper.bInDispose)
226         return;
227     if (rxListener.is())
228         mpCacheContext->AddPreviewCreationNotifyListener(rxListener);
229 }
230 
231 
232 
233 
234 void SAL_CALL PresenterPreviewCache::removePreviewCreationNotifyListener (
235     const css::uno::Reference<css::drawing::XSlidePreviewCacheListener>& rxListener)
236     throw (css::uno::RuntimeException)
237 {
238     ThrowIfDisposed();
239     mpCacheContext->RemovePreviewCreationNotifyListener(rxListener);
240 }
241 
242 
243 
244 
245 void SAL_CALL PresenterPreviewCache::pause (void)
246     throw (css::uno::RuntimeException)
247 {
248     ThrowIfDisposed();
249     OSL_ASSERT(mpCache.get()!=NULL);
250     mpCache->Pause();
251 }
252 
253 
254 
255 
256 void SAL_CALL PresenterPreviewCache::resume (void)
257     throw (css::uno::RuntimeException)
258 {
259     ThrowIfDisposed();
260     OSL_ASSERT(mpCache.get()!=NULL);
261     mpCache->Resume();
262 }
263 
264 
265 
266 
267 //-----------------------------------------------------------------------------
268 
269 void PresenterPreviewCache::ThrowIfDisposed (void)
270     throw (::com::sun::star::lang::DisposedException)
271 {
272 	if (rBHelper.bDisposed || rBHelper.bInDispose)
273 	{
274         throw lang::DisposedException (
275             ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
276                 "PresenterPreviewCache object has already been disposed")),
277             static_cast<uno::XWeak*>(this));
278     }
279 }
280 
281 
282 
283 
284 //===== PresenterPreviewCache::PresenterCacheContext ==========================
285 
286 
287 PresenterPreviewCache::PresenterCacheContext::PresenterCacheContext (void)
288     : mxSlides(),
289       mxDocument(),
290       mnFirstVisibleSlideIndex(-1),
291       mnLastVisibleSlideIndex(-1),
292       maListeners()
293 {
294 }
295 
296 
297 
298 
299 PresenterPreviewCache::PresenterCacheContext::~PresenterCacheContext (void)
300 {
301 }
302 
303 
304 
305 
306 void PresenterPreviewCache::PresenterCacheContext::SetDocumentSlides (
307     const Reference<container::XIndexAccess>& rxSlides,
308     const Reference<XInterface>& rxDocument)
309 {
310     mxSlides = rxSlides;
311     mxDocument = rxDocument;
312     mnFirstVisibleSlideIndex = -1;
313     mnLastVisibleSlideIndex = -1;
314 }
315 
316 
317 
318 
319 void PresenterPreviewCache::PresenterCacheContext::SetVisibleSlideRange (
320     const sal_Int32 nFirstVisibleSlideIndex,
321     const sal_Int32 nLastVisibleSlideIndex)
322 {
323     if (nFirstVisibleSlideIndex > nLastVisibleSlideIndex || nFirstVisibleSlideIndex<0)
324     {
325         mnFirstVisibleSlideIndex = -1;
326         mnLastVisibleSlideIndex = -1;
327     }
328     else
329     {
330         mnFirstVisibleSlideIndex = nFirstVisibleSlideIndex;
331         mnLastVisibleSlideIndex = nLastVisibleSlideIndex;
332     }
333     if (mxSlides.is() && mnLastVisibleSlideIndex >= mxSlides->getCount())
334         mnLastVisibleSlideIndex = mxSlides->getCount() - 1;
335 }
336 
337 
338 
339 
340 void PresenterPreviewCache::PresenterCacheContext::AddPreviewCreationNotifyListener (
341     const Reference<drawing::XSlidePreviewCacheListener>& rxListener)
342 {
343     maListeners.push_back(rxListener);
344 }
345 
346 
347 
348 
349 void PresenterPreviewCache::PresenterCacheContext::RemovePreviewCreationNotifyListener (
350     const Reference<drawing::XSlidePreviewCacheListener>& rxListener)
351 {
352     ListenerContainer::iterator iListener;
353     for (iListener=maListeners.begin(); iListener!=maListeners.end(); ++iListener)
354         if (*iListener == rxListener)
355         {
356             maListeners.erase(iListener);
357             return;
358         }
359 }
360 
361 
362 
363 
364 //----- CacheContext ----------------------------------------------------------
365 
366 void PresenterPreviewCache::PresenterCacheContext::NotifyPreviewCreation (
367     CacheKey aKey,
368     const Bitmap& rPreview)
369 {
370     (void)rPreview;
371 
372     if ( ! mxSlides.is())
373         return;
374     const sal_Int32 nCount(mxSlides->getCount());
375     for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex)
376         if (aKey == GetPage(nIndex))
377             CallListeners(nIndex);
378 }
379 
380 
381 
382 
383 bool PresenterPreviewCache::PresenterCacheContext::IsIdle (void)
384 {
385     return true;
386     /*
387     sal_Int32 nIdleState (tools::IdleDetection::GetIdleState(NULL));
388     if (nIdleState == tools::IdleDetection::IDET_IDLE)
389         return true;
390     else
391         return false;
392     */
393 }
394 
395 
396 
397 
398 bool PresenterPreviewCache::PresenterCacheContext::IsVisible (CacheKey aKey)
399 {
400     if (mnFirstVisibleSlideIndex < 0)
401         return false;
402     for (sal_Int32 nIndex=mnFirstVisibleSlideIndex; nIndex<=mnLastVisibleSlideIndex; ++nIndex)
403     {
404         const SdrPage* pPage = GetPage(nIndex);
405         if (pPage == static_cast<const SdrPage*>(aKey))
406             return true;
407     }
408     return false;
409 }
410 
411 
412 
413 
414 const SdrPage* PresenterPreviewCache::PresenterCacheContext::GetPage (CacheKey aKey)
415 {
416     return static_cast<const SdrPage*>(aKey);
417 }
418 
419 
420 
421 
422 ::boost::shared_ptr<std::vector<CacheKey> >
423     PresenterPreviewCache::PresenterCacheContext::GetEntryList (bool bVisible)
424 {
425     ::boost::shared_ptr<std::vector<CacheKey> > pKeys (new std::vector<CacheKey>());
426 
427     if ( ! mxSlides.is())
428         return pKeys;
429 
430     const sal_Int32 nFirstIndex (bVisible ? mnFirstVisibleSlideIndex : 0);
431     const sal_Int32 nLastIndex (bVisible ? mnLastVisibleSlideIndex : mxSlides->getCount()-1);
432 
433     if (nFirstIndex < 0)
434         return pKeys;
435 
436     for (sal_Int32 nIndex=nFirstIndex; nIndex<=nLastIndex; ++nIndex)
437     {
438         pKeys->push_back(GetPage(nIndex));
439     }
440 
441     return pKeys;
442 }
443 
444 
445 
446 
447 sal_Int32 PresenterPreviewCache::PresenterCacheContext::GetPriority (CacheKey aKey)
448 {
449     if ( ! mxSlides.is())
450         return 0;
451 
452     const sal_Int32 nCount (mxSlides->getCount());
453 
454     for (sal_Int32 nIndex=mnFirstVisibleSlideIndex; nIndex<=mnLastVisibleSlideIndex; ++nIndex)
455         if (aKey == GetPage(nIndex))
456             return -nCount-1+nIndex;
457 
458     for (sal_Int32 nIndex=0; nIndex<=nCount; ++nIndex)
459         if (aKey == GetPage(nIndex))
460             return nIndex;
461 
462     return 0;
463 }
464 
465 
466 
467 
468 Reference<XInterface> PresenterPreviewCache::PresenterCacheContext::GetModel (void)
469 {
470     return mxDocument;
471 }
472 
473 
474 
475 
476 //-----------------------------------------------------------------------------
477 
478 const SdrPage* PresenterPreviewCache::PresenterCacheContext::GetPage (
479     const sal_Int32 nSlideIndex) const
480 {
481     if ( ! mxSlides.is())
482         return NULL;
483     if (nSlideIndex < 0 || nSlideIndex >= mxSlides->getCount())
484         return NULL;
485 
486     Reference<drawing::XDrawPage> xSlide (mxSlides->getByIndex(nSlideIndex), UNO_QUERY);
487     const SdPage* pPage = SdPage::getImplementation(xSlide);
488     return dynamic_cast<const SdrPage*>(pPage);
489 }
490 
491 
492 
493 
494 void PresenterPreviewCache::PresenterCacheContext::CallListeners (
495     const sal_Int32 nIndex)
496 {
497     ListenerContainer aListeners (maListeners);
498     ListenerContainer::const_iterator iListener;
499     for (iListener=aListeners.begin(); iListener!=aListeners.end(); ++iListener)
500     {
501         try
502         {
503             (*iListener)->notifyPreviewCreation(nIndex);
504         }
505         catch (lang::DisposedException&)
506         {
507             RemovePreviewCreationNotifyListener(*iListener);
508         }
509     }
510 }
511 
512 } } // end of namespace ::sd::presenter
513