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 #include "precompiled_sd.hxx"
25 
26 #include "BasicViewFactory.hxx"
27 
28 #include "framework/ViewShellWrapper.hxx"
29 #include "framework/FrameworkHelper.hxx"
30 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
31 #include <com/sun/star/lang/IllegalArgumentException.hpp>
32 #include "framework/Pane.hxx"
33 #include "DrawController.hxx"
34 #include "DrawSubController.hxx"
35 #include "ViewShellBase.hxx"
36 #include "ViewShellManager.hxx"
37 #include "DrawDocShell.hxx"
38 #include "DrawViewShell.hxx"
39 #include "GraphicViewShell.hxx"
40 #include "OutlineViewShell.hxx"
41 #include "PresentationViewShell.hxx"
42 #include "SlideSorterViewShell.hxx"
43 #include "FrameView.hxx"
44 
45 #include <sfx2/viewfrm.hxx>
46 #include <vcl/wrkwin.hxx>
47 #include <toolkit/helper/vclunohelper.hxx>
48 
49 #include <boost/bind.hpp>
50 
51 using namespace ::com::sun::star;
52 using namespace ::com::sun::star::uno;
53 using namespace ::com::sun::star::lang;
54 using namespace ::com::sun::star::drawing::framework;
55 
56 using ::rtl::OUString;
57 using ::sd::framework::FrameworkHelper;
58 
59 
60 namespace sd { namespace framework {
61 
62 
BasicViewFactory_createInstance(const Reference<XComponentContext> & rxContext)63 Reference<XInterface> SAL_CALL BasicViewFactory_createInstance (
64     const Reference<XComponentContext>& rxContext)
65 {
66     return Reference<XInterface>(static_cast<XWeak*>(new BasicViewFactory(rxContext)));
67 }
68 
69 
70 
71 
BasicViewFactory_getImplementationName(void)72 ::rtl::OUString BasicViewFactory_getImplementationName (void) throw(RuntimeException)
73 {
74     return ::rtl::OUString(
75         RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.Draw.framework.BasicViewFactory"));
76 }
77 
78 
79 
80 
BasicViewFactory_getSupportedServiceNames(void)81 Sequence<rtl::OUString> SAL_CALL BasicViewFactory_getSupportedServiceNames (void)
82     throw (RuntimeException)
83 {
84 	static const ::rtl::OUString sServiceName(
85         ::rtl::OUString::createFromAscii("com.sun.star.drawing.framework.BasicViewFactory"));
86 	return Sequence<rtl::OUString>(&sServiceName, 1);
87 }
88 
89 
90 
91 
92 //===== ViewDescriptor ========================================================
93 
94 class BasicViewFactory::ViewDescriptor
95 {
96 public:
97     Reference<XResource> mxView;
98     ::boost::shared_ptr<sd::ViewShell> mpViewShell;
99     ViewShellWrapper* mpWrapper;
100     Reference<XResourceId> mxViewId;
CompareView(const::boost::shared_ptr<ViewDescriptor> & rpDescriptor,const Reference<XResource> & rxView)101     static bool CompareView (const ::boost::shared_ptr<ViewDescriptor>& rpDescriptor,
102         const Reference<XResource>& rxView)
103     { return rpDescriptor->mxView.get() == rxView.get(); }
104 };
105 
106 
107 
108 
109 
110 //===== BasicViewFactory::ViewShellContainer ==================================
111 
112 class BasicViewFactory::ViewShellContainer
113     : public ::std::vector<boost::shared_ptr<ViewDescriptor> >
114 {
115 public:
ViewShellContainer(void)116     ViewShellContainer (void) {};
117 };
118 
119 
120 class BasicViewFactory::ViewCache
121     : public ::std::vector<boost::shared_ptr<ViewDescriptor> >
122 {
123 public:
ViewCache(void)124     ViewCache (void) {};
125 };
126 
127 
128 
129 
130 //===== ViewFactory ===========================================================
131 
BasicViewFactory(const Reference<XComponentContext> & rxContext)132 BasicViewFactory::BasicViewFactory (
133     const Reference<XComponentContext>& rxContext)
134     : BasicViewFactoryInterfaceBase(MutexOwner::maMutex),
135       mxConfigurationController(),
136       mpViewShellContainer(new ViewShellContainer()),
137       mpBase(NULL),
138       mpFrameView(NULL),
139       mpWindow(new WorkWindow(NULL,WB_STDWORK)),
140       mpViewCache(new ViewCache()),
141       mxLocalPane(new Pane(Reference<XResourceId>(), mpWindow.get()))
142 {
143     (void)rxContext;
144 }
145 
146 
147 
148 
~BasicViewFactory(void)149 BasicViewFactory::~BasicViewFactory (void)
150 {
151 }
152 
153 
154 
155 
disposing(void)156 void SAL_CALL BasicViewFactory::disposing (void)
157 {
158     // Disconnect from the frame view.
159     if (mpFrameView != NULL)
160     {
161         mpFrameView->Disconnect();
162         mpFrameView = NULL;
163     }
164 
165     // Relase the view cache.
166     ViewShellContainer::const_iterator iView;
167     for (iView=mpViewCache->begin(); iView!=mpViewCache->end(); ++iView)
168     {
169         ReleaseView(*iView, true);
170     }
171 
172     // Release the view shell container.  At this point no one other than us
173     // should hold references to the view shells (at the moment this is a
174     // trivial requirement, because no one other then us holds a shared
175     // pointer).
176     //    ViewShellContainer::const_iterator iView;
177     for (iView=mpViewShellContainer->begin(); iView!=mpViewShellContainer->end(); ++iView)
178     {
179         OSL_ASSERT((*iView)->mpViewShell.unique());
180     }
181     mpViewShellContainer.reset();
182 }
183 
184 
185 
186 
createResource(const Reference<XResourceId> & rxViewId)187 Reference<XResource> SAL_CALL BasicViewFactory::createResource (
188     const Reference<XResourceId>& rxViewId)
189     throw(RuntimeException, IllegalArgumentException, WrappedTargetException)
190 {
191     Reference<XResource> xView;
192     const bool bIsCenterPane (
193         rxViewId->isBoundToURL(FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT));
194 
195     // Get the pane for the anchor URL.
196     Reference<XPane> xPane;
197     if (mxConfigurationController.is())
198         xPane = Reference<XPane>(mxConfigurationController->getResource(rxViewId->getAnchor()),
199             UNO_QUERY);
200 
201     // For main views use the frame view of the last main view.
202     ::sd::FrameView* pFrameView = NULL;
203     if (xPane.is() && bIsCenterPane)
204     {
205         pFrameView = mpFrameView;
206     }
207 
208     // Get Window pointer for XWindow of the pane.
209     ::Window* pWindow = NULL;
210     if (xPane.is())
211         pWindow = VCLUnoHelper::GetWindow(xPane->getWindow());
212 
213     // Get the view frame.
214     SfxViewFrame* pFrame = NULL;
215     if (mpBase != NULL)
216         pFrame = mpBase->GetViewFrame();
217 
218     if (pFrame != NULL && mpBase!=NULL && pWindow!=NULL)
219     {
220         // Try to get the view from the cache.
221         ::boost::shared_ptr<ViewDescriptor> pDescriptor (GetViewFromCache(rxViewId, xPane));
222 
223         // When the requested view is not in the cache then create a new view.
224         if (pDescriptor.get() == NULL)
225         {
226             pDescriptor = CreateView(rxViewId, *pFrame, *pWindow, xPane, pFrameView, bIsCenterPane);
227         }
228 
229         if (pDescriptor.get() != NULL)
230             xView = pDescriptor->mxView;
231 
232         mpViewShellContainer->push_back(pDescriptor);
233 
234         if (bIsCenterPane)
235             ActivateCenterView(pDescriptor);
236         else
237             pWindow->Resize();
238     }
239 
240     return xView;
241 }
242 
243 
244 
245 
releaseResource(const Reference<XResource> & rxView)246 void SAL_CALL BasicViewFactory::releaseResource (const Reference<XResource>& rxView)
247     throw(RuntimeException)
248 {
249     if ( ! rxView.is())
250         throw lang::IllegalArgumentException();
251 
252     if (rxView.is() && mpBase!=NULL)
253     {
254         ViewShellContainer::iterator iViewShell (
255             ::std::find_if(
256                 mpViewShellContainer->begin(),
257                 mpViewShellContainer->end(),
258                 ::boost::bind(&ViewDescriptor::CompareView, _1, rxView)));
259         if (iViewShell != mpViewShellContainer->end())
260         {
261             ::boost::shared_ptr<ViewShell> pViewShell ((*iViewShell)->mpViewShell);
262 
263             if ((*iViewShell)->mxViewId->isBoundToURL(
264                 FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT))
265             {
266                 // Obtain a pointer to and connect to the frame view of the
267                 // view.  The next view, that is created, will be
268                 // initialized with this frame view.
269                 if (mpFrameView == NULL)
270                 {
271                     mpFrameView = pViewShell->GetFrameView();
272                     if (mpFrameView)
273                         mpFrameView->Connect();
274                 }
275 
276                 // With the view in the center pane the sub controller is
277                 // released, too.
278                 mpBase->GetDrawController().SetSubController(
279                     Reference<drawing::XDrawSubController>());
280 
281                 SfxViewShell* pSfxViewShell = pViewShell->GetViewShell();
282                 if (pSfxViewShell != NULL)
283                     pSfxViewShell->DisconnectAllClients();
284             }
285 
286             ReleaseView(*iViewShell);
287 
288             mpViewShellContainer->erase(iViewShell);
289         }
290         else
291         {
292             throw lang::IllegalArgumentException();
293         }
294     }
295 }
296 
297 
298 
299 
initialize(const Sequence<Any> & aArguments)300 void SAL_CALL BasicViewFactory::initialize (const Sequence<Any>& aArguments)
301     throw (Exception, RuntimeException)
302 {
303     if (aArguments.getLength() > 0)
304     {
305         Reference<XConfigurationController> xCC;
306         try
307         {
308             // Get the XController from the first argument.
309             Reference<frame::XController> xController (aArguments[0], UNO_QUERY_THROW);
310 
311             // Tunnel through the controller to obtain a ViewShellBase.
312             Reference<lang::XUnoTunnel> xTunnel (xController, UNO_QUERY_THROW);
313             ::sd::DrawController* pController = reinterpret_cast<sd::DrawController*>(
314                 xTunnel->getSomething(sd::DrawController::getUnoTunnelId()));
315             if (pController != NULL)
316                 mpBase = pController->GetViewShellBase();
317 
318             // Register the factory for its supported views.
319             Reference<XControllerManager> xCM (xController,UNO_QUERY_THROW);
320             mxConfigurationController = xCM->getConfigurationController();
321             if ( ! mxConfigurationController.is())
322                 throw RuntimeException();
323             mxConfigurationController->addResourceFactory(FrameworkHelper::msImpressViewURL, this);
324             mxConfigurationController->addResourceFactory(FrameworkHelper::msDrawViewURL, this);
325             mxConfigurationController->addResourceFactory(FrameworkHelper::msOutlineViewURL, this);
326             mxConfigurationController->addResourceFactory(FrameworkHelper::msNotesViewURL, this);
327             mxConfigurationController->addResourceFactory(FrameworkHelper::msHandoutViewURL, this);
328             mxConfigurationController->addResourceFactory(FrameworkHelper::msPresentationViewURL, this);
329             mxConfigurationController->addResourceFactory(FrameworkHelper::msSlideSorterURL, this);
330         }
331         catch (RuntimeException&)
332         {
333             mpBase = NULL;
334             if (mxConfigurationController.is())
335                 mxConfigurationController->removeResourceFactoryForReference(this);
336             throw;
337         }
338     }
339 }
340 
341 
342 
343 
CreateView(const Reference<XResourceId> & rxViewId,SfxViewFrame & rFrame,::Window & rWindow,const Reference<XPane> & rxPane,FrameView * pFrameView,const bool bIsCenterPane)344 ::boost::shared_ptr<BasicViewFactory::ViewDescriptor> BasicViewFactory::CreateView (
345     const Reference<XResourceId>& rxViewId,
346     SfxViewFrame& rFrame,
347     ::Window& rWindow,
348     const Reference<XPane>& rxPane,
349     FrameView* pFrameView,
350     const bool bIsCenterPane)
351 {
352     ::boost::shared_ptr<ViewDescriptor> pDescriptor (new ViewDescriptor());
353 
354     pDescriptor->mpViewShell = CreateViewShell(
355         rxViewId,
356         rFrame,
357         rWindow,
358         pFrameView,
359         bIsCenterPane);
360     pDescriptor->mxViewId = rxViewId;
361 
362     if (pDescriptor->mpViewShell.get() != NULL)
363     {
364         pDescriptor->mpViewShell->Init(bIsCenterPane);
365         mpBase->GetViewShellManager()->ActivateViewShell(pDescriptor->mpViewShell.get());
366 
367         pDescriptor->mpWrapper = new ViewShellWrapper(
368             pDescriptor->mpViewShell,
369             rxViewId,
370             rxPane->getWindow());
371         pDescriptor->mxView.set( pDescriptor->mpWrapper->queryInterface( XResource::static_type() ), UNO_QUERY_THROW );
372     }
373 
374     return pDescriptor;
375 }
376 
377 
378 
379 
CreateViewShell(const Reference<XResourceId> & rxViewId,SfxViewFrame & rFrame,::Window & rWindow,FrameView * pFrameView,const bool bIsCenterPane)380 ::boost::shared_ptr<ViewShell> BasicViewFactory::CreateViewShell (
381     const Reference<XResourceId>& rxViewId,
382     SfxViewFrame& rFrame,
383     ::Window& rWindow,
384     FrameView* pFrameView,
385     const bool bIsCenterPane)
386 {
387     ::boost::shared_ptr<ViewShell> pViewShell;
388     const OUString& rsViewURL (rxViewId->getResourceURL());
389     if (rsViewURL.equals(FrameworkHelper::msImpressViewURL))
390     {
391         pViewShell.reset(
392             new DrawViewShell(
393                 &rFrame,
394                 *mpBase,
395                 &rWindow,
396                 PK_STANDARD,
397                 pFrameView));
398     }
399     else if (rsViewURL.equals(FrameworkHelper::msDrawViewURL))
400     {
401         pViewShell.reset(
402             new GraphicViewShell (
403                 &rFrame,
404                 *mpBase,
405                 &rWindow,
406                 pFrameView));
407     }
408     else if (rsViewURL.equals(FrameworkHelper::msOutlineViewURL))
409     {
410         pViewShell.reset(
411             new OutlineViewShell (
412                 &rFrame,
413                 *mpBase,
414                 &rWindow,
415                 pFrameView));
416     }
417     else if (rsViewURL.equals(FrameworkHelper::msNotesViewURL))
418     {
419         pViewShell.reset(
420             new DrawViewShell(
421                 &rFrame,
422                 *mpBase,
423                 &rWindow,
424                 PK_NOTES,
425                 pFrameView));
426     }
427     else if (rsViewURL.equals(FrameworkHelper::msHandoutViewURL))
428     {
429         pViewShell.reset(
430             new DrawViewShell(
431                 &rFrame,
432                 *mpBase,
433                 &rWindow,
434                 PK_HANDOUT,
435                 pFrameView));
436     }
437     else if (rsViewURL.equals(FrameworkHelper::msPresentationViewURL))
438     {
439         pViewShell.reset(
440             new PresentationViewShell(
441                 &rFrame,
442                 *mpBase,
443                 &rWindow,
444                 pFrameView));
445     }
446     else if (rsViewURL.equals(FrameworkHelper::msSlideSorterURL))
447     {
448         pViewShell = ::sd::slidesorter::SlideSorterViewShell::Create (
449             &rFrame,
450             *mpBase,
451             &rWindow,
452             pFrameView,
453             bIsCenterPane);
454     }
455 
456     return pViewShell;
457 }
458 
459 
460 
461 
ReleaseView(const::boost::shared_ptr<ViewDescriptor> & rpDescriptor,bool bDoNotCache)462 void BasicViewFactory::ReleaseView (
463     const ::boost::shared_ptr<ViewDescriptor>& rpDescriptor,
464     bool bDoNotCache)
465 {
466     bool bIsCacheable (!bDoNotCache && IsCacheable(rpDescriptor));
467 
468     if (bIsCacheable)
469     {
470         Reference<XRelocatableResource> xResource (rpDescriptor->mxView, UNO_QUERY);
471         if (xResource.is())
472         {
473             Reference<XResource> xNewAnchor (mxLocalPane, UNO_QUERY);
474             if (xNewAnchor.is())
475                 if (xResource->relocateToAnchor(xNewAnchor))
476                     mpViewCache->push_back(rpDescriptor);
477                 else
478                     bIsCacheable = false;
479             else
480                 bIsCacheable = false;
481         }
482         else
483         {
484             bIsCacheable = false;
485         }
486     }
487 
488     if ( ! bIsCacheable)
489     {
490         // Shut down the current view shell.
491         rpDescriptor->mpViewShell->Shutdown ();
492         mpBase->GetDocShell()->Disconnect(rpDescriptor->mpViewShell.get());
493         mpBase->GetViewShellManager()->DeactivateViewShell(rpDescriptor->mpViewShell.get());
494 
495         Reference<XComponent> xComponent (rpDescriptor->mxView, UNO_QUERY);
496         if (xComponent.is())
497             xComponent->dispose();
498     }
499 }
500 
501 
502 
503 
IsCacheable(const::boost::shared_ptr<ViewDescriptor> & rpDescriptor)504 bool BasicViewFactory::IsCacheable (const ::boost::shared_ptr<ViewDescriptor>& rpDescriptor)
505 {
506     bool bIsCacheable (false);
507 
508     Reference<XRelocatableResource> xResource (rpDescriptor->mxView, UNO_QUERY);
509     if (xResource.is())
510     {
511         static ::std::vector<Reference<XResourceId> > maCacheableResources;
512         if (maCacheableResources.empty() )
513         {
514             ::boost::shared_ptr<FrameworkHelper> pHelper (FrameworkHelper::Instance(*mpBase));
515 
516             // The slide sorter and the task panel are cacheable and relocatable.
517             maCacheableResources.push_back(pHelper->CreateResourceId(
518                 FrameworkHelper::msSlideSorterURL, FrameworkHelper::msLeftDrawPaneURL));
519             maCacheableResources.push_back(pHelper->CreateResourceId(
520                 FrameworkHelper::msSlideSorterURL, FrameworkHelper::msLeftImpressPaneURL));
521         }
522 
523         ::std::vector<Reference<XResourceId> >::const_iterator iId;
524         for (iId=maCacheableResources.begin(); iId!=maCacheableResources.end(); ++iId)
525         {
526             if ((*iId)->compareTo(rpDescriptor->mxViewId) == 0)
527             {
528                 bIsCacheable = true;
529                 break;
530             }
531         }
532     }
533 
534     return bIsCacheable;
535 }
536 
537 
538 
539 
GetViewFromCache(const Reference<XResourceId> & rxViewId,const Reference<XPane> & rxPane)540 ::boost::shared_ptr<BasicViewFactory::ViewDescriptor> BasicViewFactory::GetViewFromCache (
541     const Reference<XResourceId>& rxViewId,
542     const Reference<XPane>& rxPane)
543 {
544     ::boost::shared_ptr<ViewDescriptor> pDescriptor;
545 
546     // Search for the requested view in the cache.
547     ViewCache::iterator iEntry;
548     for (iEntry=mpViewCache->begin(); iEntry!=mpViewCache->end(); ++iEntry)
549     {
550         if ((*iEntry)->mxViewId->compareTo(rxViewId) == 0)
551         {
552             pDescriptor = *iEntry;
553             mpViewCache->erase(iEntry);
554             break;
555         }
556     }
557 
558     // When the view has been found then relocate it to the given pane and
559     // remove it from the cache.
560     if (pDescriptor.get() != NULL)
561     {
562         bool bRelocationSuccessfull (false);
563         Reference<XRelocatableResource> xResource (pDescriptor->mxView, UNO_QUERY);
564         Reference<XResource> xNewAnchor (rxPane, UNO_QUERY);
565         if (xResource.is() && xNewAnchor.is())
566         {
567             if (xResource->relocateToAnchor(xNewAnchor))
568                 bRelocationSuccessfull = true;
569         }
570 
571         if ( ! bRelocationSuccessfull)
572         {
573             ReleaseView(pDescriptor, true);
574             pDescriptor.reset();
575         }
576     }
577 
578     return pDescriptor;
579 }
580 
581 
582 
583 
ActivateCenterView(const::boost::shared_ptr<ViewDescriptor> & rpDescriptor)584 void BasicViewFactory::ActivateCenterView (
585     const ::boost::shared_ptr<ViewDescriptor>& rpDescriptor)
586 {
587     mpBase->GetDocShell()->Connect(rpDescriptor->mpViewShell.get());
588 
589     // During the creation of the new sub-shell, resize requests were not
590     // forwarded to it because it was not yet registered.  Therefore, we
591     // have to request a resize now.
592     rpDescriptor->mpViewShell->UIFeatureChanged();
593     if (mpBase->GetDocShell()->IsInPlaceActive())
594         mpBase->GetViewFrame()->Resize(sal_True);
595 
596     mpBase->GetDrawController().SetSubController(
597         rpDescriptor->mpViewShell->CreateSubController());
598 }
599 
600 } } // end of namespace sd::framework
601