diff options
author | Caolán McNamara <caolanm@redhat.com> | 2020-05-28 15:24:29 +0100 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2020-06-12 20:03:54 +0200 |
commit | a16e6122dc62f545df90b9ea4d1f4723c46336b6 (patch) | |
tree | b6dfbe06f36d715292fe88821f33f141645b1ad2 /sc | |
parent | a5b181df04e4688256bda19e1bece7bf9fd3fa02 (diff) |
weld checklistmenu
rework the "menu" to be a treeview using hover selection instead of
a custom set of widgetry, and drop the newly unused custom a11y code
Change-Id: Ie7d9b7875ce00843b3f262882816cebb472bf681
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/95223
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Diffstat (limited to 'sc')
-rw-r--r-- | sc/IwyuFilter_sc.yaml | 6 | ||||
-rw-r--r-- | sc/Library_sc.mk | 3 | ||||
-rw-r--r-- | sc/UIConfig_scalc.mk | 2 | ||||
-rw-r--r-- | sc/inc/AccessibleFilterMenu.hxx | 139 | ||||
-rw-r--r-- | sc/inc/AccessibleFilterMenuItem.hxx | 95 | ||||
-rw-r--r-- | sc/inc/AccessibleFilterTopWindow.hxx | 81 | ||||
-rw-r--r-- | sc/inc/strings.hrc | 4 | ||||
-rw-r--r-- | sc/qa/uitest/autofilter/tdf126306.py | 41 | ||||
-rw-r--r-- | sc/source/ui/Accessibility/AccessibleFilterMenu.cxx | 331 | ||||
-rw-r--r-- | sc/source/ui/Accessibility/AccessibleFilterMenuItem.cxx | 166 | ||||
-rw-r--r-- | sc/source/ui/Accessibility/AccessibleFilterTopWindow.cxx | 118 | ||||
-rw-r--r-- | sc/source/ui/app/inputwin.cxx | 1 | ||||
-rw-r--r-- | sc/source/ui/cctrl/checklistmenu.cxx | 1862 | ||||
-rw-r--r-- | sc/source/ui/docshell/docsh4.cxx | 1 | ||||
-rw-r--r-- | sc/source/ui/inc/checklistmenu.hxx | 472 | ||||
-rw-r--r-- | sc/source/ui/inc/gridwin.hxx | 2 | ||||
-rw-r--r-- | sc/source/ui/view/gridwin.cxx | 74 | ||||
-rw-r--r-- | sc/source/ui/view/gridwin2.cxx | 62 | ||||
-rw-r--r-- | sc/uiconfig/scalc/ui/filterdropdown.ui | 304 | ||||
-rw-r--r-- | sc/uiconfig/scalc/ui/listmenu.ui | 9 |
20 files changed, 1156 insertions, 2617 deletions
diff --git a/sc/IwyuFilter_sc.yaml b/sc/IwyuFilter_sc.yaml index 03e98182ac73..ee2301087b23 100644 --- a/sc/IwyuFilter_sc.yaml +++ b/sc/IwyuFilter_sc.yaml @@ -4,12 +4,6 @@ blacklist: sc/inc/AccessibleGlobal.hxx: # base class has to be a complete type - com/sun/star/accessibility/XAccessibleStateSet.hpp - sc/inc/AccessibleFilterMenu.hxx: - # base class has to be a complete type - - com/sun/star/accessibility/XAccessibleSelection.hpp - sc/inc/AccessibleFilterMenuItem.hxx: - # base class has to be a complete type - - com/sun/star/accessibility/XAccessibleAction.hpp sc/inc/addruno.hxx: # base class has to be a complete type - com/sun/star/beans/XPropertySet.hpp diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk index 997b14c0add9..47b801f799c4 100644 --- a/sc/Library_sc.mk +++ b/sc/Library_sc.mk @@ -363,9 +363,6 @@ $(eval $(call gb_Library_add_exception_objects,sc,\ sc/source/ui/Accessibility/AccessibleDocumentBase \ sc/source/ui/Accessibility/AccessibleDocumentPagePreview \ sc/source/ui/Accessibility/AccessibleEditObject \ - sc/source/ui/Accessibility/AccessibleFilterMenu \ - sc/source/ui/Accessibility/AccessibleFilterMenuItem \ - sc/source/ui/Accessibility/AccessibleFilterTopWindow \ sc/source/ui/Accessibility/AccessibleGlobal \ sc/source/ui/Accessibility/AccessiblePageHeader \ sc/source/ui/Accessibility/AccessiblePageHeaderArea \ diff --git a/sc/UIConfig_scalc.mk b/sc/UIConfig_scalc.mk index 8e3de9629a7f..38b6acaf0f0d 100644 --- a/sc/UIConfig_scalc.mk +++ b/sc/UIConfig_scalc.mk @@ -127,6 +127,7 @@ $(eval $(call gb_UIConfig_add_uifiles,modules/scalc,\ sc/uiconfig/scalc/ui/exponentialsmoothingdialog \ sc/uiconfig/scalc/ui/filldlg \ sc/uiconfig/scalc/ui/filterlist \ + sc/uiconfig/scalc/ui/filterdropdown \ sc/uiconfig/scalc/ui/footerdialog \ sc/uiconfig/scalc/ui/formatcellsdialog \ sc/uiconfig/scalc/ui/formulacalculationoptions \ @@ -149,6 +150,7 @@ $(eval $(call gb_UIConfig_add_uifiles,modules/scalc,\ sc/uiconfig/scalc/ui/integerdialog \ sc/uiconfig/scalc/ui/leftfooterdialog \ sc/uiconfig/scalc/ui/leftheaderdialog \ + sc/uiconfig/scalc/ui/listmenu \ sc/uiconfig/scalc/ui/namerangesdialog \ sc/uiconfig/scalc/ui/notebookbar \ sc/uiconfig/scalc/ui/notebookbar_compact \ diff --git a/sc/inc/AccessibleFilterMenu.hxx b/sc/inc/AccessibleFilterMenu.hxx deleted file mode 100644 index 878c27a637c3..000000000000 --- a/sc/inc/AccessibleFilterMenu.hxx +++ /dev/null @@ -1,139 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#ifndef INCLUDED_SC_INC_ACCESSIBLEFILTERMENU_HXX -#define INCLUDED_SC_INC_ACCESSIBLEFILTERMENU_HXX - -#include <AccessibleContextBase.hxx> -#include <cppuhelper/implbase1.hxx> - -#include <com/sun/star/accessibility/XAccessibleSelection.hpp> -#include <vcl/vclptr.hxx> - -#include <vector> - -class ScMenuFloatingWindow; - -typedef ::cppu::ImplHelper1< - css::accessibility::XAccessibleSelection > ScAccessibleFilterMenu_BASE; - -class ScAccessibleFilterMenu : - public ScAccessibleContextBase, - public ScAccessibleFilterMenu_BASE -{ -public: - explicit ScAccessibleFilterMenu( - const css::uno::Reference< css::accessibility::XAccessible>& rxParent, - ScMenuFloatingWindow* pWin, const OUString& rName, size_t nMenuPos); - virtual ~ScAccessibleFilterMenu() override; - - virtual bool isVisible() override; - - /// XAccessibleComponent - - virtual css::uno::Reference< css::accessibility::XAccessible > - SAL_CALL getAccessibleAtPoint( const css::awt::Point& rPoint ) override; - - virtual void SAL_CALL grabFocus() override; - - virtual sal_Int32 SAL_CALL getForeground() override; - - virtual sal_Int32 SAL_CALL getBackground() override; - - /// XAccessibleContext - - virtual sal_Int32 SAL_CALL getAccessibleChildCount() override; - - virtual css::uno::Reference< css::accessibility::XAccessible> SAL_CALL - getAccessibleChild(sal_Int32 nIndex) override; - - virtual css::uno::Reference< - css::accessibility::XAccessibleStateSet> SAL_CALL - getAccessibleStateSet() override; - - virtual OUString SAL_CALL getImplementationName() override; - - /// XAccessibleEventBroadcaster - virtual void SAL_CALL - addAccessibleEventListener( - const css::uno::Reference< css::accessibility::XAccessibleEventListener>& xListener) override; - - /// Remove an existing event listener. - virtual void SAL_CALL - removeAccessibleEventListener( - const css::uno::Reference< css::accessibility::XAccessibleEventListener>& xListener) override; - - /// XAccessibleSelection - - virtual void SAL_CALL selectAccessibleChild(sal_Int32 nChildIndex) override; - - virtual sal_Bool SAL_CALL isAccessibleChildSelected(sal_Int32 nChildIndex) override; - - virtual void SAL_CALL clearAccessibleSelection() override; - - virtual void SAL_CALL selectAllAccessibleChildren() override; - - virtual ::sal_Int32 SAL_CALL getSelectedAccessibleChildCount() override; - - virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL - getSelectedAccessibleChild(sal_Int32 nChildIndex) override; - - virtual void SAL_CALL deselectAccessibleChild(sal_Int32 nChildIndex) override; - - /// XInterface - - virtual css::uno::Any SAL_CALL queryInterface( - css::uno::Type const & rType ) override; - - virtual void SAL_CALL acquire() throw () override; - virtual void SAL_CALL release() throw () override; - - /// XTypeProvider - - virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override; - - /// non-UNO methods - - void appendMenuItem(const OUString& rName, size_t nMenuPos); - void setMenuPos(size_t nMenuPos); - -protected: - - sal_Int32 getMenuItemCount() const; - - virtual tools::Rectangle GetBoundingBoxOnScreen() const override; - - virtual tools::Rectangle GetBoundingBox() const override; - -private: - bool isSelected() const; - - void updateStates(); - -private: - ::std::vector< css::uno::Reference< css::accessibility::XAccessible > > maMenuItems; - css::uno::Reference< css::accessibility::XAccessibleStateSet > mxStateSet; - - size_t mnMenuPos; - VclPtr<ScMenuFloatingWindow> mpWindow; -}; - -#endif - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/inc/AccessibleFilterMenuItem.hxx b/sc/inc/AccessibleFilterMenuItem.hxx deleted file mode 100644 index d45b4c2890e2..000000000000 --- a/sc/inc/AccessibleFilterMenuItem.hxx +++ /dev/null @@ -1,95 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#ifndef INCLUDED_SC_INC_ACCESSIBLEFILTERMENUITEM_HXX -#define INCLUDED_SC_INC_ACCESSIBLEFILTERMENUITEM_HXX - -#include <AccessibleContextBase.hxx> -#include <cppuhelper/implbase1.hxx> - -#include <com/sun/star/accessibility/XAccessibleAction.hpp> -#include <vcl/vclptr.hxx> - -class ScMenuFloatingWindow; - -typedef ::cppu::ImplHelper1< - css::accessibility::XAccessibleAction > ScAccessibleFilterMenuItem_BASE; - -class ScAccessibleFilterMenuItem final : - public ScAccessibleContextBase, - public ScAccessibleFilterMenuItem_BASE -{ -public: - explicit ScAccessibleFilterMenuItem( - const css::uno::Reference< css::accessibility::XAccessible>& rxParent, - ScMenuFloatingWindow* pWin, const OUString& rName, size_t nMenuPos); - - virtual ~ScAccessibleFilterMenuItem() override; - - /// XAccessibleContext - - virtual sal_Int32 SAL_CALL getAccessibleChildCount() override; - - virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL - getAccessibleChild(sal_Int32 nIndex) override; - - virtual css::uno::Reference< css::accessibility::XAccessibleStateSet> SAL_CALL - getAccessibleStateSet() override; - - virtual OUString SAL_CALL getImplementationName() override; - - /// XAccessibleAction - - virtual ::sal_Int32 SAL_CALL getAccessibleActionCount() override; - - virtual sal_Bool SAL_CALL doAccessibleAction(sal_Int32 nIndex) override; - - virtual OUString SAL_CALL getAccessibleActionDescription(sal_Int32 nIndex) override; - - virtual css::uno::Reference< css::accessibility::XAccessibleKeyBinding > SAL_CALL - getAccessibleActionKeyBinding(sal_Int32 nIndex) override; - - /// XInterface - - virtual css::uno::Any SAL_CALL queryInterface( - css::uno::Type const & rType ) override; - - virtual void SAL_CALL acquire() throw () override; - virtual void SAL_CALL release() throw () override; - - /// Non-UNO Methods - -private: - - virtual tools::Rectangle GetBoundingBoxOnScreen() const override; - - virtual tools::Rectangle GetBoundingBox() const override; - - bool isSelected() const; - void updateStateSet(); - - css::uno::Reference< css::accessibility::XAccessibleStateSet > mxStateSet; - - VclPtr<ScMenuFloatingWindow> mpWindow; - size_t mnMenuPos; -}; - -#endif - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/inc/AccessibleFilterTopWindow.hxx b/sc/inc/AccessibleFilterTopWindow.hxx deleted file mode 100644 index 90dd9bbbfd30..000000000000 --- a/sc/inc/AccessibleFilterTopWindow.hxx +++ /dev/null @@ -1,81 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#ifndef INCLUDED_SC_INC_ACCESSIBLEFILTERTOPWINDOW_HXX -#define INCLUDED_SC_INC_ACCESSIBLEFILTERTOPWINDOW_HXX - -#include "AccessibleFilterMenu.hxx" - -class ScCheckListMenuWindow; - -class ScAccessibleFilterTopWindow final : public ScAccessibleFilterMenu -{ -public: - ScAccessibleFilterTopWindow( - const css::uno::Reference< css::accessibility::XAccessible>& rxParent, - ScCheckListMenuWindow* pWin, - const OUString& rName); - virtual ~ScAccessibleFilterTopWindow() override; - - // XAccessibleContext - - virtual sal_Int32 SAL_CALL getAccessibleChildCount() override; - - virtual css::uno::Reference< css::accessibility::XAccessible> SAL_CALL - getAccessibleChild(sal_Int32 nIndex) override; - - virtual OUString SAL_CALL getImplementationName() override; - - // Non-UNO Methods - - enum ChildControlType { - EDIT_SEARCH_BOX, LISTBOX, TOGGLE_ALL, SINGLE_ON_BTN, SINGLE_OFF_BTN, OK_BTN, CANCEL_BTN - }; - void setAccessibleChild( - const css::uno::Reference< css::accessibility::XAccessible >& rAccessible, - ChildControlType eType); - -private: - /** Edit search box for searching field members */ - css::uno::Reference< css::accessibility::XAccessible > - mxAccEditSearchBox; - /** check list box for field member visibility */ - css::uno::Reference< css::accessibility::XAccessible > - mxAccListBox; - - /** check box for toggling all field member's visibility. */ - css::uno::Reference< css::accessibility::XAccessible > - mxAccToggleAll; - - css::uno::Reference< css::accessibility::XAccessible > - mxAccSingleOnBtn; - - css::uno::Reference< css::accessibility::XAccessible > - mxAccSingleOffBtn; - - css::uno::Reference< css::accessibility::XAccessible > - mxAccOkBtn; - - css::uno::Reference< css::accessibility::XAccessible > - mxAccCancelBtn; -}; - -#endif - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/inc/strings.hrc b/sc/inc/strings.hrc index a685c1ef9d28..6f6b0299c28a 100644 --- a/sc/inc/strings.hrc +++ b/sc/inc/strings.hrc @@ -164,10 +164,6 @@ #define STR_MENU_SORT_ASC NC_("STR_MENU_SORT_ASC", "Sort Ascending") #define STR_MENU_SORT_DESC NC_("STR_MENU_SORT_DESC", "Sort Descending") #define STR_MENU_SORT_CUSTOM NC_("STR_MENU_SORT_CUSTOM", "Custom Sort") -#define STR_BTN_TOGGLE_ALL NC_("STR_BTN_TOGGLE_ALL", "All") -#define STR_BTN_SELECT_CURRENT NC_("STR_BTN_SELECT_CURRENT", "Show only the current item.") -#define STR_BTN_UNSELECT_CURRENT NC_("STR_BTN_UNSELECT_CURRENT", "Hide only the current item.") -#define STR_EDIT_SEARCH_ITEMS NC_("STR_EDIT_SEARCH_ITEMS", "Search items...") #define SCSTR_QHELP_POSWND NC_("SCSTR_QHELP_POSWND", "Name Box") #define SCSTR_QHELP_INPUTWND NC_("SCSTR_QHELP_INPUTWND", "Input line") diff --git a/sc/qa/uitest/autofilter/tdf126306.py b/sc/qa/uitest/autofilter/tdf126306.py index 5446d3337049..5a1a6ab7b053 100644 --- a/sc/qa/uitest/autofilter/tdf126306.py +++ b/sc/qa/uitest/autofilter/tdf126306.py @@ -48,8 +48,9 @@ class tdf126306(UITestCase): # Sort ascending button xGridWin.executeAction("LAUNCH", mkPropertyValues({"AUTOFILTER": "", "COL": "0", "ROW": "0"})) xFloatWindow = self.xUITest.getFloatWindow() - xFloatWindow.executeAction("TYPE", mkPropertyValues({"KEYCODE":"SHIFT+TAB"})) - xFloatWindow.executeAction("TYPE", mkPropertyValues({"KEYCODE":"RETURN"})) + xMenu = xFloatWindow.getChild("menu") + xMenu.executeAction("TYPE", mkPropertyValues({"KEYCODE":"SPACE"})) + xMenu.executeAction("TYPE", mkPropertyValues({"KEYCODE":"RETURN"})) sort_asc_values = [0, 3, 8, 9, 17, 19, 25, 25, 33, 89, 107, 204, 453, 1023] self.check_values(document, sort_asc_values) @@ -63,9 +64,9 @@ class tdf126306(UITestCase): # Sort descending button xGridWin.executeAction("LAUNCH", mkPropertyValues({"AUTOFILTER": "", "COL": "0", "ROW": "0"})) xFloatWindow = self.xUITest.getFloatWindow() - xFloatWindow.executeAction("TYPE", mkPropertyValues({"KEYCODE":"SHIFT+TAB"})) - xFloatWindow.executeAction("TYPE", mkPropertyValues({"KEYCODE":"DOWN"})) - xFloatWindow.executeAction("TYPE", mkPropertyValues({"KEYCODE":"RETURN"})) + xMenu = xFloatWindow.getChild("menu") + xMenu.executeAction("TYPE", mkPropertyValues({"KEYCODE":"DOWN"})) + xMenu.executeAction("TYPE", mkPropertyValues({"KEYCODE":"RETURN"})) sort_des_values = [1023, 453, 204, 107, 89, 33, 25, 25, 19, 17, 9, 8, 3, 0] self.check_values(document, sort_des_values) @@ -79,10 +80,10 @@ class tdf126306(UITestCase): # Top 10 button xGridWin.executeAction("LAUNCH", mkPropertyValues({"AUTOFILTER": "", "COL": "0", "ROW": "0"})) xFloatWindow = self.xUITest.getFloatWindow() - xFloatWindow.executeAction("TYPE", mkPropertyValues({"KEYCODE":"SHIFT+TAB"})) - xFloatWindow.executeAction("TYPE", mkPropertyValues({"KEYCODE":"DOWN"})) - xFloatWindow.executeAction("TYPE", mkPropertyValues({"KEYCODE":"DOWN"})) - xFloatWindow.executeAction("TYPE", mkPropertyValues({"KEYCODE":"RETURN"})) + xMenu = xFloatWindow.getChild("menu") + xMenu.executeAction("TYPE", mkPropertyValues({"KEYCODE":"DOWN"})) + xMenu.executeAction("TYPE", mkPropertyValues({"KEYCODE":"DOWN"})) + xMenu.executeAction("TYPE", mkPropertyValues({"KEYCODE":"RETURN"})) top10_hidden_values = [True, True, True, False, True, False, True, True, False, True, True, False, True, True] @@ -99,11 +100,11 @@ class tdf126306(UITestCase): # Empty button xGridWin.executeAction("LAUNCH", mkPropertyValues({"AUTOFILTER": "", "COL": "0", "ROW": "0"})) xFloatWindow = self.xUITest.getFloatWindow() - xFloatWindow.executeAction("TYPE", mkPropertyValues({"KEYCODE":"SHIFT+TAB"})) - xFloatWindow.executeAction("TYPE", mkPropertyValues({"KEYCODE":"DOWN"})) - xFloatWindow.executeAction("TYPE", mkPropertyValues({"KEYCODE":"DOWN"})) - xFloatWindow.executeAction("TYPE", mkPropertyValues({"KEYCODE":"DOWN"})) - xFloatWindow.executeAction("TYPE", mkPropertyValues({"KEYCODE":"RETURN"})) + xMenu = xFloatWindow.getChild("menu") + xMenu.executeAction("TYPE", mkPropertyValues({"KEYCODE":"DOWN"})) + xMenu.executeAction("TYPE", mkPropertyValues({"KEYCODE":"DOWN"})) + xMenu.executeAction("TYPE", mkPropertyValues({"KEYCODE":"DOWN"})) + xMenu.executeAction("TYPE", mkPropertyValues({"KEYCODE":"RETURN"})) empty_values = [False] * 14 #Values are the same @@ -118,12 +119,12 @@ class tdf126306(UITestCase): # Not Empty button xGridWin.executeAction("LAUNCH", mkPropertyValues({"AUTOFILTER": "", "COL": "0", "ROW": "0"})) xFloatWindow = self.xUITest.getFloatWindow() - xFloatWindow.executeAction("TYPE", mkPropertyValues({"KEYCODE":"SHIFT+TAB"})) - xFloatWindow.executeAction("TYPE", mkPropertyValues({"KEYCODE":"DOWN"})) - xFloatWindow.executeAction("TYPE", mkPropertyValues({"KEYCODE":"DOWN"})) - xFloatWindow.executeAction("TYPE", mkPropertyValues({"KEYCODE":"DOWN"})) - xFloatWindow.executeAction("TYPE", mkPropertyValues({"KEYCODE":"DOWN"})) - xFloatWindow.executeAction("TYPE", mkPropertyValues({"KEYCODE":"RETURN"})) + xMenu = xFloatWindow.getChild("menu") + xMenu.executeAction("TYPE", mkPropertyValues({"KEYCODE":"DOWN"})) + xMenu.executeAction("TYPE", mkPropertyValues({"KEYCODE":"DOWN"})) + xMenu.executeAction("TYPE", mkPropertyValues({"KEYCODE":"DOWN"})) + xMenu.executeAction("TYPE", mkPropertyValues({"KEYCODE":"DOWN"})) + xMenu.executeAction("TYPE", mkPropertyValues({"KEYCODE":"RETURN"})) #Nothing should change self.check_values(document, default_values) diff --git a/sc/source/ui/Accessibility/AccessibleFilterMenu.cxx b/sc/source/ui/Accessibility/AccessibleFilterMenu.cxx deleted file mode 100644 index 48149e53d69c..000000000000 --- a/sc/source/ui/Accessibility/AccessibleFilterMenu.cxx +++ /dev/null @@ -1,331 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <AccessibleGlobal.hxx> -#include <AccessibleFilterMenu.hxx> -#include <AccessibleFilterMenuItem.hxx> - -#include <o3tl/safeint.hxx> -#include <tools/gen.hxx> -#include <checklistmenu.hxx> - -#include <com/sun/star/accessibility/AccessibleRole.hpp> -#include <com/sun/star/accessibility/AccessibleStateType.hpp> -#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> - -using namespace ::com::sun::star; -using namespace ::com::sun::star::accessibility; -using namespace ::com::sun::star::accessibility::AccessibleStateType; - -using ::com::sun::star::uno::Any; -using ::com::sun::star::uno::Reference; -using ::com::sun::star::uno::Sequence; -using ::com::sun::star::uno::UNO_QUERY; -using ::com::sun::star::lang::IndexOutOfBoundsException; -using ::std::for_each; - -namespace { - -class AddRemoveEventListener -{ -public: - explicit AddRemoveEventListener(const Reference<XAccessibleEventListener>& rListener, bool bAdd) : - mxListener(rListener), mbAdd(bAdd) {} - - void operator() (const Reference<XAccessible>& xAccessible) const - { - if (!xAccessible.is()) - return; - - Reference<XAccessibleEventBroadcaster> xBc(xAccessible, UNO_QUERY); - if (xBc.is()) - { - if (mbAdd) - xBc->addAccessibleEventListener(mxListener); - else - xBc->removeAccessibleEventListener(mxListener); - } - } -private: - Reference<XAccessibleEventListener> mxListener; - bool mbAdd; -}; - -} - -ScAccessibleFilterMenu::ScAccessibleFilterMenu(const Reference<XAccessible>& rxParent, ScMenuFloatingWindow* pWin, const OUString& rName, size_t nMenuPos) : - ScAccessibleContextBase(rxParent, AccessibleRole::MENU), - mnMenuPos(nMenuPos), - mpWindow(pWin) -{ - SetName(rName); -} - -ScAccessibleFilterMenu::~ScAccessibleFilterMenu() -{ -} - -// XAccessibleComponent - -Reference<XAccessible> ScAccessibleFilterMenu::getAccessibleAtPoint( const css::awt::Point& /*rPoint*/ ) -{ - return this; -} - -bool ScAccessibleFilterMenu::isVisible() -{ - return mpWindow->IsVisible(); -} - -void ScAccessibleFilterMenu::grabFocus() -{ -} - -sal_Int32 ScAccessibleFilterMenu::getForeground() -{ - return 0; -} - -sal_Int32 ScAccessibleFilterMenu::getBackground() -{ - return 0; -} - -// XAccessibleContext - -sal_Int32 ScAccessibleFilterMenu::getAccessibleChildCount() -{ - return getMenuItemCount(); -} - -Reference<XAccessible> ScAccessibleFilterMenu::getAccessibleChild(sal_Int32 nIndex) -{ - if (maMenuItems.size() <= o3tl::make_unsigned(nIndex)) - throw IndexOutOfBoundsException(); - - return maMenuItems[nIndex]; -} - -Reference<XAccessibleStateSet> ScAccessibleFilterMenu::getAccessibleStateSet() -{ - updateStates(); - return mxStateSet; -} - -OUString ScAccessibleFilterMenu::getImplementationName() -{ - return "ScAccessibleFilterMenu"; -} - -// XAccessibleEventBroadcaster - -void ScAccessibleFilterMenu::addAccessibleEventListener( - const css::uno::Reference<css::accessibility::XAccessibleEventListener>& xListener) -{ - ScAccessibleContextBase::addAccessibleEventListener(xListener); - for_each(maMenuItems.begin(), maMenuItems.end(), AddRemoveEventListener(xListener, true)); -} - -void ScAccessibleFilterMenu::removeAccessibleEventListener( - const css::uno::Reference<css::accessibility::XAccessibleEventListener>& xListener) -{ - ScAccessibleContextBase::removeAccessibleEventListener(xListener); - for_each(maMenuItems.begin(), maMenuItems.end(), AddRemoveEventListener(xListener, false)); -} - -// XAccessibleSelection - -void ScAccessibleFilterMenu::selectAccessibleChild(sal_Int32 nChildIndex) -{ - if (o3tl::make_unsigned(nChildIndex) >= maMenuItems.size()) - throw IndexOutOfBoundsException(); - - mpWindow->setSelectedMenuItem(nChildIndex, false, true); -} - -sal_Bool ScAccessibleFilterMenu::isAccessibleChildSelected(sal_Int32 nChildIndex) -{ - if (o3tl::make_unsigned(nChildIndex) >= maMenuItems.size()) - throw IndexOutOfBoundsException(); - - return mpWindow->isMenuItemSelected(static_cast<size_t>(nChildIndex)); -} - -void ScAccessibleFilterMenu::clearAccessibleSelection() -{ - mpWindow->clearSelectedMenuItem(); -} - -void ScAccessibleFilterMenu::selectAllAccessibleChildren() -{ - // not supported - this is a menu, you can't select all menu items. -} - -sal_Int32 ScAccessibleFilterMenu::getSelectedAccessibleChildCount() -{ - // Since this is a menu, either one menu item is selected, or none at all. - return mpWindow->getSelectedMenuItem() == ScMenuFloatingWindow::MENU_NOT_SELECTED ? 0 : 1; -} - -Reference<XAccessible> ScAccessibleFilterMenu::getSelectedAccessibleChild(sal_Int32 nChildIndex) -{ - if (o3tl::make_unsigned(nChildIndex) >= maMenuItems.size()) - throw IndexOutOfBoundsException(); - - return maMenuItems[nChildIndex]; -} - -void ScAccessibleFilterMenu::deselectAccessibleChild(sal_Int32 nChildIndex) -{ - if (o3tl::make_unsigned(nChildIndex) >= maMenuItems.size()) - throw IndexOutOfBoundsException(); - - mpWindow->selectMenuItem(nChildIndex, false, false); -} - -// XInterface - -uno::Any SAL_CALL ScAccessibleFilterMenu::queryInterface( uno::Type const & rType ) -{ - Any any = ScAccessibleContextBase::queryInterface(rType); - if (any.hasValue()) - return any; - - return ScAccessibleFilterMenu_BASE::queryInterface(rType); -} - -void SAL_CALL ScAccessibleFilterMenu::acquire() throw () -{ - ScAccessibleContextBase::acquire(); -} - -void SAL_CALL ScAccessibleFilterMenu::release() throw () -{ - ScAccessibleContextBase::release(); -} - -// XTypeProvider - -Sequence<sal_Int8> ScAccessibleFilterMenu::getImplementationId() -{ - return css::uno::Sequence<sal_Int8>(); -} - -tools::Rectangle ScAccessibleFilterMenu::GetBoundingBoxOnScreen() const -{ - if (mnMenuPos == ScMenuFloatingWindow::MENU_NOT_SELECTED) - return tools::Rectangle(); - - // Menu object's bounding box is the bounding box of the menu item that - // launches the menu, which belongs to the parent window. - ScMenuFloatingWindow* pParentWin = mpWindow->getParentMenuWindow(); - if (!pParentWin) - return tools::Rectangle(); - - if (!pParentWin->IsVisible()) - return tools::Rectangle(); - - Point aPos = pParentWin->OutputToAbsoluteScreenPixel(Point(0,0)); - Point aMenuPos; - Size aMenuSize; - pParentWin->getMenuItemPosSize(mnMenuPos, aMenuPos, aMenuSize); - tools::Rectangle aRect(aPos + aMenuPos, aMenuSize); - return aRect; -} - -tools::Rectangle ScAccessibleFilterMenu::GetBoundingBox() const -{ - if (mnMenuPos == ScMenuFloatingWindow::MENU_NOT_SELECTED) - return tools::Rectangle(); - - // Menu object's bounding box is the bounding box of the menu item that - // launches the menu, which belongs to the parent window. - ScMenuFloatingWindow* pParentWin = mpWindow->getParentMenuWindow(); - if (!pParentWin) - return tools::Rectangle(); - - if (!pParentWin->IsVisible()) - return tools::Rectangle(); - - Point aMenuPos; - Size aMenuSize; - pParentWin->getMenuItemPosSize(mnMenuPos, aMenuPos, aMenuSize); - tools::Rectangle aRect(aMenuPos, aMenuSize); - return aRect; -} - -void ScAccessibleFilterMenu::appendMenuItem(const OUString& rName, size_t nMenuPos) -{ - // Check whether this menu item is a sub menu or a regular menu item. - ScMenuFloatingWindow* pSubMenu = mpWindow->getSubMenuWindow(nMenuPos); - Reference<XAccessible> xAccessible; - if (pSubMenu) - { - xAccessible = pSubMenu->CreateAccessible(); - ScAccessibleFilterMenu* p = - static_cast<ScAccessibleFilterMenu*>(xAccessible.get()); - p->setMenuPos(nMenuPos); - } - else - { - xAccessible.set(new ScAccessibleFilterMenuItem(this, mpWindow, rName, nMenuPos)); - } - maMenuItems.push_back(xAccessible); -} - -void ScAccessibleFilterMenu::setMenuPos(size_t nMenuPos) -{ - mnMenuPos = nMenuPos; -} - -sal_Int32 ScAccessibleFilterMenu::getMenuItemCount() const -{ - return maMenuItems.size(); -} - -bool ScAccessibleFilterMenu::isSelected() const -{ - // Check to see if any of the child menu items is selected. - return mpWindow->isMenuItemSelected(mnMenuPos); -} - -void ScAccessibleFilterMenu::updateStates() -{ - if (!mxStateSet.is()) - mxStateSet.set(new ScAccessibleStateSet); - - ScAccessibleStateSet* p = static_cast<ScAccessibleStateSet*>( - mxStateSet.get()); - - p->clear(); - - p->insert(ENABLED); - p->insert(FOCUSABLE); - p->insert(SELECTABLE); - p->insert(SENSITIVE); - p->insert(OPAQUE); - - if (isSelected()) - p->insert(FOCUSED); - - if (isSelected()) - p->insert(SELECTED); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/Accessibility/AccessibleFilterMenuItem.cxx b/sc/source/ui/Accessibility/AccessibleFilterMenuItem.cxx deleted file mode 100644 index 71b63fb76a70..000000000000 --- a/sc/source/ui/Accessibility/AccessibleFilterMenuItem.cxx +++ /dev/null @@ -1,166 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <AccessibleGlobal.hxx> -#include <AccessibleFilterMenuItem.hxx> -#include <checklistmenu.hxx> - -#include <com/sun/star/accessibility/AccessibleRole.hpp> -#include <com/sun/star/accessibility/AccessibleStateType.hpp> -#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> - -using namespace ::com::sun::star; -using namespace ::com::sun::star::accessibility; -using namespace ::com::sun::star::accessibility::AccessibleStateType; - -using ::com::sun::star::uno::Any; -using ::com::sun::star::uno::Reference; -using ::com::sun::star::lang::IndexOutOfBoundsException; - -ScAccessibleFilterMenuItem::ScAccessibleFilterMenuItem( - const Reference<XAccessible>& rxParent, ScMenuFloatingWindow* pWin, const OUString& rName, size_t nMenuPos) : - ScAccessibleContextBase(rxParent, AccessibleRole::MENU_ITEM), - mpWindow(pWin), - mnMenuPos(nMenuPos) -{ - SetName(rName); -} - -ScAccessibleFilterMenuItem::~ScAccessibleFilterMenuItem() -{ -} - -sal_Int32 ScAccessibleFilterMenuItem::getAccessibleChildCount() -{ - return 0; -} - -Reference<XAccessible> ScAccessibleFilterMenuItem::getAccessibleChild(sal_Int32 /*nIndex*/) -{ - throw IndexOutOfBoundsException(); -} - -Reference<XAccessibleStateSet> ScAccessibleFilterMenuItem::getAccessibleStateSet() -{ - updateStateSet(); - return mxStateSet; -} - -OUString ScAccessibleFilterMenuItem::getImplementationName() -{ - return "ScAccessibleFilterMenuItem"; -} - -// XAccessibleAction - -sal_Int32 ScAccessibleFilterMenuItem::getAccessibleActionCount() -{ - return 1; -} - -sal_Bool ScAccessibleFilterMenuItem::doAccessibleAction(sal_Int32 /*nIndex*/) -{ - mpWindow->executeMenuItem(mnMenuPos); - return true; -} - -OUString ScAccessibleFilterMenuItem::getAccessibleActionDescription(sal_Int32 /*nIndex*/) -{ - return "click"; -} - -Reference<XAccessibleKeyBinding> ScAccessibleFilterMenuItem::getAccessibleActionKeyBinding( - sal_Int32 /*nIndex*/) -{ - return Reference<XAccessibleKeyBinding>(); -} - -Any SAL_CALL ScAccessibleFilterMenuItem::queryInterface( uno::Type const & rType ) -{ - Any any = ScAccessibleContextBase::queryInterface(rType); - if (any.hasValue()) - return any; - - return ScAccessibleFilterMenuItem_BASE::queryInterface(rType); -} - -void SAL_CALL ScAccessibleFilterMenuItem::acquire() throw () -{ - ScAccessibleContextBase::acquire(); -} - -void SAL_CALL ScAccessibleFilterMenuItem::release() throw () -{ - ScAccessibleContextBase::release(); -} - -bool ScAccessibleFilterMenuItem::isSelected() const -{ - return mpWindow->isMenuItemSelected(mnMenuPos); -} - -tools::Rectangle ScAccessibleFilterMenuItem::GetBoundingBoxOnScreen() const -{ - if (!mpWindow->IsVisible()) - return tools::Rectangle(); - - Point aPos = mpWindow->OutputToAbsoluteScreenPixel(Point(0,0)); - Point aMenuPos; - Size aMenuSize; - mpWindow->getMenuItemPosSize(mnMenuPos, aMenuPos, aMenuSize); - tools::Rectangle aRect(aPos + aMenuPos, aMenuSize); - return aRect; -} - -tools::Rectangle ScAccessibleFilterMenuItem::GetBoundingBox() const -{ - if (!mpWindow->IsVisible()) - return tools::Rectangle(); - - Point aMenuPos; - Size aMenuSize; - mpWindow->getMenuItemPosSize(mnMenuPos, aMenuPos, aMenuSize); - tools::Rectangle aRect(aMenuPos, aMenuSize); - return aRect; -} - -void ScAccessibleFilterMenuItem::updateStateSet() -{ - if (!mxStateSet.is()) - mxStateSet.set(new ScAccessibleStateSet); - - ScAccessibleStateSet* p = static_cast<ScAccessibleStateSet*>( - mxStateSet.get()); - - p->clear(); - - p->insert(ENABLED); - p->insert(FOCUSABLE); - p->insert(SELECTABLE); - p->insert(SENSITIVE); - p->insert(OPAQUE); - - if (isSelected()) - p->insert(FOCUSED); - - if (isSelected()) - p->insert(SELECTED); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/Accessibility/AccessibleFilterTopWindow.cxx b/sc/source/ui/Accessibility/AccessibleFilterTopWindow.cxx deleted file mode 100644 index da8cefdb04c2..000000000000 --- a/sc/source/ui/Accessibility/AccessibleFilterTopWindow.cxx +++ /dev/null @@ -1,118 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <AccessibleFilterTopWindow.hxx> -#include <AccessibleFilterMenu.hxx> -#include <checklistmenu.hxx> - -#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> - -using namespace ::com::sun::star; -using namespace ::com::sun::star::accessibility; -using ::com::sun::star::lang::IndexOutOfBoundsException; -using ::com::sun::star::uno::Reference; - -ScAccessibleFilterTopWindow::ScAccessibleFilterTopWindow( - const Reference<XAccessible>& rxParent, ScCheckListMenuWindow* pWin, const OUString& rName) : - ScAccessibleFilterMenu(rxParent, pWin, rName, ScMenuFloatingWindow::MENU_NOT_SELECTED) -{ - SetName(rName); -} - -ScAccessibleFilterTopWindow::~ScAccessibleFilterTopWindow() -{ -} - -// XAccessibleContext - -sal_Int32 ScAccessibleFilterTopWindow::getAccessibleChildCount() -{ - sal_Int32 nMenuCount = getMenuItemCount(); - return nMenuCount + 6; -} - -Reference<XAccessible> ScAccessibleFilterTopWindow::getAccessibleChild( - sal_Int32 nIndex) -{ - if (nIndex >= getAccessibleChildCount()) - throw IndexOutOfBoundsException(); - - sal_Int32 nMenuCount = getMenuItemCount(); - if (nIndex < nMenuCount) - return ScAccessibleFilterMenu::getAccessibleChild(nIndex); - - nIndex -= nMenuCount; - switch (nIndex) - { - case 0: - return mxAccEditSearchBox; - case 1: - return mxAccListBox; - case 2: - return mxAccToggleAll; - case 3: - return mxAccSingleOnBtn; - case 4: - return mxAccSingleOffBtn; - case 5: - return mxAccOkBtn; - case 6: - return mxAccCancelBtn; - default: - ; - } - - return Reference<XAccessible>(); -} - -OUString ScAccessibleFilterTopWindow::getImplementationName() -{ - return "ScAccessibleFilterTopWindow"; -} - -void ScAccessibleFilterTopWindow::setAccessibleChild( - const Reference<XAccessible>& rAccessible, ChildControlType eType) -{ - switch (eType) - { - case EDIT_SEARCH_BOX: - mxAccEditSearchBox = rAccessible; - break; - case LISTBOX: - mxAccListBox = rAccessible; - break; - case TOGGLE_ALL: - mxAccToggleAll = rAccessible; - break; - case SINGLE_ON_BTN: - mxAccSingleOnBtn = rAccessible; - break; - case SINGLE_OFF_BTN: - mxAccSingleOffBtn = rAccessible; - break; - case OK_BTN: - mxAccOkBtn = rAccessible; - break; - case CANCEL_BTN: - mxAccCancelBtn = rAccessible; - break; - } -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/app/inputwin.cxx b/sc/source/ui/app/inputwin.cxx index cb2b00b51d58..58a8a9e861d1 100644 --- a/sc/source/ui/app/inputwin.cxx +++ b/sc/source/ui/app/inputwin.cxx @@ -39,6 +39,7 @@ #include <editeng/scriptspaceitem.hxx> #include <vcl/commandevent.hxx> #include <vcl/cursor.hxx> +#include <vcl/edit.hxx> #include <vcl/help.hxx> #include <vcl/settings.hxx> #include <svl/stritem.hxx> diff --git a/sc/source/ui/cctrl/checklistmenu.cxx b/sc/source/ui/cctrl/checklistmenu.cxx index 27976641e37d..0739b81457db 100644 --- a/sc/source/ui/cctrl/checklistmenu.cxx +++ b/sc/source/ui/cctrl/checklistmenu.cxx @@ -25,438 +25,177 @@ #include <vcl/decoview.hxx> #include <vcl/event.hxx> +#include <vcl/floatwin.hxx> #include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <vcl/virdev.hxx> #include <rtl/math.hxx> #include <tools/wintypes.hxx> #include <unotools/charclass.hxx> -#include <AccessibleFilterMenu.hxx> -#include <AccessibleFilterTopWindow.hxx> - -#include <com/sun/star/accessibility/XAccessible.hpp> -#include <com/sun/star/accessibility/XAccessibleContext.hpp> -#include <vcl/svlbitm.hxx> -#include <vcl/treelistentry.hxx> #include <document.hxx> using namespace com::sun::star; using ::com::sun::star::uno::Reference; -using ::com::sun::star::accessibility::XAccessible; -using ::com::sun::star::accessibility::XAccessibleContext; -ScMenuFloatingWindow::MenuItemData::MenuItemData() : - mbEnabled(true), mbSeparator(false), - mpSubMenuWin(static_cast<ScMenuFloatingWindow*>(nullptr)) +ScCheckListMenuControl::MenuItemData::MenuItemData() + : mbEnabled(true) + , mbSeparator(false) { } -ScMenuFloatingWindow::SubMenuItemData::SubMenuItemData(ScMenuFloatingWindow* pParent) : - mpSubMenu(nullptr), - mnMenuPos(MENU_NOT_SELECTED), - mpParent(pParent) +ScCheckListMenuControl::SubMenuItemData::SubMenuItemData(ScCheckListMenuControl* pParent) + : mpSubMenu(nullptr) + , mnMenuPos(MENU_NOT_SELECTED) + , mpParent(pParent) { - maTimer.SetInvokeHandler( LINK(this, ScMenuFloatingWindow::SubMenuItemData, TimeoutHdl) ); - maTimer.SetTimeout(mpParent->GetSettings().GetMouseSettings().GetMenuDelay()); + maTimer.SetInvokeHandler(LINK(this, ScCheckListMenuControl::SubMenuItemData, TimeoutHdl)); + maTimer.SetTimeout(Application::GetSettings().GetMouseSettings().GetMenuDelay()); } -void ScMenuFloatingWindow::SubMenuItemData::reset() +void ScCheckListMenuControl::SubMenuItemData::reset() { mpSubMenu = nullptr; mnMenuPos = MENU_NOT_SELECTED; maTimer.Stop(); } -IMPL_LINK_NOARG(ScMenuFloatingWindow::SubMenuItemData, TimeoutHdl, Timer *, void) +IMPL_LINK_NOARG(ScCheckListMenuControl::SubMenuItemData, TimeoutHdl, Timer *, void) { mpParent->handleMenuTimeout(this); } -ScMenuFloatingWindow::ScMenuFloatingWindow(vcl::Window* pParent, ScDocument* pDoc, sal_uInt16 nMenuStackLevel) : - PopupMenuFloatingWindow(pParent), - maOpenTimer(this), - maCloseTimer(this), - maName("ScMenuFloatingWindow"), - mnSelectedMenu(MENU_NOT_SELECTED), - mnClickedMenu(MENU_NOT_SELECTED), - mpDoc(pDoc), - mpParentMenu(dynamic_cast<ScMenuFloatingWindow*>(pParent)) -{ - SetMenuStackLevel(nMenuStackLevel); - SetText("ScMenuFloatingWindow"); - - const StyleSettings& rStyle = GetSettings().GetStyleSettings(); - - const sal_uInt16 nPopupFontHeight = 12 * GetDPIScaleFactor(); - maLabelFont = rStyle.GetLabelFont(); - maLabelFont.SetFontHeight(nPopupFontHeight); -} - -ScMenuFloatingWindow::~ScMenuFloatingWindow() -{ - disposeOnce(); -} - -void ScMenuFloatingWindow::dispose() -{ - EndPopupMode(); - for (auto& rMenuItem : maMenuItems) - rMenuItem.mpSubMenuWin.disposeAndClear(); - mpParentMenu.clear(); - PopupMenuFloatingWindow::dispose(); -} - -void ScMenuFloatingWindow::PopupModeEnd() -{ - handlePopupEnd(); -} - -void ScMenuFloatingWindow::MouseMove(const MouseEvent& rMEvt) -{ - const Point& rPos = rMEvt.GetPosPixel(); - size_t nSelectedMenu = getEnclosingMenuItem(rPos); - setSelectedMenuItem(nSelectedMenu, true, false); - - Window::MouseMove(rMEvt); -} - -void ScMenuFloatingWindow::MouseButtonDown(const MouseEvent& rMEvt) +IMPL_LINK_NOARG(ScCheckListMenuControl, RowActivatedHdl, weld::TreeView&, bool) { - const Point& rPos = rMEvt.GetPosPixel(); - mnClickedMenu = getEnclosingMenuItem(rPos); - Window::MouseButtonDown(rMEvt); + executeMenuItem(mxMenu->get_selected_index()); + return true; } -void ScMenuFloatingWindow::MouseButtonUp(const MouseEvent& rMEvt) +IMPL_LINK(ScCheckListMenuControl, MenuKeyInputHdl, const KeyEvent&, rKEvt, bool) { - executeMenuItem(mnClickedMenu); - mnClickedMenu = MENU_NOT_SELECTED; - Window::MouseButtonUp(rMEvt); -} - -void ScMenuFloatingWindow::KeyInput(const KeyEvent& rKEvt) -{ - if (maMenuItems.empty()) - { - Window::KeyInput(rKEvt); - return; - } - const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode(); - bool bHandled = true; - size_t nSelectedMenu = mnSelectedMenu; - size_t nLastMenuPos = maMenuItems.size() - 1; + switch (rKeyCode.GetCode()) { - case KEY_UP: + case KEY_LEFT: { - if (nLastMenuPos == 0) - // There is only one menu item. Do nothing. - break; - - size_t nOldPos = nSelectedMenu; - - if (nSelectedMenu == MENU_NOT_SELECTED || nSelectedMenu == 0) - nSelectedMenu = nLastMenuPos; - else - --nSelectedMenu; - - // Loop until a non-separator menu item is found. - while (nSelectedMenu != nOldPos) - { - if (maMenuItems[nSelectedMenu].mbSeparator) - { - if (nSelectedMenu) - --nSelectedMenu; - else - nSelectedMenu = nLastMenuPos; - } - else - break; - } - - setSelectedMenuItem(nSelectedMenu, false, false); + ScCheckListMenuWindow* pParentMenu = mxFrame->GetParentMenu(); + if (pParentMenu) + pParentMenu->get_widget().endSubMenu(*this); + break; } - break; - case KEY_DOWN: - { - if (nLastMenuPos == 0) - // There is only one menu item. Do nothing. - break; - - size_t nOldPos = nSelectedMenu; - - if (nSelectedMenu == MENU_NOT_SELECTED || nSelectedMenu == nLastMenuPos) - nSelectedMenu = 0; - else - ++nSelectedMenu; - - // Loop until a non-separator menu item is found. - while (nSelectedMenu != nOldPos) - { - if (maMenuItems[nSelectedMenu].mbSeparator) - { - if (nSelectedMenu == nLastMenuPos) - nSelectedMenu = 0; - else - ++nSelectedMenu; - } - else - break; - } - - setSelectedMenuItem(nSelectedMenu, false, false); - } - break; - case KEY_LEFT: - if (mpParentMenu) - mpParentMenu->endSubMenu(this); - break; case KEY_RIGHT: { if (mnSelectedMenu >= maMenuItems.size() || mnSelectedMenu == MENU_NOT_SELECTED) break; const MenuItemData& rMenu = maMenuItems[mnSelectedMenu]; - if (!rMenu.mbEnabled || !rMenu.mpSubMenuWin) + if (!rMenu.mbEnabled || !rMenu.mxSubMenuWin) break; maOpenTimer.mnMenuPos = mnSelectedMenu; - maOpenTimer.mpSubMenu = rMenu.mpSubMenuWin.get(); + maOpenTimer.mpSubMenu = rMenu.mxSubMenuWin.get(); launchSubMenu(true); } - break; - case KEY_RETURN: - if (nSelectedMenu != MENU_NOT_SELECTED) - executeMenuItem(nSelectedMenu); - break; - default: - bHandled = false; } - if (!bHandled) - Window::KeyInput(rKEvt); + return false; } -void ScMenuFloatingWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/) +IMPL_LINK_NOARG(ScCheckListMenuControl, SelectHdl, weld::TreeView&, void) { - const StyleSettings& rStyle = GetSettings().GetStyleSettings(); - - SetFont(maLabelFont); - - Color aBackColor = rStyle.GetMenuColor(); - Color aBorderColor = rStyle.GetShadowColor(); - - tools::Rectangle aCtrlRect(Point(0, 0), GetOutputSizePixel()); - - // Window background - bool bNativeDrawn = true; - if (rRenderContext.IsNativeControlSupported(ControlType::MenuPopup, ControlPart::Entire)) + sal_uInt32 nSelectedMenu = MENU_NOT_SELECTED; + if (!mxMenu->get_selected(mxScratchIter.get())) { - rRenderContext.SetClipRegion(); - bNativeDrawn = rRenderContext.DrawNativeControl(ControlType::MenuPopup, ControlPart::Entire, aCtrlRect, - ControlState::ENABLED, ImplControlValue(), OUString()); - } - else - bNativeDrawn = false; - - if (!bNativeDrawn) - { - rRenderContext.SetFillColor(aBackColor); - rRenderContext.SetLineColor(aBorderColor); - rRenderContext.DrawRect(aCtrlRect); - } - - // Menu items - rRenderContext.SetTextColor(rStyle.GetMenuTextColor()); - drawAllMenuItems(rRenderContext); -} - -Reference<XAccessible> ScMenuFloatingWindow::CreateAccessible() -{ - if (!mxAccessible.is()) - { - Reference<XAccessible> xAccParent = mpParentMenu ? - mpParentMenu->GetAccessible() : GetAccessibleParentWindow()->GetAccessible(); - - mxAccessible.set(new ScAccessibleFilterMenu(xAccParent, this, maName, 999)); - ScAccessibleFilterMenu* p = static_cast<ScAccessibleFilterMenu*>( - mxAccessible.get()); - - size_t nPos = 0; - for (const auto& rMenuItem : maMenuItems) + // reselect current item if its submenu is up and the launching item + // became unselected + if (mnSelectedMenu < maMenuItems.size() && + maMenuItems[mnSelectedMenu].mxSubMenuWin && + maMenuItems[mnSelectedMenu].mxSubMenuWin->IsVisible()) { - p->appendMenuItem(rMenuItem.maText, nPos); - ++nPos; + mxMenu->select(mnSelectedMenu); + return; } } + else + nSelectedMenu = mxMenu->get_iter_index_in_parent(*mxScratchIter); - return mxAccessible; + setSelectedMenuItem(nSelectedMenu, true, false); } -void ScMenuFloatingWindow::addMenuItem(const OUString& rText, Action* pAction) +void ScCheckListMenuControl::addMenuItem(const OUString& rText, Action* pAction) { MenuItemData aItem; aItem.maText = rText; aItem.mbEnabled = true; - aItem.mpAction.reset(pAction); - maMenuItems.push_back(aItem); + aItem.mxAction.reset(pAction); + maMenuItems.emplace_back(std::move(aItem)); + + mxMenu->append_text(rText); + if (mbCanHaveSubMenu) + mxMenu->set_image(mxMenu->n_children() - 1, css::uno::Reference<css::graphic::XGraphic>(), 1); } -void ScMenuFloatingWindow::addSeparator() +void ScCheckListMenuControl::addSeparator() { MenuItemData aItem; aItem.mbSeparator = true; - maMenuItems.push_back(aItem); -} + maMenuItems.emplace_back(std::move(aItem)); -ScMenuFloatingWindow* ScMenuFloatingWindow::addSubMenuItem(const OUString& rText, bool bEnabled) -{ - MenuItemData aItem; - aItem.maText = rText; - aItem.mbEnabled = bEnabled; - aItem.mpSubMenuWin.reset(VclPtr<ScMenuFloatingWindow>::Create(this, mpDoc, GetMenuStackLevel()+1)); - aItem.mpSubMenuWin->setName(rText); - maMenuItems.push_back(aItem); - return aItem.mpSubMenuWin.get(); + mxMenu->append_separator("seperator" + OUString::number(maMenuItems.size())); } -void ScMenuFloatingWindow::handlePopupEnd() +IMPL_LINK(ScCheckListMenuControl, TreeSizeAllocHdl, const Size&, rSize, void) { - clearSelectedMenuItem(); + assert(mbCanHaveSubMenu); + std::vector<int> aWidths; + aWidths.push_back(rSize.Width() - (mxMenu->get_text_height() * 3) / 4 - 6); + mxMenu->set_column_fixed_widths(aWidths); } -Size ScMenuFloatingWindow::getMenuSize() const +void ScCheckListMenuControl::CreateDropDown() { - if (maMenuItems.empty()) - return Size(); - - auto itr = std::max_element(maMenuItems.begin(), maMenuItems.end(), - [this](const MenuItemData& a, const MenuItemData& b) { - long aTextWidth = a.mbSeparator ? 0 : GetTextWidth(a.maText); - long bTextWidth = b.mbSeparator ? 0 : GetTextWidth(b.maText); - return aTextWidth < bTextWidth; - }); - long nTextWidth = itr->mbSeparator ? 0 : GetTextWidth(itr->maText); - - size_t nLastPos = maMenuItems.size()-1; - Point aPos; - Size aSize; - getMenuItemPosSize(nLastPos, aPos, aSize); - aPos.AdjustX(nTextWidth + 15 ); - aPos.AdjustY(aSize.Height() + 5 ); - return Size(aPos.X(), aPos.Y()); + int nWidth = (mxMenu->get_text_height() * 3) / 4; + mxDropDown->SetOutputSizePixel(Size(nWidth, nWidth)); + DecorationView aDecoView(mxDropDown.get()); + aDecoView.DrawSymbol(tools::Rectangle(Point(0, 0), Size(nWidth, nWidth)), + SymbolType::SPIN_RIGHT, mxDropDown->GetTextColor(), + DrawSymbolFlags::NONE); } -void ScMenuFloatingWindow::drawMenuItem(vcl::RenderContext& rRenderContext, size_t nPos) +ScCheckListMenuWindow* ScCheckListMenuControl::addSubMenuItem(const OUString& rText, bool bEnabled) { - if (nPos >= maMenuItems.size()) - return; - - Point aPos; - Size aSize; - getMenuItemPosSize(nPos, aPos, aSize); - - DecorationView aDecoView(&rRenderContext); - long const nXOffset = 5; - long nYOffset = (aSize.Height() - maLabelFont.GetFontHeight())/2; - - // Make sure the label font is used for the menu item text. - rRenderContext.Push(PushFlags::FONT); - rRenderContext.SetFont(maLabelFont); - rRenderContext. DrawCtrlText(Point(aPos.X()+nXOffset, aPos.Y() + nYOffset), maMenuItems[nPos].maText, 0, - maMenuItems[nPos].maText.getLength(), - maMenuItems[nPos].mbEnabled ? DrawTextFlags::Mnemonic : DrawTextFlags::Disable); - rRenderContext.Pop(); - - if (maMenuItems[nPos].mpSubMenuWin) - { - long nFontHeight = maLabelFont.GetFontHeight(); - Point aMarkerPos = aPos; - aMarkerPos.AdjustY(aSize.Height() / 2 - nFontHeight / 4 + 1 ); - aMarkerPos.AdjustX(aSize.Width() - nFontHeight + nFontHeight / 4 ); - Size aMarkerSize(nFontHeight / 2, nFontHeight / 2); - aDecoView.DrawSymbol(tools::Rectangle(aMarkerPos, aMarkerSize), SymbolType::SPIN_RIGHT, GetTextColor()); - } -} - -void ScMenuFloatingWindow::drawSeparator(vcl::RenderContext& rRenderContext, size_t nPos) -{ - Point aPos; - Size aSize; - getMenuItemPosSize(nPos, aPos, aSize); - tools::Rectangle aRegion(aPos,aSize); - - if (rRenderContext.IsNativeControlSupported(ControlType::MenuPopup, ControlPart::Entire)) - { - rRenderContext.Push(PushFlags::CLIPREGION); - rRenderContext.IntersectClipRegion(aRegion); - tools::Rectangle aCtrlRect(Point(0,0), GetOutputSizePixel()); - rRenderContext.DrawNativeControl(ControlType::MenuPopup, ControlPart::Entire, aCtrlRect, - ControlState::ENABLED, ImplControlValue(), OUString()); - - rRenderContext.Pop(); - } + assert(mbCanHaveSubMenu); - bool bNativeDrawn = false; - if (rRenderContext.IsNativeControlSupported(ControlType::MenuPopup, ControlPart::Separator)) - { - ControlState nState = ControlState::NONE; - const MenuItemData& rData = maMenuItems[nPos]; - if (rData.mbEnabled) - nState |= ControlState::ENABLED; - - bNativeDrawn = rRenderContext.DrawNativeControl(ControlType::MenuPopup, ControlPart::Separator, - aRegion, nState, ImplControlValue(), OUString()); - } - - if (!bNativeDrawn) - { - const StyleSettings& rStyle = rRenderContext.GetSettings().GetStyleSettings(); - Point aTmpPos = aPos; - aTmpPos.AdjustY(aSize.Height() / 2 ); - rRenderContext.SetLineColor(rStyle.GetShadowColor()); - rRenderContext.DrawLine(aTmpPos, Point(aSize.Width() + aTmpPos.X(), aTmpPos.Y())); - aTmpPos.AdjustY( 1 ); - rRenderContext.SetLineColor(rStyle.GetLightColor()); - rRenderContext.DrawLine(aTmpPos, Point(aSize.Width() + aTmpPos.X(), aTmpPos.Y())); - rRenderContext.SetLineColor(); - } -} + MenuItemData aItem; + aItem.maText = rText; + aItem.mbEnabled = bEnabled; + vcl::Window *pContainer = mxFrame->GetWindow(GetWindowType::FirstChild); + aItem.mxSubMenuWin.reset(VclPtr<ScCheckListMenuWindow>::Create(pContainer, mpDoc, false, -1, mxFrame->GetMenuStackLevel()+1, mxFrame.get())); + maMenuItems.emplace_back(std::move(aItem)); -void ScMenuFloatingWindow::drawAllMenuItems(vcl::RenderContext& rRenderContext) -{ - size_t n = maMenuItems.size(); + mxMenu->append_text(rText); + if (mbCanHaveSubMenu) + mxMenu->set_image(mxMenu->n_children() - 1, *mxDropDown, 1); - for (size_t i = 0; i < n; ++i) - { - if (maMenuItems[i].mbSeparator) - { - // Separator - drawSeparator(rRenderContext, i); - } - else - { - // Normal menu item - highlightMenuItem(rRenderContext, i, i == mnSelectedMenu); - } - } + return maMenuItems.back().mxSubMenuWin.get(); } -void ScMenuFloatingWindow::executeMenuItem(size_t nPos) +void ScCheckListMenuControl::executeMenuItem(size_t nPos) { if (nPos >= maMenuItems.size()) return; - if (!maMenuItems[nPos].mpAction) + if (!maMenuItems[nPos].mxAction) // no action is defined. return; terminateAllPopupMenus(); - maMenuItems[nPos].mpAction->execute(); + maMenuItems[nPos].mxAction->execute(); } -void ScMenuFloatingWindow::setSelectedMenuItem(size_t nPos, bool bSubMenuTimer, bool bEnsureSubMenu) +void ScCheckListMenuControl::setSelectedMenuItem(size_t nPos, bool bSubMenuTimer, bool bEnsureSubMenu) { if (mnSelectedMenu == nPos) // nothing to do. @@ -466,34 +205,24 @@ void ScMenuFloatingWindow::setSelectedMenuItem(size_t nPos, bool bSubMenuTimer, { // Dismiss any child popup menu windows. if (mnSelectedMenu < maMenuItems.size() && - maMenuItems[mnSelectedMenu].mpSubMenuWin && - maMenuItems[mnSelectedMenu].mpSubMenuWin->IsVisible()) + maMenuItems[mnSelectedMenu].mxSubMenuWin && + maMenuItems[mnSelectedMenu].mxSubMenuWin->IsVisible()) { - maMenuItems[mnSelectedMenu].mpSubMenuWin->ensureSubMenuNotVisible(); + maMenuItems[mnSelectedMenu].mxSubMenuWin->get_widget().ensureSubMenuNotVisible(); } - - // The popup is not visible, yet a menu item is selected. The request - // most likely comes from the accessible object. Make sure this - // window, as well as all its parent windows are visible. - if (!IsVisible() && mpParentMenu) - mpParentMenu->ensureSubMenuVisible(this); } - selectMenuItem(mnSelectedMenu, false, bSubMenuTimer); - selectMenuItem(nPos, true, bSubMenuTimer); - mnSelectedMenu = nPos; - - fireMenuHighlightedEvent(); + selectMenuItem(nPos, bSubMenuTimer); } -void ScMenuFloatingWindow::handleMenuTimeout(const SubMenuItemData* pTimer) +void ScCheckListMenuControl::handleMenuTimeout(const SubMenuItemData* pTimer) { if (pTimer == &maOpenTimer) { // Close any open submenu immediately. if (maCloseTimer.mpSubMenu) { - maCloseTimer.mpSubMenu->EndPopupMode(); + vcl::Window::GetDockingManager()->EndPopupMode(maCloseTimer.mpSubMenu); maCloseTimer.mpSubMenu = nullptr; maCloseTimer.maTimer.Stop(); } @@ -507,16 +236,15 @@ void ScMenuFloatingWindow::handleMenuTimeout(const SubMenuItemData* pTimer) { maOpenTimer.mpSubMenu = nullptr; - maCloseTimer.mpSubMenu->EndPopupMode(); + vcl::Window::GetDockingManager()->EndPopupMode(maCloseTimer.mpSubMenu); maCloseTimer.mpSubMenu = nullptr; - Invalidate(); maOpenTimer.mnMenuPos = MENU_NOT_SELECTED; } } } -void ScMenuFloatingWindow::queueLaunchSubMenu(size_t nPos, ScMenuFloatingWindow* pMenu) +void ScCheckListMenuControl::queueLaunchSubMenu(size_t nPos, ScCheckListMenuWindow* pMenu) { if (!pMenu) return; @@ -540,7 +268,7 @@ void ScMenuFloatingWindow::queueLaunchSubMenu(size_t nPos, ScMenuFloatingWindow* maOpenTimer.maTimer.Start(); } -void ScMenuFloatingWindow::queueCloseSubMenu() +void ScCheckListMenuControl::queueCloseSubMenu() { if (!maOpenTimer.mpSubMenu) // There is no submenu to close. @@ -554,61 +282,58 @@ void ScMenuFloatingWindow::queueCloseSubMenu() maCloseTimer.maTimer.Start(); } -void ScMenuFloatingWindow::launchSubMenu(bool bSetMenuPos) +void ScCheckListMenuControl::launchSubMenu(bool bSetMenuPos) { - Point aPos; - Size aSize; - getMenuItemPosSize(maOpenTimer.mnMenuPos, aPos, aSize); - ScMenuFloatingWindow* pSubMenu = maOpenTimer.mpSubMenu; - + ScCheckListMenuWindow* pSubMenu = maOpenTimer.mpSubMenu; if (!pSubMenu) return; - FloatWinPopupFlags nOldFlags = GetPopupModeFlags(); - SetPopupModeFlags(nOldFlags | FloatWinPopupFlags::NoAppFocusClose); - pSubMenu->resizeToFitMenuItems(); // set the size before launching the popup to get it positioned correctly. - pSubMenu->StartPopupMode( - tools::Rectangle(aPos,aSize), (FloatWinPopupFlags::Right | FloatWinPopupFlags::GrabFocus)); - pSubMenu->AddPopupModeWindow(this); + if (!mxMenu->get_selected(mxScratchIter.get())) + return; + + tools::Rectangle aRect = mxMenu->get_row_area(*mxScratchIter); + ScCheckListMenuControl& rSubMenuControl = pSubMenu->get_widget(); + rSubMenuControl.StartPopupMode(aRect, (FloatWinPopupFlags::Right | FloatWinPopupFlags::GrabFocus)); if (bSetMenuPos) - pSubMenu->setSelectedMenuItem(0, false, false); // select menu item after the popup becomes fully visible. - SetPopupModeFlags(nOldFlags); + rSubMenuControl.setSelectedMenuItem(0, false, false); // select menu item after the popup becomes fully visible. + + mxMenu->select(*mxScratchIter); + rSubMenuControl.GrabFocus(); } -void ScMenuFloatingWindow::endSubMenu(ScMenuFloatingWindow* pSubMenu) +IMPL_LINK_NOARG(ScCheckListMenuControl, PostPopdownHdl, void*, void) { - if (!pSubMenu) - return; + mnAsyncPostPopdownId = nullptr; + mxMenu->grab_focus(); +} - pSubMenu->EndPopupMode(); +void ScCheckListMenuControl::endSubMenu(ScCheckListMenuControl& rSubMenu) +{ + rSubMenu.EndPopupMode(); maOpenTimer.reset(); - size_t nMenuPos = getSubMenuPos(pSubMenu); + // EndPopup sends a user event, and we want this focus to be set after that has done its conflicting focus-setting work + if (!mnAsyncPostPopdownId) + mnAsyncPostPopdownId = Application::PostUserEvent(LINK(this, ScCheckListMenuControl, PostPopdownHdl)); + + size_t nMenuPos = getSubMenuPos(&rSubMenu); if (nMenuPos != MENU_NOT_SELECTED) { mnSelectedMenu = nMenuPos; - Invalidate(); - fireMenuHighlightedEvent(); + mxMenu->select(mnSelectedMenu); } } -void ScMenuFloatingWindow::fillMenuItemsToAccessible(ScAccessibleFilterMenu* pAccMenu) const +void ScCheckListMenuControl::resizeToFitMenuItems() { - size_t nPos = 0; - for (const auto& rMenuItem : maMenuItems) - { - pAccMenu->appendMenuItem(rMenuItem.maText, nPos); - ++nPos; - } + mxMenu->set_size_request(-1, mxMenu->get_preferred_size().Height() + 2); } -void ScMenuFloatingWindow::resizeToFitMenuItems() +void ScCheckListMenuControl::selectMenuItem(size_t nPos, bool bSubMenuTimer) { - SetOutputSizePixel(getMenuSize()); -} + mxMenu->select(nPos == MENU_NOT_SELECTED ? -1 : nPos); + mnSelectedMenu = nPos; -void ScMenuFloatingWindow::selectMenuItem(size_t nPos, bool bSelected, bool bSubMenuTimer) -{ if (nPos >= maMenuItems.size() || nPos == MENU_NOT_SELECTED) { queueCloseSubMenu(); @@ -621,18 +346,18 @@ void ScMenuFloatingWindow::selectMenuItem(size_t nPos, bool bSelected, bool bSub return; } - Invalidate(); - if (bSelected) + if (nPos != MENU_NOT_SELECTED) { - if (mpParentMenu) - mpParentMenu->setSubMenuFocused(this); + ScCheckListMenuWindow* pParentMenu = mxFrame->GetParentMenu(); + if (pParentMenu) + pParentMenu->get_widget().setSubMenuFocused(this); if (bSubMenuTimer) { - if (maMenuItems[nPos].mpSubMenuWin) + if (maMenuItems[nPos].mxSubMenuWin) { - ScMenuFloatingWindow* pSubMenu = maMenuItems[nPos].mpSubMenuWin.get(); + ScCheckListMenuWindow* pSubMenu = maMenuItems[nPos].mxSubMenuWin.get(); queueLaunchSubMenu(nPos, pSubMenu); } else @@ -641,209 +366,70 @@ void ScMenuFloatingWindow::selectMenuItem(size_t nPos, bool bSelected, bool bSub } } -void ScMenuFloatingWindow::clearSelectedMenuItem() +void ScCheckListMenuControl::clearSelectedMenuItem() { - selectMenuItem(mnSelectedMenu, false, false); - mnSelectedMenu = MENU_NOT_SELECTED; -} - -ScMenuFloatingWindow* ScMenuFloatingWindow::getSubMenuWindow(size_t nPos) const -{ - if (maMenuItems.size() <= nPos) - return nullptr; - - return maMenuItems[nPos].mpSubMenuWin.get(); + selectMenuItem(MENU_NOT_SELECTED, false); } -bool ScMenuFloatingWindow::isMenuItemSelected(size_t nPos) const -{ - return nPos == mnSelectedMenu; -} - -void ScMenuFloatingWindow::setName(const OUString& rName) -{ - maName = rName; -} - -void ScMenuFloatingWindow::highlightMenuItem(vcl::RenderContext& rRenderContext, size_t nPos, bool bSelected) -{ - if (nPos == MENU_NOT_SELECTED) - return; - - const StyleSettings& rStyle = rRenderContext.GetSettings().GetStyleSettings(); - Color aBackColor = rStyle.GetMenuColor(); - rRenderContext.SetFillColor(aBackColor); - rRenderContext.SetLineColor(aBackColor); - - Point aPos; - Size aSize; - getMenuItemPosSize(nPos, aPos, aSize); - tools::Rectangle aRegion(aPos,aSize); - - if (rRenderContext.IsNativeControlSupported(ControlType::MenuPopup, ControlPart::Entire)) - { - rRenderContext.Push(PushFlags::CLIPREGION); - rRenderContext.IntersectClipRegion(tools::Rectangle(aPos, aSize)); - tools::Rectangle aCtrlRect(Point(0,0), GetOutputSizePixel()); - rRenderContext.DrawNativeControl(ControlType::MenuPopup, ControlPart::Entire, aCtrlRect, ControlState::ENABLED, - ImplControlValue(), OUString()); - rRenderContext.Pop(); - } - - bool bNativeDrawn = true; - if (rRenderContext.IsNativeControlSupported(ControlType::MenuPopup, ControlPart::MenuItem)) - { - ControlState nState = bSelected ? ControlState::SELECTED : ControlState::NONE; - if (maMenuItems[nPos].mbEnabled) - nState |= ControlState::ENABLED; - bNativeDrawn = rRenderContext.DrawNativeControl(ControlType::MenuPopup, ControlPart::MenuItem, - aRegion, nState, ImplControlValue(), OUString()); - } - else - bNativeDrawn = false; - - if (!bNativeDrawn) - { - if (bSelected) - { - aBackColor = rStyle.GetMenuHighlightColor(); - rRenderContext.SetFillColor(aBackColor); - rRenderContext.SetLineColor(aBackColor); - } - rRenderContext.DrawRect(tools::Rectangle(aPos,aSize)); - } - - Color aTextColor = bSelected ? rStyle.GetMenuHighlightTextColor() : rStyle.GetMenuTextColor(); - rRenderContext.SetTextColor(aTextColor); - drawMenuItem(rRenderContext, nPos); -} - -void ScMenuFloatingWindow::getMenuItemPosSize(size_t nPos, Point& rPos, Size& rSize) const -{ - size_t nCount = maMenuItems.size(); - if (nPos >= nCount) - return; - - const sal_uInt16 nLeftMargin = 5; - const sal_uInt16 nTopMargin = 5; - const sal_uInt16 nMenuItemHeight = static_cast<sal_uInt16>(maLabelFont.GetFontHeight()*1.8); - const sal_uInt16 nSepHeight = static_cast<sal_uInt16>(maLabelFont.GetFontHeight()*0.8); - - Point aPos1(nLeftMargin, nTopMargin); - rPos = aPos1; - for (size_t i = 0; i < nPos; ++i) - rPos.AdjustY(maMenuItems[i].mbSeparator ? nSepHeight : nMenuItemHeight ); - - Size aWndSize = GetSizePixel(); - sal_uInt16 nH = maMenuItems[nPos].mbSeparator ? nSepHeight : nMenuItemHeight; - rSize = Size(aWndSize.Width() - nLeftMargin*2, nH); -} - -size_t ScMenuFloatingWindow::getEnclosingMenuItem(const Point& rPos) const -{ - size_t n = maMenuItems.size(); - for (size_t i = 0; i < n; ++i) - { - Point aPos; - Size aSize; - getMenuItemPosSize(i, aPos, aSize); - tools::Rectangle aRect(aPos, aSize); - if (aRect.IsInside(rPos)) - return maMenuItems[i].mbSeparator ? MENU_NOT_SELECTED : i; - } - return MENU_NOT_SELECTED; -} - -size_t ScMenuFloatingWindow::getSubMenuPos(const ScMenuFloatingWindow* pSubMenu) +size_t ScCheckListMenuControl::getSubMenuPos(const ScCheckListMenuControl* pSubMenu) { size_t n = maMenuItems.size(); for (size_t i = 0; i < n; ++i) { - if (maMenuItems[i].mpSubMenuWin.get() == pSubMenu) + if (!maMenuItems[i].mxSubMenuWin) + continue; + if (&maMenuItems[i].mxSubMenuWin->get_widget() == pSubMenu) return i; } return MENU_NOT_SELECTED; } -void ScMenuFloatingWindow::fireMenuHighlightedEvent() -{ - if (mnSelectedMenu == MENU_NOT_SELECTED) - return; - - if (!mxAccessible.is()) - return; - - Reference<XAccessibleContext> xAccCxt = mxAccessible->getAccessibleContext(); - if (!xAccCxt.is()) - return; - - Reference<XAccessible> xAccMenu = xAccCxt->getAccessibleChild(mnSelectedMenu); - if (!xAccMenu.is()) - return; - - VclAccessibleEvent aEvent(VclEventId::MenuHighlight, xAccMenu); - FireVclEvent(aEvent); -} - -void ScMenuFloatingWindow::setSubMenuFocused(const ScMenuFloatingWindow* pSubMenu) +void ScCheckListMenuControl::setSubMenuFocused(const ScCheckListMenuControl* pSubMenu) { maCloseTimer.reset(); size_t nMenuPos = getSubMenuPos(pSubMenu); if (mnSelectedMenu != nMenuPos) { mnSelectedMenu = nMenuPos; - Invalidate(); + mxMenu->select(mnSelectedMenu); } } -void ScMenuFloatingWindow::ensureSubMenuVisible(ScMenuFloatingWindow* pSubMenu) +void ScCheckListMenuControl::EndPopupMode() { - if (mpParentMenu) - mpParentMenu->ensureSubMenuVisible(this); - - if (pSubMenu->IsVisible()) - return; + vcl::Window::GetDockingManager()->EndPopupMode(mxFrame); + mxFrame->EnableDocking(false); +} - // Find the menu position of the submenu. - size_t nMenuPos = getSubMenuPos(pSubMenu); - if (nMenuPos != MENU_NOT_SELECTED) - { - setSelectedMenuItem(nMenuPos, false, false); - - Point aPos; - Size aSize; - getMenuItemPosSize(nMenuPos, aPos, aSize); - - FloatWinPopupFlags nOldFlags = GetPopupModeFlags(); - SetPopupModeFlags(nOldFlags | FloatWinPopupFlags::NoAppFocusClose); - pSubMenu->resizeToFitMenuItems(); // set the size before launching the popup to get it positioned correctly. - pSubMenu->StartPopupMode( - tools::Rectangle(aPos,aSize), (FloatWinPopupFlags::Right | FloatWinPopupFlags::GrabFocus)); - pSubMenu->AddPopupModeWindow(this); - SetPopupModeFlags(nOldFlags); - } +void ScCheckListMenuControl::StartPopupMode(const tools::Rectangle& rRect, FloatWinPopupFlags nPopupModeFlags) +{ + mxFrame->EnableDocking(true); + DockingManager* pDockingManager = vcl::Window::GetDockingManager(); + pDockingManager->SetPopupModeEndHdl(mxFrame, LINK(this, ScCheckListMenuControl, PopupModeEndHdl)); + pDockingManager->StartPopupMode(mxFrame, rRect, nPopupModeFlags); } -void ScMenuFloatingWindow::ensureSubMenuNotVisible() +void ScCheckListMenuControl::ensureSubMenuNotVisible() { if (mnSelectedMenu < maMenuItems.size() && - maMenuItems[mnSelectedMenu].mpSubMenuWin && - maMenuItems[mnSelectedMenu].mpSubMenuWin->IsVisible()) + maMenuItems[mnSelectedMenu].mxSubMenuWin && + maMenuItems[mnSelectedMenu].mxSubMenuWin->IsVisible()) { - maMenuItems[mnSelectedMenu].mpSubMenuWin->ensureSubMenuNotVisible(); + maMenuItems[mnSelectedMenu].mxSubMenuWin->get_widget().ensureSubMenuNotVisible(); } EndPopupMode(); } -void ScMenuFloatingWindow::terminateAllPopupMenus() +void ScCheckListMenuControl::terminateAllPopupMenus() { EndPopupMode(); - if (mpParentMenu) - mpParentMenu->terminateAllPopupMenus(); + ScCheckListMenuWindow* pParentMenu = mxFrame->GetParentMenu(); + if (pParentMenu) + pParentMenu->get_widget().terminateAllPopupMenus(); } -ScCheckListMenuWindow::Config::Config() : +ScCheckListMenuControl::Config::Config() : mbAllowEmptySet(true), mbRTL(false) { } @@ -853,67 +439,104 @@ ScCheckListMember::ScCheckListMember() , mbDate(false) , mbLeaf(false) , meDatePartType(YEAR) - , mpParent(nullptr) { } -ScCheckListMenuWindow::CancelButton::CancelButton(ScCheckListMenuWindow* pParent) : - ::CancelButton(pParent), mpParent(pParent) {} - -ScCheckListMenuWindow::CancelButton::~CancelButton() +ScCheckListMenuControl::ScCheckListMenuControl(ScCheckListMenuWindow* pParent, vcl::Window* pContainer, + ScDocument* pDoc, bool bCanHaveSubMenu, int nWidth) + : mxFrame(pParent) + , mxBuilder(Application::CreateInterimBuilder(pContainer, "modules/scalc/ui/filterdropdown.ui")) + , mxContainer(mxBuilder->weld_container("FilterDropDown")) + , mxMenu(mxBuilder->weld_tree_view("menu")) + , mxScratchIter(mxMenu->make_iterator()) + , mxEdSearch(mxBuilder->weld_entry("search_edit")) + , mxBox(mxBuilder->weld_widget("box")) + , mxChecks(mxBuilder->weld_tree_view("check_list_box")) + , mxChkToggleAll(mxBuilder->weld_check_button("toggle_all")) + , mxBtnSelectSingle(mxBuilder->weld_button("select_current")) + , mxBtnUnselectSingle(mxBuilder->weld_button("unselect_current")) + , mxButtonBox(mxBuilder->weld_box("buttonbox")) + , mxBtnOk(mxBuilder->weld_button("ok")) + , mxBtnCancel(mxBuilder->weld_button("cancel")) + , mxDropDown(mxMenu->create_virtual_device()) + , mnWidthHint(nWidth) + , maWndSize() + , mePrevToggleAllState(TRISTATE_INDET) + , mnSelectedMenu(MENU_NOT_SELECTED) + , mpDoc(pDoc) + , mnAsyncPostPopdownId(nullptr) + , mbHasDates(false) + , mbCanHaveSubMenu(bCanHaveSubMenu) + , maOpenTimer(this) + , maCloseTimer(this) { - disposeOnce(); + // sort ok/cancel into native order, if this was a dialog they would be auto-sorted, but this + // popup isn't a true dialog + mxButtonBox->sort_native_button_order(); + + mxChecks->enable_toggle_buttons(weld::ColumnToggleType::Check); + + mxContainer->connect_focus_in(LINK(this, ScCheckListMenuControl, FocusHdl)); + mxMenu->connect_row_activated(LINK(this, ScCheckListMenuControl, RowActivatedHdl)); + mxMenu->connect_changed(LINK(this, ScCheckListMenuControl, SelectHdl)); + mxMenu->connect_key_press(LINK(this, ScCheckListMenuControl, MenuKeyInputHdl)); + + if (mbCanHaveSubMenu) + { + CreateDropDown(); + mxMenu->connect_size_allocate(LINK(this, ScCheckListMenuControl, TreeSizeAllocHdl)); + } } -void ScCheckListMenuWindow::CancelButton::dispose() +IMPL_LINK_NOARG(ScCheckListMenuControl, FocusHdl, weld::Widget&, void) { - mpParent.clear(); - ::CancelButton::dispose(); + GrabFocus(); } -void ScCheckListMenuWindow::CancelButton::Click() +void ScCheckListMenuControl::GrabFocus() { - mpParent->EndPopupMode(); - ::CancelButton::Click(); + if (mxEdSearch->get_visible()) + mxEdSearch->grab_focus(); + else + { + mxMenu->set_cursor(0); + mxMenu->grab_focus(); + } } -ScCheckListMenuWindow::ScCheckListMenuWindow(vcl::Window* pParent, ScDocument* pDoc, int nWidth) : - ScMenuFloatingWindow(pParent, pDoc), - maEdSearch(VclPtr<ScSearchEdit>::Create(this)), - maChecks(VclPtr<ScCheckListBox>::Create(this)), - maChkToggleAll(VclPtr<CheckBox>::Create(this, 0)), - maBtnSelectSingle(VclPtr<ImageButton>::Create(this, 0)), - maBtnUnselectSingle(VclPtr<ImageButton>::Create(this, 0)), - maBtnOk(VclPtr<OKButton>::Create(this)), - maBtnCancel(VclPtr<CancelButton>::Create(this)), - maWndSize(), - mePrevToggleAllState(TRISTATE_INDET), - maTabStops(this), - mbHasDates(false) +ScCheckListMenuControl::~ScCheckListMenuControl() { - maChkToggleAll->EnableTriState(true); - - float fScaleFactor = GetDPIScaleFactor(); - - nWidth = std::max<int>(nWidth, 200 * fScaleFactor); - maWndSize = Size(nWidth, 330 * fScaleFactor); - - maTabStops.AddTabStop( this ); - maTabStops.AddTabStop( maEdSearch.get() ); - maTabStops.AddTabStop( maChecks.get() ); - maTabStops.AddTabStop( maChkToggleAll.get() ); - maTabStops.AddTabStop( maBtnSelectSingle.get() ); - maTabStops.AddTabStop( maBtnUnselectSingle.get() ); - maTabStops.AddTabStop( maBtnOk.get() ); - maTabStops.AddTabStop( maBtnCancel.get() ); - - maEdSearch->SetTabStopsContainer( &maTabStops ); - maChecks->SetTabStopsContainer( &maTabStops ); + EndPopupMode(); + for (auto& rMenuItem : maMenuItems) + rMenuItem.mxSubMenuWin.disposeAndClear(); + if (mnAsyncPostPopdownId) + { + Application::RemoveUserEvent(mnAsyncPostPopdownId); + mnAsyncPostPopdownId = nullptr; + } +} +ScCheckListMenuWindow::ScCheckListMenuWindow(vcl::Window* pParent, ScDocument* pDoc, bool bCanHaveSubMenu, + int nWidth, sal_uInt16 nMenuStackLevel, ScCheckListMenuWindow* pParentMenu) + : DockingWindow(pParent, "InterimDockParent", "svx/ui/interimdockparent.ui") + , mxParentMenu(pParentMenu) + , mxBox(get("box")) + , mxControl(new ScCheckListMenuControl(this, mxBox.get(), pDoc, bCanHaveSubMenu, nWidth)) + , mnMenuStackLevel(nMenuStackLevel) +{ + SetBackground(Application::GetSettings().GetStyleSettings().GetMenuColor()); set_id("check_list_menu"); - maChkToggleAll->set_id("toggle_all"); - maBtnSelectSingle->set_id("select_current"); - maBtnUnselectSingle->set_id("unselect_current"); +} + +bool ScCheckListMenuWindow::EventNotify(NotifyEvent& rNEvt) +{ + if (rNEvt.GetType() == MouseNotifyEvent::MOUSEMOVE) + { + ScCheckListMenuControl& rMenuControl = get_widget(); + rMenuControl.queueCloseSubMenu(); + rMenuControl.clearSelectedMenuItem(); + } + return DockingWindow::EventNotify(rNEvt); } ScCheckListMenuWindow::~ScCheckListMenuWindow() @@ -923,315 +546,123 @@ ScCheckListMenuWindow::~ScCheckListMenuWindow() void ScCheckListMenuWindow::dispose() { - maTabStops.clear(); - maEdSearch.disposeAndClear(); - maChecks.disposeAndClear(); - maChkToggleAll.disposeAndClear(); - maBtnSelectSingle.disposeAndClear(); - maBtnUnselectSingle.disposeAndClear(); - maBtnOk.disposeAndClear(); - maBtnCancel.disposeAndClear(); - ScMenuFloatingWindow::dispose(); -} - -void ScCheckListMenuWindow::getSectionPosSize( - Point& rPos, Size& rSize, SectionType eType) const -{ - float fScaleFactor = GetDPIScaleFactor(); - - // constant parameters. - const long nSearchBoxMargin = 10 *fScaleFactor; - const long nListBoxMargin = 5 * fScaleFactor; // horizontal distance from the side of the dialog to the listbox border. - const long nListBoxInnerPadding = 5 * fScaleFactor; - const long nTopMargin = 5 * fScaleFactor; - const long nMenuHeight = maMenuSize.getHeight(); - const long nSingleItemBtnAreaHeight = 32 * fScaleFactor; // height of the middle area below the list box where the single-action buttons are. - const long nBottomBtnAreaHeight = 50 * fScaleFactor; // height of the bottom area where the OK and Cancel buttons are. - const long nBtnWidth = 90 * fScaleFactor; - const long nLabelHeight = getLabelFont().GetFontHeight(); - const long nBtnHeight = nLabelHeight * 2; - const long nBottomMargin = 10 * fScaleFactor; - const long nMenuListMargin = 5 * fScaleFactor; - const long nSearchBoxHeight = nLabelHeight * 2; - - // parameters calculated from constants. - const long nListBoxWidth = maWndSize.Width() - nListBoxMargin*2; - const long nListBoxHeight = maWndSize.Height() - nTopMargin - nMenuHeight - - nMenuListMargin - nSearchBoxHeight - nSearchBoxMargin - nSingleItemBtnAreaHeight - nBottomBtnAreaHeight; - - const long nSingleBtnAreaY = nTopMargin + nMenuHeight + nMenuListMargin + nSearchBoxHeight + nSearchBoxMargin; - - switch (eType) - { - case WHOLE: - { - rPos = Point(0, 0); - rSize = maWndSize; - } - break; - case EDIT_SEARCH: - { - rPos = Point(nSearchBoxMargin, nTopMargin + nMenuHeight + nMenuListMargin); - rSize = Size(maWndSize.Width() - 2*nSearchBoxMargin, nSearchBoxHeight); - } - break; - case SINGLE_BTN_AREA: - { - rPos = Point(nListBoxMargin, nSingleBtnAreaY); - rSize = Size(nListBoxWidth, nSingleItemBtnAreaHeight); - } - break; - case CHECK_TOGGLE_ALL: - { - long h = std::min(maChkToggleAll->CalcMinimumSize().Height(), 26L); - rPos = Point(nListBoxMargin, nSingleBtnAreaY); - rPos.AdjustX(5 ); - rPos.AdjustY((nSingleItemBtnAreaHeight - h)/2 ); - rSize = Size(70, h); - } - break; - case BTN_SINGLE_SELECT: - { - long h = 26 * fScaleFactor; - rPos = Point(nListBoxMargin, nSingleBtnAreaY); - rPos.AdjustX(nListBoxWidth - h - 10 - h - 10 ); - rPos.AdjustY((nSingleItemBtnAreaHeight - h)/2 ); - rSize = Size(h, h); - } - break; - case BTN_SINGLE_UNSELECT: - { - long h = 26 * fScaleFactor; - rPos = Point(nListBoxMargin, nSingleBtnAreaY); - rPos.AdjustX(nListBoxWidth - h - 10 ); - rPos.AdjustY((nSingleItemBtnAreaHeight - h)/2 ); - rSize = Size(h, h); - } - break; - case LISTBOX_AREA_OUTER: - { - rPos = Point(nListBoxMargin, nSingleBtnAreaY + nSingleItemBtnAreaHeight-1); - rSize = Size(nListBoxWidth, nListBoxHeight); - } - break; - case LISTBOX_AREA_INNER: - { - rPos = Point(nListBoxMargin, nSingleBtnAreaY + nSingleItemBtnAreaHeight-1); - rPos.AdjustX(nListBoxInnerPadding ); - rPos.AdjustY(nListBoxInnerPadding ); - - rSize = Size(nListBoxWidth, nListBoxHeight); - rSize.AdjustWidth( -(nListBoxInnerPadding*2) ); - rSize.AdjustHeight( -(nListBoxInnerPadding*2) ); - } - break; - case BTN_OK: - { - long x = (maWndSize.Width() - nBtnWidth*2)/3; - long y = maWndSize.Height() - nBottomMargin - nBtnHeight; - rPos = Point(x, y); - rSize = Size(nBtnWidth, nBtnHeight); - } - break; - case BTN_CANCEL: - { - long x = (maWndSize.Width() - nBtnWidth*2)/3*2 + nBtnWidth; - long y = maWndSize.Height() - nBottomMargin - nBtnHeight; - rPos = Point(x, y); - rSize = Size(nBtnWidth, nBtnHeight); - } - break; - default: - ; - } + mxControl.reset(); + mxBox.disposeAndClear(); + mxParentMenu.clear(); + DockingWindow::dispose(); } -void ScCheckListMenuWindow::packWindow() +void ScCheckListMenuWindow::GetFocus() { - maMenuSize = getMenuSize(); - - if (maWndSize.Width() < maMenuSize.Width()) - // Widen the window to fit the menu items. - maWndSize.setWidth( maMenuSize.Width() ); - - // Set proper window height based on the number of menu items. - if (maWndSize.Height() < maMenuSize.Height()*2.8) - maWndSize.setHeight( maMenuSize.Height()*2.8 ); - - // TODO: Make sure the window height never exceeds the height of the - // screen. Also do adjustment based on the number of check box items. - - SetOutputSizePixel(maWndSize); - - const StyleSettings& rStyle = GetSettings().GetStyleSettings(); - - Point aPos; - Size aSize; - getSectionPosSize(aPos, aSize, WHOLE); - SetOutputSizePixel(aSize); - - getSectionPosSize(aPos, aSize, BTN_OK); - maBtnOk->SetPosSizePixel(aPos, aSize); - maBtnOk->SetFont(getLabelFont()); - maBtnOk->SetClickHdl( LINK(this, ScCheckListMenuWindow, ButtonHdl) ); - maBtnOk->Show(); - - getSectionPosSize(aPos, aSize, BTN_CANCEL); - maBtnCancel->SetPosSizePixel(aPos, aSize); - maBtnCancel->SetFont(getLabelFont()); - maBtnCancel->Show(); - - getSectionPosSize(aPos, aSize, EDIT_SEARCH); - maEdSearch->SetPosSizePixel(aPos, aSize); - maEdSearch->SetFont(getLabelFont()); - maEdSearch->SetControlBackground(rStyle.GetFieldColor()); - maEdSearch->SetPlaceholderText(ScResId(STR_EDIT_SEARCH_ITEMS)); - maEdSearch->SetModifyHdl( LINK(this, ScCheckListMenuWindow, EdModifyHdl) ); - maEdSearch->Show(); - - getSectionPosSize(aPos, aSize, LISTBOX_AREA_INNER); - maChecks->SetPosSizePixel(aPos, aSize); - maChecks->SetFont(getLabelFont()); - maChecks->SetCheckButtonHdl( LINK(this, ScCheckListMenuWindow, CheckHdl) ); - maChecks->Show(); - - getSectionPosSize(aPos, aSize, CHECK_TOGGLE_ALL); - maChkToggleAll->SetPosSizePixel(aPos, aSize); - maChkToggleAll->SetFont(getLabelFont()); - maChkToggleAll->SetText(ScResId(STR_BTN_TOGGLE_ALL)); - maChkToggleAll->SetTextColor(rStyle.GetMenuTextColor()); - maChkToggleAll->SetControlBackground(rStyle.GetMenuColor()); - maChkToggleAll->SetClickHdl( LINK(this, ScCheckListMenuWindow, TriStateHdl) ); - maChkToggleAll->Show(); - - float fScaleFactor = GetDPIScaleFactor(); - - ; + DockingWindow::GetFocus(); + if (!mxControl) + return; + mxControl->GrabFocus(); +} - getSectionPosSize(aPos, aSize, BTN_SINGLE_SELECT); - maBtnSelectSingle->SetPosSizePixel(aPos, aSize); - maBtnSelectSingle->SetQuickHelpText(ScResId(STR_BTN_SELECT_CURRENT)); - maBtnSelectSingle->SetModeImage(Image(StockImage::Yes, RID_BMP_SELECT_CURRENT)); - maBtnSelectSingle->SetClickHdl( LINK(this, ScCheckListMenuWindow, ButtonHdl) ); - maBtnSelectSingle->Show(); +void ScCheckListMenuControl::packWindow() +{ + mxBox->show(); + mxEdSearch->show(); + mxButtonBox->show(); - BitmapEx aSingleUnselectBmp(RID_BMP_UNSELECT_CURRENT); - if (fScaleFactor > 1) - aSingleUnselectBmp.Scale(fScaleFactor, fScaleFactor, BmpScaleFlag::Fast); - Image aSingleUnselect(aSingleUnselectBmp); + mxBtnOk->connect_clicked(LINK(this, ScCheckListMenuControl, ButtonHdl)); + mxBtnCancel->connect_clicked(LINK(this, ScCheckListMenuControl, ButtonHdl)); + mxEdSearch->connect_changed(LINK(this, ScCheckListMenuControl, EdModifyHdl)); + mxEdSearch->connect_activate(LINK(this, ScCheckListMenuControl, EdActivateHdl)); + mxChecks->connect_toggled(LINK(this, ScCheckListMenuControl, CheckHdl)); + mxChecks->connect_key_press(LINK(this, ScCheckListMenuControl, KeyInputHdl)); + mxChkToggleAll->connect_toggled(LINK(this, ScCheckListMenuControl, TriStateHdl)); + mxBtnSelectSingle->connect_clicked(LINK(this, ScCheckListMenuControl, ButtonHdl)); + mxBtnUnselectSingle->connect_clicked(LINK(this, ScCheckListMenuControl, ButtonHdl)); - getSectionPosSize(aPos, aSize, BTN_SINGLE_UNSELECT); - maBtnUnselectSingle->SetPosSizePixel(aPos, aSize); - maBtnUnselectSingle->SetQuickHelpText(ScResId(STR_BTN_UNSELECT_CURRENT)); - maBtnUnselectSingle->SetModeImage(aSingleUnselect); - maBtnUnselectSingle->SetClickHdl( LINK(this, ScCheckListMenuWindow, ButtonHdl) ); - maBtnUnselectSingle->Show(); -} + mxChecks->set_size_request(-1, mxChecks->get_height_rows(9)); + mxMenu->set_size_request(-1, mxMenu->get_preferred_size().Height() + 2); + mnSelectedMenu = 0; + mxMenu->set_cursor(mnSelectedMenu); + mxMenu->unselect_all(); -void ScCheckListMenuWindow::setAllMemberState(bool bSet) -{ - size_t n = maMembers.size(); - std::set<SvTreeListEntry*> aParents; - for (size_t i = 0; i < n; ++i) + maWndSize = mxContainer->get_preferred_size(); + if (maWndSize.Width() < mnWidthHint) { - aParents.insert(maMembers[i].mpParent); + mxContainer->set_size_request(mnWidthHint, -1); + maWndSize.setWidth(mnWidthHint); } +} - for (const auto& pParent : aParents) - { - if (!pParent) - { - sal_uInt32 nCount = maChecks->GetEntryCount(); - for( sal_uInt32 i = 0; i < nCount; ++i) - { - SvTreeListEntry* pEntry = maChecks->GetEntry(i); - if (!pEntry) - continue; - - maChecks->CheckEntry(pEntry, bSet); - } - } - else - { - SvTreeListEntries& rEntries = pParent->GetChildEntries(); - for (const auto& rxEntry : rEntries) - { - maChecks->CheckEntry(rxEntry.get(), bSet); - } - } - } +void ScCheckListMenuControl::setAllMemberState(bool bSet) +{ + CheckAllChildren(nullptr, bSet); if (!maConfig.mbAllowEmptySet) + { // We need to have at least one member selected. - maBtnOk->Enable(maChecks->GetCheckedEntryCount() != 0); + mxBtnOk->set_sensitive(GetCheckedEntryCount() != 0); + } } -void ScCheckListMenuWindow::selectCurrentMemberOnly(bool bSet) +void ScCheckListMenuControl::selectCurrentMemberOnly(bool bSet) { setAllMemberState(!bSet); - SvTreeListEntry* pEntry = maChecks->GetCurEntry(); - if (!pEntry) + std::unique_ptr<weld::TreeIter> xEntry = mxChecks->make_iterator(); + if (!mxChecks->get_cursor(xEntry.get())) return; - maChecks->CheckEntry(pEntry, bSet ); - - // Make sure all checkboxes are invalidated. - Invalidate(); + mxChecks->set_toggle(*xEntry, bSet ? TRISTATE_TRUE : TRISTATE_FALSE); } -IMPL_LINK( ScCheckListMenuWindow, ButtonHdl, Button*, pBtn, void ) +IMPL_LINK(ScCheckListMenuControl, ButtonHdl, weld::Button&, rBtn, void) { - if (pBtn == maBtnOk.get()) + if (&rBtn == mxBtnOk.get()) close(true); - else if (pBtn == maBtnSelectSingle.get()) - { - selectCurrentMemberOnly(true); - CheckHdl(maChecks.get()); - } - else if (pBtn == maBtnUnselectSingle.get()) + else if (&rBtn == mxBtnCancel.get()) + close(false); + else if (&rBtn == mxBtnSelectSingle.get() || &rBtn == mxBtnUnselectSingle.get()) { - selectCurrentMemberOnly(false); - CheckHdl(maChecks.get()); + selectCurrentMemberOnly(&rBtn == mxBtnSelectSingle.get()); + std::unique_ptr<weld::TreeIter> xEntry = mxChecks->make_iterator(); + if (!mxChecks->get_cursor(xEntry.get())) + xEntry.reset(); + Check(xEntry.get()); } } -IMPL_LINK_NOARG(ScCheckListMenuWindow, TriStateHdl, Button*, void) +IMPL_LINK_NOARG(ScCheckListMenuControl, TriStateHdl, weld::ToggleButton&, void) { switch (mePrevToggleAllState) { case TRISTATE_FALSE: - maChkToggleAll->SetState(TRISTATE_TRUE); + mxChkToggleAll->set_state(TRISTATE_TRUE); setAllMemberState(true); break; case TRISTATE_TRUE: - maChkToggleAll->SetState(TRISTATE_FALSE); + mxChkToggleAll->set_state(TRISTATE_FALSE); setAllMemberState(false); break; case TRISTATE_INDET: default: - maChkToggleAll->SetState(TRISTATE_TRUE); + mxChkToggleAll->set_state(TRISTATE_TRUE); setAllMemberState(true); break; } - mePrevToggleAllState = maChkToggleAll->GetState(); - maTabStops.SetTabStop(maChkToggleAll); // Needed for when accelerator is used + mePrevToggleAllState = mxChkToggleAll->get_state(); } -IMPL_LINK_NOARG(ScCheckListMenuWindow, EdModifyHdl, Edit&, void) +IMPL_LINK_NOARG(ScCheckListMenuControl, EdModifyHdl, weld::Entry&, void) { - OUString aSearchText = maEdSearch->GetText(); + OUString aSearchText = mxEdSearch->get_text(); aSearchText = ScGlobal::getCharClassPtr()->lowercase( aSearchText ); bool bSearchTextEmpty = aSearchText.isEmpty(); size_t n = maMembers.size(); size_t nSelCount = 0; bool bSomeDateDeletes = false; - maChecks->SetUpdateMode(false); + mxChecks->freeze(); if (bSearchTextEmpty && !mbHasDates) { // when there are a lot of rows, it is cheaper to simply clear the tree and re-initialise - maChecks->Clear(); + mxChecks->clear(); nSelCount = initMembers(); } else @@ -1260,8 +691,8 @@ IMPL_LINK_NOARG(ScCheckListMenuWindow, EdModifyHdl, Edit&, void) if ( bSearchTextEmpty ) { - SvTreeListEntry* pLeaf = maChecks->ShowCheckEntry( aLabelDisp, maMembers[i], true, maMembers[i].mbVisible ); - updateMemberParents( pLeaf, i ); + auto xLeaf = ShowCheckEntry(aLabelDisp, maMembers[i], true, maMembers[i].mbVisible); + updateMemberParents(xLeaf.get(), i); if ( maMembers[i].mbVisible ) ++nSelCount; continue; @@ -1269,13 +700,13 @@ IMPL_LINK_NOARG(ScCheckListMenuWindow, EdModifyHdl, Edit&, void) if ( bPartialMatch ) { - SvTreeListEntry* pLeaf = maChecks->ShowCheckEntry( aLabelDisp, maMembers[i] ); - updateMemberParents( pLeaf, i ); + auto xLeaf = ShowCheckEntry(aLabelDisp, maMembers[i]); + updateMemberParents(xLeaf.get(), i); ++nSelCount; } else { - maChecks->ShowCheckEntry( aLabelDisp, maMembers[i], false, false ); + ShowCheckEntry(aLabelDisp, maMembers[i], false, false); if( bIsDate ) bSomeDateDeletes = true; } @@ -1286,115 +717,69 @@ IMPL_LINK_NOARG(ScCheckListMenuWindow, EdModifyHdl, Edit&, void) { for (size_t i = 0; i < n; ++i) { - if ( !maMembers[i].mbDate ) continue; - if ( maMembers[i].meDatePartType != ScCheckListMember::DAY ) continue; - updateMemberParents( nullptr, i ); + if (!maMembers[i].mbDate) + continue; + if (maMembers[i].meDatePartType != ScCheckListMember::DAY) + continue; + updateMemberParents(nullptr, i); } } - maChecks->SetUpdateMode(true); + mxChecks->thaw(); if ( nSelCount == n ) - maChkToggleAll->SetState( TRISTATE_TRUE ); + mxChkToggleAll->set_state( TRISTATE_TRUE ); else if ( nSelCount == 0 ) - maChkToggleAll->SetState( TRISTATE_FALSE ); + mxChkToggleAll->set_state( TRISTATE_FALSE ); else - maChkToggleAll->SetState( TRISTATE_INDET ); + mxChkToggleAll->set_state( TRISTATE_INDET ); if ( !maConfig.mbAllowEmptySet ) { const bool bEmptySet( nSelCount == 0 ); - maChecks->Enable( !bEmptySet ); - maChkToggleAll->Enable( !bEmptySet ); - maBtnSelectSingle->Enable( !bEmptySet ); - maBtnUnselectSingle->Enable( !bEmptySet ); - maBtnOk->Enable( !bEmptySet ); + mxChecks->set_sensitive(!bEmptySet); + mxChkToggleAll->set_sensitive(!bEmptySet); + mxBtnSelectSingle->set_sensitive(!bEmptySet); + mxBtnUnselectSingle->set_sensitive(!bEmptySet); + mxBtnOk->set_sensitive(!bEmptySet); } } -IMPL_LINK( ScCheckListMenuWindow, CheckHdl, SvTreeListBox*, pChecks, void ) +IMPL_LINK_NOARG(ScCheckListMenuControl, EdActivateHdl, weld::Entry&, bool) { - if (pChecks != maChecks.get()) - return; - SvTreeListEntry* pEntry = pChecks->GetHdlEntry(); - if ( pEntry ) - maChecks->CheckEntry( pEntry, ( pChecks->GetCheckButtonState( pEntry ) == SvButtonState::Checked ) ); - size_t nNumChecked = maChecks->GetCheckedEntryCount(); + if (mxBtnOk->get_sensitive()) + close(true); + return true; +} + +IMPL_LINK( ScCheckListMenuControl, CheckHdl, const weld::TreeView::iter_col&, rRowCol, void ) +{ + Check(&rRowCol.first); +} + +void ScCheckListMenuControl::Check(const weld::TreeIter* pEntry) +{ + if (pEntry) + CheckEntry(pEntry, mxChecks->get_toggle(*pEntry) == TRISTATE_TRUE); + size_t nNumChecked = GetCheckedEntryCount(); if (nNumChecked == maMembers.size()) // all members visible - maChkToggleAll->SetState(TRISTATE_TRUE); + mxChkToggleAll->set_state(TRISTATE_TRUE); else if (nNumChecked == 0) // no members visible - maChkToggleAll->SetState(TRISTATE_FALSE); + mxChkToggleAll->set_state(TRISTATE_FALSE); else - maChkToggleAll->SetState(TRISTATE_INDET); + mxChkToggleAll->set_state(TRISTATE_INDET); if (!maConfig.mbAllowEmptySet) // We need to have at least one member selected. - maBtnOk->Enable(nNumChecked != 0); - - mePrevToggleAllState = maChkToggleAll->GetState(); -} - -void ScCheckListMenuWindow::MouseMove(const MouseEvent& rMEvt) -{ - ScMenuFloatingWindow::MouseMove(rMEvt); - - size_t nSelectedMenu = getSelectedMenuItem(); - if (nSelectedMenu == MENU_NOT_SELECTED) - queueCloseSubMenu(); -} + mxBtnOk->set_sensitive(nNumChecked != 0); -bool ScCheckListMenuWindow::EventNotify(NotifyEvent& rNEvt) -{ - MouseNotifyEvent nType = rNEvt.GetType(); - if (HasFocus() && nType == MouseNotifyEvent::GETFOCUS) - { - setSelectedMenuItem( 0 , false, false ); - return true; - } - if (nType == MouseNotifyEvent::KEYINPUT) - { - const KeyEvent* pKeyEvent = rNEvt.GetKeyEvent(); - const vcl::KeyCode& rCode = pKeyEvent->GetKeyCode(); - const sal_uInt16 nCode = rCode.GetCode(); - if (nCode != KEY_RETURN) - { - bool bShift = rCode.IsShift(); - if (nCode == KEY_TAB) - maTabStops.CycleFocus(bShift); - return true; - } - } - return ScMenuFloatingWindow::EventNotify(rNEvt); -} - -void ScCheckListMenuWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) -{ - ScMenuFloatingWindow::Paint(rRenderContext, rRect); - - const StyleSettings& rStyle = GetSettings().GetStyleSettings(); - Color aMemberBackColor = rStyle.GetFieldColor(); - Color aBorderColor = rStyle.GetShadowColor(); - - Point aPos; - Size aSize; - getSectionPosSize(aPos, aSize, LISTBOX_AREA_OUTER); - - // Member list box background - rRenderContext.SetFillColor(aMemberBackColor); - rRenderContext.SetLineColor(aBorderColor); - rRenderContext.DrawRect(tools::Rectangle(aPos,aSize)); - - // Single-action button box - getSectionPosSize(aPos, aSize, SINGLE_BTN_AREA); - rRenderContext.SetFillColor(rStyle.GetMenuColor()); - rRenderContext.DrawRect(tools::Rectangle(aPos,aSize)); + mePrevToggleAllState = mxChkToggleAll->get_state(); } -void ScCheckListMenuWindow::updateMemberParents( const SvTreeListEntry* pLeaf, size_t nIdx ) +void ScCheckListMenuControl::updateMemberParents(const weld::TreeIter* pLeaf, size_t nIdx) { - if ( !maMembers[nIdx].mbDate || maMembers[nIdx].meDatePartType != ScCheckListMember::DAY ) return; @@ -1404,67 +789,46 @@ void ScCheckListMenuWindow::updateMemberParents( const SvTreeListEntry* pLeaf, s if ( pLeaf ) { - SvTreeListEntry* pMonthEntry = pLeaf->GetParent(); - SvTreeListEntry* pYearEntry = pMonthEntry ? pMonthEntry->GetParent() : nullptr; + std::unique_ptr<weld::TreeIter> xYearEntry; + std::unique_ptr<weld::TreeIter> xMonthEntry = mxChecks->make_iterator(pLeaf); + if (!mxChecks->iter_parent(*xMonthEntry)) + xMonthEntry.reset(); + else + { + xYearEntry = mxChecks->make_iterator(xMonthEntry.get()); + if (!mxChecks->iter_parent(*xYearEntry)) + xYearEntry.reset(); + } - maMembers[nIdx].mpParent = pMonthEntry; + maMembers[nIdx].mxParent = std::move(xMonthEntry); if ( aItr != maYearMonthMap.end() ) { size_t nMonthIdx = aItr->second; - maMembers[nMonthIdx].mpParent = pYearEntry; + maMembers[nMonthIdx].mxParent = std::move(xYearEntry); } } else { - SvTreeListEntry* pYearEntry = maChecks->FindEntry( nullptr, aYearName ); - if ( aItr != maYearMonthMap.end() && !pYearEntry ) + std::unique_ptr<weld::TreeIter> xYearEntry = FindEntry(nullptr, aYearName); + if (aItr != maYearMonthMap.end() && !xYearEntry) { size_t nMonthIdx = aItr->second; - maMembers[nMonthIdx].mpParent = nullptr; - maMembers[nIdx].mpParent = nullptr; + maMembers[nMonthIdx].mxParent.reset(); + maMembers[nIdx].mxParent.reset(); } - else if ( pYearEntry && !maChecks->FindEntry( pYearEntry, aMonthName ) ) - maMembers[nIdx].mpParent = nullptr; - } -} - -Reference<XAccessible> ScCheckListMenuWindow::CreateAccessible() -{ - if (!mxAccessible.is() && maEdSearch) - { - mxAccessible.set(new ScAccessibleFilterTopWindow( - GetAccessibleParentWindow()->GetAccessible(), this, getName())); - ScAccessibleFilterTopWindow* pAccTop = static_cast<ScAccessibleFilterTopWindow*>(mxAccessible.get()); - fillMenuItemsToAccessible(pAccTop); - - pAccTop->setAccessibleChild( - maEdSearch->CreateAccessible(), ScAccessibleFilterTopWindow::EDIT_SEARCH_BOX); - pAccTop->setAccessibleChild( - maChecks->CreateAccessible(), ScAccessibleFilterTopWindow::LISTBOX); - pAccTop->setAccessibleChild( - maChkToggleAll->CreateAccessible(), ScAccessibleFilterTopWindow::TOGGLE_ALL); - pAccTop->setAccessibleChild( - maBtnSelectSingle->CreateAccessible(), ScAccessibleFilterTopWindow::SINGLE_ON_BTN); - pAccTop->setAccessibleChild( - maBtnUnselectSingle->CreateAccessible(), ScAccessibleFilterTopWindow::SINGLE_OFF_BTN); - pAccTop->setAccessibleChild( - maBtnOk->CreateAccessible(), ScAccessibleFilterTopWindow::OK_BTN); - pAccTop->setAccessibleChild( - maBtnCancel->CreateAccessible(), ScAccessibleFilterTopWindow::CANCEL_BTN); + else if (xYearEntry && !FindEntry(xYearEntry.get(), aMonthName)) + maMembers[nIdx].mxParent.reset(); } - - return mxAccessible; } -void ScCheckListMenuWindow::setMemberSize(size_t n) +void ScCheckListMenuControl::setMemberSize(size_t n) { maMembers.reserve(n); } -void ScCheckListMenuWindow::addDateMember(const OUString& rsName, double nVal, bool bVisible) +void ScCheckListMenuControl::addDateMember(const OUString& rsName, double nVal, bool bVisible) { - ScDocument* pDoc = getDoc(); - SvNumberFormatter* pFormatter = pDoc->GetFormatTable(); + SvNumberFormatter* pFormatter = mpDoc->GetFormatTable(); // Convert the numeric date value to a date object. Date aDate = pFormatter->GetNullDate(); @@ -1487,43 +851,52 @@ void ScCheckListMenuWindow::addDateMember(const OUString& rsName, double nVal, b if ( aDayName.getLength() == 1 ) aDayName = "0" + aDayName; - maChecks->SetUpdateMode(false); + mxChecks->freeze(); - SvTreeListEntry* pYearEntry = maChecks->FindEntry(nullptr, aYearName); - if (!pYearEntry) + std::unique_ptr<weld::TreeIter> xYearEntry = FindEntry(nullptr, aYearName); + if (!xYearEntry) { - pYearEntry = maChecks->InsertEntry(aYearName, nullptr, true); + xYearEntry = mxChecks->make_iterator(); + mxChecks->insert(nullptr, -1, nullptr, nullptr, nullptr, nullptr, false, xYearEntry.get()); + mxChecks->set_toggle(*xYearEntry, TRISTATE_FALSE); + mxChecks->set_text(*xYearEntry, aYearName, 0); ScCheckListMember aMemYear; aMemYear.maName = aYearName; aMemYear.maRealName = rsName; aMemYear.mbDate = true; aMemYear.mbLeaf = false; aMemYear.mbVisible = bVisible; - aMemYear.mpParent = nullptr; + aMemYear.mxParent.reset(); aMemYear.meDatePartType = ScCheckListMember::YEAR; - maMembers.push_back(aMemYear); + maMembers.emplace_back(std::move(aMemYear)); } - SvTreeListEntry* pMonthEntry = maChecks->FindEntry(pYearEntry, aMonthName); - if (!pMonthEntry) + std::unique_ptr<weld::TreeIter> xMonthEntry = FindEntry(xYearEntry.get(), aMonthName); + if (!xMonthEntry) { - pMonthEntry = maChecks->InsertEntry(aMonthName, pYearEntry, true); + xMonthEntry = mxChecks->make_iterator(); + mxChecks->insert(xYearEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, false, xMonthEntry.get()); + mxChecks->set_toggle(*xMonthEntry, TRISTATE_FALSE); + mxChecks->set_text(*xMonthEntry, aMonthName, 0); ScCheckListMember aMemMonth; aMemMonth.maName = aMonthName; aMemMonth.maRealName = rsName; aMemMonth.mbDate = true; aMemMonth.mbLeaf = false; aMemMonth.mbVisible = bVisible; - aMemMonth.mpParent = pYearEntry; + aMemMonth.mxParent = std::move(xYearEntry); aMemMonth.meDatePartType = ScCheckListMember::MONTH; - maMembers.push_back(aMemMonth); + maMembers.emplace_back(std::move(aMemMonth)); maYearMonthMap[aYearName + aMonthName] = maMembers.size() - 1; } - SvTreeListEntry* pDayEntry = maChecks->FindEntry(pMonthEntry, aDayName); - if (!pDayEntry) + std::unique_ptr<weld::TreeIter> xDayEntry = FindEntry(xMonthEntry.get(), aDayName); + if (!xDayEntry) { - maChecks->InsertEntry(aDayName, pMonthEntry); + xDayEntry = mxChecks->make_iterator(); + mxChecks->insert(xMonthEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, false, xDayEntry.get()); + mxChecks->set_toggle(*xDayEntry, TRISTATE_FALSE); + mxChecks->set_text(*xDayEntry, aDayName, 0); ScCheckListMember aMemDay; aMemDay.maName = aDayName; aMemDay.maRealName = rsName; @@ -1533,168 +906,65 @@ void ScCheckListMenuWindow::addDateMember(const OUString& rsName, double nVal, b aMemDay.mbDate = true; aMemDay.mbLeaf = true; aMemDay.mbVisible = bVisible; - aMemDay.mpParent = pMonthEntry; + aMemDay.mxParent = std::move(xMonthEntry); aMemDay.meDatePartType = ScCheckListMember::DAY; - maMembers.push_back(aMemDay); + maMembers.emplace_back(std::move(aMemDay)); } - maChecks->SetUpdateMode(true); + mxChecks->thaw(); } -void ScCheckListMenuWindow::addMember(const OUString& rName, bool bVisible) +void ScCheckListMenuControl::addMember(const OUString& rName, bool bVisible) { ScCheckListMember aMember; aMember.maName = rName; aMember.mbDate = false; aMember.mbLeaf = true; aMember.mbVisible = bVisible; - aMember.mpParent = nullptr; - maMembers.push_back(aMember); + aMember.mxParent.reset(); + maMembers.emplace_back(std::move(aMember)); } -ScTabStops::ScTabStops( ScCheckListMenuWindow* pMenuWin ) : - mpMenuWindow( pMenuWin ), - maControlToPos( ControlToPosMap() ), - mnCurTabStop(0) +std::unique_ptr<weld::TreeIter> ScCheckListMenuControl::FindEntry(const weld::TreeIter* pParent, const OUString& sNode) { - maControls.reserve( 8 ); -} - -ScTabStops::~ScTabStops() -{} - -void ScTabStops::AddTabStop( vcl::Window* pWin ) -{ - maControls.emplace_back(pWin ); - maControlToPos[pWin] = maControls.size() - 1; -} - -void ScTabStops::SetTabStop( vcl::Window* pWin ) -{ - if ( maControls.empty() ) - return; - ControlToPosMap::const_iterator aIter = maControlToPos.find( pWin ); - if ( aIter == maControlToPos.end() ) - return; - if ( aIter->second == mnCurTabStop ) - return; - if ( mnCurTabStop < maControls.size() ) - { - maControls[mnCurTabStop]->SetFakeFocus( false ); - maControls[mnCurTabStop]->LoseFocus(); - } - mnCurTabStop = aIter->second; - maControls[mnCurTabStop]->SetFakeFocus( true ); - maControls[mnCurTabStop]->GrabFocus(); -} - -void ScTabStops::CycleFocus( bool bReverse ) -{ - if (maControls.empty()) - return; - if ( mnCurTabStop < maControls.size() ) + std::unique_ptr<weld::TreeIter> xEntry = mxChecks->make_iterator(pParent); + bool bEntry = pParent ? mxChecks->iter_children(*xEntry) : mxChecks->get_iter_first(*xEntry); + while (bEntry) { - maControls[mnCurTabStop]->SetFakeFocus( false ); - maControls[mnCurTabStop]->LoseFocus(); - } - else - mnCurTabStop = 0; - - if ( mpMenuWindow && mnCurTabStop == 0 ) - mpMenuWindow->clearSelectedMenuItem(); - - size_t nIterCount = 0; - - if ( bReverse ) - { - do - { - if ( mnCurTabStop > 0 ) - --mnCurTabStop; - else - mnCurTabStop = maControls.size() - 1; - ++nIterCount; - } while ( nIterCount <= maControls.size() && !maControls[mnCurTabStop]->IsEnabled() ); - } - else - { - do - { - ++mnCurTabStop; - if ( mnCurTabStop >= maControls.size() ) - mnCurTabStop = 0; - ++nIterCount; - } while ( nIterCount <= maControls.size() && !maControls[mnCurTabStop]->IsEnabled() ); - } - - if ( nIterCount <= maControls.size() ) - { - maControls[mnCurTabStop]->SetFakeFocus( true ); - maControls[mnCurTabStop]->GrabFocus(); - } - // else : all controls are disabled, so can't do anything -} - -void ScTabStops::clear() -{ - mnCurTabStop = 0; - maControlToPos.clear(); - maControls.clear(); -} - -ScCheckListBox::ScCheckListBox( vcl::Window* pParent ) - : SvTreeListBox( pParent, 0 ), mbSeenMouseButtonDown( false ) -{ - Init(); - set_id("check_list_box"); -} - -SvTreeListEntry* ScCheckListBox::FindEntry( SvTreeListEntry* pParent, const OUString& sNode ) -{ - sal_uInt32 nRootPos = 0; - SvTreeListEntry* pEntry = pParent ? FirstChild( pParent ) : GetEntry( nRootPos ); - while ( pEntry ) - { - if ( sNode == GetEntryText( pEntry ) ) - return pEntry; - - pEntry = pParent ? pEntry->NextSibling() : GetEntry( ++nRootPos ); + if (sNode == mxChecks->get_text(*xEntry, 0)) + return xEntry; + bEntry = mxChecks->iter_next_sibling(*xEntry); } return nullptr; } -void ScCheckListBox::Init() +void ScCheckListMenuControl::GetRecursiveChecked(const weld::TreeIter* pEntry, std::unordered_set<OUString>& vOut, + OUString& rLabel) { - mpCheckButton.reset( new SvLBoxButtonData( this ) ); - EnableCheckButton( mpCheckButton.get() ); - SetNodeDefaultImages(); -} - -void ScCheckListBox::GetRecursiveChecked( SvTreeListEntry* pEntry, std::unordered_set<OUString>& vOut, - OUString& rLabel ) -{ - if (GetCheckButtonState(pEntry) == SvButtonState::Checked) + if (mxChecks->get_toggle(*pEntry) == TRISTATE_TRUE) { // We have to hash parents and children together. // Per convention for easy access in getResult() // "child;parent;grandparent" while descending. if (rLabel.isEmpty()) - rLabel = GetEntryText(pEntry); + rLabel = mxChecks->get_text(*pEntry, 0); else - rLabel = GetEntryText(pEntry) + ";" + rLabel; + rLabel = mxChecks->get_text(*pEntry, 0) + ";" + rLabel; // Prerequisite: the selection mechanism guarantees that if a child is // selected then also the parent is selected, so we only have to // inspect the children in case the parent is selected. - if (pEntry->HasChildren()) + if (mxChecks->iter_has_child(*pEntry)) { - const SvTreeListEntries& rChildren = pEntry->GetChildEntries(); - for (auto& rChild : rChildren) + std::unique_ptr<weld::TreeIter> xChild(mxChecks->make_iterator(pEntry)); + bool bChild = mxChecks->iter_children(*xChild); + while (bChild) { OUString aLabel = rLabel; - GetRecursiveChecked( rChild.get(), vOut, aLabel); + GetRecursiveChecked(xChild.get(), vOut, aLabel); if (!aLabel.isEmpty() && aLabel != rLabel) - vOut.insert( aLabel); + vOut.insert(aLabel); + bChild = mxChecks->iter_next_sibling(*xChild); } // Let the caller not add the parent alone. rLabel.clear(); @@ -1702,228 +972,215 @@ void ScCheckListBox::GetRecursiveChecked( SvTreeListEntry* pEntry, std::unordere } } -std::unordered_set<OUString> ScCheckListBox::GetAllChecked() +std::unordered_set<OUString> ScCheckListMenuControl::GetAllChecked() { std::unordered_set<OUString> vResults(0); - sal_uInt32 nRootPos = 0; - SvTreeListEntry* pEntry = GetEntry(nRootPos); - while (pEntry) + + std::unique_ptr<weld::TreeIter> xEntry = mxChecks->make_iterator(); + bool bEntry = mxChecks->get_iter_first(*xEntry); + while (bEntry) { OUString aLabel; - GetRecursiveChecked( pEntry, vResults, aLabel); + GetRecursiveChecked(xEntry.get(), vResults, aLabel); if (!aLabel.isEmpty()) - vResults.insert( aLabel); - pEntry = GetEntry(++nRootPos); + vResults.insert(aLabel); + bEntry = mxChecks->iter_next_sibling(*xEntry); } return vResults; } -bool ScCheckListBox::IsChecked( const OUString& sName, SvTreeListEntry* pParent ) +bool ScCheckListMenuControl::IsChecked(const OUString& sName, const weld::TreeIter* pParent) { - SvTreeListEntry* pEntry = FindEntry( pParent, sName ); - return pEntry && GetCheckButtonState( pEntry ) == SvButtonState::Checked; + std::unique_ptr<weld::TreeIter> xEntry = FindEntry(pParent, sName); + return xEntry && mxChecks->get_toggle(*xEntry) == TRISTATE_TRUE; } -void ScCheckListBox::CheckEntry( const OUString& sName, SvTreeListEntry* pParent, bool bCheck ) +void ScCheckListMenuControl::CheckEntry(const OUString& sName, const weld::TreeIter* pParent, bool bCheck) { - SvTreeListEntry* pEntry = FindEntry( pParent, sName ); - if ( pEntry ) - CheckEntry( pEntry, bCheck ); + std::unique_ptr<weld::TreeIter> xEntry = FindEntry(pParent, sName); + if (xEntry) + CheckEntry(xEntry.get(), bCheck); } // Recursively check all children of pParent -void ScCheckListBox::CheckAllChildren( SvTreeListEntry* pParent, bool bCheck ) +void ScCheckListMenuControl::CheckAllChildren(const weld::TreeIter* pParent, bool bCheck) { - if ( pParent ) + if (pParent) + mxChecks->set_toggle(*pParent, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE); + std::unique_ptr<weld::TreeIter> xEntry = mxChecks->make_iterator(pParent); + bool bEntry = pParent ? mxChecks->iter_children(*xEntry) : mxChecks->get_iter_first(*xEntry); + while (bEntry) { - SetCheckButtonState( - pParent, bCheck ? SvButtonState::Checked : SvButtonState::Unchecked ); - } - SvTreeListEntry* pEntry = pParent ? FirstChild( pParent ) : First(); - while ( pEntry ) - { - CheckAllChildren( pEntry, bCheck ); - pEntry = pEntry->NextSibling(); + CheckAllChildren(xEntry.get(), bCheck); + bEntry = mxChecks->iter_next_sibling(*xEntry); } } -void ScCheckListBox::CheckEntry( SvTreeListEntry* pParent, bool bCheck ) +void ScCheckListMenuControl::CheckEntry(const weld::TreeIter* pParent, bool bCheck) { // recursively check all items below pParent - CheckAllChildren( pParent, bCheck ); + CheckAllChildren(pParent, bCheck); // checking pParent can affect ancestors, e.g. if ancestor is unchecked and pParent is // now checked then the ancestor needs to be checked also - SvTreeListEntry* pAncestor = GetParent(pParent); - if ( pAncestor ) + if (pParent && mxChecks->get_iter_depth(*pParent)) { - while ( pAncestor ) + std::unique_ptr<weld::TreeIter> xAncestor(mxChecks->make_iterator(pParent)); + bool bAncestor = mxChecks->iter_parent(*xAncestor); + while (bAncestor) { // if any first level children checked then ancestor // needs to be checked, similarly if no first level children // checked then ancestor needs to be unchecked - SvTreeListEntry* pChild = FirstChild( pAncestor ); + std::unique_ptr<weld::TreeIter> xChild(mxChecks->make_iterator(xAncestor.get())); + bool bChild = mxChecks->iter_children(*xChild); bool bChildChecked = false; - while ( pChild ) + while (bChild) { - if ( GetCheckButtonState( pChild ) == SvButtonState::Checked ) + if (mxChecks->get_toggle(*xChild) == TRISTATE_TRUE) { bChildChecked = true; break; } - pChild = pChild->NextSibling(); + bChild = mxChecks->iter_next_sibling(*xChild); } - SetCheckButtonState( pAncestor, bChildChecked ? SvButtonState::Checked : SvButtonState::Unchecked ); - pAncestor = GetParent(pAncestor); + mxChecks->set_toggle(*xAncestor, bChildChecked ? TRISTATE_TRUE : TRISTATE_FALSE); + bAncestor = mxChecks->iter_parent(*xAncestor); } } } -SvTreeListEntry* ScCheckListBox::ShowCheckEntry( const OUString& sName, ScCheckListMember& rMember, bool bShow, bool bCheck ) +std::unique_ptr<weld::TreeIter> ScCheckListMenuControl::ShowCheckEntry(const OUString& sName, ScCheckListMember& rMember, bool bShow, bool bCheck) { - SvTreeListEntry* pEntry = nullptr; - if (!rMember.mbDate || rMember.mpParent) - pEntry = FindEntry( rMember.mpParent, sName ); + std::unique_ptr<weld::TreeIter> xEntry; + if (!rMember.mbDate || rMember.mxParent) + xEntry = FindEntry(rMember.mxParent.get(), sName); if ( bShow ) { - if ( !pEntry ) + if (!xEntry) { if (rMember.mbDate) { if (rMember.maDateParts.empty()) return nullptr; - SvTreeListEntry* pYearEntry = FindEntry( nullptr, rMember.maDateParts[0] ); - if ( !pYearEntry ) - pYearEntry = InsertEntry( rMember.maDateParts[0], nullptr, true ); - SvTreeListEntry* pMonthEntry = FindEntry( pYearEntry, rMember.maDateParts[1] ); - if ( !pMonthEntry ) - pMonthEntry = InsertEntry( rMember.maDateParts[1], pYearEntry, true ); - SvTreeListEntry* pDayEntry = FindEntry( pMonthEntry, rMember.maName ); - if ( !pDayEntry ) - pDayEntry = InsertEntry( rMember.maName, pMonthEntry ); - - return pDayEntry; // Return leaf node + std::unique_ptr<weld::TreeIter> xYearEntry = FindEntry(nullptr, rMember.maDateParts[0]); + if (!xYearEntry) + { + xYearEntry = mxChecks->make_iterator(); + mxChecks->insert(nullptr, -1, nullptr, nullptr, nullptr, nullptr, false, xYearEntry.get()); + mxChecks->set_toggle(*xYearEntry, TRISTATE_FALSE); + mxChecks->set_text(*xYearEntry, rMember.maDateParts[0], 0); + } + std::unique_ptr<weld::TreeIter> xMonthEntry = FindEntry(xYearEntry.get(), rMember.maDateParts[1]); + if (!xMonthEntry) + { + xMonthEntry = mxChecks->make_iterator(); + mxChecks->insert(xYearEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, false, xMonthEntry.get()); + mxChecks->set_toggle(*xMonthEntry, TRISTATE_FALSE); + mxChecks->set_text(*xMonthEntry, rMember.maDateParts[1], 0); + } + std::unique_ptr<weld::TreeIter> xDayEntry = FindEntry(xMonthEntry.get(), rMember.maName); + if (!xDayEntry) + { + xDayEntry = mxChecks->make_iterator(); + mxChecks->insert(xMonthEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, false, xDayEntry.get()); + mxChecks->set_toggle(*xDayEntry, TRISTATE_FALSE); + mxChecks->set_text(*xDayEntry, rMember.maName, 0); + } + return xDayEntry; // Return leaf node } - pEntry = InsertEntry( - sName); - - SetCheckButtonState( - pEntry, bCheck ? SvButtonState::Checked : SvButtonState::Unchecked); + xEntry = mxChecks->make_iterator(); + mxChecks->append(xEntry.get()); + mxChecks->set_toggle(*xEntry, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE); + mxChecks->set_text(*xEntry, sName, 0); } else - CheckEntry( pEntry, bCheck ); + CheckEntry(xEntry.get(), bCheck); } - else if ( pEntry ) + else if (xEntry) { - GetModel()->Remove( pEntry ); - SvTreeListEntry* pParent = rMember.mpParent; - while ( pParent && !pParent->HasChildren() ) + mxChecks->remove(*xEntry); + if (rMember.mxParent) { - SvTreeListEntry* pTmp = pParent; - pParent = pTmp->GetParent(); - GetModel()->Remove( pTmp ); + std::unique_ptr<weld::TreeIter> xParent(mxChecks->make_iterator(rMember.mxParent.get())); + while (xParent && !mxChecks->iter_has_child(*xParent)) + { + std::unique_ptr<weld::TreeIter> xTmp(mxChecks->make_iterator(xParent.get())); + if (!mxChecks->iter_parent(*xParent)) + xParent.reset(); + mxChecks->remove(*xTmp); + } } } return nullptr; } -void ScCheckListBox::CountCheckedEntries( SvTreeListEntry* pParent, sal_uLong& nCount ) const +int ScCheckListMenuControl::GetCheckedEntryCount() const { - if ( pParent && GetCheckButtonState( pParent ) == SvButtonState::Checked ) - nCount++; - // Iterate over the children - SvTreeListEntry* pEntry = pParent ? FirstChild( pParent ) : First(); - while ( pEntry ) - { - CountCheckedEntries( pEntry, nCount ); - pEntry = pEntry->NextSibling(); - } -} + int nRet = 0; -sal_uInt16 ScCheckListBox::GetCheckedEntryCount() const -{ - sal_uLong nCount = 0; - CountCheckedEntries( nullptr, nCount ); - return nCount; + mxChecks->all_foreach([this, &nRet](weld::TreeIter& rEntry){ + if (mxChecks->get_toggle(rEntry) == TRISTATE_TRUE) + ++nRet; + return false; + }); + + return nRet; } -void ScCheckListBox::KeyInput( const KeyEvent& rKEvt ) +IMPL_LINK(ScCheckListMenuControl, KeyInputHdl, const KeyEvent&, rKEvt, bool) { const vcl::KeyCode& rKey = rKEvt.GetKeyCode(); if ( rKey.GetCode() == KEY_RETURN || rKey.GetCode() == KEY_SPACE ) { - SvTreeListEntry* pEntry = GetCurEntry(); - if ( pEntry ) + std::unique_ptr<weld::TreeIter> xEntry = mxChecks->make_iterator(); + bool bEntry = mxChecks->get_cursor(xEntry.get()); + if (bEntry) { - bool bCheck = ( GetCheckButtonState( pEntry ) == SvButtonState::Checked ); - CheckEntry( pEntry, !bCheck ); - if ( bCheck != ( GetCheckButtonState( pEntry ) == SvButtonState::Checked ) ) - CheckButtonHdl(); + bool bOldCheck = mxChecks->get_toggle(*xEntry) == TRISTATE_TRUE; + CheckEntry(xEntry.get(), !bOldCheck); + bool bNewCheck = mxChecks->get_toggle(*xEntry) == TRISTATE_TRUE; + if (bOldCheck != bNewCheck) + Check(xEntry.get()); } + return true; } - else if ( GetEntryCount() ) - SvTreeListBox::KeyInput( rKEvt ); -} - -void ScCheckListBox::MouseButtonDown(const MouseEvent& rMEvt) -{ - SvTreeListBox::MouseButtonDown( rMEvt ); - if ( rMEvt.IsLeft() ) - mbSeenMouseButtonDown = true; -} - -void ScCheckListBox::MouseButtonUp(const MouseEvent& rMEvt) -{ - SvTreeListBox::MouseButtonUp( rMEvt ); - if ( mpTabStops && mbSeenMouseButtonDown && rMEvt.IsLeft() ) - { - mpTabStops->SetTabStop( this ); - mbSeenMouseButtonDown = false; - } -} -void ScSearchEdit::MouseButtonDown(const MouseEvent& rMEvt) -{ - Edit::MouseButtonDown( rMEvt ); - if ( mpTabStops && rMEvt.IsLeft() && rMEvt.GetClicks() >= 1 ) - mpTabStops->SetTabStop( this ); + return false; } -void ScCheckListMenuWindow::setHasDates(bool bHasDates) +void ScCheckListMenuControl::setHasDates(bool bHasDates) { mbHasDates = bHasDates; - // Enables type-ahead search in the check list box. - maChecks->SetQuickSearch(true); - if (mbHasDates) - maChecks->SetStyle(WB_HASBUTTONS | WB_HASLINES | WB_HASLINESATROOT | WB_HASBUTTONSATROOT); - else - maChecks->SetStyle(WB_HASBUTTONS); + mxChecks->set_show_expanders(mbHasDates); } -size_t ScCheckListMenuWindow::initMembers() +size_t ScCheckListMenuControl::initMembers() { size_t n = maMembers.size(); size_t nVisMemCount = 0; - maChecks->SetUpdateMode(false); - maChecks->GetModel()->EnableInvalidate(false); + mxChecks->freeze(); + + std::unique_ptr<weld::TreeIter> xEntry = mxChecks->make_iterator(); + std::vector<std::unique_ptr<weld::TreeIter>> aExpandRows; for (size_t i = 0; i < n; ++i) { if (maMembers[i].mbDate) { - maChecks->CheckEntry(maMembers[i].maName, maMembers[i].mpParent, maMembers[i].mbVisible); + CheckEntry(maMembers[i].maName, maMembers[i].mxParent.get(), maMembers[i].mbVisible); // Expand first node of checked dates - if (!maMembers[i].mpParent && maChecks->IsChecked(maMembers[i].maName, maMembers[i].mpParent)) + if (!maMembers[i].mxParent && IsChecked(maMembers[i].maName, maMembers[i].mxParent.get())) { - SvTreeListEntry* pEntry = maChecks->FindEntry(nullptr, maMembers[i].maName); - if (pEntry) - maChecks->Expand(pEntry); + std::unique_ptr<weld::TreeIter> xDateEntry = FindEntry(nullptr, maMembers[i].maName); + if (xDateEntry) + aExpandRows.emplace_back(std::move(xDateEntry)); } } else @@ -1931,11 +1188,10 @@ size_t ScCheckListMenuWindow::initMembers() OUString aLabel = maMembers[i].maName; if (aLabel.isEmpty()) aLabel = ScResId(STR_EMPTYDATA); - SvTreeListEntry* pEntry = maChecks->InsertEntry( - aLabel); - maChecks->SetCheckButtonState( - pEntry, maMembers[i].mbVisible ? SvButtonState::Checked : SvButtonState::Unchecked); + mxChecks->append(xEntry.get()); + mxChecks->set_toggle(*xEntry, maMembers[i].mbVisible ? TRISTATE_TRUE : TRISTATE_FALSE); + mxChecks->set_text(*xEntry, aLabel, 0); } if (maMembers[i].mbVisible) @@ -1944,40 +1200,46 @@ size_t ScCheckListMenuWindow::initMembers() if (nVisMemCount == n) { // all members visible - maChkToggleAll->SetState(TRISTATE_TRUE); + mxChkToggleAll->set_state(TRISTATE_TRUE); mePrevToggleAllState = TRISTATE_TRUE; } else if (nVisMemCount == 0) { // no members visible - maChkToggleAll->SetState(TRISTATE_FALSE); + mxChkToggleAll->set_state(TRISTATE_FALSE); mePrevToggleAllState = TRISTATE_FALSE; } else { - maChkToggleAll->SetState(TRISTATE_INDET); + mxChkToggleAll->set_state(TRISTATE_INDET); mePrevToggleAllState = TRISTATE_INDET; } - maChecks->GetModel()->EnableInvalidate(true); - maChecks->SetUpdateMode(true); + mxChecks->thaw(); + + for (auto& rRow : aExpandRows) + mxChecks->expand_row(*rRow); + + if (nVisMemCount) + mxChecks->select(0); + return nVisMemCount; } -void ScCheckListMenuWindow::setConfig(const Config& rConfig) +void ScCheckListMenuControl::setConfig(const Config& rConfig) { maConfig = rConfig; } -bool ScCheckListMenuWindow::isAllSelected() const +bool ScCheckListMenuControl::isAllSelected() const { - return maChkToggleAll->IsChecked(); + return mxChkToggleAll->get_state() == TRISTATE_TRUE; } -void ScCheckListMenuWindow::getResult(ResultType& rResult) +void ScCheckListMenuControl::getResult(ResultType& rResult) { ResultType aResult; - std::unordered_set<OUString> vCheckeds = maChecks->GetAllChecked(); + std::unordered_set<OUString> vCheckeds = GetAllChecked(); size_t n = maMembers.size(); for (size_t i = 0; i < n; ++i) { @@ -1990,12 +1252,16 @@ void ScCheckListMenuWindow::getResult(ResultType& rResult) /* TODO: performance-wise this looks suspicious, concatenating to * do the lookup for each leaf item seems wasteful. */ // Checked labels are in the form "child;parent;grandparent". - for (SvTreeListEntry* pParent = maMembers[i].mpParent; - pParent && pParent->GetFirstItem( SvLBoxItemType::String); - pParent = pParent->GetParent()) + if (maMembers[i].mxParent) { - aLabel.append(";").append(maChecks->GetEntryText( pParent)); + std::unique_ptr<weld::TreeIter> xIter(mxChecks->make_iterator(maMembers[i].mxParent.get())); + do + { + aLabel.append(";").append(mxChecks->get_text(*xIter)); + } + while (mxChecks->iter_parent(*xIter)); } + bool bState = vCheckeds.find(aLabel.makeStringAndClear()) != vCheckeds.end(); ResultEntry aResultEntry; @@ -2011,12 +1277,12 @@ void ScCheckListMenuWindow::getResult(ResultType& rResult) rResult.swap(aResult); } -void ScCheckListMenuWindow::launch(const tools::Rectangle& rRect) +void ScCheckListMenuControl::launch(const tools::Rectangle& rRect) { packWindow(); if (!maConfig.mbAllowEmptySet) // We need to have at least one member selected. - maBtnOk->Enable(maChecks->GetCheckedEntryCount() != 0); + mxBtnOk->set_sensitive(GetCheckedEntryCount() != 0); tools::Rectangle aRect(rRect); if (maConfig.mbRTL) @@ -2035,42 +1301,40 @@ void ScCheckListMenuWindow::launch(const tools::Rectangle& rRect) } StartPopupMode(aRect, (FloatWinPopupFlags::Down | FloatWinPopupFlags::GrabFocus)); - maTabStops.CycleFocus(); // Set initial focus to the search box ( index = 1 ) } -void ScCheckListMenuWindow::close(bool bOK) +void ScCheckListMenuControl::close(bool bOK) { - if (bOK && mpOKAction) - mpOKAction->execute(); - + if (bOK && mxOKAction) + mxOKAction->execute(); EndPopupMode(); } -void ScCheckListMenuWindow::setExtendedData(std::unique_ptr<ExtendedData> p) +void ScCheckListMenuControl::setExtendedData(std::unique_ptr<ExtendedData> p) { - mpExtendedData = std::move(p); + mxExtendedData = std::move(p); } -ScCheckListMenuWindow::ExtendedData* ScCheckListMenuWindow::getExtendedData() +ScCheckListMenuControl::ExtendedData* ScCheckListMenuControl::getExtendedData() { - return mpExtendedData.get(); + return mxExtendedData.get(); } -void ScCheckListMenuWindow::setOKAction(Action* p) +void ScCheckListMenuControl::setOKAction(Action* p) { - mpOKAction.reset(p); + mxOKAction.reset(p); } -void ScCheckListMenuWindow::setPopupEndAction(Action* p) +void ScCheckListMenuControl::setPopupEndAction(Action* p) { - mpPopupEndAction.reset(p); + mxPopupEndAction.reset(p); } -void ScCheckListMenuWindow::handlePopupEnd() +IMPL_LINK_NOARG(ScCheckListMenuControl, PopupModeEndHdl, FloatingWindow*, void) { clearSelectedMenuItem(); - if (mpPopupEndAction) - mpPopupEndAction->execute(); + if (mxPopupEndAction) + mxPopupEndAction->execute(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/docshell/docsh4.cxx b/sc/source/ui/docshell/docsh4.cxx index 9b948fb94575..c021ee40da3d 100644 --- a/sc/source/ui/docshell/docsh4.cxx +++ b/sc/source/ui/docshell/docsh4.cxx @@ -40,6 +40,7 @@ using namespace ::com::sun::star; #include <svx/ofaitem.hxx> #include <svl/stritem.hxx> #include <svl/whiter.hxx> +#include <vcl/button.hxx> #include <vcl/svapp.hxx> #include <vcl/weld.hxx> #include <svx/dataaccessdescriptor.hxx> diff --git a/sc/source/ui/inc/checklistmenu.hxx b/sc/source/ui/inc/checklistmenu.hxx index 5e988e31e3d7..02c966d8f13d 100644 --- a/sc/source/ui/inc/checklistmenu.hxx +++ b/sc/source/ui/inc/checklistmenu.hxx @@ -10,11 +10,10 @@ #ifndef INCLUDED_SC_SOURCE_UI_INC_CHECKLISTMENU_HXX #define INCLUDED_SC_SOURCE_UI_INC_CHECKLISTMENU_HXX -#include <vcl/popupmenuwindow.hxx> -#include <vcl/button.hxx> -#include <vcl/edit.hxx> +#include <vcl/InterimItemWindow.hxx> +#include <vcl/dockwin.hxx> #include <vcl/timer.hxx> -#include <vcl/svlbitm.hxx> +#include <vcl/weld.hxx> #include <memory> #include <unordered_set> @@ -22,249 +21,12 @@ #include <map> #include <set> -namespace com::sun::star { - namespace accessibility { - class XAccessible; - } -} - class ScDocument; -class ScAccessibleFilterMenu; - -class ScMenuFloatingWindow : public PopupMenuFloatingWindow -{ -public: - static constexpr size_t MENU_NOT_SELECTED = 999; - - /** - * Action to perform when an event takes place. Create a sub-class of - * this to implement the desired action. - */ - class Action - { - public: - virtual ~Action() {} - virtual void execute() = 0; - }; - - explicit ScMenuFloatingWindow(vcl::Window* pParent, ScDocument* pDoc, sal_uInt16 nMenuStackLevel = 0); - virtual ~ScMenuFloatingWindow() override; - void dispose() override; - - virtual void PopupModeEnd() override; - virtual void MouseMove(const MouseEvent& rMEvt) override; - virtual void MouseButtonDown(const MouseEvent& rMEvt) override; - virtual void MouseButtonUp(const MouseEvent& rMEvt) override; - virtual void KeyInput(const KeyEvent& rKEvt) override; - virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override; - virtual css::uno::Reference<css::accessibility::XAccessible> CreateAccessible() override; - - void addMenuItem(const OUString& rText, Action* pAction); - void addSeparator(); - - ScMenuFloatingWindow* addSubMenuItem(const OUString& rText, bool bEnabled); - void setSelectedMenuItem(size_t nPos, bool bSubMenuTimer, bool bEnsureSubMenu); - void selectMenuItem(size_t nPos, bool bSelected, bool bSubMenuTimer); - void clearSelectedMenuItem(); - ScMenuFloatingWindow* getSubMenuWindow(size_t nPos) const; - bool isMenuItemSelected(size_t nPos) const; - size_t getSelectedMenuItem() const { return mnSelectedMenu;} - - void setName(const OUString& rName); - const OUString& getName() const { return maName;} - - void executeMenuItem(size_t nPos); - void getMenuItemPosSize(size_t nPos, Point& rPos, Size& rSize) const; - ScMenuFloatingWindow* getParentMenuWindow() const { return mpParentMenu;} - -protected: - virtual void handlePopupEnd(); - - Size getMenuSize() const; - void drawMenuItem(vcl::RenderContext& rRenderContext, size_t nPos); - void drawSeparator(vcl::RenderContext& rRenderContext, size_t nPos); - void drawAllMenuItems(vcl::RenderContext& rRenderContext); - const vcl::Font& getLabelFont() const - { - return maLabelFont; - } - - void queueLaunchSubMenu(size_t nPos, ScMenuFloatingWindow* pMenu); - void queueCloseSubMenu(); - void launchSubMenu(bool bSetMenuPos); - void endSubMenu(ScMenuFloatingWindow* pSubMenu); - - void fillMenuItemsToAccessible(ScAccessibleFilterMenu* pAccMenu) const; - - ScDocument* getDoc() { return mpDoc;} - -protected: - css::uno::Reference<css::accessibility::XAccessible> mxAccessible; - -private: - struct SubMenuItemData; - void handleMenuTimeout(const SubMenuItemData* pTimer); - - void resizeToFitMenuItems(); - void highlightMenuItem(vcl::RenderContext& rRenderContext, size_t nPos, bool bSelected); - - size_t getEnclosingMenuItem(const Point& rPos) const; - size_t getSubMenuPos(const ScMenuFloatingWindow* pSubMenu); - /** - * Fire a menu highlight event since the accessibility framework needs - * this to track focus on menu items. - */ - void fireMenuHighlightedEvent(); - - /** - * Make sure that the specified submenu is permanently up, the submenu - * close timer is not active, and the correct menu item associated with - * the submenu is highlighted. - */ - void setSubMenuFocused(const ScMenuFloatingWindow* pSubMenu); - - /** - * When a menu item of an invisible submenu is selected, we need to make - * sure that all its parent menu(s) are visible, with the right menu item - * highlighted in each of the parents. Calling this method ensures it. - */ - void ensureSubMenuVisible(ScMenuFloatingWindow* pSubMenu); - - /** - * Dismiss any visible child submenus when a menu item of a parent menu is - * selected. - */ - void ensureSubMenuNotVisible(); - - /** - * Dismiss all visible popup menus and set focus back to the application - * window. This method is called e.g. when a menu action is fired. - */ - void terminateAllPopupMenus(); - -private: - - struct MenuItemData - { - OUString maText; - bool mbEnabled:1; - bool mbSeparator:1; - - std::shared_ptr<Action> mpAction; - VclPtr<ScMenuFloatingWindow> mpSubMenuWin; - - MenuItemData(); - }; - - std::vector<MenuItemData> maMenuItems; - - struct SubMenuItemData - { - Timer maTimer; - VclPtr<ScMenuFloatingWindow> mpSubMenu; - size_t mnMenuPos; - - DECL_LINK( TimeoutHdl, Timer*, void ); - - SubMenuItemData(ScMenuFloatingWindow* pParent); - void reset(); - - private: - VclPtr<ScMenuFloatingWindow> mpParent; - }; - SubMenuItemData maOpenTimer; - SubMenuItemData maCloseTimer; - - vcl::Font maLabelFont; - - // Name of this menu window, taken from the menu item of the parent window - // that launches it (if this is a sub menu). If this is a top-level menu - // window, then this name can be anything. - OUString maName; - - size_t mnSelectedMenu; - size_t mnClickedMenu; - - ScDocument* mpDoc; - - VclPtr<ScMenuFloatingWindow> mpParentMenu; -}; - -class ScCheckListMenuWindow; - -template <class T> struct VclPtr_hash; -template <> struct VclPtr_hash< VclPtr<vcl::Window> > -{ - size_t operator()( const VclPtr<vcl::Window>& r ) const - { - return reinterpret_cast<size_t>(r.get()); - } -}; - -class ScTabStops -{ -private: - typedef std::unordered_map< VclPtr<vcl::Window>, size_t, VclPtr_hash<VclPtr<vcl::Window>> > ControlToPosMap; - VclPtr<ScCheckListMenuWindow> mpMenuWindow; - ControlToPosMap maControlToPos; - std::vector<VclPtr<vcl::Window>> maControls; - size_t mnCurTabStop; -public: - ScTabStops( ScCheckListMenuWindow* mpMenuWin ); - ~ScTabStops(); - void AddTabStop( vcl::Window* pWin ); - void SetTabStop( vcl::Window* pWin ); - void CycleFocus( bool bReverse = false ); - void clear(); -}; +class ScCheckListMenuControl; struct ScCheckListMember; -class ScCheckListBox : public SvTreeListBox -{ - std::unique_ptr<SvLBoxButtonData> mpCheckButton; - ScTabStops* mpTabStops; - bool mbSeenMouseButtonDown; - void CountCheckedEntries( SvTreeListEntry* pParent, sal_uLong& nCount ) const; - void CheckAllChildren( SvTreeListEntry* pEntry, bool bCheck ); - - public: - - ScCheckListBox( vcl::Window* pParent ); - virtual ~ScCheckListBox() override { disposeOnce(); } - virtual void dispose() override { mpCheckButton.reset(); SvTreeListBox::dispose(); } - void Init(); - void CheckEntry( const OUString& sName, SvTreeListEntry* pParent, bool bCheck ); - void CheckEntry( SvTreeListEntry* pEntry, bool bCheck ); - SvTreeListEntry* ShowCheckEntry( const OUString& sName, ScCheckListMember& rMember, bool bShow = true, bool bCheck = true ); - void GetRecursiveChecked( SvTreeListEntry* pEntry, std::unordered_set<OUString>& vOut, OUString& rLabel ); - std::unordered_set<OUString> GetAllChecked(); - bool IsChecked( const OUString& sName, SvTreeListEntry* pParent ); - SvTreeListEntry* FindEntry( SvTreeListEntry* pParent, const OUString& sNode ); - sal_uInt16 GetCheckedEntryCount() const; - virtual void KeyInput( const KeyEvent& rKEvt ) override; - virtual void MouseButtonDown(const MouseEvent& rMEvt) override; - virtual void MouseButtonUp(const MouseEvent& rMEvt) override; - void SetTabStopsContainer( ScTabStops* pTabStops ) { mpTabStops = pTabStops; } -}; - -class ScSearchEdit : public Edit -{ -private: - ScTabStops* mpTabStops; -public: - ScSearchEdit(Window* pParent) - : Edit(pParent) - , mpTabStops(nullptr) - { - set_id("search_edit"); - } - - virtual void MouseButtonDown( const MouseEvent& rMEvt ) override; - void SetTabStopsContainer( ScTabStops* pTabStops ) { mpTabStops = pTabStops; } -}; - struct ScCheckListMember { enum DatePartType @@ -283,16 +45,27 @@ struct ScCheckListMember // To store Year and Month if the member if DAY type std::vector<OUString> maDateParts; ScCheckListMember(); - SvTreeListEntry* mpParent; + std::unique_ptr<weld::TreeIter> mxParent; }; -/** - * This class implements a popup window for field button, for quick access - * of hide-item list, and possibly more stuff related to field options. - */ -class ScCheckListMenuWindow : public ScMenuFloatingWindow +class ScCheckListMenuWindow; + +class ScCheckListMenuControl final { public: + static constexpr size_t MENU_NOT_SELECTED = 999; + + /** + * Action to perform when an event takes place. Create a sub-class of + * this to implement the desired action. + */ + class Action + { + public: + virtual ~Action() {} + virtual void execute() = 0; + }; + struct ResultEntry { OUString aName; @@ -313,6 +86,18 @@ public: }; typedef std::set<ResultEntry> ResultType; + struct MenuItemData + { + OUString maText; + bool mbEnabled:1; + bool mbSeparator:1; + + std::shared_ptr<Action> mxAction; + VclPtr<ScCheckListMenuWindow> mxSubMenuWin; + + MenuItemData(); + }; + /** * Extended data that the client code may need to store. Create a * sub-class of this and store data there. @@ -333,17 +118,19 @@ public: Config(); }; - explicit ScCheckListMenuWindow(vcl::Window* pParent, ScDocument* pDoc, int nWidth = -1); - virtual ~ScCheckListMenuWindow() override; - virtual void dispose() override; + explicit ScCheckListMenuControl(ScCheckListMenuWindow* pParent, vcl::Window* pContainer, ScDocument* pDoc, + bool bCanHaveSubMenu, int nWidth); + ~ScCheckListMenuControl(); - virtual void MouseMove(const MouseEvent& rMEvt) override; - virtual bool EventNotify(NotifyEvent& rNEvt) override; - virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override; - virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override; + void addMenuItem(const OUString& rText, Action* pAction); + void addSeparator(); + ScCheckListMenuWindow* addSubMenuItem(const OUString& rText, bool bEnabled); + void resizeToFitMenuItems(); + + void selectMenuItem(size_t nPos, bool bSubMenuTimer); + void queueLaunchSubMenu(size_t nPos, ScCheckListMenuWindow* pMenu); void setMemberSize(size_t n); - void setHasDates(bool bHasDates); void addDateMember(const OUString& rName, double nVal, bool bVisible); void addMember(const OUString& rName, bool bVisible); size_t initMembers(); @@ -354,6 +141,14 @@ public: void launch(const tools::Rectangle& rRect); void close(bool bOK); + void StartPopupMode(const tools::Rectangle& rRect, FloatWinPopupFlags nPopupModeFlags); + void EndPopupMode(); + + size_t getSubMenuPos(const ScCheckListMenuControl* pSubMenu); + void setSubMenuFocused(const ScCheckListMenuControl* pSubMenu); + void queueCloseSubMenu(); + void clearSelectedMenuItem(); + /** * Set auxiliary data that the client code might need. Note that this * popup window class manages its life time; no explicit deletion of the @@ -366,26 +161,16 @@ public: */ ExtendedData* getExtendedData(); + void GrabFocus(); + void setOKAction(Action* p); void setPopupEndAction(Action* p); -protected: - virtual void handlePopupEnd() override; + void setHasDates(bool bHasDates); private: - class CancelButton : public ::CancelButton - { - public: - CancelButton(ScCheckListMenuWindow* pParent); - virtual ~CancelButton() override; - virtual void dispose() override; - - virtual void Click() override; - - private: - VclPtr<ScCheckListMenuWindow> mpParent; - }; + std::vector<MenuItemData> maMenuItems; enum SectionType { WHOLE, // entire window @@ -408,38 +193,153 @@ private: void packWindow(); void setAllMemberState(bool bSet); void selectCurrentMemberOnly(bool bSet); - void updateMemberParents( const SvTreeListEntry* pLeaf, size_t nIdx ); + void updateMemberParents(const weld::TreeIter* pLeaf, size_t nIdx); + + std::unique_ptr<weld::TreeIter> ShowCheckEntry(const OUString& sName, ScCheckListMember& rMember, bool bShow = true, bool bCheck = true); + void CheckEntry(const OUString& sName, const weld::TreeIter* pParent, bool bCheck); + void CheckEntry(const weld::TreeIter* pEntry, bool bCheck); + void GetRecursiveChecked(const weld::TreeIter* pEntry, std::unordered_set<OUString>& vOut, OUString& rLabel); + std::unordered_set<OUString> GetAllChecked(); + bool IsChecked(const OUString& sName, const weld::TreeIter* pParent); + int GetCheckedEntryCount() const; + void CheckAllChildren(const weld::TreeIter* pEntry, bool bCheck); + + void setSelectedMenuItem(size_t nPos, bool bSubMenuTimer, bool bEnsureSubMenu); + + std::unique_ptr<weld::TreeIter> FindEntry(const weld::TreeIter* pParent, const OUString& sNode); + + void executeMenuItem(size_t nPos); + + /** + * Dismiss all visible popup menus and set focus back to the application + * window. This method is called e.g. when a menu action is fired. + */ + void terminateAllPopupMenus(); + + /** + * Dismiss any visible child submenus when a menu item of a parent menu is + * selected. + */ + void ensureSubMenuNotVisible(); + + void endSubMenu(ScCheckListMenuControl& rSubMenu); + + struct SubMenuItemData; + + void handleMenuTimeout(const SubMenuItemData* pTimer); + + void launchSubMenu(bool bSetMenuPos); - DECL_LINK( ButtonHdl, Button*, void ); - DECL_LINK( TriStateHdl, Button*, void ); - DECL_LINK( CheckHdl, SvTreeListBox*, void ); - DECL_LINK( EdModifyHdl, Edit&, void ); + void CreateDropDown(); + + DECL_LINK(ButtonHdl, weld::Button&, void); + DECL_LINK(TriStateHdl, weld::ToggleButton&, void); + + void Check(const weld::TreeIter* pIter); + + DECL_LINK(CheckHdl, const weld::TreeView::iter_col&, void); + + DECL_LINK(PopupModeEndHdl, FloatingWindow*, void); + + DECL_LINK(EdModifyHdl, weld::Entry&, void); + DECL_LINK(EdActivateHdl, weld::Entry&, bool); + + DECL_LINK(FocusHdl, weld::Widget&, void); + DECL_LINK(RowActivatedHdl, weld::TreeView& rMEvt, bool); + DECL_LINK(SelectHdl, weld::TreeView&, void); + DECL_LINK(TreeSizeAllocHdl, const Size&, void); + DECL_LINK(KeyInputHdl, const KeyEvent&, bool); + DECL_LINK(MenuKeyInputHdl, const KeyEvent&, bool); + + DECL_LINK(PostPopdownHdl, void*, void); private: - VclPtr<ScSearchEdit> maEdSearch; - VclPtr<ScCheckListBox> maChecks; + VclPtr<ScCheckListMenuWindow> mxFrame; + std::unique_ptr<weld::Builder> mxBuilder; + std::unique_ptr<weld::Container> mxContainer; + std::unique_ptr<weld::TreeView> mxMenu; + std::unique_ptr<weld::TreeIter> mxScratchIter; + std::unique_ptr<weld::Entry> mxEdSearch; + std::unique_ptr<weld::Widget> mxBox; + std::unique_ptr<weld::TreeView> mxChecks; + + std::unique_ptr<weld::CheckButton> mxChkToggleAll; + std::unique_ptr<weld::Button> mxBtnSelectSingle; + std::unique_ptr<weld::Button> mxBtnUnselectSingle; - VclPtr<CheckBox> maChkToggleAll; - VclPtr<ImageButton> maBtnSelectSingle; - VclPtr<ImageButton> maBtnUnselectSingle; + std::unique_ptr<weld::Box> mxButtonBox; + std::unique_ptr<weld::Button> mxBtnOk; + std::unique_ptr<weld::Button> mxBtnCancel; - VclPtr<OKButton> maBtnOk; - VclPtr<CancelButton> maBtnCancel; + ScopedVclPtr<VirtualDevice> mxDropDown; std::vector<ScCheckListMember> maMembers; // For Dates std::map<OUString, size_t> maYearMonthMap; - std::unique_ptr<ExtendedData> mpExtendedData; - std::unique_ptr<Action> mpOKAction; - std::unique_ptr<Action> mpPopupEndAction; + std::unique_ptr<ExtendedData> mxExtendedData; + std::unique_ptr<Action> mxOKAction; + std::unique_ptr<Action> mxPopupEndAction; Config maConfig; + int mnWidthHint; /// min width hint Size maWndSize; /// whole window size. Size maMenuSize; /// size of all menu items combined. TriState mePrevToggleAllState; - ScTabStops maTabStops; + + size_t mnSelectedMenu; + + ScDocument* mpDoc; + + ImplSVEvent* mnAsyncPostPopdownId; + bool mbHasDates; + bool mbCanHaveSubMenu; + + struct SubMenuItemData + { + Timer maTimer; + VclPtr<ScCheckListMenuWindow> mpSubMenu; + size_t mnMenuPos; + + DECL_LINK( TimeoutHdl, Timer*, void ); + + SubMenuItemData(ScCheckListMenuControl* pParent); + void reset(); + + private: + ScCheckListMenuControl* mpParent; + }; + + SubMenuItemData maOpenTimer; + SubMenuItemData maCloseTimer; +}; + +/** + * This class implements a popup window for field button, for quick access + * of hide-item list, and possibly more stuff related to field options. + */ +class ScCheckListMenuWindow : public DockingWindow +{ +public: + explicit ScCheckListMenuWindow(vcl::Window* pParent, ScDocument* pDoc, bool bCanHaveSubMenu, int nWidth = -1, + sal_uInt16 nMenuStackLevel = 0, ScCheckListMenuWindow* pParentMenu = nullptr); + virtual void dispose() override; + virtual ~ScCheckListMenuWindow() override; + + virtual void GetFocus() override; + virtual bool EventNotify(NotifyEvent& rNEvt) override; + + ScCheckListMenuWindow* GetParentMenu() { return mxParentMenu; } + ScCheckListMenuControl& get_widget() { return *mxControl; } + + sal_uInt16 GetMenuStackLevel() const { return mnMenuStackLevel; } + +private: + VclPtr<ScCheckListMenuWindow> mxParentMenu; + VclPtr<vcl::Window> mxBox; + std::unique_ptr<ScCheckListMenuControl> mxControl; + sal_uInt16 mnMenuStackLevel; }; #endif diff --git a/sc/source/ui/inc/gridwin.hxx b/sc/source/ui/inc/gridwin.hxx index e04fc42cbc74..b3439381f702 100644 --- a/sc/source/ui/inc/gridwin.hxx +++ b/sc/source/ui/inc/gridwin.hxx @@ -157,7 +157,7 @@ class SAL_DLLPUBLIC_RTTI ScGridWindow : public vcl::Window, public DropTargetHel VclPtr<ScCheckListMenuWindow> mpDPFieldPopup; std::unique_ptr<ScDPFieldButton> mpFilterButton; - ScCheckListMenuWindow::ResultType aSaveAutoFilterResult; + ScCheckListMenuControl::ResultType aSaveAutoFilterResult; sal_uInt16 nCursorHideCount; diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx index 85f2cd517085..9fbc6798d320 100644 --- a/sc/source/ui/view/gridwin.cxx +++ b/sc/source/ui/view/gridwin.cxx @@ -522,7 +522,7 @@ void ScGridWindow::ClickExtern() if (mpDPFieldPopup) { - mpDPFieldPopup->close(false); + mpDPFieldPopup->get_widget().close(false); mpDPFieldPopup.disposeAndClear(); } } @@ -544,13 +544,13 @@ IMPL_LINK( ScGridWindow, PopupSpellingHdl, SpellCallbackInfo&, rInfo, void ) namespace { -struct AutoFilterData : public ScCheckListMenuWindow::ExtendedData +struct AutoFilterData : public ScCheckListMenuControl::ExtendedData { ScAddress maPos; ScDBData* mpData; }; -class AutoFilterAction : public ScMenuFloatingWindow::Action +class AutoFilterAction : public ScCheckListMenuControl::Action { VclPtr<ScGridWindow> mpWindow; ScGridWindow::AutoFilterMode meMode; @@ -563,7 +563,7 @@ public: } }; -class AutoFilterPopupEndAction : public ScMenuFloatingWindow::Action +class AutoFilterPopupEndAction : public ScCheckListMenuControl::Action { VclPtr<ScGridWindow> mpWindow; ScAddress maPos; @@ -583,7 +583,7 @@ class AddItemToEntry public: AddItemToEntry(ScQueryEntry::QueryItemsType& rItems, svl::SharedStringPool& rPool) : mrItems(rItems), mrPool(rPool) {} - void operator() (const ScCheckListMenuWindow::ResultEntry& rEntry) + void operator() (const ScCheckListMenuControl::ResultEntry& rEntry) { if (rEntry.bValid) { @@ -632,17 +632,13 @@ void ScGridWindow::LaunchAutoFilterMenu(SCCOL nCol, SCROW nRow) mpAutoFilterPopup.disposeAndClear(); int nColWidth = ScViewData::ToPixel(pDoc->GetColWidth(nCol, nTab), pViewData->GetPPTX()); - mpAutoFilterPopup.reset(VclPtr<ScCheckListMenuWindow>::Create(this, pDoc, nColWidth)); - - // Avoid flicker when hovering over the menu items. - if (!IsNativeControlSupported(ControlType::Pushbutton, ControlPart::Focus)) - // If NWF renders the focus rects itself, that breaks double-buffering. - mpAutoFilterPopup->RequestDoubleBuffering(true); + mpAutoFilterPopup.reset(VclPtr<ScCheckListMenuWindow>::Create(this, pDoc, false, nColWidth)); + ScCheckListMenuControl& rControl = mpAutoFilterPopup->get_widget(); if (bLOKActive) mpAutoFilterPopup->SetLOKNotifier(SfxViewShell::Current()); - mpAutoFilterPopup->setOKAction(new AutoFilterAction(this, AutoFilterMode::Normal)); - mpAutoFilterPopup->setPopupEndAction( + rControl.setOKAction(new AutoFilterAction(this, AutoFilterMode::Normal)); + rControl.setPopupEndAction( new AutoFilterPopupEndAction(this, ScAddress(nCol, nRow, nTab))); std::unique_ptr<AutoFilterData> pData(new AutoFilterData); pData->maPos = ScAddress(nCol, nRow, nTab); @@ -670,7 +666,7 @@ void ScGridWindow::LaunchAutoFilterMenu(SCCOL nCol, SCROW nRow) return; pData->mpData = pDBData; - mpAutoFilterPopup->setExtendedData(std::move(pData)); + rControl.setExtendedData(std::move(pData)); ScQueryParam aParam; pDBData->GetQueryParam(aParam); @@ -689,8 +685,8 @@ void ScGridWindow::LaunchAutoFilterMenu(SCCOL nCol, SCROW nRow) ScFilterEntries aFilterEntries; pDoc->GetFilterEntries(nCol, nRow, nTab, aFilterEntries); - mpAutoFilterPopup->setHasDates(aFilterEntries.mbHasDates); - mpAutoFilterPopup->setMemberSize(aFilterEntries.size()); + rControl.setHasDates(aFilterEntries.mbHasDates); + rControl.setMemberSize(aFilterEntries.size()); for (const auto& rEntry : aFilterEntries) { const OUString& aVal = rEntry.GetString(); @@ -698,38 +694,40 @@ void ScGridWindow::LaunchAutoFilterMenu(SCCOL nCol, SCROW nRow) if (!aSelected.empty()) bSelected = aSelected.count(aVal) > 0; if ( rEntry.IsDate() ) - mpAutoFilterPopup->addDateMember( aVal, rEntry.GetValue(), bSelected ); + rControl.addDateMember( aVal, rEntry.GetValue(), bSelected ); else - mpAutoFilterPopup->addMember(aVal, bSelected); + rControl.addMember(aVal, bSelected); } - mpAutoFilterPopup->initMembers(); + rControl.initMembers(); // Populate the menu. - mpAutoFilterPopup->addMenuItem( + rControl.addMenuItem( ScResId(STR_MENU_SORT_ASC), new AutoFilterAction(this, AutoFilterMode::SortAscending)); - mpAutoFilterPopup->addMenuItem( + rControl.addMenuItem( ScResId(STR_MENU_SORT_DESC), new AutoFilterAction(this, AutoFilterMode::SortDescending)); - mpAutoFilterPopup->addSeparator(); - mpAutoFilterPopup->addMenuItem( + rControl.addSeparator(); + rControl.addMenuItem( ScResId(SCSTR_TOP10FILTER), new AutoFilterAction(this, AutoFilterMode::Top10)); - mpAutoFilterPopup->addMenuItem( + rControl.addMenuItem( ScResId(SCSTR_FILTER_EMPTY), new AutoFilterAction(this, AutoFilterMode::Empty)); - mpAutoFilterPopup->addMenuItem( + rControl.addMenuItem( ScResId(SCSTR_FILTER_NOTEMPTY), new AutoFilterAction(this, AutoFilterMode::NonEmpty)); - mpAutoFilterPopup->addSeparator(); - mpAutoFilterPopup->addMenuItem( + rControl.addSeparator(); + rControl.addMenuItem( ScResId(SCSTR_STDFILTER), new AutoFilterAction(this, AutoFilterMode::Custom)); - ScCheckListMenuWindow::Config aConfig; + ScCheckListMenuControl::Config aConfig; aConfig.mbAllowEmptySet = false; aConfig.mbRTL = pViewData->GetDocument()->IsLayoutRTL(pViewData->GetTabNo()); - mpAutoFilterPopup->setConfig(aConfig); - mpAutoFilterPopup->launch(aCellRect); + rControl.setConfig(aConfig); + if (IsMouseCaptured()) + ReleaseMouse(); + rControl.launch(aCellRect); // remember filter rules before modification - mpAutoFilterPopup->getResult(aSaveAutoFilterResult); + rControl.getResult(aSaveAutoFilterResult); collectUIInformation(OUString::number(nRow), OUString::number(nCol)); } @@ -747,8 +745,10 @@ void ScGridWindow::RefreshAutoFilterButton(const ScAddress& rPos) void ScGridWindow::UpdateAutoFilterFromMenu(AutoFilterMode eMode) { + ScCheckListMenuControl& rControl = mpAutoFilterPopup->get_widget(); + const AutoFilterData* pData = - static_cast<const AutoFilterData*>(mpAutoFilterPopup->getExtendedData()); + static_cast<const AutoFilterData*>(rControl.getExtendedData()); if (!pData) return; @@ -812,8 +812,8 @@ void ScGridWindow::UpdateAutoFilterFromMenu(AutoFilterMode eMode) if (eMode == AutoFilterMode::Normal) { // Do not recreate autofilter rules if there are no changes from the user - ScCheckListMenuWindow::ResultType aResult; - mpAutoFilterPopup->getResult(aResult); + ScCheckListMenuControl::ResultType aResult; + rControl.getResult(aResult); if (aResult == aSaveAutoFilterResult) { @@ -832,7 +832,7 @@ void ScGridWindow::UpdateAutoFilterFromMenu(AutoFilterMode eMode) // Remove old entries in auto-filter rules aParam.RemoveAllEntriesByField(rPos.Col()); - if( !(eMode == AutoFilterMode::Normal && mpAutoFilterPopup->isAllSelected() ) ) + if( !(eMode == AutoFilterMode::Normal && rControl.isAllSelected() ) ) { // Try to use the existing entry for the column (if one exists). ScQueryEntry* pEntry = aParam.FindEntryByField(rPos.Col(), true); @@ -854,8 +854,8 @@ void ScGridWindow::UpdateAutoFilterFromMenu(AutoFilterMode eMode) { pEntry->eOp = SC_EQUAL; - ScCheckListMenuWindow::ResultType aResult; - mpAutoFilterPopup->getResult(aResult); + ScCheckListMenuControl::ResultType aResult; + rControl.getResult(aResult); ScQueryEntry::QueryItemsType& rItems = pEntry->GetQueryItems(); rItems.clear(); diff --git a/sc/source/ui/view/gridwin2.cxx b/sc/source/ui/view/gridwin2.cxx index 134a6f4734ed..71a68605d1d2 100644 --- a/sc/source/ui/view/gridwin2.cxx +++ b/sc/source/ui/view/gridwin2.cxx @@ -370,14 +370,14 @@ bool ScGridWindow::DPTestFieldPopupArrow( namespace { -struct DPFieldPopupData : public ScCheckListMenuWindow::ExtendedData +struct DPFieldPopupData : public ScCheckListMenuControl::ExtendedData { ScDPLabelData maLabels; ScDPObject* mpDPObj; long mnDim; }; -class DPFieldPopupOKAction : public ScMenuFloatingWindow::Action +class DPFieldPopupOKAction : public ScCheckListMenuControl::Action { public: explicit DPFieldPopupOKAction(ScGridWindow* p) : @@ -391,7 +391,7 @@ private: VclPtr<ScGridWindow> mpGridWindow; }; -class PopupSortAction : public ScMenuFloatingWindow::Action +class PopupSortAction : public ScCheckListMenuControl::Action { public: enum SortType { ASCENDING, DESCENDING, CUSTOM }; @@ -458,6 +458,8 @@ void ScGridWindow::DPLaunchFieldPopupMenu(const Point& rScrPos, const Size& rScr // This should never happen. return; + bool bDimOrientNotPage = pDim->GetOrientation() != DataPilotFieldOrientation_PAGE; + // We need to get the list of field members. pDPObj->FillLabelData(pDPData->mnDim, pDPData->maLabels); pDPData->mpDPObj = pDPObj; @@ -465,34 +467,29 @@ void ScGridWindow::DPLaunchFieldPopupMenu(const Point& rScrPos, const Size& rScr const ScDPLabelData& rLabelData = pDPData->maLabels; mpDPFieldPopup.disposeAndClear(); - mpDPFieldPopup.reset(VclPtr<ScCheckListMenuWindow>::Create(this, pViewData->GetDocument())); - - // Avoid flicker when hovering over the menu items. - if (!IsNativeControlSupported(ControlType::Pushbutton, ControlPart::Focus)) - // If NWF renders the focus rects itself, that breaks double-buffering. - mpDPFieldPopup->RequestDoubleBuffering(true); + mpDPFieldPopup.reset(VclPtr<ScCheckListMenuWindow>::Create(this, pViewData->GetDocument(), bDimOrientNotPage)); - mpDPFieldPopup->setName("DataPilot field member popup"); - mpDPFieldPopup->setExtendedData(std::move(pDPData)); - mpDPFieldPopup->setOKAction(new DPFieldPopupOKAction(this)); + ScCheckListMenuControl& rControl = mpDPFieldPopup->get_widget(); + rControl.setExtendedData(std::move(pDPData)); + rControl.setOKAction(new DPFieldPopupOKAction(this)); { // Populate field members. size_t n = rLabelData.maMembers.size(); - mpDPFieldPopup->setMemberSize(n); + rControl.setMemberSize(n); for (size_t i = 0; i < n; ++i) { const ScDPLabelData::Member& rMem = rLabelData.maMembers[i]; OUString aName = rMem.getDisplayName(); if (aName.isEmpty()) // Use special string for an empty name. - mpDPFieldPopup->addMember(ScResId(STR_EMPTYDATA), rMem.mbVisible); + rControl.addMember(ScResId(STR_EMPTYDATA), rMem.mbVisible); else - mpDPFieldPopup->addMember(rMem.getDisplayName(), rMem.mbVisible); + rControl.addMember(rMem.getDisplayName(), rMem.mbVisible); } - mpDPFieldPopup->initMembers(); + rControl.initMembers(); } - if (pDim->GetOrientation() != DataPilotFieldOrientation_PAGE) + if (bDimOrientNotPage) { vector<OUString> aUserSortNames; ScUserList* pUserList = ScGlobal::GetUserList(); @@ -509,35 +506,36 @@ void ScGridWindow::DPLaunchFieldPopupMenu(const Point& rScrPos, const Size& rScr // Populate the menus. ScTabViewShell* pViewShell = pViewData->GetViewShell(); - mpDPFieldPopup->addMenuItem( + rControl.addMenuItem( ScResId(STR_MENU_SORT_ASC), new PopupSortAction(pDPObj, nDimIndex, PopupSortAction::ASCENDING, 0, pViewShell)); - mpDPFieldPopup->addMenuItem( + rControl.addMenuItem( ScResId(STR_MENU_SORT_DESC), new PopupSortAction(pDPObj, nDimIndex, PopupSortAction::DESCENDING, 0, pViewShell)); - ScMenuFloatingWindow* pSubMenu = mpDPFieldPopup->addSubMenuItem( - ScResId(STR_MENU_SORT_CUSTOM), !aUserSortNames.empty()); + ScCheckListMenuWindow* pSubMenu = rControl.addSubMenuItem(ScResId(STR_MENU_SORT_CUSTOM), !aUserSortNames.empty()); if (pSubMenu) { + ScCheckListMenuControl& rSubMenu = pSubMenu->get_widget(); size_t n = aUserSortNames.size(); for (size_t i = 0; i < n; ++i) { - pSubMenu->addMenuItem( - aUserSortNames[i], - new PopupSortAction(pDPObj, nDimIndex, PopupSortAction::CUSTOM, sal_uInt16(i), pViewShell)); + rSubMenu.addMenuItem(aUserSortNames[i], + new PopupSortAction(pDPObj, nDimIndex, PopupSortAction::CUSTOM, sal_uInt16(i), pViewShell)); } + rSubMenu.resizeToFitMenuItems(); } } tools::Rectangle aCellRect(rScrPos, rScrSize); - mpDPFieldPopup->SetPopupModeEndHdl( LINK(this, ScGridWindow, PopupModeEndHdl) ); - ScCheckListMenuWindow::Config aConfig; + ScCheckListMenuControl::Config aConfig; aConfig.mbAllowEmptySet = false; aConfig.mbRTL = pViewData->GetDocument()->IsLayoutRTL(pViewData->GetTabNo()); - mpDPFieldPopup->setConfig(aConfig); - mpDPFieldPopup->launch(aCellRect); + rControl.setConfig(aConfig); + if (IsMouseCaptured()) + ReleaseMouse(); + rControl.launch(aCellRect); } void ScGridWindow::UpdateDPFromFieldPopupMenu() @@ -547,7 +545,9 @@ void ScGridWindow::UpdateDPFromFieldPopupMenu() if (!mpDPFieldPopup) return; - DPFieldPopupData* pDPData = static_cast<DPFieldPopupData*>(mpDPFieldPopup->getExtendedData()); + ScCheckListMenuControl& rControl = mpDPFieldPopup->get_widget(); + + DPFieldPopupData* pDPData = static_cast<DPFieldPopupData*>(rControl.getExtendedData()); if (!pDPData) return; @@ -567,8 +567,8 @@ void ScGridWindow::UpdateDPFromFieldPopupMenu() aMemNameMap.emplace(rMember.maLayoutName, rMember.maName); // The raw result may contain a mixture of layout names and original names. - ScCheckListMenuWindow::ResultType aRawResult; - mpDPFieldPopup->getResult(aRawResult); + ScCheckListMenuControl::ResultType aRawResult; + rControl.getResult(aRawResult); std::unordered_map<OUString, bool> aResult; for (const auto& rItem : aRawResult) diff --git a/sc/uiconfig/scalc/ui/filterdropdown.ui b/sc/uiconfig/scalc/ui/filterdropdown.ui new file mode 100644 index 000000000000..c37771a2116c --- /dev/null +++ b/sc/uiconfig/scalc/ui/filterdropdown.ui @@ -0,0 +1,304 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.2 --> +<interface domain="sw"> + <requires lib="gtk+" version="3.18"/> + <object class="GtkImage" id="image1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="icon_name">sc/res/popup_select_current.png</property> + </object> + <object class="GtkImage" id="image2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="icon_name">sc/res/popup_unselect_current.png</property> + </object> + <object class="GtkTreeStore" id="liststore1"> + <columns> + <!-- column-name text --> + <column type="gchararray"/> + <!-- column-name image1 --> + <column type="GdkPixbuf"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> + <object class="GtkTreeStore" id="liststore2"> + <columns> + <!-- column-name check1 --> + <column type="gboolean"/> + <!-- column-name text --> + <column type="gchararray"/> + <!-- column-name id --> + <column type="gchararray"/> + <!-- column-name checkvis1 --> + <column type="gboolean"/> + <!-- column-name checktri1 --> + <column type="gboolean"/> + </columns> + </object> + <object class="GtkBox" id="FilterDropDown"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">never</property> + <property name="vscrollbar_policy">never</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="menu"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="model">liststore1</property> + <property name="headers_visible">False</property> + <property name="headers_clickable">False</property> + <property name="search_column">0</property> + <property name="hover_selection">True</property> + <property name="show_expanders">False</property> + <property name="activate_on_single_click">True</property> + <child internal-child="selection"> + <object class="GtkTreeSelection" id="treeview-selection1"/> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn1"> + <child> + <object class="GtkCellRendererText" id="cellrenderertext1"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn44"> + <child> + <object class="GtkCellRendererPixbuf" id="cellrenderertext55"/> + <attributes> + <attribute name="pixbuf">1</attribute> + </attributes> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="search_edit"> + <property name="can_focus">True</property> + <property name="no_show_all">True</property> + <property name="tooltip_text" translatable="yes" context="filterdropdown|STR_EDIT_SEARCH_ITEMS">Search items...</property> + <property name="activates_default">True</property> + <property name="placeholder_text" translatable="yes" context="filterdropdown|STR_EDIT_SEARCH_ITEMS">Search items...</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box"> + <property name="can_focus">False</property> + <property name="no_show_all">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkSeparator"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="border_width">3</property> + <property name="spacing">6</property> + <child> + <object class="GtkCheckButton" id="toggle_all"> + <property name="label" translatable="yes" context="filterdropdown|STR_BTN_TOGGLE_ALL">All</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="hexpand">True</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="select_current"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="tooltip_text" translatable="yes" context="filterdropdown|STR_BTN_SELECT_CURRENT">Show only the current item.</property> + <property name="image">image1</property> + <property name="always_show_image">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="unselect_current"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="tooltip_text" translatable="yes" context="filterdropdown|STR_BTN_UNSELECT_CURRENT">Hide only the current item.</property> + <property name="image">image2</property> + <property name="always_show_image">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="hscrollbar_policy">never</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="check_list_box"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="model">liststore2</property> + <property name="headers_visible">False</property> + <property name="headers_clickable">False</property> + <property name="search_column">1</property> + <property name="show_expanders">False</property> + <property name="enable_tree_lines">True</property> + <child internal-child="selection"> + <object class="GtkTreeSelection"/> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn4"> + <property name="resizable">True</property> + <property name="spacing">6</property> + <property name="alignment">0.5</property> + <child> + <object class="GtkCellRendererToggle" id="cellrenderer5"/> + <attributes> + <attribute name="visible">3</attribute> + <attribute name="active">0</attribute> + </attributes> + </child> + <child> + <object class="GtkCellRendererText" id="cellrenderer4"/> + <attributes> + <attribute name="text">1</attribute> + </attributes> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkButtonBox" id="buttonbox"> + <property name="can_focus">False</property> + <property name="no_show_all">True</property> + <property name="spacing">6</property> + <property name="layout_style">spread</property> + <child> + <object class="GtkButton" id="ok"> + <property name="label">gtk-ok</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="cancel"> + <property name="label">gtk-cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> +</interface> diff --git a/sc/uiconfig/scalc/ui/listmenu.ui b/sc/uiconfig/scalc/ui/listmenu.ui new file mode 100644 index 000000000000..c826f21f3eae --- /dev/null +++ b/sc/uiconfig/scalc/ui/listmenu.ui @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.2 --> +<interface domain="sc"> + <requires lib="gtk+" version="3.18"/> + <object class="GtkMenu" id="listmenu"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> +</interface> |