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