/* SPDX-FileCopyrightText: 2006-2008 Robert Knight SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef VIEWMANAGER_H #define VIEWMANAGER_H // Qt #include #include #include #include #include "konsoleprivate_export.h" // Konsole class KActionCollection; class KConfigGroup; namespace Konsole { class ColorScheme; class Profile; class Session; class SessionController; class TabbedViewContainer; class TabbedViewContainer; class TerminalDisplay; class ViewProperties; class ViewSplitter; /** * Manages the terminal display widgets in a Konsole window or part. * * When a view manager is created, it constructs a tab widget ( accessed via * widget() ) to hold one or more view splitters. Each view splitter holds * one or more terminal displays and splitters. * * The view manager provides menu actions ( defined in the 'konsoleui.rc' XML file ) * to manipulate the views and view containers - for example, actions to split the view * left/right or top/bottom, detach a view from the current window and navigate between * views and containers. These actions are added to the collection specified in the * ViewManager's constructor. * * The view manager provides facilities to construct display widgets for a terminal * session and also to construct the SessionController which provides the menus and other * user interface elements specific to each display/session pair. * */ class KONSOLEPRIVATE_EXPORT ViewManager : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.konsole.Window") public: /** * Constructs a new view manager with the specified @p parent. * View-related actions defined in 'konsoleui.rc' are created * and added to the specified @p collection. */ ViewManager(QObject *parent, KActionCollection *collection); ~ViewManager() override; /** * Creates a new view to display the output from and deliver input to @p session. * Constructs a new container to hold the views if no container has yet been created. */ void createView(TabbedViewContainer *tabWidget, Session *session); /* * Applies the view-specific settings associated with specified @p profile * to the terminal display @p view. */ void applyProfileToView(TerminalDisplay *view, const QExplicitlySharedDataPointer &profile); void toggleActionsBasedOnState(); /** * Return the main widget for the view manager which * holds all of the views managed by this ViewManager instance. */ QWidget *widget() const; /** * Returns the view manager's active view. */ QWidget *activeView() const; /** * Returns the list of view properties for views in the active container. * Each view widget is associated with a ViewProperties instance which * provides access to basic information about the session being * displayed in the view, such as title, current directory and * associated icon. */ QList viewProperties() const; /** * This enum describes the available types of navigation widget * which newly created containers can provide to allow navigation * between open sessions. */ enum NavigationMethod { /** * Each container has a row of tabs (one per session) which the user * can click on to navigate between open sessions. */ TabbedNavigation, /** The container has no navigation widget. */ NoNavigation, }; /** * Describes the options for showing or hiding the container's navigation widget. */ enum NavigationVisibility { NavigationNotSet, // Don't rely on this information, Only use the settings. AlwaysShowNavigation, ShowNavigationAsNeeded, AlwaysHideNavigation, }; /** * Sets the visibility of the view container's navigation widget. * The ViewContainer subclass is responsible for ensuring that this * setting is respected as views are dded or removed from the container */ void setNavigationVisibility(NavigationVisibility navigationVisibility); /** Returns the current mode for controlling the visibility of the * view container's navigation widget. */ NavigationVisibility navigationVisibility() const; /** * Sets the type of widget provided to navigate between open sessions * in a container. The changes will only apply to newly created containers. * * The default method is TabbedNavigation. To disable navigation widgets, call * setNavigationMethod(ViewManager::NoNavigation) before creating any sessions. */ void setNavigationMethod(NavigationMethod method); /** * Returns the type of navigation widget created in new containers. * See setNavigationMethod() */ NavigationMethod navigationMethod() const; /** * Returns the controller for the active view. activeViewChanged() is * emitted when this changes. */ SessionController *activeViewController() const; /** * Session management */ void saveSessions(KConfigGroup &group); void restoreSessions(const KConfigGroup &group); int managerId() const; /** Returns a list of sessions in this ViewManager */ QList sessions() { return _sessionMap.values(); } /** * Returns whether the @p profile has the blur setting enabled */ static bool profileHasBlurEnabled(const QExplicitlySharedDataPointer &profile); /** returns the active tab from the view */ TabbedViewContainer *activeContainer(); TerminalDisplay *createView(Session *session); void attachView(TerminalDisplay *terminal, Session *session); static std::shared_ptr colorSchemeForProfile(const QExplicitlySharedDataPointer &profile); /** Reorder the terminal display history list */ void updateTerminalDisplayHistory(TerminalDisplay *terminalDisplay = nullptr, bool remove = false); QHash forgetAll(ViewSplitter *splitter); Session *forgetTerminal(TerminalDisplay *terminal); /** * Creates and returns new session * * The session has specified @p profile, working @p directory * and configured environment. */ Session *createSession(const QExplicitlySharedDataPointer &profile, const QString &directory = QString()); Q_SIGNALS: /** Emitted when the last view is removed from the view manager */ void empty(); /** Emitted when a session is detached from a view owned by this ViewManager */ void terminalsDetached(ViewSplitter *splitter, QHash sessionsMap); /** * Emitted when the active view changes. * @param controller The controller associated with the active view */ void activeViewChanged(SessionController *controller); /** * Emitted when the current session needs unplugged from factory(). * @param controller The controller associated with the active view */ void unplugController(SessionController *controller); /** * Emitted when the list of view properties ( as returned by viewProperties() ) changes. * This occurs when views are added to or removed from the active container, or * if the active container is changed. */ void viewPropertiesChanged(const QList &propertiesList); /** * Emitted when menu bar visibility changes because a profile that requires so is * activated. */ void setMenuBarVisibleRequest(bool); void updateWindowIcon(); void blurSettingChanged(bool); /** Requests creation of a new view with the default profile. */ void newViewRequest(); /** Requests creation of a new view, with the selected profile. */ void newViewWithProfileRequest(const QExplicitlySharedDataPointer &profile); void activationRequest(const QString &xdgActivationToken); public Q_SLOTS: /** DBus slot that returns the number of sessions in the current view. */ Q_SCRIPTABLE int sessionCount(); /** * DBus slot that returns the unique ids of the sessions in the * current view. The returned list is ordered by tab. * QList is not printable by qdbus so we use QStringList * Example: * A) create tab, create tab 2, create tab 3, go to tab 2, split view * sessionList() returns 1 4 2 3 * B) create tab, create tab 2, split view, create tab 3 * sessionList() returns 1 3 2 4 */ Q_SCRIPTABLE QStringList sessionList(); /** DBus slot that returns the current (active) session window */ Q_SCRIPTABLE int currentSession(); /** DBus slot that sets the current (active) session window */ Q_SCRIPTABLE void setCurrentSession(int sessionId); /** DBus slot that creates a new session in the current view with the associated * default profile and the default working directory */ Q_SCRIPTABLE int newSession(); /** DBus slot that creates a new session in the current view. * @param profile the name of the profile to be used * started. */ Q_SCRIPTABLE int newSession(const QString &profile); /** DBus slot that creates a new session in the current view. * @param profile the name of the profile to be used * @param directory the working directory where the session is * started. */ Q_SCRIPTABLE int newSession(const QString &profile, const QString &directory); // TODO: its semantic is application-wide. Move it to more appropriate place // DBus slot that returns the name of default profile Q_SCRIPTABLE QString defaultProfile(); // TODO: its semantic is application-wide. Move it to more appropriate place // DBus slot that sets the default profile Q_SCRIPTABLE void setDefaultProfile(const QString &profile); // TODO: its semantic is application-wide. Move it to more appropriate place // DBus slot that returns a string list of defined (known) profiles Q_SCRIPTABLE QStringList profileList(); /** DBus slot that changes the view port to the next session */ Q_SCRIPTABLE void nextSession(); /** DBus slot that changes the view port to the previous session */ Q_SCRIPTABLE void prevSession(); /** DBus slot that switches the current session (as returned by * currentSession()) with the left (or previous) one in the * navigation tab. */ Q_SCRIPTABLE void moveSessionLeft(); /** DBus slot that Switches the current session (as returned by * currentSession()) with the right (or next) one in the navigation * tab. */ Q_SCRIPTABLE void moveSessionRight(); /** DBus slot that sets ALL tabs' width to match their text */ Q_SCRIPTABLE void setTabWidthToText(bool); // Creates json file with split config Q_SCRIPTABLE void saveLayoutFile(); Q_SCRIPTABLE void loadLayoutFile(); Q_SCRIPTABLE void loadLayout(QString File); /** DBus slot that returns a description of the layout hierarchy * in each tab. * * A ViewSplitter is described by its id enclosed in round brackets, * followed by square (horizontal split) or curly (vertical split) * brackets. Format: (%id)[...] OR (%id){...} * * A TerminalDisplay is simply described by its id. * * The child widgets of a ViewSplitter are described in the square or * curly brackets using their ids and are separated by '|'. The * order which they are described in is top to bottom for vertical * split or left to right for horizontal split. */ Q_SCRIPTABLE QStringList viewHierarchy(); /** DBus slot that returns the sizes of the direct child widgets as * percentages of the size of the ViewSplitter in the form of a * list. Will return an empty list if a splitter with id splitterId * cannot be found. */ Q_SCRIPTABLE QList getSplitProportions(int splitterId); /** DBus slot that splits an existing view in the current tab **/ Q_SCRIPTABLE bool createSplit(int viewId, bool horizontalSplit); /** DBus slot that creates a splitter containing a series of * existing widgets and inserts it at an index in an existing splitter. * * Each element in widgetInfos is QString of format "x-y", describing * each moved widget. Regarding the to-be-created splitter, the first * QString will represent the leftmost widget (horizontal split) * or the topmost widget (vertical split). x is either 's' * for a ViewSplitter or 'v' for a TerminalDisplay. y is the id of * the widget. */ Q_SCRIPTABLE bool createSplitWithExisting(int targetSplitterId, QStringList widgetInfos, int idx, bool horizontalSplit); /** DBus slot that focuses a view. **/ Q_SCRIPTABLE bool setCurrentView(int viewId); /** DBus slot that allows setting of the relative sizes of widgets * in a splitter by specifying their percentages. */ /* NOTE: not all ways of calling dbus can handle "ad" QList Does not work AFAIK: qdbus6, qdbusviewer6, busctl Works: dbus-send, gdbus Example: 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 gdbus call --session --dest org.kde.konsole-16710 --object-path /Windows/1 --method org.kde.konsole.Window.resizeSplits 0 "[10.5, 89.5]" */ Q_SCRIPTABLE bool resizeSplits(int splitterId, QList percentages); /** DBus slot that moves a splitter to a different position under a specified splitter**/ Q_SCRIPTABLE bool moveSplitter(int splitterId, int targetSplitterId, int idx); /** DBus slot that move a view to a different position under a specified splitter**/ Q_SCRIPTABLE bool moveView(int viewId, int targetSplitterId, int idx); private Q_SLOTS: // called when the "Split View Left/Right" menu item is selected void splitLeftRight(); void splitTopBottom(); void splitAuto(bool fromNextTab = false); void splitLeftRightNextTab(); void splitTopBottomNextTab(); void splitAutoNextTab(); void expandActiveContainer(); void shrinkActiveContainer(); void equalSizeAllContainers(); // called when the "Detach View" menu item is selected void detachActiveView(); void detachActiveTab(); // called when a session terminates - the view manager will delete any // views associated with the session void sessionFinished(Session *session); // called when one view has been destroyed void viewDestroyed(QWidget *view); // controller detects when an associated view is given the focus // and emits a signal. ViewManager listens for that signal // and then plugs the action into the UI // void viewFocused( SessionController* controller ); // called when the active view in a ViewContainer changes, so // that we can plug the appropriate actions into the UI void activateView(TerminalDisplay *view); void focusUp(); void focusDown(); void focusLeft(); void focusRight(); // called when "Next View" shortcut is activated void nextView(); // called when "Previous View" shortcut is activated void previousView(); // called when "Switch to last tab" shortcut is activated void lastView(); // called when "Switch to last used tab" shortcut is activated void lastUsedView(); // called when "Switch to last used tab (reverse)" shortcut is activated void lastUsedViewReverse(); // called when "Next View Container" shortcut is activated void nextContainer(); // called when "Toggle Two tabs" shortcut is activated void toggleTwoViews(); // called when the views in a container owned by this view manager // changes void containerViewsChanged(TabbedViewContainer *container); // called when a profile changes void profileChanged(const QExplicitlySharedDataPointer &profile); void updateViewsForSession(Session *session); // moves active view to the left void moveActiveViewLeft(); // moves active view to the right void moveActiveViewRight(); // switches to the view at visual position 'index' // in the current container void switchToView(int index); // gives focus and switches the terminal display, changing tab if needed void switchToTerminalDisplay(TerminalDisplay *terminalDisplay); // called when a SessionController gains focus void controllerChanged(SessionController *controller); /** * Disconnect this ViewManager and MainWindow from @p controller * and its associated view/session pair such as after a split-view * has been drag-and-dropped to a new window. */ void forgetController(SessionController *controller); /* Detaches the tab at index tabIdx */ void detachTab(int tabIdx); void semanticSetupBash(); void toggleSemanticHints(); void toggleLineNumbers(); private: Q_DISABLE_COPY(ViewManager) TerminalDisplay *findTerminalDisplay(int viewId); void setCurrentView(TerminalDisplay *view); void createView(Session *session, TabbedViewContainer *container, int index); void setupActions(); // takes a view from a view container owned by a different manager and places it in // newContainer owned by this manager void takeView(ViewManager *otherManager, TabbedViewContainer *otherContainer, TabbedViewContainer *newContainer, TerminalDisplay *view); void splitView(Qt::Orientation orientation, bool fromNextTab = false); // creates a new container which can hold terminal displays TabbedViewContainer *createContainer(); // creates a new terminal display // the 'session' is used so that the terminal display's random seed // can be set to something which depends uniquely on that session TerminalDisplay *createTerminalDisplay(Session *session = nullptr); // creates a new controller for a session/display pair which provides the menu // actions associated with that view, and exposes basic information // about the session ( such as title and associated icon ) to the display. SessionController *createController(Session *session, TerminalDisplay *view); void removeController(SessionController *controller); // Activates a different terminal when the TerminalDisplay // closes or is detached and another one should be focused. // It will activate the last used terminal within the same splitView // if possible otherwise it will focus the last used tab void focusAnotherTerminal(ViewSplitter *toplevelSplitter); void activateLastUsedView(bool reverse); void registerTerminal(TerminalDisplay *terminal); void unregisterTerminal(TerminalDisplay *terminal); private: QPointer _viewContainer; QPointer _pluggedController; QHash _sessionMap; KActionCollection *_actionCollection; NavigationMethod _navigationMethod; NavigationVisibility _navigationVisibility; int _managerId; static int lastManagerId; QList _terminalDisplayHistory; int _terminalDisplayHistoryIndex; // List of actions that should only be enabled when there are multiple view // containers open QList _multiTabOnlyActions; QList _multiSplitterOnlyActions; }; } #endif