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 ¬e) const; 0518 }; 0519 0520 #endif