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::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(std::make_shared<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());
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 auto pDescriptor = std::make_shared<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);
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 =
325 std::make_shared<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 = std::shared_ptr<GraphicViewShell>(
335 new GraphicViewShell(*mpBase, &rWindow, pFrameView),
336 o3tl::default_delete<GraphicViewShell>());
337 pViewShell->GetContentWindow()->set_id("draw_win");
338 }
339 else if (rsViewURL == FrameworkHelper::msOutlineViewURL)
340 {
341 pViewShell =
342 std::make_shared<OutlineViewShell>(
343 &rFrame,
344 *mpBase,
345 &rWindow,
346 pFrameView);
347 pViewShell->GetContentWindow()->set_id("outline_win");
348 }
349 else if (rsViewURL == FrameworkHelper::msNotesViewURL)
350 {
351 pViewShell =
352 std::make_shared<DrawViewShell>(
353 *mpBase,
354 &rWindow,
355 PageKind::Notes,
356 pFrameView);
357 pViewShell->GetContentWindow()->set_id("notes_win");
358 }
359 else if (rsViewURL == FrameworkHelper::msHandoutViewURL)
360 {
361 pViewShell =
362 std::make_shared<DrawViewShell>(
363 *mpBase,
364 &rWindow,
365 PageKind::Handout,
366 pFrameView);
367 pViewShell->GetContentWindow()->set_id("handout_win");
368 }
369 else if (rsViewURL == FrameworkHelper::msPresentationViewURL)
370 {
371 pViewShell =
372 std::make_shared<PresentationViewShell>(
373 *mpBase,
374 &rWindow,
375 pFrameView);
376 pViewShell->GetContentWindow()->set_id("presentation_win");
377 }
378 else if (rsViewURL == FrameworkHelper::msSlideSorterURL)
379 {
380 pViewShell = ::sd::slidesorter::SlideSorterViewShell::Create (
381 &rFrame,
382 *mpBase,
383 &rWindow,
384 pFrameView);
385 pViewShell->GetContentWindow()->set_id("slidesorter");
386 }
387
388 return pViewShell;
389 }
390
ReleaseView(const std::shared_ptr<ViewDescriptor> & rpDescriptor,bool bDoNotCache)391 void BasicViewFactory::ReleaseView (
392 const std::shared_ptr<ViewDescriptor>& rpDescriptor,
393 bool bDoNotCache)
394 {
395 bool bIsCacheable (!bDoNotCache && IsCacheable(rpDescriptor));
396
397 if (bIsCacheable)
398 {
399 Reference<XRelocatableResource> xResource (rpDescriptor->mxView, UNO_QUERY);
400 if (xResource.is())
401 {
402 if (mxLocalPane.is())
403 if (xResource->relocateToAnchor(mxLocalPane))
404 mpViewCache->push_back(rpDescriptor);
405 else
406 bIsCacheable = false;
407 else
408 bIsCacheable = false;
409 }
410 else
411 {
412 bIsCacheable = false;
413 }
414 }
415
416 if ( ! bIsCacheable)
417 {
418 // Shut down the current view shell.
419 rpDescriptor->mpViewShell->Shutdown ();
420 mpBase->GetDocShell()->Disconnect(rpDescriptor->mpViewShell.get());
421 mpBase->GetViewShellManager()->DeactivateViewShell(rpDescriptor->mpViewShell.get());
422
423 Reference<XComponent> xComponent (rpDescriptor->mxView, UNO_QUERY);
424 if (xComponent.is())
425 xComponent->dispose();
426 }
427 }
428
IsCacheable(const std::shared_ptr<ViewDescriptor> & rpDescriptor)429 bool BasicViewFactory::IsCacheable (const std::shared_ptr<ViewDescriptor>& rpDescriptor)
430 {
431 bool bIsCacheable (false);
432
433 Reference<XRelocatableResource> xResource (rpDescriptor->mxView, UNO_QUERY);
434 if (xResource.is())
435 {
436 static ::std::vector<Reference<XResourceId> > s_aCacheableResources = [&]()
437 {
438 ::std::vector<Reference<XResourceId> > tmp;
439 FrameworkHelper::Instance(*mpBase);
440
441 // The slide sorter and the task panel are cacheable and relocatable.
442 tmp.push_back(FrameworkHelper::CreateResourceId(
443 FrameworkHelper::msSlideSorterURL, FrameworkHelper::msLeftDrawPaneURL));
444 tmp.push_back(FrameworkHelper::CreateResourceId(
445 FrameworkHelper::msSlideSorterURL, FrameworkHelper::msLeftImpressPaneURL));
446 return tmp;
447 }();
448
449 bIsCacheable = std::any_of(s_aCacheableResources.begin(), s_aCacheableResources.end(),
450 [&rpDescriptor](const Reference<XResourceId>& rxId) { return rxId->compareTo(rpDescriptor->mxViewId) == 0; });
451 }
452
453 return bIsCacheable;
454 }
455
GetViewFromCache(const Reference<XResourceId> & rxViewId,const Reference<XPane> & rxPane)456 std::shared_ptr<BasicViewFactory::ViewDescriptor> BasicViewFactory::GetViewFromCache (
457 const Reference<XResourceId>& rxViewId,
458 const Reference<XPane>& rxPane)
459 {
460 std::shared_ptr<ViewDescriptor> pDescriptor;
461
462 // Search for the requested view in the cache.
463 ViewCache::iterator iEntry = std::find_if(mpViewCache->begin(), mpViewCache->end(),
464 [&rxViewId](const ViewCache::value_type& rxEntry) { return rxEntry->mxViewId->compareTo(rxViewId) == 0; });
465 if (iEntry != mpViewCache->end())
466 {
467 pDescriptor = *iEntry;
468 mpViewCache->erase(iEntry);
469 }
470
471 // When the view has been found then relocate it to the given pane and
472 // remove it from the cache.
473 if (pDescriptor != nullptr)
474 {
475 bool bRelocationSuccessfull (false);
476 Reference<XRelocatableResource> xResource (pDescriptor->mxView, UNO_QUERY);
477 if (xResource.is() && rxPane.is())
478 {
479 if (xResource->relocateToAnchor(rxPane))
480 bRelocationSuccessfull = true;
481 }
482
483 if ( ! bRelocationSuccessfull)
484 {
485 ReleaseView(pDescriptor, true);
486 pDescriptor.reset();
487 }
488 }
489
490 return pDescriptor;
491 }
492
ActivateCenterView(const std::shared_ptr<ViewDescriptor> & rpDescriptor)493 void BasicViewFactory::ActivateCenterView (
494 const std::shared_ptr<ViewDescriptor>& rpDescriptor)
495 {
496 mpBase->GetDocShell()->Connect(rpDescriptor->mpViewShell.get());
497
498 // During the creation of the new sub-shell, resize requests were not
499 // forwarded to it because it was not yet registered. Therefore, we
500 // have to request a resize now.
501 rpDescriptor->mpViewShell->UIFeatureChanged();
502 if (mpBase->GetDocShell()->IsInPlaceActive())
503 mpBase->GetViewFrame()->Resize(true);
504
505 mpBase->GetDrawController().SetSubController(
506 rpDescriptor->mpViewShell->CreateSubController());
507 }
508
509 } // end of namespace sd::framework
510
511
512 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 &)513 com_sun_star_comp_Draw_framework_BasicViewFactory_get_implementation(css::uno::XComponentContext*,
514 css::uno::Sequence<css::uno::Any> const &)
515 {
516 return cppu::acquire(new sd::framework::BasicViewFactory);
517 }
518
519
520 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
521