Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #pragma once
24 :
25 : #include <memory>
26 : #include <QObject>
27 : #include <QList>
28 : #include <QHash>
29 : #include <QTimer>
30 :
31 : #include "global/async/asyncable.h"
32 : #include "global/async/channel.h"
33 : #include "global/iapplication.h"
34 :
35 : #include "modularity/ioc.h"
36 : #include "../iaccessibleapprootobject.h"
37 : #include "../iaccessibilitycontroller.h"
38 : #include "accessibleobject.h"
39 : #include "interactive/iinteractive.h"
40 : #include "ui/imainwindow.h"
41 : #include "ui/inavigationcontroller.h"
42 : #include "rcommand/icommanddispatcher.h"
43 : #include "rcommand/icommandsregister.h"
44 :
45 : #include "muse_framework_config.h"
46 : #ifdef MUSE_MODULE_ACTIONS_SUPPORT
47 : #include "actions/iactionsdispatcher.h"
48 : #include "ui/iuiactionsregister.h"
49 : #endif
50 :
51 : class QAccessibleInterface;
52 : class QAccessibleEvent;
53 :
54 : namespace muse::diagnostics {
55 : class DiagnosticAccessibleModel;
56 : }
57 :
58 : namespace muse::accessibility {
59 : class AccessibilityController : public IAccessibilityController, public IAccessible, public muse::Contextable, public async::Asyncable,
60 : public std::enable_shared_from_this<AccessibilityController>
61 : {
62 : public:
63 : GlobalInject<IApplication> application;
64 : GlobalInject<IAccessibleAppRootObject> appRootObject;
65 : GlobalInject<rcommand::ICommandsRegister> commandsRegister;
66 : ContextInject<IInteractive> interactive = { this };
67 : ContextInject<ui::IMainWindow> mainWindow = { this };
68 : ContextInject<ui::INavigationController> navigationController = { this };
69 : ContextInject<rcommand::ICommandDispatcher> commandDispatcher = { this };
70 :
71 : #ifdef MUSE_MODULE_ACTIONS_SUPPORT
72 : ContextInject<actions::IActionsDispatcher> actionsDispatcher = { this };
73 : ContextInject<ui::IUiActionsRegister> actionsRegister = { this };
74 : #endif
75 :
76 : public:
77 : AccessibilityController(const muse::modularity::ContextPtr& iocCtx);
78 : ~AccessibilityController() override;
79 :
80 : static QAccessibleInterface* accessibleInterface(QObject* object);
81 :
82 : void setAccessibilityEnabled(bool enabled);
83 : void deinit();
84 :
85 : // IAccessibilityController
86 : void reg(IAccessible* item) override;
87 : void unreg(IAccessible* item) override;
88 : bool isReg(IAccessible* item) const override;
89 :
90 : void announce(const QString& announcement) override;
91 : QString announcement() const override;
92 :
93 : const IAccessible* accessibleRoot() const override;
94 : const IAccessible* lastFocused() const override;
95 :
96 : bool needToVoicePanelInfo() const override;
97 : QString currentPanelAccessibleName() const override;
98 :
99 : bool isEnabled() const override;
100 :
101 : void setIgnoreQtAccessibilityEvents(bool ignore) override;
102 :
103 : // -----
104 :
105 : // IAccessibility (root)
106 : IAccessible* accessibleParent() const override;
107 :
108 : size_t accessibleChildCount() const override;
109 : IAccessible* accessibleChild(size_t i) const override;
110 :
111 : QWindow* accessibleWindow() const override;
112 : muse::modularity::ContextPtr iocContext() const override;
113 :
114 : Role accessibleRole() const override;
115 : QString accessibleName() const override;
116 : QString accessibleDescription() const override;
117 : bool accessibleState(State st) const override;
118 : QRect accessibleRect() const override;
119 : bool accessibleIgnored() const override;
120 :
121 : // Value Interface
122 : QVariant accessibleValue() const override;
123 : QVariant accessibleMaximumValue() const override;
124 : QVariant accessibleMinimumValue() const override;
125 : QVariant accessibleValueStepSize() const override;
126 :
127 : // Text Interface
128 : void accessibleSelection(int selectionIndex, int* startOffset, int* endOffset) const override;
129 : int accessibleSelectionCount() const override;
130 :
131 : int accessibleCursorPosition() const override;
132 :
133 : QString accessibleText(int startOffset, int endOffset) const override;
134 : QString accessibleTextBeforeOffset(int offset, TextBoundaryType boundaryType, int* startOffset, int* endOffset) const override;
135 : QString accessibleTextAfterOffset(int offset, TextBoundaryType boundaryType, int* startOffset, int* endOffset) const override;
136 : QString accessibleTextAtOffset(int offset, TextBoundaryType boundaryType, int* startOffset, int* endOffset) const override;
137 : int accessibleCharacterCount() const override;
138 :
139 : // ListView item Interface
140 : int accessibleRowIndex() const override;
141 :
142 : async::Channel<Property, Val> accessiblePropertyChanged() const override;
143 : async::Channel<State, bool> accessibleStateChanged() const override;
144 :
145 : void setState(State state, bool arg) override;
146 : // -----
147 :
148 : QAccessibleInterface* parentIface(const IAccessible* item) const;
149 : int childCount(const IAccessible* item) const;
150 : QAccessibleInterface* child(const IAccessible* item, int i) const;
151 : int indexOfChild(const IAccessible* item, const QAccessibleInterface* iface) const;
152 : QAccessibleInterface* focusedChild(const IAccessible* item) const;
153 :
154 : IAccessible* pretendFocus() const;
155 : async::Channel<QAccessibleEvent*> eventSent() const;
156 :
157 : private:
158 :
159 : friend class muse::diagnostics::DiagnosticAccessibleModel;
160 :
161 : struct Item
162 : {
163 : IAccessible* item = nullptr;
164 : AccessibleObject* object = nullptr;
165 : QAccessibleInterface* iface = nullptr;
166 :
167 12 : bool isValid() const { return item != nullptr; }
168 0 : bool isUsable() const { return item && iface && !item->accessibleIgnored(); }
169 : };
170 :
171 : void init();
172 :
173 : const Item& findItem(const IAccessible* aitem) const;
174 :
175 : void propertyChanged(IAccessible* item, IAccessible::Property property, const Val& value);
176 : void stateChanged(IAccessible* item, IAccessible::State state, bool arg);
177 :
178 : void sendEvent(QAccessibleEvent* ev);
179 :
180 : void cancelPreviousReading();
181 : void savePanelAccessibleName(const IAccessible* oldItem, const IAccessible* newItem);
182 : bool needsRevoicing(const QAccessibleInterface& iface, QAccessible::Event eventType) const;
183 : void triggerRevoicing(const Item& current);
184 : void restoreFocus();
185 : void setExternalFocus(const Item& other);
186 :
187 : const IAccessible* panel(const IAccessible* item) const;
188 :
189 : const Item& findSiblingItem(const Item& parent, const Item& current) const;
190 :
191 : QHash<const IAccessible*, Item> m_allItems;
192 :
193 : QList<IAccessible*> m_children;
194 : async::Channel<QAccessibleEvent*> m_eventSent;
195 : IAccessible* m_lastFocused = nullptr;
196 : IAccessible* m_pretendFocus = nullptr;
197 : QTimer m_pretendFocusTimer;
198 : QString m_announcement;
199 :
200 : IAccessible* m_preDispatchFocus = nullptr;
201 : QString m_preDispatchName;
202 :
203 : bool m_inited = false;
204 : bool m_enabled = false;
205 : bool m_treeConnected = false;
206 :
207 : bool m_ignorePanelChangingVoice = false;
208 : bool m_needToVoicePanelInfo = false;
209 : };
210 : }
|