officecfg/registry/data/org/openoffice/Office/UI/Sidebar.xcu |   52 ++++
 svx/uiconfig/ui/accessibilitycheckentry.ui                   |    2 
 sw/Library_sw.mk                                             |    1 
 sw/UIConfig_swriter.mk                                       |    1 
 sw/source/uibase/sidebar/A11yCheckIssuesPanel.cxx            |  129 +++++++++++
 sw/source/uibase/sidebar/A11yCheckIssuesPanel.hxx            |   74 ++++++
 sw/source/uibase/sidebar/SwPanelFactory.cxx                  |    7 
 sw/uiconfig/swriter/ui/a11ycheckissuespanel.ui               |   49 ++++
 8 files changed, 314 insertions(+), 1 deletion(-)

New commits:
commit 403ea882af35337431e0f67aa973c5f046deb630
Author:     Samuel Mehrbrodt <samuel.mehrbr...@allotropia.de>
AuthorDate: Mon Mar 13 21:42:47 2023 +0100
Commit:     Samuel Mehrbrodt <samuel.mehrbr...@allotropia.de>
CommitDate: Mon Mar 20 15:41:17 2023 +0000

    tdf#142978 Add a11y check sidebar
    
    Change-Id: I6d9d6dca0118567f68db11b7c0cce60643211ab2
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149000
    Tested-by: Jenkins
    Reviewed-by: Samuel Mehrbrodt <samuel.mehrbr...@allotropia.de>

diff --git a/officecfg/registry/data/org/openoffice/Office/UI/Sidebar.xcu 
b/officecfg/registry/data/org/openoffice/Office/UI/Sidebar.xcu
index 0747b7eee792..83f4aa33091b 100644
--- a/officecfg/registry/data/org/openoffice/Office/UI/Sidebar.xcu
+++ b/officecfg/registry/data/org/openoffice/Office/UI/Sidebar.xcu
@@ -81,6 +81,26 @@
         </prop>
       </node>
 
+      <node oor:name="A11yCheckDeck" oor:op="replace">
+        <prop oor:name="Title" oor:type="xs:string">
+          <value xml:lang="en-US">Accessibility Check</value>
+        </prop>
+        <prop oor:name="Id" oor:type="xs:string">
+          <value>A11yCheckDeck</value>
+        </prop>
+        <prop oor:name="IconURL" oor:type="xs:string">
+          <value>private:graphicrepository/cmd/lc_adddirect.png</value>
+        </prop>
+        <prop oor:name="ContextList">
+          <value oor:separator=";">
+            WriterVariants, any, visible ;
+          </value>
+        </prop>
+        <prop oor:name="OrderIndex" oor:type="xs:int">
+          <value>900</value>
+        </prop>
+      </node>
+
       <node oor:name="ShapesDeck" oor:op="replace">
         <prop oor:name="Title" oor:type="xs:string">
           <value xml:lang="en-US">Shapes</value>
@@ -577,6 +597,38 @@
         </prop>
       </node>
 
+      <node oor:name="A11yCheckIssuesPanel" oor:op="replace">
+        <prop oor:name="Title" oor:type="xs:string">
+          <value xml:lang="en-US">Accessibility Issues</value>
+        </prop>
+        <prop oor:name="TitleBarIsOptional" oor:type="xs:boolean">
+          <value>true</value>
+        </prop>
+        <prop oor:name="Id" oor:type="xs:string">
+          <value>A11yCheckIssuesPanel</value>
+        </prop>
+        <prop oor:name="DeckId" oor:type="xs:string">
+          <value>A11yCheckDeck</value>
+        </prop>
+        <prop oor:name="DefaultMenuCommand">
+          <value></value>
+        </prop>
+        <prop oor:name="ContextList">
+          <value oor:separator=";">
+            WriterVariants, any, visible ;
+          </value>
+        </prop>
+        <prop oor:name="ImplementationURL" oor:type="xs:string">
+          
<value>private:resource/toolpanel/SwPanelFactory/A11yCheckIssuesPanel</value>
+        </prop>
+        <prop oor:name="OrderIndex" oor:type="xs:int">
+          <value>100</value>
+        </prop>
+        <prop oor:name="WantsAWT" oor:type="xs:boolean">
+          <value>false</value>
+        </prop>
+      </node>
+
       <node oor:name="AreaPropertyPanel" oor:op="replace">
         <prop oor:name="Title" oor:type="xs:string">
           <value xml:lang="en-US">Area</value>
diff --git a/svx/uiconfig/ui/accessibilitycheckentry.ui 
b/svx/uiconfig/ui/accessibilitycheckentry.ui
index 3d60179f16b5..e084bb367473 100644
--- a/svx/uiconfig/ui/accessibilitycheckentry.ui
+++ b/svx/uiconfig/ui/accessibilitycheckentry.ui
@@ -29,7 +29,7 @@
     </child>
     <child>
       <object class="GtkButton" id="accessibilityCheckEntryGotoButton">
-        <property name="label" translatable="yes" 
context="accessibilitycheckentry|accessibilityCheckEntryGotoButton">Go to 
Issue</property>
+        <property name="label" translatable="yes" 
context="accessibilitycheckentry|accessibilityCheckEntryGotoButton">Go 
to</property>
         <property name="visible">True</property>
         <property name="can-focus">True</property>
         <property name="receives-default">True</property>
diff --git a/sw/Library_sw.mk b/sw/Library_sw.mk
index 05dd36258649..8a79be4f9e41 100644
--- a/sw/Library_sw.mk
+++ b/sw/Library_sw.mk
@@ -734,6 +734,7 @@ $(eval $(call gb_Library_add_exception_objects,sw,\
     sw/source/uibase/sidebar/ThemePanel \
     sw/source/uibase/sidebar/SwPanelFactory \
     sw/source/uibase/sidebar/WriterInspectorTextPanel \
+    sw/source/uibase/sidebar/A11yCheckIssuesPanel \
     sw/source/uibase/table/chartins \
     sw/source/uibase/table/swtablerep \
     sw/source/uibase/table/tablemgr \
diff --git a/sw/UIConfig_swriter.mk b/sw/UIConfig_swriter.mk
index 867baf40ba88..7011ed16bdc2 100644
--- a/sw/UIConfig_swriter.mk
+++ b/sw/UIConfig_swriter.mk
@@ -285,6 +285,7 @@ $(eval $(call gb_UIConfig_add_uifiles,modules/swriter,\
        sw/uiconfig/swriter/ui/pagestylespanel \
        sw/uiconfig/swriter/ui/pageheaderpanel \
        sw/uiconfig/swriter/ui/pagefooterpanel \
+       sw/uiconfig/swriter/ui/a11ycheckissuespanel \
        sw/uiconfig/swriter/ui/poseditbox \
        sw/uiconfig/swriter/ui/sidebarwrap \
        sw/uiconfig/swriter/ui/sidebarstylepresets \
diff --git a/sw/source/uibase/sidebar/A11yCheckIssuesPanel.cxx 
b/sw/source/uibase/sidebar/A11yCheckIssuesPanel.cxx
new file mode 100644
index 000000000000..f9d625f8427b
--- /dev/null
+++ b/sw/source/uibase/sidebar/A11yCheckIssuesPanel.cxx
@@ -0,0 +1,129 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * 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 <sal/config.h>
+
+#include <AccessibilityCheck.hxx>
+#include <cmdid.h>
+#include <doc.hxx>
+#include <docsh.hxx>
+#include <ndtxt.hxx>
+#include <wrtsh.hxx>
+
+#include <sfx2/AccessibilityIssue.hxx>
+#include <vcl/svapp.hxx>
+
+#include "A11yCheckIssuesPanel.hxx"
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+namespace sw::sidebar
+{
+AccessibilityCheckEntry::AccessibilityCheckEntry(
+    weld::Container* pParent, std::shared_ptr<sfx::AccessibilityIssue> const& 
rAccessibilityIssue)
+    : m_xBuilder(Application::CreateBuilder(pParent, 
"svx/ui/accessibilitycheckentry.ui"))
+    , m_xContainer(m_xBuilder->weld_container("accessibilityCheckEntryBox"))
+    , m_xLabel(m_xBuilder->weld_label("accessibilityCheckEntryLabel"))
+    , 
m_xGotoButton(m_xBuilder->weld_button("accessibilityCheckEntryGotoButton"))
+    , m_pAccessibilityIssue(rAccessibilityIssue)
+{
+    m_xLabel->set_label(m_pAccessibilityIssue->m_aIssueText);
+    // lock in the height as including the button so all rows are the same 
height
+    m_xContainer->set_size_request(-1, 
m_xContainer->get_preferred_size().Height());
+    m_xGotoButton->set_visible(m_pAccessibilityIssue->canGotoIssue());
+    m_xGotoButton->connect_clicked(LINK(this, AccessibilityCheckEntry, 
GotoButtonClicked));
+}
+
+IMPL_LINK_NOARG(AccessibilityCheckEntry, GotoButtonClicked, weld::Button&, 
void)
+{
+    m_pAccessibilityIssue->gotoIssue();
+}
+
+std::unique_ptr<PanelLayout> A11yCheckIssuesPanel::Create(weld::Widget* 
pParent,
+                                                          SfxBindings* 
pBindings)
+{
+    if (pParent == nullptr)
+        throw ::com::sun::star::lang::IllegalArgumentException(
+            "no parent window given to A11yCheckIssuesPanel::Create", nullptr, 
0);
+    return std::make_unique<A11yCheckIssuesPanel>(pParent, pBindings);
+}
+
+A11yCheckIssuesPanel::A11yCheckIssuesPanel(weld::Widget* pParent, SfxBindings* 
pBindings)
+    : PanelLayout(pParent, "A11yCheckIssuesPanel", 
"modules/swriter/ui/a11ycheckissuespanel.ui")
+    , m_xAccessibilityCheckBox(m_xBuilder->weld_box("accessibilityCheckBox"))
+    , m_xScrolledWindow(m_xBuilder->weld_scrolled_window("scrolledwindow"))
+    , maA11yCheckController(FN_STAT_ACCESSIBILITY_CHECK, *pBindings, *this)
+    , mnIssueCount(0)
+{
+    SwDocShell* pDocSh = dynamic_cast<SwDocShell*>(SfxObjectShell::Current());
+    if (!pDocSh)
+        return;
+
+    mpDoc = pDocSh->GetDoc();
+
+    populateIssues();
+}
+
+A11yCheckIssuesPanel::~A11yCheckIssuesPanel() { 
m_xAccessibilityCheckBox.reset(); }
+
+void A11yCheckIssuesPanel::populateIssues()
+{
+    if (!mpDoc)
+        return;
+    sw::AccessibilityCheck aCheck(mpDoc);
+    aCheck.check();
+    m_aIssueCollection = aCheck.getIssueCollection();
+
+    // Remove old issue widgets
+    for (auto const& xEntry : m_aAccessibilityCheckEntries)
+        m_xAccessibilityCheckBox->move(xEntry->get_widget(), nullptr);
+
+    sal_Int32 i = 0;
+    for (std::shared_ptr<sfx::AccessibilityIssue> const& pIssue : 
m_aIssueCollection.getIssues())
+    {
+        auto xEntry
+            = 
std::make_unique<AccessibilityCheckEntry>(m_xAccessibilityCheckBox.get(), 
pIssue);
+        m_xAccessibilityCheckBox->reorder_child(xEntry->get_widget(), i++);
+        m_aAccessibilityCheckEntries.push_back(std::move(xEntry));
+    }
+
+    if (!m_aAccessibilityCheckEntries.empty())
+    {
+        auto nRowHeight
+            = 
m_aAccessibilityCheckEntries.back()->get_widget()->get_preferred_size().Height();
+        // 6 is the spacing set in the .ui
+        m_xScrolledWindow->vadjustment_set_step_increment(nRowHeight + 6);
+    }
+}
+
+void A11yCheckIssuesPanel::NotifyItemUpdate(const sal_uInt16 nSid, const 
SfxItemState /* eState */,
+                                            const SfxPoolItem* pState)
+{
+    if (!m_xAccessibilityCheckBox) //disposed
+        return;
+
+    switch (nSid)
+    {
+        case FN_STAT_ACCESSIBILITY_CHECK:
+        {
+            sal_Int32 nIssueCount = static_cast<const 
SfxInt32Item*>(pState)->GetValue();
+            if (nIssueCount != mnIssueCount)
+            {
+                mnIssueCount = nIssueCount;
+                populateIssues();
+            }
+        }
+        break;
+        default:
+            break;
+    }
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/sw/source/uibase/sidebar/A11yCheckIssuesPanel.hxx 
b/sw/source/uibase/sidebar/A11yCheckIssuesPanel.hxx
new file mode 100644
index 000000000000..23bf6468f196
--- /dev/null
+++ b/sw/source/uibase/sidebar/A11yCheckIssuesPanel.hxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * 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 <memory>
+
+#include <sfx2/AccessibilityIssue.hxx>
+#include <sfx2/sidebar/ControllerItem.hxx>
+#include <sfx2/sidebar/PanelLayout.hxx>
+#include <svl/poolitem.hxx>
+#include <tools/link.hxx>
+#include <vcl/weld.hxx>
+
+#include <doc.hxx>
+
+namespace sw::sidebar
+{
+class AccessibilityCheckEntry final
+{
+private:
+    std::unique_ptr<weld::Builder> m_xBuilder;
+    std::unique_ptr<weld::Container> m_xContainer;
+    std::unique_ptr<weld::Label> m_xLabel;
+    std::unique_ptr<weld::Button> m_xGotoButton;
+
+    std::shared_ptr<sfx::AccessibilityIssue> const& m_pAccessibilityIssue;
+
+public:
+    AccessibilityCheckEntry(weld::Container* pParent,
+                            std::shared_ptr<sfx::AccessibilityIssue> const& 
pAccessibilityIssue);
+
+    weld::Widget* get_widget() const { return m_xContainer.get(); }
+
+    DECL_LINK(GotoButtonClicked, weld::Button&, void);
+};
+
+class A11yCheckIssuesPanel : public PanelLayout,
+                             public 
::sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface
+{
+public:
+    static std::unique_ptr<PanelLayout> Create(weld::Widget* pParent, 
SfxBindings* pBindings);
+
+    virtual void NotifyItemUpdate(const sal_uInt16 nSId, const SfxItemState 
eState,
+                                  const SfxPoolItem* pState) override;
+
+    virtual void GetControlState(const sal_uInt16 /*nSId*/,
+                                 boost::property_tree::ptree& /*rState*/) 
override{};
+
+    A11yCheckIssuesPanel(weld::Widget* pParent, SfxBindings* pBindings);
+    virtual ~A11yCheckIssuesPanel() override;
+
+private:
+    std::vector<std::unique_ptr<AccessibilityCheckEntry>> 
m_aAccessibilityCheckEntries;
+    std::unique_ptr<weld::Box> m_xAccessibilityCheckBox;
+    std::unique_ptr<weld::ScrolledWindow> m_xScrolledWindow;
+    sfx::AccessibilityIssueCollection m_aIssueCollection;
+    std::function<sfx::AccessibilityIssueCollection()> m_getIssueCollection;
+    void populateIssues();
+
+    SwDoc* mpDoc;
+    ::sfx2::sidebar::ControllerItem maA11yCheckController;
+    sal_Int32 mnIssueCount;
+};
+
+} //end of namespace sw::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/sw/source/uibase/sidebar/SwPanelFactory.cxx 
b/sw/source/uibase/sidebar/SwPanelFactory.cxx
index 5dcd0f389216..5ae3a781bc2d 100644
--- a/sw/source/uibase/sidebar/SwPanelFactory.cxx
+++ b/sw/source/uibase/sidebar/SwPanelFactory.cxx
@@ -19,6 +19,7 @@
 
 #include <com/sun/star/ui/XUIElementFactory.hpp>
 
+#include "A11yCheckIssuesPanel.hxx"
 #include "ThemePanel.hxx"
 #include "StylePresetsPanel.hxx"
 #include "PageStylesPanel.hxx"
@@ -196,6 +197,12 @@ Reference<ui::XUIElement> SAL_CALL 
SwPanelFactory::createUIElement (
         xElement = sfx2::sidebar::SidebarPanelBase::Create(
                         rsResourceURL, xFrame, std::move(xPanel), 
ui::LayoutSize(-1,-1,-1));
     }
+    else if (rsResourceURL.endsWith("/A11yCheckIssuesPanel"))
+    {
+        std::unique_ptr<PanelLayout> xPanel = 
sw::sidebar::A11yCheckIssuesPanel::Create(pParent, pBindings);
+        xElement = sfx2::sidebar::SidebarPanelBase::Create(
+                        rsResourceURL, xFrame, std::move(xPanel), 
ui::LayoutSize(-1,-1,-1));
+    }
 
     return xElement;
 }
diff --git a/sw/uiconfig/swriter/ui/a11ycheckissuespanel.ui 
b/sw/uiconfig/swriter/ui/a11ycheckissuespanel.ui
new file mode 100644
index 000000000000..da87f9bc8be7
--- /dev/null
+++ b/sw/uiconfig/swriter/ui/a11ycheckissuespanel.ui
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.40.0 -->
+<interface domain="sw">
+  <requires lib="gtk+" version="3.20"/>
+  <object class="GtkBox" id="A11yCheckIssuesPanel">
+    <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="GtkScrolledWindow" id="scrolledwindow">
+        <property name="visible">True</property>
+        <property name="can-focus">True</property>
+        <property name="hexpand">True</property>
+        <property name="vexpand">True</property>
+        <property name="shadow-type">in</property>
+        <child>
+          <object class="GtkViewport">
+            <property name="visible">True</property>
+            <property name="can-focus">False</property>
+            <property name="hexpand">True</property>
+            <property name="vexpand">True</property>
+            <child>
+              <object class="GtkBox" id="accessibilityCheckBox">
+                <property name="visible">True</property>
+                <property name="can-focus">False</property>
+                <property name="valign">start</property>
+                <property name="hexpand">True</property>
+                <property name="vexpand">True</property>
+                <property name="orientation">vertical</property>
+                <property name="spacing">6</property>
+                <property name="homogeneous">True</property>
+                <child>
+                  <placeholder/>
+                </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>

Reply via email to