1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2002 John Firebaugh <jfirebaugh@kde.org>
4 SPDX-FileCopyrightText: 2001 Anders Lund <anders@alweb.dk>
5 SPDX-FileCopyrightText: 2001 Christoph Cullmann <cullmann@kde.org>
6 SPDX-FileCopyrightText: 2017-2018 Friedrich W. H. Kossebau <kossebau@kde.org>
7
8 SPDX-License-Identifier: LGPL-2.0-only
9*/
10
11#ifndef KATE_VIEW_HELPERS_H
12#define KATE_VIEW_HELPERS_H
13
14#include <KActionMenu>
15#include <KLineEdit>
16#include <KSelectAction>
17
18#include <QColor>
19#include <QHash>
20#include <QLayout>
21#include <QPixmap>
22#include <QPointer>
23#include <QScrollBar>
24#include <QTimer>
25
26#include "katetextline.h"
27#include <ktexteditor/cursor.h>
28#include <ktexteditor/message.h>
29
30namespace KTextEditor
31{
32class ViewPrivate;
33class DocumentPrivate;
34class Command;
35class AnnotationModel;
36class MovingRange;
37class AbstractAnnotationItemDelegate;
38class StyleOptionAnnotationItem;
39}
40
41class KateViewInternal;
42class KateTextLayout;
43
44#define MAXFOLDINGCOLORS 16
45
46class KateLineInfo;
47class KateTextPreview;
48
49namespace Kate
50{
51class TextRange;
52}
53
54class QTimer;
55class QVBoxLayout;
56class QStackedWidget;
57
58/**
59 * Class to layout KTextEditor::Message%s in KateView. Only the floating
60 * positions TopInView, CenterInView, and BottomInView are supported.
61 * AboveView and BelowView are not supported and ASSERT.
62 */
63class KateMessageLayout : public QLayout
64{
65public:
66 explicit KateMessageLayout(QWidget *parent);
67 ~KateMessageLayout() override;
68
69 void addWidget(QWidget *widget, KTextEditor::Message::MessagePosition pos);
70 int count() const override;
71 QLayoutItem *itemAt(int index) const override;
72 void setGeometry(const QRect &rect) override;
73 QSize sizeHint() const override;
74 QLayoutItem *takeAt(int index) override;
75
76 void add(QLayoutItem *item, KTextEditor::Message::MessagePosition pos);
77
78private:
79 void addItem(QLayoutItem *item) override; // never called publically
80
81 struct ItemWrapper {
82 ItemWrapper() = default;
83 ItemWrapper(QLayoutItem *i, KTextEditor::Message::MessagePosition pos)
84 : item(i)
85 , position(pos)
86 {
87 }
88
89 QLayoutItem *item = nullptr;
90 KTextEditor::Message::MessagePosition position = KTextEditor::Message::AboveView;
91 };
92
93 QList<ItemWrapper> m_items;
94};
95
96/**
97 * This class is required because QScrollBar's sliderMoved() signal is
98 * really supposed to be a sliderDragged() signal... so this way we can capture
99 * MMB slider moves as well
100 *
101 * Also, it adds some useful indicators on the scrollbar.
102 */
103class KateScrollBar : public QScrollBar
104{
105 Q_OBJECT
106
107public:
108 KateScrollBar(Qt::Orientation orientation, class KateViewInternal *parent);
109 ~KateScrollBar() override;
110 QSize sizeHint() const override;
111
112 void showEvent(QShowEvent *event) override;
113
114 inline bool showMarks() const
115 {
116 return m_showMarks;
117 }
118 inline void setShowMarks(bool b)
119 {
120 m_showMarks = b;
121 update();
122 }
123
124 inline bool showMiniMap() const
125 {
126 return m_showMiniMap;
127 }
128 void setShowMiniMap(bool b);
129
130 inline bool miniMapAll() const
131 {
132 return m_miniMapAll;
133 }
134 inline void setMiniMapAll(bool b)
135 {
136 m_miniMapAll = b;
137 updateGeometry();
138 update();
139 }
140
141 inline bool miniMapWidth() const
142 {
143 return m_miniMapWidth;
144 }
145 inline void setMiniMapWidth(int width)
146 {
147 m_miniMapWidth = width;
148 updateGeometry();
149 update();
150 }
151
152 inline void queuePixmapUpdate()
153 {
154 m_updateTimer.start();
155 }
156
157Q_SIGNALS:
158 void sliderMMBMoved(int value);
159
160protected:
161 void mousePressEvent(QMouseEvent *e) override;
162 void mouseReleaseEvent(QMouseEvent *e) override;
163 void mouseMoveEvent(QMouseEvent *e) override;
164 void leaveEvent(QEvent *event) override;
165 bool eventFilter(QObject *object, QEvent *event) override;
166 void paintEvent(QPaintEvent *e) override;
167 void resizeEvent(QResizeEvent *) override;
168 void sliderChange(SliderChange change) override;
169
170protected Q_SLOTS:
171 void sliderMaybeMoved(int value);
172 void marksChanged();
173
174public Q_SLOTS:
175 void updatePixmap();
176
177private Q_SLOTS:
178 void showTextPreview();
179
180private:
181 void showTextPreviewDelayed();
182 void hideTextPreview();
183
184 void redrawMarks();
185 void recomputeMarksPositions();
186
187 void miniMapPaintEvent(QPaintEvent *e);
188 void normalPaintEvent(QPaintEvent *e);
189
190 int minimapYToStdY(int y);
191
192 struct ColumnRangeWithColor {
193 int penIndex = -1;
194 int startColumn;
195 int endColumn;
196 };
197 void getCharColorRanges(const QList<Kate::TextLine::Attribute> &attributes,
198 const QList<Kate::TextRange *> &decorations,
199 const QString &text,
200 QList<KateScrollBar::ColumnRangeWithColor> &ranges,
201 QVarLengthArray<std::pair<QRgb, QPen>, 20> &penCache);
202
203 bool m_middleMouseDown;
204 bool m_leftMouseDown;
205
206 KTextEditor::ViewPrivate *m_view;
207 KTextEditor::DocumentPrivate *m_doc;
208 class KateViewInternal *m_viewInternal;
209 QPointer<KateTextPreview> m_textPreview;
210 QTimer m_delayTextPreviewTimer;
211
212 QHash<int, QColor> m_lines;
213
214 bool m_showMarks;
215 bool m_showMiniMap;
216 bool m_miniMapAll;
217 bool m_needsUpdateOnShow;
218 int m_miniMapWidth;
219
220 QPixmap m_pixmap;
221 int m_grooveHeight;
222 QRect m_stdGroveRect;
223 QRect m_mapGroveRect;
224 QRect m_sliderRect;
225 QTimer m_updateTimer;
226 QPoint m_toolTipPos;
227
228 // lists of lines added/removed recently to avoid scrollbar flickering
229 QHash<int, int> m_linesAdded;
230
231 static const unsigned char characterOpacity[256];
232};
233
234class KateIconBorder : public QWidget
235{
236 Q_OBJECT
237
238public:
239 KateIconBorder(KateViewInternal *internalView, QWidget *parent);
240 ~KateIconBorder() override;
241 // VERY IMPORTANT ;)
242 QSize sizeHint() const override;
243
244 void updateFont();
245 int lineNumberWidth() const;
246
247 void setIconBorderOn(bool enable);
248 void setLineNumbersOn(bool enable);
249 void setRelLineNumbersOn(bool enable);
250 void setAnnotationBorderOn(bool enable);
251 void setDynWrapIndicators(int state);
252 int dynWrapIndicators() const
253 {
254 return m_dynWrapIndicators;
255 }
256 bool dynWrapIndicatorsOn() const
257 {
258 return m_dynWrapIndicatorsOn;
259 }
260 void setFoldingMarkersOn(bool enable);
261 void toggleIconBorder()
262 {
263 setIconBorderOn(!iconBorderOn());
264 }
265 void toggleLineNumbers()
266 {
267 setLineNumbersOn(!lineNumbersOn());
268 }
269 void toggleFoldingMarkers()
270 {
271 setFoldingMarkersOn(!foldingMarkersOn());
272 }
273 inline bool iconBorderOn() const
274 {
275 return m_iconBorderOn;
276 }
277 inline bool lineNumbersOn() const
278 {
279 return m_lineNumbersOn;
280 }
281 inline bool viRelNumbersOn() const
282 {
283 return m_relLineNumbersOn;
284 }
285 inline bool foldingMarkersOn() const
286 {
287 return m_foldingMarkersOn;
288 }
289 inline bool annotationBorderOn() const
290 {
291 return m_annotationBorderOn;
292 }
293
294 void updateForCursorLineChange();
295
296 enum BorderArea { None, LineNumbers, IconBorder, FoldingMarkers, AnnotationBorder, ModificationBorder };
297 BorderArea positionToArea(const QPoint &) const;
298
299 KTextEditor::AbstractAnnotationItemDelegate *annotationItemDelegate() const;
300 void setAnnotationItemDelegate(KTextEditor::AbstractAnnotationItemDelegate *delegate);
301 inline bool uniformAnnotationItemSizes() const
302 {
303 return m_hasUniformAnnotationItemSizes;
304 }
305 inline void setAnnotationUniformItemSizes(bool enable)
306 {
307 m_hasUniformAnnotationItemSizes = enable;
308 }
309
310public Q_SLOTS:
311 void updateAnnotationBorderWidth();
312 void updateAnnotationLine(int line);
313 void annotationModelChanged(KTextEditor::AnnotationModel *oldmodel, KTextEditor::AnnotationModel *newmodel);
314 void displayRangeChanged();
315
316private:
317 void dragEnterEvent(QDragEnterEvent *) override;
318 void dragMoveEvent(QDragMoveEvent *event) override;
319 void dropEvent(QDropEvent *event) override;
320 void paintEvent(QPaintEvent *) override;
321 void paintBorder(int x, int y, int width, int height);
322
323 void mousePressEvent(QMouseEvent *) override;
324 void mouseMoveEvent(QMouseEvent *) override;
325 void mouseReleaseEvent(QMouseEvent *) override;
326 void mouseDoubleClickEvent(QMouseEvent *) override;
327 void contextMenuEvent(QContextMenuEvent *e) override;
328 void leaveEvent(QEvent *event) override;
329 void wheelEvent(QWheelEvent *e) override;
330
331 void enterEvent(QEnterEvent *e) override;
332
333 void showMarkMenu(uint line, const QPoint &pos);
334
335 void hideAnnotationTooltip();
336 void removeAnnotationHovering();
337 void showAnnotationMenu(int line, const QPoint &pos);
338 void calcAnnotationBorderWidth();
339
340 void initStyleOption(KTextEditor::StyleOptionAnnotationItem *styleOption) const;
341 void setStyleOptionLineData(KTextEditor::StyleOptionAnnotationItem *styleOption,
342 int y,
343 int realLine,
344 const KTextEditor::AnnotationModel *model,
345 const QString &annotationGroupIdentifier) const;
346 QRect annotationLineRectInView(int line) const;
347
348private:
349 KTextEditor::ViewPrivate *m_view;
350 KTextEditor::DocumentPrivate *m_doc;
351 KateViewInternal *m_viewInternal;
352
353 bool m_iconBorderOn : 1;
354 bool m_lineNumbersOn : 1;
355 bool m_relLineNumbersOn : 1;
356 bool m_updateRelLineNumbers : 1;
357 bool m_foldingMarkersOn : 1;
358 bool m_dynWrapIndicatorsOn : 1;
359 bool m_annotationBorderOn : 1;
360 bool m_updatePositionToArea : 1;
361 bool m_mouseOver = false;
362
363 typedef QPair<int, KateIconBorder::BorderArea> AreaPosition;
364 std::vector<AreaPosition> m_positionToArea;
365
366 const int m_separatorWidth = 2;
367 const int m_modAreaWidth = 3;
368 qreal m_maxCharWidth = 0.0;
369 int m_lineNumberAreaWidth = 0;
370 int m_iconAreaWidth = 0;
371 int m_foldingAreaWidth = 0;
372 int m_annotationAreaWidth = 0;
373 const QChar m_dynWrapIndicatorChar = QChar(0x21AA);
374 int m_dynWrapIndicators = 0;
375 int m_lastClickedLine = -1;
376
377 KTextEditor::AbstractAnnotationItemDelegate *m_annotationItemDelegate;
378 bool m_hasUniformAnnotationItemSizes = false;
379 bool m_isDefaultAnnotationItemDelegate = true;
380
381 QPointer<KateTextPreview> m_foldingPreview;
382 KTextEditor::MovingRange *m_foldingRange = nullptr;
383 int m_currentLine = -1;
384 QTimer m_antiFlickerTimer;
385 void highlightFoldingDelayed(int line);
386 void hideFolding();
387
388private Q_SLOTS:
389 void highlightFolding();
390 void handleDestroyedAnnotationItemDelegate();
391 void delayedUpdateOfSizeWithRepaint();
392
393private:
394 QString m_hoveredAnnotationGroupIdentifier;
395};
396
397class KateViewEncodingAction : public KSelectAction
398{
399public:
400 KateViewEncodingAction(KTextEditor::DocumentPrivate *_doc, KTextEditor::ViewPrivate *_view, const QString &text, QObject *parent, bool saveAsMode = false);
401
402 bool setCurrentCodec(const QString &codec);
403
404private:
405 void init();
406 void subActionTriggered(QAction *);
407
408 KTextEditor::DocumentPrivate *doc;
409 KTextEditor::ViewPrivate *view;
410 QAction *currentSubAction;
411 const bool m_saveAsMode;
412
413private:
414 void setEncoding(const QString &e);
415 void slotAboutToShow();
416};
417
418class KateViewBar;
419
420class KateViewBarWidget : public QWidget
421{
422 Q_OBJECT
423 friend class KateViewBar;
424
425public:
426 explicit KateViewBarWidget(bool addCloseButton, QWidget *parent = nullptr);
427
428 virtual void closed()
429 {
430 }
431
432 /// returns the currently associated KateViewBar and 0, if it is not associated
433 KateViewBar *viewBar()
434 {
435 return m_viewBar;
436 }
437
438protected:
439 /**
440 * @return widget that should be used to add controls to bar widget
441 */
442 QWidget *centralWidget()
443 {
444 return m_centralWidget;
445 }
446
447 /**
448 * @return close button, if there
449 */
450 QToolButton *closeButton()
451 {
452 return m_closeButton;
453 }
454
455Q_SIGNALS:
456 void hideMe();
457
458 // for friend class KateViewBar
459private:
460 void setAssociatedViewBar(KateViewBar *bar)
461 {
462 m_viewBar = bar;
463 }
464
465private:
466 QWidget *m_centralWidget = nullptr;
467 KateViewBar *m_viewBar = nullptr; // 0-pointer, if not added to a view bar
468 QToolButton *m_closeButton = nullptr;
469};
470
471class KateViewBar : public QWidget
472{
473 Q_OBJECT
474
475public:
476 KateViewBar(bool external, QWidget *parent, KTextEditor::ViewPrivate *view);
477
478 /**
479 * Adds a widget to this viewbar.
480 * Widget is initially invisible, you should call showBarWidget, to show it.
481 * Several widgets can be added to the bar, but only one can be visible
482 */
483 void addBarWidget(KateViewBarWidget *newBarWidget);
484
485 /**
486 * Removes a widget from this viewbar.
487 * Removing a widget makes sense if it takes a lot of space vertically,
488 * because we use a QStackedWidget to maintain the same height for all
489 * widgets in the viewbar.
490 */
491 void removeBarWidget(KateViewBarWidget *barWidget);
492
493 /**
494 * @return if viewbar has widget @p barWidget
495 */
496 bool hasBarWidget(KateViewBarWidget *barWidget) const;
497
498 /**
499 * Shows barWidget that was previously added with addBarWidget.
500 * @see hideCurrentBarWidget
501 */
502 void showBarWidget(KateViewBarWidget *barWidget);
503
504 /**
505 * Adds widget that will be always shown in the viewbar.
506 * After adding permanent widget viewbar is immediately shown.
507 * ViewBar with permanent widget won't hide itself
508 * until permanent widget is removed.
509 * OTOH showing/hiding regular barWidgets will work as usual
510 * (they will be shown above permanent widget)
511 *
512 * If permanent widget already exists, asserts!
513 */
514 void addPermanentBarWidget(KateViewBarWidget *barWidget);
515
516 /**
517 * Removes permanent bar widget from viewbar.
518 * If no other viewbar widgets are shown, viewbar gets hidden.
519 *
520 * barWidget is not deleted, caller must do it if it wishes
521 */
522 void removePermanentBarWidget(KateViewBarWidget *barWidget);
523
524 /**
525 * @return true if the a KateViewBar is visible*/
526 bool barWidgetVisible() const;
527
528public Q_SLOTS:
529 /**
530 * Hides currently shown bar widget
531 */
532 void hideCurrentBarWidget();
533
534protected:
535 void keyPressEvent(QKeyEvent *event) override;
536 void hideEvent(QHideEvent *event) override;
537
538private:
539 /**
540 * Shows or hides whole viewbar
541 */
542 void setViewBarVisible(bool visible);
543
544 bool m_external;
545
546private:
547 KTextEditor::ViewPrivate *m_view;
548 QStackedWidget *m_stack;
549 KateViewBarWidget *m_permanentBarWidget;
550 QVBoxLayout *m_layout;
551};
552
553class KateCommandLineBar : public KateViewBarWidget
554{
555public:
556 explicit KateCommandLineBar(KTextEditor::ViewPrivate *view, QWidget *parent = nullptr);
557 ~KateCommandLineBar() override;
558
559 void setText(const QString &text, bool selected = true);
560 void execute(const QString &text);
561
562public:
563 static void showHelpPage();
564
565private:
566 class KateCmdLineEdit *m_lineEdit;
567};
568
569class KateCmdLineEdit : public KLineEdit
570{
571 Q_OBJECT
572
573public:
574 KateCmdLineEdit(KateCommandLineBar *bar, KTextEditor::ViewPrivate *view);
575 bool event(QEvent *e) override;
576
577 void hideEvent(QHideEvent *e) override;
578
579Q_SIGNALS:
580 void hideRequested();
581
582public Q_SLOTS:
583 void slotReturnPressed(const QString &cmd);
584
585private Q_SLOTS:
586 void hideLineEdit();
587
588protected:
589 void focusInEvent(QFocusEvent *ev) override;
590 void keyPressEvent(QKeyEvent *ev) override;
591
592private:
593 /**
594 * Parse an expression denoting a position in the document.
595 * Return the position as an integer.
596 * Examples of expressions are "10" (the 10th line),
597 * "$" (the last line), "." (the current line),
598 * "'a" (the mark 'a), "/foo/" (a forwards search for "foo"),
599 * and "?bar?" (a backwards search for "bar").
600 * @param string the expression to parse
601 * @return the position, an integer
602 */
603 void fromHistory(bool up);
604 QString helptext(const QPoint &) const;
605
606 KTextEditor::ViewPrivate *m_view;
607 KateCommandLineBar *m_bar;
608 bool m_msgMode;
609 QString m_oldText;
610 uint m_histpos; ///< position in the history
611 uint m_cmdend; ///< the point where a command ends in the text, if we have a valid one.
612 KTextEditor::Command *m_command; ///< For completing flags/args and interactiveness
613 class KateCmdLnWhatsThis *m_help;
614
615 QTimer *m_hideTimer;
616};
617
618class KateViewSchemaAction : public KActionMenu
619{
620public:
621 KateViewSchemaAction(const QString &text, QObject *parent)
622 : KActionMenu(text, parent)
623 {
624 init();
625 setPopupMode(QToolButton::InstantPopup);
626 }
627
628 void updateMenu(KTextEditor::ViewPrivate *view);
629
630private:
631 void init();
632
633 QPointer<KTextEditor::ViewPrivate> m_view;
634 QStringList names;
635 QActionGroup *m_group;
636 int last;
637
638public:
639 void slotAboutToShow();
640
641private:
642 void setSchema();
643};
644
645#endif
646

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