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 <NotesPanelViewShell.hxx>
35 #include <PresentationViewShell.hxx>
36 #include <SlideSorterViewShell.hxx>
37 #include <FrameView.hxx>
40 #include <comphelper/servicehelper.hxx>
41 #include <sfx2/viewfrm.hxx>
42 #include <vcl/wrkwin.hxx>
43 #include <toolkit/helper/vclunohelper.hxx>
46 using namespace ::com::sun::star
;
47 using namespace ::com::sun::star::uno
;
48 using namespace ::com::sun::star::lang
;
49 using namespace ::com::sun::star::drawing::framework
;
51 using ::sd::framework::FrameworkHelper
;
53 namespace sd::framework
{
55 //===== ViewDescriptor ========================================================
57 class BasicViewFactory::ViewDescriptor
60 rtl::Reference
<ViewShellWrapper
> mxView
;
61 std::shared_ptr
<sd::ViewShell
> mpViewShell
;
62 Reference
<XResourceId
> mxViewId
;
63 static bool CompareView (const std::shared_ptr
<ViewDescriptor
>& rpDescriptor
,
64 const Reference
<XResource
>& rxView
)
65 { return rpDescriptor
->mxView
.get() == rxView
.get(); }
68 //===== BasicViewFactory::ViewShellContainer ==================================
70 class BasicViewFactory::ViewShellContainer
71 : public ::std::vector
<std::shared_ptr
<ViewDescriptor
> >
74 ViewShellContainer() {};
77 class BasicViewFactory::ViewCache
78 : public ::std::vector
<std::shared_ptr
<ViewDescriptor
> >
84 //===== ViewFactory ===========================================================
86 BasicViewFactory::BasicViewFactory (const rtl::Reference
<::sd::DrawController
>& rxController
)
87 : mpViewShellContainer(new ViewShellContainer()),
90 mpWindow(VclPtr
<WorkWindow
>::Create(nullptr,WB_STDWORK
)),
91 mpViewCache(std::make_shared
<ViewCache
>()),
92 mxLocalPane(new Pane(Reference
<XResourceId
>(), mpWindow
.get()))
96 // Tunnel through the controller to obtain a ViewShellBase.
97 mpBase
= rxController
->GetViewShellBase();
99 // Register the factory for its supported views.
100 mxConfigurationController
= rxController
->getConfigurationController();
101 if ( ! mxConfigurationController
.is())
102 throw RuntimeException();
103 mxConfigurationController
->addResourceFactory(FrameworkHelper::msImpressViewURL
, this);
104 mxConfigurationController
->addResourceFactory(FrameworkHelper::msDrawViewURL
, this);
105 mxConfigurationController
->addResourceFactory(FrameworkHelper::msOutlineViewURL
, this);
106 mxConfigurationController
->addResourceFactory(FrameworkHelper::msNotesViewURL
, this);
107 mxConfigurationController
->addResourceFactory(FrameworkHelper::msHandoutViewURL
, this);
108 mxConfigurationController
->addResourceFactory(FrameworkHelper::msPresentationViewURL
, this);
109 mxConfigurationController
->addResourceFactory(FrameworkHelper::msSlideSorterURL
, this);
110 mxConfigurationController
->addResourceFactory(FrameworkHelper::msNotesPanelViewURL
, this);
112 catch (RuntimeException
&)
115 if (mxConfigurationController
.is())
116 mxConfigurationController
->removeResourceFactoryForReference(this);
121 BasicViewFactory::~BasicViewFactory()
125 void BasicViewFactory::disposing(std::unique_lock
<std::mutex
>&)
127 // Disconnect from the frame view.
128 if (mpFrameView
!= nullptr)
130 mpFrameView
->Disconnect();
131 mpFrameView
= nullptr;
134 // Release the view cache.
135 for (const auto& rxView
: *mpViewCache
)
137 ReleaseView(rxView
, true);
140 // Release the view shell container. At this point no one other than us
141 // should hold references to the view shells (at the moment this is a
142 // trivial requirement, because no one other than us holds a shared
144 // ViewShellContainer::const_iterator iView;
145 for (const auto& rxView
: *mpViewShellContainer
)
147 OSL_ASSERT(rxView
->mpViewShell
.use_count() == 1);
149 mpViewShellContainer
.reset();
152 Reference
<XResource
> SAL_CALL
BasicViewFactory::createResource (
153 const Reference
<XResourceId
>& rxViewId
)
155 Reference
<XResource
> xView
;
156 const bool bIsCenterPane (
157 rxViewId
->isBoundToURL(FrameworkHelper::msCenterPaneURL
, AnchorBindingMode_DIRECT
));
159 // Get the pane for the anchor URL.
160 Reference
<XPane
> xPane
;
161 if (mxConfigurationController
.is())
162 xPane
.set(mxConfigurationController
->getResource(rxViewId
->getAnchor()), UNO_QUERY
);
164 // For main views use the frame view of the last main view.
165 ::sd::FrameView
* pFrameView
= nullptr;
166 if (xPane
.is() && bIsCenterPane
)
168 pFrameView
= mpFrameView
;
171 // Get Window pointer for XWindow of the pane.
172 vcl::Window
* pWindow
= nullptr;
174 pWindow
= VCLUnoHelper::GetWindow(xPane
->getWindow());
176 // Get the view frame.
177 SfxViewFrame
* pFrame
= nullptr;
178 if (mpBase
!= nullptr)
179 pFrame
= &mpBase
->GetViewFrame();
181 if (pFrame
!= nullptr && mpBase
!=nullptr && pWindow
!=nullptr)
183 // Try to get the view from the cache.
184 std::shared_ptr
<ViewDescriptor
> pDescriptor (GetViewFromCache(rxViewId
, xPane
));
186 // When the requested view is not in the cache then create a new view.
187 if (pDescriptor
== nullptr)
189 pDescriptor
= CreateView(rxViewId
, *pFrame
, *pWindow
, xPane
, pFrameView
, bIsCenterPane
);
192 xView
= pDescriptor
->mxView
;
194 mpViewShellContainer
->push_back(pDescriptor
);
197 ActivateCenterView(pDescriptor
);
205 void SAL_CALL
BasicViewFactory::releaseResource (const Reference
<XResource
>& rxView
)
208 throw lang::IllegalArgumentException();
210 if (!rxView
.is() || !mpBase
)
213 ViewShellContainer::iterator
iViewShell (
215 mpViewShellContainer
->begin(),
216 mpViewShellContainer
->end(),
217 [&] (std::shared_ptr
<ViewDescriptor
> const& pVD
) {
218 return ViewDescriptor::CompareView(pVD
, rxView
);
220 if (iViewShell
== mpViewShellContainer
->end())
222 throw lang::IllegalArgumentException();
225 std::shared_ptr
<ViewShell
> pViewShell ((*iViewShell
)->mpViewShell
);
227 if ((*iViewShell
)->mxViewId
->isBoundToURL(
228 FrameworkHelper::msCenterPaneURL
, AnchorBindingMode_DIRECT
))
230 // Obtain a pointer to and connect to the frame view of the
231 // view. The next view, that is created, will be
232 // initialized with this frame view.
233 if (mpFrameView
== nullptr)
235 mpFrameView
= pViewShell
->GetFrameView();
237 mpFrameView
->Connect();
240 // With the view in the center pane the sub controller is
242 mpBase
->GetDrawController()->SetSubController(
243 Reference
<drawing::XDrawSubController
>());
245 SfxViewShell
* pSfxViewShell
= pViewShell
->GetViewShell();
246 if (pSfxViewShell
!= nullptr)
247 pSfxViewShell
->DisconnectAllClients();
250 ReleaseView(*iViewShell
, false);
252 mpViewShellContainer
->erase(iViewShell
);
255 std::shared_ptr
<BasicViewFactory::ViewDescriptor
> BasicViewFactory::CreateView (
256 const Reference
<XResourceId
>& rxViewId
,
257 SfxViewFrame
& rFrame
,
258 vcl::Window
& rWindow
,
259 const Reference
<XPane
>& rxPane
,
260 FrameView
* pFrameView
,
261 const bool bIsCenterPane
)
263 auto pDescriptor
= std::make_shared
<ViewDescriptor
>();
265 pDescriptor
->mpViewShell
= CreateViewShell(
270 pDescriptor
->mxViewId
= rxViewId
;
272 if (pDescriptor
->mpViewShell
!= nullptr)
274 pDescriptor
->mpViewShell
->Init(bIsCenterPane
);
275 mpBase
->GetViewShellManager()->ActivateViewShell(pDescriptor
->mpViewShell
.get());
277 Reference
<awt::XWindow
> xWindow(rxPane
->getWindow());
278 rtl::Reference
<ViewShellWrapper
> wrapper(new ViewShellWrapper(
279 pDescriptor
->mpViewShell
,
283 // register ViewShellWrapper on pane window
286 xWindow
->addWindowListener(wrapper
);
287 if (pDescriptor
->mpViewShell
!= nullptr)
289 pDescriptor
->mpViewShell
->Resize();
293 pDescriptor
->mxView
= wrapper
.get();
299 std::shared_ptr
<ViewShell
> BasicViewFactory::CreateViewShell (
300 const Reference
<XResourceId
>& rxViewId
,
301 SfxViewFrame
& rFrame
,
302 vcl::Window
& rWindow
,
303 FrameView
* pFrameView
)
305 std::shared_ptr
<ViewShell
> pViewShell
;
306 const OUString
sViewURL (rxViewId
->getResourceURL());
307 if (sViewURL
== FrameworkHelper::msImpressViewURL
)
310 std::make_shared
<DrawViewShell
>(
315 pViewShell
->GetContentWindow()->set_id(u
"impress_win"_ustr
);
317 else if (sViewURL
== FrameworkHelper::msDrawViewURL
)
319 pViewShell
= std::shared_ptr
<GraphicViewShell
>(
320 new GraphicViewShell(*mpBase
, &rWindow
, pFrameView
),
321 o3tl::default_delete
<GraphicViewShell
>());
322 pViewShell
->GetContentWindow()->set_id(u
"draw_win"_ustr
);
324 else if (sViewURL
== FrameworkHelper::msOutlineViewURL
)
327 std::make_shared
<OutlineViewShell
>(
332 pViewShell
->GetContentWindow()->set_id(u
"outline_win"_ustr
);
334 else if (sViewURL
== FrameworkHelper::msNotesViewURL
)
337 std::make_shared
<DrawViewShell
>(
342 pViewShell
->GetContentWindow()->set_id(u
"notes_win"_ustr
);
344 else if (sViewURL
== FrameworkHelper::msHandoutViewURL
)
347 std::make_shared
<DrawViewShell
>(
352 pViewShell
->GetContentWindow()->set_id(u
"handout_win"_ustr
);
354 else if (sViewURL
== FrameworkHelper::msPresentationViewURL
)
357 std::make_shared
<PresentationViewShell
>(
361 pViewShell
->GetContentWindow()->set_id(u
"presentation_win"_ustr
);
363 else if (sViewURL
== FrameworkHelper::msSlideSorterURL
)
365 pViewShell
= ::sd::slidesorter::SlideSorterViewShell::Create (
370 pViewShell
->GetContentWindow()->set_id(u
"slidesorter"_ustr
);
372 else if (sViewURL
== FrameworkHelper::msNotesPanelViewURL
)
374 pViewShell
= std::make_shared
<NotesPanelViewShell
>(&rFrame
, *mpBase
, &rWindow
, pFrameView
);
375 pViewShell
->GetContentWindow()->set_id(u
"notes_panel_win"_ustr
);
381 void BasicViewFactory::ReleaseView (
382 const std::shared_ptr
<ViewDescriptor
>& rpDescriptor
,
385 bool bIsCacheable (!bDoNotCache
&& IsCacheable(rpDescriptor
));
389 if (rpDescriptor
->mxView
)
391 if (mxLocalPane
.is())
392 if (rpDescriptor
->mxView
->relocateToAnchor(mxLocalPane
))
393 mpViewCache
->push_back(rpDescriptor
);
395 bIsCacheable
= false;
397 bIsCacheable
= false;
401 bIsCacheable
= false;
407 // Shut down the current view shell.
408 rpDescriptor
->mpViewShell
->Shutdown ();
409 mpBase
->GetDocShell()->Disconnect(rpDescriptor
->mpViewShell
.get());
410 mpBase
->GetViewShellManager()->DeactivateViewShell(rpDescriptor
->mpViewShell
.get());
412 if (rpDescriptor
->mxView
)
413 rpDescriptor
->mxView
->dispose();
417 bool BasicViewFactory::IsCacheable (const std::shared_ptr
<ViewDescriptor
>& rpDescriptor
)
419 bool bIsCacheable (false);
421 if (rpDescriptor
->mxView
)
423 static ::std::vector
<Reference
<XResourceId
> > s_aCacheableResources
= [&]()
425 ::std::vector
<Reference
<XResourceId
> > tmp
;
426 FrameworkHelper::Instance(*mpBase
);
428 // The slide sorter and the task panel are cacheable and relocatable.
429 tmp
.push_back(FrameworkHelper::CreateResourceId(
430 FrameworkHelper::msSlideSorterURL
, FrameworkHelper::msLeftDrawPaneURL
));
431 tmp
.push_back(FrameworkHelper::CreateResourceId(
432 FrameworkHelper::msSlideSorterURL
, FrameworkHelper::msLeftImpressPaneURL
));
436 bIsCacheable
= std::any_of(s_aCacheableResources
.begin(), s_aCacheableResources
.end(),
437 [&rpDescriptor
](const Reference
<XResourceId
>& rxId
) { return rxId
->compareTo(rpDescriptor
->mxViewId
) == 0; });
443 std::shared_ptr
<BasicViewFactory::ViewDescriptor
> BasicViewFactory::GetViewFromCache (
444 const Reference
<XResourceId
>& rxViewId
,
445 const Reference
<XPane
>& rxPane
)
447 std::shared_ptr
<ViewDescriptor
> pDescriptor
;
449 // Search for the requested view in the cache.
450 ViewCache::iterator iEntry
= std::find_if(mpViewCache
->begin(), mpViewCache
->end(),
451 [&rxViewId
](const ViewCache::value_type
& rxEntry
) { return rxEntry
->mxViewId
->compareTo(rxViewId
) == 0; });
452 if (iEntry
!= mpViewCache
->end())
454 pDescriptor
= *iEntry
;
455 mpViewCache
->erase(iEntry
);
458 // When the view has been found then relocate it to the given pane and
459 // remove it from the cache.
460 if (pDescriptor
!= nullptr)
462 bool bRelocationSuccessful (false);
463 if (pDescriptor
->mxView
&& rxPane
.is())
465 if (pDescriptor
->mxView
->relocateToAnchor(rxPane
))
466 bRelocationSuccessful
= true;
469 if ( ! bRelocationSuccessful
)
471 ReleaseView(pDescriptor
, true);
479 void BasicViewFactory::ActivateCenterView (
480 const std::shared_ptr
<ViewDescriptor
>& rpDescriptor
)
482 mpBase
->GetDocShell()->Connect(rpDescriptor
->mpViewShell
.get());
484 // During the creation of the new sub-shell, resize requests were not
485 // forwarded to it because it was not yet registered. Therefore, we
486 // have to request a resize now.
487 rpDescriptor
->mpViewShell
->UIFeatureChanged();
488 if (mpBase
->GetDocShell()->IsInPlaceActive())
489 mpBase
->GetViewFrame().Resize(true);
491 mpBase
->GetDrawController()->SetSubController(
492 rpDescriptor
->mpViewShell
->CreateSubController());
495 } // end of namespace sd::framework
498 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */