1/*
2 SPDX-FileCopyrightText: 2002-2007 Hamish Rodda <rodda@kde.org>
3 SPDX-FileCopyrightText: 2002 John Firebaugh <jfirebaugh@kde.org>
4 SPDX-FileCopyrightText: 2002 Joseph Wenninger <jowenn@kde.org>
5 SPDX-FileCopyrightText: 2002 Christoph Cullmann <cullmann@kde.org>
6 SPDX-FileCopyrightText: 2007 Mirko Stocker <me@misto.ch>
7
8 Based on KWriteView:
9 SPDX-FileCopyrightText: 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
10
11 SPDX-License-Identifier: LGPL-2.0-or-later
12*/
13#ifndef _KATE_VIEW_INTERNAL_
14#define _KATE_VIEW_INTERNAL_
15
16#include <KSyntaxHighlighting/FoldingRegion>
17
18#include <ktexteditor/attribute.h>
19#include <ktexteditor/range.h>
20#include <ktexteditor/view.h>
21
22#include "inlinenotedata.h"
23#include "katetextcursor.h"
24#include "katetextline.h"
25
26#include <QDrag>
27#include <QElapsedTimer>
28#include <QPoint>
29#include <QPointer>
30#include <QSet>
31#include <QTime>
32#include <QTimer>
33#include <QWidget>
34
35#include <array>
36#include <memory>
37
38namespace KTextEditor
39{
40class MovingRange;
41class TextHintProvider;
42class DocumentPrivate;
43class ViewPrivate;
44}
45
46class KateIconBorder;
47class KateScrollBar;
48class KateAnnotationItemDelegate;
49class KateAnnotationGroupPositionState;
50class KateTextLayout;
51class KateTextAnimation;
52class KateAbstractInputMode;
53class ZoomEventFilter;
54class KateRenderer;
55class KateTextPreview;
56class KateViewTest;
57
58class QScrollBar;
59class QScroller;
60class QScrollEvent;
61class QScrollPrepareEvent;
62
63class KateViewInternal final : public QWidget
64{
65 Q_OBJECT
66
67 friend class KTextEditor::ViewPrivate;
68 friend class KateIconBorder;
69 friend class KateScrollBar;
70 friend class KateAnnotationGroupPositionState;
71 friend class CalculatingCursor;
72 friend class BoundedCursor;
73 friend class WrappingCursor;
74 friend class CamelCursor;
75 friend class KateAbstractInputMode;
76 friend class ::KateTextPreview;
77 friend class KateViewTest;
78
79public:
80 enum Bias { left = -1, none = 0, right = 1 };
81
82public:
83 explicit KateViewInternal(KTextEditor::ViewPrivate *view);
84 ~KateViewInternal() override;
85 KTextEditor::ViewPrivate *view() const
86 {
87 return m_view;
88 }
89
90 // BEGIN EDIT STUFF
91public:
92 void editStart();
93 void editEnd(int editTagLineStart, int editTagLineEnd, bool tagFrom);
94
95 void editSetCursor(const KTextEditor::Cursor cursor);
96
97private:
98 uint editSessionNumber;
99 bool editIsRunning;
100 KTextEditor::Cursor editOldCursor;
101 KTextEditor::Range editOldSelection;
102 // END
103
104 // BEGIN TAG & CLEAR & UPDATE STUFF
105public:
106 bool tagLine(const KTextEditor::Cursor virtualCursor);
107
108 bool tagLines(int start, int end, bool realLines = false);
109 // cursors not const references as they are manipulated within
110 bool tagLines(KTextEditor::Cursor start, KTextEditor::Cursor end, bool realCursors = false);
111
112 bool tagRange(KTextEditor::Range range, bool realCursors);
113
114 void tagAll();
115
116 void updateDirty();
117
118 void clear();
119 // END
120
121private Q_SLOTS:
122 // Updates the view and requests a redraw.
123 void updateView(bool changed = false, int viewLinesScrolled = 0);
124
125private:
126 void makeVisible(const KTextEditor::Cursor c, int endCol, bool force = false, bool center = false, bool calledExternally = false);
127
128public:
129 // Start Position is a virtual cursor
130 KTextEditor::Cursor startPos() const
131 {
132 return m_startPos;
133 }
134 int startLine() const
135 {
136 return m_startPos.line();
137 }
138 int startX() const
139 {
140 return m_startX;
141 }
142
143 KTextEditor::Cursor endPos() const;
144 int endLine() const;
145
146 KateTextLayout yToKateTextLayout(int y) const;
147
148 void dynWrapChanged();
149
150public Q_SLOTS:
151 void slotIncFontSizes(qreal step = 1.0);
152 void slotDecFontSizes(qreal step = 1.0);
153 void slotResetFontSizes();
154
155 void paintCursor();
156
157private Q_SLOTS:
158 void scrollLines(int line); // connected to the sliderMoved of the m_lineScroll
159 void scrollViewLines(int offset);
160 void scrollAction(int action);
161 void scrollNextPage();
162 void scrollPrevPage();
163 void scrollPrevLine();
164 void scrollNextLine();
165 void scrollColumns(int x); // connected to the valueChanged of the m_columnScroll
166 void viewSelectionChanged();
167
168public:
169 void cursorPrevChar(bool sel = false);
170 void cursorNextChar(bool sel = false);
171 void wordPrev(bool sel = false);
172 void wordNext(bool sel = false);
173 void home(bool sel = false);
174 void end(bool sel = false);
175 void cursorUp(bool sel = false);
176 void cursorDown(bool sel = false);
177 void cursorToMatchingBracket(bool sel = false);
178 void scrollUp();
179 void scrollDown();
180 void topOfView(bool sel = false);
181 void bottomOfView(bool sel = false);
182 void pageUp(bool sel = false, bool half = false);
183 void pageDown(bool sel = false, bool half = false);
184 void top(bool sel = false);
185 void bottom(bool sel = false);
186 void top_home(bool sel = false);
187 void bottom_end(bool sel = false);
188
189private:
190 // Takes as input @p c and applies the home command on it
191 KTextEditor::Cursor moveCursorToLineStart(KTextEditor::Cursor c);
192 // Takes as input @p c and applies the end command on it
193 KTextEditor::Cursor moveCursorToLineEnd(KTextEditor::Cursor c);
194
195public:
196 /**
197 * Accessor to the current caret position
198 * @return position of the caret as @c KTextEditor::Cursor
199 * @see KTextEditor::Cursor
200 */
201 KTextEditor::Cursor cursorPosition() const
202 {
203 return m_cursor;
204 }
205
206 /**
207 * Accessor to the current mouse position
208 * @return position of the mouse as @c KTextEditor::Cursor
209 * @see KTextEditor::Cursor
210 */
211 KTextEditor::Cursor mousePosition() const
212 {
213 return m_mouse;
214 }
215
216 QPoint cursorToCoordinate(const KTextEditor::Cursor cursor, bool realCursor = true, bool includeBorder = true) const;
217 // by default, works on coordinates of the whole widget, eg. offsetted by the border
218 KTextEditor::Cursor coordinatesToCursor(const QPoint &coord, bool includeBorder = true) const;
219 QPoint cursorCoordinates(bool includeBorder = true) const;
220 KTextEditor::Cursor findMatchingBracket();
221
222 // exported for unit tests
223 KTEXTEDITOR_EXPORT KTextEditor::Range
224 findMatchingFoldingMarker(const KTextEditor::Cursor current_cursor_pos, const KSyntaxHighlighting::FoldingRegion foldingRegion, const int maxLines);
225 KTEXTEDITOR_EXPORT void updateFoldingMarkersHighlighting();
226
227 inline int getStartOffset(int direction, int offset, int length) const
228 {
229 return direction == 1 ? offset - length : offset;
230 }
231
232 inline int getEndOffset(int direction, int offset, int length) const
233 {
234 return direction == 1 ? offset : offset + length;
235 }
236
237 KateIconBorder *iconBorder() const
238 {
239 return m_leftBorder;
240 }
241
242 // EVENT HANDLING STUFF - IMPORTANT
243private:
244 void fixDropEvent(QDropEvent *event);
245
246 static bool isAcceptableInput(const QKeyEvent *e);
247
248protected:
249 void hideEvent(QHideEvent *e) override;
250 void paintEvent(QPaintEvent *e) override;
251 bool eventFilter(QObject *obj, QEvent *e) override;
252 void keyPressEvent(QKeyEvent *) override;
253 void keyReleaseEvent(QKeyEvent *) override;
254 void resizeEvent(QResizeEvent *) override;
255 void moveEvent(QMoveEvent *) override;
256 void mousePressEvent(QMouseEvent *) override;
257 void mouseDoubleClickEvent(QMouseEvent *) override;
258 void mouseReleaseEvent(QMouseEvent *) override;
259 void mouseMoveEvent(QMouseEvent *) override;
260 void leaveEvent(QEvent *) override;
261 void dragEnterEvent(QDragEnterEvent *) override;
262 void dragMoveEvent(QDragMoveEvent *) override;
263 void dropEvent(QDropEvent *) override;
264 void showEvent(QShowEvent *) override;
265 void wheelEvent(QWheelEvent *e) override;
266 void scrollPrepareEvent(QScrollPrepareEvent *);
267 void scrollEvent(QScrollEvent *);
268 void focusInEvent(QFocusEvent *) override;
269 void focusOutEvent(QFocusEvent *) override;
270 void inputMethodEvent(QInputMethodEvent *e) override;
271
272 void contextMenuEvent(QContextMenuEvent *e) override;
273
274private Q_SLOTS:
275 void tripleClickTimeout();
276
277Q_SIGNALS:
278 // emitted when KateViewInternal is not handling its own URI drops
279 void dropEventPass(QDropEvent *);
280
281private Q_SLOTS:
282 void slotRegionVisibilityChanged();
283 void slotRegionBeginEndAddedRemoved(unsigned int);
284
285private:
286 void moveChar(Bias bias, bool sel);
287 void moveEdge(Bias bias, bool sel);
288 KTextEditor::Cursor maxStartPos(bool changed = false);
289 void scrollPos(KTextEditor::Cursor &c, bool force = false, bool calledExternally = false, bool emitSignals = true);
290 void scrollLines(int lines, bool sel);
291
292 KTextEditor::Attribute::Ptr attributeAt(const KTextEditor::Cursor position) const;
293 int linesDisplayed() const;
294
295 int lineToY(int viewLine) const;
296
297 void updateSecondarySelection(int cursorIdx, KTextEditor::Cursor old, KTextEditor::Cursor newPos) const;
298 void updateSelection(const KTextEditor::Cursor, bool keepSel);
299 void setSelection(KTextEditor::Range);
300 void moveCursorToSelectionEdge(bool scroll = true);
301 void updateCursor(const KTextEditor::Cursor newCursor, bool force = false, bool center = false, bool calledExternally = false, bool scroll = true);
302 void updateBracketMarks();
303 void beginSelectLine(const QPoint &pos);
304
305 struct CursorPair {
306 KTextEditor::Cursor oldPos;
307 KTextEditor::Cursor newPos;
308 };
309 // @brief updates the secondary cursor, schedules repaint
310 // MUST setPosition of the corresponding moving cursors before calling this
311 void updateSecondaryCursors(const QVarLengthArray<CursorPair, 16> &cursors, bool sel);
312 void mergeSelections();
313
314 KTextEditor::Cursor cursorForPoint(QPoint p);
315 void placeCursor(const QPoint &p, bool keepSelection = false, bool updateSelection = true);
316 bool isTargetSelected(const QPoint &p);
317 // Returns whether the given range affects the area currently visible in the view
318 bool rangeAffectsView(KTextEditor::Range range, bool realCursors) const;
319
320 void doDrag();
321
322 KateRenderer *renderer() const;
323
324 bool sendMouseEventToInputContext(QMouseEvent *e);
325 void commitPreedit();
326
327 KTextEditor::ViewPrivate *m_view;
328 class KateIconBorder *m_leftBorder;
329
330 int m_mouseX;
331 int m_mouseY;
332 int m_scrollX;
333 int m_scrollY;
334
335 std::unique_ptr<ZoomEventFilter> m_zoomEventFilter;
336
337 Qt::CursorShape m_mouseCursor;
338
339 Kate::TextCursor m_cursor;
340 KTextEditor::Cursor m_mouse;
341 KTextEditor::Cursor m_displayCursor;
342
343 bool m_possibleTripleClick;
344
345 // Bracket mark and corresponding decorative ranges
346 std::unique_ptr<KTextEditor::MovingRange> m_bm, m_bmStart, m_bmEnd;
347 std::unique_ptr<KTextEditor::MovingCursor> m_bmLastFlashPos;
348 std::unique_ptr<KateTextPreview> m_bmPreview;
349 void updateBracketMarkAttributes();
350
351 // Folding mark
352 std::unique_ptr<KTextEditor::MovingRange> m_fmStart, m_fmEnd;
353
354 enum DragState { diNone, diPending, diDragging };
355
356 struct _dragInfo {
357 DragState state;
358 QPoint start;
359 QDrag *dragObject;
360 } m_dragInfo;
361
362 //
363 // line scrollbar + first visible (virtual) line in the current view
364 //
365 KateScrollBar *m_lineScroll;
366 qreal m_accumulatedScroll = 0.0;
367 QWidget *m_dummy;
368
369 // These are now cursors to account for word-wrap.
370 // Start Position is a virtual cursor
371 Kate::TextCursor m_startPos;
372 // Count of lines that are visible behind m_startPos.
373 // This does not respect dynamic word wrap, so take it as an approximation.
374 uint m_visibleLineCount;
375
376 // This is set to false on resize or scroll (other than that called by makeVisible),
377 // so that makeVisible is again called when a key is pressed and the cursor is in the same spot
378 bool m_madeVisible;
379 bool m_shiftKeyPressed;
380
381 // How many lines to should be kept visible above/below the cursor when possible
382 void setAutoCenterLines(int viewLines, bool updateView = true);
383 int m_autoCenterLines;
384 int m_minLinesVisible;
385
386 //
387 // column scrollbar + x position
388 //
389 QScrollBar *m_columnScroll;
390 QScroller *m_scroller;
391 int m_startX;
392
393 // has selection changed while your mouse or shift key is pressed
394 bool m_selChangedByUser;
395 KTextEditor::Cursor m_selectAnchor;
396
397 enum SelectionMode { Default = 0, Mouse, Word, Line }; ///< for drag selection.
398 uint m_selectionMode;
399 // when drag selecting after double/triple click, keep the initial selected
400 // word/line independent of direction.
401 // They get set in the event of a double click, and is used with mouse move + leftbutton
402 KTextEditor::Range m_selectionCached;
403
404 // maximal length of textlines visible from given startLine
405 int maxLen(int startLine);
406
407 // are we allowed to scroll columns?
408 bool columnScrollingPossible();
409
410 // the same for lines
411 bool lineScrollingPossible();
412
413 // returns the maximum X value / col value a cursor can take for a specific line range
414 int lineMaxCursorX(const KateTextLayout &line);
415 static int lineMaxCol(const KateTextLayout &line);
416
417 class KateLayoutCache *cache() const;
418 KateLayoutCache *m_layoutCache;
419
420 // convenience methods
421
422 /// returns layout for the line c.line()
423 KateTextLayout currentLayout(KTextEditor::Cursor c) const;
424 // returns layout for the line previous to @p c
425 KateTextLayout previousLayout(KTextEditor::Cursor c) const;
426 // returns layout for the line next to @p c
427 KateTextLayout nextLayout(KTextEditor::Cursor c) const;
428
429 // find the cursor offset by (offset) view lines from a cursor.
430 // when keepX is true, the column position will be calculated based on the x
431 // position of the specified cursor.
432 KTextEditor::Cursor viewLineOffset(const KTextEditor::Cursor virtualCursor, int offset, bool keepX = false);
433
434 KTextEditor::Cursor toRealCursor(const KTextEditor::Cursor virtualCursor) const;
435 KTextEditor::Cursor toVirtualCursor(const KTextEditor::Cursor realCursor) const;
436
437 // These variable holds the most recent maximum real & visible column number
438 bool m_preserveX;
439 int m_preservedX;
440
441 KTextEditor::Cursor m_cachedMaxStartPos;
442
443 //
444 // implementation details for KTextEditor::FlashTextInterface
445 //
446public:
447 void flashChar(const KTextEditor::Cursor pos, KTextEditor::Attribute::Ptr attribute);
448 void showBracketMatchPreview();
449 void hideBracketMatchPreview();
450
451private:
452 QPointer<KateTextAnimation> m_textAnimation;
453
454private Q_SLOTS:
455 void doDragScroll();
456 void startDragScroll();
457 void stopDragScroll();
458
459private:
460 // Timers
461 QTimer m_dragScrollTimer;
462 QTimer m_scrollTimer;
463 QTimer m_cursorTimer;
464 QTimer m_textHintTimer;
465
466 static const int s_scrollTime = 30;
467 static const int s_scrollMargin = 16;
468
469private Q_SLOTS:
470 void scrollTimeout();
471 void cursorTimeout();
472 void textHintTimeout();
473
474 void documentTextInserted(KTextEditor::Document *document, KTextEditor::Range range);
475 void documentTextRemoved(KTextEditor::Document *document, KTextEditor::Range range, const QString &oldText);
476
477 //
478 // KTE::TextHintInterface
479 //
480public:
481 void registerTextHintProvider(KTextEditor::TextHintProvider *provider);
482 void unregisterTextHintProvider(KTextEditor::TextHintProvider *provider);
483 void setTextHintDelay(int delay);
484 int textHintDelay() const;
485 bool textHintsEnabled(); // not part of the interface
486
487private:
488 std::vector<KTextEditor::TextHintProvider *> m_textHintProviders;
489 int m_textHintDelay;
490 QPoint m_textHintPos;
491
492 //
493 // IM input stuff
494 //
495public:
496 QVariant inputMethodQuery(Qt::InputMethodQuery query) const override;
497
498private:
499 std::unique_ptr<KTextEditor::MovingRange> m_imPreeditRange;
500 std::vector<std::unique_ptr<KTextEditor::MovingRange>> m_imPreeditRangeChildren;
501
502private:
503 void mouseMoved();
504 void cursorMoved();
505
506private:
507 KTextEditor::DocumentPrivate *doc();
508 KTextEditor::DocumentPrivate *doc() const;
509
510 // input modes
511private:
512 std::array<std::unique_ptr<KateAbstractInputMode>, KTextEditor::View::ViInputMode + 1> m_inputModes;
513 KateAbstractInputMode *m_currentInputMode;
514
515 KateInlineNoteData m_activeInlineNote;
516 KateInlineNoteData inlineNoteAt(const QPoint &globalPos) const;
517 QRect inlineNoteRect(const KateInlineNoteData &note) const;
518};
519
520#endif
521

source code of ktexteditor/src/view/kateviewinternal.h