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