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 "backingwindow.hxx"
22 #include <com/sun/star/frame/XDispatchProvider.hpp>
23 #include <com/sun/star/beans/XPropertySet.hpp>
24 #include <com/sun/star/awt/KeyEvent.hpp>
25 #include <com/sun/star/frame/XLayoutManager.hpp>
26 #include <com/sun/star/lang/XServiceInfo.hpp>
27 #include <com/sun/star/lang/XInitialization.hpp>
28 #include <com/sun/star/awt/XWindow.hpp>
29 #include <com/sun/star/awt/XKeyListener.hpp>
30 #include <com/sun/star/uno/XComponentContext.hpp>
31 #include <com/sun/star/frame/XFrame.hpp>
32 #include <com/sun/star/frame/XDispatch.hpp>
33 #include <com/sun/star/lang/XEventListener.hpp>
34 #include <com/sun/star/lang/XComponent.hpp>
35 #include <com/sun/star/lang/XTypeProvider.hpp>
37 #include <cppuhelper/supportsservice.hxx>
38 #include <cppuhelper/queryinterface.hxx>
39 #include <cppuhelper/typeprovider.hxx>
40 #include <cppuhelper/weak.hxx>
41 #include <toolkit/helper/vclunohelper.hxx>
42 #include <vcl/wrkwin.hxx>
43 #include <vcl/svapp.hxx>
44 #include <vcl/syswin.hxx>
46 #include <sfx2/notebookbar/SfxNotebookBar.hxx>
51 implements the backing component.
53 This component is a special one, which doesn't provide a controller
54 nor a model. It supports the following features:
61 class BackingComp
: public css::lang::XTypeProvider
62 , public css::lang::XServiceInfo
63 , public css::lang::XInitialization
64 , public css::frame::XController
// => XComponent
65 , public css::awt::XKeyListener
// => XEventListener
66 , public css::frame::XDispatchProvider
67 , public css::frame::XDispatch
68 , public ::cppu::OWeakObject
71 /** reference to the component window. */
72 css::uno::Reference
< css::awt::XWindow
> m_xWindow
;
74 /** the owner frame of this component. */
75 css::uno::Reference
< css::frame::XFrame
> m_xFrame
;
77 Size m_aInitialWindowMinSize
;
81 explicit BackingComp();
84 virtual css::uno::Any SAL_CALL
queryInterface( const css::uno::Type
& aType
) override
;
85 virtual void SAL_CALL
acquire ( ) noexcept override
;
86 virtual void SAL_CALL
release ( ) noexcept override
;
89 virtual css::uno::Sequence
< css::uno::Type
> SAL_CALL
getTypes () override
;
90 virtual css::uno::Sequence
< sal_Int8
> SAL_CALL
getImplementationId() override
;
93 virtual OUString SAL_CALL
getImplementationName ( ) override
;
94 virtual sal_Bool SAL_CALL
supportsService ( const OUString
& sServiceName
) override
;
95 virtual css::uno::Sequence
< OUString
> SAL_CALL
getSupportedServiceNames( ) override
;
98 virtual void SAL_CALL
initialize( const css::uno::Sequence
< css::uno::Any
>& lArgs
) override
;
101 virtual void SAL_CALL
attachFrame( const css::uno::Reference
< css::frame::XFrame
>& xFrame
) override
;
102 virtual sal_Bool SAL_CALL
attachModel( const css::uno::Reference
< css::frame::XModel
>& xModel
) override
;
103 virtual sal_Bool SAL_CALL
suspend( sal_Bool bSuspend
) override
;
104 virtual css::uno::Any SAL_CALL
getViewData() override
;
105 virtual void SAL_CALL
restoreViewData( const css::uno::Any
& aData
) override
;
106 virtual css::uno::Reference
< css::frame::XModel
> SAL_CALL
getModel() override
;
107 virtual css::uno::Reference
< css::frame::XFrame
> SAL_CALL
getFrame() override
;
110 virtual void SAL_CALL
keyPressed ( const css::awt::KeyEvent
& aEvent
) override
;
111 virtual void SAL_CALL
keyReleased( const css::awt::KeyEvent
& aEvent
) override
;
114 virtual void SAL_CALL
disposing( const css::lang::EventObject
& aEvent
) override
;
117 virtual void SAL_CALL
dispose ( ) override
;
118 virtual void SAL_CALL
addEventListener ( const css::uno::Reference
< css::lang::XEventListener
>& xListener
) override
;
119 virtual void SAL_CALL
removeEventListener( const css::uno::Reference
< css::lang::XEventListener
>& xListener
) override
;
122 virtual css::uno::Reference
< css::frame::XDispatch
> SAL_CALL
queryDispatch( const css::util::URL
& aURL
, const OUString
& sTargetFrameName
, sal_Int32 nSearchFlags
) override
;
123 virtual css::uno::Sequence
< css::uno::Reference
< css::frame::XDispatch
> > SAL_CALL
queryDispatches( const css::uno::Sequence
< css::frame::DispatchDescriptor
>& lDescriptions
) override
;
126 virtual void SAL_CALL
dispatch( const css::util::URL
& aURL
, const css::uno::Sequence
< css::beans::PropertyValue
>& lArguments
) override
;
127 virtual void SAL_CALL
addStatusListener( const css::uno::Reference
< css::frame::XStatusListener
>& xListener
, const css::util::URL
& aURL
) override
;
128 virtual void SAL_CALL
removeStatusListener( const css::uno::Reference
< css::frame::XStatusListener
>& xListener
, const css::util::URL
& aURL
) override
;
131 BackingComp::BackingComp()
135 /** return information about supported interfaces.
137 Some interfaces are supported by his class directly, but some other ones are
138 used by aggregation. An instance of this class must provide some window interfaces.
139 But it must represent a VCL window behind such interfaces too! So we use an internal
140 saved window member to ask it for its interfaces and return it. But we must be aware then,
141 that it can be destroyed from outside too ...
144 describe the required interface type
146 @return An Any holding the instance, which provides the queried interface.
147 Note: There exist two possible results ... this instance itself and her window member!
150 css::uno::Any SAL_CALL
BackingComp::queryInterface( /*IN*/ const css::uno::Type
& aType
)
152 // first look for own supported interfaces
153 css::uno::Any aResult
= ::cppu::queryInterface(
155 static_cast< css::lang::XTypeProvider
* >(this),
156 static_cast< css::lang::XServiceInfo
* >(this),
157 static_cast< css::lang::XInitialization
* >(this),
158 static_cast< css::frame::XController
* >(this),
159 static_cast< css::lang::XComponent
* >(this),
160 static_cast< css::lang::XEventListener
* >(this),
161 static_cast< css::awt::XKeyListener
* >(static_cast< css::lang::XEventListener
* >(this)),
162 static_cast< css::frame::XDispatchProvider
* >(this),
163 static_cast< css::frame::XDispatch
* >(this) );
165 // then look for supported window interfaces
166 // Note: They exist only, if this instance was initialized
167 // with a valid window reference. It's aggregation on demand ...
168 if (!aResult
.hasValue())
171 SolarMutexGuard aGuard
;
173 aResult
= m_xWindow
->queryInterface(aType
);
177 // look for XWeak and XInterface
178 if (!aResult
.hasValue())
179 aResult
= OWeakObject::queryInterface(aType
);
185 /** increase ref count of this instance.
188 void SAL_CALL
BackingComp::acquire()
191 OWeakObject::acquire();
195 /** decrease ref count of this instance.
198 void SAL_CALL
BackingComp::release()
201 OWeakObject::release();
205 /** return collection about all supported interfaces.
207 Optimize this method !
208 We initialize a static variable only one time.
209 And we don't must use a mutex at every call!
210 For the first call; pTypeCollection is NULL -
211 for the second call pTypeCollection is different from NULL!
213 @return A list of all supported interface types.
216 css::uno::Sequence
< css::uno::Type
> SAL_CALL
BackingComp::getTypes()
218 static cppu::OTypeCollection aTypeCollection
= [this]() {
219 SolarMutexGuard aGuard
;
220 css::uno::Reference
<css::lang::XTypeProvider
> xProvider(m_xWindow
, css::uno::UNO_QUERY
);
222 css::uno::Sequence
<css::uno::Type
> lWindowTypes
;
224 lWindowTypes
= xProvider
->getTypes();
226 return cppu::OTypeCollection(
227 cppu::UnoType
<css::lang::XInitialization
>::get(),
228 cppu::UnoType
<css::lang::XTypeProvider
>::get(),
229 cppu::UnoType
<css::lang::XServiceInfo
>::get(),
230 cppu::UnoType
<css::frame::XController
>::get(),
231 cppu::UnoType
<css::lang::XComponent
>::get(),
232 cppu::UnoType
<css::frame::XDispatchProvider
>::get(),
233 cppu::UnoType
<css::frame::XDispatch
>::get(), lWindowTypes
);
236 return aTypeCollection
.getTypes();
240 /** create one unique Id for all instances of this class.
243 We initialize a static variable only one time. And we don't must use a mutex at every call!
244 For the first call; pID is NULL - for the second call pID is different from NULL!
246 @return A byte array, which represent the unique id.
249 css::uno::Sequence
< sal_Int8
> SAL_CALL
BackingComp::getImplementationId()
251 return css::uno::Sequence
<sal_Int8
>();
254 OUString SAL_CALL
BackingComp::getImplementationName()
256 return u
"com.sun.star.comp.sfx2.BackingComp"_ustr
;
259 sal_Bool SAL_CALL
BackingComp::supportsService( /*IN*/ const OUString
& sServiceName
)
261 return cppu::supportsService(this, sServiceName
);
264 css::uno::Sequence
< OUString
> SAL_CALL
BackingComp::getSupportedServiceNames()
266 return { u
"com.sun.star.frame.StartModule"_ustr
, u
"com.sun.star.frame.ProtocolHandler"_ustr
};
271 attach this component to a target frame.
273 We have to use the container window of this frame as parent window of our own component window.
274 But it's not allowed to work with it really. May another component used it too.
275 Currently we need it only to create our child component window and support it's
276 interfaces inside our queryInterface() method. The user of us must have e.g. the
277 XWindow interface of it to be able to call setComponent(xWindow,xController) at the
280 May he will do the following things:
283 XController xBackingComp = (XController)UnoRuntime.queryInterface(
285 xSMGR.createInstance(SERVICENAME_STARTMODULE));
287 // at this time XWindow isn't present at this instance!
288 XWindow xBackingComp = (XWindow)UnoRuntime.queryInterface(
292 // attach controller to the frame
293 // We will use its container window, to create
294 // the component window. From now we offer the window interfaces!
295 xBackingComp.attachFrame(xFrame);
297 XWindow xBackingComp = (XWindow)UnoRuntime.queryInterface(
301 // Our user can set us at the frame as new component
302 xFrame.setComponent(xBackingWin, xBackingComp);
304 // But that had no effect to our view state.
305 // We must be started to create our UI elements like e.g. menu, title, background ...
306 XInitialization xBackingInit = (XInitialization)UnoRuntime.queryInterface(
307 XInitialization.class,
310 xBackingInit.initialize(lArgs);
314 reference to our new target frame
316 @throw css::uno::RuntimeException
317 if the given frame reference is wrong or component window couldn't be created
319 We throw it too, if we already attached to a frame. Because we don't support
320 reparenting of our component window on demand!
323 void SAL_CALL
BackingComp::attachFrame( /*IN*/ const css::uno::Reference
< css::frame::XFrame
>& xFrame
)
326 SolarMutexGuard aGuard
;
328 // check some required states
330 throw css::uno::RuntimeException(
331 u
"already attached"_ustr
,
335 throw css::uno::RuntimeException(
336 u
"invalid frame reference"_ustr
,
342 // safe the frame reference
345 // initialize the component and its parent window
346 css::uno::Reference
< css::awt::XWindow
> xParentWindow
= xFrame
->getContainerWindow();
347 VclPtr
< WorkWindow
> pParent
= static_cast<WorkWindow
*>(VCLUnoHelper::GetWindow(xParentWindow
));
348 VclPtr
< vcl::Window
> pWindow
= VCLUnoHelper::GetWindow(m_xWindow
);
350 // disable full screen mode of the frame!
351 if (pParent
&& pParent
->IsFullScreenMode())
353 pParent
->ShowFullScreenMode(false);
354 pParent
->SetMenuBarMode(MenuBarMode::Normal
);
357 // create the menu bar for the backing component
358 css::uno::Reference
< css::beans::XPropertySet
> xPropSet(m_xFrame
, css::uno::UNO_QUERY_THROW
);
359 css::uno::Reference
< css::frame::XLayoutManager
> xLayoutManager
;
360 xPropSet
->getPropertyValue(u
"LayoutManager"_ustr
) >>= xLayoutManager
;
361 if (xLayoutManager
.is())
363 xLayoutManager
->lock();
364 xLayoutManager
->createElement(u
"private:resource/menubar/menubar"_ustr
);
365 xLayoutManager
->unlock();
370 // set help ID for our canvas
371 pWindow
->SetHelpId(u
"FWK_HID_BACKINGWINDOW"_ustr
);
374 // inform BackingWindow about frame
375 BackingWindow
* pBack
= dynamic_cast<BackingWindow
*>(pWindow
.get());
377 pBack
->setOwningFrame( m_xFrame
);
379 // Set a minimum size for Start Center
380 if( !pParent
|| !pBack
)
383 tools::Long nMenuHeight
= 0;
384 vcl::Window
* pMenu
= pParent
->GetWindow(GetWindowType::Next
);
386 nMenuHeight
= pMenu
->GetSizePixel().Height();
388 m_aInitialWindowMinSize
= pParent
->GetMinOutputSizePixel();
389 if (!m_aInitialWindowMinSize
.Width())
390 m_aInitialWindowMinSize
.AdjustWidth(1);
391 if (!m_aInitialWindowMinSize
.Height())
392 m_aInitialWindowMinSize
.AdjustHeight(1);
394 pParent
->SetMinOutputSizePixel(
396 pBack
->get_width_request(),
397 pBack
->get_height_request() + nMenuHeight
));
405 This component does not know any model. It will be represented by a window and
408 return <FALSE/> every time.
411 sal_Bool SAL_CALL
BackingComp::attachModel( /*IN*/ const css::uno::Reference
< css::frame::XModel
>& )
419 This component does not know any model. It will be represented by a window and
422 return An empty reference every time.
425 css::uno::Reference
< css::frame::XModel
> SAL_CALL
BackingComp::getModel()
427 return css::uno::Reference
< css::frame::XModel
>();
433 return An empty value.
436 css::uno::Any SAL_CALL
BackingComp::getViewData()
438 return css::uno::Any();
448 void SAL_CALL
BackingComp::restoreViewData( /*IN*/ const css::uno::Any
& )
453 /** returns the attached frame for this component.
457 @return The internally saved frame reference.
458 Can be null, if attachFrame() was not called before.
461 css::uno::Reference
< css::frame::XFrame
> SAL_CALL
BackingComp::getFrame()
464 SolarMutexGuard aGuard
;
470 /** ask controller for its current working state.
472 If someone wishes to close this component, it must suspend the controller before.
473 That will be a chance for it to disagree with that AND show any UI for a possible
477 If it's set to sal_True this controller should be suspended.
478 sal_False will resuspend it.
480 @return sal_True if the request could be finished successfully; sal_False otherwise.
483 sal_Bool SAL_CALL
BackingComp::suspend( /*IN*/ sal_Bool
)
485 /* FIXME ... implemented by using default :-( */
490 /** callback from our window member.
492 Our internal saved window wish to die. It will be disposed from outside (may be the frame)
493 and inform us. We must release its reference only here. Of course we check the given reference
494 here and reject callback from unknown sources.
496 Note: deregistration as listener isn't necessary here. The broadcaster do it automatically.
499 describe the broadcaster of this callback
501 @throw css::uno::RuntimeException
502 if the broadcaster doesn't represent the expected window reference.
505 void SAL_CALL
BackingComp::disposing( /*IN*/ const css::lang::EventObject
& aEvent
)
507 // Attention: don't free m_pAccExec here! see comments inside dtor and
508 // keyPressed() for further details.
511 SolarMutexGuard aGuard
;
513 if (!aEvent
.Source
.is() || aEvent
.Source
!=m_xWindow
|| !m_xWindow
.is())
514 throw css::uno::RuntimeException(
515 u
"unexpected source or called twice"_ustr
,
524 /** kill this instance.
526 It can be called from our owner frame only. But there is no possibility to check the caller.
527 We have to release all our internal used resources and die. From this point we can throw
528 DisposedExceptions for every further interface request... but current implementation doesn't do so...
532 void SAL_CALL
BackingComp::dispose()
535 SolarMutexGuard aGuard
;
539 css::uno::Reference
< css::awt::XWindow
> xParentWindow
= m_xFrame
->getContainerWindow();
540 VclPtr
< WorkWindow
> pParent
= static_cast<WorkWindow
*>(VCLUnoHelper::GetWindow(xParentWindow
));
543 pParent
->SetMinOutputSizePixel(m_aInitialWindowMinSize
);
545 sfx2::SfxNotebookBar::CloseMethod(static_cast<SystemWindow
*>(pParent
));
549 // stop listening at the window
552 m_xWindow
->removeEventListener(this);
553 m_xWindow
->removeKeyListener(this);
557 // forget all other used references
569 @throw css::uno::RuntimeException
570 because the listener expect to be holded alive by this container.
571 We must inform it about this unsupported feature.
574 void SAL_CALL
BackingComp::addEventListener( /*IN*/ const css::uno::Reference
< css::lang::XEventListener
>& )
576 throw css::uno::RuntimeException(
577 u
"not supported"_ustr
,
584 Because registration is not supported too, we must do nothing here. Nobody can call this method really.
590 void SAL_CALL
BackingComp::removeEventListener( /*IN*/ const css::uno::Reference
< css::lang::XEventListener
>& )
596 force initialization for this component.
598 Inside attachFrame() we created our component window. But it was not allowed there, to
599 initialize it. E.g. the menu must be set at the container window of the frame, which
600 is our parent window. But may at that time another component used it.
601 That's why our creator has to inform us, when it's time to initialize us really.
602 Currently only calling of this method must be done. But further implementations
603 can use special in parameter to configure this initialization...
608 @throw css::uno::RuntimeException
609 if some resources are missing
610 Means if may be attachedFrame() wasn't called before.
613 void SAL_CALL
BackingComp::initialize( /*IN*/ const css::uno::Sequence
< css::uno::Any
>& lArgs
)
616 SolarMutexGuard aGuard
;
619 throw css::uno::Exception(
620 u
"already initialized"_ustr
,
623 css::uno::Reference
< css::awt::XWindow
> xParentWindow
;
625 (lArgs
.getLength()!=1 ) ||
626 (!(lArgs
[0] >>= xParentWindow
)) ||
627 (!xParentWindow
.is() )
630 throw css::uno::Exception(
631 u
"wrong or corrupt argument list"_ustr
,
635 // create the component window
636 VclPtr
<vcl::Window
> pParent
= VCLUnoHelper::GetWindow(xParentWindow
);
637 VclPtr
<vcl::Window
> pWindow
= VclPtr
<BackingWindow
>::Create(pParent
);
638 m_xWindow
= VCLUnoHelper::GetInterface(pWindow
);
641 throw css::uno::RuntimeException(
642 u
"couldn't create component window"_ustr
,
645 // start listening for window disposing
646 // It's set at our owner frame as component window later too. So it will may be disposed there ...
647 m_xWindow
->addEventListener(static_cast< css::lang::XEventListener
* >(this));
649 m_xWindow
->setVisible(true);
655 void SAL_CALL
BackingComp::keyPressed( /*IN*/ const css::awt::KeyEvent
& )
660 void SAL_CALL
BackingComp::keyReleased( /*IN*/ const css::awt::KeyEvent
& )
663 Please use keyPressed() instead of this method. Otherwise it would be possible, that
664 - a key input may be first switch to the backing mode
665 - and this component register itself as key listener too
666 - and it's first event will be a keyReleased() for the already well known event, which switched to the backing mode!
667 So it will be handled twice! document => backing mode => exit app...
672 css::uno::Reference
< css::frame::XDispatch
> SAL_CALL
BackingComp::queryDispatch( const css::util::URL
& aURL
, const OUString
& /*sTargetFrameName*/, sal_Int32
/*nSearchFlags*/ )
674 css::uno::Reference
< css::frame::XDispatch
> xDispatch
;
675 if ( aURL
.Protocol
== "vnd.org.libreoffice.recentdocs:" )
681 css::uno::Sequence
< css::uno::Reference
< css::frame::XDispatch
> > SAL_CALL
BackingComp::queryDispatches( const css::uno::Sequence
< css::frame::DispatchDescriptor
>& seqDescripts
)
683 sal_Int32 nCount
= seqDescripts
.getLength();
684 css::uno::Sequence
< css::uno::Reference
< XDispatch
> > lDispatcher( nCount
);
686 std::transform(seqDescripts
.begin(), seqDescripts
.end(), lDispatcher
.getArray(),
687 [this](const css::frame::DispatchDescriptor
& rDesc
) -> css::uno::Reference
<XDispatch
> {
688 return queryDispatch(rDesc
.FeatureURL
, rDesc
.FrameName
, rDesc
.SearchFlags
); });
694 void SAL_CALL
BackingComp::dispatch( const css::util::URL
& aURL
, const css::uno::Sequence
< css::beans::PropertyValue
>& /*lArgs*/ )
696 // vnd.org.libreoffice.recentdocs:ClearRecentFileList - clear recent files
697 if ( aURL
.Path
!= "ClearRecentFileList" )
700 VclPtr
<vcl::Window
> pWindow
= VCLUnoHelper::GetWindow(m_xWindow
);
701 BackingWindow
* pBack
= dynamic_cast<BackingWindow
*>(pWindow
.get());
705 pBack
->clearRecentFileList();
707 // Recalculate minimum width
708 css::uno::Reference
< css::awt::XWindow
> xParentWindow
= m_xFrame
->getContainerWindow();
709 VclPtr
< WorkWindow
> pParent
= static_cast<WorkWindow
*>(VCLUnoHelper::GetWindow(xParentWindow
));
712 pParent
->SetMinOutputSizePixel( Size(
713 pBack
->get_width_request(),
714 pParent
->GetMinOutputSizePixel().Height()) );
718 void SAL_CALL
BackingComp::addStatusListener( const css::uno::Reference
< css::frame::XStatusListener
>& /*xControl*/, const css::util::URL
& /*aURL*/ )
722 void SAL_CALL
BackingComp::removeStatusListener( const css::uno::Reference
< css::frame::XStatusListener
>& /*xControl*/, const css::util::URL
& /*aURL*/ )
728 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
729 com_sun_star_comp_sfx2_BackingComp_get_implementation(
730 css::uno::XComponentContext
*,
731 css::uno::Sequence
<css::uno::Any
> const &)
733 return cppu::acquire(new BackingComp
);
736 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */