include/vcl/weld.hxx                        |    8 ++---
 svx/source/inc/StylesPreviewWindow.hxx      |    2 -
 svx/source/tbxctrls/StylesPreviewWindow.cxx |   14 +++------
 vcl/inc/iconview.hxx                        |   12 ++++----
 vcl/inc/jsdialog/jsdialogbuilder.hxx        |   18 ++++++++++--
 vcl/inc/salvtables.hxx                      |    8 +++--
 vcl/jsdialog/executor.cxx                   |   36 ++++++++++++++-----------
 vcl/jsdialog/jsdialogbuilder.cxx            |   16 ++++++++++-
 vcl/source/app/salvtables.cxx               |   16 ++++-------
 vcl/source/treelist/iconview.cxx            |   40 ++++++++++++++++++++--------
 vcl/unx/gtk3/gtkinst.cxx                    |    2 -
 11 files changed, 109 insertions(+), 63 deletions(-)

New commits:
commit 12ff4396d973e7aae4dd68b742d9790f8c88ea53
Author:     Szymon Kłos <szymon.k...@collabora.com>
AuthorDate: Thu Jun 27 11:11:13 2024 +0200
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Fri Jun 28 09:57:26 2024 +0200

    jsdialog: support on demand rendering for icon view
    
    - rename action: rendered_combobox_entry -> rendered_entry
    - change generic get json property callback to more specialized
      image getter as it wasn't used anywhere apart of that and we need
      image enceded as base64 only not JSON
    - add to the full update of icon view "ondemand" property to the entries
      with images so LOK client will know it has to download the render
    - it will be possible to support HiDPI renders in the future: added TODO
    
    Signed-off-by: Szymon Kłos <szymon.k...@collabora.com>
    Change-Id: I83a6e91133f8f9cb03e0bc794b51e1947435fa90
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169622
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>

diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx
index 52e70e4f08d6..3e334f2cbbee 100644
--- a/include/vcl/weld.hxx
+++ b/include/vcl/weld.hxx
@@ -1386,7 +1386,7 @@ public:
     using Widget::get_sensitive;
 };
 
-typedef std::tuple<tools::JsonWriter&, const TreeIter&, std::string_view> 
json_prop_query;
+typedef std::tuple<OUString&, const TreeIter&> encoded_image_query;
 
 class VCL_DLLPUBLIC IconView : virtual public Widget
 {
@@ -1400,7 +1400,7 @@ protected:
     Link<IconView&, bool> m_aItemActivatedHdl;
     Link<const CommandEvent&, bool> m_aCommandHdl;
     Link<const TreeIter&, OUString> m_aQueryTooltipHdl;
-    Link<const json_prop_query&, bool> m_aGetPropertyTreeElemHdl;
+    Link<const encoded_image_query&, bool> m_aGetPropertyTreeElemHdl;
 
     void signal_selection_changed() { m_aSelectionChangeHdl.Call(*this); }
     bool signal_item_activated() { return m_aItemActivatedHdl.Call(*this); }
@@ -1455,8 +1455,8 @@ public:
         m_aQueryTooltipHdl = rLink;
     }
 
-    // 0: json writer, 1: TreeIter, 2: property. returns true if supported
-    virtual void connect_get_property_tree_elem(const Link<const 
json_prop_query&, bool>& rLink)
+    // 0: OUString, 1: TreeIter, returns true if supported
+    virtual void connect_get_image(const Link<const encoded_image_query&, 
bool>& rLink)
     {
         m_aGetPropertyTreeElemHdl = rLink;
     }
diff --git a/svx/source/inc/StylesPreviewWindow.hxx 
b/svx/source/inc/StylesPreviewWindow.hxx
index 76b385c084d2..471b32f946cf 100644
--- a/svx/source/inc/StylesPreviewWindow.hxx
+++ b/svx/source/inc/StylesPreviewWindow.hxx
@@ -113,7 +113,7 @@ protected:
     DECL_LINK(Selected, weld::IconView&, void);
     DECL_LINK(DoubleClick, weld::IconView&, bool);
     DECL_LINK(DoCommand, const CommandEvent&, bool);
-    DECL_LINK(DoJsonProperty, const weld::json_prop_query&, bool);
+    DECL_LINK(GetPreviewImage, const weld::encoded_image_query&, bool);
 
 public:
     StylesPreviewWindow_Base(weld::Builder& xBuilder,
diff --git a/svx/source/tbxctrls/StylesPreviewWindow.cxx 
b/svx/source/tbxctrls/StylesPreviewWindow.cxx
index da560feb0e15..15a7382e06da 100644
--- a/svx/source/tbxctrls/StylesPreviewWindow.cxx
+++ b/svx/source/tbxctrls/StylesPreviewWindow.cxx
@@ -455,8 +455,7 @@ StylesPreviewWindow_Base::StylesPreviewWindow_Base(
     m_xStylesView->connect_selection_changed(LINK(this, 
StylesPreviewWindow_Base, Selected));
     m_xStylesView->connect_item_activated(LINK(this, StylesPreviewWindow_Base, 
DoubleClick));
     m_xStylesView->connect_command(LINK(this, StylesPreviewWindow_Base, 
DoCommand));
-    m_xStylesView->connect_get_property_tree_elem(
-        LINK(this, StylesPreviewWindow_Base, DoJsonProperty));
+    m_xStylesView->connect_get_image(LINK(this, StylesPreviewWindow_Base, 
GetPreviewImage));
 
     const css::uno::Reference<css::frame::XDispatchProvider> 
xProvider(m_xFrame,
                                                                        
css::uno::UNO_QUERY);
@@ -567,12 +566,9 @@ static OString extractPngString(const BitmapEx& rBitmap)
     return ""_ostr;
 }
 
-// 0: json writer, 1: TreeIter, 2: property. returns true if supported
-IMPL_LINK(StylesPreviewWindow_Base, DoJsonProperty, const 
weld::json_prop_query&, rQuery, bool)
+// 0: OUString, 1: TreeIter, returns true if supported
+IMPL_LINK(StylesPreviewWindow_Base, GetPreviewImage, const 
weld::encoded_image_query&, rQuery, bool)
 {
-    if (std::get<2>(rQuery) != "image")
-        return false;
-
     const weld::TreeIter& rIter = std::get<1>(rQuery);
     OUString sStyleId(m_xStylesView->get_id(rIter));
     OUString sStyleName(m_xStylesView->get_text(rIter));
@@ -580,8 +576,8 @@ IMPL_LINK(StylesPreviewWindow_Base, DoJsonProperty, const 
weld::json_prop_query&
     if (sBase64Png.isEmpty())
         return false;
 
-    tools::JsonWriter& rJsonWriter = std::get<0>(rQuery);
-    rJsonWriter.put("image", sBase64Png);
+    OUString& rResult = std::get<0>(rQuery);
+    rResult = OStringToOUString(sBase64Png, RTL_TEXTENCODING_ASCII_US);
 
     return true;
 }
diff --git a/vcl/inc/iconview.hxx b/vcl/inc/iconview.hxx
index 54c2681a9e79..438590b083ab 100644
--- a/vcl/inc/iconview.hxx
+++ b/vcl/inc/iconview.hxx
@@ -47,20 +47,22 @@ public:
 
     virtual FactoryFunction GetUITestFactory() const override;
     virtual void DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) override;
+    typedef std::tuple<OUString&, SvTreeListEntry*> encoded_image_query;
 
-    typedef std::tuple<tools::JsonWriter&, SvTreeListEntry*, std::string_view> 
json_prop_query;
-
-    void SetDumpElemToPropertyTreeHdl(const Link<const json_prop_query&, 
bool>& rLink)
+    void SetDumpImageHdl(const Link<const encoded_image_query&, bool>& rLink)
     {
-        maDumpElemToPropertyTreeHdl = rLink;
+        maDumpImageHdl = rLink;
     }
 
+    /// returns string with encoded image for an entry
+    OUString renderEntry(int pos, int dpix, int dpiy) const;
+
 protected:
     virtual void CalcEntryHeight(SvTreeListEntry const* pEntry) override;
 
 private:
     Link<SvTreeListEntry*, OUString> maEntryAccessibleDescriptionHdl;
-    Link<const json_prop_query&, bool> maDumpElemToPropertyTreeHdl;
+    Link<const encoded_image_query&, bool> maDumpImageHdl;
     void DumpEntryAndSiblings(tools::JsonWriter& rJsonWriter, SvTreeListEntry* 
pEntry);
 };
 
diff --git a/vcl/inc/jsdialog/jsdialogbuilder.hxx 
b/vcl/inc/jsdialog/jsdialogbuilder.hxx
index 71061c27cb3b..58f8d431d258 100644
--- a/vcl/inc/jsdialog/jsdialogbuilder.hxx
+++ b/vcl/inc/jsdialog/jsdialogbuilder.hxx
@@ -353,6 +353,12 @@ public:
     virtual void sendClosePopup(vcl::LOKWindowId nWindowId) = 0;
 };
 
+class SAL_LOPLUGIN_ANNOTATE("crosscast") OnDemandRenderingHandler
+{
+public:
+    virtual void render_entry(int pos, int dpix, int dpiy) = 0;
+};
+
 template <class BaseInstanceClass, class VclClass>
 class JSWidget : public BaseInstanceClass, public BaseJSWidget
 {
@@ -616,7 +622,8 @@ public:
     virtual void set_active(int pos) override;
 };
 
-class JSComboBox final : public JSWidget<SalInstanceComboBoxWithEdit, 
::ComboBox>
+class JSComboBox final : public JSWidget<SalInstanceComboBoxWithEdit, 
::ComboBox>,
+                         public OnDemandRenderingHandler
 {
 public:
     JSComboBox(JSDialogSender* pSender, ::ComboBox* pComboBox, 
SalInstanceBuilder* pBuilder,
@@ -630,7 +637,8 @@ public:
     virtual void set_active_id(const OUString& rText) override;
     virtual bool changed_by_direct_pick() const override;
 
-    void render_entry(int pos, int dpix, int dpiy);
+    // OnDemandRenderingHandler
+    virtual void render_entry(int pos, int dpix, int dpiy) override;
 };
 
 class JSNotebook final : public JSWidget<SalInstanceNotebook, ::TabControl>
@@ -804,7 +812,8 @@ public:
     virtual void set_expanded(bool bExpand) override;
 };
 
-class JSIconView final : public JSWidget<SalInstanceIconView, ::IconView>
+class JSIconView final : public JSWidget<SalInstanceIconView, ::IconView>,
+                         public OnDemandRenderingHandler
 {
 public:
     JSIconView(JSDialogSender* pSender, ::IconView* pIconView, 
SalInstanceBuilder* pBuilder,
@@ -821,6 +830,9 @@ public:
     virtual void clear() override;
     virtual void select(int pos) override;
     virtual void unselect(int pos) override;
+
+    // OnDemandRenderingHandler
+    virtual void render_entry(int pos, int dpix, int dpiy) override;
 };
 
 class JSRadioButton final : public JSWidget<SalInstanceRadioButton, 
::RadioButton>
diff --git a/vcl/inc/salvtables.hxx b/vcl/inc/salvtables.hxx
index 59d9d2061807..079d9b78af5e 100644
--- a/vcl/inc/salvtables.hxx
+++ b/vcl/inc/salvtables.hxx
@@ -1917,10 +1917,12 @@ public:
 
 class SalInstanceIconView : public SalInstanceWidget, public virtual 
weld::IconView
 {
+protected:
+    VclPtr<::IconView> m_xIconView;
+
 private:
     // owner for UserData
     std::vector<std::unique_ptr<OUString>> m_aUserData;
-    VclPtr<::IconView> m_xIconView;
 
     DECL_LINK(SelectHdl, SvTreeListBox*, void);
     DECL_LINK(DeSelectHdl, SvTreeListBox*, void);
@@ -1928,7 +1930,7 @@ private:
     DECL_LINK(CommandHdl, const CommandEvent&, bool);
     DECL_LINK(TooltipHdl, SvTreeListEntry*, OUString);
     DECL_LINK(EntryAccessibleDescriptionHdl, SvTreeListEntry*, OUString);
-    DECL_LINK(DumpElemToPropertyTreeHdl, const ::IconView::json_prop_query&, 
bool);
+    DECL_LINK(DumpImageHdl, const ::IconView::encoded_image_query&, bool);
 
 public:
     SalInstanceIconView(::IconView* pIconView, SalInstanceBuilder* pBuilder, 
bool bTakeOwnership);
@@ -1951,7 +1953,7 @@ public:
     virtual void connect_query_tooltip(const Link<const weld::TreeIter&, 
OUString>& rLink) override;
 
     virtual void
-    connect_get_property_tree_elem(const Link<const weld::json_prop_query&, 
bool>& rLink) override;
+    connect_get_image(const Link<const weld::encoded_image_query&, bool>& 
rLink) override;
 
     virtual OUString get_selected_id() const override;
 
diff --git a/vcl/jsdialog/executor.cxx b/vcl/jsdialog/executor.cxx
index 3eebd350ef88..891e7cedd378 100644
--- a/vcl/jsdialog/executor.cxx
+++ b/vcl/jsdialog/executor.cxx
@@ -76,11 +76,31 @@ bool ExecuteAction(const OUString& nWindowId, const 
OUString& rWidget, StringMap
 
     if (pWidget != nullptr)
     {
+        // shared actions
+
         if (sAction == "grab_focus")
         {
             pWidget->grab_focus();
             return true;
         }
+        else if (sAction == "render_entry")
+        {
+            auto pRenderer = dynamic_cast<OnDemandRenderingHandler*>(pWidget);
+            if (pRenderer)
+            {
+                // pos;dpix;dpiy
+                const OUString& sParams = rData["data"];
+                const OUString aPos = sParams.getToken(0, ';');
+                const OUString aDpiScaleX = sParams.getToken(1, ';');
+                const OUString aDpiScaleY = sParams.getToken(2, ';');
+
+                pRenderer->render_entry(o3tl::toInt32(aPos), 
o3tl::toInt32(aDpiScaleX),
+                                        o3tl::toInt32(aDpiScaleY));
+            }
+            return true;
+        }
+
+        // depends on type
 
         if (sControlType == "tabcontrol")
         {
@@ -129,22 +149,6 @@ bool ExecuteAction(const OUString& nWindowId, const 
OUString& rWidget, StringMap
                     LOKTrigger::trigger_changed(*pCombobox);
                     return true;
                 }
-                else if (sAction == "render_entry")
-                {
-                    auto pJSCombobox = dynamic_cast<JSComboBox*>(pWidget);
-                    if (pJSCombobox)
-                    {
-                        // pos;dpix;dpiy
-                        const OUString& sParams = rData["data"];
-                        const OUString aPos = sParams.getToken(0, ';');
-                        const OUString aDpiScaleX = sParams.getToken(1, ';');
-                        const OUString aDpiScaleY = sParams.getToken(2, ';');
-
-                        pJSCombobox->render_entry(o3tl::toInt32(aPos), 
o3tl::toInt32(aDpiScaleX),
-                                                  o3tl::toInt32(aDpiScaleY));
-                    }
-                    return true;
-                }
             }
         }
         else if (sControlType == "pushbutton")
diff --git a/vcl/jsdialog/jsdialogbuilder.cxx b/vcl/jsdialog/jsdialogbuilder.cxx
index 709f4461470e..c127f6c3b984 100644
--- a/vcl/jsdialog/jsdialogbuilder.cxx
+++ b/vcl/jsdialog/jsdialogbuilder.cxx
@@ -11,6 +11,7 @@
 #include <sal/log.hxx>
 #include <comphelper/base64.hxx>
 #include <comphelper/lok.hxx>
+#include <iconview.hxx>
 #include <utility>
 #include <vcl/tabpage.hxx>
 #include <vcl/toolbox.hxx>
@@ -1710,7 +1711,7 @@ void JSComboBox::render_entry(int pos, int dpix, int dpiy)
         ::comphelper::Base64::encode(aBuffer, aSeq);
 
         std::unique_ptr<jsdialog::ActionDataMap> pMap = 
std::make_unique<jsdialog::ActionDataMap>();
-        (*pMap)[ACTION_TYPE ""_ostr] = "rendered_combobox_entry";
+        (*pMap)[ACTION_TYPE ""_ostr] = "rendered_entry";
         (*pMap)["pos"_ostr] = OUString::number(pos);
         (*pMap)["image"_ostr] = aBuffer;
         sendAction(std::move(pMap));
@@ -2253,6 +2254,19 @@ void JSIconView::unselect(int pos)
     sendUpdate();
 }
 
+void JSIconView::render_entry(int pos, int dpix, int dpiy)
+{
+    OUString sImage = m_xIconView->renderEntry(pos, dpix, dpiy);
+    if (sImage.isEmpty())
+        return;
+
+    std::unique_ptr<jsdialog::ActionDataMap> pMap = 
std::make_unique<jsdialog::ActionDataMap>();
+    (*pMap)[ACTION_TYPE ""_ostr] = "rendered_entry";
+    (*pMap)["pos"_ostr] = OUString::number(pos);
+    (*pMap)["image"_ostr] = sImage;
+    sendAction(std::move(pMap));
+}
+
 JSRadioButton::JSRadioButton(JSDialogSender* pSender, ::RadioButton* 
pRadioButton,
                              SalInstanceBuilder* pBuilder, bool bTakeOwnership)
     : JSWidget<SalInstanceRadioButton, ::RadioButton>(pSender, pRadioButton, 
pBuilder,
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index 868163577bdd..35a02638422f 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -5534,20 +5534,18 @@ void SalInstanceIconView::connect_query_tooltip(const 
Link<const weld::TreeIter&
     m_xIconView->SetTooltipHdl(LINK(this, SalInstanceIconView, TooltipHdl));
 }
 
-IMPL_LINK(SalInstanceIconView, DumpElemToPropertyTreeHdl, const 
::IconView::json_prop_query&,
-          rQuery, bool)
+IMPL_LINK(SalInstanceIconView, DumpImageHdl, const 
::IconView::encoded_image_query&, rQuery, bool)
 {
     SvTreeListEntry* pEntry = std::get<1>(rQuery);
-    return m_aGetPropertyTreeElemHdl.Call(weld::json_prop_query(
-        std::get<0>(rQuery), SalInstanceTreeIter(pEntry), 
std::get<2>(rQuery)));
+    return m_aGetPropertyTreeElemHdl.Call(
+        weld::encoded_image_query(std::get<0>(rQuery), 
SalInstanceTreeIter(pEntry)));
 }
 
-void SalInstanceIconView::connect_get_property_tree_elem(
-    const Link<const weld::json_prop_query&, bool>& rLink)
+void SalInstanceIconView::connect_get_image(
+    const Link<const weld::encoded_image_query&, bool>& rLink)
 {
-    weld::IconView::connect_get_property_tree_elem(rLink);
-    m_xIconView->SetDumpElemToPropertyTreeHdl(
-        LINK(this, SalInstanceIconView, DumpElemToPropertyTreeHdl));
+    weld::IconView::connect_get_image(rLink);
+    m_xIconView->SetDumpImageHdl(LINK(this, SalInstanceIconView, 
DumpImageHdl));
 }
 
 OUString SalInstanceIconView::get_selected_id() const
diff --git a/vcl/source/treelist/iconview.cxx b/vcl/source/treelist/iconview.cxx
index e80a29b0bc0b..57bf2aea4bda 100644
--- a/vcl/source/treelist/iconview.cxx
+++ b/vcl/source/treelist/iconview.cxx
@@ -278,6 +278,30 @@ static OString extractPngString(const SvLBoxContextBmp* 
pBmpItem)
     return ""_ostr;
 }
 
+OUString IconView::renderEntry(int pos, int /*dpix*/, int /*dpiy*/) const
+{
+    // TODO: support various DPI
+    SvTreeListEntry* pEntry = GetEntry(pos);
+    if (!pEntry)
+        return "";
+
+    OUString sResult;
+    const bool bHandled
+        = maDumpImageHdl.IsSet() && 
maDumpImageHdl.Call(encoded_image_query(sResult, pEntry));
+
+    if (!bHandled)
+    {
+        if (const SvLBoxItem* pIt = 
pEntry->GetFirstItem(SvLBoxItemType::ContextBmp))
+        {
+            const SvLBoxContextBmp* pBmpItem = static_cast<const 
SvLBoxContextBmp*>(pIt);
+            if (pBmpItem)
+                return OStringToOUString(extractPngString(pBmpItem), 
RTL_TEXTENCODING_ASCII_US);
+        }
+    }
+
+    return sResult;
+}
+
 void IconView::DumpEntryAndSiblings(tools::JsonWriter& rJsonWriter, 
SvTreeListEntry* pEntry)
 {
     while (pEntry)
@@ -289,18 +313,12 @@ void IconView::DumpEntryAndSiblings(tools::JsonWriter& 
rJsonWriter, SvTreeListEn
         if (pIt)
             rJsonWriter.put("text", static_cast<const 
SvLBoxString*>(pIt)->GetText());
 
-        const bool bHandled
-            = maDumpElemToPropertyTreeHdl.IsSet()
-              && maDumpElemToPropertyTreeHdl.Call(json_prop_query(rJsonWriter, 
pEntry, "image"));
-        if (!bHandled)
+        pIt = pEntry->GetFirstItem(SvLBoxItemType::ContextBmp);
+        if (pIt)
         {
-            pIt = pEntry->GetFirstItem(SvLBoxItemType::ContextBmp);
-            if (pIt)
-            {
-                const SvLBoxContextBmp* pBmpItem = static_cast<const 
SvLBoxContextBmp*>(pIt);
-                if (pBmpItem)
-                    rJsonWriter.put("image", extractPngString(pBmpItem));
-            }
+            const SvLBoxContextBmp* pBmpItem = static_cast<const 
SvLBoxContextBmp*>(pIt);
+            if (pBmpItem)
+                rJsonWriter.put("ondemand", true);
         }
 
         if (const OUString tooltip = GetEntryTooltip(pEntry); 
!tooltip.isEmpty())
diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx
index 6a06947d4cd2..3b9ce8bc0de9 100644
--- a/vcl/unx/gtk3/gtkinst.cxx
+++ b/vcl/unx/gtk3/gtkinst.cxx
@@ -17158,7 +17158,7 @@ public:
         gtk_widget_set_has_tooltip(GTK_WIDGET(m_pIconView), true);
     }
 
-    virtual void connect_get_property_tree_elem(const Link<const 
weld::json_prop_query&, bool>& /*rLink*/) override
+    virtual void connect_get_image(const Link<const 
weld::encoded_image_query&, bool>& /*rLink*/) override
     {
         //not implemented for the gtk variant
     }

Reply via email to