diff options
author | Maxim Monastirsky <momonasmon@gmail.com> | 2017-02-12 22:14:48 +0200 |
---|---|---|
committer | Maxim Monastirsky <momonasmon@gmail.com> | 2017-02-12 21:56:29 +0000 |
commit | 81d4fbc0daa54889ccb09e6a3fadff9c70d99448 (patch) | |
tree | e76c9281a295dda0e1b25316efc77640ad3dc3bf | |
parent | e5aa7a5b5753c57969fc2e17fb334781bb2a0481 (diff) |
tdf#42029 Use a floating toolbar to show clipped items
Change-Id: I6b366f115258ef8497807163179d3e08ab3d5e6f
Reviewed-on: https://gerrit.libreoffice.org/34180
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Maxim Monastirsky <momonasmon@gmail.com>
-rw-r--r-- | framework/inc/uielement/toolbarmanager.hxx | 11 | ||||
-rw-r--r-- | framework/source/uielement/addonstoolbarmanager.cxx | 1 | ||||
-rw-r--r-- | framework/source/uielement/popuptoolbarcontroller.cxx | 10 | ||||
-rw-r--r-- | framework/source/uielement/subtoolbarcontroller.cxx | 1 | ||||
-rw-r--r-- | framework/source/uielement/toolbarmanager.cxx | 217 | ||||
-rw-r--r-- | include/vcl/toolbox.hxx | 10 | ||||
-rw-r--r-- | vcl/inc/toolbox.h | 1 | ||||
-rw-r--r-- | vcl/source/window/floatwin.cxx | 14 | ||||
-rw-r--r-- | vcl/source/window/toolbox.cxx | 20 | ||||
-rw-r--r-- | vcl/source/window/toolbox2.cxx | 48 |
10 files changed, 185 insertions, 148 deletions
diff --git a/framework/inc/uielement/toolbarmanager.hxx b/framework/inc/uielement/toolbarmanager.hxx index 739d22f5647a..9876d6b61ef8 100644 --- a/framework/inc/uielement/toolbarmanager.hxx +++ b/framework/inc/uielement/toolbarmanager.hxx @@ -94,6 +94,7 @@ class ToolBarManager : public ToolbarManager_Base void CheckAndUpdateImages(); virtual void RefreshImages(); void FillToolbar( const css::uno::Reference< css::container::XIndexAccess >& rToolBarData ); + void FillOverflowToolbar( ToolBox* pParent ); void notifyRegisteredControllers( const OUString& aUIElementName, const OUString& aCommand ); void Destroy(); @@ -113,8 +114,6 @@ class ToolBarManager : public ToolbarManager_Base }; protected: - DECL_LINK( Command, CommandEvent const *, void ); - PopupMenu * GetToolBarCustomMenu(ToolBox* pToolBar); DECL_LINK(Click, ToolBox *, void); DECL_LINK(DropdownClick, ToolBox *, void); DECL_LINK(DoubleClick, ToolBox *, void); @@ -124,13 +123,16 @@ class ToolBarManager : public ToolbarManager_Base DECL_LINK( MiscOptionsChanged, LinkParamNone*, void ); DECL_LINK( MenuButton, ToolBox *, void ); + DECL_LINK( MenuPreExecute, ToolBox *, void ); DECL_LINK( MenuSelect, Menu *, bool ); - void MenuDeactivated(); DECL_LINK(AsyncUpdateControllersHdl, Timer *, void); + DECL_LINK( OverflowEventListener, VclWindowEvent&, void ); DECL_STATIC_LINK( ToolBarManager, ExecuteHdl_Impl, void*, void ); virtual bool MenuItemAllowed( sal_uInt16 ) const; + void AddCustomizeMenuItems(ToolBox* pToolBar); + void InitImageManager(); void RemoveControllers(); void CreateControllers(); void UpdateControllers(); @@ -138,7 +140,6 @@ class ToolBarManager : public ToolbarManager_Base void UpdateController( const css::uno::Reference< css::frame::XToolbarController >& xController); //end void AddFrameActionListener(); - void ImplClearPopupMenu( ToolBox *pToolBar ); void RequestImages(); ToolBoxItemBits ConvertStyleToToolboxItemBits( sal_Int32 nStyle ); css::uno::Reference< css::frame::XModel > GetModelFromFrame() const; @@ -178,6 +179,8 @@ class ToolBarManager : public ToolbarManager_Base SubToolBarToSubToolBarControllerMap m_aSubToolBarControllerMap; Timer m_aAsyncUpdateControllersTimer; OUString m_sIconTheme; + + rtl::Reference< ToolBarManager > m_aOverflowManager; }; } diff --git a/framework/source/uielement/addonstoolbarmanager.cxx b/framework/source/uielement/addonstoolbarmanager.cxx index 9458d2f6e45f..4f8a4f6a7b7d 100644 --- a/framework/source/uielement/addonstoolbarmanager.cxx +++ b/framework/source/uielement/addonstoolbarmanager.cxx @@ -82,7 +82,6 @@ AddonsToolBarManager::AddonsToolBarManager( const Reference< XComponentContext > m_pToolBar->SetSelectHdl( LINK( this, AddonsToolBarManager, Select) ); m_pToolBar->SetClickHdl( LINK( this, AddonsToolBarManager, Click ) ); m_pToolBar->SetDoubleClickHdl( LINK( this, AddonsToolBarManager, DoubleClick ) ); - m_pToolBar->SetCommandHdl( LINK( this, AddonsToolBarManager, Command ) ); m_pToolBar->SetStateChangedHdl( LINK( this, AddonsToolBarManager, StateChanged ) ); m_pToolBar->SetDataChangedHdl( LINK( this, AddonsToolBarManager, DataChanged ) ); } diff --git a/framework/source/uielement/popuptoolbarcontroller.cxx b/framework/source/uielement/popuptoolbarcontroller.cxx index b04c831e7a12..34b3a39cf528 100644 --- a/framework/source/uielement/popuptoolbarcontroller.cxx +++ b/framework/source/uielement/popuptoolbarcontroller.cxx @@ -200,7 +200,13 @@ PopupMenuToolbarController::createPopupWindow() pToolBox->SetItemDown( m_nToolBoxId, true ); WindowAlign eAlign( pToolBox->GetAlign() ); - sal_uInt16 nId = m_xPopupMenu->execute( + + // If the parent ToolBox is in popup mode (e.g. sub toolbar, overflow popup), + // its ToolBarManager can be disposed along with our controller, destroying + // m_xPopupMenu, while the latter still in execute. This should be fixed at a + // different level, for now just hold it here so it won't crash. + css::uno::Reference< css::awt::XPopupMenu > xPopupMenu ( m_xPopupMenu ); + sal_uInt16 nId = xPopupMenu->execute( css::uno::Reference< css::awt::XWindowPeer >( getParent(), css::uno::UNO_QUERY ), VCLUnoHelper::ConvertToAWTRect( pToolBox->GetItemRect( m_nToolBoxId ) ), ( eAlign == WindowAlign::Top || eAlign == WindowAlign::Bottom ) ? @@ -209,7 +215,7 @@ PopupMenuToolbarController::createPopupWindow() pToolBox->SetItemDown( m_nToolBoxId, false ); if ( nId ) - functionExecuted( m_xPopupMenu->getCommand( nId ) ); + functionExecuted( xPopupMenu->getCommand( nId ) ); return xRet; } diff --git a/framework/source/uielement/subtoolbarcontroller.cxx b/framework/source/uielement/subtoolbarcontroller.cxx index de8dffd16875..aa5450fe9436 100644 --- a/framework/source/uielement/subtoolbarcontroller.cxx +++ b/framework/source/uielement/subtoolbarcontroller.cxx @@ -245,6 +245,7 @@ css::uno::Reference< css::awt::XWindow > SubToolBarController::createPopupWindow // calc and set size for popup mode Size aSize = pToolBar->CalcPopupWindowSizePixel(); pToolBar->SetSizePixel( aSize ); + pToolBar->SetMenuType( ToolBoxMenuType::NONE ); // open subtoolbox in popup mode vcl::Window::GetDockingManager()->StartPopupMode( pToolBox, pToolBar ); } diff --git a/framework/source/uielement/toolbarmanager.cxx b/framework/source/uielement/toolbarmanager.cxx index 7331d246018b..c7af7cf5869e 100644 --- a/framework/source/uielement/toolbarmanager.cxx +++ b/framework/source/uielement/toolbarmanager.cxx @@ -180,9 +180,10 @@ ToolBarManager::ToolBarManager( const Reference< XComponentContext >& rxContext, if ( !aCmdOptions.Lookup( SvtCommandOptions::CMDOPTION_DISABLED, "CreateDialog")) nMenuType |= ToolBoxMenuType::Customize; - m_pToolBar->SetCommandHdl( LINK( this, ToolBarManager, Command ) ); m_pToolBar->SetMenuType( nMenuType ); m_pToolBar->SetMenuButtonHdl( LINK( this, ToolBarManager, MenuButton ) ); + m_pToolBar->SetMenuExecuteHdl( LINK( this, ToolBarManager, MenuPreExecute ) ); + m_pToolBar->GetMenu()->SetSelectHdl( LINK( this, ToolBarManager, MenuSelect ) ); // set name for testtool, the useful part is after the last '/' sal_Int32 idx = rResourceName.lastIndexOf('/'); @@ -243,7 +244,6 @@ void ToolBarManager::Destroy() m_pToolBar->SetDoubleClickHdl( Link<ToolBox *, void>() ); m_pToolBar->SetStateChangedHdl( Link<StateChangedType const *, void>() ); m_pToolBar->SetDataChangedHdl( Link<DataChangedEvent const *, void>() ); - m_pToolBar->SetCommandHdl( Link<CommandEvent const *, void>() ); m_pToolBar.clear(); @@ -493,7 +493,11 @@ void SAL_CALL ToolBarManager::dispose() } m_xModuleImageManager.clear(); - ImplClearPopupMenu( m_pToolBar ); + if ( m_aOverflowManager.is() ) + { + m_aOverflowManager->dispose(); + m_aOverflowManager.clear(); + } // We have to destroy our toolbar instance now. Destroy(); @@ -919,18 +923,8 @@ ToolBoxItemBits ToolBarManager::ConvertStyleToToolboxItemBits( sal_Int32 nStyle return nItemBits; } -void ToolBarManager::FillToolbar( const Reference< XIndexAccess >& rItemContainer ) +void ToolBarManager::InitImageManager() { - OString aTbxName = OUStringToOString( m_aResourceName, RTL_TEXTENCODING_ASCII_US ); - SAL_INFO( "fwk.uielement", "framework (cd100003) ::ToolBarManager::FillToolbar " << aTbxName.getStr() ); - - SolarMutexGuard g; - - if ( m_bDisposed ) - return; - - sal_uInt16 nId( 1 ); - Reference< XModuleManager2 > xModuleManager = ModuleManager::create( m_xContext ); if ( !m_xDocImageManager.is() ) { @@ -966,6 +960,19 @@ void ToolBarManager::FillToolbar( const Reference< XIndexAccess >& rItemContaine m_xModuleImageManager->addConfigurationListener( Reference< XUIConfigurationListener >( static_cast< OWeakObject* >( this ), UNO_QUERY )); } +} + +void ToolBarManager::FillToolbar( const Reference< XIndexAccess >& rItemContainer ) +{ + OString aTbxName = OUStringToOString( m_aResourceName, RTL_TEXTENCODING_ASCII_US ); + SAL_INFO( "fwk.uielement", "framework (cd100003) ::ToolBarManager::FillToolbar " << aTbxName.getStr() ); + + SolarMutexGuard g; + + if ( m_bDisposed ) + return; + + InitImageManager(); RemoveControllers(); @@ -974,6 +981,7 @@ void ToolBarManager::FillToolbar( const Reference< XIndexAccess >& rItemContaine m_aControllerMap.clear(); m_aCommandMap.clear(); + sal_uInt16 nId( 1 ); CommandInfo aCmdInfo; for ( sal_Int32 n = 0; n < rItemContainer->getCount(); n++ ) { @@ -1165,6 +1173,65 @@ void ToolBarManager::FillToolbar( const Reference< XIndexAccess >& rItemContaine } } +void ToolBarManager::FillOverflowToolbar( ToolBox* pParent ) +{ + CommandInfo aCmdInfo; + bool bInsertSeparator = false; + for ( sal_uInt16 i = 0; i < pParent->GetItemCount(); ++i ) + { + sal_uInt16 nId = pParent->GetItemId( i ); + if ( pParent->IsItemClipped( nId ) ) + { + if ( bInsertSeparator ) + { + m_pToolBar->InsertSeparator(); + bInsertSeparator = false; + } + + const OUString aCommandURL( pParent->GetItemCommand( nId ) ); + m_pToolBar->InsertItem( nId, pParent->GetItemText( nId ) ); + m_pToolBar->SetItemCommand( nId, aCommandURL ); + m_pToolBar->SetQuickHelpText( nId, pParent->GetQuickHelpText( nId ) ); + + // Fill command map. It stores all our commands and from what + // image manager we got our image. So we can decide if we have to use an + // image from a notification message. + CommandToInfoMap::iterator pIter = m_aCommandMap.find( aCommandURL ); + if ( pIter == m_aCommandMap.end()) + { + aCmdInfo.nId = nId; + const CommandToInfoMap::value_type aValue( aCommandURL, aCmdInfo ); + m_aCommandMap.insert( aValue ); + } + else + { + pIter->second.aIds.push_back( nId ); + } + } + else + { + ToolBoxItemType eType = pParent->GetItemType( i ); + if ( m_pToolBar->GetItemCount() && + ( eType == ToolBoxItemType::SEPARATOR || eType == ToolBoxItemType::BREAK ) ) + bInsertSeparator = true; + } + } + + InitImageManager(); + + // Request images for all toolbar items. Must be done before CreateControllers as + // some controllers need access to the image. + RequestImages(); + + // Create controllers after we set the images. There are controllers which needs + // an image at the toolbar at creation time! + CreateControllers(); + + // Notify controllers that they are now correctly initialized and can start listening + // toolbars that will open in popup mode will be updated immediately to avoid flickering + UpdateControllers(); +} + void ToolBarManager::RequestImages() { @@ -1297,39 +1364,6 @@ IMPL_LINK_NOARG(ToolBarManager, DoubleClick, ToolBox *, void) HandleClick(&XToolbarController::doubleClick); } -void ToolBarManager::ImplClearPopupMenu( ToolBox *pToolBar ) -{ - if ( m_bDisposed ) - return; - - ::PopupMenu *pMenu = pToolBar->GetMenu(); - if (pMenu == nullptr) { - return; - } - - // remove config entries from menu, so we have a clean menu to start with - // remove submenu first - pMenu->SetPopupMenu( 1, nullptr ); - - // remove all items that were not added by the toolbar itself - sal_uInt16 i; - for( i=0; i<pMenu->GetItemCount(); ) - { - if( pMenu->GetItemId( i ) < TOOLBOX_MENUITEM_START - && pMenu->GetItemId( i ) != 0 ) // Don't remove separators (Id == 0) - pMenu->RemoveItem( i ); - else - i++; - } -} - -void ToolBarManager::MenuDeactivated() -{ - if (m_bDisposed) - return; - ImplClearPopupMenu(m_pToolBar); -} - Reference< XModel > ToolBarManager::GetModelFromFrame() const { Reference< XController > xController = m_xFrame->getController(); @@ -1363,14 +1397,10 @@ bool ToolBarManager::MenuItemAllowed( sal_uInt16 ) const return true; } -::PopupMenu * ToolBarManager::GetToolBarCustomMenu(ToolBox* pToolBar) +void ToolBarManager::AddCustomizeMenuItems(ToolBox* pToolBar) { - // update the list of hidden tool items first - pToolBar->UpdateCustomMenu(); - ::PopupMenu *pMenu = pToolBar->GetMenu(); - // remove all entries before inserting new ones - ImplClearPopupMenu( pToolBar ); + // No config menu entries if command ".uno:ConfigureDialog" is not enabled Reference< XDispatch > xDisp; css::util::URL aURL; @@ -1383,7 +1413,7 @@ bool ToolBarManager::MenuItemAllowed( sal_uInt16 ) const xDisp = xProv->queryDispatch( aURL, OUString(), 0 ); if ( !xDisp.is() || IsPluginMode() ) - return nullptr; + return; } // popup menu for quick customization @@ -1485,60 +1515,57 @@ bool ToolBarManager::MenuItemAllowed( sal_uInt16 ) const if ( bHideDisabledEntries ) pMenu->RemoveDisabledEntries(); - - return pMenu; } -IMPL_LINK( ToolBarManager, Command, CommandEvent const *, pCmdEvt, void ) +IMPL_LINK( ToolBarManager, MenuButton, ToolBox*, pToolBar, void ) { SolarMutexGuard g; if ( m_bDisposed ) return; - if ( pCmdEvt->GetCommand() != CommandEventId::ContextMenu ) + + assert( !m_aOverflowManager.is() ); + + VclPtrInstance<ToolBox> pOverflowToolBar( pToolBar, WB_LINESPACING | WB_BORDER | WB_SCROLL ); + pOverflowToolBar->SetOutStyle( pToolBar->GetOutStyle() ); + m_aOverflowManager.set( new ToolBarManager( m_xContext, m_xFrame, OUString(), pOverflowToolBar ) ); + m_aOverflowManager->FillOverflowToolbar( pToolBar ); + pOverflowToolBar->SetMenuType( ToolBoxMenuType::NONE ); + + ::Size aActSize( pOverflowToolBar->GetSizePixel() ); + ::Size aSize( pOverflowToolBar->CalcWindowSizePixel() ); + aSize.Width() = aActSize.Width(); + pOverflowToolBar->SetOutputSizePixel( aSize ); + + aSize = pOverflowToolBar->CalcPopupWindowSizePixel(); + pOverflowToolBar->SetSizePixel( aSize ); + + pOverflowToolBar->EnableDocking(); + pOverflowToolBar->AddEventListener( LINK( this, ToolBarManager, OverflowEventListener ) ); + vcl::Window::GetDockingManager()->StartPopupMode( pToolBar, pOverflowToolBar, FloatWinPopupFlags::AllMouseButtonClose ); +} + +IMPL_LINK( ToolBarManager, OverflowEventListener, VclWindowEvent&, rWindowEvent, void ) +{ + if ( rWindowEvent.GetId() != VclEventId::WindowEndPopupMode ) return; - ::PopupMenu * pMenu = GetToolBarCustomMenu(m_pToolBar); - if (pMenu) + if ( m_aOverflowManager.is() ) { - // We only want to handle events for the context menu, but not events - // on the toolbars overflow menu, hence we should only receive events - // from the toolbox menu when we are actually showing it as our context - // menu (the same menu retrieved with GetMenu() is reused for both the - // overflow and context menus). If we set these Hdls permanently rather - // than just when the context menu is showing, then events are duplicated - // when the menu is being used as an overflow menu. - Menu *pManagerMenu = m_pToolBar->GetMenu(); - pManagerMenu->SetSelectHdl( LINK( this, ToolBarManager, MenuSelect ) ); - - // make sure all disabled entries will be shown - pMenu->SetMenuFlags( pMenu->GetMenuFlags() | MenuFlags::AlwaysShowDisabledEntries ); - ::Point aPoint( pCmdEvt->GetMousePosPixel() ); - pMenu->Execute( m_pToolBar, aPoint ); - - //fdo#86820 We may have been disposed and so have a NULL m_pToolBar by - //executing a menu entry, e.g. inserting a chart replaces the toolbars - pManagerMenu = m_bDisposed ? nullptr : m_pToolBar->GetMenu(); - if (pManagerMenu) - { - // Unlink our listeners again -- see above for why. - pManagerMenu->SetSelectHdl( Link<Menu*, bool>() ); - MenuDeactivated(); - } + m_aOverflowManager->dispose(); + m_aOverflowManager.clear(); } } -IMPL_LINK( ToolBarManager, MenuButton, ToolBox*, pToolBar, void ) +IMPL_LINK( ToolBarManager, MenuPreExecute, ToolBox*, pToolBar, void ) { SolarMutexGuard g; if ( m_bDisposed ) return; - pToolBar->UpdateCustomMenu(); - // remove all entries that do not come from the toolbar itself (fdo#38276) - ImplClearPopupMenu( pToolBar ); - } + AddCustomizeMenuItems( pToolBar ); +} IMPL_LINK( ToolBarManager, MenuSelect, Menu*, pMenu, bool ) { @@ -1700,21 +1727,9 @@ IMPL_LINK( ToolBarManager, MenuSelect, Menu*, pMenu, bool ) } } } - else - // The list of "hidden items", i.e. items which are disabled on - // the toolbar hence shown in the context menu for easier access, - // which are managed by the owning toolbar. - { - m_pToolBar->TriggerItem( pMenu->GetCurItemId() - - TOOLBOX_MENUITEM_START ); - } break; } } - - // remove all entries - deactivate is not reliable - // The method checks if we are already disposed and in that case does nothing! - ImplClearPopupMenu( m_pToolBar ); } return true; diff --git a/include/vcl/toolbox.hxx b/include/vcl/toolbox.hxx index 3dbcb3441547..19730ecd879a 100644 --- a/include/vcl/toolbox.hxx +++ b/include/vcl/toolbox.hxx @@ -160,7 +160,7 @@ private: Link<ToolBox *, void> maActivateHdl; Link<ToolBox *, void> maDeactivateHdl; Link<ToolBox *, void> maSelectHdl; - Link<CommandEvent const *, void> maCommandHandler; + Link<ToolBox *, void> maMenuButtonHdl; Link<StateChangedType const *, void> maStateChangedHandler; Link<DataChangedEvent const *, void> maDataChangedHandler; /** StatusListener. Notifies about rotated images etc */ @@ -354,6 +354,7 @@ public: sal_uInt16 GetItemId( const OUString& rCommand ) const; Rectangle GetItemRect( sal_uInt16 nItemId ) const; Rectangle GetItemPosRect( sal_uInt16 nPos ) const; + Rectangle GetOverflowRect() const; /// Returns size of the bitmap / text that is inside this toolbox item. Size GetItemContentSize( sal_uInt16 nItemId ) const; @@ -402,6 +403,7 @@ public: /// Convenience method to hide items (via ShowItem). void HideItem(sal_uInt16 nItemId) { ShowItem( nItemId, false ); } + bool IsItemClipped( sal_uInt16 nItemId ) const; bool IsItemVisible( sal_uInt16 nItemId ) const; bool IsItemReallyVisible( sal_uInt16 nItemId ) const; @@ -463,9 +465,9 @@ public: void SetDeactivateHdl( const Link<ToolBox *, void>& rLink ) { maDeactivateHdl = rLink; } void SetSelectHdl( const Link<ToolBox *, void>& rLink ) { maSelectHdl = rLink; } const Link<ToolBox *, void>& GetSelectHdl() const { return maSelectHdl; } - void SetCommandHdl( const Link<CommandEvent const *, void>& aLink ) { maCommandHandler = aLink; } void SetStateChangedHdl( const Link<StateChangedType const *, void>& aLink ) { maStateChangedHandler = aLink; } void SetDataChangedHdl( const Link<DataChangedEvent const *, void>& aLink ) { maDataChangedHandler = aLink; } + void SetMenuButtonHdl( const Link<ToolBox *, void>& rLink ) { maMenuButtonHdl = rLink; } // support for custom menu (eg for configuration) // note: this menu will also be used to display currently @@ -479,10 +481,10 @@ public: bool IsMenuEnabled() const; PopupMenu* GetMenu() const; void UpdateCustomMenu(); - void SetMenuButtonHdl( const Link<ToolBox *, void>& rLink ); + void SetMenuExecuteHdl( const Link<ToolBox *, void>& rLink ); // open custommenu - void ExecuteCustomMenu(); + void ExecuteCustomMenu( const Rectangle& rRect = Rectangle() ); // allow Click Handler to distinguish between mouse and key input bool IsKeyEvent() const { return mbIsKeyEvent; } diff --git a/vcl/inc/toolbox.h b/vcl/inc/toolbox.h index 7be02bf73cab..5ea8b50a4415 100644 --- a/vcl/inc/toolbox.h +++ b/vcl/inc/toolbox.h @@ -128,6 +128,7 @@ struct ImplToolBoxPrivateData // the optional custom menu VclPtr<PopupMenu> mpMenu; + Rectangle maMenuRect; ToolBoxMenuType maMenuType; ImplSVEvent * mnEventId; diff --git a/vcl/source/window/floatwin.cxx b/vcl/source/window/floatwin.cxx index 3e9cd967edf1..41e12ea67aea 100644 --- a/vcl/source/window/floatwin.cxx +++ b/vcl/source/window/floatwin.cxx @@ -708,16 +708,16 @@ void FloatingWindow::StartPopupMode( const Rectangle& rRect, FloatWinPopupFlags void FloatingWindow::StartPopupMode( ToolBox* pBox, FloatWinPopupFlags nFlags ) { + mpImplData->mpBox = pBox; + // get selected button sal_uInt16 nItemId = pBox->GetDownItemId(); - if ( !nItemId ) - return; - mpImplData->mpBox = pBox; - pBox->ImplFloatControl( true, this ); + if ( nItemId ) + pBox->ImplFloatControl( true, this ); // retrieve some data from the ToolBox - Rectangle aRect = pBox->GetItemRect( nItemId ); + Rectangle aRect = nItemId ? pBox->GetItemRect( nItemId ) : pBox->GetOverflowRect(); Point aPos; // convert to parent's screen coordinates aPos = GetParent()->OutputToScreenPixel( GetParent()->AbsoluteScreenToOutputPixel( pBox->OutputToAbsoluteScreenPixel( aRect.TopLeft() ) ) ); @@ -793,6 +793,10 @@ void FloatingWindow::ImplEndPopupMode( FloatWinPopupEndFlags nFlags, const VclPt if (mpImplData && mpImplData->mpBox) { mpImplData->mpBox->ImplFloatControl( false, this ); + // if the parent ToolBox is in popup mode, it should be closed too. + if ( GetDockingManager()->IsInPopupMode( mpImplData->mpBox ) ) + nFlags |= FloatWinPopupEndFlags::CloseAll; + mpImplData->mpBox = nullptr; } diff --git a/vcl/source/window/toolbox.cxx b/vcl/source/window/toolbox.cxx index 6cf2f6a89c93..a6e3d5640e6f 100644 --- a/vcl/source/window/toolbox.cxx +++ b/vcl/source/window/toolbox.cxx @@ -3947,7 +3947,10 @@ void ToolBox::MouseButtonDown( const MouseEvent& rMEvt ) // menu button hit ? if( mpData->maMenubuttonItem.maRect.IsInside( aMousePos ) && ImplHasClippedItems() ) { - ExecuteCustomMenu(); + if ( maMenuButtonHdl.IsSet() ) + maMenuButtonHdl.Call( this ); + else + ExecuteCustomMenu( mpData->maMenubuttonItem.maRect ); return; } @@ -4405,8 +4408,6 @@ bool ToolBox::EventNotify( NotifyEvent& rNEvt ) void ToolBox::Command( const CommandEvent& rCEvt ) { - maCommandHandler.Call( &rCEvt ); - // depict StartDrag on MouseButton/Left/Alt if ( (rCEvt.GetCommand() == CommandEventId::StartDrag) && rCEvt.IsMouseEvent() && mbCustomize && !mbDragging && !mbDrag && !mbSelection && @@ -4462,6 +4463,11 @@ void ToolBox::Command( const CommandEvent& rCEvt ) } } } + else if ( rCEvt.GetCommand() == CommandEventId::ContextMenu ) + { + ExecuteCustomMenu( Rectangle( rCEvt.GetMousePosPixel(), rCEvt.GetMousePosPixel() ) ); + return; + } DockingWindow::Command( rCEvt ); } @@ -5052,13 +5058,15 @@ bool ToolBox::ImplOpenItem( vcl::KeyCode aKeyCode ) || ((nCode == KEY_UP || nCode == KEY_DOWN) && !IsHorizontal()) ) return false; - if( IsMenuEnabled() && mpData->mbMenubuttonSelected ) + if( mpData->mbMenubuttonSelected ) { if( ImplCloseLastPopup( GetParent() ) ) return bRet; - UpdateCustomMenu(); - mpData->mnEventId = Application::PostUserEvent( LINK( this, ToolBox, ImplCallExecuteCustomMenu ), nullptr, true ); + if ( maMenuButtonHdl.IsSet() ) + maMenuButtonHdl.Call( this ); + else + ExecuteCustomMenu( mpData->maMenubuttonItem.maRect ); } else if( mnHighItemId && ImplGetItem( mnHighItemId ) && (ImplGetItem( mnHighItemId )->mnBits & ToolBoxItemBits::DROPDOWN) ) diff --git a/vcl/source/window/toolbox2.cxx b/vcl/source/window/toolbox2.cxx index 10cede7eeeac..ec58bbd8c415 100644 --- a/vcl/source/window/toolbox2.cxx +++ b/vcl/source/window/toolbox2.cxx @@ -873,6 +873,11 @@ Rectangle ToolBox::GetItemPosRect( sal_uInt16 nPos ) const return Rectangle(); } +Rectangle ToolBox::GetOverflowRect() const +{ + return mpData->maMenubuttonItem.maRect; +} + bool ToolBox::ImplHasExternalMenubutton() { // check if the borderwindow (i.e. the decoration) provides the menu button @@ -1317,6 +1322,16 @@ void ToolBox::ShowItem( sal_uInt16 nItemId, bool bVisible ) } } +bool ToolBox::IsItemClipped( sal_uInt16 nItemId ) const +{ + ImplToolItem* pItem = ImplGetItem( nItemId ); + + if ( pItem ) + return pItem->IsClipped(); + else + return false; +} + bool ToolBox::IsItemVisible( sal_uInt16 nItemId ) const { ImplToolItem* pItem = ImplGetItem( nItemId ); @@ -1564,7 +1579,7 @@ PopupMenu* ToolBox::GetMenu() const return mpData == nullptr ? nullptr : mpData->mpMenu; } -void ToolBox::SetMenuButtonHdl( const Link<ToolBox *, void>& rLink ) +void ToolBox::SetMenuExecuteHdl( const Link<ToolBox *, void>& rLink ) { mpData->maMenuButtonHdl = rLink; } @@ -1604,19 +1619,7 @@ void ToolBox::UpdateCustomMenu() return; PopupMenu *pMenu = GetMenu(); - - sal_uInt16 i = 0; - // remove old entries - while( i < pMenu->GetItemCount() ) - { - if( pMenu->GetItemId( i ) >= TOOLBOX_MENUITEM_START ) - { - pMenu->RemoveItem( i ); - i = 0; - } - else - i++; - } + pMenu->Clear(); // add menu items: first the overflow items, then hidden items, both in the // order they would usually appear in the toolbar. Separators that would be @@ -1680,13 +1683,6 @@ IMPL_LINK_NOARG(ToolBox, ImplCallExecuteCustomMenu, void*, void) // call button handler to allow for menu customization mpData->maMenuButtonHdl.Call( this ); - // We specifically only register this event listener when executing our - // overflow menu (and remove it directly afterwards), as the same menu - // is reused for both the overflow menu (as managed here in ToolBox), - // but also by ToolBarManager for its context menu. If we leave event - // listeners alive beyond when the menu is showing in the desired mode - // then duplicate events can happen as the context menu "duplicates" - // items from the overflow menu, which both listeners would then act on. GetMenu()->AddEventListener( LINK( this, ToolBox, ImplCustomMenuListener ) ); // make sure all disabled entries will be shown @@ -1697,9 +1693,10 @@ IMPL_LINK_NOARG(ToolBox, ImplCallExecuteCustomMenu, void*, void) bool bBorderDel = false; VclPtr<vcl::Window> pWin = this; - Rectangle aMenuRect = mpData->maMenubuttonItem.maRect; + Rectangle aMenuRect = mpData->maMenuRect; + mpData->maMenuRect.SetEmpty(); VclPtr<ImplBorderWindow> pBorderWin; - if( IsFloatingMode() ) + if( aMenuRect.IsEmpty() && IsFloatingMode() ) { // custom menu is placed in the decoration pBorderWin = dynamic_cast<ImplBorderWindow*>( GetWindow( GetWindowType::Border ) ); @@ -1732,13 +1729,14 @@ IMPL_LINK_NOARG(ToolBox, ImplCallExecuteCustomMenu, void*, void) } } -void ToolBox::ExecuteCustomMenu() +void ToolBox::ExecuteCustomMenu( const Rectangle& rRect ) { if( IsMenuEnabled() ) { + UpdateCustomMenu(); // handle custom menu asynchronously // to avoid problems if the toolbox is closed during menu execute - UpdateCustomMenu(); + mpData->maMenuRect = rRect; mpData->mnEventId = Application::PostUserEvent( LINK( this, ToolBox, ImplCallExecuteCustomMenu ), nullptr, true ); } } |