[Libreoffice-commits] core.git: Branch 'private/tvajngerl/staging' - 2 commits - drawinglayer/source include/sfx2 officecfg/registry sfx2/Library_sfx.mk sfx2/sdi sfx2/source sfx2/uiconfig sfx2/UIConfig_sfx.mk vcl/headless vcl/inc

Tomaž Vajngerl (via logerrit) logerrit at kemper.freedesktop.org
Tue Sep 22 13:28:11 UTC 2020


Rebased ref, commits from common ancestor:
commit bc77adc8eb6915e03a2e91183b483000352dedbd
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Tue Sep 22 15:20:57 2020 +0200
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Tue Sep 22 15:27:13 2020 +0200

    use vcl lin. gradient drawing in drawinglayer + cairo impl.
    
    This adds a divert for drawing of linear gradients drawing, which
    can be implemented natively with a much higher quality and speed.
    
    This also adds a implementation of drawing linear gradients with
    cairo.
    
    Change-Id: I8c39915c3579e6eb88cdce8ae4ac9694ffdb4957

diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
index 716c23028ba6..4314c656c389 100644
--- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
@@ -53,6 +53,7 @@
 #include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx>
 #include <drawinglayer/primitive2d/controlprimitive2d.hxx>
 #include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
+#include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
 #include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
 #include <drawinglayer/primitive2d/backgroundcolorprimitive2d.hxx>
@@ -66,6 +67,13 @@
 #include <com/sun/star/awt/XWindow2.hpp>
 #include <com/sun/star/awt/XControl.hpp>
 
+#include <vcl/window.hxx>
+#include <vcl/gradient.hxx>
+#include <svtools/borderhelper.hxx>
+#include <editeng/borderline.hxx>
+
+#include <com/sun/star/table/BorderLineStyle.hpp>
+
 using namespace com::sun::star;
 
 namespace drawinglayer::processor2d
@@ -198,6 +206,30 @@ bool VclPixelProcessor2D::tryDrawPolygonStrokePrimitive2DDirect(
         /* false bBypassAACheck, default*/);
 }
 
+namespace
+{
+GradientStyle convertGradientStyle(drawinglayer::attribute::GradientStyle eGradientStyle)
+{
+    switch (eGradientStyle)
+    {
+        case drawinglayer::attribute::GradientStyle::Axial:
+            return GradientStyle::Axial;
+        case drawinglayer::attribute::GradientStyle::Radial:
+            return GradientStyle::Radial;
+        case drawinglayer::attribute::GradientStyle::Elliptical:
+            return GradientStyle::Elliptical;
+        case drawinglayer::attribute::GradientStyle::Square:
+            return GradientStyle::Square;
+        case drawinglayer::attribute::GradientStyle::Rect:
+            return GradientStyle::Rect;
+        case drawinglayer::attribute::GradientStyle::Linear:
+        default:
+            return GradientStyle::Linear;
+    }
+}
+
+} // end anonymous namespace
+
 void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
 {
     switch (rCandidate.getPrimitive2DID())
@@ -400,6 +432,12 @@ void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitiv
                 static_cast<const drawinglayer::primitive2d::ShadowPrimitive2D&>(rCandidate));
             break;
         }
+        case PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D:
+        {
+            processFillGradientPrimitive2D(
+                static_cast<const drawinglayer::primitive2d::FillGradientPrimitive2D&>(rCandidate));
+            break;
+        }
         default:
         {
             SAL_INFO("drawinglayer", "default case for " << drawinglayer::primitive2d::idToString(
@@ -1141,6 +1179,39 @@ void VclPixelProcessor2D::processShadowPrimitive2D(const primitive2d::ShadowPrim
         SAL_WARN("drawinglayer", "Temporary buffered virtual device is not visible");
 }
 
+void VclPixelProcessor2D::processFillGradientPrimitive2D(
+    const primitive2d::FillGradientPrimitive2D& rPrimitive)
+{
+    const attribute::FillGradientAttribute& rFillGradient = rPrimitive.getFillGradient();
+
+    if (rFillGradient.getSteps() > 0
+        || rFillGradient.getStyle() != drawinglayer::attribute::GradientStyle::Linear)
+    {
+        process(rPrimitive);
+        return;
+    }
+
+    GradientStyle eGradientStyle = convertGradientStyle(rFillGradient.getStyle());
+
+    basegfx::B2DRange aRange(rPrimitive.getOutputRange());
+    aRange.transform(maCurrentTransformation);
+
+    const tools::Rectangle aRectangle(
+        sal_Int32(std::floor(aRange.getMinX())), sal_Int32(std::floor(aRange.getMinY())),
+        sal_Int32(std::ceil(aRange.getMaxX())), sal_Int32(std::ceil(aRange.getMaxY())));
+
+    Gradient aGradient(eGradientStyle, Color(rFillGradient.getStartColor()),
+                       Color(rFillGradient.getEndColor()));
+
+    aGradient.SetAngle(rFillGradient.getAngle() / F_PI1800);
+    aGradient.SetBorder(rFillGradient.getBorder() * 100);
+    aGradient.SetOfsX(rFillGradient.getOffsetX() * 100.0);
+    aGradient.SetOfsY(rFillGradient.getOffsetY() * 100.0);
+    aGradient.SetSteps(rFillGradient.getSteps());
+
+    mpOutputDevice->DrawGradient(aRectangle, aGradient);
+}
+
 } // end of namespace
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx
index c3bd19141669..480fdcaa6e18 100644
--- a/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx
+++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx
@@ -42,6 +42,7 @@ class BorderLinePrimitive2D;
 class GlowPrimitive2D;
 class ShadowPrimitive2D;
 class SoftEdgePrimitive2D;
+class FillGradientPrimitive2D;
 }
 
 namespace drawinglayer::processor2d
@@ -99,6 +100,7 @@ class VclPixelProcessor2D final : public VclProcessor2D
     void processGlowPrimitive2D(const primitive2d::GlowPrimitive2D& rCandidate);
     void processSoftEdgePrimitive2D(const primitive2d::SoftEdgePrimitive2D& rCandidate);
     void processShadowPrimitive2D(const primitive2d::ShadowPrimitive2D& rCandidate);
+    void processFillGradientPrimitive2D(const primitive2d::FillGradientPrimitive2D& rPrimitive);
 
 public:
     /// constructor/destructor
diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx
index 458ac9cb565a..e769474c3dd5 100644
--- a/vcl/headless/svpgdi.cxx
+++ b/vcl/headless/svpgdi.cxx
@@ -1910,6 +1910,55 @@ bool SvpSalGraphics::drawPolyPolygon(
     return true;
 }
 
+bool SvpSalGraphics::drawGradient(const tools::PolyPolygon& rPolyPolygon, const Gradient& rGradient)
+{
+    cairo_t* cr = getCairoContext(true);
+    clipRegion(cr);
+
+    basegfx::B2DPolyPolygon aB2DPolyPolygon(rPolyPolygon.getB2DPolyPolygon());
+
+    for (auto const & rPolygon : aB2DPolyPolygon)
+    {
+        basegfx::B2DHomMatrix rObjectToDevice;
+        AddPolygonToPath(cr, rPolygon, rObjectToDevice, !getAntiAliasB2DDraw(), false);
+    }
+
+    Gradient aGradient(rGradient);
+
+    tools::Rectangle aInputRect(rPolyPolygon.GetBoundRect());
+    tools::Rectangle aBoundRect;
+    Point aCenter;
+
+    aGradient.SetAngle(aGradient.GetAngle() + 2700);
+    aGradient.GetBoundRect(aInputRect, aBoundRect, aCenter);
+
+    tools::Polygon aPoly(aBoundRect);
+    aPoly.Rotate(aCenter, aGradient.GetAngle() % 3600);
+
+    cairo_pattern_t* pattern;
+    pattern = cairo_pattern_create_linear(aPoly[0].X(), aPoly[0].Y(), aPoly[1].X(), aPoly[1].Y());
+
+    cairo_pattern_add_color_stop_rgba(pattern, aGradient.GetBorder() / 100.0,
+                                                    aGradient.GetStartColor().GetRed()   / 255.0,
+                                                    aGradient.GetStartColor().GetGreen() / 255.0,
+                                                    aGradient.GetStartColor().GetBlue()  / 255.0,
+                                                    1.0);
+
+    cairo_pattern_add_color_stop_rgba(pattern, 1.0,
+                                                    aGradient.GetEndColor().GetRed()   / 255.0,
+                                                    aGradient.GetEndColor().GetGreen() / 255.0,
+                                                    aGradient.GetEndColor().GetBlue()  / 255.0,
+                                                    1.0);
+    cairo_set_source(cr, pattern);
+
+    basegfx::B2DRange extents = getClippedFillDamage(cr);
+    cairo_fill_preserve(cr);
+
+    releaseCairoContext(cr, true, extents);
+
+    return true;
+}
+
 bool SvpSalGraphics::implDrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, SalGradient const & rGradient)
 {
     cairo_t* cr = getCairoContext(true);
diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx
index 3cffdcd2a1c0..8ffe104627c4 100644
--- a/vcl/inc/headless/svpgdi.hxx
+++ b/vcl/inc/headless/svpgdi.hxx
@@ -232,7 +232,8 @@ public:
                                                    const sal_uInt32* pPoints,
                                                    const SalPoint* const* pPtAry,
                                                    const PolyFlags* const* pFlgAry ) override;
-    virtual bool            drawGradient( const tools::PolyPolygon&, const Gradient& ) override { return false; };
+
+    virtual bool drawGradient(tools::PolyPolygon const & rPolyPolygon, Gradient const & rGradient) override;
 
     virtual bool implDrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, SalGradient const & rGradient) override;
 
commit 2b422e71e0b79689535e1ee2805ece1f1f358f06
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Tue May 22 14:44:39 2018 +0900
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Tue Sep 22 10:42:21 2020 +0200

    Command Popup
    
    Change-Id: I92cdd3130b8de42ee0863c9e7154e7c7246d9377

diff --git a/include/sfx2/sfxsids.hrc b/include/sfx2/sfxsids.hrc
index 88d708e4cb98..7cf9ccc52ce0 100644
--- a/include/sfx2/sfxsids.hrc
+++ b/include/sfx2/sfxsids.hrc
@@ -382,7 +382,7 @@ class SvxSearchItem;
 
 // default-ids for windows
 
-// free                                     (SID_SFX_START + 610)
+#define SID_COMMAND_POPUP                   (SID_SFX_START + 610)
 #define SID_NEWWINDOW                       (SID_SFX_START + 620)
 #define SID_CLOSEWIN                        (SID_SFX_START + 621)
 #define SID_VIEWSHELL                       (SID_SFX_START + 623)
diff --git a/officecfg/registry/data/org/openoffice/Office/Accelerators.xcu b/officecfg/registry/data/org/openoffice/Office/Accelerators.xcu
index b8a46cfc035a..2db3f82fc808 100644
--- a/officecfg/registry/data/org/openoffice/Office/Accelerators.xcu
+++ b/officecfg/registry/data/org/openoffice/Office/Accelerators.xcu
@@ -313,6 +313,12 @@ Ctrl+Shift+e aka E_SHIFT_MOD1 under GTK/IBUS is for some emoji thing
           <value xml:lang="en-US" install:module="unxwnt">.uno:OptionsTreeDialog</value>
         </prop>
       </node>
+      <node oor:name="SPACE_MOD1" oor:op="replace">
+        <prop oor:name="Command">
+          <value xml:lang="x-no-translate">I10N SHORTCUTS - NO TRANSLATE</value>
+          <value xml:lang="en-US">.uno:CommandPopup</value>
+        </prop>
+      </node>
     </node>
     <node oor:name="Modules">
       <node oor:name="com.sun.star.script.BasicIDE" oor:op="replace">
diff --git a/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu b/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu
index 97b8e210924c..4dde5dd0d73d 100644
--- a/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu
+++ b/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu
@@ -6488,6 +6488,14 @@
           <value>1</value>
         </prop>
       </node>
+      <node oor:name=".uno:CommandPopup" oor:op="replace">
+        <prop oor:name="Label" oor:type="xs:string">
+          <value xml:lang="en-US">Command Popup</value>
+        </prop>
+        <prop oor:name="Properties" oor:type="xs:int">
+          <value>1</value>
+        </prop>
+      </node>
     </node>
     <node oor:name="Popups">
       <node oor:name=".uno:PasteSpecialMenu" oor:op="replace">
diff --git a/sfx2/Library_sfx.mk b/sfx2/Library_sfx.mk
index cb0b099eb37d..4c7d994de08d 100644
--- a/sfx2/Library_sfx.mk
+++ b/sfx2/Library_sfx.mk
@@ -296,6 +296,7 @@ $(eval $(call gb_Library_add_exception_objects,sfx,\
     sfx2/source/styles/StyleManager \
     sfx2/source/toolbox/tbxitem \
     sfx2/source/toolbox/weldutils \
+    sfx2/source/view/CommandPopup \
     sfx2/source/view/classificationcontroller \
     sfx2/source/view/classificationhelper \
     sfx2/source/view/frame \
diff --git a/sfx2/UIConfig_sfx.mk b/sfx2/UIConfig_sfx.mk
index 5bb91d7ac6f6..da64557e8964 100644
--- a/sfx2/UIConfig_sfx.mk
+++ b/sfx2/UIConfig_sfx.mk
@@ -21,6 +21,7 @@ $(eval $(call gb_UIConfig_add_uifiles,sfx,\
 	sfx2/uiconfig/ui/classificationbox \
 	sfx2/uiconfig/ui/cmisinfopage \
 	sfx2/uiconfig/ui/cmisline \
+	sfx2/uiconfig/ui/commandpopup \
 	sfx2/uiconfig/ui/custominfopage \
 	sfx2/uiconfig/ui/descriptioninfopage \
 	sfx2/uiconfig/ui/dockingwindow \
diff --git a/sfx2/sdi/frmslots.sdi b/sfx2/sdi/frmslots.sdi
index 09aafef95b7d..a7c8a472e73d 100644
--- a/sfx2/sdi/frmslots.sdi
+++ b/sfx2/sdi/frmslots.sdi
@@ -262,6 +262,11 @@ interface TopWindow : BrowseWindow
         ExecMethod = MiscExec_Impl ;
         StateMethod = MiscState_Impl ;
     ]
+    SID_COMMAND_POPUP
+    [
+        ExecMethod = MiscExec_Impl ;
+        StateMethod = MiscState_Impl ;
+    ]
     SID_CLOSEWIN // ole(no) api(final/play/rec)
     [
         ExecMethod = Exec_Impl ;
@@ -307,4 +312,3 @@ shell SfxViewFrame
         StateMethod = GetState_Impl ;
     ]
 }
-
diff --git a/sfx2/sdi/sfx.sdi b/sfx2/sdi/sfx.sdi
index a50b5f1a17a6..813ef070c978 100644
--- a/sfx2/sdi/sfx.sdi
+++ b/sfx2/sdi/sfx.sdi
@@ -1271,6 +1271,23 @@ SfxStringItem FullName SID_DOCFULLNAME
     GroupId = ;
 ]
 
+SfxVoidItem CommandPopup SID_COMMAND_POPUP
+[
+    AutoUpdate = TRUE,
+    FastCall = FALSE,
+    ReadOnlyDoc = TRUE,
+    Toggle = FALSE,
+    Container = TRUE,
+    RecordAbsolute = FALSE,
+    RecordPerSet;
+    Asynchron;
+
+
+    AccelConfig = TRUE,
+    MenuConfig = TRUE,
+    ToolBoxConfig = TRUE,
+    GroupId = SfxGroupId::View;
+]
 
 SfxBoolItem FullScreen SID_WIN_FULLSCREEN
 
diff --git a/sfx2/source/view/CommandPopup.cxx b/sfx2/source/view/CommandPopup.cxx
new file mode 100644
index 000000000000..0bbe8adba5b2
--- /dev/null
+++ b/sfx2/source/view/CommandPopup.cxx
@@ -0,0 +1,220 @@
+/* -*- 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/.
+ */
+
+#include "CommandPopup.hxx"
+
+#include <vcl/layout.hxx>
+#include <vcl/fixed.hxx>
+#include <workwin.hxx>
+#include <sfx2/msgpool.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/dispatchcommand.hxx>
+
+#include <com/sun/star/frame/XDispatchInformationProvider.hpp>
+#include <com/sun/star/frame/theUICommandDescription.hpp>
+#include <com/sun/star/ui/theUICategoryDescription.hpp>
+
+#include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
+#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
+
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+
+#include <vcl/commandinfoprovider.hxx>
+
+using namespace css;
+
+CommandListBox::CommandListBox(vcl::Window* pParent, CommandPopup& rPopUp,
+                               uno::Reference<frame::XFrame> xFrame)
+    : InterimItemWindow(pParent, "sfx/ui/commandpopup.ui", "CommandBox")
+    , m_rPopUp(rPopUp)
+    , m_xFrame(xFrame)
+    , m_pEntry(m_xBuilder->weld_entry("entry"))
+    , m_pListBox(m_xBuilder->weld_tree_view("listBox"))
+{
+    m_pEntry->connect_changed(LINK(this, CommandListBox, ModifyHdl));
+}
+
+void CommandListBox::recurse(uno::Reference<container::XIndexAccess> xIndexAccess,
+                             MenuContent& rMenuContent)
+{
+    for (sal_Int32 n = 0; n < xIndexAccess->getCount(); n++)
+    {
+        MenuContent aNewContent;
+        OUString aModuleIdentifier;
+        uno::Sequence<beans::PropertyValue> aProperty;
+        uno::Reference<container::XIndexAccess> xIndexContainer;
+        try
+        {
+            if (xIndexAccess->getByIndex(n) >>= aProperty)
+            {
+                bool bShow = true;
+                bool bEnabled = true;
+
+                for (int i = 0; i < aProperty.getLength(); i++)
+                {
+                    OUString aPropName = aProperty[i].Name;
+                    if (aPropName == "CommandURL")
+                        aProperty[i].Value >>= aNewContent.m_aCommandURL;
+                    else if (aPropName == "ItemDescriptorContainer")
+                        aProperty[i].Value >>= xIndexContainer;
+                    else if (aPropName == "ModuleIdentifier")
+                        aProperty[i].Value >>= aModuleIdentifier;
+                    else if (aPropName == "IsVisible")
+                        aProperty[i].Value >>= bShow;
+                    else if (aPropName == "Enabled")
+                        aProperty[i].Value >>= bEnabled;
+                }
+
+                OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(m_xFrame));
+                auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(
+                    aNewContent.m_aCommandURL, aModuleName);
+                aNewContent.m_aMenuLabel
+                    = vcl::CommandInfoProvider::GetMenuLabelForCommand(aProperties)
+                          .replaceAll("~", "");
+                aNewContent.m_aLabel = rMenuContent.m_aLabel + " -> " + aNewContent.m_aMenuLabel;
+                //OUString aTooltip(vcl::CommandInfoProvider::GetTooltipForCommand(aNewContent.m_aCommandURL, aProperties, m_xFrame));
+                if (xIndexContainer.is())
+                    recurse(xIndexContainer, aNewContent);
+
+                rMenuContent.m_aSubMenuContent.push_back(aNewContent);
+            }
+        }
+        catch (const lang::IndexOutOfBoundsException&)
+        {
+            return;
+        }
+    }
+}
+
+void CommandListBox::initialize()
+{
+    m_xGlobalCategoryInfo
+        = ui::theUICategoryDescription::get(comphelper::getProcessComponentContext());
+    m_sModuleLongName = vcl::CommandInfoProvider::GetModuleIdentifier(m_xFrame);
+    m_xModuleCategoryInfo.set(m_xGlobalCategoryInfo->getByName(m_sModuleLongName),
+                              uno::UNO_QUERY_THROW);
+    m_xUICmdDescription
+        = frame::theUICommandDescription::get(comphelper::getProcessComponentContext());
+
+    uno::Reference<ui::XModuleUIConfigurationManagerSupplier> xModuleCfgSupplier
+        = ui::theModuleUIConfigurationManagerSupplier::get(
+            comphelper::getProcessComponentContext());
+
+    uno::Reference<ui::XUIConfigurationManager> xCfgMgr
+        = xModuleCfgSupplier->getUIConfigurationManager(m_sModuleLongName);
+    uno::Reference<container::XIndexAccess> xConfigData
+        = xCfgMgr->getSettings("private:resource/menubar/menubar", false);
+
+    recurse(xConfigData, m_aMenuContent);
+
+    Size aSize(400, 400);
+    SetSizePixel(aSize);
+    m_rPopUp.SetOutputSizePixel(aSize);
+    m_rPopUp.StartPopupMode(tools::Rectangle(Point(10, 10), aSize),
+                            FloatWinPopupFlags::Down | FloatWinPopupFlags::GrabFocus
+                                | FloatWinPopupFlags::AllMouseButtonClose
+                                | FloatWinPopupFlags::NoMouseUpClose);
+
+    Show();
+
+    GrabFocus();
+    m_pEntry->grab_focus();
+}
+
+void CommandListBox::dispose()
+{
+    m_pEntry.reset();
+    m_pListBox.reset();
+    InterimItemWindow::dispose();
+}
+
+IMPL_LINK_NOARG(CommandListBox, ModifyHdl, weld::Entry&, void)
+{
+    m_pListBox->clear();
+
+    OUString sText = m_pEntry->get_text();
+    if (sText.isEmpty())
+        return;
+
+    m_aCommandList.clear();
+
+    m_pListBox->freeze();
+    findInMenu(m_aMenuContent, sText.toAsciiLowerCase());
+    m_pListBox->thaw();
+
+    if (m_pListBox->n_children() > 0)
+    {
+        m_pListBox->set_cursor(0);
+        m_pListBox->select(0);
+    }
+
+    m_pEntry->grab_focus();
+}
+
+void CommandListBox::findInMenu(MenuContent& aMenuContent, OUString const& rText)
+{
+    for (MenuContent& aSubContent : aMenuContent.m_aSubMenuContent)
+    {
+        if (aSubContent.m_aMenuLabel.toAsciiLowerCase().startsWith(rText))
+        {
+            OUString sCommandURL = aSubContent.m_aCommandURL;
+            //Image aImage = vcl::CommandInfoProvider::GetImageForCommand(sCommandURL, m_xFrame);
+            m_pListBox->append_text(aSubContent.m_aLabel);
+            m_aCommandList.push_back(sCommandURL);
+        }
+        findInMenu(aSubContent, rText);
+    }
+}
+
+bool CommandListBox::EventNotify(NotifyEvent& rNotifyEvent)
+{
+    const KeyEvent* pKeyEvent = rNotifyEvent.GetKeyEvent();
+
+    if (pKeyEvent)
+    {
+        if (pKeyEvent->GetKeyCode().GetCode() == KEY_DOWN
+            || pKeyEvent->GetKeyCode().GetCode() == KEY_UP)
+        {
+            m_pListBox->grab_focus();
+        }
+        else if (pKeyEvent->GetKeyCode().GetCode() == KEY_RETURN)
+        {
+            size_t nSelected = m_pListBox->get_selected_index();
+            if (nSelected < m_aCommandList.size())
+            {
+                OUString sCommand = m_aCommandList[nSelected];
+                dispatchCommandAndClose(sCommand);
+            }
+        }
+        else
+        {
+            m_pEntry->grab_focus();
+        }
+    }
+
+    return InterimItemWindow::EventNotify(rNotifyEvent);
+}
+
+void CommandListBox::dispatchCommandAndClose(OUString const& rCommand)
+{
+    m_rPopUp.EndPopupMode(FloatWinPopupEndFlags::CloseAll);
+    comphelper::dispatchCommand(rCommand, uno::Sequence<beans::PropertyValue>());
+}
+
+CommandPopup::CommandPopup(vcl::Window* pParent)
+    : FloatingWindow(pParent, WB_BORDER | WB_SYSTEMWINDOW)
+{
+}
+
+CommandPopup::~CommandPopup() { disposeOnce(); }
+
+void CommandPopup::dispose() { FloatingWindow::dispose(); }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/view/CommandPopup.hxx b/sfx2/source/view/CommandPopup.hxx
new file mode 100644
index 000000000000..a3469c04cf6d
--- /dev/null
+++ b/sfx2/source/view/CommandPopup.hxx
@@ -0,0 +1,80 @@
+/* -*- 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/.
+ *
+ */
+
+#pragma once
+
+#include <vcl/layout.hxx>
+
+#include <sfx2/dllapi.h>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/floatwin.hxx>
+
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+
+#include <vcl/InterimItemWindow.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/window.hxx>
+
+struct MenuContent
+{
+    OUString m_aCommandURL;
+    OUString m_aLabel;
+    OUString m_aMenuLabel;
+    std::vector<MenuContent> m_aSubMenuContent;
+};
+
+class SFX2_DLLPUBLIC CommandPopup : public FloatingWindow
+{
+public:
+    explicit CommandPopup(vcl::Window* pWorkWindow);
+
+    ~CommandPopup() override;
+
+    void dispose() override;
+};
+
+class SFX2_DLLPUBLIC CommandListBox final : public InterimItemWindow
+{
+private:
+    CommandPopup& m_rPopUp;
+
+    std::vector<OUString> m_aCommandList;
+    css::uno::Reference<css::frame::XFrame> m_xFrame;
+    css::uno::Reference<css::container::XNameAccess> m_xGlobalCategoryInfo;
+    css::uno::Reference<css::container::XNameAccess> m_xModuleCategoryInfo;
+    css::uno::Reference<css::container::XNameAccess> m_xUICmdDescription;
+    OUString m_sModuleLongName;
+
+    MenuContent m_aMenuContent;
+    OUString m_PreviousText;
+
+    std::unique_ptr<weld::Entry> m_pEntry;
+    std::unique_ptr<weld::TreeView> m_pListBox;
+
+    DECL_LINK(ModifyHdl, weld::Entry&, void);
+
+    void recurse(css::uno::Reference<css::container::XIndexAccess> xIndexAccess,
+                 MenuContent& rMenuContent);
+    void findInMenu(MenuContent& aMenuContent, OUString const& rText);
+
+    void dispatchCommandAndClose(OUString const& rCommand);
+    bool EventNotify(NotifyEvent& rNotifyEvent) override;
+
+public:
+    CommandListBox(vcl::Window* pParent, CommandPopup& rPopUp,
+                   css::uno::Reference<css::frame::XFrame> xFrame);
+
+    void initialize();
+
+    void dispose() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/view/viewfrm.cxx b/sfx2/source/view/viewfrm.cxx
index ccb39350f223..596cdb958eca 100644
--- a/sfx2/source/view/viewfrm.cxx
+++ b/sfx2/source/view/viewfrm.cxx
@@ -25,6 +25,7 @@
 #include <sfx2/viewfrm.hxx>
 #include <sfx2/classificationhelper.hxx>
 #include <sfx2/notebookbar/SfxNotebookBar.hxx>
+#include <svx/svdview.hxx>
 #include <com/sun/star/document/MacroExecMode.hpp>
 #include <com/sun/star/frame/Desktop.hpp>
 #include <com/sun/star/frame/DispatchRecorder.hpp>
@@ -92,6 +93,7 @@
 
 #include <unotools/configmgr.hxx>
 #include <comphelper/sequenceashashmap.hxx>
+#include "CommandPopup.hxx"
 
 using namespace ::com::sun::star;
 using namespace ::com::sun::star::uno;
@@ -2921,8 +2923,26 @@ void SfxViewFrame::MiscExec_Impl( SfxRequest& rReq )
             rReq.Done();
             break;
         }
+        case SID_COMMAND_POPUP:
+        {
+            static VclPtr<CommandPopup> spCommandPopup;
+            static VclPtr<CommandListBox> spCommandListBox;
+
+            if (spCommandListBox)
+                spCommandListBox.disposeAndClear();
+
+            if (spCommandPopup)
+                spCommandPopup.disposeAndClear();
+
+            css::uno::Reference<css::frame::XFrame> xFrame(GetFrame().GetFrameInterface(), css::uno::UNO_QUERY);
+            spCommandPopup.reset(VclPtr<CommandPopup>::Create(&GetWindow()));
 
-        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+            spCommandListBox.reset(VclPtr<CommandListBox>::Create(spCommandPopup.get(), *spCommandPopup.get(), xFrame));
+            spCommandListBox->initialize();
+
+            rReq.Done();
+            break;
+        }
         case SID_WIN_FULLSCREEN:
         {
             const SfxBoolItem* pItem = rReq.GetArg<SfxBoolItem>(rReq.GetSlot());
diff --git a/sfx2/uiconfig/ui/commandpopup.ui b/sfx2/uiconfig/ui/commandpopup.ui
new file mode 100644
index 000000000000..c6e035b9d7bf
--- /dev/null
+++ b/sfx2/uiconfig/ui/commandpopup.ui
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.36.0 -->
+<interface domain="sfx">
+  <requires lib="gtk+" version="3.18"/>
+  <object class="GtkTreeStore" id="liststore1">
+    <columns>
+      <!-- column-name text -->
+      <column type="gchararray"/>
+      <!-- column-name id -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkBox" id="CommandBox">
+    <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="GtkEntry" id="entry">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="placeholder_text" translatable="yes" context="commandpopup|entry">Search command</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkScrolledWindow">
+        <property name="height_request">400</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="shadow_type">in</property>
+        <child>
+          <object class="GtkViewport">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkTreeView" id="listBox">
+                <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="enable_search">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"/>
+                </child>
+                <child>
+                  <object class="GtkTreeViewColumn" id="column">
+                    <child>
+                      <object class="GtkCellRendererText" id="cellrenderertext"/>
+                      <attributes>
+                        <attribute name="text">0</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">True</property>
+        <property name="fill">True</property>
+        <property name="position">1</property>
+      </packing>
+    </child>
+  </object>
+</interface>


More information about the Libreoffice-commits mailing list