File indexing completed on 2024-04-28 05:49:35
0001 /* This file is part of the KDE project 0002 SPDX-FileCopyrightText: 2001 Christoph Cullmann <cullmann@kde.org> 0003 SPDX-FileCopyrightText: 2001 Joseph Wenninger <jowenn@kde.org> 0004 SPDX-FileCopyrightText: 2001 Anders Lund <anders.lund@lund.tdcadsl.dk> 0005 0006 SPDX-License-Identifier: LGPL-2.0-only 0007 */ 0008 0009 #pragma once 0010 0011 #include "doc_or_widget.h" 0012 #include "katedocmanager.h" 0013 #include "kateprivate_export.h" 0014 #include "katesplitter.h" 0015 #include "kateviewspace.h" 0016 0017 #include <QList> 0018 #include <QPointer> 0019 #include <QScrollBar> 0020 0021 #include <unordered_map> 0022 0023 namespace KTextEditor 0024 { 0025 class View; 0026 class Document; 0027 } 0028 0029 class KateDocumentInfo; 0030 0031 class KConfigGroup; 0032 class KConfigBase; 0033 class KateMainWindow; 0034 class KateViewSpace; 0035 0036 class KATE_PRIVATE_EXPORT KateViewManager : public KateSplitter 0037 { 0038 Q_OBJECT 0039 0040 friend class KateViewManagementTests; 0041 0042 public: 0043 KateViewManager(QWidget *parentW, KateMainWindow *parent); 0044 ~KateViewManager() override; 0045 0046 /** 0047 * triggered delayed focus set to current active view 0048 */ 0049 void triggerActiveViewFocus(); 0050 0051 private: 0052 /** 0053 * create all actions needed for the view manager 0054 */ 0055 void setupActions(); 0056 0057 void updateViewSpaceActions(); 0058 0059 public: 0060 /* This will save the splitter configuration */ 0061 void saveViewConfiguration(KConfigGroup &group); 0062 0063 /* restore it */ 0064 void restoreViewConfiguration(const KConfigGroup &group); 0065 0066 KTextEditor::Document *openUrl(const QUrl &url, 0067 const QString &encoding, 0068 bool activate = true, 0069 bool ignoreForRecentFiles = false, 0070 const KateDocumentInfo &docInfo = KateDocumentInfo()); 0071 0072 KTextEditor::Document *openUrls(const QList<QUrl> &url, const QString &encoding, const KateDocumentInfo &docInfo = KateDocumentInfo()); 0073 0074 KTextEditor::View *openUrlWithView(const QUrl &url, const QString &encoding); 0075 0076 KTextEditor::View *openViewForDoc(KTextEditor::Document *doc); 0077 0078 public Q_SLOTS: 0079 void openUrl(const QUrl &url); 0080 void openUrlOrProject(const QUrl &url); 0081 void addPositionToHistory(const QUrl &url, KTextEditor::Cursor pos); 0082 0083 public: 0084 void closeView(KTextEditor::View *view); 0085 KateMainWindow *mainWindow(); 0086 0087 void moveViewToViewSpace(KateViewSpace *dest, KateViewSpace *src, DocOrWidget doc); 0088 0089 private Q_SLOTS: 0090 void activateView(KTextEditor::View *view); 0091 void activateSpace(KTextEditor::View *v); 0092 0093 public Q_SLOTS: 0094 void slotDocumentNew(); 0095 void slotDocumentOpen(); 0096 void slotDocumentClose(); 0097 void slotDocumentClose(KTextEditor::Document *document); 0098 0099 void setActiveSpace(KateViewSpace *vs); 0100 0101 void activateNextView(); 0102 void activatePrevView(); 0103 void activateLeftView(); 0104 void activateRightView(); 0105 void activateUpwardView(); 0106 void activateDownwardView(); 0107 0108 private: 0109 void activateIntuitiveNeighborView(Qt::Orientation o, int dir); 0110 KateViewSpace *findIntuitiveNeighborView(KateSplitter *splitter, QWidget *widget, Qt::Orientation o, int dir); 0111 0112 Q_SIGNALS: 0113 void viewChanged(KTextEditor::View *); 0114 void viewCreated(KTextEditor::View *); 0115 0116 void historyBackEnabled(bool e); 0117 void historyForwardEnabled(bool e); 0118 0119 void showUrlNavBarChanged(bool); 0120 0121 public: 0122 /** 0123 * create and activate a new view for doc, if doc == 0, then 0124 * create a new document. 0125 * Can return NULL. 0126 */ 0127 KTextEditor::View *createView(KTextEditor::Document *doc = nullptr, KateViewSpace *vs = nullptr); 0128 0129 bool deleteView(KTextEditor::View *view); 0130 0131 private: 0132 void moveViewtoSplit(KTextEditor::View *view); 0133 void moveViewtoStack(KTextEditor::View *view); 0134 0135 /* Save the configuration of a single splitter. 0136 * If child splitters are found, it calls it self with those as the argument. 0137 * If a viewspace child is found, it is asked to save its filelist. 0138 */ 0139 QString saveSplitterConfig(KateSplitter *s, KConfigBase *config, const QString &viewConfGrp); 0140 0141 /** Restore a single splitter. 0142 * This is all the work is done for @see saveSplitterConfig() 0143 */ 0144 void restoreSplitter(const KConfigBase *config, const QString &group, KateSplitter *parent, const QString &viewConfGrp); 0145 0146 void removeViewSpace(KateViewSpace *viewspace); 0147 0148 public: 0149 KTextEditor::View *activeView(); 0150 KateViewSpace *activeViewSpace(); 0151 0152 /// Returns all non-KTE::View widgets in this viewManager 0153 QWidgetList widgets() const; 0154 bool removeWidget(QWidget *w); 0155 bool activateWidget(QWidget *w); 0156 0157 private Q_SLOTS: 0158 void slotViewChanged(); 0159 0160 void documentWillBeDeleted(KTextEditor::Document *doc); 0161 0162 void documentSavedOrUploaded(KTextEditor::Document *document, bool saveAs); 0163 0164 /** 0165 * This signal is emitted before the documents batch is going to be deleted 0166 * 0167 * note that the batch can be interrupted in the middle and only some 0168 * of the documents may be actually deleted. See documentsDeleted() signal. 0169 * 0170 * @param documents documents we want to delete, may not be deleted 0171 */ 0172 void aboutToDeleteDocuments(const QList<KTextEditor::Document *> &documents); 0173 0174 /** 0175 * This signal is emitted after the documents batch was deleted 0176 * 0177 * This is the batch closing signal for aboutToDeleteDocuments 0178 * @param documents the documents that weren't deleted after all 0179 */ 0180 void documentsDeleted(const QList<KTextEditor::Document *> &documents); 0181 0182 /** 0183 * Read and apply the config for this view manager. 0184 */ 0185 void readConfig(); 0186 0187 /** 0188 * Scroll all synched views according to the delta scroll of the given view 0189 * @param view Other synchronised views will be scrolled according to this 0190 */ 0191 void slotScrollSynchedViews(KTextEditor::View *view); 0192 0193 public Q_SLOTS: 0194 /** 0195 * Splits a KateViewSpace into two in the following steps: 0196 * 1. create a KateSplitter in the parent of the KateViewSpace to be split 0197 * 2. move the to-be-split KateViewSpace to the new splitter 0198 * 3. create new KateViewSpace and added to the new splitter 0199 * 4. create KateView to populate the new viewspace. 0200 * 5. The new KateView is made the active one, because createView() does that. 0201 * If no viewspace is provided, the result of activeViewSpace() is used. 0202 * The orientation of the new splitter is determined by the value of o. 0203 * Note: horizontal splitter means vertically aligned views. 0204 */ 0205 void splitViewSpace(KateViewSpace *vs = nullptr, Qt::Orientation o = Qt::Horizontal, bool moveDocument = false); 0206 0207 /** 0208 * Set the synchronisation of scrolling of multiple views according to user input 0209 */ 0210 void slotSynchroniseScrolling(bool checked); 0211 0212 /** 0213 * Sets the currentView as the scroll-synched view 0214 * and removes synchronisation for the previous view in the same viewSpace 0215 * @param synched scroll for the activeViewSpace() will be set to scrollbar found in this view 0216 */ 0217 void slotChangeSynchedView(KTextEditor::View *currentView); 0218 0219 /** 0220 * Close the view space that contains the given view. If no view was 0221 * given, then the active view space will be closed instead. 0222 */ 0223 void closeViewSpace(KTextEditor::View *view = nullptr); 0224 0225 /** 0226 * @returns true of the two given views share the same view space. 0227 */ 0228 bool viewsInSameViewSpace(KTextEditor::View *view1, KTextEditor::View *view2); 0229 0230 /** 0231 * activate view for given document 0232 * @param doc document to activate view for 0233 * @param vs the target viewspace in which the doc should be activated. If it is 0234 * null, activeViewSpace will be used instead 0235 */ 0236 KTextEditor::View *activateView(DocOrWidget docOrWidget, KateViewSpace *vs = nullptr); 0237 0238 /** Splits the active viewspace horizontally */ 0239 void slotSplitViewSpaceHoriz() 0240 { 0241 splitViewSpace(nullptr, Qt::Vertical); 0242 } 0243 0244 /** Splits the active viewspace vertically */ 0245 void slotSplitViewSpaceVert() 0246 { 0247 splitViewSpace(); 0248 } 0249 0250 /** Splits the active viewspace horizontally and moves the active document to the viewspace below */ 0251 void slotSplitViewSpaceHorizMoveDoc() 0252 { 0253 splitViewSpace(nullptr, Qt::Vertical, true); 0254 } 0255 0256 /** Splits the active viewspace vertically and moves the active document to the right viewspace */ 0257 void slotSplitViewSpaceVertMoveDoc() 0258 { 0259 splitViewSpace(nullptr, Qt::Horizontal, true); 0260 } 0261 0262 /** moves the splitter according to the key that has been pressed */ 0263 void moveSplitter(Qt::Key key, int repeats = 1); 0264 0265 /** moves the splitter to the right */ 0266 void moveSplitterRight() 0267 { 0268 moveSplitter(Qt::Key_Right); 0269 } 0270 0271 /** moves the splitter to the left */ 0272 void moveSplitterLeft() 0273 { 0274 moveSplitter(Qt::Key_Left); 0275 } 0276 0277 /** moves the splitter up */ 0278 void moveSplitterUp() 0279 { 0280 moveSplitter(Qt::Key_Up); 0281 } 0282 0283 /** moves the splitter down */ 0284 void moveSplitterDown() 0285 { 0286 moveSplitter(Qt::Key_Down); 0287 } 0288 0289 /** closes the current view space. */ 0290 void slotCloseCurrentViewSpace() 0291 { 0292 closeViewSpace(); 0293 } 0294 0295 /** closes every view but the active one */ 0296 void slotCloseOtherViews(); 0297 0298 /** hide every view but the active one */ 0299 void slotHideOtherViews(bool hideOthers); 0300 0301 void replugActiveView(); 0302 0303 /** 0304 * Toogle the orientation of current split view 0305 */ 0306 void toggleSplitterOrientation(); 0307 0308 /** 0309 * Get a list of all views. 0310 * @return all views sorted by their last use, most recently used first 0311 */ 0312 QList<KTextEditor::View *> views() const 0313 { 0314 std::vector<std::pair<KTextEditor::View *, qint64>> sorted; 0315 0316 // extract into a list 0317 std::transform(m_views.begin(), m_views.end(), std::back_inserter(sorted), [](const std::pair<KTextEditor::View *, ViewData> &p) { 0318 return std::pair<KTextEditor::View *, qint64>{p.first, p.second.lruAge}; 0319 }); 0320 // sort the views based on lru 0321 std::sort(sorted.begin(), sorted.end(), [](const std::pair<KTextEditor::View *, qint64> &l, const std::pair<KTextEditor::View *, qint64> &r) { 0322 return l.second < r.second; 0323 }); 0324 0325 // extract the views only and return 0326 QList<KTextEditor::View *> ret; 0327 ret.reserve(sorted.size()); 0328 std::transform(sorted.begin(), sorted.end(), std::back_inserter(ret), [](const std::pair<KTextEditor::View *, qint64> &p) { 0329 return p.first; 0330 }); 0331 return ret; 0332 } 0333 0334 void onViewSpaceEmptied(KateViewSpace *vs); 0335 0336 // Returns the number of viewspaces this document is registered in 0337 int viewspaceCountForDoc(KTextEditor::Document *doc) const; 0338 // returns true if @p doc exists only in one viewspace 0339 bool docOnlyInOneViewspace(KTextEditor::Document *doc) const; 0340 // returns true if any viewspace in this viewmanager has its tabbar visible 0341 bool tabsVisible() const; 0342 0343 void setShowUrlNavBar(bool show); 0344 bool showUrlNavBar() const; 0345 0346 void hideWelcomeView(KateViewSpace *vs); 0347 void showWelcomeViewOrNewDocumentIfNeeded(); 0348 void showWelcomeView(); 0349 0350 private: 0351 KateMainWindow *m_mainWindow; 0352 0353 QAction *m_splitViewVert = nullptr; 0354 QAction *m_splitViewHoriz = nullptr; 0355 QAction *m_splitViewVertMove = nullptr; 0356 QAction *m_splitViewHorizMove = nullptr; 0357 QAction *m_closeView = nullptr; 0358 QAction *m_closeOtherViews = nullptr; 0359 QAction *m_toggleSplitterOrientation = nullptr; 0360 QAction *m_hideOtherViews = nullptr; 0361 QAction *goNext = nullptr; 0362 QAction *goPrev = nullptr; 0363 QAction *goLeft = nullptr; 0364 QAction *goRight = nullptr; 0365 QAction *goUp = nullptr; 0366 QAction *goDown = nullptr; 0367 0368 std::vector<KateViewSpace *> m_viewSpaceList; 0369 0370 bool m_blockViewCreationAndActivation; 0371 0372 bool m_showUrlNavBar = false; 0373 0374 int m_splitterIndex = 0; // used during saving splitter config. 0375 0376 /** 0377 * View meta data 0378 */ 0379 class ViewData 0380 { 0381 public: 0382 /** 0383 * lru age of the view 0384 * important: smallest age ==> latest used view 0385 */ 0386 qint64 lruAge = 0; 0387 }; 0388 0389 /** 0390 * central storage of all views known in the view manager 0391 * maps the view to meta data 0392 */ 0393 std::unordered_map<KTextEditor::View *, ViewData> m_views; 0394 0395 struct ScrollSynchronisation { 0396 /** 0397 * stores a reference scroll value according to which, 0398 * all others will be set 0399 */ 0400 int referenceScrollValue = 0; 0401 /** 0402 * Keeps track of all viewspace having a scroll-synched view 0403 * to help with finding the required view when user changes the tab 0404 */ 0405 QHash<KateViewSpace *, KTextEditor::View *> synchedViewSpaces; 0406 0407 /** 0408 * @struct ScrollBarInfo 0409 * @param scrollBar stores the pointer to the vertical scroll bar of the view 0410 * @param initScrollValue stores the offset position of the scroll bar to the reference scroll value using which the sync will occur 0411 */ 0412 struct ScrollBarInfo { 0413 QScrollBar *scrollBar; 0414 int initScrollValue; 0415 }; 0416 0417 /** 0418 * stores the information required for synchronisation of scrolling between multiple split views 0419 * Key - KTextEditor::View* stores the pointer to the corresp view 0420 * Value - ScrollBarInfo stores relevant information regarding the scrollbar of the synched view 0421 */ 0422 QHash<KTextEditor::View *, ScrollBarInfo> viewScrollInfo; 0423 0424 ScrollBarInfo getViewScrollBarInfo(KTextEditor::View *view) 0425 { 0426 const QList<QScrollBar *> scrollBars = view->findChildren<QScrollBar *>(); 0427 // Cannot use std::find_if because QList<>::last() is inclusive 0428 ScrollSynchronisation::ScrollBarInfo scrollBarInfo; 0429 scrollBarInfo.scrollBar = [scrollBars] { 0430 for (auto scrollBar : scrollBars) { 0431 if (qstrcmp(scrollBar->metaObject()->className(), "KateScrollBar") == 0) { 0432 return scrollBar; 0433 } 0434 } 0435 Q_ASSERT_X(false, 0436 "void " 0437 "KateViewManager::ScrollSynchronisation::getViewScrollBarInfo(" 0438 "KTextEditor::View *currentView)", 0439 "No QScrollBar* named \"KateScrollBar\" found in the selected View"); 0440 return static_cast<QScrollBar *>(nullptr); 0441 }(); 0442 if (scrollBarInfo.scrollBar) { 0443 scrollBarInfo.initScrollValue = scrollBarInfo.scrollBar->value() - this->referenceScrollValue; 0444 } 0445 return scrollBarInfo; 0446 } 0447 } m_scrollSynchronisation; 0448 0449 /** 0450 * current minimal age 0451 */ 0452 qint64 m_minAge; 0453 0454 /** 0455 * the view that is ATM merged to the xml gui factory 0456 */ 0457 QPointer<KTextEditor::View> m_guiMergedView; 0458 0459 /** 0460 * last url of open file dialog, used if current document has no valid url 0461 */ 0462 QUrl m_lastOpenDialogUrl; 0463 0464 /** 0465 * SDI mode: open every new document in a new window in most cases 0466 */ 0467 bool m_sdiMode = false; 0468 0469 /** 0470 * was the welcome view already shown? 0471 * ensures it doesn't auto popup multiple times 0472 */ 0473 bool m_welcomeViewAlreadyShown = false; 0474 };