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>