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>
diff --git a/compilerplugins/clang/constantparam.numbers.results b/compilerplugins/clang/constantparam.numbers.results
index dd73f62..49da62a 100644
--- a/compilerplugins/clang/constantparam.numbers.results
+++ b/compilerplugins/clang/constantparam.numbers.results
@@ -1826,10 +1826,6 @@ sax/source/tools/converter.cxx:994
enum sax::(anonymous namespace)::Result readUnsignedNumberMaxDigits(int,const class rtl::OUString &,int &,int &)
int maxDigits
9
sc/inc/AccessibleFilterMenu.hxx:41
void ScAccessibleFilterMenu::ScAccessibleFilterMenu(const class com::sun::star::uno::Reference<class com::sun::star::accessibility::XAccessible> &,class ScMenuFloatingWindow *,const class rtl::OUString &,unsigned long)
unsigned long nMenuPos
999
sc/inc/address.hxx:334
void ScAddress::Format(class rtl::OStringBuffer &,enum ScRefFlags,const class ScDocument *,const struct ScAddress::Details &) const
enum ScRefFlags nFlags
diff --git a/include/vcl/dockwin.hxx b/include/vcl/dockwin.hxx
index f0f0ee5..689a2f4 100644
--- a/include/vcl/dockwin.hxx
+++ b/include/vcl/dockwin.hxx
@@ -83,6 +83,7 @@ private:
VclPtr<FloatingWindow> mpFloatWin;
VclPtr<vcl::Window> mpOldBorderWin;
VclPtr<vcl::Window> mpParent;
Link<FloatingWindow*,void> maPopupModeEndHdl;
Point maFloatPos;
Point maDockPos;
Point maMouseOff;
@@ -138,6 +139,8 @@ public:
void StartPopupMode( ToolBox* pParentToolBox, FloatWinPopupFlags nPopupModeFlags );
bool IsInPopupMode() const;
void SetPopupModeEndHdl( const Link<FloatingWindow*,void>& rLink ) { maPopupModeEndHdl = rLink; }
void TitleButtonClick( TitleButton nButton );
void Resizing( Size& rSize );
void Tracking( const TrackingEvent& rTEvt );
@@ -193,6 +196,8 @@ public:
void StartPopupMode( ToolBox *pParentToolBox, const vcl::Window *pWin );
void StartPopupMode( ToolBox *pParentToolBox, const vcl::Window *pWin, FloatWinPopupFlags nPopupModeFlags );
void SetPopupModeEndHdl( const vcl::Window *pWindow, const Link<FloatingWindow*,void>& rLink );
bool IsInPopupMode( const vcl::Window *pWin );
void EndPopupMode( const vcl::Window *pWin );
diff --git a/sc/IwyuFilter_sc.yaml b/sc/IwyuFilter_sc.yaml
index 03e9818..ee230108 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 997b14c..47b801f 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 8e3de96..38b6aca 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 878c27a..0000000
--- 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 d45b4c2..0000000
--- 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 90dd9bb..0000000
--- 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 a685c1e..6f6b029 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 5446d33..5a1a6ab 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 48149e5..0000000
--- 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 71b63fb..0000000
--- 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 da8cefd..0000000
--- 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 cb2b00b..58a8a9e 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 2797664..0739b81 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))
IMPL_LINK_NOARG(ScCheckListMenuControl, RowActivatedHdl, weld::TreeView&, bool)
{
SetMenuStackLevel(nMenuStackLevel);
SetText("ScMenuFloatingWindow");
const StyleSettings& rStyle = GetSettings().GetStyleSettings();
const sal_uInt16 nPopupFontHeight = 12 * GetDPIScaleFactor();
maLabelFont = rStyle.GetLabelFont();
maLabelFont.SetFontHeight(nPopupFontHeight);
executeMenuItem(mxMenu->get_selected_index());
return true;
}
ScMenuFloatingWindow::~ScMenuFloatingWindow()
IMPL_LINK(ScCheckListMenuControl, MenuKeyInputHdl, const KeyEvent&, rKEvt, bool)
{
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)
{
const Point& rPos = rMEvt.GetPosPixel();
mnClickedMenu = getEnclosingMenuItem(rPos);
Window::MouseButtonDown(rMEvt);
}
void ScMenuFloatingWindow::MouseButtonUp(const MouseEvent& rMEvt)
{
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:
{
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);
}
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;
{
ScCheckListMenuWindow* pParentMenu = mxFrame->GetParentMenu();
if (pParentMenu)
pParentMenu->get_widget().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));
mxMenu->append_separator("seperator" + OUString::number(maMenuItems.size()));
}
ScMenuFloatingWindow* ScMenuFloatingWindow::addSubMenuItem(const OUString& rText, bool bEnabled)
IMPL_LINK(ScCheckListMenuControl, TreeSizeAllocHdl, const Size&, rSize, void)
{
assert(mbCanHaveSubMenu);
std::vector<int> aWidths;
aWidths.push_back(rSize.Width() - (mxMenu->get_text_height() * 3) / 4 - 6);
mxMenu->set_column_fixed_widths(aWidths);
}
void ScCheckListMenuControl::CreateDropDown()
{
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);
}
ScCheckListMenuWindow* ScCheckListMenuControl::addSubMenuItem(const OUString& rText, bool bEnabled)
{
assert(mbCanHaveSubMenu);
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();
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));
mxMenu->append_text(rText);
if (mbCanHaveSubMenu)
mxMenu->set_image(mxMenu->n_children() - 1, *mxDropDown, 1);
return maMenuItems.back().mxSubMenuWin.get();
}
void ScMenuFloatingWindow::handlePopupEnd()
{
clearSelectedMenuItem();
}
Size ScMenuFloatingWindow::getMenuSize() const
{
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());
}
void ScMenuFloatingWindow::drawMenuItem(vcl::RenderContext& rRenderContext, size_t nPos)
void ScCheckListMenuControl::executeMenuItem(size_t nPos)
{
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();
}
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();
}
}
void ScMenuFloatingWindow::drawAllMenuItems(vcl::RenderContext& rRenderContext)
{
size_t n = maMenuItems.size();
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);
}
}
}
void ScMenuFloatingWindow::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;
selectMenuItem(MENU_NOT_SELECTED, false);
}
ScMenuFloatingWindow* ScMenuFloatingWindow::getSubMenuWindow(size_t nPos) const
{
if (maMenuItems.size() <= nPos)
return nullptr;
return maMenuItems[nPos].mpSubMenuWin.get();
}
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 ScCheckListMenuControl::getSubMenuPos(const ScCheckListMenuControl* pSubMenu)
{
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 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;
// 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);
}
vcl::Window::GetDockingManager()->EndPopupMode(mxFrame);
mxFrame->EnableDocking(false);
}
void ScMenuFloatingWindow::ensureSubMenuNotVisible()
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 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);
EndPopupMode();
for (auto& rMenuItem : maMenuItems)
rMenuItem.mxSubMenuWin.disposeAndClear();
if (mnAsyncPostPopdownId)
{
Application::RemoveUserEvent(mnAsyncPostPopdownId);
mnAsyncPostPopdownId = nullptr;
}
}
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 );
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();
mxControl.reset();
mxBox.disposeAndClear();
mxParentMenu.clear();
DockingWindow::dispose();
}
void ScCheckListMenuWindow::getSectionPosSize(
Point& rPos, Size& rSize, SectionType eType) const
void ScCheckListMenuWindow::GetFocus()
{
float fScaleFactor = GetDPIScaleFactor();
DockingWindow::GetFocus();
if (!mxControl)
return;
mxControl->GrabFocus();
}
// 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;
void ScCheckListMenuControl::packWindow()
{
mxBox->show();
mxEdSearch->show();
mxButtonBox->show();
// parameters calculated from constants.
const long nListBoxWidth = maWndSize.Width() - nListBoxMargin*2;
const long nListBoxHeight = maWndSize.Height() - nTopMargin - nMenuHeight -
nMenuListMargin - nSearchBoxHeight - nSearchBoxMargin - nSingleItemBtnAreaHeight - nBottomBtnAreaHeight;
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));
const long nSingleBtnAreaY = nTopMargin + nMenuHeight + nMenuListMargin + nSearchBoxHeight + nSearchBoxMargin;
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();
switch (eType)
maWndSize = mxContainer->get_preferred_size();
if (maWndSize.Width() < mnWidthHint)
{
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:
;
mxContainer->set_size_request(mnWidthHint, -1);
maWndSize.setWidth(mnWidthHint);
}
}
void ScCheckListMenuWindow::packWindow()
void ScCheckListMenuControl::setAllMemberState(bool bSet)
{
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();
;
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();
BitmapEx aSingleUnselectBmp(RID_BMP_UNSELECT_CURRENT);
if (fScaleFactor > 1)
aSingleUnselectBmp.Scale(fScaleFactor, fScaleFactor, BmpScaleFlag::Fast);
Image aSingleUnselect(aSingleUnselectBmp);
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();
}
void ScCheckListMenuWindow::setAllMemberState(bool bSet)
{
size_t n = maMembers.size();
std::set<SvTreeListEntry*> aParents;
for (size_t i = 0; i < n; ++i)
{
aParents.insert(maMembers[i].mpParent);
}
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);
}
}
}
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())
else if (&rBtn == mxBtnCancel.get())
close(false);
else if (&rBtn == mxBtnSelectSingle.get() || &rBtn == mxBtnUnselectSingle.get())
{
selectCurrentMemberOnly(true);
CheckHdl(maChecks.get());
}
else if (pBtn == maBtnUnselectSingle.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);
mxBtnOk->set_sensitive(nNumChecked != 0);
mePrevToggleAllState = maChkToggleAll->GetState();
mePrevToggleAllState = mxChkToggleAll->get_state();
}
void ScCheckListMenuWindow::MouseMove(const MouseEvent& rMEvt)
void ScCheckListMenuControl::updateMemberParents(const weld::TreeIter* pLeaf, size_t nIdx)
{
ScMenuFloatingWindow::MouseMove(rMEvt);
size_t nSelectedMenu = getSelectedMenuItem();
if (nSelectedMenu == MENU_NOT_SELECTED)
queueCloseSubMenu();
}
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));
}
void ScCheckListMenuWindow::updateMemberParents( const SvTreeListEntry* 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;
else if (xYearEntry && !FindEntry(xYearEntry.get(), aMonthName))
maMembers[nIdx].mxParent.reset();
}
}
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);
}
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() )
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();
}
mnCurTabStop = aIter->second;
maControls[mnCurTabStop]->SetFakeFocus( true );
maControls[mnCurTabStop]->GrabFocus();
}
void ScTabStops::CycleFocus( bool bReverse )
{
if (maControls.empty())
return;
if ( mnCurTabStop < maControls.size() )
{
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;
mxChecks->all_foreach([this, &nRet](weld::TreeIter& rEntry){
if (mxChecks->get_toggle(rEntry) == TRISTATE_TRUE)
++nRet;
return false;
});
return nRet;
}
sal_uInt16 ScCheckListBox::GetCheckedEntryCount() const
{
sal_uLong nCount = 0;
CountCheckedEntries( nullptr, nCount );
return nCount;
}
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 );
return false;
}
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 );
}
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 9b948fb..c021ee4 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 5e988e3..02c966d 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);
DECL_LINK( ButtonHdl, Button*, void );
DECL_LINK( TriStateHdl, Button*, void );
DECL_LINK( CheckHdl, SvTreeListBox*, void );
DECL_LINK( EdModifyHdl, Edit&, void );
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);
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;
VclPtr<CheckBox> maChkToggleAll;
VclPtr<ImageButton> maBtnSelectSingle;
VclPtr<ImageButton> maBtnUnselectSingle;
std::unique_ptr<weld::CheckButton> mxChkToggleAll;
std::unique_ptr<weld::Button> mxBtnSelectSingle;
std::unique_ptr<weld::Button> mxBtnUnselectSingle;
VclPtr<OKButton> maBtnOk;
VclPtr<CancelButton> maBtnCancel;
std::unique_ptr<weld::Box> mxButtonBox;
std::unique_ptr<weld::Button> mxBtnOk;
std::unique_ptr<weld::Button> mxBtnCancel;
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 e04fc42..b343938 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 85f2cd5..9fbc679 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 134a6f4..71a6860 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()));
mpDPFieldPopup.reset(VclPtr<ScCheckListMenuWindow>::Create(this, pViewData->GetDocument(), bDimOrientNotPage));
// 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->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 0000000..c37771a
--- /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 0000000..c826f21
--- /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>
diff --git a/solenv/clang-format/blacklist b/solenv/clang-format/blacklist
index 566479f..1a1e268 100644
--- a/solenv/clang-format/blacklist
+++ b/solenv/clang-format/blacklist
@@ -9152,9 +9152,6 @@ sax/test/sax/testsax.cxx
sax/test/sax/testwriter.cxx
sax/test/saxdemo.cxx
sax/test/testcomponent.cxx
sc/inc/AccessibleFilterMenu.hxx
sc/inc/AccessibleFilterMenuItem.hxx
sc/inc/AccessibleFilterTopWindow.hxx
sc/inc/AccessibleGlobal.hxx
sc/inc/ChartTools.hxx
sc/inc/NumberFormatControl.hxx
@@ -10113,9 +10110,6 @@ sc/source/ui/Accessibility/AccessibleDocument.cxx
sc/source/ui/Accessibility/AccessibleDocumentBase.cxx
sc/source/ui/Accessibility/AccessibleDocumentPagePreview.cxx
sc/source/ui/Accessibility/AccessibleEditObject.cxx
sc/source/ui/Accessibility/AccessibleFilterMenu.cxx
sc/source/ui/Accessibility/AccessibleFilterMenuItem.cxx
sc/source/ui/Accessibility/AccessibleFilterTopWindow.cxx
sc/source/ui/Accessibility/AccessibleGlobal.cxx
sc/source/ui/Accessibility/AccessiblePageHeader.cxx
sc/source/ui/Accessibility/AccessiblePageHeaderArea.cxx
diff --git a/svtools/source/control/toolbarmenu.cxx b/svtools/source/control/toolbarmenu.cxx
index da45acf..5c76ae6 100644
--- a/svtools/source/control/toolbarmenu.cxx
+++ b/svtools/source/control/toolbarmenu.cxx
@@ -237,6 +237,8 @@ InterimToolbarPopup::InterimToolbarPopup(const css::uno::Reference<css::frame::X
void InterimToolbarPopup::GetFocus()
{
ToolbarPopup::GetFocus();
if (!m_xPopup)
return;
m_xPopup->GrabFocus();
}
diff --git a/vcl/source/window/dockmgr.cxx b/vcl/source/window/dockmgr.cxx
index 4cd3482..90f9caf 100644
--- a/vcl/source/window/dockmgr.cxx
+++ b/vcl/source/window/dockmgr.cxx
@@ -366,6 +366,13 @@ void DockingManager::EndPopupMode( const vcl::Window *pWin )
pWrapper->GetFloatingWindow()->EndPopupMode();
}
void DockingManager::SetPopupModeEndHdl( const vcl::Window *pWindow, const Link<FloatingWindow*,void>& rLink )
{
ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
if( pWrapper )
pWrapper->SetPopupModeEndHdl(rLink);
}
void DockingManager::AddWindow( const vcl::Window *pWindow )
{
ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow );
@@ -472,6 +479,7 @@ ImplDockingWindowWrapper::ImplDockingWindowWrapper( const vcl::Window *pWindow )
, mbStartDockingEnabled(false)
, mbLocked(false)
{
assert(mpDockingWindow);
DockingWindow *pDockWin = dynamic_cast< DockingWindow* > ( mpDockingWindow.get() );
if( pDockWin )
mnFloatBits = pDockWin->GetFloatStyle();
@@ -850,6 +858,7 @@ IMPL_LINK_NOARG(ImplDockingWindowWrapper, PopupModeEnd, FloatingWindow*, void)
GetWindow()->SetParent( pRealParent );
GetWindow()->mpWindowImpl->mpRealParent = pRealParent;
maPopupModeEndHdl.Call(mpFloatWin);
mpFloatWin.disposeAndClear();
// call handler - which will destroy the window and thus the wrapper as well !