File indexing completed on 2024-04-14 05:44:15

0001 /*
0002     SPDX-FileCopyrightText: 2006-2008 Robert Knight <robertknight@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #ifndef VIEWMANAGER_H
0008 #define VIEWMANAGER_H
0009 
0010 // Qt
0011 #include <QAction>
0012 #include <QHash>
0013 #include <QObject>
0014 #include <QPointer>
0015 
0016 #include "konsoleprivate_export.h"
0017 // Konsole
0018 
0019 class KActionCollection;
0020 class KConfigGroup;
0021 
0022 namespace Konsole
0023 {
0024 class ColorScheme;
0025 class Profile;
0026 class Session;
0027 class SessionController;
0028 class TabbedViewContainer;
0029 class TabbedViewContainer;
0030 class TerminalDisplay;
0031 class ViewProperties;
0032 class ViewSplitter;
0033 
0034 /**
0035  * Manages the terminal display widgets in a Konsole window or part.
0036  *
0037  * When a view manager is created, it constructs a tab widget ( accessed via
0038  * widget() ) to hold one or more view splitters.  Each view splitter holds
0039  * one or more terminal displays  and splitters.
0040  *
0041  * The view manager provides menu actions ( defined in the 'konsoleui.rc' XML file )
0042  * to manipulate the views and view containers - for example, actions to split the view
0043  * left/right or top/bottom, detach a view from the current window and navigate between
0044  * views and containers.  These actions are added to the collection specified in the
0045  * ViewManager's constructor.
0046  *
0047  * The view manager provides facilities to construct display widgets for a terminal
0048  * session and also to construct the SessionController which provides the menus and other
0049  * user interface elements specific to each display/session pair.
0050  *
0051  */
0052 class KONSOLEPRIVATE_EXPORT ViewManager : public QObject
0053 {
0054     Q_OBJECT
0055     Q_CLASSINFO("D-Bus Interface", "org.kde.konsole.Window")
0056 
0057 public:
0058     /**
0059      * Constructs a new view manager with the specified @p parent.
0060      * View-related actions defined in 'konsoleui.rc' are created
0061      * and added to the specified @p collection.
0062      */
0063     ViewManager(QObject *parent, KActionCollection *collection);
0064     ~ViewManager() override;
0065 
0066     /**
0067      * Creates a new view to display the output from and deliver input to @p session.
0068      * Constructs a new container to hold the views if no container has yet been created.
0069      */
0070     void createView(TabbedViewContainer *tabWidget, Session *session);
0071 
0072     /*
0073      * Applies the view-specific settings associated with specified @p profile
0074      * to the terminal display @p view.
0075      */
0076     void applyProfileToView(TerminalDisplay *view, const QExplicitlySharedDataPointer<Profile> &profile);
0077 
0078     void toggleActionsBasedOnState();
0079     /**
0080      * Return the main widget for the view manager which
0081      * holds all of the views managed by this ViewManager instance.
0082      */
0083     QWidget *widget() const;
0084 
0085     /**
0086      * Returns the view manager's active view.
0087      */
0088     QWidget *activeView() const;
0089 
0090     /**
0091      * Returns the list of view properties for views in the active container.
0092      * Each view widget is associated with a ViewProperties instance which
0093      * provides access to basic information about the session being
0094      * displayed in the view, such as title, current directory and
0095      * associated icon.
0096      */
0097     QList<ViewProperties *> viewProperties() const;
0098 
0099     /**
0100      * This enum describes the available types of navigation widget
0101      * which newly created containers can provide to allow navigation
0102      * between open sessions.
0103      */
0104     enum NavigationMethod {
0105         /**
0106          * Each container has a row of tabs (one per session) which the user
0107          * can click on to navigate between open sessions.
0108          */
0109         TabbedNavigation,
0110         /** The container has no navigation widget. */
0111         NoNavigation,
0112     };
0113 
0114     /**
0115      * Describes the options for showing or hiding the container's navigation widget.
0116      */
0117     enum NavigationVisibility {
0118         NavigationNotSet, // Don't rely on this information, Only use the settings.
0119         AlwaysShowNavigation,
0120         ShowNavigationAsNeeded,
0121         AlwaysHideNavigation,
0122     };
0123 
0124     /**
0125      * Sets the visibility of the view container's navigation widget.
0126      * The ViewContainer subclass is responsible for ensuring that this
0127      * setting is respected as views are dded or removed from the container
0128      */
0129     void setNavigationVisibility(NavigationVisibility navigationVisibility);
0130 
0131     /** Returns the current mode for controlling the visibility of the
0132      * view container's navigation widget.
0133      */
0134     NavigationVisibility navigationVisibility() const;
0135 
0136     /**
0137      * Sets the type of widget provided to navigate between open sessions
0138      * in a container.  The changes will only apply to newly created containers.
0139      *
0140      * The default method is TabbedNavigation.  To disable navigation widgets, call
0141      * setNavigationMethod(ViewManager::NoNavigation) before creating any sessions.
0142      */
0143     void setNavigationMethod(NavigationMethod method);
0144 
0145     /**
0146      * Returns the type of navigation widget created in new containers.
0147      * See setNavigationMethod()
0148      */
0149     NavigationMethod navigationMethod() const;
0150 
0151     /**
0152      * Returns the controller for the active view.  activeViewChanged() is
0153      * emitted when this changes.
0154      */
0155     SessionController *activeViewController() const;
0156 
0157     /**
0158      * Session management
0159      */
0160     void saveSessions(KConfigGroup &group);
0161     void restoreSessions(const KConfigGroup &group);
0162 
0163     int managerId() const;
0164 
0165     /** Returns a list of sessions in this ViewManager */
0166     QList<Session *> sessions()
0167     {
0168         return _sessionMap.values();
0169     }
0170 
0171     /**
0172      * Returns whether the @p profile has the blur setting enabled
0173      */
0174     static bool profileHasBlurEnabled(const QExplicitlySharedDataPointer<Profile> &profile);
0175 
0176     /** returns the active tab from the view
0177      */
0178     TabbedViewContainer *activeContainer();
0179     TerminalDisplay *createView(Session *session);
0180     void attachView(TerminalDisplay *terminal, Session *session);
0181 
0182     static std::shared_ptr<const ColorScheme> colorSchemeForProfile(const QExplicitlySharedDataPointer<Profile> &profile);
0183     /** Reorder the terminal display history list */
0184     void updateTerminalDisplayHistory(TerminalDisplay *terminalDisplay = nullptr, bool remove = false);
0185 
0186     QHash<TerminalDisplay *, Session *> forgetAll(ViewSplitter *splitter);
0187     Session *forgetTerminal(TerminalDisplay *terminal);
0188 
0189     /**
0190      * Creates and returns new session
0191      *
0192      * The session has specified @p profile, working @p directory
0193      * and configured environment.
0194      */
0195     Session *createSession(const QExplicitlySharedDataPointer<Profile> &profile, const QString &directory = QString());
0196 
0197 Q_SIGNALS:
0198     /** Emitted when the last view is removed from the view manager */
0199     void empty();
0200 
0201     /** Emitted when a session is detached from a view owned by this ViewManager */
0202     void terminalsDetached(ViewSplitter *splitter, QHash<TerminalDisplay *, Session *> sessionsMap);
0203 
0204     /**
0205      * Emitted when the active view changes.
0206      * @param controller The controller associated with the active view
0207      */
0208     void activeViewChanged(SessionController *controller);
0209 
0210     /**
0211      * Emitted when the current session needs unplugged from factory().
0212      * @param controller The controller associated with the active view
0213      */
0214     void unplugController(SessionController *controller);
0215 
0216     /**
0217      * Emitted when the list of view properties ( as returned by viewProperties() ) changes.
0218      * This occurs when views are added to or removed from the active container, or
0219      * if the active container is changed.
0220      */
0221     void viewPropertiesChanged(const QList<ViewProperties *> &propertiesList);
0222 
0223     /**
0224      * Emitted when menu bar visibility changes because a profile that requires so is
0225      * activated.
0226      */
0227     void setMenuBarVisibleRequest(bool);
0228     void updateWindowIcon();
0229 
0230     void blurSettingChanged(bool);
0231 
0232     /** Requests creation of a new view with the default profile. */
0233     void newViewRequest();
0234     /** Requests creation of a new view, with the selected profile. */
0235     void newViewWithProfileRequest(const QExplicitlySharedDataPointer<Profile> &profile);
0236 
0237     void activationRequest(const QString &xdgActivationToken);
0238 
0239 public Q_SLOTS:
0240     /** DBus slot that returns the number of sessions in the current view. */
0241     Q_SCRIPTABLE int sessionCount();
0242 
0243     /**
0244      * DBus slot that returns the unique ids of the sessions in the
0245      * current view.  The returned list is ordered by tab.
0246      * QList<int> is not printable by qdbus so we use QStringList
0247      * Example:
0248      *  A) create tab, create tab 2, create tab 3, go to tab 2, split view
0249      *     sessionList() returns 1 4 2 3
0250      *  B) create tab, create tab 2, split view, create tab 3
0251      *     sessionList() returns 1 3 2 4
0252      */
0253     Q_SCRIPTABLE QStringList sessionList();
0254 
0255     /** DBus slot that returns the current (active) session window */
0256     Q_SCRIPTABLE int currentSession();
0257 
0258     /** DBus slot that sets the current (active) session window */
0259     Q_SCRIPTABLE void setCurrentSession(int sessionId);
0260 
0261     /** DBus slot that creates a new session in the current view with the associated
0262      * default profile and the default working directory
0263      */
0264     Q_SCRIPTABLE int newSession();
0265 
0266     /** DBus slot that creates a new session in the current view.
0267      * @param profile the name of the profile to be used
0268      * started.
0269      */
0270     Q_SCRIPTABLE int newSession(const QString &profile);
0271 
0272     /** DBus slot that creates a new session in the current view.
0273      * @param profile the name of the profile to be used
0274      * @param directory the working directory where the session is
0275      * started.
0276      */
0277     Q_SCRIPTABLE int newSession(const QString &profile, const QString &directory);
0278 
0279     // TODO: its semantic is application-wide. Move it to more appropriate place
0280     // DBus slot that returns the name of default profile
0281     Q_SCRIPTABLE QString defaultProfile();
0282 
0283     // TODO: its semantic is application-wide. Move it to more appropriate place
0284     // DBus slot that sets the default profile
0285     Q_SCRIPTABLE void setDefaultProfile(const QString &profile);
0286 
0287     // TODO: its semantic is application-wide. Move it to more appropriate place
0288     // DBus slot that returns a string list of defined (known) profiles
0289     Q_SCRIPTABLE QStringList profileList();
0290 
0291     /** DBus slot that changes the view port to the next session */
0292     Q_SCRIPTABLE void nextSession();
0293 
0294     /** DBus slot that changes the view port to the previous session */
0295     Q_SCRIPTABLE void prevSession();
0296 
0297     /** DBus slot that switches the current session (as returned by
0298      * currentSession()) with the left (or previous) one in the
0299      * navigation tab.
0300      */
0301     Q_SCRIPTABLE void moveSessionLeft();
0302 
0303     /** DBus slot that Switches the current session (as returned by
0304      * currentSession()) with the right (or next) one in the navigation
0305      * tab.
0306      */
0307     Q_SCRIPTABLE void moveSessionRight();
0308 
0309     /** DBus slot that sets ALL tabs' width to match their text */
0310     Q_SCRIPTABLE void setTabWidthToText(bool);
0311 
0312     // Creates json file with split config
0313     Q_SCRIPTABLE void saveLayoutFile();
0314     Q_SCRIPTABLE void loadLayoutFile();
0315     Q_SCRIPTABLE void loadLayout(QString File);
0316 
0317     /** DBus slot that returns a description of the layout hierarchy
0318      * in each tab.
0319      *
0320      * A ViewSplitter is described by its id enclosed in round brackets,
0321      * followed by square (horizontal split) or curly (vertical split)
0322      * brackets. Format: (%id)[...] OR (%id){...}
0323      *
0324      * A TerminalDisplay is simply described by its id.
0325      *
0326      * The child widgets of a ViewSplitter are described in the square or
0327      * curly brackets using their ids and are separated by '|'. The
0328      * order which they are described in is top to bottom for vertical
0329      * split or left to right for horizontal split.
0330      */
0331     Q_SCRIPTABLE QStringList viewHierarchy();
0332 
0333     /** DBus slot that returns the sizes of the direct child widgets as
0334      * percentages of the size of the ViewSplitter in the form of a
0335      * list. Will return an empty list if a splitter with id splitterId
0336      * cannot be found.
0337      */
0338     Q_SCRIPTABLE QList<double> getSplitProportions(int splitterId);
0339 
0340     /** DBus slot that splits an existing view in the current tab **/
0341     Q_SCRIPTABLE bool createSplit(int viewId, bool horizontalSplit);
0342 
0343     /** DBus slot that creates a splitter containing a series of
0344      * existing widgets and inserts it at an index in an existing splitter.
0345      *
0346      * Each element in widgetInfos is QString of format "x-y", describing
0347      * each moved widget. Regarding the to-be-created splitter, the first
0348      * QString will represent the leftmost widget (horizontal split)
0349      * or the topmost widget (vertical split). x is either 's'
0350      * for a ViewSplitter or 'v' for a TerminalDisplay. y is the id of
0351      * the widget.
0352      */
0353     Q_SCRIPTABLE bool createSplitWithExisting(int targetSplitterId, QStringList widgetInfos, int idx, bool horizontalSplit);
0354 
0355     /** DBus slot that focuses a view. **/
0356     Q_SCRIPTABLE bool setCurrentView(int viewId);
0357 
0358     /** DBus slot that allows setting of the relative sizes of widgets
0359      * in a splitter by specifying their percentages.
0360      */
0361     /* NOTE: not all ways of calling dbus can handle "ad" QList<double>
0362         Does not work AFAIK: qdbus6, qdbusviewer6, busctl
0363         Works: dbus-send, gdbus
0364          Example:
0365             dbus-send --session --print-reply=literal --type=method_call --dest=org.kde.konsole-16710 /Windows/1   org.kde.konsole.Window.resizeSplits int32:0 array:double:40.0,60.0
0366             gdbus call --session --dest org.kde.konsole-16710  --object-path /Windows/1 --method org.kde.konsole.Window.resizeSplits 0 "[10.5, 89.5]"
0367     */
0368     Q_SCRIPTABLE bool resizeSplits(int splitterId, QList<double> percentages);
0369 
0370     /** DBus slot that moves a splitter to a different position under a specified splitter**/
0371     Q_SCRIPTABLE bool moveSplitter(int splitterId, int targetSplitterId, int idx);
0372 
0373     /** DBus slot that move a view to a different position under a specified splitter**/
0374     Q_SCRIPTABLE bool moveView(int viewId, int targetSplitterId, int idx);
0375 
0376 private Q_SLOTS:
0377     // called when the "Split View Left/Right" menu item is selected
0378     void splitLeftRight();
0379     void splitTopBottom();
0380     void splitAuto(bool fromNextTab = false);
0381     void splitLeftRightNextTab();
0382     void splitTopBottomNextTab();
0383     void splitAutoNextTab();
0384     void expandActiveContainer();
0385     void shrinkActiveContainer();
0386     void equalSizeAllContainers();
0387 
0388     // called when the "Detach View" menu item is selected
0389     void detachActiveView();
0390     void detachActiveTab();
0391 
0392     // called when a session terminates - the view manager will delete any
0393     // views associated with the session
0394     void sessionFinished(Session *session);
0395     // called when one view has been destroyed
0396     void viewDestroyed(QWidget *view);
0397 
0398     // controller detects when an associated view is given the focus
0399     // and emits a signal.  ViewManager listens for that signal
0400     // and then plugs the action into the UI
0401     // void viewFocused( SessionController* controller );
0402 
0403     // called when the active view in a ViewContainer changes, so
0404     // that we can plug the appropriate actions into the UI
0405     void activateView(TerminalDisplay *view);
0406 
0407     void focusUp();
0408     void focusDown();
0409     void focusLeft();
0410     void focusRight();
0411 
0412     // called when "Next View" shortcut is activated
0413     void nextView();
0414 
0415     // called when "Previous View" shortcut is activated
0416     void previousView();
0417 
0418     // called when "Switch to last tab" shortcut is activated
0419     void lastView();
0420 
0421     // called when "Switch to last used tab" shortcut is activated
0422     void lastUsedView();
0423 
0424     // called when "Switch to last used tab (reverse)" shortcut is activated
0425     void lastUsedViewReverse();
0426 
0427     // called when "Next View Container" shortcut is activated
0428     void nextContainer();
0429 
0430     // called when "Toggle Two tabs" shortcut is activated
0431     void toggleTwoViews();
0432 
0433     // called when the views in a container owned by this view manager
0434     // changes
0435     void containerViewsChanged(TabbedViewContainer *container);
0436 
0437     // called when a profile changes
0438     void profileChanged(const QExplicitlySharedDataPointer<Profile> &profile);
0439 
0440     void updateViewsForSession(Session *session);
0441 
0442     // moves active view to the left
0443     void moveActiveViewLeft();
0444     // moves active view to the right
0445     void moveActiveViewRight();
0446     // switches to the view at visual position 'index'
0447     // in the current container
0448     void switchToView(int index);
0449     // gives focus and switches the terminal display, changing tab if needed
0450     void switchToTerminalDisplay(TerminalDisplay *terminalDisplay);
0451 
0452     // called when a SessionController gains focus
0453     void controllerChanged(SessionController *controller);
0454 
0455     /**
0456      * Disconnect this ViewManager and MainWindow from @p controller
0457      * and its associated view/session pair such as after a split-view
0458      * has been drag-and-dropped to a new window.
0459      */
0460     void forgetController(SessionController *controller);
0461 
0462     /* Detaches the tab at index tabIdx */
0463     void detachTab(int tabIdx);
0464 
0465     void semanticSetupBash();
0466 
0467     void toggleSemanticHints();
0468 
0469     void toggleLineNumbers();
0470 
0471 private:
0472     Q_DISABLE_COPY(ViewManager)
0473 
0474     TerminalDisplay *findTerminalDisplay(int viewId);
0475 
0476     void setCurrentView(TerminalDisplay *view);
0477 
0478     void createView(Session *session, TabbedViewContainer *container, int index);
0479 
0480     void setupActions();
0481 
0482     // takes a view from a view container owned by a different manager and places it in
0483     // newContainer owned by this manager
0484     void takeView(ViewManager *otherManager, TabbedViewContainer *otherContainer, TabbedViewContainer *newContainer, TerminalDisplay *view);
0485     void splitView(Qt::Orientation orientation, bool fromNextTab = false);
0486 
0487     // creates a new container which can hold terminal displays
0488     TabbedViewContainer *createContainer();
0489 
0490     // creates a new terminal display
0491     // the 'session' is used so that the terminal display's random seed
0492     // can be set to something which depends uniquely on that session
0493     TerminalDisplay *createTerminalDisplay(Session *session = nullptr);
0494 
0495     // creates a new controller for a session/display pair which provides the menu
0496     // actions associated with that view, and exposes basic information
0497     // about the session ( such as title and associated icon ) to the display.
0498     SessionController *createController(Session *session, TerminalDisplay *view);
0499     void removeController(SessionController *controller);
0500 
0501     // Activates a different terminal when the TerminalDisplay
0502     // closes or is detached and another one should be focused.
0503     // It will activate the last used terminal within the same splitView
0504     // if possible otherwise it will focus the last used tab
0505     void focusAnotherTerminal(ViewSplitter *toplevelSplitter);
0506 
0507     void activateLastUsedView(bool reverse);
0508 
0509     void registerTerminal(TerminalDisplay *terminal);
0510     void unregisterTerminal(TerminalDisplay *terminal);
0511 
0512 private:
0513     QPointer<TabbedViewContainer> _viewContainer;
0514     QPointer<SessionController> _pluggedController;
0515 
0516     QHash<TerminalDisplay *, Session *> _sessionMap;
0517 
0518     KActionCollection *_actionCollection;
0519 
0520     NavigationMethod _navigationMethod;
0521     NavigationVisibility _navigationVisibility;
0522     int _managerId;
0523     static int lastManagerId;
0524     QList<TerminalDisplay *> _terminalDisplayHistory;
0525     int _terminalDisplayHistoryIndex;
0526 
0527     // List of actions that should only be enabled when there are multiple view
0528     // containers open
0529     QList<QAction *> _multiTabOnlyActions;
0530     QList<QAction *> _multiSplitterOnlyActions;
0531 };
0532 }
0533 
0534 #endif