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

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2002 John Firebaugh <jfirebaugh@kde.org>
0004     SPDX-FileCopyrightText: 2001 Anders Lund <anders@alweb.dk>
0005     SPDX-FileCopyrightText: 2001 Christoph Cullmann <cullmann@kde.org>
0006     SPDX-FileCopyrightText: 2017-2018 Friedrich W. H. Kossebau <kossebau@kde.org>
0007 
0008     SPDX-License-Identifier: LGPL-2.0-only
0009 */
0010 
0011 #ifndef KATE_VIEW_HELPERS_H
0012 #define KATE_VIEW_HELPERS_H
0013 
0014 #include <KActionMenu>
0015 #include <KLineEdit>
0016 #include <KSelectAction>
0017 
0018 #include <QColor>
0019 #include <QHash>
0020 #include <QLayout>
0021 #include <QPixmap>
0022 #include <QPointer>
0023 #include <QScrollBar>
0024 #include <QTimer>
0025 
0026 #include "katetextline.h"
0027 #include <ktexteditor/cursor.h>
0028 #include <ktexteditor/message.h>
0029 
0030 namespace KTextEditor
0031 {
0032 class ViewPrivate;
0033 class DocumentPrivate;
0034 class Command;
0035 class AnnotationModel;
0036 class MovingRange;
0037 class AbstractAnnotationItemDelegate;
0038 class StyleOptionAnnotationItem;
0039 }
0040 
0041 class KateViewInternal;
0042 class KateTextLayout;
0043 
0044 #define MAXFOLDINGCOLORS 16
0045 
0046 class KateLineInfo;
0047 class KateTextPreview;
0048 
0049 namespace Kate
0050 {
0051 class TextRange;
0052 }
0053 
0054 class QTimer;
0055 class QVBoxLayout;
0056 class QStackedWidget;
0057 
0058 /**
0059  * Class to layout KTextEditor::Message%s in KateView. Only the floating
0060  * positions TopInView, CenterInView, and BottomInView are supported.
0061  * AboveView and BelowView are not supported and ASSERT.
0062  */
0063 class KateMessageLayout : public QLayout
0064 {
0065 public:
0066     explicit KateMessageLayout(QWidget *parent);
0067     ~KateMessageLayout() override;
0068 
0069     void addWidget(QWidget *widget, KTextEditor::Message::MessagePosition pos);
0070     int count() const override;
0071     QLayoutItem *itemAt(int index) const override;
0072     void setGeometry(const QRect &rect) override;
0073     QSize sizeHint() const override;
0074     QLayoutItem *takeAt(int index) override;
0075 
0076     void add(QLayoutItem *item, KTextEditor::Message::MessagePosition pos);
0077 
0078 private:
0079     void addItem(QLayoutItem *item) override; // never called publically
0080 
0081     struct ItemWrapper {
0082         ItemWrapper() = default;
0083         ItemWrapper(QLayoutItem *i, KTextEditor::Message::MessagePosition pos)
0084             : item(i)
0085             , position(pos)
0086         {
0087         }
0088 
0089         QLayoutItem *item = nullptr;
0090         KTextEditor::Message::MessagePosition position = KTextEditor::Message::AboveView;
0091     };
0092 
0093     QList<ItemWrapper> m_items;
0094 };
0095 
0096 /**
0097  * This class is required because QScrollBar's sliderMoved() signal is
0098  * really supposed to be a sliderDragged() signal... so this way we can capture
0099  * MMB slider moves as well
0100  *
0101  * Also, it adds some useful indicators on the scrollbar.
0102  */
0103 class KateScrollBar : public QScrollBar
0104 {
0105     Q_OBJECT
0106 
0107 public:
0108     KateScrollBar(Qt::Orientation orientation, class KateViewInternal *parent);
0109     ~KateScrollBar() override;
0110     QSize sizeHint() const override;
0111 
0112     void showEvent(QShowEvent *event) override;
0113 
0114     inline bool showMarks() const
0115     {
0116         return m_showMarks;
0117     }
0118     inline void setShowMarks(bool b)
0119     {
0120         m_showMarks = b;
0121         update();
0122     }
0123 
0124     inline bool showMiniMap() const
0125     {
0126         return m_showMiniMap;
0127     }
0128     void setShowMiniMap(bool b);
0129 
0130     inline bool miniMapAll() const
0131     {
0132         return m_miniMapAll;
0133     }
0134     inline void setMiniMapAll(bool b)
0135     {
0136         m_miniMapAll = b;
0137         updateGeometry();
0138         update();
0139     }
0140 
0141     inline bool miniMapWidth() const
0142     {
0143         return m_miniMapWidth;
0144     }
0145     inline void setMiniMapWidth(int width)
0146     {
0147         m_miniMapWidth = width;
0148         updateGeometry();
0149         update();
0150     }
0151 
0152     inline void queuePixmapUpdate()
0153     {
0154         m_updateTimer.start();
0155     }
0156 
0157 Q_SIGNALS:
0158     void sliderMMBMoved(int value);
0159 
0160 protected:
0161     void mousePressEvent(QMouseEvent *e) override;
0162     void mouseReleaseEvent(QMouseEvent *e) override;
0163     void mouseMoveEvent(QMouseEvent *e) override;
0164     void leaveEvent(QEvent *event) override;
0165     bool eventFilter(QObject *object, QEvent *event) override;
0166     void paintEvent(QPaintEvent *e) override;
0167     void resizeEvent(QResizeEvent *) override;
0168     void sliderChange(SliderChange change) override;
0169 
0170 protected Q_SLOTS:
0171     void sliderMaybeMoved(int value);
0172     void marksChanged();
0173 
0174 public Q_SLOTS:
0175     void updatePixmap();
0176 
0177 private Q_SLOTS:
0178     void showTextPreview();
0179 
0180 private:
0181     void showTextPreviewDelayed();
0182     void hideTextPreview();
0183 
0184     void redrawMarks();
0185     void recomputeMarksPositions();
0186 
0187     void miniMapPaintEvent(QPaintEvent *e);
0188     void normalPaintEvent(QPaintEvent *e);
0189 
0190     int minimapYToStdY(int y);
0191 
0192     struct ColumnRangeWithColor {
0193         int penIndex = -1;
0194         int startColumn;
0195         int endColumn;
0196     };
0197     void getCharColorRanges(const QList<Kate::TextLine::Attribute> &attributes,
0198                             const QList<Kate::TextRange *> &decorations,
0199                             const QString &text,
0200                             QList<KateScrollBar::ColumnRangeWithColor> &ranges,
0201                             QVarLengthArray<std::pair<QRgb, QPen>, 20> &penCache);
0202 
0203     bool m_middleMouseDown;
0204     bool m_leftMouseDown;
0205 
0206     KTextEditor::ViewPrivate *m_view;
0207     KTextEditor::DocumentPrivate *m_doc;
0208     class KateViewInternal *m_viewInternal;
0209     QPointer<KateTextPreview> m_textPreview;
0210     QTimer m_delayTextPreviewTimer;
0211 
0212     QHash<int, QColor> m_lines;
0213 
0214     bool m_showMarks;
0215     bool m_showMiniMap;
0216     bool m_miniMapAll;
0217     bool m_needsUpdateOnShow;
0218     int m_miniMapWidth;
0219 
0220     QPixmap m_pixmap;
0221     int m_grooveHeight;
0222     QRect m_stdGroveRect;
0223     QRect m_mapGroveRect;
0224     QRect m_sliderRect;
0225     QTimer m_updateTimer;
0226     QPoint m_toolTipPos;
0227 
0228     // lists of lines added/removed recently to avoid scrollbar flickering
0229     QHash<int, int> m_linesAdded;
0230 
0231     static const unsigned char characterOpacity[256];
0232 };
0233 
0234 class KateIconBorder : public QWidget
0235 {
0236     Q_OBJECT
0237 
0238 public:
0239     KateIconBorder(KateViewInternal *internalView, QWidget *parent);
0240     ~KateIconBorder() override;
0241     // VERY IMPORTANT ;)
0242     QSize sizeHint() const override;
0243 
0244     void updateFont();
0245     int lineNumberWidth() const;
0246 
0247     void setIconBorderOn(bool enable);
0248     void setLineNumbersOn(bool enable);
0249     void setRelLineNumbersOn(bool enable);
0250     void setAnnotationBorderOn(bool enable);
0251     void setDynWrapIndicators(int state);
0252     int dynWrapIndicators() const
0253     {
0254         return m_dynWrapIndicators;
0255     }
0256     bool dynWrapIndicatorsOn() const
0257     {
0258         return m_dynWrapIndicatorsOn;
0259     }
0260     void setFoldingMarkersOn(bool enable);
0261     void toggleIconBorder()
0262     {
0263         setIconBorderOn(!iconBorderOn());
0264     }
0265     void toggleLineNumbers()
0266     {
0267         setLineNumbersOn(!lineNumbersOn());
0268     }
0269     void toggleFoldingMarkers()
0270     {
0271         setFoldingMarkersOn(!foldingMarkersOn());
0272     }
0273     inline bool iconBorderOn() const
0274     {
0275         return m_iconBorderOn;
0276     }
0277     inline bool lineNumbersOn() const
0278     {
0279         return m_lineNumbersOn;
0280     }
0281     inline bool viRelNumbersOn() const
0282     {
0283         return m_relLineNumbersOn;
0284     }
0285     inline bool foldingMarkersOn() const
0286     {
0287         return m_foldingMarkersOn;
0288     }
0289     inline bool annotationBorderOn() const
0290     {
0291         return m_annotationBorderOn;
0292     }
0293 
0294     void updateForCursorLineChange();
0295 
0296     enum BorderArea { None, LineNumbers, IconBorder, FoldingMarkers, AnnotationBorder, ModificationBorder };
0297     BorderArea positionToArea(const QPoint &) const;
0298 
0299     KTextEditor::AbstractAnnotationItemDelegate *annotationItemDelegate() const;
0300     void setAnnotationItemDelegate(KTextEditor::AbstractAnnotationItemDelegate *delegate);
0301     inline bool uniformAnnotationItemSizes() const
0302     {
0303         return m_hasUniformAnnotationItemSizes;
0304     }
0305     inline void setAnnotationUniformItemSizes(bool enable)
0306     {
0307         m_hasUniformAnnotationItemSizes = enable;
0308     }
0309 
0310 public Q_SLOTS:
0311     void updateAnnotationBorderWidth();
0312     void updateAnnotationLine(int line);
0313     void annotationModelChanged(KTextEditor::AnnotationModel *oldmodel, KTextEditor::AnnotationModel *newmodel);
0314     void displayRangeChanged();
0315 
0316 private:
0317     void dragEnterEvent(QDragEnterEvent *) override;
0318     void dragMoveEvent(QDragMoveEvent *event) override;
0319     void dropEvent(QDropEvent *event) override;
0320     void paintEvent(QPaintEvent *) override;
0321     void paintBorder(int x, int y, int width, int height);
0322 
0323     void mousePressEvent(QMouseEvent *) override;
0324     void mouseMoveEvent(QMouseEvent *) override;
0325     void mouseReleaseEvent(QMouseEvent *) override;
0326     void mouseDoubleClickEvent(QMouseEvent *) override;
0327     void contextMenuEvent(QContextMenuEvent *e) override;
0328     void leaveEvent(QEvent *event) override;
0329     void wheelEvent(QWheelEvent *e) override;
0330 
0331     void enterEvent(QEnterEvent *e) override;
0332 
0333     void showMarkMenu(uint line, const QPoint &pos);
0334 
0335     void hideAnnotationTooltip();
0336     void removeAnnotationHovering();
0337     void showAnnotationMenu(int line, const QPoint &pos);
0338     void calcAnnotationBorderWidth();
0339 
0340     void initStyleOption(KTextEditor::StyleOptionAnnotationItem *styleOption) const;
0341     void setStyleOptionLineData(KTextEditor::StyleOptionAnnotationItem *styleOption,
0342                                 int y,
0343                                 int realLine,
0344                                 const KTextEditor::AnnotationModel *model,
0345                                 const QString &annotationGroupIdentifier) const;
0346     QRect annotationLineRectInView(int line) const;
0347 
0348 private:
0349     KTextEditor::ViewPrivate *m_view;
0350     KTextEditor::DocumentPrivate *m_doc;
0351     KateViewInternal *m_viewInternal;
0352 
0353     bool m_iconBorderOn : 1;
0354     bool m_lineNumbersOn : 1;
0355     bool m_relLineNumbersOn : 1;
0356     bool m_updateRelLineNumbers : 1;
0357     bool m_foldingMarkersOn : 1;
0358     bool m_dynWrapIndicatorsOn : 1;
0359     bool m_annotationBorderOn : 1;
0360     bool m_updatePositionToArea : 1;
0361     bool m_mouseOver = false;
0362 
0363     typedef QPair<int, KateIconBorder::BorderArea> AreaPosition;
0364     std::vector<AreaPosition> m_positionToArea;
0365 
0366     const int m_separatorWidth = 2;
0367     const int m_modAreaWidth = 3;
0368     qreal m_maxCharWidth = 0.0;
0369     int m_lineNumberAreaWidth = 0;
0370     int m_iconAreaWidth = 0;
0371     int m_foldingAreaWidth = 0;
0372     int m_annotationAreaWidth = 0;
0373     const QChar m_dynWrapIndicatorChar = QChar(0x21AA);
0374     int m_dynWrapIndicators = 0;
0375     int m_lastClickedLine = -1;
0376 
0377     KTextEditor::AbstractAnnotationItemDelegate *m_annotationItemDelegate;
0378     bool m_hasUniformAnnotationItemSizes = false;
0379     bool m_isDefaultAnnotationItemDelegate = true;
0380 
0381     QPointer<KateTextPreview> m_foldingPreview;
0382     KTextEditor::MovingRange *m_foldingRange = nullptr;
0383     int m_currentLine = -1;
0384     QTimer m_antiFlickerTimer;
0385     void highlightFoldingDelayed(int line);
0386     void hideFolding();
0387 
0388 private Q_SLOTS:
0389     void highlightFolding();
0390     void handleDestroyedAnnotationItemDelegate();
0391     void delayedUpdateOfSizeWithRepaint();
0392 
0393 private:
0394     QString m_hoveredAnnotationGroupIdentifier;
0395 };
0396 
0397 class KateViewEncodingAction : public KSelectAction
0398 {
0399 public:
0400     KateViewEncodingAction(KTextEditor::DocumentPrivate *_doc, KTextEditor::ViewPrivate *_view, const QString &text, QObject *parent, bool saveAsMode = false);
0401 
0402     bool setCurrentCodec(const QString &codec);
0403 
0404 private:
0405     void init();
0406     void subActionTriggered(QAction *);
0407 
0408     KTextEditor::DocumentPrivate *doc;
0409     KTextEditor::ViewPrivate *view;
0410     QAction *currentSubAction;
0411     const bool m_saveAsMode;
0412 
0413 private:
0414     void setEncoding(const QString &e);
0415     void slotAboutToShow();
0416 };
0417 
0418 class KateViewBar;
0419 
0420 class KateViewBarWidget : public QWidget
0421 {
0422     Q_OBJECT
0423     friend class KateViewBar;
0424 
0425 public:
0426     explicit KateViewBarWidget(bool addCloseButton, QWidget *parent = nullptr);
0427 
0428     virtual void closed()
0429     {
0430     }
0431 
0432     /// returns the currently associated KateViewBar and 0, if it is not associated
0433     KateViewBar *viewBar()
0434     {
0435         return m_viewBar;
0436     }
0437 
0438 protected:
0439     /**
0440      * @return widget that should be used to add controls to bar widget
0441      */
0442     QWidget *centralWidget()
0443     {
0444         return m_centralWidget;
0445     }
0446 
0447     /**
0448      * @return close button, if there
0449      */
0450     QToolButton *closeButton()
0451     {
0452         return m_closeButton;
0453     }
0454 
0455 Q_SIGNALS:
0456     void hideMe();
0457 
0458     // for friend class KateViewBar
0459 private:
0460     void setAssociatedViewBar(KateViewBar *bar)
0461     {
0462         m_viewBar = bar;
0463     }
0464 
0465 private:
0466     QWidget *m_centralWidget = nullptr;
0467     KateViewBar *m_viewBar = nullptr; // 0-pointer, if not added to a view bar
0468     QToolButton *m_closeButton = nullptr;
0469 };
0470 
0471 class KateViewBar : public QWidget
0472 {
0473     Q_OBJECT
0474 
0475 public:
0476     KateViewBar(bool external, QWidget *parent, KTextEditor::ViewPrivate *view);
0477 
0478     /**
0479      * Adds a widget to this viewbar.
0480      * Widget is initially invisible, you should call showBarWidget, to show it.
0481      * Several widgets can be added to the bar, but only one can be visible
0482      */
0483     void addBarWidget(KateViewBarWidget *newBarWidget);
0484 
0485     /**
0486      * Removes a widget from this viewbar.
0487      * Removing a widget makes sense if it takes a lot of space vertically,
0488      * because we use a QStackedWidget to maintain the same height for all
0489      * widgets in the viewbar.
0490      */
0491     void removeBarWidget(KateViewBarWidget *barWidget);
0492 
0493     /**
0494      * @return if viewbar has widget @p barWidget
0495      */
0496     bool hasBarWidget(KateViewBarWidget *barWidget) const;
0497 
0498     /**
0499      * Shows barWidget that was previously added with addBarWidget.
0500      * @see hideCurrentBarWidget
0501      */
0502     void showBarWidget(KateViewBarWidget *barWidget);
0503 
0504     /**
0505      * Adds widget that will be always shown in the viewbar.
0506      * After adding permanent widget viewbar is immediately shown.
0507      * ViewBar with permanent widget won't hide itself
0508      * until permanent widget is removed.
0509      * OTOH showing/hiding regular barWidgets will work as usual
0510      * (they will be shown above permanent widget)
0511      *
0512      * If permanent widget already exists, asserts!
0513      */
0514     void addPermanentBarWidget(KateViewBarWidget *barWidget);
0515 
0516     /**
0517      * Removes permanent bar widget from viewbar.
0518      * If no other viewbar widgets are shown, viewbar gets hidden.
0519      *
0520      * barWidget is not deleted, caller must do it if it wishes
0521      */
0522     void removePermanentBarWidget(KateViewBarWidget *barWidget);
0523 
0524     /**
0525      * @return true if the a KateViewBar is visible*/
0526     bool barWidgetVisible() const;
0527 
0528 public Q_SLOTS:
0529     /**
0530      * Hides currently shown bar widget
0531      */
0532     void hideCurrentBarWidget();
0533 
0534 protected:
0535     void keyPressEvent(QKeyEvent *event) override;
0536     void hideEvent(QHideEvent *event) override;
0537 
0538 private:
0539     /**
0540      * Shows or hides whole viewbar
0541      */
0542     void setViewBarVisible(bool visible);
0543 
0544     bool m_external;
0545 
0546 private:
0547     KTextEditor::ViewPrivate *m_view;
0548     QStackedWidget *m_stack;
0549     KateViewBarWidget *m_permanentBarWidget;
0550     QVBoxLayout *m_layout;
0551 };
0552 
0553 class KateCommandLineBar : public KateViewBarWidget
0554 {
0555 public:
0556     explicit KateCommandLineBar(KTextEditor::ViewPrivate *view, QWidget *parent = nullptr);
0557     ~KateCommandLineBar() override;
0558 
0559     void setText(const QString &text, bool selected = true);
0560     void execute(const QString &text);
0561 
0562 public:
0563     static void showHelpPage();
0564 
0565 private:
0566     class KateCmdLineEdit *m_lineEdit;
0567 };
0568 
0569 class KateCmdLineEdit : public KLineEdit
0570 {
0571     Q_OBJECT
0572 
0573 public:
0574     KateCmdLineEdit(KateCommandLineBar *bar, KTextEditor::ViewPrivate *view);
0575     bool event(QEvent *e) override;
0576 
0577     void hideEvent(QHideEvent *e) override;
0578 
0579 Q_SIGNALS:
0580     void hideRequested();
0581 
0582 public Q_SLOTS:
0583     void slotReturnPressed(const QString &cmd);
0584 
0585 private Q_SLOTS:
0586     void hideLineEdit();
0587 
0588 protected:
0589     void focusInEvent(QFocusEvent *ev) override;
0590     void keyPressEvent(QKeyEvent *ev) override;
0591 
0592 private:
0593     /**
0594      * Parse an expression denoting a position in the document.
0595      * Return the position as an integer.
0596      * Examples of expressions are "10" (the 10th line),
0597      * "$" (the last line), "." (the current line),
0598      * "'a" (the mark 'a), "/foo/" (a forwards search for "foo"),
0599      * and "?bar?" (a backwards search for "bar").
0600      * @param string the expression to parse
0601      * @return the position, an integer
0602      */
0603     void fromHistory(bool up);
0604     QString helptext(const QPoint &) const;
0605 
0606     KTextEditor::ViewPrivate *m_view;
0607     KateCommandLineBar *m_bar;
0608     bool m_msgMode;
0609     QString m_oldText;
0610     uint m_histpos; ///< position in the history
0611     uint m_cmdend; ///< the point where a command ends in the text, if we have a valid one.
0612     KTextEditor::Command *m_command; ///< For completing flags/args and interactiveness
0613     class KateCmdLnWhatsThis *m_help;
0614 
0615     QTimer *m_hideTimer;
0616 };
0617 
0618 class KateViewSchemaAction : public KActionMenu
0619 {
0620 public:
0621     KateViewSchemaAction(const QString &text, QObject *parent)
0622         : KActionMenu(text, parent)
0623     {
0624         init();
0625         setPopupMode(QToolButton::InstantPopup);
0626     }
0627 
0628     void updateMenu(KTextEditor::ViewPrivate *view);
0629 
0630 private:
0631     void init();
0632 
0633     QPointer<KTextEditor::ViewPrivate> m_view;
0634     QStringList names;
0635     QActionGroup *m_group;
0636     int last;
0637 
0638 public:
0639     void slotAboutToShow();
0640 
0641 private:
0642     void setSchema();
0643 };
0644 
0645 #endif