KTextEditor

kateviewaccessible.h
1 /* SPDX-License-Identifier: LGPL-2.0-or-later
2 
3  Copyright (C) 2010 Sebastian Sauer <[email protected]>
4  Copyright (C) 2012 Frederik Gladhorn <[email protected]>
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License as published by the Free Software Foundation; either
9  version 2 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Library General Public License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 */
21 
22 #ifndef _KATE_VIEW_ACCESSIBLE_
23 #define _KATE_VIEW_ACCESSIBLE_
24 
25 #ifndef QT_NO_ACCESSIBILITY
26 
27 #include "katedocument.h"
28 #include "kateviewinternal.h"
29 
30 #include <KLocalizedString>
31 #include <QAccessible>
32 #include <QAccessibleWidget>
33 
40 class KateViewAccessible : public QAccessibleWidget, public QAccessibleTextInterface // FIXME maybe:, public QAccessibleEditableTextInterface
41 {
42 public:
43  explicit KateViewAccessible(KateViewInternal *view)
45  , m_lastPosition(-1)
46  {
47  // to invalidate positionFromCursor cache when the document is changed
48  m_conn = QObject::connect(view->view()->document(), &KTextEditor::Document::textChanged, [this]() { m_lastPosition = -1; });
49  }
50 
51  void *interface_cast(QAccessible::InterfaceType t) override
52  {
54  return static_cast<QAccessibleTextInterface *>(this);
55  return nullptr;
56  }
57 
58  ~KateViewAccessible() override
59  {
60  QObject::disconnect(m_conn);
61  }
62 
63  QAccessibleInterface *childAt(int x, int y) const override
64  {
65  Q_UNUSED(x);
66  Q_UNUSED(y);
67  return nullptr;
68  }
69 
70  void setText(QAccessible::Text t, const QString &text) override
71  {
72  if (t == QAccessible::Value && view()->view()->document()) {
73  view()->view()->document()->setText(text);
74  m_lastPosition = -1;
75  }
76  }
77 
78  QAccessible::State state() const override
79  {
81  s.focusable = view()->focusPolicy() != Qt::NoFocus;
82  s.focused = view()->hasFocus();
83  s.editable = true;
84  s.multiLine = true;
85  s.selectableText = true;
86  return s;
87  }
88 
89  QString text(QAccessible::Text t) const override
90  {
91  QString s;
92  if (view()->view()->document()) {
93  if (t == QAccessible::Name) {
94  s = view()->view()->document()->documentName();
95  }
96  if (t == QAccessible::Value) {
97  s = view()->view()->document()->text();
98  }
99  }
100  return s;
101  }
102 
103  int characterCount() const override
104  {
105  return view()->view()->document()->text().size();
106  }
107 
108  void addSelection(int startOffset, int endOffset) override
109  {
110  KTextEditor::Range range;
111  range.setRange(cursorFromInt(startOffset), cursorFromInt(endOffset));
112  view()->view()->setSelection(range);
113  view()->view()->setCursorPosition(cursorFromInt(endOffset));
114  }
115 
116  QString attributes(int offset, int *startOffset, int *endOffset) const override
117  {
118  Q_UNUSED(offset);
119  *startOffset = 0;
120  *endOffset = characterCount();
121  return QString();
122  }
123  QRect characterRect(int offset) const override
124  {
125  KTextEditor::Cursor c = cursorFromInt(offset);
126  if (!c.isValid()) {
127  return QRect();
128  }
129  QPoint p = view()->cursorToCoordinate(c);
130  KTextEditor::Cursor endCursor = KTextEditor::Cursor(c.line(), c.column() + 1);
131  QPoint size = view()->cursorToCoordinate(endCursor) - p;
132  return QRect(view()->mapToGlobal(p), QSize(size.x(), size.y()));
133  }
134  int cursorPosition() const override
135  {
136  KTextEditor::Cursor c = view()->cursorPosition();
137  return positionFromCursor(view(), c);
138  }
139  int offsetAtPoint(const QPoint & /*point*/) const override
140  {
141  return 0;
142  }
143  void removeSelection(int selectionIndex) override
144  {
145  if (selectionIndex != 0) {
146  return;
147  }
148  view()->view()->clearSelection();
149  }
150  void scrollToSubstring(int /*startIndex*/, int /*endIndex*/) override
151  {
152  // FIXME
153  }
154  void selection(int selectionIndex, int *startOffset, int *endOffset) const override
155  {
156  if (selectionIndex != 0 || !view()->view()->selection()) {
157  *startOffset = 0;
158  *endOffset = 0;
159  return;
160  }
161  KTextEditor::Range range = view()->view()->selectionRange();
162  *startOffset = positionFromCursor(view(), range.start());
163  *endOffset = positionFromCursor(view(), range.end());
164  }
165 
166  int selectionCount() const override
167  {
168  return view()->view()->selection() ? 1 : 0;
169  }
170  void setCursorPosition(int position) override
171  {
172  view()->view()->setCursorPosition(cursorFromInt(position));
173  }
174  void setSelection(int selectionIndex, int startOffset, int endOffset) override
175  {
176  if (selectionIndex != 0) {
177  return;
178  }
179  KTextEditor::Range range = KTextEditor::Range(cursorFromInt(startOffset), cursorFromInt(endOffset));
180  view()->view()->setSelection(range);
181  }
182  QString text(int startOffset, int endOffset) const override
183  {
184  if (startOffset > endOffset) {
185  return QString();
186  }
187  return view()->view()->document()->text().mid(startOffset, endOffset - startOffset);
188  }
189 
196  int positionFromCursor(KateViewInternal *view, const KTextEditor::Cursor &cursor) const
197  {
198  int pos = m_lastPosition;
199  const auto *doc = view->view()->document();
200 
201  // m_lastPosition < 0 is invalid, calculate from the beginning of the document
202  if (m_lastPosition < 0 || view != m_lastView) {
203  pos = 0;
204  // Default (worst) case
205  for (int line = 0; line < cursor.line(); ++line) {
206  pos += doc->line(line).size();
207  }
208  // new line for each line
209  pos += cursor.line();
210  m_lastView = view;
211  } else {
212  // if the lines are the same, just add the cursor.column(), otherwise
213  if (cursor.line() != m_lastCursor.line()) {
214  // If the cursor is after the previous cursor
215  if (m_lastCursor.line() < cursor.line()) {
216  for (int line = m_lastCursor.line(); line < cursor.line(); ++line) {
217  pos += doc->line(line).size();
218  }
219  // add new line character for each line
220  pos += cursor.line() - m_lastCursor.line();
221  } else {
222  for (int line = cursor.line(); line < m_lastCursor.line(); ++line) {
223  pos -= doc->line(line).size();
224  }
225  // remove new line character for each line
226  pos -= m_lastCursor.line() - cursor.line();
227  }
228  }
229  }
230  m_lastCursor = cursor;
231  m_lastPosition = pos;
232 
233  return pos + cursor.column();
234  }
235 
236 private:
237  inline KateViewInternal *view() const
238  {
239  return static_cast<KateViewInternal *>(object());
240  }
241 
242  KTextEditor::Cursor cursorFromInt(int position) const
243  {
244  int line = 0;
245  for (;;) {
246  const QString lineString = view()->view()->document()->line(line);
247  if (position > lineString.length()) {
248  // one is the newline
249  position -= lineString.length() + 1;
250  ++line;
251  } else {
252  break;
253  }
254  }
255  return KTextEditor::Cursor(line, position);
256  }
257 
258  QString textLine(int shiftLines, int offset, int *startOffset, int *endOffset) const
259  {
260  KTextEditor::Cursor pos = cursorFromInt(offset);
261  pos.setColumn(0);
262  if (shiftLines) {
263  pos.setLine(pos.line() + shiftLines);
264  }
265  *startOffset = positionFromCursor(view(), pos);
266  QString line = view()->view()->document()->line(pos.line()) + QLatin1Char('\n');
267  *endOffset = *startOffset + line.length();
268  return line;
269  }
270 
271 private:
272  // Cache data for positionFromCursor
273  mutable KateViewInternal *m_lastView;
274  mutable KTextEditor::Cursor m_lastCursor;
275  // m_lastPosition stores the positionFromCursor, with the cursor always in column 0
276  mutable int m_lastPosition;
277  // to disconnect the signal
279 };
280 
285 QAccessibleInterface *accessibleInterfaceFactory(const QString &key, QObject *object)
286 {
287  Q_UNUSED(key)
288  // if (key == QLatin1String("KateViewInternal"))
289  if (KateViewInternal *view = qobject_cast<KateViewInternal *>(object)) {
290  return new KateViewAccessible(view);
291  }
292  return nullptr;
293 }
294 
295 #endif
296 #endif
int positionFromCursor(KateViewInternal *view, const KTextEditor::Cursor &cursor) const
When possible, using the last returned value m_lastPosition do the count from the last cursor positio...
virtual QAccessible::State state() const const override
The Cursor represents a position in a Document.
Definition: cursor.h:85
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
This class implements a QAccessible-interface for a KateViewInternal.
constexpr bool isValid() const Q_DECL_NOEXCEPT
Returns whether the current position of this cursor is a valid position (line + column must both be >...
Definition: cursor.h:113
virtual QObject * object() const const override
constexpr int column() const Q_DECL_NOEXCEPT
Retrieve the column on which this cursor is situated.
Definition: cursor.h:217
void textChanged(KTextEditor::Document *document)
The document emits this signal whenever its text changes.
constexpr Cursor start() const Q_DECL_NOEXCEPT
Get the start position of this range.
An object representing a section of text, from one Cursor to another.
constexpr Cursor end() const Q_DECL_NOEXCEPT
Get the end position of this range.
constexpr int line() const Q_DECL_NOEXCEPT
Retrieve the line on which this cursor is situated.
Definition: cursor.h:199
int length() const const
void setRange(const Range &range) Q_DECL_NOEXCEPT
Set the start and end cursors to range.start() and range.end() respectively.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void setLine(int line) Q_DECL_NOEXCEPT
Set the cursor line to line.
Definition: cursor.h:208
QAccessibleWidget(QWidget *w, QAccessible::Role role, const QString &name)
void setColumn(int column) Q_DECL_NOEXCEPT
Set the cursor column to column.
Definition: cursor.h:226
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Wed Aug 5 2020 22:55:40 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.