File indexing completed on 2024-04-28 05:49:31

0001 /*
0002     SPDX-FileCopyrightText: 2005 Christoph Cullmann <cullmann@kde.org>
0003     SPDX-FileCopyrightText: 2002, 2003 Joseph Wenninger <jowenn@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #pragma once
0009 
0010 #include <KTextEditor/Plugin>
0011 
0012 #include <KParts/MainWindow>
0013 
0014 #include <KMultiTabBar>
0015 #include <KToggleAction>
0016 #include <KXMLGUIClient>
0017 
0018 #include <QChildEvent>
0019 #include <QEvent>
0020 #include <QFrame>
0021 #include <QPointer>
0022 #include <QSplitter>
0023 
0024 #include <map>
0025 #include <unordered_map>
0026 #include <vector>
0027 
0028 class KActionMenu;
0029 class QAction;
0030 class QLabel;
0031 class QPixmap;
0032 class QStackedWidget;
0033 class KConfigBase;
0034 class QHBoxLayout;
0035 class QRubberBand;
0036 
0037 namespace KTextEditor
0038 {
0039 class ConfigPageInterface;
0040 }
0041 
0042 namespace KateMDI
0043 {
0044 class ToolView;
0045 
0046 class ToggleToolViewAction : public KToggleAction
0047 {
0048     Q_OBJECT
0049 
0050 public:
0051     ToggleToolViewAction(const QString &text, ToolView *tv, QObject *parent);
0052 
0053 protected Q_SLOTS:
0054     void slotToggled(bool) override;
0055     void toolVisibleChanged(bool);
0056 
0057 private:
0058     ToolView *m_tv;
0059 };
0060 
0061 class GUIClient : public QObject, public KXMLGUIClient
0062 {
0063     Q_OBJECT
0064 
0065 public:
0066     explicit GUIClient(class MainWindow *mw);
0067 
0068     void registerToolView(ToolView *tv);
0069     void unregisterToolView(ToolView *tv);
0070     void updateSidebarsVisibleAction();
0071 
0072 private Q_SLOTS:
0073     void clientAdded(KXMLGUIClient *client);
0074     void updateActions();
0075 
0076 private:
0077     MainWindow *m_mw;
0078     KToggleAction *m_showSidebarsAction;
0079     std::unordered_map<ToolView *, std::vector<QAction *>> m_toolToActions;
0080     KActionMenu *m_toolMenu;
0081     QAction *m_hideToolViews;
0082     KActionMenu *m_sidebarButtonsMenu;
0083     KActionMenu *m_focusToolviewMenu;
0084 };
0085 
0086 class ToolView : public QFrame
0087 {
0088     Q_OBJECT
0089 
0090     friend class Sidebar;
0091     friend class MultiTabBar;
0092     friend class MainWindow;
0093     friend class GUIClient;
0094     friend class ToggleToolViewAction;
0095 
0096 protected:
0097     /**
0098      * ToolView
0099      * Objects of this clas represent a toolview in the mainwindow
0100      * you should only add one widget as child to this toolview, it will
0101      * be automatically set to be the focus proxy of the toolview
0102      * @param mainwin main window for this toolview
0103      * @param sidebar sidebar of this toolview
0104      * @param parent parent widget, e.g. the splitter of one of the sidebars
0105      * @param identifier unique id
0106      */
0107     ToolView(class MainWindow *mainwin, class Sidebar *sidebar, QWidget *parent, const QString &identifier);
0108 
0109 public:
0110     /**
0111      * destruct me, this is allowed for all, will care itself that the toolview is removed
0112      * from the mainwindow and sidebar
0113      */
0114     ~ToolView() override;
0115 
0116 Q_SIGNALS:
0117     /**
0118      * toolview hidden or shown
0119      * @param visible is this toolview made visible?
0120      */
0121     void toolVisibleChanged(bool visible);
0122 
0123     void tabButtonVisibleChanged(bool visible);
0124 
0125     /**
0126      * some internal methodes needed by the main window and the sidebars
0127      */
0128 protected:
0129     MainWindow *mainWindow()
0130     {
0131         return m_mainWin;
0132     }
0133 
0134     Sidebar *sidebar()
0135     {
0136         return m_sidebar;
0137     }
0138 
0139     void setToolVisible(bool vis);
0140 
0141 public:
0142     bool toolVisible() const;
0143     QSize sizeHint() const override;
0144     QSize minimumSizeHint() const override;
0145 
0146     /**
0147      * Whether the tab button for this toolview is visible
0148      * in the sidebar or hidden
0149      */
0150     bool tabButtonVisible() const;
0151     void setTabButtonVisible(bool visible);
0152 
0153 protected:
0154     void childEvent(QChildEvent *ev) override;
0155     void actionEvent(QActionEvent *event) override;
0156 
0157 private:
0158     MainWindow *m_mainWin;
0159     Sidebar *m_sidebar;
0160     KToolBar *m_toolbar;
0161 
0162     /// plugin this view belongs to, may be 0
0163     QPointer<KTextEditor::Plugin> plugin;
0164 
0165     /**
0166      * unique id
0167      */
0168     const QString id;
0169 
0170     /**
0171      * is visible in sidebar
0172      */
0173     bool m_toolVisible;
0174 
0175     /**
0176      * Is the button visible in sidebar
0177      */
0178     bool isTabButtonVisible = true;
0179 
0180     QIcon icon;
0181     QString text;
0182 };
0183 
0184 class MultiTabBar : public QWidget
0185 {
0186     Q_OBJECT
0187 
0188 public:
0189     MultiTabBar(KMultiTabBar::KMultiTabBarPosition pos, Sidebar *sb, int idx);
0190     ~MultiTabBar();
0191 
0192     KMultiTabBarTab *addTab(int id, ToolView *tv);
0193     int addBlankTab();
0194     void removeBlankTab(int id);
0195     void removeTab(int id);
0196     void reorderTab(int id, KMultiTabBarTab *before);
0197 
0198     void showToolView(int id);
0199     void hideToolView(int id);
0200 
0201     void setTabActive(int id, bool state);
0202 
0203     bool isToolActive() const;
0204     void collapseToolView() const;
0205     bool expandToolView() const;
0206 
0207     KMultiTabBar *tabBar() const
0208     {
0209         return m_multiTabBar;
0210     }
0211 
0212     const std::vector<int> &tabList() const
0213     {
0214         return m_tabList;
0215     }
0216 
0217     int tabCount() const
0218     {
0219         return m_tabList.size();
0220     }
0221 
0222     int sectionSize() const
0223     {
0224         return m_sectionSize;
0225     }
0226 
0227     void setSectionSize(int size)
0228     {
0229         m_sectionSize = size;
0230     }
0231 
0232 Q_SIGNALS:
0233     void lastTabRemoved(MultiTabBar *);
0234 
0235 private Q_SLOTS:
0236     void tabClicked(int);
0237 
0238 private:
0239     Sidebar *m_sb;
0240     QStackedWidget *m_stack;
0241     KMultiTabBar *m_multiTabBar;
0242     std::vector<int> m_tabList;
0243     int m_activeTab = 0;
0244     int m_sectionSize = 0;
0245 };
0246 
0247 class Sidebar : public QSplitter
0248 {
0249     Q_OBJECT
0250 
0251     friend class MultiTabBar;
0252 
0253 public:
0254     Sidebar(KMultiTabBar::KMultiTabBarPosition pos, QSplitter *sp, class MainWindow *mainwin, QWidget *parent);
0255 
0256     QSize sizeHint() const override;
0257     QSize minimumSizeHint() const override;
0258 
0259     ToolView *addToolView(const QIcon &icon, const QString &text, const QString &identifier, ToolView *widget);
0260     bool removeToolView(ToolView *widget);
0261 
0262     bool showToolView(ToolView *widget);
0263     bool hideToolView(ToolView *widget);
0264 
0265     void showToolviewTab(ToolView *widget, bool show);
0266 
0267     bool isCollapsed();
0268 
0269     QWidget *tabButtonForToolview(ToolView *widget) const
0270     {
0271         auto it = m_widgetToId.find(widget);
0272         if (it == m_widgetToId.end()) {
0273             return nullptr;
0274         }
0275         if (auto tabbar = kmTabBar(widget)) {
0276             return tabbar->tab(it->second);
0277         }
0278         return nullptr;
0279     }
0280 
0281     int toolviewCount() const
0282     {
0283         return m_idToWidget.size();
0284     }
0285 
0286     /**
0287      * Will the sidebar expand when some tool has to be visible in any section,
0288      * or calling collapseSidebar() if non such tool is found
0289      */
0290     void updateSidebar();
0291     void collapseSidebar();
0292 
0293     KMultiTabBar::KMultiTabBarPosition position() const
0294     {
0295         return m_tabBarPosition;
0296     }
0297 
0298     bool isVertical() const
0299     {
0300         return m_tabBarPosition == KMultiTabBar::Right || m_tabBarPosition == KMultiTabBar::Left;
0301     }
0302 
0303     void setStyle(KMultiTabBar::KMultiTabBarStyle style);
0304 
0305     KMultiTabBar::KMultiTabBarStyle tabStyle() const
0306     {
0307         return m_tabBarStyle;
0308     }
0309 
0310     void startRestoreSession(KConfigGroup &config);
0311 
0312     /**
0313      * restore the current session config from given object, use current group
0314      * @param config config object to use
0315      */
0316     void restoreSession(KConfigGroup &config);
0317 
0318     /**
0319      * save the current session config to given object, use current group
0320      * @param config config object to use
0321      */
0322     void saveSession(KConfigGroup &config);
0323 
0324 public Q_SLOTS:
0325     // reimplemented, to block a show() call if all sidebars are forced hidden
0326     void setVisible(bool visible) override;
0327 
0328 protected:
0329     bool eventFilter(QObject *obj, QEvent *ev) override;
0330     void dragEnterEvent(QDragEnterEvent *) override;
0331     void dragLeaveEvent(QDragLeaveEvent *) override;
0332     void dragMoveEvent(QDragMoveEvent *) override;
0333     void dropEvent(QDropEvent *) override;
0334 
0335 private Q_SLOTS:
0336     void buttonPopupActivate(QAction *);
0337     void readConfig();
0338     void handleCollapse(int pos, int index);
0339     void ownSplitMoved(int pos, int index);
0340     void barSplitMoved(int pos, int index);
0341     bool tabBarIsEmpty(MultiTabBar *bar);
0342 
0343 private:
0344     void updateLastSize();
0345     int nextId();
0346     bool adjustSplitterSections();
0347 
0348     /**
0349      * Append a tab with our styling & needed connections/event filter.
0350      */
0351     void appendStyledTab(int id, MultiTabBar *bar, ToolView *widget);
0352 
0353     /**
0354      * Update style of button to our style.
0355      */
0356     void updateButtonStyle(KMultiTabBarTab *button);
0357 
0358     /**
0359      * Monitor resizes using the mouse and update the last size accordingly.
0360      */
0361     void updateLastSizeOnResize();
0362 
0363     MultiTabBar *insertTabBar(int idx = -1);
0364 
0365     MultiTabBar *tabBar(int idx) const
0366     {
0367         return static_cast<MultiTabBar *>(widget(idx));
0368     }
0369 
0370     MultiTabBar *tabBar(ToolView *tv) const
0371     {
0372         return m_widgetToTabBar.at(tv);
0373     }
0374 
0375     KMultiTabBar *kmTabBar(ToolView *widget) const
0376     {
0377         return m_widgetToTabBar.at(widget)->tabBar();
0378     }
0379 
0380     int tabBarCount() const
0381     {
0382         return count();
0383     }
0384 
0385 private:
0386     enum ActionIds {
0387         HideButtonAction = 11,
0388         ConfigureAction = 20,
0389         ToOwnSectAction = 30,
0390         UpLeftAction = 31,
0391         DownRightAction = 32,
0392     };
0393 
0394     MainWindow *m_mainWin;
0395 
0396     KMultiTabBar::KMultiTabBarPosition m_tabBarPosition{};
0397     KMultiTabBar::KMultiTabBarStyle m_tabBarStyle{};
0398     QSplitter *m_splitter;
0399     QSplitter *m_ownSplit;
0400     const int m_ownSplitIndex;
0401 
0402     std::map<int, ToolView *> m_idToWidget;
0403     std::map<ToolView *, int> m_widgetToId;
0404     std::map<ToolView *, MultiTabBar *> m_widgetToTabBar;
0405 
0406     // Session restore only
0407     std::map<QString, int> m_tvIdToTabId;
0408     std::map<QString, int> m_tvIdToTabBar;
0409     bool m_sessionRestoreRunning = false;
0410 
0411     int m_lastSize;
0412     int m_popupButton = 0;
0413     QPointer<QLabel> m_resizePlaceholder;
0414     bool m_isPreviouslyCollapsed = false;
0415     bool m_syncWithTabs = false;
0416     bool m_showTextForLeftRight = false;
0417     int m_leftRightSidebarIconSize = 32;
0418     QPoint dragStartPos;
0419     QRubberBand *m_dropIndicator;
0420     QRubberBand *m_internalDropIndicator;
0421 
0422 Q_SIGNALS:
0423     void sigShowPluginConfigPage(KTextEditor::Plugin *configpageinterface, int id);
0424     void dragStarted();
0425     void dragEnded();
0426 };
0427 
0428 class MainWindow : public KParts::MainWindow
0429 {
0430     Q_OBJECT
0431 
0432     friend class ToolView;
0433 
0434     //
0435     // Constructor area
0436     //
0437 public:
0438     /**
0439      * Constructor
0440      */
0441     explicit MainWindow(QWidget *parent = nullptr);
0442 
0443     /**
0444      * Destructor
0445      */
0446     ~MainWindow() override;
0447 
0448     //
0449     // public interfaces
0450     //
0451 
0452     /**
0453      * add a given widget to the given sidebar if possible, name is very important
0454      * @param plugin pointer to the plugin
0455      * @param identifier unique identifier for this toolview
0456      * @param pos position for the toolview, if we are in session restore, this is only a preference
0457      * @param icon icon to use for the toolview
0458      * @param text text to use in addition to icon
0459      * @return created toolview on success or 0
0460      */
0461     ToolView *
0462     createToolView(KTextEditor::Plugin *plugin, const QString &identifier, KMultiTabBar::KMultiTabBarPosition pos, const QIcon &icon, const QString &text);
0463 
0464     /**
0465      * give you handle to toolview for the given name, 0 if no toolview around
0466      * @param identifier toolview name
0467      * @return toolview if existing, else 0
0468      */
0469     ToolView *toolView(const QString &identifier) const;
0470 
0471     /**
0472      * get the sidebars' visibility.
0473      * @return false, if the sidebars' visibility is forced hidden, otherwise true
0474      */
0475     bool sidebarsVisible() const;
0476 
0477     /**
0478      * set the sidebars' visibility to @p visible. If false, the sidebars
0479      * are @e always hidden. Usually you do not have to call this because
0480      * the user can set this in the menu.
0481      * @param visible sidebars visibility
0482      * @param hideFullySilent hide the stuff forever, e.g. for KWrite
0483      */
0484     void setSidebarsVisibleInternal(bool visible, bool hideFullySilent);
0485 
0486 public Q_SLOTS:
0487     /**
0488      * set the sidebars' visibility to @p visible. If false, the sidebars
0489      * are @e always hidden. Usually you do not have to call this because
0490      * the user can set this in the menu.
0491      * @param visible sidebars visibility
0492      */
0493     void setSidebarsVisible(bool visible)
0494     {
0495         setSidebarsVisibleInternal(visible, false);
0496     }
0497 
0498     /**
0499      * hide all tool views
0500      */
0501     void hideToolViews();
0502 
0503 protected:
0504     /**
0505      * called by toolview destructor
0506      * @param widget toolview which is destroyed
0507      */
0508     void toolViewDeleted(ToolView *widget);
0509 
0510     /**
0511      * set the toolview's tabbar style.
0512      * @param style the tabbar style.
0513      */
0514     void setToolViewStyle(KMultiTabBar::KMultiTabBarStyle style);
0515 
0516     /**
0517      * get the toolview's tabbar style. Call this before @p startRestore(),
0518      * otherwise you overwrite the usersettings.
0519      * @return toolview's tabbar style
0520      */
0521     KMultiTabBar::KMultiTabBarStyle toolViewStyle() const;
0522 
0523 public:
0524     /**
0525      * central widget ;)
0526      * use this as parent for your content
0527      * @return central widget
0528      */
0529     QWidget *centralWidget() const;
0530 
0531     /**
0532      * Called if focus should go to the important part of the central widget.
0533      * Default doesn't do a thing, if we are called in destructor by accident.
0534      */
0535     virtual void triggerFocusForCentralWidget()
0536     {
0537     }
0538 
0539 protected:
0540     /**
0541      * Status bar area stacked widget.
0542      * We plug in our status bars from the KTextEditor::Views here
0543      */
0544     QStackedWidget *statusBarStackedWidget() const
0545     {
0546         return m_statusBarStackedWidget;
0547     }
0548 
0549     void insertWidgetBeforeStatusbar(QWidget *widget);
0550 
0551     // ensure we don't have toolbar accelerators that clash with other stuff
0552     QWidget *createContainer(QWidget *parent, int index, const QDomElement &element, QAction *&containerAction) override;
0553 
0554     /**
0555      * modifiers for existing toolviews
0556      */
0557 public:
0558     /**
0559      * move a toolview around
0560      * @param widget toolview to move
0561      * @param pos position to move too, during session restore, only preference
0562      * @return success
0563      */
0564     bool moveToolView(ToolView *widget, KMultiTabBar::KMultiTabBarPosition pos, bool isDND = false);
0565 
0566     /**
0567      * show given toolview, discarded while session restore
0568      * @param widget toolview to show
0569      * @return success
0570      */
0571     bool showToolView(ToolView *widget);
0572 
0573     /**
0574      * hide given toolview, discarded while session restore
0575      * @param widget toolview to hide
0576      * @return success
0577      */
0578     bool hideToolView(ToolView *widget);
0579 
0580     /**
0581      * session saving and restore stuff
0582      */
0583 public:
0584     /**
0585      * start the restore
0586      * @param config config object to use
0587      * @param group config group to use
0588      */
0589     void startRestore(KConfigBase *config, const QString &group);
0590 
0591     /**
0592      * finish the restore
0593      */
0594     void finishRestore();
0595 
0596     /**
0597      * save the current session config to given object and group
0598      * @param group config group to use
0599      */
0600     void saveSession(KConfigGroup &group);
0601 
0602     /**
0603      * internal data ;)
0604      */
0605 private:
0606     /**
0607      * all existing tool views
0608      * mapped by their constant identifier, to have some stable order
0609      * tool views de-register them self on destruction
0610      */
0611     std::map<QString, ToolView *> m_toolviews;
0612 
0613     /**
0614      * widget, which is the central part of the
0615      * main window ;)
0616      */
0617     QWidget *m_centralWidget;
0618 
0619     /**
0620      * horizontal splitter
0621      */
0622     QSplitter *m_hSplitter;
0623 
0624     /**
0625      * vertical splitter
0626      */
0627     QSplitter *m_vSplitter;
0628 
0629     /**
0630      * sidebars for the four sides
0631      */
0632     std::unique_ptr<Sidebar> m_sidebars[4];
0633 
0634     /**
0635      * sidebars state.
0636      */
0637     bool m_sidebarsVisible = true;
0638 
0639     /**
0640      * config object for session restore, only valid between
0641      * start and finish restore calls
0642      */
0643     KConfigBase *m_restoreConfig = nullptr;
0644 
0645     /**
0646      * restore group
0647      */
0648     QString m_restoreGroup;
0649 
0650     /**
0651      * out guiclient
0652      */
0653     GUIClient *m_guiClient;
0654 
0655     /**
0656      * stacked widget for status bars
0657      */
0658     QStackedWidget *m_statusBarStackedWidget;
0659 
0660     QHBoxLayout *m_bottomSidebarLayout = nullptr;
0661 
0662     struct DragState {
0663         bool m_wasVisible[4] = {};
0664     } m_dragState;
0665 
0666 Q_SIGNALS:
0667     void sigShowPluginConfigPage(KTextEditor::Plugin *configpageinterface, int id);
0668     void tabForToolViewAdded(QWidget *toolView, QWidget *tab);
0669 };
0670 
0671 }