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 }