Use correct object
[LibreOffice.git] / sfx2 / source / view / sfxbasecontroller.cxx
blobc4a255e7722f518d73d330d241bb44611a81727f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <time.h>
21 #include <sfx2/sfxbasecontroller.hxx>
22 #include <com/sun/star/awt/XVclWindowPeer.hpp>
23 #include <com/sun/star/beans/XPropertySet.hpp>
24 #include <com/sun/star/util/XCloseable.hpp>
25 #include <com/sun/star/util/XCloseBroadcaster.hpp>
26 #include <com/sun/star/util/XCloseListener.hpp>
27 #include <com/sun/star/util/CloseVetoException.hpp>
28 #include <com/sun/star/document/XCmisDocument.hpp>
29 #include <com/sun/star/document/XViewDataSupplier.hpp>
30 #include <cppuhelper/implbase.hxx>
31 #include <com/sun/star/frame/FrameActionEvent.hpp>
32 #include <com/sun/star/frame/FrameAction.hpp>
33 #include <com/sun/star/frame/FrameSearchFlag.hpp>
34 #include <com/sun/star/frame/CommandGroup.hpp>
35 #include <com/sun/star/frame/XFrame.hpp>
36 #include <com/sun/star/frame/XBorderResizeListener.hpp>
37 #include <com/sun/star/frame/XUntitledNumbers.hpp>
38 #include <com/sun/star/lang/DisposedException.hpp>
39 #include <com/sun/star/lang/EventObject.hpp>
40 #include <com/sun/star/lang/XEventListener.hpp>
41 #include <com/sun/star/lang/XComponent.hpp>
42 #include <com/sun/star/container/XIndexAccess.hpp>
43 #include <comphelper/interfacecontainer3.hxx>
44 #include <comphelper/multicontainer2.hxx>
45 #include <sfx2/viewsh.hxx>
46 #include <sfx2/docfac.hxx>
47 #include <sfx2/viewfrm.hxx>
48 #include <sfx2/objsh.hxx>
49 #include <sfx2/app.hxx>
50 #include <sfx2/msgpool.hxx>
51 #include <sfx2/dispatch.hxx>
52 #include <sfx2/userinputinterception.hxx>
54 #include <unoctitm.hxx>
55 #include <sfx2/childwin.hxx>
56 #include <sfx2/sfxsids.hrc>
57 #include <sfx2/sfxresid.hxx>
58 #include <workwin.hxx>
59 #include <sfx2/infobar.hxx>
61 #include <osl/mutex.hxx>
62 #include <comphelper/diagnose_ex.hxx>
63 #include <comphelper/namedvaluecollection.hxx>
64 #include <comphelper/sequence.hxx>
65 #include <toolkit/helper/vclunohelper.hxx>
66 #include <framework/titlehelper.hxx>
67 #include <comphelper/processfactory.hxx>
68 #include <vcl/svapp.hxx>
69 #include <vcl/unohelp.hxx>
70 #include <tools/svborder.hxx>
72 #include <sfx2/event.hxx>
73 #include <sfx2/viewfac.hxx>
74 #include <sfx2/strings.hrc>
75 #include <sfxbasecontroller_internal.hxx>
77 #include <unordered_map>
79 #include <com/sun/star/ui/XSidebarProvider.hpp>
80 #include <sidebar/UnoSidebar.hxx>
82 #define TIMEOUT_START_RESCHEDULE 10L /* 10th s */
84 using namespace ::com::sun::star;
85 using ::com::sun::star::uno::Reference;
86 using ::com::sun::star::uno::RuntimeException;
87 using ::com::sun::star::uno::UNO_QUERY_THROW;
88 using ::com::sun::star::lang::DisposedException;
89 using ::com::sun::star::awt::XWindow;
90 using ::com::sun::star::frame::XController;
91 using ::com::sun::star::frame::XDispatchProvider;
92 using ::com::sun::star::document::XViewDataSupplier;
93 using ::com::sun::star::container::XIndexAccess;
94 using ::com::sun::star::beans::PropertyValue;
95 using ::com::sun::star::beans::StringPair;
96 using ::com::sun::star::uno::Sequence;
97 using ::com::sun::star::uno::UNO_QUERY;
98 using ::com::sun::star::uno::Exception;
99 using ::com::sun::star::frame::XFrame;
100 using ::com::sun::star::frame::XFrameActionListener;
101 using ::com::sun::star::util::XCloseListener;
102 using ::com::sun::star::task::XStatusIndicator;
103 using ::com::sun::star::frame::XTitle;
104 using ::com::sun::star::ui::XSidebarProvider;
107 typedef std::unordered_map< SfxGroupId, sal_Int16 > GroupHashMap;
109 sal_Int16 MapGroupIDToCommandGroup( SfxGroupId nGroupID )
111 static GroupHashMap s_aHashMap
113 { SfxGroupId::Intern , frame::CommandGroup::INTERNAL },
114 { SfxGroupId::Application , frame::CommandGroup::APPLICATION },
115 { SfxGroupId::Document , frame::CommandGroup::DOCUMENT },
116 { SfxGroupId::View , frame::CommandGroup::VIEW },
117 { SfxGroupId::Edit , frame::CommandGroup::EDIT },
118 { SfxGroupId::Macro , frame::CommandGroup::MACRO },
119 { SfxGroupId::Options , frame::CommandGroup::OPTIONS },
120 { SfxGroupId::Math , frame::CommandGroup::MATH },
121 { SfxGroupId::Navigator , frame::CommandGroup::NAVIGATOR },
122 { SfxGroupId::Insert , frame::CommandGroup::INSERT },
123 { SfxGroupId::Format , frame::CommandGroup::FORMAT },
124 { SfxGroupId::Template , frame::CommandGroup::TEMPLATE },
125 { SfxGroupId::Text , frame::CommandGroup::TEXT },
126 { SfxGroupId::Frame , frame::CommandGroup::FRAME },
127 { SfxGroupId::Graphic , frame::CommandGroup::GRAPHIC },
128 { SfxGroupId::Table , frame::CommandGroup::TABLE },
129 { SfxGroupId::Enumeration , frame::CommandGroup::ENUMERATION },
130 { SfxGroupId::Data , frame::CommandGroup::DATA },
131 { SfxGroupId::Special , frame::CommandGroup::SPECIAL },
132 { SfxGroupId::Image , frame::CommandGroup::IMAGE },
133 { SfxGroupId::Chart , frame::CommandGroup::CHART },
134 { SfxGroupId::Explorer , frame::CommandGroup::EXPLORER },
135 { SfxGroupId::Connector , frame::CommandGroup::CONNECTOR },
136 { SfxGroupId::Modify , frame::CommandGroup::MODIFY },
137 { SfxGroupId::Drawing , frame::CommandGroup::DRAWING },
138 { SfxGroupId::Controls , frame::CommandGroup::CONTROLS },
142 GroupHashMap::const_iterator pIter = s_aHashMap.find( nGroupID );
143 if ( pIter != s_aHashMap.end() )
144 return pIter->second;
145 else
146 return frame::CommandGroup::INTERNAL;
149 sal_uInt32 Get10ThSec()
151 sal_uInt32 n10Ticks = 10 * static_cast<sal_uInt32>(clock());
152 return n10Ticks / CLOCKS_PER_SEC;
155 static sal_Int32 m_nInReschedule = 0; /// static counter for rescheduling
157 static void reschedule()
159 if ( m_nInReschedule == 0 )
161 ++m_nInReschedule;
162 Application::Reschedule();
163 --m_nInReschedule;
167 namespace {
169 class SfxStatusIndicator : public ::cppu::WeakImplHelper< task::XStatusIndicator, lang::XEventListener >
171 Reference < XController > xOwner;
172 Reference < task::XStatusIndicator > xProgress;
173 SfxWorkWindow* pWorkWindow;
174 tools::Long _nStartTime;
175 public:
176 SfxStatusIndicator(SfxBaseController* pController, SfxWorkWindow* pWork)
177 : xOwner( pController )
178 , pWorkWindow( pWork )
179 , _nStartTime(0)
181 osl_atomic_increment(&m_refCount);
182 Reference< lang::XComponent > xComponent = pController;
183 if (xComponent.is())
184 xComponent->addEventListener(this);
185 osl_atomic_decrement(&m_refCount);
188 virtual void SAL_CALL start(const OUString& aText, sal_Int32 nRange) override;
189 virtual void SAL_CALL end() override;
190 virtual void SAL_CALL setText(const OUString& aText) override;
191 virtual void SAL_CALL setValue(sal_Int32 nValue) override;
192 virtual void SAL_CALL reset() override;
194 virtual void SAL_CALL disposing( const lang::EventObject& Source ) override;
199 void SAL_CALL SfxStatusIndicator::start(const OUString& aText, sal_Int32 nRange)
201 SolarMutexGuard aGuard;
202 if ( xOwner.is() )
204 if ( !xProgress.is() )
205 xProgress = pWorkWindow->GetStatusIndicator();
207 if ( xProgress.is() )
208 xProgress->start( aText, nRange );
210 _nStartTime = Get10ThSec();
211 reschedule();
215 void SAL_CALL SfxStatusIndicator::end()
217 SolarMutexGuard aGuard;
218 if ( xOwner.is() )
220 if ( !xProgress.is() )
221 xProgress = pWorkWindow->GetStatusIndicator();
223 if ( xProgress.is() )
224 xProgress->end();
226 reschedule();
230 void SAL_CALL SfxStatusIndicator::setText(const OUString& aText)
232 SolarMutexGuard aGuard;
233 if ( xOwner.is() )
235 if ( !xProgress.is() )
236 xProgress = pWorkWindow->GetStatusIndicator();
238 if ( xProgress.is() )
239 xProgress->setText( aText );
241 reschedule();
245 void SAL_CALL SfxStatusIndicator::setValue( sal_Int32 nValue )
247 SolarMutexGuard aGuard;
248 if ( xOwner.is() )
250 if ( !xProgress.is() )
251 xProgress = pWorkWindow->GetStatusIndicator();
253 if ( xProgress.is() )
254 xProgress->setValue( nValue );
256 bool bReschedule = (( Get10ThSec() - _nStartTime ) > TIMEOUT_START_RESCHEDULE );
257 if ( bReschedule )
258 reschedule();
262 void SAL_CALL SfxStatusIndicator::reset()
264 SolarMutexGuard aGuard;
265 if ( xOwner.is() )
267 if ( !xProgress.is() )
268 xProgress = pWorkWindow->GetStatusIndicator();
270 if ( xProgress.is() )
271 xProgress->reset();
273 reschedule();
277 void SAL_CALL SfxStatusIndicator::disposing( const lang::EventObject& /*Source*/ )
279 SolarMutexGuard aGuard;
280 xOwner = nullptr;
281 xProgress.clear();
285 // declaration IMPL_SfxBaseController_ListenerHelper
287 namespace {
289 class IMPL_SfxBaseController_ListenerHelper : public ::cppu::WeakImplHelper< frame::XFrameActionListener >
291 public:
292 explicit IMPL_SfxBaseController_ListenerHelper( SfxBaseController* pController ) ;
294 virtual void SAL_CALL frameAction( const frame::FrameActionEvent& aEvent ) override ;
295 virtual void SAL_CALL disposing( const lang::EventObject& aEvent ) override ;
297 private:
299 SfxBaseController* m_pController ;
301 } ; // class IMPL_SfxBaseController_ListenerContainer
303 class IMPL_SfxBaseController_CloseListenerHelper : public ::cppu::WeakImplHelper< util::XCloseListener >
305 public:
306 explicit IMPL_SfxBaseController_CloseListenerHelper( SfxBaseController* pController ) ;
308 virtual void SAL_CALL queryClosing( const lang::EventObject& aEvent, sal_Bool bDeliverOwnership ) override ;
309 virtual void SAL_CALL notifyClosing( const lang::EventObject& aEvent ) override ;
310 virtual void SAL_CALL disposing( const lang::EventObject& aEvent ) override ;
312 private:
314 SfxBaseController* m_pController;
316 } ; // class IMPL_SfxBaseController_ListenerContainer
320 IMPL_SfxBaseController_CloseListenerHelper::IMPL_SfxBaseController_CloseListenerHelper( SfxBaseController* pController )
321 : m_pController ( pController )
325 void SAL_CALL IMPL_SfxBaseController_CloseListenerHelper::disposing( const lang::EventObject& /*aEvent*/ )
329 void SAL_CALL IMPL_SfxBaseController_CloseListenerHelper::queryClosing( const lang::EventObject& /*aEvent*/, sal_Bool /*bDeliverOwnership*/ )
331 SolarMutexGuard aGuard;
332 SfxViewShell* pShell = m_pController->GetViewShell_Impl();
333 if (pShell)
335 bool bCanClose = pShell->PrepareClose( false );
336 if ( !bCanClose )
338 throw util::CloseVetoException(u"Controller disagree ..."_ustr,getXWeak());
343 void SAL_CALL IMPL_SfxBaseController_CloseListenerHelper::notifyClosing( const lang::EventObject& /*aEvent*/ )
348 // declaration IMPL_SfxBaseController_DataContainer
351 struct IMPL_SfxBaseController_DataContainer
353 Reference< XFrame > m_xFrame ;
354 Reference< XFrameActionListener > m_xListener ;
355 Reference< XCloseListener > m_xCloseListener ;
356 ::sfx2::UserInputInterception m_aUserInputInterception;
357 ::comphelper::OMultiTypeInterfaceContainerHelper2 m_aListenerContainer ;
358 ::comphelper::OInterfaceContainerHelper3<ui::XContextMenuInterceptor> m_aInterceptorContainer ;
359 rtl::Reference< SfxStatusIndicator > m_xIndicator ;
360 SfxViewShell* m_pViewShell ;
361 SfxBaseController* m_pController ;
362 bool m_bDisposing ;
363 bool m_bSuspendState ;
364 rtl::Reference< ::framework::TitleHelper > m_xTitleHelper ;
365 Sequence< PropertyValue > m_aCreationArgs ;
367 IMPL_SfxBaseController_DataContainer( ::osl::Mutex& aMutex ,
368 SfxViewShell* pViewShell ,
369 SfxBaseController* pController )
370 : m_xListener ( new IMPL_SfxBaseController_ListenerHelper( pController ) )
371 , m_xCloseListener ( new IMPL_SfxBaseController_CloseListenerHelper( pController ) )
372 , m_aUserInputInterception ( *pController, aMutex )
373 , m_aListenerContainer ( aMutex )
374 , m_aInterceptorContainer ( aMutex )
375 , m_pViewShell ( pViewShell )
376 , m_pController ( pController )
377 , m_bDisposing ( false )
378 , m_bSuspendState ( false )
382 } ; // struct IMPL_SfxBaseController_DataContainer
385 // IMPL_SfxBaseController_ListenerHelper constructor
388 IMPL_SfxBaseController_ListenerHelper::IMPL_SfxBaseController_ListenerHelper( SfxBaseController* pController )
389 : m_pController ( pController )
393 void SAL_CALL IMPL_SfxBaseController_ListenerHelper::frameAction( const frame::FrameActionEvent& aEvent )
395 SolarMutexGuard aGuard;
396 if (
397 ( m_pController != nullptr ) &&
398 ( aEvent.Frame == m_pController->getFrame() ) &&
399 ( m_pController->GetViewShell_Impl() && m_pController->GetViewShell_Impl()->GetWindow() != nullptr )
402 if ( aEvent.Action == frame::FrameAction_FRAME_UI_ACTIVATED )
404 if ( !m_pController->GetViewShell_Impl()->GetUIActiveIPClient_Impl() )
405 m_pController->GetViewShell_Impl()->GetViewFrame().MakeActive_Impl( false );
407 else if ( aEvent.Action == frame::FrameAction_CONTEXT_CHANGED )
409 m_pController->GetViewShell_Impl()->GetViewFrame().GetBindings().ContextChanged_Impl();
415 // IMPL_SfxBaseController_ListenerHelper -> XEventListener
418 void SAL_CALL IMPL_SfxBaseController_ListenerHelper::disposing( const lang::EventObject& /*aEvent*/ )
420 SolarMutexGuard aGuard;
421 if ( m_pController && m_pController->getFrame().is() )
422 m_pController->getFrame()->removeFrameActionListener( this ) ;
425 SfxBaseController::SfxBaseController( SfxViewShell* pViewShell )
426 : m_pData ( new IMPL_SfxBaseController_DataContainer( m_aMutex, pViewShell, this ))
428 m_pData->m_pViewShell->SetController( this );
432 // SfxBaseController -> destructor
435 SfxBaseController::~SfxBaseController()
440 // SfxBaseController -> XController2
443 Reference< XWindow > SAL_CALL SfxBaseController::getComponentWindow()
445 SolarMutexGuard aGuard;
446 if ( !m_pData->m_pViewShell )
447 throw DisposedException();
449 return Reference< XWindow >( GetViewFrame_Impl().GetFrame().GetWindow().GetComponentInterface(), UNO_QUERY_THROW );
452 OUString SAL_CALL SfxBaseController::getViewControllerName()
454 SolarMutexGuard aGuard;
455 if ( !m_pData->m_pViewShell || !m_pData->m_pViewShell->GetObjectShell() )
456 throw DisposedException();
458 const SfxObjectFactory& rDocFac( m_pData->m_pViewShell->GetObjectShell()->GetFactory() );
459 sal_uInt16 nViewNo = rDocFac.GetViewNo_Impl( GetViewFrame_Impl().GetCurViewId(), rDocFac.GetViewFactoryCount() );
460 OSL_ENSURE( nViewNo < rDocFac.GetViewFactoryCount(), "SfxBaseController::getViewControllerName: view ID not found in view factories!" );
462 OUString sViewName;
463 if ( nViewNo < rDocFac.GetViewFactoryCount() )
464 sViewName = rDocFac.GetViewFactory( nViewNo ).GetAPIViewName();
466 return sViewName;
469 Sequence< PropertyValue > SAL_CALL SfxBaseController::getCreationArguments()
471 SolarMutexGuard aGuard;
472 if ( !m_pData->m_pViewShell || !m_pData->m_pViewShell->GetObjectShell() )
473 throw DisposedException();
475 return m_pData->m_aCreationArgs;
478 void SfxBaseController::SetCreationArguments_Impl( const Sequence< PropertyValue >& i_rCreationArgs )
480 OSL_ENSURE( !m_pData->m_aCreationArgs.hasElements(), "SfxBaseController::SetCreationArguments_Impl: not intended to be called twice!" );
481 m_pData->m_aCreationArgs = i_rCreationArgs;
484 SfxViewFrame& SfxBaseController::GetViewFrame_Impl() const
486 ENSURE_OR_THROW( m_pData->m_pViewShell, "not to be called without a view shell" );
487 SfxViewFrame* pActFrame = m_pData->m_pViewShell->GetFrame();
488 ENSURE_OR_THROW( pActFrame, "a view shell without a view frame is pretty pathological" );
489 return *pActFrame;
493 Reference<XSidebarProvider> SAL_CALL SfxBaseController::getSidebar()
495 SfxViewFrame& rViewFrame = GetViewFrame_Impl();
496 SfxFrame& rFrame = rViewFrame.GetFrame();
498 Reference<XSidebarProvider> rSidebar = new SfxUnoSidebar(rFrame.GetFrameInterface());
499 return rSidebar;
503 // SfxBaseController -> XController2 -> XController
506 void SAL_CALL SfxBaseController::attachFrame( const Reference< frame::XFrame >& xFrame )
508 Reference< frame::XFrame > xTemp( getFrame() ) ;
510 SolarMutexGuard aGuard;
511 if ( xTemp.is() )
513 xTemp->removeFrameActionListener( m_pData->m_xListener ) ;
514 Reference < util::XCloseBroadcaster > xCloseable( xTemp, uno::UNO_QUERY );
515 if ( xCloseable.is() )
516 xCloseable->removeCloseListener( m_pData->m_xCloseListener );
519 m_pData->m_xFrame = xFrame;
521 if ( !xFrame.is() )
522 return;
524 xFrame->addFrameActionListener( m_pData->m_xListener ) ;
525 Reference < util::XCloseBroadcaster > xCloseable( xFrame, uno::UNO_QUERY );
526 if ( xCloseable.is() )
527 xCloseable->addCloseListener( m_pData->m_xCloseListener );
529 if ( m_pData->m_pViewShell )
531 ConnectSfxFrame_Impl( E_CONNECT );
532 ShowInfoBars( );
534 // attaching the frame to the controller is the last step in the creation of a new view, so notify this
535 SfxViewEventHint aHint( SfxEventHintId::ViewCreated, GlobalEventConfig::GetEventName( GlobalEventId::VIEWCREATED ), m_pData->m_pViewShell->GetObjectShell(), Reference< frame::XController2 >( this ) );
536 SfxGetpApp()->NotifyEvent( aHint );
541 // SfxBaseController -> XController
544 sal_Bool SAL_CALL SfxBaseController::attachModel( const Reference< frame::XModel >& xModel )
546 if ( m_pData->m_pViewShell && xModel.is() && xModel != m_pData->m_pViewShell->GetObjectShell()->GetModel() )
548 // don't allow to reattach a model!
549 OSL_FAIL("Can't reattach model!");
550 return false;
553 Reference < util::XCloseBroadcaster > xCloseable( xModel, uno::UNO_QUERY );
554 if ( xCloseable.is() )
555 xCloseable->addCloseListener( m_pData->m_xCloseListener );
556 return true;
560 // SfxBaseController -> XController
563 sal_Bool SAL_CALL SfxBaseController::suspend( sal_Bool bSuspend )
565 SolarMutexGuard aGuard;
567 // ignore duplicate calls, which doesn't change anything real
568 if (bool(bSuspend) == m_pData->m_bSuspendState)
569 return true;
571 if ( bSuspend )
573 if ( !m_pData->m_pViewShell )
575 m_pData->m_bSuspendState = true;
576 return true;
579 if ( !m_pData->m_pViewShell->PrepareClose() )
580 return false;
582 if ( getFrame().is() )
583 getFrame()->removeFrameActionListener( m_pData->m_xListener ) ;
584 SfxViewFrame* pActFrame = m_pData->m_pViewShell->GetFrame() ;
586 // More Views on the same document?
587 SfxObjectShell* pDocShell = m_pData->m_pViewShell->GetObjectShell() ;
588 bool bOther = false ;
590 for ( const SfxViewFrame* pFrame = SfxViewFrame::GetFirst( pDocShell ); !bOther && pFrame; pFrame = SfxViewFrame::GetNext( *pFrame, pDocShell ) )
591 bOther = (pFrame != pActFrame);
593 bool bRet = bOther || pDocShell->PrepareClose();
594 if ( bRet )
596 ConnectSfxFrame_Impl( E_DISCONNECT );
597 m_pData->m_bSuspendState = true;
600 return bRet;
602 else
604 if ( getFrame().is() )
605 getFrame()->addFrameActionListener( m_pData->m_xListener ) ;
607 if ( m_pData->m_pViewShell )
609 ConnectSfxFrame_Impl( E_RECONNECT );
612 m_pData->m_bSuspendState = false;
613 return true ;
618 // SfxBaseController -> XController
621 uno::Any SfxBaseController::getViewData()
623 uno::Any aAny;
624 SolarMutexGuard aGuard;
625 if ( m_pData->m_pViewShell )
627 OUString sData;
628 m_pData->m_pViewShell->WriteUserData( sData ) ;
629 aAny <<= sData ;
632 return aAny ;
636 // SfxBaseController -> XController
639 void SAL_CALL SfxBaseController::restoreViewData( const uno::Any& aValue )
641 SolarMutexGuard aGuard;
642 if ( m_pData->m_pViewShell )
644 OUString sData;
645 aValue >>= sData ;
646 m_pData->m_pViewShell->ReadUserData( sData ) ;
651 // SfxBaseController -> XController
654 Reference< frame::XFrame > SAL_CALL SfxBaseController::getFrame()
656 SolarMutexGuard aGuard;
657 return m_pData->m_xFrame;
661 // SfxBaseController -> XController
664 Reference< frame::XModel > SAL_CALL SfxBaseController::getModel()
666 SolarMutexGuard aGuard;
667 return m_pData->m_pViewShell ? m_pData->m_pViewShell->GetObjectShell()->GetModel() : Reference < frame::XModel > () ;
671 // SfxBaseController -> XDispatchProvider
673 static css::uno::Reference<css::frame::XDispatch>
674 GetSlotDispatchWithFallback(SfxViewFrame* pViewFrame, const css::util::URL& aURL,
675 const OUString& sActCommand, bool bMasterCommand, const SfxSlot* pSlot)
677 assert(pViewFrame);
679 if (pSlot && (!pViewFrame->GetFrame().IsInPlace() || !pSlot->IsMode(SfxSlotMode::CONTAINER)))
680 return pViewFrame->GetBindings().GetDispatch(pSlot, aURL, bMasterCommand);
682 // try to find parent SfxViewFrame
683 if (const auto& xOwnFrame = pViewFrame->GetFrame().GetFrameInterface())
685 if (const auto xParentFrame = xOwnFrame->getCreator())
687 // TODO/LATER: in future probably SfxViewFrame hierarchy should be the same as XFrame hierarchy
688 // SfxViewFrame* pParentFrame = pViewFrame->GetParentViewFrame();
690 // search the related SfxViewFrame
691 SfxViewFrame* pParentFrame = nullptr;
692 for (SfxViewFrame* pFrame = SfxViewFrame::GetFirst(); pFrame;
693 pFrame = SfxViewFrame::GetNext(*pFrame))
695 if (pFrame->GetFrame().GetFrameInterface() == xParentFrame)
697 pParentFrame = pFrame;
698 break;
702 if (pParentFrame)
704 const SfxSlotPool& rFrameSlotPool = SfxSlotPool::GetSlotPool(pParentFrame);
705 if (const SfxSlot* pSlot2 = rFrameSlotPool.GetUnoSlot(sActCommand))
706 return pParentFrame->GetBindings().GetDispatch(pSlot2, aURL, bMasterCommand);
711 return {};
714 Reference< frame::XDispatch > SAL_CALL SfxBaseController::queryDispatch( const util::URL& aURL ,
715 const OUString& sTargetFrameName,
716 sal_Int32 eSearchFlags )
718 SolarMutexGuard aGuard;
720 if (!m_pData->m_bDisposing && m_pData->m_pViewShell)
722 SfxViewFrame& rAct = m_pData->m_pViewShell->GetViewFrame() ;
723 if ( sTargetFrameName == "_beamer" )
725 if ( eSearchFlags & frame::FrameSearchFlag::CREATE )
726 rAct.SetChildWindow( SID_BROWSER, true );
727 if (SfxChildWindow* pChildWin = rAct.GetChildWindow(SID_BROWSER))
729 if (Reference<frame::XFrame> xFrame{ pChildWin->GetFrame() })
731 xFrame->setName(sTargetFrameName);
732 if (Reference<XDispatchProvider> xProv{ xFrame, uno::UNO_QUERY })
733 return xProv->queryDispatch(aURL, sTargetFrameName, frame::FrameSearchFlag::SELF);
738 if ( aURL.Protocol == ".uno:" )
740 OUString aActCommand = SfxOfficeDispatch::GetMasterUnoCommand(aURL);
741 bool bMasterCommand(!aActCommand.isEmpty());
742 if (!bMasterCommand)
743 aActCommand = aURL.Path;
744 const SfxSlot* pSlot = SfxSlotPool::GetSlotPool(&rAct).GetUnoSlot(aActCommand);
745 return GetSlotDispatchWithFallback(&rAct, aURL, aActCommand, bMasterCommand, pSlot);
747 else if ( aURL.Protocol == "slot:" )
749 sal_uInt16 nId = static_cast<sal_uInt16>(aURL.Path.toInt32());
751 if (nId >= SID_VERB_START && nId <= SID_VERB_END)
753 const SfxSlot* pSlot = m_pData->m_pViewShell->GetVerbSlot_Impl(nId);
754 if ( pSlot )
755 return rAct.GetBindings().GetDispatch( pSlot, aURL, false );
758 const SfxSlot* pSlot = SfxSlotPool::GetSlotPool(&rAct).GetSlot(nId);
759 return GetSlotDispatchWithFallback(&rAct, aURL, aURL.Path, false, pSlot);
761 else if( sTargetFrameName == "_self" || sTargetFrameName.isEmpty() )
763 // check for already loaded URL ... but with additional jumpmark!
764 Reference< frame::XModel > xModel = getModel();
765 if( xModel.is() && !aURL.Mark.isEmpty() )
767 SfxSlotPool& rSlotPool = SfxSlotPool::GetSlotPool( &rAct );
768 const SfxSlot* pSlot = rSlotPool.GetSlot( SID_JUMPTOMARK );
769 if( !aURL.Main.isEmpty() && aURL.Main == xModel->getURL() && pSlot )
770 return Reference< frame::XDispatch >( new SfxOfficeDispatch( rAct.GetBindings(), rAct.GetDispatcher(), pSlot, aURL) );
775 return {};
779 // SfxBaseController -> XDispatchProvider
782 uno::Sequence< Reference< frame::XDispatch > > SAL_CALL SfxBaseController::queryDispatches( const uno::Sequence< frame::DispatchDescriptor >& seqDescripts )
784 // Create return list - which must have same size then the given descriptor
785 // It's not allowed to pack it!
786 sal_Int32 nCount = seqDescripts.getLength();
787 uno::Sequence< Reference< frame::XDispatch > > lDispatcher( nCount );
789 std::transform(seqDescripts.begin(), seqDescripts.end(), lDispatcher.getArray(),
790 [this](const frame::DispatchDescriptor& rDesc) -> Reference< frame::XDispatch > {
791 return queryDispatch(rDesc.FeatureURL, rDesc.FrameName, rDesc.SearchFlags); });
793 return lDispatcher;
797 // SfxBaseController -> XControllerBorder
800 frame::BorderWidths SAL_CALL SfxBaseController::getBorder()
802 frame::BorderWidths aResult;
804 SolarMutexGuard aGuard;
805 if ( m_pData->m_pViewShell )
807 SvBorder aBorder = m_pData->m_pViewShell->GetBorderPixel();
808 aResult.Left = aBorder.Left();
809 aResult.Top = aBorder.Top();
810 aResult.Right = aBorder.Right();
811 aResult.Bottom = aBorder.Bottom();
814 return aResult;
817 void SAL_CALL SfxBaseController::addBorderResizeListener( const Reference< frame::XBorderResizeListener >& xListener )
819 m_pData->m_aListenerContainer.addInterface( cppu::UnoType<frame::XBorderResizeListener>::get(),
820 xListener );
823 void SAL_CALL SfxBaseController::removeBorderResizeListener( const Reference< frame::XBorderResizeListener >& xListener )
825 m_pData->m_aListenerContainer.removeInterface( cppu::UnoType<frame::XBorderResizeListener>::get(),
826 xListener );
829 awt::Rectangle SAL_CALL SfxBaseController::queryBorderedArea( const awt::Rectangle& aPreliminaryRectangle )
831 SolarMutexGuard aGuard;
832 if ( m_pData->m_pViewShell )
834 tools::Rectangle aTmpRect = vcl::unohelper::ConvertToVCLRect(aPreliminaryRectangle);
835 m_pData->m_pViewShell->QueryObjAreaPixel( aTmpRect );
836 return vcl::unohelper::ConvertToAWTRect(aTmpRect);
839 return aPreliminaryRectangle;
842 void SfxBaseController::BorderWidthsChanged_Impl()
844 ::comphelper::OInterfaceContainerHelper2* pContainer = m_pData->m_aListenerContainer.getContainer(
845 cppu::UnoType<frame::XBorderResizeListener>::get());
846 if ( !pContainer )
847 return;
849 frame::BorderWidths aBWidths = getBorder();
850 Reference< uno::XInterface > xThis( getXWeak() );
852 ::comphelper::OInterfaceIteratorHelper2 pIterator(*pContainer);
853 while (pIterator.hasMoreElements())
857 static_cast<frame::XBorderResizeListener*>(pIterator.next())->borderWidthsChanged( xThis, aBWidths );
859 catch (const RuntimeException&)
861 pIterator.remove();
867 // SfxBaseController -> XComponent
870 void SAL_CALL SfxBaseController::dispose()
872 SolarMutexGuard aGuard;
873 Reference< XController > xKeepAlive( this );
874 m_pData->m_bDisposing = true ;
876 lang::EventObject aEventObject;
877 aEventObject.Source = *this ;
878 m_pData->m_aListenerContainer.disposeAndClear( aEventObject ) ;
880 if ( m_pData->m_pController && m_pData->m_pController->getFrame().is() )
881 m_pData->m_pController->getFrame()->removeFrameActionListener( m_pData->m_xListener ) ;
883 if ( !m_pData->m_pViewShell )
884 return;
886 SfxViewFrame& rFrame = m_pData->m_pViewShell->GetViewFrame() ;
887 if (rFrame.GetViewShell() == m_pData->m_pViewShell )
888 rFrame.GetFrame().SetIsClosing_Impl();
889 m_pData->m_pViewShell->DisconnectAllClients();
891 lang::EventObject aObject;
892 aObject.Source = *this ;
894 SfxObjectShell* pDoc = rFrame.GetObjectShell() ;
895 SfxViewFrame *pView = SfxViewFrame::GetFirst(pDoc);
896 while( pView )
898 // if there is another ViewFrame or currently the ViewShell in my ViewFrame is switched (PagePreview)
899 if ( pView != &rFrame || pView->GetViewShell() != m_pData->m_pViewShell )
900 break;
901 pView = SfxViewFrame::GetNext( *pView, pDoc );
904 SfxGetpApp()->NotifyEvent( SfxViewEventHint(SfxEventHintId::CloseView, GlobalEventConfig::GetEventName( GlobalEventId::CLOSEVIEW ), pDoc, Reference< frame::XController2 >( this ) ) );
905 if ( !pView )
906 SfxGetpApp()->NotifyEvent( SfxEventHint(SfxEventHintId::CloseDoc, GlobalEventConfig::GetEventName( GlobalEventId::CLOSEDOC ), pDoc) );
908 Reference< frame::XModel > xModel = pDoc->GetModel();
909 Reference < util::XCloseable > xCloseable( xModel, uno::UNO_QUERY );
910 if ( xModel.is() )
912 xModel->disconnectController( this );
913 if ( xCloseable.is() )
914 xCloseable->removeCloseListener( m_pData->m_xCloseListener );
917 Reference < frame::XFrame > aXFrame;
918 attachFrame( aXFrame );
920 m_pData->m_xListener->disposing( aObject );
921 SfxViewShell *pShell = m_pData->m_pViewShell;
922 m_pData->m_pViewShell = nullptr;
923 if (rFrame.GetViewShell() == pShell)
925 // Enter registrations only allowed if we are the owner!
926 if ( rFrame.GetFrame().OwnsBindings_Impl() )
927 rFrame.GetBindings().ENTERREGISTRATIONS();
928 rFrame.GetFrame().SetFrameInterface_Impl( aXFrame );
929 rFrame.GetFrame().DoClose_Impl();
934 // SfxBaseController -> XComponent
937 void SAL_CALL SfxBaseController::addEventListener( const Reference< lang::XEventListener >& aListener )
939 m_pData->m_aListenerContainer.addInterface( cppu::UnoType<lang::XEventListener>::get(), aListener );
943 // SfxBaseController -> XComponent
946 void SAL_CALL SfxBaseController::removeEventListener( const Reference< lang::XEventListener >& aListener )
948 m_pData->m_aListenerContainer.removeInterface( cppu::UnoType<lang::XEventListener>::get(), aListener );
951 void SfxBaseController::ReleaseShell_Impl()
953 SolarMutexGuard aGuard;
954 if ( !m_pData->m_pViewShell )
955 return;
957 SfxObjectShell* pDoc = m_pData->m_pViewShell->GetObjectShell() ;
958 Reference< frame::XModel > xModel = pDoc->GetModel();
959 Reference < util::XCloseable > xCloseable( xModel, uno::UNO_QUERY );
960 if ( xModel.is() )
962 xModel->disconnectController( this );
963 if ( xCloseable.is() )
964 xCloseable->removeCloseListener( m_pData->m_xCloseListener );
966 m_pData->m_pViewShell = nullptr;
968 Reference < frame::XFrame > aXFrame;
969 attachFrame( aXFrame );
972 void SfxBaseController::CopyLokViewCallbackFromFrameCreator()
974 if (!m_pData->m_pViewShell)
975 return;
976 SfxLokCallbackInterface* pCallback = nullptr;
977 if (m_pData->m_xFrame)
978 if (auto xCreator = m_pData->m_xFrame->getCreator())
979 if (auto parentVS = SfxViewShell::Get(xCreator->getController()))
980 pCallback = parentVS->getLibreOfficeKitViewCallback();
981 m_pData->m_pViewShell->setLibreOfficeKitViewCallback(pCallback);
984 SfxViewShell* SfxBaseController::GetViewShell_Impl() const
986 return m_pData->m_pViewShell;
989 Reference< task::XStatusIndicator > SAL_CALL SfxBaseController::getStatusIndicator( )
991 SolarMutexGuard aGuard;
992 if ( m_pData->m_pViewShell && !m_pData->m_xIndicator.is() )
993 m_pData->m_xIndicator = new SfxStatusIndicator( this, m_pData->m_pViewShell->GetViewFrame().GetFrame().GetWorkWindow_Impl() );
994 return m_pData->m_xIndicator;
997 void SAL_CALL SfxBaseController::registerContextMenuInterceptor( const Reference< ui::XContextMenuInterceptor >& xInterceptor )
1000 m_pData->m_aInterceptorContainer.addInterface( xInterceptor );
1002 SolarMutexGuard aGuard;
1003 if ( m_pData->m_pViewShell )
1004 m_pData->m_pViewShell->AddContextMenuInterceptor_Impl( xInterceptor );
1007 void SAL_CALL SfxBaseController::releaseContextMenuInterceptor( const Reference< ui::XContextMenuInterceptor >& xInterceptor )
1010 m_pData->m_aInterceptorContainer.removeInterface( xInterceptor );
1012 SolarMutexGuard aGuard;
1013 if ( m_pData->m_pViewShell )
1014 m_pData->m_pViewShell->RemoveContextMenuInterceptor_Impl( xInterceptor );
1017 void SAL_CALL SfxBaseController::addKeyHandler( const Reference< awt::XKeyHandler >& xHandler )
1019 SolarMutexGuard aGuard;
1020 m_pData->m_aUserInputInterception.addKeyHandler( xHandler );
1023 void SAL_CALL SfxBaseController::removeKeyHandler( const Reference< awt::XKeyHandler >& xHandler )
1025 SolarMutexGuard aGuard;
1026 m_pData->m_aUserInputInterception.removeKeyHandler( xHandler );
1029 void SAL_CALL SfxBaseController::addMouseClickHandler( const Reference< awt::XMouseClickHandler >& xHandler )
1031 SolarMutexGuard aGuard;
1032 m_pData->m_aUserInputInterception.addMouseClickHandler( xHandler );
1035 void SAL_CALL SfxBaseController::removeMouseClickHandler( const Reference< awt::XMouseClickHandler >& xHandler )
1037 SolarMutexGuard aGuard;
1038 m_pData->m_aUserInputInterception.removeMouseClickHandler( xHandler );
1041 uno::Sequence< sal_Int16 > SAL_CALL SfxBaseController::getSupportedCommandGroups()
1043 SolarMutexGuard aGuard;
1045 std::vector< sal_Int16 > aGroupList;
1046 SfxViewFrame* pViewFrame = m_pData->m_pViewShell ? m_pData->m_pViewShell->GetFrame() : nullptr;
1047 SfxSlotPool* pSlotPool = pViewFrame ? &SfxSlotPool::GetSlotPool(pViewFrame) : &SFX_SLOTPOOL();
1048 const SfxSlotMode nMode( SfxSlotMode::TOOLBOXCONFIG|SfxSlotMode::ACCELCONFIG|SfxSlotMode::MENUCONFIG );
1050 // Select Group ( Group 0 is internal )
1051 for ( sal_uInt16 i=0; i<pSlotPool->GetGroupCount(); i++ )
1053 pSlotPool->SeekGroup( i );
1054 const SfxSlot* pSfxSlot = pSlotPool->FirstSlot();
1055 while ( pSfxSlot )
1057 if ( pSfxSlot->GetMode() & nMode )
1059 sal_Int16 nCommandGroup = MapGroupIDToCommandGroup( pSfxSlot->GetGroupId() );
1060 aGroupList.push_back( nCommandGroup );
1061 break;
1063 pSfxSlot = pSlotPool->NextSlot();
1067 return comphelper::containerToSequence( aGroupList );
1070 uno::Sequence< frame::DispatchInformation > SAL_CALL SfxBaseController::getConfigurableDispatchInformation( sal_Int16 nCmdGroup )
1072 std::vector< frame::DispatchInformation > aCmdVector;
1074 SolarMutexGuard aGuard;
1075 if ( m_pData->m_pViewShell )
1077 const SfxSlotMode nMode( SfxSlotMode::TOOLBOXCONFIG|SfxSlotMode::ACCELCONFIG|SfxSlotMode::MENUCONFIG );
1079 SfxViewFrame* pViewFrame( m_pData->m_pViewShell->GetFrame() );
1080 SfxSlotPool* pSlotPool
1081 = pViewFrame ? &SfxSlotPool::GetSlotPool(pViewFrame) : &SFX_SLOTPOOL();
1082 for ( sal_uInt16 i=0; i<pSlotPool->GetGroupCount(); i++ )
1084 pSlotPool->SeekGroup( i );
1085 const SfxSlot* pSfxSlot = pSlotPool->FirstSlot();
1086 if ( pSfxSlot )
1088 sal_Int16 nCommandGroup = MapGroupIDToCommandGroup( pSfxSlot->GetGroupId() );
1089 if ( nCommandGroup == nCmdGroup )
1091 while ( pSfxSlot )
1093 if ( pSfxSlot->GetMode() & nMode )
1095 frame::DispatchInformation aCmdInfo;
1096 aCmdInfo.Command = pSfxSlot->GetCommand();
1097 aCmdInfo.GroupId = nCommandGroup;
1098 aCmdVector.push_back( aCmdInfo );
1100 pSfxSlot = pSlotPool->NextSlot();
1107 return comphelper::containerToSequence( aCmdVector );
1110 bool SfxBaseController::HandleEvent_Impl( NotifyEvent const & rEvent )
1112 return m_pData->m_aUserInputInterception.handleNotifyEvent( rEvent );
1115 bool SfxBaseController::HasKeyListeners_Impl() const
1117 return m_pData->m_aUserInputInterception.hasKeyHandlers();
1120 bool SfxBaseController::HasMouseClickListeners_Impl() const
1122 return m_pData->m_aUserInputInterception.hasMouseClickListeners();
1125 void SfxBaseController::ConnectSfxFrame_Impl( const ConnectSfxFrame i_eConnect )
1127 ENSURE_OR_THROW( m_pData->m_pViewShell, "not to be called without a view shell" );
1128 SfxViewFrame* pViewFrame = m_pData->m_pViewShell->GetFrame();
1129 ENSURE_OR_THROW( pViewFrame, "a view shell without a view frame is pretty pathological" );
1131 const bool bConnect = ( i_eConnect != E_DISCONNECT );
1133 // disable window and dispatcher
1134 pViewFrame->Enable( bConnect );
1135 pViewFrame->GetDispatcher()->Lock( !bConnect );
1137 if ( bConnect )
1139 if ( i_eConnect == E_CONNECT )
1141 if ( ( m_pData->m_pViewShell->GetObjectShell() != nullptr )
1142 && ( m_pData->m_pViewShell->GetObjectShell()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
1145 SfxViewFrame& rViewFrm = m_pData->m_pViewShell->GetViewFrame();
1146 if ( !rViewFrm.GetFrame().IsInPlace() )
1148 // for outplace embedded objects, we want the layout manager to keep the content window
1149 // size constant, if possible
1152 Reference< beans::XPropertySet > xFrameProps( m_pData->m_xFrame, uno::UNO_QUERY_THROW );
1153 Reference< beans::XPropertySet > xLayouterProps(
1154 xFrameProps->getPropertyValue(u"LayoutManager"_ustr), uno::UNO_QUERY_THROW );
1155 xLayouterProps->setPropertyValue(u"PreserveContentSize"_ustr, uno::Any( true ) );
1157 catch (const uno::Exception&)
1159 DBG_UNHANDLED_EXCEPTION("sfx.view");
1165 // upon DISCONNECT, we did *not* pop the shells from the stack (this is done elsewhere), so upon
1166 // RECONNECT, we're not allowed to push them
1167 if ( i_eConnect != E_RECONNECT )
1169 pViewFrame->GetDispatcher()->Push( *m_pData->m_pViewShell );
1170 m_pData->m_pViewShell->PushSubShells_Impl();
1171 pViewFrame->GetDispatcher()->Flush();
1174 vcl::Window* pEditWin = m_pData->m_pViewShell->GetWindow();
1175 if ( pEditWin )
1176 pEditWin->Show();
1178 if ( SfxViewFrame::Current() == pViewFrame )
1179 pViewFrame->GetDispatcher()->Update_Impl( true );
1181 vcl::Window* pFrameWin = &pViewFrame->GetWindow();
1182 if ( pFrameWin != &pViewFrame->GetFrame().GetWindow() )
1183 pFrameWin->Show();
1185 if ( i_eConnect == E_CONNECT )
1187 css::uno::Reference<css::frame::XModel3> xModel(getModel(), css::uno::UNO_QUERY_THROW);
1188 const sal_Int16 nPluginMode = ::comphelper::NamedValueCollection::getOrDefault( xModel->getArgs2( { u"PluginMode"_ustr } ), u"PluginMode", sal_Int16( 0 ) );
1189 const bool bHasPluginMode = ( nPluginMode != 0 );
1191 SfxFrame& rFrame = pViewFrame->GetFrame();
1192 SfxObjectShell& rDoc = *m_pData->m_pViewShell->GetObjectShell();
1193 if ( !rFrame.IsMarkedHidden_Impl() )
1195 if ( rDoc.IsHelpDocument() || ( nPluginMode == 2 ) )
1196 pViewFrame->GetDispatcher()->HideUI();
1197 else
1198 pViewFrame->GetDispatcher()->HideUI( false );
1200 if ( rFrame.IsInPlace() )
1201 pViewFrame->LockAdjustPosSizePixel();
1203 if ( nPluginMode == 3 )
1204 rFrame.GetWorkWindow_Impl()->SetInternalDockingAllowed( false );
1206 if ( !rFrame.IsInPlace() )
1207 pViewFrame->GetDispatcher()->Update_Impl();
1208 pViewFrame->Show();
1209 rFrame.GetWindow().Show();
1210 if ( !rFrame.IsInPlace() || ( nPluginMode == 3 ) )
1211 pViewFrame->MakeActive_Impl( rFrame.GetFrameInterface()->isActive() );
1213 if ( rFrame.IsInPlace() )
1215 pViewFrame->UnlockAdjustPosSizePixel();
1216 // force resize for OLE server to fix layout problems of writer and math
1217 // see i53651
1218 if ( nPluginMode == 3 )
1219 pViewFrame->Resize( true );
1222 else
1224 DBG_ASSERT( !rFrame.IsInPlace() && !bHasPluginMode, "Special modes not compatible with hidden mode!" );
1225 rFrame.GetWindow().Show();
1228 // UpdateTitle now, hidden TopFrames have otherwise no Name!
1229 pViewFrame->UpdateTitle();
1231 if ( !rFrame.IsInPlace() )
1232 pViewFrame->Resize( true );
1234 ::comphelper::NamedValueCollection aViewArgs(getCreationArguments());
1236 // sometimes we want to avoid adding to the recent documents
1237 bool bAllowPickListEntry = aViewArgs.getOrDefault(u"PickListEntry"_ustr, true);
1238 m_pData->m_pViewShell->GetObjectShell()->AvoidRecentDocs(!bAllowPickListEntry);
1240 // if there's a JumpMark given, then, well, jump to it
1241 const OUString sJumpMark = aViewArgs.getOrDefault( u"JumpMark"_ustr, OUString() );
1242 const bool bHasJumpMark = !sJumpMark.isEmpty();
1243 OSL_ENSURE( ( !m_pData->m_pViewShell->GetObjectShell()->IsLoading() )
1244 || ( sJumpMark.isEmpty() ),
1245 "SfxBaseController::ConnectSfxFrame_Impl: so this code wasn't dead?" );
1246 // Before CWS autorecovery, there was code which postponed jumping to the Mark to a later time
1247 // (SfxObjectShell::PositionView_Impl), but it seems this branch was never used, since this method
1248 // here is never called before the load process finished. At least not with a non-empty jump mark
1249 if ( !sJumpMark.isEmpty() )
1250 m_pData->m_pViewShell->JumpToMark( sJumpMark );
1252 // if no plugin mode and no jump mark was supplied, check whether the document itself can provide view data, and
1253 // if so, forward it to the view/shell.
1254 if ( !bHasPluginMode && !bHasJumpMark )
1256 // Note that this might not be the ideal place here. Restoring view data should, IMO, be the
1257 // responsibility of the loader, not an implementation detail buried here deep within the controller's
1258 // implementation.
1259 // What I think should be done to replace the below code:
1260 // - change SfxBaseController::restoreViewData to also accept a PropertyValue[] (it currently accepts
1261 // a string only), and forward it to its ViewShell's ReadUserDataSequence
1262 // - change the frame loader so that when a new document is loaded (as opposed to an existing
1263 // document being loaded into a new frame), the model's view data is examine the very same
1264 // way as below, and the proper view data is set via XController::restoreViewData
1265 // - extend SfxViewFrame::SwitchToViewShell_Impl. Currently, it cares for the case where a non-PrintPreview
1266 // view is exchanged, and sets the old view's data at the model. It should also care for the other
1267 // way, were the PrintPreview view is left: in this case, the new view should also be initialized
1268 // with the model's view data
1271 Reference< XViewDataSupplier > xViewDataSupplier( getModel(), UNO_QUERY_THROW );
1272 Reference< XIndexAccess > xViewData( xViewDataSupplier->getViewData() );
1274 // find the view data item whose ViewId matches the ID of the view we're just connecting to
1275 const SfxObjectFactory& rDocFactory( rDoc.GetFactory() );
1276 const sal_Int32 nCount = xViewData.is() ? xViewData->getCount() : 0;
1277 sal_Int32 nViewDataIndex = 0;
1278 for ( sal_Int32 i=0; i<nCount; ++i )
1280 const ::comphelper::NamedValueCollection aViewData( xViewData->getByIndex(i) );
1281 OUString sViewId( aViewData.getOrDefault( u"ViewId"_ustr, OUString() ) );
1282 if ( sViewId.isEmpty() )
1283 continue;
1285 const SfxViewFactory* pViewFactory = rDocFactory.GetViewFactoryByViewName( sViewId );
1286 if ( pViewFactory == nullptr )
1287 continue;
1289 if ( pViewFactory->GetOrdinal() == pViewFrame->GetCurViewId() )
1291 nViewDataIndex = i;
1292 break;
1295 if (nViewDataIndex < nCount || !xViewData.is())
1297 Sequence< PropertyValue > aViewData;
1298 if (xViewData.is())
1300 OSL_VERIFY(xViewData->getByIndex(nViewDataIndex) >>= aViewData);
1302 if (aViewData.hasElements() || !xViewData.is())
1304 // Tolerate empty xViewData, ReadUserDataSequence() has side effects.
1305 m_pData->m_pViewShell->ReadUserDataSequence( aViewData );
1309 catch (const Exception&)
1311 DBG_UNHANDLED_EXCEPTION("sfx.view");
1317 // invalidate slot corresponding to the view shell
1318 const sal_uInt16 nViewNo = m_pData->m_pViewShell->GetObjectShell()->GetFactory().GetViewNo_Impl( pViewFrame->GetCurViewId(), USHRT_MAX );
1319 DBG_ASSERT( nViewNo != USHRT_MAX, "view shell id not found" );
1320 if ( nViewNo != USHRT_MAX )
1321 pViewFrame->GetBindings().Invalidate( nViewNo + SID_VIEWSHELL0 );
1324 void SfxBaseController::ShowInfoBars( )
1326 if ( !m_pData->m_pViewShell )
1327 return;
1329 // CMIS verifications
1330 Reference< document::XCmisDocument > xCmisDoc( m_pData->m_pViewShell->GetObjectShell()->GetModel(), uno::UNO_QUERY );
1331 if ( !xCmisDoc.is( ) || !xCmisDoc->canCheckOut( ) )
1332 return;
1334 const uno::Sequence< document::CmisProperty> aCmisProperties = xCmisDoc->getCmisProperties( );
1336 if ( !(xCmisDoc->isVersionable( ) && aCmisProperties.hasElements( )) )
1337 return;
1339 // Loop over the CMIS Properties to find cmis:isVersionSeriesCheckedOut
1340 // and find if it is a Google Drive file.
1341 bool bIsGoogleFile = false;
1342 bool bCheckedOut = false;
1343 for ( const auto& rCmisProp : aCmisProperties )
1345 if ( rCmisProp.Id == "cmis:isVersionSeriesCheckedOut" ) {
1346 uno::Sequence< sal_Bool > bTmp;
1347 rCmisProp.Value >>= bTmp;
1348 bCheckedOut = bTmp[0];
1350 // if it is a Google Drive file, we don't need the checkout bar,
1351 // still need the checkout feature for the version dialog.
1352 if ( rCmisProp.Name == "title" )
1353 bIsGoogleFile = true;
1356 if ( bCheckedOut || bIsGoogleFile )
1357 return;
1359 // Get the Frame and show the InfoBar if not checked out
1360 SfxViewFrame* pViewFrame = m_pData->m_pViewShell->GetFrame();
1361 auto pInfoBar = pViewFrame->AppendInfoBar(u"checkout"_ustr, u""_ustr, SfxResId(STR_NONCHECKEDOUT_DOCUMENT),
1362 InfobarType::WARNING);
1363 if (pInfoBar)
1365 weld::Button &rBtn = pInfoBar->addButton();
1366 rBtn.set_label(SfxResId(STR_CHECKOUT));
1367 rBtn.connect_clicked(LINK(this, SfxBaseController, CheckOutHandler));
1371 IMPL_LINK_NOARG ( SfxBaseController, CheckOutHandler, weld::Button&, void )
1373 if ( m_pData->m_pViewShell )
1374 m_pData->m_pViewShell->GetObjectShell()->CheckOut( );
1378 Reference< frame::XTitle > SfxBaseController::impl_getTitleHelper ()
1380 SolarMutexGuard aGuard;
1382 if ( ! m_pData->m_xTitleHelper.is ())
1384 Reference< frame::XModel > xModel = getModel ();
1385 Reference< frame::XUntitledNumbers > xUntitledProvider(xModel , uno::UNO_QUERY );
1387 m_pData->m_xTitleHelper = new ::framework::TitleHelper(::comphelper::getProcessComponentContext(),
1388 Reference< frame::XController >(this), xUntitledProvider);
1391 return m_pData->m_xTitleHelper;
1395 // frame::XTitle
1396 OUString SAL_CALL SfxBaseController::getTitle()
1398 return impl_getTitleHelper()->getTitle ();
1402 // frame::XTitle
1403 void SAL_CALL SfxBaseController::setTitle(const OUString& sTitle)
1405 impl_getTitleHelper()->setTitle (sTitle);
1409 // frame::XTitleChangeBroadcaster
1410 void SAL_CALL SfxBaseController::addTitleChangeListener(const Reference< frame::XTitleChangeListener >& xListener)
1412 Reference< frame::XTitleChangeBroadcaster > xBroadcaster(impl_getTitleHelper(), uno::UNO_QUERY);
1413 if (xBroadcaster.is ())
1414 xBroadcaster->addTitleChangeListener (xListener);
1418 // frame::XTitleChangeBroadcaster
1419 void SAL_CALL SfxBaseController::removeTitleChangeListener(const Reference< frame::XTitleChangeListener >& xListener)
1421 Reference< frame::XTitleChangeBroadcaster > xBroadcaster(impl_getTitleHelper(), uno::UNO_QUERY);
1422 if (xBroadcaster.is ())
1423 xBroadcaster->removeTitleChangeListener (xListener);
1426 void SfxBaseController::initialize( const css::uno::Sequence< css::uno::Any >& /*aArguments*/ )
1430 void SAL_CALL SfxBaseController::appendInfobar(const OUString& sId, const OUString& sPrimaryMessage,
1431 const OUString& sSecondaryMessage,
1432 sal_Int32 aInfobarType,
1433 const Sequence<StringPair>& actionButtons,
1434 sal_Bool bShowCloseButton)
1436 SolarMutexGuard aGuard;
1438 if (aInfobarType < static_cast<sal_Int32>(InfobarType::INFO)
1439 || aInfobarType > static_cast<sal_Int32>(InfobarType::DANGER))
1440 throw lang::IllegalArgumentException("Undefined InfobarType: "
1441 + OUString::number(aInfobarType),
1442 getXWeak(), 0);
1443 SfxViewFrame* pViewFrame = m_pData->m_pViewShell->GetFrame();
1444 if (pViewFrame->HasInfoBarWithID(sId))
1445 throw lang::IllegalArgumentException("Infobar with ID '" + sId + "' already existing.",
1446 getXWeak(), 0);
1448 auto pInfoBar
1449 = pViewFrame->AppendInfoBar(sId, sPrimaryMessage, sSecondaryMessage,
1450 static_cast<InfobarType>(aInfobarType), bShowCloseButton);
1451 if (!pInfoBar)
1452 throw uno::RuntimeException(u"Could not create Infobar"_ustr);
1454 for (const StringPair& actionButton : actionButtons)
1456 if (actionButton.First.isEmpty() || actionButton.Second.isEmpty())
1457 continue;
1458 weld::Button& rBtn = pInfoBar->addButton(&actionButton.Second);
1459 rBtn.set_label(actionButton.First);
1463 void SAL_CALL SfxBaseController::updateInfobar(const OUString& sId, const OUString& sPrimaryMessage,
1464 const OUString& sSecondaryMessage,
1465 sal_Int32 aInfobarType)
1467 SolarMutexGuard aGuard;
1469 if (aInfobarType < static_cast<sal_Int32>(InfobarType::INFO)
1470 || aInfobarType > static_cast<sal_Int32>(InfobarType::DANGER))
1471 throw lang::IllegalArgumentException("Undefined InfobarType: "
1472 + OUString::number(aInfobarType),
1473 getXWeak(), 0);
1474 SfxViewFrame* pViewFrame = m_pData->m_pViewShell->GetFrame();
1475 if (!pViewFrame->HasInfoBarWithID(sId))
1476 throw css::container::NoSuchElementException("Infobar with ID '" + sId + "' not found.");
1478 pViewFrame->UpdateInfoBar(sId, sPrimaryMessage, sSecondaryMessage,
1479 static_cast<InfobarType>(aInfobarType));
1482 void SAL_CALL SfxBaseController::removeInfobar(const OUString& sId)
1484 SolarMutexGuard aGuard;
1486 SfxViewFrame* pViewFrame = m_pData->m_pViewShell->GetFrame();
1487 if (!pViewFrame->HasInfoBarWithID(sId))
1488 throw css::container::NoSuchElementException("Infobar with ID '" + sId + "' not found.");
1489 pViewFrame->RemoveInfoBar(sId);
1492 sal_Bool SAL_CALL SfxBaseController::hasInfobar(const OUString& sId)
1494 SolarMutexGuard aGuard;
1495 SfxViewFrame* pViewFrame = m_pData->m_pViewShell->GetFrame();
1496 return pViewFrame->HasInfoBarWithID(sId);
1499 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */