1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <framework/factories/BasicViewFactory.hxx>
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>
39 #include <comphelper/servicehelper.hxx>
40 #include <sfx2/viewfrm.hxx>
41 #include <vcl/wrkwin.hxx>
42 #include <toolkit/helper/vclunohelper.hxx>
45 using namespace ::com::sun::star
;
46 using namespace ::com::sun::star::uno
;
47 using namespace ::com::sun::star::lang
;
48 using namespace ::com::sun::star::drawing::framework
;
50 using ::sd::framework::FrameworkHelper
;
52 namespace sd::framework
{
54 //===== ViewDescriptor ========================================================
56 class BasicViewFactory::ViewDescriptor
59 Reference
<XResource
> mxView
;
60 std::shared_ptr
<sd::ViewShell
> mpViewShell
;
61 Reference
<XResourceId
> mxViewId
;
62 static bool CompareView (const std::shared_ptr
<ViewDescriptor
>& rpDescriptor
,
63 const Reference
<XResource
>& rxView
)
64 { return rpDescriptor
->mxView
.get() == rxView
.get(); }
67 //===== BasicViewFactory::ViewShellContainer ==================================
69 class BasicViewFactory::ViewShellContainer
70 : public ::std::vector
<std::shared_ptr
<ViewDescriptor
> >
73 ViewShellContainer() {};
76 class BasicViewFactory::ViewCache
77 : public ::std::vector
<std::shared_ptr
<ViewDescriptor
> >
83 //===== ViewFactory ===========================================================
85 BasicViewFactory::BasicViewFactory (const rtl::Reference
<::sd::DrawController
>& rxController
)
86 : mpViewShellContainer(new ViewShellContainer()),
89 mpWindow(VclPtr
<WorkWindow
>::Create(nullptr,WB_STDWORK
)),
90 mpViewCache(std::make_shared
<ViewCache
>()),
91 mxLocalPane(new Pane(Reference
<XResourceId
>(), mpWindow
.get()))
95 // Tunnel through the controller to obtain a ViewShellBase.
96 mpBase
= rxController
->GetViewShellBase();
98 // Register the factory for its supported views.
99 mxConfigurationController
= rxController
->getConfigurationController();
100 if ( ! mxConfigurationController
.is())
101 throw RuntimeException();
102 mxConfigurationController
->addResourceFactory(FrameworkHelper::msImpressViewURL
, this);
103 mxConfigurationController
->addResourceFactory(FrameworkHelper::msDrawViewURL
, this);
104 mxConfigurationController
->addResourceFactory(FrameworkHelper::msOutlineViewURL
, this);
105 mxConfigurationController
->addResourceFactory(FrameworkHelper::msNotesViewURL
, this);
106 mxConfigurationController
->addResourceFactory(FrameworkHelper::msHandoutViewURL
, this);
107 mxConfigurationController
->addResourceFactory(FrameworkHelper::msPresentationViewURL
, this);
108 mxConfigurationController
->addResourceFactory(FrameworkHelper::msSlideSorterURL
, this);
110 catch (RuntimeException
&)
113 if (mxConfigurationController
.is())
114 mxConfigurationController
->removeResourceFactoryForReference(this);
119 BasicViewFactory::~BasicViewFactory()
123 void BasicViewFactory::disposing(std::unique_lock
<std::mutex
>&)
125 // Disconnect from the frame view.
126 if (mpFrameView
!= nullptr)
128 mpFrameView
->Disconnect();
129 mpFrameView
= nullptr;
132 // Release the view cache.
133 for (const auto& rxView
: *mpViewCache
)
135 ReleaseView(rxView
, true);
138 // Release the view shell container. At this point no one other than us
139 // should hold references to the view shells (at the moment this is a
140 // trivial requirement, because no one other than us holds a shared
142 // ViewShellContainer::const_iterator iView;
143 for (const auto& rxView
: *mpViewShellContainer
)
145 OSL_ASSERT(rxView
->mpViewShell
.use_count() == 1);
147 mpViewShellContainer
.reset();
150 Reference
<XResource
> SAL_CALL
BasicViewFactory::createResource (
151 const Reference
<XResourceId
>& rxViewId
)
153 Reference
<XResource
> xView
;
154 const bool bIsCenterPane (
155 rxViewId
->isBoundToURL(FrameworkHelper::msCenterPaneURL
, AnchorBindingMode_DIRECT
));
157 // Get the pane for the anchor URL.
158 Reference
<XPane
> xPane
;
159 if (mxConfigurationController
.is())
160 xPane
.set(mxConfigurationController
->getResource(rxViewId
->getAnchor()), UNO_QUERY
);
162 // For main views use the frame view of the last main view.
163 ::sd::FrameView
* pFrameView
= nullptr;
164 if (xPane
.is() && bIsCenterPane
)
166 pFrameView
= mpFrameView
;
169 // Get Window pointer for XWindow of the pane.
170 vcl::Window
* pWindow
= nullptr;
172 pWindow
= VCLUnoHelper::GetWindow(xPane
->getWindow());
174 // Get the view frame.
175 SfxViewFrame
* pFrame
= nullptr;
176 if (mpBase
!= nullptr)
177 pFrame
= &mpBase
->GetViewFrame();
179 if (pFrame
!= nullptr && mpBase
!=nullptr && pWindow
!=nullptr)
181 // Try to get the view from the cache.
182 std::shared_ptr
<ViewDescriptor
> pDescriptor (GetViewFromCache(rxViewId
, xPane
));
184 // When the requested view is not in the cache then create a new view.
185 if (pDescriptor
== nullptr)
187 pDescriptor
= CreateView(rxViewId
, *pFrame
, *pWindow
, xPane
, pFrameView
, bIsCenterPane
);
190 xView
= pDescriptor
->mxView
;
192 mpViewShellContainer
->push_back(pDescriptor
);
195 ActivateCenterView(pDescriptor
);
203 void SAL_CALL
BasicViewFactory::releaseResource (const Reference
<XResource
>& rxView
)
206 throw lang::IllegalArgumentException();
208 if (!rxView
.is() || !mpBase
)
211 ViewShellContainer::iterator
iViewShell (
213 mpViewShellContainer
->begin(),
214 mpViewShellContainer
->end(),
215 [&] (std::shared_ptr
<ViewDescriptor
> const& pVD
) {
216 return ViewDescriptor::CompareView(pVD
, rxView
);
218 if (iViewShell
== mpViewShellContainer
->end())
220 throw lang::IllegalArgumentException();
223 std::shared_ptr
<ViewShell
> pViewShell ((*iViewShell
)->mpViewShell
);
225 if ((*iViewShell
)->mxViewId
->isBoundToURL(
226 FrameworkHelper::msCenterPaneURL
, AnchorBindingMode_DIRECT
))
228 // Obtain a pointer to and connect to the frame view of the
229 // view. The next view, that is created, will be
230 // initialized with this frame view.
231 if (mpFrameView
== nullptr)
233 mpFrameView
= pViewShell
->GetFrameView();
235 mpFrameView
->Connect();
238 // With the view in the center pane the sub controller is
240 mpBase
->GetDrawController()->SetSubController(
241 Reference
<drawing::XDrawSubController
>());
243 SfxViewShell
* pSfxViewShell
= pViewShell
->GetViewShell();
244 if (pSfxViewShell
!= nullptr)
245 pSfxViewShell
->DisconnectAllClients();
248 ReleaseView(*iViewShell
, false);
250 mpViewShellContainer
->erase(iViewShell
);
253 std::shared_ptr
<BasicViewFactory::ViewDescriptor
> BasicViewFactory::CreateView (
254 const Reference
<XResourceId
>& rxViewId
,
255 SfxViewFrame
& rFrame
,
256 vcl::Window
& rWindow
,
257 const Reference
<XPane
>& rxPane
,
258 FrameView
* pFrameView
,
259 const bool bIsCenterPane
)
261 auto pDescriptor
= std::make_shared
<ViewDescriptor
>();
263 pDescriptor
->mpViewShell
= CreateViewShell(
268 pDescriptor
->mxViewId
= rxViewId
;
270 if (pDescriptor
->mpViewShell
!= nullptr)
272 pDescriptor
->mpViewShell
->Init(bIsCenterPane
);
273 mpBase
->GetViewShellManager()->ActivateViewShell(pDescriptor
->mpViewShell
.get());
275 Reference
<awt::XWindow
> xWindow(rxPane
->getWindow());
276 rtl::Reference
<ViewShellWrapper
> wrapper(new ViewShellWrapper(
277 pDescriptor
->mpViewShell
,
281 // register ViewShellWrapper on pane window
284 xWindow
->addWindowListener(wrapper
);
285 if (pDescriptor
->mpViewShell
!= nullptr)
287 pDescriptor
->mpViewShell
->Resize();
291 pDescriptor
->mxView
= wrapper
.get();
297 std::shared_ptr
<ViewShell
> BasicViewFactory::CreateViewShell (
298 const Reference
<XResourceId
>& rxViewId
,
299 SfxViewFrame
& rFrame
,
300 vcl::Window
& rWindow
,
301 FrameView
* pFrameView
)
303 std::shared_ptr
<ViewShell
> pViewShell
;
304 const OUString
& rsViewURL (rxViewId
->getResourceURL());
305 if (rsViewURL
== FrameworkHelper::msImpressViewURL
)
308 std::make_shared
<DrawViewShell
>(
313 pViewShell
->GetContentWindow()->set_id("impress_win");
315 else if (rsViewURL
== FrameworkHelper::msDrawViewURL
)
317 pViewShell
= std::shared_ptr
<GraphicViewShell
>(
318 new GraphicViewShell(*mpBase
, &rWindow
, pFrameView
),
319 o3tl::default_delete
<GraphicViewShell
>());
320 pViewShell
->GetContentWindow()->set_id("draw_win");
322 else if (rsViewURL
== FrameworkHelper::msOutlineViewURL
)
325 std::make_shared
<OutlineViewShell
>(
330 pViewShell
->GetContentWindow()->set_id("outline_win");
332 else if (rsViewURL
== FrameworkHelper::msNotesViewURL
)
335 std::make_shared
<DrawViewShell
>(
340 pViewShell
->GetContentWindow()->set_id("notes_win");
342 else if (rsViewURL
== FrameworkHelper::msHandoutViewURL
)
345 std::make_shared
<DrawViewShell
>(
350 pViewShell
->GetContentWindow()->set_id("handout_win");
352 else if (rsViewURL
== FrameworkHelper::msPresentationViewURL
)
355 std::make_shared
<PresentationViewShell
>(
359 pViewShell
->GetContentWindow()->set_id("presentation_win");
361 else if (rsViewURL
== FrameworkHelper::msSlideSorterURL
)
363 pViewShell
= ::sd::slidesorter::SlideSorterViewShell::Create (
368 pViewShell
->GetContentWindow()->set_id("slidesorter");
374 void BasicViewFactory::ReleaseView (
375 const std::shared_ptr
<ViewDescriptor
>& rpDescriptor
,
378 bool bIsCacheable (!bDoNotCache
&& IsCacheable(rpDescriptor
));
382 Reference
<XRelocatableResource
> xResource (rpDescriptor
->mxView
, UNO_QUERY
);
385 if (mxLocalPane
.is())
386 if (xResource
->relocateToAnchor(mxLocalPane
))
387 mpViewCache
->push_back(rpDescriptor
);
389 bIsCacheable
= false;
391 bIsCacheable
= false;
395 bIsCacheable
= false;
401 // Shut down the current view shell.
402 rpDescriptor
->mpViewShell
->Shutdown ();
403 mpBase
->GetDocShell()->Disconnect(rpDescriptor
->mpViewShell
.get());
404 mpBase
->GetViewShellManager()->DeactivateViewShell(rpDescriptor
->mpViewShell
.get());
406 Reference
<XComponent
> xComponent (rpDescriptor
->mxView
, UNO_QUERY
);
408 xComponent
->dispose();
412 bool BasicViewFactory::IsCacheable (const std::shared_ptr
<ViewDescriptor
>& rpDescriptor
)
414 bool bIsCacheable (false);
416 Reference
<XRelocatableResource
> xResource (rpDescriptor
->mxView
, UNO_QUERY
);
419 static ::std::vector
<Reference
<XResourceId
> > s_aCacheableResources
= [&]()
421 ::std::vector
<Reference
<XResourceId
> > tmp
;
422 FrameworkHelper::Instance(*mpBase
);
424 // The slide sorter and the task panel are cacheable and relocatable.
425 tmp
.push_back(FrameworkHelper::CreateResourceId(
426 FrameworkHelper::msSlideSorterURL
, FrameworkHelper::msLeftDrawPaneURL
));
427 tmp
.push_back(FrameworkHelper::CreateResourceId(
428 FrameworkHelper::msSlideSorterURL
, FrameworkHelper::msLeftImpressPaneURL
));
432 bIsCacheable
= std::any_of(s_aCacheableResources
.begin(), s_aCacheableResources
.end(),
433 [&rpDescriptor
](const Reference
<XResourceId
>& rxId
) { return rxId
->compareTo(rpDescriptor
->mxViewId
) == 0; });
439 std::shared_ptr
<BasicViewFactory::ViewDescriptor
> BasicViewFactory::GetViewFromCache (
440 const Reference
<XResourceId
>& rxViewId
,
441 const Reference
<XPane
>& rxPane
)
443 std::shared_ptr
<ViewDescriptor
> pDescriptor
;
445 // Search for the requested view in the cache.
446 ViewCache::iterator iEntry
= std::find_if(mpViewCache
->begin(), mpViewCache
->end(),
447 [&rxViewId
](const ViewCache::value_type
& rxEntry
) { return rxEntry
->mxViewId
->compareTo(rxViewId
) == 0; });
448 if (iEntry
!= mpViewCache
->end())
450 pDescriptor
= *iEntry
;
451 mpViewCache
->erase(iEntry
);
454 // When the view has been found then relocate it to the given pane and
455 // remove it from the cache.
456 if (pDescriptor
!= nullptr)
458 bool bRelocationSuccessful (false);
459 Reference
<XRelocatableResource
> xResource (pDescriptor
->mxView
, UNO_QUERY
);
460 if (xResource
.is() && rxPane
.is())
462 if (xResource
->relocateToAnchor(rxPane
))
463 bRelocationSuccessful
= true;
466 if ( ! bRelocationSuccessful
)
468 ReleaseView(pDescriptor
, true);
476 void BasicViewFactory::ActivateCenterView (
477 const std::shared_ptr
<ViewDescriptor
>& rpDescriptor
)
479 mpBase
->GetDocShell()->Connect(rpDescriptor
->mpViewShell
.get());
481 // During the creation of the new sub-shell, resize requests were not
482 // forwarded to it because it was not yet registered. Therefore, we
483 // have to request a resize now.
484 rpDescriptor
->mpViewShell
->UIFeatureChanged();
485 if (mpBase
->GetDocShell()->IsInPlaceActive())
486 mpBase
->GetViewFrame().Resize(true);
488 mpBase
->GetDrawController()->SetSubController(
489 rpDescriptor
->mpViewShell
->CreateSubController());
492 } // end of namespace sd::framework
495 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */