File indexing completed on 2024-04-28 15:31:06

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