1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 
21 #ifdef __sun
22 #include <ctime>
23 #endif
24 
25 #include <string>
26 #include <com/sun/star/uno/Reference.h>
27 #include <com/sun/star/frame/XFrame.hpp>
28 #include <com/sun/star/awt/XPopupMenu.hpp>
29 #include <com/sun/star/awt/XWindow.hpp>
30 #include <com/sun/star/awt/XWindowPeer.hpp>
31 #include <com/sun/star/util/URL.hpp>
32 #include <com/sun/star/util/URLTransformer.hpp>
33 #include <com/sun/star/util/XURLTransformer.hpp>
34 #include <com/sun/star/frame/XController.hpp>
35 #include <com/sun/star/lang/XUnoTunnel.hpp>
36 #include <com/sun/star/document/MacroExecMode.hpp>
37 #include <com/sun/star/document/UpdateDocMode.hpp>
38 #include <com/sun/star/beans/PropertyValue.hpp>
39 #include <com/sun/star/beans/XPropertySet.hpp>
40 #include <com/sun/star/frame/status/ItemStatus.hpp>
41 #include <com/sun/star/ui/XUIElementFactory.hpp>
42 #include <com/sun/star/container/XNameAccess.hpp>
43 #include <com/sun/star/ui/XUIFunctionListener.hpp>
44 #include <com/sun/star/ui/theUIElementFactoryManager.hpp>
45 #include <com/sun/star/frame/status/Visibility.hpp>
46 #include <svl/eitem.hxx>
47 #include <svl/stritem.hxx>
48 #include <svl/intitem.hxx>
49 #include <svl/imageitm.hxx>
50 #include <svl/visitem.hxx>
51 #include <svl/urlbmk.hxx>
52 #include <vcl/svapp.hxx>
53 #include <vcl/toolbox.hxx>
54 #include <unotools/moduleoptions.hxx>
55 
56 #include <svtools/imagemgr.hxx>
57 #include <svtools/framestatuslistener.hxx>
58 #include <comphelper/processfactory.hxx>
59 #include <framework/addonmenu.hxx>
60 #include <framework/addonsoptions.hxx>
61 #include <framework/menuconfiguration.hxx>
62 #include <framework/sfxhelperfunctions.hxx>
63 #include <vcl/taskpanelist.hxx>
64 #include <vcl/event.hxx>
65 #include <toolkit/helper/vclunohelper.hxx>
66 #include <tools/globname.hxx>
67 #include <svtools/menuoptions.hxx>
68 #include <svtools/miscopt.hxx>
69 
70 #include <sfx2/tbxctrl.hxx>
71 #include <sfx2/dispatch.hxx>
72 #include <sfx2/msg.hxx>
73 #include <sfx2/msgpool.hxx>
74 #include <statcach.hxx>
75 #include <sfx2/viewfrm.hxx>
76 #include <sfxtypes.hxx>
77 #include <sfx2/module.hxx>
78 #include <sfx2/docfile.hxx>
79 #include <sfx2/docfac.hxx>
80 #include <sfx2/frmhtmlw.hxx>
81 #include <sfx2/app.hxx>
82 #include <sfx2/unoctitm.hxx>
83 #include <workwin.hxx>
84 #include <ctrlfactoryimpl.hxx>
85 
86 using namespace ::com::sun::star;
87 using namespace ::com::sun::star::beans;
88 using namespace ::com::sun::star::frame;
89 using namespace ::com::sun::star::frame::status;
90 using namespace ::com::sun::star::lang;
91 using namespace ::com::sun::star::uno;
92 using namespace ::com::sun::star::util;
93 using namespace ::com::sun::star::container;
94 using namespace ::com::sun::star::ui;
95 
96 
97 SFX_IMPL_TOOLBOX_CONTROL_ARG(SfxToolBoxControl, SfxStringItem, true);
98 
GetTopMostParentSystemWindow(vcl::Window * pWindow)99 static vcl::Window* GetTopMostParentSystemWindow( vcl::Window* pWindow )
100 {
101     OSL_ASSERT( pWindow );
102     if ( pWindow )
103     {
104         // ->manually search topmost system window
105         // required because their might be another system window between this and the top window
106         pWindow = pWindow->GetParent();
107         SystemWindow* pTopMostSysWin = nullptr;
108         while ( pWindow )
109         {
110             if ( pWindow->IsSystemWindow() )
111                 pTopMostSysWin = static_cast<SystemWindow*>(pWindow);
112             pWindow = pWindow->GetParent();
113         }
114         pWindow = pTopMostSysWin;
115         OSL_ASSERT( pWindow );
116         return pWindow;
117     }
118 
119     return nullptr;
120 }
121 
SfxToolBoxControllerFactory(const Reference<XFrame> & rFrame,ToolBox * pToolbox,unsigned short nID,const OUString & aCommandURL)122 svt::ToolboxController* SfxToolBoxControllerFactory( const Reference< XFrame >& rFrame, ToolBox* pToolbox, unsigned short nID, const OUString& aCommandURL )
123 {
124     SolarMutexGuard aGuard;
125 
126     URL aTargetURL;
127     aTargetURL.Complete = aCommandURL;
128     Reference < XURLTransformer > xTrans( URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
129     xTrans->parseStrict( aTargetURL );
130     if ( !aTargetURL.Arguments.isEmpty() )
131         return nullptr;
132 
133     SfxObjectShell* pObjShell = nullptr;
134     Reference < XController > xController;
135     Reference < XModel > xModel;
136     if ( rFrame.is() )
137     {
138         xController = rFrame->getController();
139         if ( xController.is() )
140             xModel = xController->getModel();
141     }
142 
143     if ( xModel.is() )
144     {
145         // Get tunnel from model to retrieve the SfxObjectShell pointer from it
146         css::uno::Reference < css::lang::XUnoTunnel > xObj( xModel, UNO_QUERY );
147         if ( xObj.is() )
148         {
149             css::uno::Sequence < sal_Int8 > aSeq = SvGlobalName( SFX_GLOBAL_CLASSID ).GetByteSequence();
150             sal_Int64 nHandle = xObj->getSomething( aSeq );
151             if ( nHandle )
152                 pObjShell = reinterpret_cast< SfxObjectShell* >( sal::static_int_cast< sal_IntPtr >( nHandle ));
153         }
154     }
155 
156     SfxModule*     pModule   = pObjShell ? pObjShell->GetModule() : nullptr;
157     SfxSlotPool*   pSlotPool = nullptr;
158 
159     if ( pModule )
160         pSlotPool = pModule->GetSlotPool();
161     else
162         pSlotPool = &(SfxSlotPool::GetSlotPool());
163 
164     const SfxSlot* pSlot = pSlotPool->GetUnoSlot( aTargetURL.Path );
165     if ( pSlot )
166     {
167         sal_uInt16 nSlotId = pSlot->GetSlotId();
168         if ( nSlotId > 0 )
169             return SfxToolBoxControl::CreateControl( nSlotId, nID, pToolbox, pModule );
170     }
171 
172     return nullptr;
173 }
174 
175 struct SfxToolBoxControl_Impl
176 {
177     VclPtr<ToolBox>         pBox;
178     bool                    bShowString;
179     sal_uInt16              nTbxId;
180     sal_uInt16              nSlotId;
181     VclPtr<SfxPopupWindow>  mpFloatingWindow;
182     VclPtr<SfxPopupWindow>  mpPopupWindow;
183     DECL_LINK( WindowEventListener, VclWindowEvent&, void );
184 };
185 
IMPL_LINK(SfxToolBoxControl_Impl,WindowEventListener,VclWindowEvent &,rEvent,void)186 IMPL_LINK( SfxToolBoxControl_Impl, WindowEventListener, VclWindowEvent&, rEvent, void )
187 {
188     if ( ( rEvent.GetId() == VclEventId::WindowMove ) ||
189          ( rEvent.GetId() == VclEventId::WindowActivate ))
190     {
191         vcl::Window* pWindow( rEvent.GetWindow() );
192         if (( pWindow == mpFloatingWindow ) &&
193             ( mpPopupWindow != nullptr ))
194         {
195             mpPopupWindow.disposeAndClear();
196         }
197     }
198 }
199 
200 
SfxToolBoxControl(sal_uInt16 nSlotID,sal_uInt16 nID,ToolBox & rBox,bool bShowStringItems)201 SfxToolBoxControl::SfxToolBoxControl(
202     sal_uInt16      nSlotID,
203     sal_uInt16      nID,
204     ToolBox&        rBox,
205     bool            bShowStringItems     )
206     : pImpl( new SfxToolBoxControl_Impl )
207 {
208     pImpl->pBox = &rBox;
209     pImpl->bShowString = bShowStringItems;
210     pImpl->nTbxId = nID;
211     pImpl->nSlotId = nSlotID;
212     pImpl->mpFloatingWindow = nullptr;
213     pImpl->mpPopupWindow = nullptr;
214 }
215 
216 
~SfxToolBoxControl()217 SfxToolBoxControl::~SfxToolBoxControl()
218 {
219 }
220 
221 
GetToolBox() const222 ToolBox& SfxToolBoxControl::GetToolBox() const
223 {
224     return *pImpl->pBox;
225 }
GetId() const226 unsigned short SfxToolBoxControl::GetId() const
227 {
228     return pImpl->nTbxId;
229 }
GetSlotId() const230 unsigned short SfxToolBoxControl::GetSlotId() const
231 {
232     return pImpl->nSlotId;
233 }
234 
235 
dispose()236 void SAL_CALL SfxToolBoxControl::dispose()
237 {
238     if ( m_bDisposed )
239         return;
240 
241     svt::ToolboxController::dispose();
242 
243     // Remove and destroy our item window at our toolbox
244     SolarMutexGuard aGuard;
245     VclPtr< vcl::Window > pWindow = pImpl->pBox->GetItemWindow( pImpl->nTbxId );
246     pImpl->pBox->SetItemWindow( pImpl->nTbxId, nullptr );
247     pWindow.disposeAndClear();
248 
249     // Delete my popup windows
250     pImpl->mpFloatingWindow.disposeAndClear();
251     pImpl->mpPopupWindow.disposeAndClear();
252 }
253 
254 
RegisterToolBoxControl(SfxModule * pMod,const SfxTbxCtrlFactory & rFact)255 void SfxToolBoxControl::RegisterToolBoxControl( SfxModule* pMod, const SfxTbxCtrlFactory& rFact)
256 {
257     SfxGetpApp()->RegisterToolBoxControl_Impl( pMod, rFact );
258 }
259 
CreateControl(sal_uInt16 nSlotId,sal_uInt16 nTbxId,ToolBox * pBox,SfxModule const * pMod)260 SfxToolBoxControl* SfxToolBoxControl::CreateControl( sal_uInt16 nSlotId, sal_uInt16 nTbxId, ToolBox *pBox, SfxModule const * pMod  )
261 {
262     SolarMutexGuard aGuard;
263 
264     SfxApplication *pApp = SfxGetpApp();
265 
266     SfxSlotPool *pSlotPool;
267     if ( pMod )
268         pSlotPool = pMod->GetSlotPool();
269     else
270         pSlotPool = &SfxSlotPool::GetSlotPool();
271     const std::type_info* aSlotType = pSlotPool->GetSlotType( nSlotId );
272     if ( aSlotType )
273     {
274         SfxToolBoxControl *pCtrl;
275         if ( pMod )
276         {
277             SfxTbxCtrlFactArr_Impl *pFactories = pMod->GetTbxCtrlFactories_Impl();
278             if ( pFactories )
279             {
280                 SfxTbxCtrlFactArr_Impl &rFactories = *pFactories;
281                 sal_uInt16 nFactory;
282                 const sal_uInt16 nCount = rFactories.size();
283 
284                 // search for a factory with the given slot id
285                 for( nFactory = 0; nFactory < nCount; ++nFactory )
286                     if( (rFactories[nFactory].nTypeId == *aSlotType) && (rFactories[nFactory].nSlotId == nSlotId) )
287                         break;
288 
289                 if( nFactory == nCount )
290                 {
291                     // if no factory exists for the given slot id, see if we
292                     // have a generic factory with the correct slot type and slot id == 0
293                     for ( nFactory = 0; nFactory < nCount; ++nFactory )
294                         if( (rFactories[nFactory].nTypeId == *aSlotType) && (rFactories[nFactory].nSlotId == 0) )
295                             break;
296                 }
297 
298                 if( nFactory < nCount )
299                 {
300                     pCtrl = rFactories[nFactory].pCtor( nSlotId, nTbxId, *pBox );
301                     return pCtrl;
302                 }
303             }
304         }
305 
306         SfxTbxCtrlFactArr_Impl &rFactories = pApp->GetTbxCtrlFactories_Impl();
307         sal_uInt16 nFactory;
308         const sal_uInt16 nCount = rFactories.size();
309 
310         for( nFactory = 0; nFactory < nCount; ++nFactory )
311             if( (rFactories[nFactory].nTypeId == *aSlotType) && (rFactories[nFactory].nSlotId == nSlotId) )
312                 break;
313 
314         if( nFactory == nCount )
315         {
316             // if no factory exists for the given slot id, see if we
317             // have a generic factory with the correct slot type and slot id == 0
318             for( nFactory = 0; nFactory < nCount; ++nFactory )
319                 if( (rFactories[nFactory].nTypeId == *aSlotType) && (rFactories[nFactory].nSlotId == 0) )
320                     break;
321         }
322 
323         if( nFactory < nCount )
324         {
325             pCtrl = rFactories[nFactory].pCtor( nSlotId, nTbxId, *pBox );
326             return pCtrl;
327         }
328     }
329 
330     return nullptr;
331 }
332 
GetItemState(const SfxPoolItem * pState)333 SfxItemState SfxToolBoxControl::GetItemState(
334     const SfxPoolItem* pState )
335 /*  [Description]
336 
337     Static method for determining the status of the SfxPoolItem-pointer,
338     used in the method <SfxControllerItem::StateChanged(const SfxPoolItem*)>.
339 
340     [Return value]
341 
342     SfxItemState        SfxItemState::UNKNOWN
343                         Enabled, however no further status information is available.
344                         Typical for <Slot>s, which are temporarily disabled a
345                         anyway but other than that do not change their appearance.
346 
347                         SfxItemState::DISABLED
348                         Disabled, no further status information is available.
349                         All other displayed values should be reset to the default
350                         if possible.
351 
352                         SfxItemState::DONTCARE
353                         Enabled but there were only ambiguous values available
354                         (i.e. none that could be queried).
355 
356                         SfxItemState::DEFAULT
357                         Enabled and with available values which can be queried
358                         through'pState'. The type is thus by the Slot clearly
359                         defined in the entire Program.
360 */
361 
362 {
363     return !pState
364                 ? SfxItemState::DISABLED
365                 : IsInvalidItem(pState)
366                     ? SfxItemState::DONTCARE
367                     : pState->IsVoidItem() && !pState->Which()
368                         ? SfxItemState::UNKNOWN
369                         : SfxItemState::DEFAULT;
370 }
371 
Dispatch(const Reference<XDispatchProvider> & rProvider,const OUString & rCommand,Sequence<::PropertyValue> const & aArgs)372 void SfxToolBoxControl::Dispatch(
373     const Reference< XDispatchProvider >& rProvider,
374     const OUString& rCommand,
375     Sequence< ::PropertyValue > const & aArgs )
376 {
377     if ( rProvider.is() )
378     {
379         css::util::URL aTargetURL;
380         aTargetURL.Complete = rCommand;
381         Reference < XURLTransformer > xTrans( URLTransformer::create( ::comphelper::getProcessComponentContext() ) );
382         xTrans->parseStrict( aTargetURL );
383 
384         Reference < XDispatch > xDispatch = rProvider->queryDispatch( aTargetURL, OUString(), 0 );
385         if ( xDispatch.is() )
386             xDispatch->dispatch( aTargetURL, aArgs );
387     }
388 }
389 
Dispatch(const OUString & aCommand,css::uno::Sequence<css::beans::PropertyValue> const & aArgs)390 void SfxToolBoxControl::Dispatch( const OUString& aCommand, css::uno::Sequence< css::beans::PropertyValue > const & aArgs )
391 {
392     Reference < XController > xController;
393 
394     SolarMutexGuard aGuard;
395     if ( getFrameInterface().is() )
396         xController = getFrameInterface()->getController();
397 
398     Reference < XDispatchProvider > xProvider( xController, UNO_QUERY );
399     if ( xProvider.is() )
400     {
401         css::util::URL aTargetURL;
402         aTargetURL.Complete = aCommand;
403         getURLTransformer()->parseStrict( aTargetURL );
404 
405         Reference < XDispatch > xDispatch = xProvider->queryDispatch( aTargetURL, OUString(), 0 );
406         if ( xDispatch.is() )
407             xDispatch->dispatch( aTargetURL, aArgs );
408     }
409 }
410 
411 // XStatusListener
statusChanged(const FeatureStateEvent & rEvent)412 void SAL_CALL SfxToolBoxControl::statusChanged( const FeatureStateEvent& rEvent )
413 {
414     SfxViewFrame* pViewFrame = nullptr;
415     Reference < XController > xController;
416 
417     SolarMutexGuard aGuard;
418     if ( getFrameInterface().is() )
419         xController = getFrameInterface()->getController();
420 
421     Reference < XDispatchProvider > xProvider( xController, UNO_QUERY );
422     if ( xProvider.is() )
423     {
424         Reference < XDispatch > xDisp = xProvider->queryDispatch( rEvent.FeatureURL, OUString(), 0 );
425         if ( xDisp.is() )
426         {
427             Reference< XUnoTunnel > xTunnel( xDisp, UNO_QUERY );
428             SfxOfficeDispatch* pDisp = nullptr;
429             if ( xTunnel.is() )
430             {
431                 sal_Int64 nImplementation = xTunnel->getSomething(SfxOfficeDispatch::impl_getStaticIdentifier());
432                 pDisp = reinterpret_cast< SfxOfficeDispatch* >( sal::static_int_cast< sal_IntPtr >( nImplementation ));
433             }
434 
435             if ( pDisp )
436                 pViewFrame = pDisp->GetDispatcher_Impl()->GetFrame();
437         }
438     }
439 
440     sal_uInt16 nSlotId = 0;
441     SfxSlotPool& rPool = SfxSlotPool::GetSlotPool( pViewFrame );
442     const SfxSlot* pSlot = rPool.GetUnoSlot( rEvent.FeatureURL.Path );
443     if ( pSlot )
444         nSlotId = pSlot->GetSlotId();
445     else if ( m_aCommandURL == rEvent.FeatureURL.Path )
446         nSlotId = GetSlotId();
447 
448     if ( nSlotId <= 0 )
449         return;
450 
451     if ( rEvent.Requery )
452         svt::ToolboxController::statusChanged( rEvent );
453     else
454     {
455         SfxItemState eState = SfxItemState::DISABLED;
456         std::unique_ptr<SfxPoolItem> pItem;
457         if ( rEvent.IsEnabled )
458         {
459             eState = SfxItemState::DEFAULT;
460             css::uno::Type aType = rEvent.State.getValueType();
461 
462             if ( aType == cppu::UnoType<void>::get() )
463             {
464                 pItem.reset(new SfxVoidItem( nSlotId ));
465                 eState = SfxItemState::UNKNOWN;
466             }
467             else if ( aType == cppu::UnoType<bool>::get() )
468             {
469                 bool bTemp = false;
470                 rEvent.State >>= bTemp ;
471                 pItem.reset(new SfxBoolItem( nSlotId, bTemp ));
472             }
473             else if ( aType == ::cppu::UnoType< ::cppu::UnoUnsignedShortType >::get())
474             {
475                 sal_uInt16 nTemp = 0;
476                 rEvent.State >>= nTemp ;
477                 pItem.reset(new SfxUInt16Item( nSlotId, nTemp ));
478             }
479             else if ( aType == cppu::UnoType<sal_uInt32>::get() )
480             {
481                 sal_uInt32 nTemp = 0;
482                 rEvent.State >>= nTemp ;
483                 pItem.reset(new SfxUInt32Item( nSlotId, nTemp ));
484             }
485             else if ( aType == cppu::UnoType<OUString>::get() )
486             {
487                 OUString sTemp ;
488                 rEvent.State >>= sTemp ;
489                 pItem.reset(new SfxStringItem( nSlotId, sTemp ));
490             }
491             else if ( aType == cppu::UnoType< css::frame::status::ItemStatus>::get() )
492             {
493                 ItemStatus aItemStatus;
494                 rEvent.State >>= aItemStatus;
495                 SfxItemState tmpState = static_cast<SfxItemState>(aItemStatus.State);
496                 // make sure no-one tries to send us a combination of states
497                 if (tmpState != SfxItemState::UNKNOWN && tmpState != SfxItemState::DISABLED &&
498                     tmpState != SfxItemState::READONLY && tmpState != SfxItemState::DONTCARE &&
499                     tmpState != SfxItemState::DEFAULT && tmpState != SfxItemState::SET)
500                     throw css::uno::RuntimeException("unknown status");
501                 eState = tmpState;
502                 pItem.reset(new SfxVoidItem( nSlotId ));
503             }
504             else if ( aType == cppu::UnoType< css::frame::status::Visibility>::get() )
505             {
506                 Visibility aVisibilityStatus;
507                 rEvent.State >>= aVisibilityStatus;
508                 pItem.reset(new SfxVisibilityItem( nSlotId, aVisibilityStatus.bVisible ));
509             }
510             else
511             {
512                 if ( pSlot )
513                     pItem = pSlot->GetType()->CreateItem();
514                 if ( pItem )
515                 {
516                     pItem->SetWhich( nSlotId );
517                     pItem->PutValue( rEvent.State, 0 );
518                 }
519                 else
520                     pItem.reset(new SfxVoidItem( nSlotId ));
521             }
522         }
523 
524         StateChanged( nSlotId, eState, pItem.get() );
525     }
526 }
527 
528 // XToolbarController
execute(sal_Int16 KeyModifier)529 void SAL_CALL SfxToolBoxControl::execute( sal_Int16 KeyModifier )
530 {
531     SolarMutexGuard aGuard;
532     Select( static_cast<sal_uInt16>(KeyModifier) );
533 }
534 
click()535 void SAL_CALL SfxToolBoxControl::click()
536 {
537     SolarMutexGuard aGuard;
538     Click();
539 }
540 
doubleClick()541 void SAL_CALL SfxToolBoxControl::doubleClick()
542 {
543     SolarMutexGuard aGuard;
544     DoubleClick();
545 }
546 
createPopupWindow()547 Reference< css::awt::XWindow > SAL_CALL SfxToolBoxControl::createPopupWindow()
548 {
549     SolarMutexGuard aGuard;
550     VclPtr<vcl::Window> pWindow = CreatePopupWindow();
551     if ( pWindow )
552         return VCLUnoHelper::GetInterface( pWindow );
553     else
554         return Reference< css::awt::XWindow >();
555 }
556 
createItemWindow(const Reference<css::awt::XWindow> & rParent)557 Reference< css::awt::XWindow > SAL_CALL SfxToolBoxControl::createItemWindow( const Reference< css::awt::XWindow >& rParent )
558 {
559     SolarMutexGuard aGuard;
560     return VCLUnoHelper::GetInterface( CreateItemWindow( VCLUnoHelper::GetWindow( rParent )));
561 }
562 
SetPopupWindow(SfxPopupWindow * pWindow)563 void SfxToolBoxControl::SetPopupWindow( SfxPopupWindow* pWindow )
564 {
565     pImpl->mpPopupWindow = pWindow;
566     pImpl->mpPopupWindow->SetPopupModeEndHdl( LINK( this, SfxToolBoxControl, PopupModeEndHdl ));
567     pImpl->mpPopupWindow->SetDeleteLink_Impl( LINK( this, SfxToolBoxControl, ClosePopupWindow ));
568 }
569 
570 
IMPL_LINK_NOARG(SfxToolBoxControl,PopupModeEndHdl,FloatingWindow *,void)571 IMPL_LINK_NOARG(SfxToolBoxControl, PopupModeEndHdl, FloatingWindow*, void)
572 {
573     if ( pImpl->mpPopupWindow->IsVisible() )
574     {
575         // Replace floating window with popup window and destroy
576         // floating window instance.
577         pImpl->mpFloatingWindow.disposeAndClear();
578         pImpl->mpFloatingWindow = pImpl->mpPopupWindow;
579         pImpl->mpPopupWindow.clear();
580         // We also need to know when the user tries to use the
581         // floating window.
582         pImpl->mpFloatingWindow->AddEventListener( LINK( pImpl.get(), SfxToolBoxControl_Impl, WindowEventListener ));
583     }
584     else
585     {
586         // Popup window has been closed by the user. No replacement, instance
587         // will destroy itself.
588         pImpl->mpPopupWindow.clear();
589     }
590 }
591 
592 
IMPL_LINK(SfxToolBoxControl,ClosePopupWindow,SfxPopupWindow *,pWindow,void)593 IMPL_LINK( SfxToolBoxControl, ClosePopupWindow, SfxPopupWindow *, pWindow, void )
594 {
595     if ( pWindow == pImpl->mpFloatingWindow )
596         pImpl->mpFloatingWindow = nullptr;
597     else
598         pImpl->mpPopupWindow = nullptr;
599 }
600 
601 
StateChanged(sal_uInt16 nId,SfxItemState eState,const SfxPoolItem * pState)602 void SfxToolBoxControl::StateChanged
603 (
604     sal_uInt16              nId,
605     SfxItemState        eState,
606     const SfxPoolItem*  pState
607 )
608 {
609     DBG_ASSERT( pImpl->pBox != nullptr, "setting state to dangling ToolBox" );
610 
611     // enabled/disabled-Flag correcting the lump sum
612     pImpl->pBox->EnableItem( GetId(), eState != SfxItemState::DISABLED );
613 
614     ToolBoxItemBits nItemBits = pImpl->pBox->GetItemBits( GetId() );
615     nItemBits &= ~ToolBoxItemBits::CHECKABLE;
616     ::TriState eTri = TRISTATE_FALSE;
617     switch ( eState )
618     {
619         case SfxItemState::DEFAULT:
620         if ( pState )
621         {
622             if ( auto pBoolItem = dynamic_cast< const SfxBoolItem* >(pState) )
623             {
624                 // BoolItem for checking
625                 if ( pBoolItem->GetValue() )
626                     eTri = TRISTATE_TRUE;
627                 nItemBits |= ToolBoxItemBits::CHECKABLE;
628             }
629             else if ( dynamic_cast< const SfxEnumItemInterface *>( pState ) !=  nullptr &&
630                 static_cast<const SfxEnumItemInterface *>(pState)->HasBoolValue())
631             {
632                 // EnumItem is handled as Bool
633                 if ( static_cast<const SfxEnumItemInterface *>(pState)->GetBoolValue() )
634                     eTri = TRISTATE_TRUE;
635                 nItemBits |= ToolBoxItemBits::CHECKABLE;
636             }
637             else if ( pImpl->bShowString && dynamic_cast< const SfxStringItem *>( pState ) !=  nullptr )
638                 pImpl->pBox->SetItemText(nId, static_cast<const SfxStringItem*>(pState)->GetValue() );
639         }
640         break;
641 
642         case SfxItemState::DONTCARE:
643         {
644             eTri = TRISTATE_INDET;
645             nItemBits |= ToolBoxItemBits::CHECKABLE;
646         }
647         break;
648 
649         default: break; // do nothing
650     }
651 
652     pImpl->pBox->SetItemState( GetId(), eTri );
653     pImpl->pBox->SetItemBits( GetId(), nItemBits );
654 }
655 
656 
Select(sal_uInt16 nSelectModifier)657 void SfxToolBoxControl::Select( sal_uInt16 nSelectModifier )
658 {
659     svt::ToolboxController::execute( nSelectModifier );
660 }
661 
662 
DoubleClick()663 void SfxToolBoxControl::DoubleClick()
664 {
665 }
666 
667 
Click()668 void SfxToolBoxControl::Click()
669 {
670 }
671 
672 
CreatePopupWindow()673 VclPtr<SfxPopupWindow> SfxToolBoxControl::CreatePopupWindow()
674 {
675     return nullptr;
676 }
677 
CreateItemWindow(vcl::Window *)678 VclPtr<vcl::Window> SfxToolBoxControl::CreateItemWindow( vcl::Window * )
679 {
680     return VclPtr<vcl::Window>();
681 }
682 
683 class SfxFrameStatusListener : public svt::FrameStatusListener
684 {
685     public:
686         SfxFrameStatusListener( const css::uno::Reference< css::uno::XComponentContext >& rxContext,
687                                 const css::uno::Reference< css::frame::XFrame >& xFrame,
688                                 SfxPopupWindow* pCallee );
689 
690         // XStatusListener
691         virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& Event ) override;
692 
693     private:
694         VclPtr<SfxPopupWindow> m_pCallee;
695 };
SfxFrameStatusListener(const Reference<XComponentContext> & rxContext,const Reference<XFrame> & xFrame,SfxPopupWindow * pCallee)696 SfxFrameStatusListener::SfxFrameStatusListener(
697     const Reference< XComponentContext >& rxContext,
698     const Reference< XFrame >& xFrame,
699     SfxPopupWindow* pCallee ) :
700     svt::FrameStatusListener( rxContext, xFrame ),
701     m_pCallee( pCallee )
702 {
703 }
704 
705 // XStatusListener
statusChanged(const css::frame::FeatureStateEvent & rEvent)706 void SAL_CALL SfxFrameStatusListener::statusChanged( const css::frame::FeatureStateEvent& rEvent )
707 {
708     m_pCallee->statusChanged( rEvent );
709 }
710 
SfxPopupWindow(sal_uInt16 nId,vcl::Window * pParentWindow,const Reference<XFrame> & rFrame,WinBits nBits)711 SfxPopupWindow::SfxPopupWindow(
712     sal_uInt16 nId,
713     vcl::Window* pParentWindow,
714     const Reference< XFrame >& rFrame,
715     WinBits nBits ) :
716     FloatingWindow( pParentWindow, nBits )
717     , m_bFloating( false )
718     , m_bCascading( false )
719     , m_nId( nId )
720     , m_xFrame( rFrame )
721 {
722     vcl::Window* pWindow = GetTopMostParentSystemWindow( this );
723     if ( pWindow )
724         static_cast<SystemWindow *>(pWindow)->GetTaskPaneList()->AddWindow( this );
725 }
726 
SfxPopupWindow(sal_uInt16 nId,vcl::Window * pParentWindow,const OString & rID,const OUString & rUIXMLDescription,const Reference<XFrame> & rFrame)727 SfxPopupWindow::SfxPopupWindow(
728     sal_uInt16 nId,
729     vcl::Window* pParentWindow,
730     const OString& rID, const OUString& rUIXMLDescription,
731     const Reference< XFrame >& rFrame ) :
732     FloatingWindow( pParentWindow, rID, rUIXMLDescription, rFrame)
733     , m_bFloating( false )
734     , m_bCascading( false )
735     , m_nId( nId )
736     , m_xFrame( rFrame )
737 {
738     vcl::Window* pWindow = GetTopMostParentSystemWindow( this );
739     if ( pWindow )
740         static_cast<SystemWindow *>(pWindow)->GetTaskPaneList()->AddWindow( this );
741 }
742 
~SfxPopupWindow()743 SfxPopupWindow::~SfxPopupWindow()
744 {
745     disposeOnce();
746 }
747 
dispose()748 void SfxPopupWindow::dispose()
749 {
750     if ( m_xStatusListener.is() )
751     {
752         m_xStatusListener->dispose();
753         m_xStatusListener.clear();
754     }
755 
756     vcl::Window* pWindow = GetTopMostParentSystemWindow( this );
757     if ( pWindow )
758         static_cast<SystemWindow *>(pWindow)->GetTaskPaneList()->RemoveWindow( this );
759     FloatingWindow::dispose();
760 }
761 
762 
AddStatusListener(const OUString & rCommandURL)763 void SfxPopupWindow::AddStatusListener( const OUString& rCommandURL )
764 {
765     if ( !m_xStatusListener.is() )
766     {
767         m_xStatusListener = new SfxFrameStatusListener(
768                                     ::comphelper::getProcessComponentContext(),
769                                     m_xFrame,
770                                     this );
771     }
772     if ( m_xStatusListener.is() )
773         m_xStatusListener->addStatusListener( rCommandURL );
774 }
775 
776 
Close()777 bool SfxPopupWindow::Close()
778 {
779     m_bFloating = false;
780     FloatingWindow::Close();
781 
782     Delete();
783     return true;
784 }
785 
786 
PopupModeEnd()787 void SfxPopupWindow::PopupModeEnd()
788 {
789     //! to allow PopupModeEndHdl to be called
790     FloatingWindow::PopupModeEnd();
791 
792     if ( IsVisible() )
793     {
794         // was teared-off
795         if ( m_bFloating )
796         {
797             Hide();
798             Delete();
799         }
800         m_bFloating = true;
801     }
802     else
803         Close();
804 }
805 
806 
MouseMove(const::MouseEvent & rMEvt)807 void SfxPopupWindow::MouseMove( const ::MouseEvent& rMEvt )
808 {
809     if ( !m_bCascading )
810         FloatingWindow::MouseMove( rMEvt );
811     else
812     {
813         // Forward MouseMove-Event to Children
814         ::Point       aPos = rMEvt.GetPosPixel();
815         ::Point       aScrPos = OutputToScreenPixel( aPos );
816         sal_uInt16 i = 0;
817         vcl::Window* pWindow = GetChild( i );
818         while ( pWindow )
819         {
820             ::MouseEvent aChildMEvt( pWindow->ScreenToOutputPixel( aScrPos ),
821                               rMEvt.GetClicks(), rMEvt.GetMode(),
822                               rMEvt.GetButtons(), rMEvt.GetModifier() );
823             pWindow->MouseMove( aChildMEvt );
824             pWindow->Update();
825             i++;
826             pWindow = GetChild( i );
827         }
828     }
829 }
830 
831 
StartCascading()832 void SfxPopupWindow::StartCascading()
833 {
834     m_bCascading = true;
835 }
836 
837 
statusChanged(const css::frame::FeatureStateEvent & rEvent)838 void SfxPopupWindow::statusChanged( const css::frame::FeatureStateEvent& rEvent )
839 {
840     if ( !rEvent.IsEnabled )
841     {
842         Hide();
843     }
844     else if ( m_bFloating )
845     {
846         Show( true, ShowFlags::NoFocusChange | ShowFlags::NoActivate );
847     }
848 }
849 
850 
Delete()851 void SfxPopupWindow::Delete()
852 {
853     VclPtr<SfxPopupWindow> xThis(this);
854     m_aDeleteLink.Call( this );
855     disposeOnce();
856 }
857 
858 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
859