File indexing completed on 2024-04-14 03:55:42

0001 /*
0002     SPDX-FileCopyrightText: 2002-2007 Hamish Rodda <rodda@kde.org>
0003     SPDX-FileCopyrightText: 2002 John Firebaugh <jfirebaugh@kde.org>
0004     SPDX-FileCopyrightText: 2002 Joseph Wenninger <jowenn@kde.org>
0005     SPDX-FileCopyrightText: 2002 Christoph Cullmann <cullmann@kde.org>
0006     SPDX-FileCopyrightText: 2007 Mirko Stocker <me@misto.ch>
0007 
0008     Based on KWriteView:
0009     SPDX-FileCopyrightText: 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
0010 
0011     SPDX-License-Identifier: LGPL-2.0-or-later
0012 */
0013 #ifndef _KATE_VIEW_INTERNAL_
0014 #define _KATE_VIEW_INTERNAL_
0015 
0016 #include <KSyntaxHighlighting/FoldingRegion>
0017 
0018 #include <ktexteditor/attribute.h>
0019 #include <ktexteditor/range.h>
0020 #include <ktexteditor/view.h>
0021 
0022 #include "inlinenotedata.h"
0023 #include "katetextcursor.h"
0024 #include "katetextline.h"
0025 
0026 #include <QDrag>
0027 #include <QElapsedTimer>
0028 #include <QPoint>
0029 #include <QPointer>
0030 #include <QSet>
0031 #include <QTime>
0032 #include <QTimer>
0033 #include <QWidget>
0034 
0035 #include <array>
0036 #include <memory>
0037 
0038 namespace KTextEditor
0039 {
0040 class MovingRange;
0041 class TextHintProvider;
0042 class DocumentPrivate;
0043 class ViewPrivate;
0044 }
0045 
0046 class KateIconBorder;
0047 class KateScrollBar;
0048 class KateAnnotationItemDelegate;
0049 class KateAnnotationGroupPositionState;
0050 class KateTextLayout;
0051 class KateTextAnimation;
0052 class KateAbstractInputMode;
0053 class ZoomEventFilter;
0054 class KateRenderer;
0055 class KateTextPreview;
0056 class KateViewTest;
0057 
0058 class QScrollBar;
0059 class QScroller;
0060 class QScrollEvent;
0061 class QScrollPrepareEvent;
0062 
0063 class KateViewInternal final : public QWidget
0064 {
0065     Q_OBJECT
0066 
0067     friend class KTextEditor::ViewPrivate;
0068     friend class KateIconBorder;
0069     friend class KateScrollBar;
0070     friend class KateAnnotationGroupPositionState;
0071     friend class CalculatingCursor;
0072     friend class BoundedCursor;
0073     friend class WrappingCursor;
0074     friend class CamelCursor;
0075     friend class KateAbstractInputMode;
0076     friend class ::KateTextPreview;
0077     friend class KateViewTest;
0078 
0079 public:
0080     enum Bias { left = -1, none = 0, right = 1 };
0081 
0082 public:
0083     explicit KateViewInternal(KTextEditor::ViewPrivate *view);
0084     ~KateViewInternal() override;
0085     KTextEditor::ViewPrivate *view() const
0086     {
0087         return m_view;
0088     }
0089 
0090     // BEGIN EDIT STUFF
0091 public:
0092     void editStart();
0093     void editEnd(int editTagLineStart, int editTagLineEnd, bool tagFrom);
0094 
0095     void editSetCursor(const KTextEditor::Cursor cursor);
0096 
0097 private:
0098     uint editSessionNumber;
0099     bool editIsRunning;
0100     KTextEditor::Cursor editOldCursor;
0101     KTextEditor::Range editOldSelection;
0102     // END
0103 
0104     // BEGIN TAG & CLEAR & UPDATE STUFF
0105 public:
0106     bool tagLine(const KTextEditor::Cursor virtualCursor);
0107 
0108     bool tagLines(int start, int end, bool realLines = false);
0109     // cursors not const references as they are manipulated within
0110     bool tagLines(KTextEditor::Cursor start, KTextEditor::Cursor end, bool realCursors = false);
0111 
0112     bool tagRange(KTextEditor::Range range, bool realCursors);
0113 
0114     void tagAll();
0115 
0116     void updateDirty();
0117 
0118     void clear();
0119     // END
0120 
0121 private Q_SLOTS:
0122     // Updates the view and requests a redraw.
0123     void updateView(bool changed = false, int viewLinesScrolled = 0);
0124 
0125 private:
0126     void makeVisible(const KTextEditor::Cursor c, int endCol, bool force = false, bool center = false, bool calledExternally = false);
0127 
0128 public:
0129     // Start Position is a virtual cursor
0130     KTextEditor::Cursor startPos() const
0131     {
0132         return m_startPos;
0133     }
0134     int startLine() const
0135     {
0136         return m_startPos.line();
0137     }
0138     int startX() const
0139     {
0140         return m_startX;
0141     }
0142 
0143     KTextEditor::Cursor endPos() const;
0144     int endLine() const;
0145 
0146     KateTextLayout yToKateTextLayout(int y) const;
0147 
0148     void dynWrapChanged();
0149 
0150 public Q_SLOTS:
0151     void slotIncFontSizes(qreal step = 1.0);
0152     void slotDecFontSizes(qreal step = 1.0);
0153     void slotResetFontSizes();
0154 
0155     void paintCursor();
0156 
0157 private Q_SLOTS:
0158     void scrollLines(int line); // connected to the sliderMoved of the m_lineScroll
0159     void scrollViewLines(int offset);
0160     void scrollAction(int action);
0161     void scrollNextPage();
0162     void scrollPrevPage();
0163     void scrollPrevLine();
0164     void scrollNextLine();
0165     void scrollColumns(int x); // connected to the valueChanged of the m_columnScroll
0166     void viewSelectionChanged();
0167 
0168 public:
0169     void cursorPrevChar(bool sel = false);
0170     void cursorNextChar(bool sel = false);
0171     void wordPrev(bool sel = false);
0172     void wordNext(bool sel = false);
0173     void home(bool sel = false);
0174     void end(bool sel = false);
0175     void cursorUp(bool sel = false);
0176     void cursorDown(bool sel = false);
0177     void cursorToMatchingBracket(bool sel = false);
0178     void scrollUp();
0179     void scrollDown();
0180     void topOfView(bool sel = false);
0181     void bottomOfView(bool sel = false);
0182     void pageUp(bool sel = false, bool half = false);
0183     void pageDown(bool sel = false, bool half = false);
0184     void top(bool sel = false);
0185     void bottom(bool sel = false);
0186     void top_home(bool sel = false);
0187     void bottom_end(bool sel = false);
0188 
0189 private:
0190     // Takes as input @p c and applies the home command on it
0191     KTextEditor::Cursor moveCursorToLineStart(KTextEditor::Cursor c);
0192     // Takes as input @p c and applies the end command on it
0193     KTextEditor::Cursor moveCursorToLineEnd(KTextEditor::Cursor c);
0194 
0195 public:
0196     /**
0197      * Accessor to the current caret position
0198      * @return position of the caret as @c KTextEditor::Cursor
0199      * @see KTextEditor::Cursor
0200      */
0201     KTextEditor::Cursor cursorPosition() const
0202     {
0203         return m_cursor;
0204     }
0205 
0206     /**
0207      * Accessor to the current mouse position
0208      * @return position of the mouse as @c KTextEditor::Cursor
0209      * @see KTextEditor::Cursor
0210      */
0211     KTextEditor::Cursor mousePosition() const
0212     {
0213         return m_mouse;
0214     }
0215 
0216     QPoint cursorToCoordinate(const KTextEditor::Cursor cursor, bool realCursor = true, bool includeBorder = true) const;
0217     // by default, works on coordinates of the whole widget, eg. offsetted by the border
0218     KTextEditor::Cursor coordinatesToCursor(const QPoint &coord, bool includeBorder = true) const;
0219     QPoint cursorCoordinates(bool includeBorder = true) const;
0220     KTextEditor::Cursor findMatchingBracket();
0221 
0222     // exported for unit tests
0223     KTEXTEDITOR_EXPORT KTextEditor::Range
0224     findMatchingFoldingMarker(const KTextEditor::Cursor current_cursor_pos, const KSyntaxHighlighting::FoldingRegion foldingRegion, const int maxLines);
0225     KTEXTEDITOR_EXPORT void updateFoldingMarkersHighlighting();
0226 
0227     inline int getStartOffset(int direction, int offset, int length) const
0228     {
0229         return direction == 1 ? offset - length : offset;
0230     }
0231 
0232     inline int getEndOffset(int direction, int offset, int length) const
0233     {
0234         return direction == 1 ? offset : offset + length;
0235     }
0236 
0237     KateIconBorder *iconBorder() const
0238     {
0239         return m_leftBorder;
0240     }
0241 
0242     // EVENT HANDLING STUFF - IMPORTANT
0243 private:
0244     void fixDropEvent(QDropEvent *event);
0245 
0246     static bool isAcceptableInput(const QKeyEvent *e);
0247 
0248 protected:
0249     void hideEvent(QHideEvent *e) override;
0250     void paintEvent(QPaintEvent *e) override;
0251     bool eventFilter(QObject *obj, QEvent *e) override;
0252     void keyPressEvent(QKeyEvent *) override;
0253     void keyReleaseEvent(QKeyEvent *) override;
0254     void resizeEvent(QResizeEvent *) override;
0255     void moveEvent(QMoveEvent *) override;
0256     void mousePressEvent(QMouseEvent *) override;
0257     void mouseDoubleClickEvent(QMouseEvent *) override;
0258     void mouseReleaseEvent(QMouseEvent *) override;
0259     void mouseMoveEvent(QMouseEvent *) override;
0260     void leaveEvent(QEvent *) override;
0261     void dragEnterEvent(QDragEnterEvent *) override;
0262     void dragMoveEvent(QDragMoveEvent *) override;
0263     void dropEvent(QDropEvent *) override;
0264     void showEvent(QShowEvent *) override;
0265     void wheelEvent(QWheelEvent *e) override;
0266     void scrollPrepareEvent(QScrollPrepareEvent *);
0267     void scrollEvent(QScrollEvent *);
0268     void focusInEvent(QFocusEvent *) override;
0269     void focusOutEvent(QFocusEvent *) override;
0270     void inputMethodEvent(QInputMethodEvent *e) override;
0271 
0272     void contextMenuEvent(QContextMenuEvent *e) override;
0273 
0274 private Q_SLOTS:
0275     void tripleClickTimeout();
0276 
0277 Q_SIGNALS:
0278     // emitted when KateViewInternal is not handling its own URI drops
0279     void dropEventPass(QDropEvent *);
0280 
0281 private Q_SLOTS:
0282     void slotRegionVisibilityChanged();
0283     void slotRegionBeginEndAddedRemoved(unsigned int);
0284 
0285 private:
0286     void moveChar(Bias bias, bool sel);
0287     void moveEdge(Bias bias, bool sel);
0288     KTextEditor::Cursor maxStartPos(bool changed = false);
0289     void scrollPos(KTextEditor::Cursor &c, bool force = false, bool calledExternally = false, bool emitSignals = true);
0290     void scrollLines(int lines, bool sel);
0291 
0292     KTextEditor::Attribute::Ptr attributeAt(const KTextEditor::Cursor position) const;
0293     int linesDisplayed() const;
0294 
0295     int lineToY(int viewLine) const;
0296 
0297     void updateSecondarySelection(int cursorIdx, KTextEditor::Cursor old, KTextEditor::Cursor newPos) const;
0298     void updateSelection(const KTextEditor::Cursor, bool keepSel);
0299     void setSelection(KTextEditor::Range);
0300     void moveCursorToSelectionEdge(bool scroll = true);
0301     void updateCursor(const KTextEditor::Cursor newCursor, bool force = false, bool center = false, bool calledExternally = false, bool scroll = true);
0302     void updateBracketMarks();
0303     void beginSelectLine(const QPoint &pos);
0304 
0305     struct CursorPair {
0306         KTextEditor::Cursor oldPos;
0307         KTextEditor::Cursor newPos;
0308     };
0309     // @brief updates the secondary cursor, schedules repaint
0310     // MUST setPosition of the corresponding moving cursors before calling this
0311     void updateSecondaryCursors(const QVarLengthArray<CursorPair, 16> &cursors, bool sel);
0312     void mergeSelections();
0313 
0314     KTextEditor::Cursor cursorForPoint(QPoint p);
0315     void placeCursor(const QPoint &p, bool keepSelection = false, bool updateSelection = true);
0316     bool isTargetSelected(const QPoint &p);
0317     // Returns whether the given range affects the area currently visible in the view
0318     bool rangeAffectsView(KTextEditor::Range range, bool realCursors) const;
0319 
0320     void doDrag();
0321 
0322     KateRenderer *renderer() const;
0323 
0324     bool sendMouseEventToInputContext(QMouseEvent *e);
0325     void commitPreedit();
0326 
0327     KTextEditor::ViewPrivate *m_view;
0328     class KateIconBorder *m_leftBorder;
0329 
0330     int m_mouseX;
0331     int m_mouseY;
0332     int m_scrollX;
0333     int m_scrollY;
0334 
0335     std::unique_ptr<ZoomEventFilter> m_zoomEventFilter;
0336 
0337     Qt::CursorShape m_mouseCursor;
0338 
0339     Kate::TextCursor m_cursor;
0340     KTextEditor::Cursor m_mouse;
0341     KTextEditor::Cursor m_displayCursor;
0342 
0343     bool m_possibleTripleClick;
0344 
0345     // Bracket mark and corresponding decorative ranges
0346     std::unique_ptr<KTextEditor::MovingRange> m_bm, m_bmStart, m_bmEnd;
0347     std::unique_ptr<KTextEditor::MovingCursor> m_bmLastFlashPos;
0348     std::unique_ptr<KateTextPreview> m_bmPreview;
0349     void updateBracketMarkAttributes();
0350 
0351     // Folding mark
0352     std::unique_ptr<KTextEditor::MovingRange> m_fmStart, m_fmEnd;
0353 
0354     enum DragState { diNone, diPending, diDragging };
0355 
0356     struct _dragInfo {
0357         DragState state;
0358         QPoint start;
0359         QDrag *dragObject;
0360     } m_dragInfo;
0361 
0362     //
0363     // line scrollbar + first visible (virtual) line in the current view
0364     //
0365     KateScrollBar *m_lineScroll;
0366     qreal m_accumulatedScroll = 0.0;
0367     QWidget *m_dummy;
0368 
0369     // These are now cursors to account for word-wrap.
0370     // Start Position is a virtual cursor
0371     Kate::TextCursor m_startPos;
0372     // Count of lines that are visible behind m_startPos.
0373     // This does not respect dynamic word wrap, so take it as an approximation.
0374     uint m_visibleLineCount;
0375 
0376     // This is set to false on resize or scroll (other than that called by makeVisible),
0377     // so that makeVisible is again called when a key is pressed and the cursor is in the same spot
0378     bool m_madeVisible;
0379     bool m_shiftKeyPressed;
0380 
0381     // How many lines to should be kept visible above/below the cursor when possible
0382     void setAutoCenterLines(int viewLines, bool updateView = true);
0383     int m_autoCenterLines;
0384     int m_minLinesVisible;
0385 
0386     //
0387     // column scrollbar + x position
0388     //
0389     QScrollBar *m_columnScroll;
0390     QScroller *m_scroller;
0391     int m_startX;
0392 
0393     // has selection changed while your mouse or shift key is pressed
0394     bool m_selChangedByUser;
0395     KTextEditor::Cursor m_selectAnchor;
0396 
0397     enum SelectionMode { Default = 0, Mouse, Word, Line }; ///< for drag selection.
0398     uint m_selectionMode;
0399     // when drag selecting after double/triple click, keep the initial selected
0400     // word/line independent of direction.
0401     // They get set in the event of a double click, and is used with mouse move + leftbutton
0402     KTextEditor::Range m_selectionCached;
0403 
0404     // maximal length of textlines visible from given startLine
0405     int maxLen(int startLine);
0406 
0407     // are we allowed to scroll columns?
0408     bool columnScrollingPossible();
0409 
0410     // the same for lines
0411     bool lineScrollingPossible();
0412 
0413     // returns the maximum X value / col value a cursor can take for a specific line range
0414     int lineMaxCursorX(const KateTextLayout &line);
0415     static int lineMaxCol(const KateTextLayout &line);
0416 
0417     class KateLayoutCache *cache() const;
0418     KateLayoutCache *m_layoutCache;
0419 
0420     // convenience methods
0421 
0422     /// returns layout for the line c.line()
0423     KateTextLayout currentLayout(KTextEditor::Cursor c) const;
0424     // returns layout for the line previous to @p c
0425     KateTextLayout previousLayout(KTextEditor::Cursor c) const;
0426     // returns layout for the line next to @p c
0427     KateTextLayout nextLayout(KTextEditor::Cursor c) const;
0428 
0429     // find the cursor offset by (offset) view lines from a cursor.
0430     // when keepX is true, the column position will be calculated based on the x
0431     // position of the specified cursor.
0432     KTextEditor::Cursor viewLineOffset(const KTextEditor::Cursor virtualCursor, int offset, bool keepX = false);
0433 
0434     KTextEditor::Cursor toRealCursor(const KTextEditor::Cursor virtualCursor) const;
0435     KTextEditor::Cursor toVirtualCursor(const KTextEditor::Cursor realCursor) const;
0436 
0437     // These variable holds the most recent maximum real & visible column number
0438     bool m_preserveX;
0439     int m_preservedX;
0440 
0441     KTextEditor::Cursor m_cachedMaxStartPos;
0442 
0443     //
0444     // implementation details for KTextEditor::FlashTextInterface
0445     //
0446 public:
0447     void flashChar(const KTextEditor::Cursor pos, KTextEditor::Attribute::Ptr attribute);
0448     void showBracketMatchPreview();
0449     void hideBracketMatchPreview();
0450 
0451 private:
0452     QPointer<KateTextAnimation> m_textAnimation;
0453 
0454 private Q_SLOTS:
0455     void doDragScroll();
0456     void startDragScroll();
0457     void stopDragScroll();
0458 
0459 private:
0460     // Timers
0461     QTimer m_dragScrollTimer;
0462     QTimer m_scrollTimer;
0463     QTimer m_cursorTimer;
0464     QTimer m_textHintTimer;
0465 
0466     static const int s_scrollTime = 30;
0467     static const int s_scrollMargin = 16;
0468 
0469 private Q_SLOTS:
0470     void scrollTimeout();
0471     void cursorTimeout();
0472     void textHintTimeout();
0473 
0474     void documentTextInserted(KTextEditor::Document *document, KTextEditor::Range range);
0475     void documentTextRemoved(KTextEditor::Document *document, KTextEditor::Range range, const QString &oldText);
0476 
0477     //
0478     // KTE::TextHintInterface
0479     //
0480 public:
0481     void registerTextHintProvider(KTextEditor::TextHintProvider *provider);
0482     void unregisterTextHintProvider(KTextEditor::TextHintProvider *provider);
0483     void setTextHintDelay(int delay);
0484     int textHintDelay() const;
0485     bool textHintsEnabled(); // not part of the interface
0486 
0487 private:
0488     std::vector<KTextEditor::TextHintProvider *> m_textHintProviders;
0489     int m_textHintDelay;
0490     QPoint m_textHintPos;
0491 
0492     //
0493     // IM input stuff
0494     //
0495 public:
0496     QVariant inputMethodQuery(Qt::InputMethodQuery query) const override;
0497 
0498 private:
0499     std::unique_ptr<KTextEditor::MovingRange> m_imPreeditRange;
0500     std::vector<std::unique_ptr<KTextEditor::MovingRange>> m_imPreeditRangeChildren;
0501 
0502 private:
0503     void mouseMoved();
0504     void cursorMoved();
0505 
0506 private:
0507     KTextEditor::DocumentPrivate *doc();
0508     KTextEditor::DocumentPrivate *doc() const;
0509 
0510     // input modes
0511 private:
0512     std::array<std::unique_ptr<KateAbstractInputMode>, KTextEditor::View::ViInputMode + 1> m_inputModes;
0513     KateAbstractInputMode *m_currentInputMode;
0514 
0515     KateInlineNoteData m_activeInlineNote;
0516     KateInlineNoteData inlineNoteAt(const QPoint &globalPos) const;
0517     QRect inlineNoteRect(const KateInlineNoteData &note) const;
0518 };
0519 
0520 #endif