KTextEditor

kateviewaccessible.h
1 /*
2  SPDX-FileCopyrightText: 2010 Sebastian Sauer <[email protected]>
3  SPDX-FileCopyrightText: 2012 Frederik Gladhorn <[email protected]>
4 
5  SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 
8 #ifndef _KATE_VIEW_ACCESSIBLE_
9 #define _KATE_VIEW_ACCESSIBLE_
10 
11 #ifndef QT_NO_ACCESSIBILITY
12 
13 #include "katedocument.h"
14 #include "kateviewinternal.h"
15 
16 #include <KLocalizedString>
17 #include <QAccessible>
18 #include <QAccessibleWidget>
19 
26 class KateViewAccessible : public QAccessibleWidget, public QAccessibleTextInterface // FIXME maybe:, public QAccessibleEditableTextInterface
27 {
28 public:
29  explicit KateViewAccessible(KateViewInternal *view)
31  , m_lastPosition(-1)
32  {
33  // to invalidate positionFromCursor cache when the document is changed
34  m_conn = QObject::connect(view->view()->document(), &KTextEditor::Document::textChanged, [this]() {
35  m_lastPosition = -1;
36  });
37  }
38 
39  void *interface_cast(QAccessible::InterfaceType t) override
40  {
42  return static_cast<QAccessibleTextInterface *>(this);
43  return nullptr;
44  }
45 
46  ~KateViewAccessible() override
47  {
48  QObject::disconnect(m_conn);
49  }
50 
51  QAccessibleInterface *childAt(int x, int y) const override
52  {
53  Q_UNUSED(x);
54  Q_UNUSED(y);
55  return nullptr;
56  }
57 
58  void setText(QAccessible::Text t, const QString &text) override
59  {
60  if (t == QAccessible::Value && view()->view()->document()) {
61  view()->view()->document()->setText(text);
62  m_lastPosition = -1;
63  }
64  }
65 
66  QAccessible::State state() const override
67  {
69  s.focusable = view()->focusPolicy() != Qt::NoFocus;
70  s.focused = view()->hasFocus();
71  s.editable = true;
72  s.multiLine = true;
73  s.selectableText = true;
74  return s;
75  }
76 
77  QString text(QAccessible::Text t) const override
78  {
79  QString s;
80  if (view()->view()->document()) {
81  if (t == QAccessible::Name) {
82  s = view()->view()->document()->documentName();
83  }
84  if (t == QAccessible::Value) {
85  s = view()->view()->document()->text();
86  }
87  }
88  return s;
89  }
90 
91  int characterCount() const override
92  {
93  return view()->view()->document()->text().size();
94  }
95 
96  void addSelection(int startOffset, int endOffset) override
97  {
98  KTextEditor::Range range;
99  range.setRange(cursorFromInt(startOffset), cursorFromInt(endOffset));
100  view()->view()->setSelection(range);
101  view()->view()->setCursorPosition(cursorFromInt(endOffset));
102  }
103 
104  QString attributes(int offset, int *startOffset, int *endOffset) const override
105  {
106  Q_UNUSED(offset);
107  *startOffset = 0;
108  *endOffset = characterCount();
109  return QString();
110  }
111  QRect characterRect(int offset) const override
112  {
113  KTextEditor::Cursor c = cursorFromInt(offset);
114  if (!c.isValid()) {
115  return QRect();
116  }
117  QPoint p = view()->cursorToCoordinate(c);
118  KTextEditor::Cursor endCursor = KTextEditor::Cursor(c.line(), c.column() + 1);
119  QPoint size = view()->cursorToCoordinate(endCursor) - p;
120  return QRect(view()->mapToGlobal(p), QSize(size.x(), size.y()));
121  }
122  int cursorPosition() const override
123  {
124  KTextEditor::Cursor c = view()->cursorPosition();
125  return positionFromCursor(view(), c);
126  }
127  int offsetAtPoint(const QPoint & /*point*/) const override
128  {
129  return 0;
130  }
131  void removeSelection(int selectionIndex) override
132  {
133  if (selectionIndex != 0) {
134  return;
135  }
136  view()->view()->clearSelection();
137  }
138  void scrollToSubstring(int /*startIndex*/, int /*endIndex*/) override
139  {
140  // FIXME
141  }
142  void selection(int selectionIndex, int *startOffset, int *endOffset) const override
143  {
144  if (selectionIndex != 0 || !view()->view()->selection()) {
145  *startOffset = 0;
146  *endOffset = 0;
147  return;
148  }
149  KTextEditor::Range range = view()->view()->selectionRange();
150  *startOffset = positionFromCursor(view(), range.start());
151  *endOffset = positionFromCursor(view(), range.end());
152  }
153 
154  int selectionCount() const override
155  {
156  return view()->view()->selection() ? 1 : 0;
157  }
158  void setCursorPosition(int position) override
159  {
160  view()->view()->setCursorPosition(cursorFromInt(position));
161  }
162  void setSelection(int selectionIndex, int startOffset, int endOffset) override
163  {
164  if (selectionIndex != 0) {
165  return;
166  }
167  KTextEditor::Range range = KTextEditor::Range(cursorFromInt(startOffset), cursorFromInt(endOffset));
168  view()->view()->setSelection(range);
169  }
170  QString text(int startOffset, int endOffset) const override
171  {
172  if (startOffset > endOffset) {
173  return QString();
174  }
175  return view()->view()->document()->text().mid(startOffset, endOffset - startOffset);
176  }
177 
184  int positionFromCursor(KateViewInternal *view, const KTextEditor::Cursor &cursor) const
185  {
186  int pos = m_lastPosition;
187  const auto *doc = view->view()->document();
188 
189  // m_lastPosition < 0 is invalid, calculate from the beginning of the document
190  if (m_lastPosition < 0 || view != m_lastView) {
191  pos = 0;
192  // Default (worst) case
193  for (int line = 0; line < cursor.line(); ++line) {
194  pos += doc->line(line).size();
195  }
196  // new line for each line
197  pos += cursor.line();
198  m_lastView = view;
199  } else {
200  // if the lines are the same, just add the cursor.column(), otherwise
201  if (cursor.line() != m_lastCursor.line()) {
202  // If the cursor is after the previous cursor
203  if (m_lastCursor.line() < cursor.line()) {
204  for (int line = m_lastCursor.line(); line < cursor.line(); ++line) {
205  pos += doc->line(line).size();
206  }
207  // add new line character for each line
208  pos += cursor.line() - m_lastCursor.line();
209  } else {
210  for (int line = cursor.line(); line < m_lastCursor.line(); ++line) {
211  pos -= doc->line(line).size();
212  }
213  // remove new line character for each line
214  pos -= m_lastCursor.line() - cursor.line();
215  }
216  }
217  }
218  m_lastCursor = cursor;
219  m_lastPosition = pos;
220 
221  return pos + cursor.column();
222  }
223 
224 private:
225  inline KateViewInternal *view() const
226  {
227  return static_cast<KateViewInternal *>(object());
228  }
229 
230  KTextEditor::Cursor cursorFromInt(int position) const
231  {
232  int line = 0;
233  for (;;) {
234  const QString lineString = view()->view()->document()->line(line);
235  if (position > lineString.length()) {
236  // one is the newline
237  position -= lineString.length() + 1;
238  ++line;
239  } else {
240  break;
241  }
242  }
243  return KTextEditor::Cursor(line, position);
244  }
245 
246  QString textLine(int shiftLines, int offset, int *startOffset, int *endOffset) const
247  {
248  KTextEditor::Cursor pos = cursorFromInt(offset);
249  pos.setColumn(0);
250  if (shiftLines) {
251  pos.setLine(pos.line() + shiftLines);
252  }
253  *startOffset = positionFromCursor(view(), pos);
254  QString line = view()->view()->document()->line(pos.line()) + QLatin1Char('\n');
255  *endOffset = *startOffset + line.length();
256  return line;
257  }
258 
259 private:
260  // Cache data for positionFromCursor
261  mutable KateViewInternal *m_lastView;
262  mutable KTextEditor::Cursor m_lastCursor;
263  // m_lastPosition stores the positionFromCursor, with the cursor always in column 0
264  mutable int m_lastPosition;
265  // to disconnect the signal
267 };
268 
273 QAccessibleInterface *accessibleInterfaceFactory(const QString &key, QObject *object)
274 {
275  Q_UNUSED(key)
276  // if (key == QLatin1String("KateViewInternal"))
277  if (KateViewInternal *view = qobject_cast<KateViewInternal *>(object)) {
278  return new KateViewAccessible(view);
279  }
280  return nullptr;
281 }
282 
283 #endif
284 #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:71
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:99
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:213
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:195
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:204
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:222
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Wed Jan 20 2021 23:01:55 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.