diff --git a/src/Application.cpp b/src/Application.cpp --- a/src/Application.cpp +++ b/src/Application.cpp @@ -186,7 +186,7 @@ MainWindow *window = newMainWindow(); ViewManager *manager = window->viewManager(); - manager->createView(manager->activeContainer(), session); + manager->createView(session); // Since user is dragging and dropping, move dnd window to where // the user has the cursor (correct multiple monitor setups). diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -467,6 +467,7 @@ void MainWindow::newTab(TabbedViewContainer *tabWidget) { + qDebug() << "New Tab Triggered"; Profile::Ptr defaultProfile = ProfileManager::instance()->defaultProfile(); createSession(tabWidget, defaultProfile, activeSessionDir()); } @@ -504,8 +505,8 @@ // doesn't suffer a change in terminal size right after the session // starts. Some applications such as GNU Screen and Midnight Commander // don't like this happening - _viewManager->createView(tabWidget, session); - + auto newView = _viewManager->createView(session); + _viewManager->activeContainer()->addView(newView); return session; } @@ -534,8 +535,8 @@ // doesn't suffer a change in terminal size right after the session // starts. some applications such as GNU Screen and Midnight Commander // don't like this happening - _viewManager->createView(tabWidget, session); - + auto newView = _viewManager->createView(session); + _viewManager->activeContainer()->addView(newView); return session; } diff --git a/src/Part.cpp b/src/Part.cpp --- a/src/Part.cpp +++ b/src/Part.cpp @@ -213,7 +213,8 @@ session->setInitialWorkingDirectory(directory); } - _viewManager->createView(_viewManager->activeContainer(), session); + auto newView = _viewManager->createView(session); + _viewManager->activeContainer()->addView(newView); } void Part::activeViewChanged(SessionController *controller) diff --git a/src/Shortcut_p.h b/src/Shortcut_p.h --- a/src/Shortcut_p.h +++ b/src/Shortcut_p.h @@ -30,9 +30,13 @@ */ enum Modifier { #ifdef Q_OS_MACOS - ACCEL = Qt::META + ACCEL = Qt::META, + LEFT = Qt::Key_BracketLeft, + RIGHT = Qt::Key_BracketRight #else - ACCEL = Qt::CTRL + ACCEL = Qt::CTRL, + LEFT = Qt::Key_Left, + RIGHT = Qt::Key_Right #endif }; } diff --git a/src/ViewContainer.h b/src/ViewContainer.h --- a/src/ViewContainer.h +++ b/src/ViewContainer.h @@ -103,6 +103,8 @@ void setCss(const QString& styleSheet = QString()); void setCssFromFile(const QUrl& url); + + ViewSplitter *activeViewSplitter(); /** * This enum describes the directions * in which views can be re-arranged within the container @@ -140,12 +142,14 @@ void setNavigationVisibility(ViewManager::NavigationVisibility navigationVisibility); void moveTabToWindow(int index, QWidget *window); + void maximizeCurrentTerminal(); + void restoreOtherTerminals(); /* return the widget(int index) casted to TerminalDisplay* * * The only thing that this class holds are TerminalDisplays, so * this is the only thing that should be used to retrieve widgets. */ - TerminalDisplay *terminalAt(int index); + ViewSplitter *viewSplitterAt(int index); Q_SIGNALS: /** Emitted when the container has no more children */ void empty(TabbedViewContainer *container); @@ -198,7 +202,7 @@ void konsoleConfigChanged(); private: - void forgetView(TerminalDisplay *view); + void forgetView(ViewSplitter *view); void updateTabHistory(TerminalDisplay *view, bool remove = false); QList _tabHistory; @@ -209,6 +213,7 @@ int _contextMenuTabIndex; ViewManager::NavigationVisibility _navigationVisibility; int _tabHistoryIndex; + ViewSplitter *_viewSplitter; }; diff --git a/src/ViewContainer.cpp b/src/ViewContainer.cpp --- a/src/ViewContainer.cpp +++ b/src/ViewContainer.cpp @@ -47,6 +47,7 @@ #include "SessionController.h" #include "DetachableTabBar.h" #include "TerminalDisplay.h" +#include "ViewSplitter.h" // TODO Perhaps move everything which is Konsole-specific into different files @@ -86,9 +87,12 @@ &Konsole::TabbedViewContainer::tabDoubleClicked); connect(tabBar(), &QTabBar::customContextMenuRequested, this, &Konsole::TabbedViewContainer::openTabContextMenu); - connect(tabBarWidget, &DetachableTabBar::detachTab, this, [this](int idx) { - emit detachTab(this, terminalAt(idx)); - }); + + //TODO: Fix Detach. + // connect(tabBarWidget, &DetachableTabBar::detachTab, this, [this](int idx) { + // emit detachTab(this, terminalAt(idx)); + //}); + connect(this, &TabbedViewContainer::currentChanged, this, &TabbedViewContainer::currentTabChanged); // The context menu of tab bar @@ -104,12 +108,14 @@ }); #if defined(ENABLE_DETACHING) + /* TODO FIX DETACH auto detachAction = _contextPopupMenu->addAction( QIcon::fromTheme(QStringLiteral("tab-detach")), i18nc("@action:inmenu", "&Detach Tab"), this, [this] { emit detachTab(this, terminalAt(_contextMenuTabIndex)); } ); detachAction->setObjectName(QStringLiteral("tab-detach")); + */ #endif auto editAction = _contextPopupMenu->addAction( @@ -145,13 +151,20 @@ } } -TerminalDisplay *TabbedViewContainer::terminalAt(int index) +ViewSplitter *TabbedViewContainer::activeViewSplitter() +{ + return viewSplitterAt(currentIndex()); +} + +ViewSplitter *TabbedViewContainer::viewSplitterAt(int index) { - return qobject_cast(widget(index)); + return qobject_cast(widget(index)); } void TabbedViewContainer::moveTabToWindow(int index, QWidget *window) { + // TODO: Fix Detaching. + /* const int id = terminalAt(index)->sessionController()->identifier(); // This one line here will be removed as soon as I finish my new split handling. // it's hacky but it works. @@ -163,6 +176,7 @@ removeView(terminalAt(index)); } } + */ } void TabbedViewContainer::konsoleConfigChanged() @@ -232,28 +246,33 @@ const int currentIndex = indexOf(currentWidget()); int newIndex = direction == MoveViewLeft ? qMax(currentIndex - 1, 0) : qMin(currentIndex + 1, count() - 1); - auto swappedWidget = terminalAt(newIndex); - auto currentWidget = terminalAt(currentIndex); - auto swappedContext = swappedWidget->sessionController(); - auto currentContext = currentWidget->sessionController(); + auto swappedWidget = viewSplitterAt(newIndex); + auto swappedTitle = tabBar()->tabText(newIndex); + auto swappedIcon = tabBar()->tabIcon(newIndex); + + auto currentWidget = viewSplitterAt(currentIndex); + auto currentTitle = tabBar()->tabText(currentIndex); + auto currentIcon = tabBar()->tabIcon(currentIndex); if (newIndex < currentIndex) { - insertTab(newIndex, currentWidget, currentContext->icon(), currentContext->title()); - insertTab(currentIndex, swappedWidget, swappedContext->icon(), swappedContext->title()); + insertTab(newIndex, currentWidget, currentIcon, currentTitle); + insertTab(currentIndex, swappedWidget, swappedIcon, swappedTitle); } else { - insertTab(currentIndex, swappedWidget, swappedContext->icon(), swappedContext->title()); - insertTab(newIndex, currentWidget, currentContext->icon(), currentContext->title()); + insertTab(currentIndex, swappedWidget, swappedIcon, swappedTitle); + insertTab(newIndex, currentWidget, currentIcon, currentTitle); } setCurrentIndex(newIndex); } void TabbedViewContainer::addView(TerminalDisplay *view, int index) { + auto viewSplitter = new ViewSplitter(); + viewSplitter->addTerminalDisplay(view, Qt::Horizontal); auto item = view->sessionController(); if (index == -1) { - addTab(view, item->icon(), item->title()); + index = addTab(viewSplitter, item->icon(), item->title()); } else { - insertTab(index, view, item->icon(), item->title()); + insertTab(index, viewSplitter, item->icon(), item->title()); } _tabHistory.append(view); @@ -263,35 +282,38 @@ &Konsole::TabbedViewContainer::updateIcon); connect(item, &Konsole::ViewProperties::activity, this, &Konsole::TabbedViewContainer::updateActivity); - connect(view, &QWidget::destroyed, this, - &Konsole::TabbedViewContainer::viewDestroyed); + + connect(viewSplitter, &ViewSplitter::destroyed, this, &TabbedViewContainer::viewDestroyed); + setCurrentIndex(index); emit viewAdded(view); } void TabbedViewContainer::viewDestroyed(QObject *view) { - auto widget = static_cast(view); + auto widget = static_cast(view); const auto idx = indexOf(widget); removeTab(idx); forgetView(widget); } -void TabbedViewContainer::forgetView(TerminalDisplay *view) +void TabbedViewContainer::forgetView(ViewSplitter *view) { - updateTabHistory(view, true); - emit viewRemoved(view); + //TODO: Fix updateTabHistory + // updateTabHistory(view, true); + // emit viewRemoved(view); if (count() == 0) { emit empty(this); } } void TabbedViewContainer::removeView(TerminalDisplay *view) { - const int idx = indexOf(view); - disconnect(view, &QWidget::destroyed, this, &Konsole::TabbedViewContainer::viewDestroyed); - removeTab(idx); - forgetView(view); + /* TODO: This is absolutely the wrong place. + * We are removing a terminal display from a ViewSplitter, + * this should be inside of the view splitter or something. + */ + view->setParent(nullptr); } void TabbedViewContainer::activateNextView() @@ -387,8 +409,12 @@ void TabbedViewContainer::renameTab(int index) { + /* TODO: Fix renaming. + The problem with the renaming right now is that many Terminals can be at a tab. + */ + if (index != -1) { - terminalAt(index)->sessionController()->rename(); +// terminalAt(index)->sessionController()->rename(); } } @@ -413,9 +439,13 @@ } #endif + /* This needs to nove away fro the tab or to lock every thing inside of it. + * for now, disable. + * */ + // // Add the read-only action - auto controller = terminalAt(_contextMenuTabIndex)->sessionController(); - auto sessionController = qobject_cast(controller); +#if 0 + auto sessionController = terminalAt(_contextMenuTabIndex)->sessionController(); if (sessionController != nullptr) { auto collection = sessionController->actionCollection(); @@ -433,14 +463,14 @@ } } } - +#endif _contextPopupMenu->exec(tabBar()->mapToGlobal(point)); } void TabbedViewContainer::currentTabChanged(int index) { if (index != -1) { - auto *view = terminalAt(index); + auto view = widget(index)->findChild(); view->setFocus(); updateTabHistory(view); emit activeViewChanged(view); @@ -506,7 +536,10 @@ } void TabbedViewContainer::closeTerminalTab(int idx) { - terminalAt(idx)->sessionController()->closeSession(); + //TODO: This for should probably go to the ViewSplitter + for (auto terminal : viewSplitterAt(idx)->findChildren()) { + terminal->sessionController()->closeSession(); + } } ViewManager *TabbedViewContainer::connectedViewManager() @@ -526,3 +559,13 @@ tabBar()->setVisible(false); } } + +void TabbedViewContainer::maximizeCurrentTerminal() +{ + activeViewSplitter()->maximizeCurrentTerminal(); +} + +void TabbedViewContainer::restoreOtherTerminals() +{ + activeViewSplitter()->restoreOtherTerminals(); +} diff --git a/src/ViewManager.h b/src/ViewManager.h --- a/src/ViewManager.h +++ b/src/ViewManager.h @@ -44,10 +44,9 @@ /** * Manages the terminal display widgets in a Konsole window or part. * - * When a view manager is created, it constructs a splitter widget ( accessed via - * widget() ) to hold one or more view containers. Each view container holds - * one or more terminal displays and a navigation widget ( eg. tabs or a list ) - * to allow the user to navigate between the displays in that container. + * 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 @@ -74,12 +73,6 @@ ViewManager(QObject *parent, KActionCollection *collection); ~ViewManager() Q_DECL_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. @@ -197,6 +190,7 @@ /** returns the active tab from the view */ TabbedViewContainer *activeContainer(); + TerminalDisplay *createView(Session *session); Q_SIGNALS: /** Emitted when the last view is removed from the view manager */ @@ -316,8 +310,6 @@ // called when the "Split View Left/Right" menu item is selected void splitLeftRight(); void splitTopBottom(); - void closeActiveContainer(); - void closeOtherContainers(); void expandActiveContainer(); void shrinkActiveContainer(); @@ -340,6 +332,11 @@ // that we can plug the appropriate actions into the UI void viewActivated(QWidget *view); + void focusUp(); + void focusDown(); + void focusLeft(); + void focusRight(); + // called when "Next View" shortcut is activated void nextView(); @@ -387,7 +384,6 @@ private: Q_DISABLE_COPY(ViewManager) - void createView(Session *session, TabbedViewContainer *container, int index); static const ColorScheme *colorSchemeForProfile(const Profile::Ptr profile); void setupActions(); @@ -413,8 +409,13 @@ // about the session ( such as title and associated icon ) to the display. SessionController *createController(Session *session, TerminalDisplay *view); + // Activates a different terminal than the one passed by + // that lives in the same tab. this is used when the TerminalDisplay + // closes and another one should be focused. + void focusAnotherTerminal(TerminalDisplay *lostFocus); + private: - QPointer _viewSplitter; + QPointer _viewContainer; QPointer _pluggedController; QHash _sessionMap; diff --git a/src/ViewManager.cpp b/src/ViewManager.cpp --- a/src/ViewManager.cpp +++ b/src/ViewManager.cpp @@ -52,36 +52,24 @@ ViewManager::ViewManager(QObject *parent, KActionCollection *collection) : QObject(parent), - _viewSplitter(nullptr), + _viewContainer(nullptr), _pluggedController(nullptr), _sessionMap(QHash()), _actionCollection(collection), _navigationMethod(NoNavigation), _navigationVisibility(NavigationNotSet), _newTabBehavior(PutNewTabAtTheEnd), _managerId(0) { - // create main view area - _viewSplitter = new ViewSplitter(nullptr); - KAcceleratorManager::setNoAccel(_viewSplitter); - - // the ViewSplitter class supports both recursive and non-recursive splitting, - // in non-recursive mode, all containers are inserted into the same top-level splitter - // widget, and all the divider lines between the containers have the same orientation - // - // the ViewManager class is not currently able to handle a ViewSplitter in recursive-splitting - // mode - _viewSplitter->setRecursiveSplitting(false); - _viewSplitter->setFocusPolicy(Qt::NoFocus); - + _viewContainer = createContainer(); // setup actions which are related to the views setupActions(); + /* TODO: Reconnect // emit a signal when all of the views held by this view manager are destroyed - connect(_viewSplitter.data(), &Konsole::ViewSplitter::allContainersEmpty, + */ + connect(_viewContainer.data(), &Konsole::TabbedViewContainer::empty, this, &Konsole::ViewManager::empty); - connect(_viewSplitter.data(), &Konsole::ViewSplitter::empty, this, - &Konsole::ViewManager::empty); // listen for profile changes connect(ProfileManager::instance(), &Konsole::ProfileManager::profileChanged, @@ -95,8 +83,6 @@ _managerId = ++lastManagerId; QDBusConnection::sessionBus().registerObject(QLatin1String("/Windows/") + QString::number(_managerId), this); - - _viewSplitter->addContainer(createContainer(), Qt::Vertical); } ViewManager::~ViewManager() = default; @@ -108,17 +94,12 @@ QWidget *ViewManager::activeView() const { - TabbedViewContainer *container = _viewSplitter->activeContainer(); - if (container != nullptr) { - return container->currentWidget(); - } else { - return nullptr; - } + return _viewContainer->currentWidget(); } QWidget *ViewManager::widget() const { - return _viewSplitter; + return _viewContainer; } void ViewManager::setupActions() @@ -130,171 +111,139 @@ KActionCollection *collection = _actionCollection; - QAction *nextViewAction = new QAction(i18nc("@action Shortcut entry", "Next Tab"), this); - QAction *previousViewAction = new QAction(i18nc("@action Shortcut entry", "Previous Tab"), this); - QAction *lastViewAction = new QAction(i18nc("@action Shortcut entry", - "Switch to Last Tab"), this); - QAction *lastUsedViewAction = new QAction(i18nc("@action Shortcut entry", "Last Used Tabs"), this); - QAction *lastUsedViewReverseAction = new QAction(i18nc("@action Shortcut entry", - "Last Used Tabs (Reverse)"), this); - QAction *nextContainerAction = new QAction(i18nc("@action Shortcut entry", - "Next View Container"), this); - - QAction *moveViewLeftAction = new QAction(i18nc("@action Shortcut entry", "Move Tab Left"), this); - QAction *moveViewRightAction = new QAction(i18nc("@action Shortcut entry", - "Move Tab Right"), this); - - // list of actions that should only be enabled when there are multiple view - // containers open + // list of actions that should only be enabled when there are multiple view containers open QList multiViewOnlyActions; - multiViewOnlyActions << nextContainerAction; - - QAction *splitLeftRightAction = new QAction(QIcon::fromTheme(QStringLiteral("view-split-left-right")), - i18nc("@action:inmenu", "Split View Left/Right"), - this); - collection->setDefaultShortcut(splitLeftRightAction, Konsole::ACCEL + Qt::Key_ParenLeft); - collection->addAction(QStringLiteral("split-view-left-right"), splitLeftRightAction); - connect(splitLeftRightAction, &QAction::triggered, this, &Konsole::ViewManager::splitLeftRight); - - QAction *splitTopBottomAction = new QAction(QIcon::fromTheme(QStringLiteral("view-split-top-bottom")), - i18nc("@action:inmenu", - "Split View Top/Bottom"), this); - collection->setDefaultShortcut(splitTopBottomAction, Konsole::ACCEL + Qt::Key_ParenRight); - collection->addAction(QStringLiteral("split-view-top-bottom"), splitTopBottomAction); - connect(splitTopBottomAction, &QAction::triggered, this, &Konsole::ViewManager::splitTopBottom); - - QAction *closeActiveAction = new QAction(i18nc("@action:inmenu Close Active View", "Close Active"), this); - closeActiveAction->setIcon(QIcon::fromTheme(QStringLiteral("view-close"))); - collection->setDefaultShortcut(closeActiveAction, Konsole::ACCEL + Qt::SHIFT + Qt::Key_X); - closeActiveAction->setEnabled(false); - collection->addAction(QStringLiteral("close-active-view"), closeActiveAction); - connect(closeActiveAction, &QAction::triggered, this, - &Konsole::ViewManager::closeActiveContainer); - - multiViewOnlyActions << closeActiveAction; - - QAction *closeOtherAction = new QAction(i18nc("@action:inmenu Close Other Views", - "Close Others"), this); - collection->setDefaultShortcut(closeOtherAction, Konsole::ACCEL + Qt::SHIFT + Qt::Key_O); - closeOtherAction->setEnabled(false); - collection->addAction(QStringLiteral("close-other-views"), closeOtherAction); - connect(closeOtherAction, &QAction::triggered, this, - &Konsole::ViewManager::closeOtherContainers); - - multiViewOnlyActions << closeOtherAction; - - // Expand & Shrink Active View - QAction *expandActiveAction = new QAction(i18nc("@action:inmenu", "Expand View"), this); - collection->setDefaultShortcut(expandActiveAction, - Konsole::ACCEL + Qt::SHIFT + Qt::Key_BracketRight); - expandActiveAction->setEnabled(false); - collection->addAction(QStringLiteral("expand-active-view"), expandActiveAction); - connect(expandActiveAction, &QAction::triggered, this, - &Konsole::ViewManager::expandActiveContainer); - - multiViewOnlyActions << expandActiveAction; - - QAction *shrinkActiveAction = new QAction(i18nc("@action:inmenu", "Shrink View"), this); - collection->setDefaultShortcut(shrinkActiveAction, - Konsole::ACCEL + Qt::SHIFT + Qt::Key_BracketLeft); - shrinkActiveAction->setEnabled(false); - collection->addAction(QStringLiteral("shrink-active-view"), shrinkActiveAction); - connect(shrinkActiveAction, &QAction::triggered, this, - &Konsole::ViewManager::shrinkActiveContainer); - - multiViewOnlyActions << shrinkActiveAction; + + // Let's reuse the pointer, no need not to. + auto *action = new QAction(); + action->setIcon(QIcon::fromTheme(QStringLiteral("view-split-left-right"))); + action->setText(i18nc("@action:inmenu", "Split View Left/Right")); + connect(action, &QAction::triggered, this, &ViewManager::splitLeftRight); + collection->addAction(QStringLiteral("split-view-left-right"), action); + collection->setDefaultShortcut(action, Konsole::ACCEL + Qt::Key_ParenLeft); + + action = new QAction(); + action->setIcon(QIcon::fromTheme(QStringLiteral("view-split-top-bottom"))); + action->setText(i18nc("@action:inmenu", "Split View Top/Bottom")); + connect(action, &QAction::triggered, this, &ViewManager::splitTopBottom); + collection->setDefaultShortcut(action, Konsole::ACCEL + Qt::Key_ParenRight); + collection->addAction(QStringLiteral("split-view-top-bottom"), action); + + action = new QAction(); + action->setText(i18nc("@action:inmenu", "Expand View")); + action->setEnabled(false); + connect(action, &QAction::triggered, this, &ViewManager::expandActiveContainer); + collection->setDefaultShortcut(action, Konsole::ACCEL + Qt::SHIFT + Qt::Key_BracketRight); + collection->addAction(QStringLiteral("expand-active-view"), action); + multiViewOnlyActions << action; + + action = new QAction(); + action->setText(i18nc("@action:inmenu", "Shrink View")); + collection->setDefaultShortcut(action, Konsole::ACCEL + Qt::SHIFT + Qt::Key_BracketLeft); + action->setEnabled(false); + collection->addAction(QStringLiteral("shrink-active-view"), action); + connect(action, &QAction::triggered, this, &ViewManager::shrinkActiveContainer); + multiViewOnlyActions << action; // Crashes on Mac. #if defined(ENABLE_DETACHING) - QAction *detachViewAction = collection->addAction(QStringLiteral("detach-view")); - detachViewAction->setEnabled(true); - detachViewAction->setIcon(QIcon::fromTheme(QStringLiteral("tab-detach"))); - detachViewAction->setText(i18nc("@action:inmenu", "D&etach Current Tab")); + action = collection->addAction(QStringLiteral("detach-view")); + action->setEnabled(true); + action->setIcon(QIcon::fromTheme(QStringLiteral("tab-detach"))); + action->setText(i18nc("@action:inmenu", "D&etach Current Tab")); + + connect(this, &ViewManager::splitViewToggle, this, &ViewManager::updateDetachViewState); + connect(action, &QAction::triggered, this, &ViewManager::detachActiveView); + // Ctrl+Shift+D is not used as a shortcut by default because it is too close // to Ctrl+D - which will terminate the session in many cases - collection->setDefaultShortcut(detachViewAction, Konsole::ACCEL + Qt::SHIFT + Qt::Key_H); - - connect(this, &Konsole::ViewManager::splitViewToggle, this, - &Konsole::ViewManager::updateDetachViewState); - connect(detachViewAction, &QAction::triggered, this, &Konsole::ViewManager::detachActiveView); + collection->setDefaultShortcut(action, Konsole::ACCEL + Qt::SHIFT + Qt::Key_H); #endif - // Next / Previous View , Next Container - collection->addAction(QStringLiteral("next-view"), nextViewAction); - collection->addAction(QStringLiteral("previous-view"), previousViewAction); - collection->addAction(QStringLiteral("last-tab"), lastViewAction); - collection->addAction(QStringLiteral("last-used-tab"), lastUsedViewAction); - collection->addAction(QStringLiteral("last-used-tab-reverse"), lastUsedViewReverseAction); - collection->addAction(QStringLiteral("next-container"), nextContainerAction); - collection->addAction(QStringLiteral("move-view-left"), moveViewLeftAction); - collection->addAction(QStringLiteral("move-view-right"), moveViewRightAction); - - // Switch to tab N shortcuts + // keyboard shortcut only actions + action = new QAction(i18nc("@action Shortcut entry", "Next Tab"), this); + const QList nextViewActionKeys{Qt::SHIFT + Qt::Key_Right, Qt::CTRL + Qt::Key_PageDown}; + collection->setDefaultShortcuts(action, nextViewActionKeys); + collection->addAction(QStringLiteral("next-tab"), action); + connect(action, &QAction::triggered, this, &ViewManager::nextView); + // _viewSplitter->addAction(nextViewAction); + + action = new QAction(i18nc("@action Shortcut entry", "Previous Tab"), this); + const QList previousViewActionKeys{Qt::SHIFT + Qt::Key_Left, Qt::CTRL + Qt::Key_PageUp}; + collection->setDefaultShortcuts(action, previousViewActionKeys); + collection->addAction(QStringLiteral("previous-tab"), action); + connect(action, &QAction::triggered, this, &ViewManager::previousView); + // _viewSplitter->addAction(previousViewAction); + + action = new QAction(i18nc("@action Shortcut entry", "Next View Container"), this); + connect(action, &QAction::triggered, this, &ViewManager::focusUp); + collection->addAction(QStringLiteral("next-container"), action); + collection->setDefaultShortcut(action, Qt::SHIFT + Qt::CTRL + Qt::Key_Up); + _viewContainer->addAction(action); + multiViewOnlyActions << action; + + action = new QAction(QStringLiteral("Focus Down")); + collection->setDefaultShortcut(action, Qt::SHIFT + Qt::CTRL + Qt::Key_Down); + connect(action, &QAction::triggered, this, &ViewManager::focusDown); + _viewContainer->addAction(action); + + action = new QAction(i18nc("@action Shortcut entry", "Move Tab Left"), this); + collection->setDefaultShortcut(action, Konsole::ACCEL + Qt::SHIFT + Konsole::LEFT); + connect(action, &QAction::triggered, this, &ViewManager::focusLeft); + collection->addAction(QStringLiteral("move-view-left"), action); + // _viewSplitter->addAction(action); + + action = new QAction(i18nc("@action Shortcut entry", "Move Tab Right"), this); + collection->setDefaultShortcut(action, Konsole::ACCEL + Qt::SHIFT + Konsole::RIGHT); + connect(action, &QAction::triggered, this, &ViewManager::focusRight); + collection->addAction(QStringLiteral("move-view-right"), action); + // _viewSplitter->addAction(action); + + action = new QAction(i18nc("@action Shortcut entry", "Switch to Last Tab"), this); + connect(action, &QAction::triggered, this, &ViewManager::lastView); + collection->addAction(QStringLiteral("last-tab"), action); + // _viewSplitter->addAction(action); + + action = new QAction(i18nc("@action Shortcut entry", "Last Used Tabs"), this); + connect(action, &QAction::triggered, this, &ViewManager::lastUsedView); + collection->setDefaultShortcut(action, Qt::CTRL + Qt::Key_Tab); + collection->addAction(QStringLiteral("last-used-tab"), action); + // _viewSplitter->addAction(lastUsedViewAction); + + action = new QAction(i18nc("@action Shortcut entry", "Last Used Tabs (Reverse)"), this); + collection->addAction(QStringLiteral("last-used-tab-reverse"), action); + collection->setDefaultShortcut(action, Qt::CTRL + Qt::SHIFT + Qt::Key_Tab); + connect(action, &QAction::triggered, this, &ViewManager::lastUsedViewReverse); + // _viewSplitter->addAction(lastUsedViewReverseAction); + + action = new QAction(i18nc("@action Shortcut entry", "Maximize current Terminal"), this); + collection->addAction(QStringLiteral("maximize-current-terminal"), action); + collection->setDefaultShortcut(action, Qt::CTRL + Qt::SHIFT + Qt::Key_E); + connect(action, &QAction::triggered, _viewContainer, &TabbedViewContainer::maximizeCurrentTerminal); + _viewContainer->addAction(action); + + action = new QAction(i18nc("@action Shortcut entry", "Restore other terminals"), this); + collection->addAction(QStringLiteral("restore-other-terminals"), action); + collection->setDefaultShortcut(action, Qt::CTRL + Qt::SHIFT + Qt::Key_Minus); + connect(action, &QAction::triggered, _viewContainer, &TabbedViewContainer::restoreOtherTerminals); + _viewContainer->addAction(action); + + // _viewSplitter->addAction(lastUsedViewReverseAction); const int SWITCH_TO_TAB_COUNT = 19; for (int i = 0; i < SWITCH_TO_TAB_COUNT; i++) { - QAction *switchToTabAction = new QAction(i18nc("@action Shortcut entry", "Switch to Tab %1", i + 1), this); - - connect(switchToTabAction, &QAction::triggered, this, - [this, i]() { - switchToView(i); - }); - collection->addAction(QStringLiteral("switch-to-tab-%1").arg(i), switchToTabAction); + action = new QAction(i18nc("@action Shortcut entry", "Switch to Tab %1", i + 1), this); + connect(action, &QAction::triggered, this, [this, i]() { switchToView(i); }); + collection->addAction(QStringLiteral("switch-to-tab-%1").arg(i), action); } foreach (QAction *action, multiViewOnlyActions) { - connect(this, &Konsole::ViewManager::splitViewToggle, action, &QAction::setEnabled); + connect(this, &ViewManager::splitViewToggle, action, &QAction::setEnabled); } - - // keyboard shortcut only actions - const QList nextViewActionKeys{Qt::SHIFT + Qt::Key_Right, Qt::CTRL + Qt::Key_PageDown}; - collection->setDefaultShortcuts(nextViewAction, nextViewActionKeys); - connect(nextViewAction, &QAction::triggered, this, &Konsole::ViewManager::nextView); - _viewSplitter->addAction(nextViewAction); - - const QList previousViewActionKeys{Qt::SHIFT + Qt::Key_Left, Qt::CTRL + Qt::Key_PageUp}; - collection->setDefaultShortcuts(previousViewAction, previousViewActionKeys); - connect(previousViewAction, &QAction::triggered, this, &Konsole::ViewManager::previousView); - _viewSplitter->addAction(previousViewAction); - - collection->setDefaultShortcut(nextContainerAction, Qt::SHIFT + Qt::Key_Tab); - connect(nextContainerAction, &QAction::triggered, this, &Konsole::ViewManager::nextContainer); - _viewSplitter->addAction(nextContainerAction); - -#ifdef Q_OS_MACOS - collection->setDefaultShortcut(moveViewLeftAction, - Konsole::ACCEL + Qt::SHIFT + Qt::Key_BracketLeft); -#else - collection->setDefaultShortcut(moveViewLeftAction, Konsole::ACCEL + Qt::SHIFT + Qt::Key_Left); -#endif - connect(moveViewLeftAction, &QAction::triggered, this, - &Konsole::ViewManager::moveActiveViewLeft); - _viewSplitter->addAction(moveViewLeftAction); - -#ifdef Q_OS_MACOS - collection->setDefaultShortcut(moveViewRightAction, - Konsole::ACCEL + Qt::SHIFT + Qt::Key_BracketRight); -#else - collection->setDefaultShortcut(moveViewRightAction, Konsole::ACCEL + Qt::SHIFT + Qt::Key_Right); -#endif - connect(moveViewRightAction, &QAction::triggered, this, - &Konsole::ViewManager::moveActiveViewRight); - _viewSplitter->addAction(moveViewRightAction); - - connect(lastViewAction, &QAction::triggered, this, &Konsole::ViewManager::lastView); - _viewSplitter->addAction(lastViewAction); - - collection->setDefaultShortcut(lastUsedViewAction, Qt::CTRL + Qt::Key_Tab); - connect(lastUsedViewAction, &QAction::triggered, this, &Konsole::ViewManager::lastUsedView); - _viewSplitter->addAction(lastUsedViewAction); - - collection->setDefaultShortcut(lastUsedViewReverseAction, Qt::CTRL + Qt::SHIFT + Qt::Key_Tab); - connect(lastUsedViewReverseAction, &QAction::triggered, this, &Konsole::ViewManager::lastUsedViewReverse); - _viewSplitter->addAction(lastUsedViewReverseAction); } void ViewManager::switchToView(int index) { - _viewSplitter->activeContainer()->setCurrentIndex(index); + _viewContainer->setCurrentIndex(index); } void ViewManager::updateDetachViewState() @@ -304,6 +253,7 @@ return; } +#if 0 const bool splitView = _viewSplitter->containers().count() >= 2; auto activeContainer = _viewSplitter->activeContainer(); const bool shouldEnable = splitView @@ -315,67 +265,77 @@ if ((detachAction != nullptr) && shouldEnable != detachAction->isEnabled()) { detachAction->setEnabled(shouldEnable); } +#endif +} + +void ViewManager::focusUp() +{ + _viewContainer->activeViewSplitter()->focusUp(); +} + +void ViewManager::focusDown() +{ + _viewContainer->activeViewSplitter()->focusDown(); +} + +void ViewManager::focusLeft() +{ + _viewContainer->activeViewSplitter()->focusLeft(); +} + +void ViewManager::focusRight() +{ + _viewContainer->activeViewSplitter()->focusRight(); } void ViewManager::moveActiveViewLeft() { - TabbedViewContainer *container = _viewSplitter->activeContainer(); - Q_ASSERT(container); - container->moveActiveView(TabbedViewContainer::MoveViewLeft); + _viewContainer->moveActiveView(TabbedViewContainer::MoveViewLeft); } void ViewManager::moveActiveViewRight() { - TabbedViewContainer *container = _viewSplitter->activeContainer(); - Q_ASSERT(container); - container->moveActiveView(TabbedViewContainer::MoveViewRight); + _viewContainer->moveActiveView(TabbedViewContainer::MoveViewRight); } void ViewManager::nextContainer() { - _viewSplitter->activateNextContainer(); +// _viewSplitter->activateNextContainer(); } void ViewManager::nextView() { - TabbedViewContainer *container = _viewSplitter->activeContainer(); - Q_ASSERT(container); - container->activateNextView(); + _viewContainer->activateNextView(); } void ViewManager::previousView() { - TabbedViewContainer *container = _viewSplitter->activeContainer(); - Q_ASSERT(container); - container->activatePreviousView(); + _viewContainer->activatePreviousView(); } void ViewManager::lastView() { - TabbedViewContainer *container = _viewSplitter->activeContainer(); - Q_ASSERT(container); - container->activateLastView(); + _viewContainer->activateLastView(); } void ViewManager::lastUsedView() { - TabbedViewContainer *container = _viewSplitter->activeContainer(); - Q_ASSERT(container); - container->activateLastUsedView(false); + _viewContainer->activateLastUsedView(false); } void ViewManager::lastUsedViewReverse() { - TabbedViewContainer *container = _viewSplitter->activeContainer(); - Q_ASSERT(container); - container->activateLastUsedView(true); + _viewContainer->activateLastUsedView(true); } void ViewManager::detachActiveView() { + //TODO: Disable Detach temporarely. +#if 0 // find the currently active view and remove it from its container TabbedViewContainer *container = _viewSplitter->activeContainer(); detachView(container, container->currentWidget()); +#endif } void ViewManager::detachView(TabbedViewContainer *container, QWidget *view) @@ -406,32 +366,33 @@ // if the container from which the view was removed is now empty then it can be deleted, // unless it is the only container in the window, in which case it is left empty // so that there is always an active container +//TODO: Verify if this is correct. +#if 0 if (_viewSplitter->containers().count() > 1 && container->count() == 0) { removeContainer(container); } +#endif } void ViewManager::sessionFinished() { // if this slot is called after the view manager's main widget // has been destroyed, do nothing - if (_viewSplitter.isNull()) { + if (_viewContainer.isNull()) { return; } auto *session = qobject_cast(sender()); Q_ASSERT(session); - // close attached views - QList children = _viewSplitter->findChildren(); + auto view = _sessionMap.key(session); + _sessionMap.remove(view); - foreach (TerminalDisplay *view, children) { - if (_sessionMap[view] == session) { - _sessionMap.remove(view); - view->deleteLater(); - } - } + // Before deleting the view, let's unmaximize if it's maximized. + auto splitter = qobject_cast(view->parentWidget()); + splitter->getToplevelSplitter()->restoreOtherTerminals(); + view->deleteLater(); // Only remove the controller from factory() if it's actually controlling // the session from the sender. @@ -441,8 +402,21 @@ // order to prevent BUG: 185466 - disappearing menu popup emit unplugController(_pluggedController); } + + focusAnotherTerminal(view); } +void ViewManager::focusAnotherTerminal(TerminalDisplay *lostFocus) +{ + auto viewSplitter = _viewContainer->activeViewSplitter(); + auto terminalDisplays = viewSplitter->findChildren(); + for (auto terminalDisplay : terminalDisplays) { + if (terminalDisplay != lostFocus) { + terminalDisplay->setFocus(Qt::OtherFocusReason); + return; + } + } +} void ViewManager::viewActivated(QWidget *view) { Q_ASSERT(view != nullptr); @@ -465,38 +439,29 @@ void ViewManager::splitView(Qt::Orientation orientation) { - TabbedViewContainer *container = createContainer(); + auto viewSplitter = qobject_cast(_viewContainer->currentWidget()); - if (_viewSplitter->activeContainer()->count()) { - // get the currently applied profile and use it to create the new tab. - auto *activeContainer= _viewSplitter->activeContainer(); - auto *currentDisplay = qobject_cast(activeContainer->currentWidget()); - auto profile = SessionManager::instance()->sessionProfile(_sessionMap[currentDisplay]); + // get the currently applied profile and use it to create the new tab. + auto *currentDisplay = viewSplitter->findChild(); + auto profile = SessionManager::instance()->sessionProfile(_sessionMap[currentDisplay]); - // Create a new session with the selected profile. - auto *session = SessionManager::instance()->createSession(profile); - session->addEnvironmentEntry(QStringLiteral("KONSOLE_DBUS_WINDOW=/Windows/%1").arg(managerId())); + // Create a new session with the selected profile. + auto *session = SessionManager::instance()->createSession(profile); + session->addEnvironmentEntry(QStringLiteral("KONSOLE_DBUS_WINDOW=/Windows/%1").arg(managerId())); - createView(session, container, 0); - } + auto terminalDisplay = createView(session); - _viewSplitter->addContainer(container, orientation); - emit splitViewToggle(_viewSplitter->containers().count() > 0); + viewSplitter->addTerminalDisplay(terminalDisplay, orientation); + emit splitViewToggle(viewSplitter->count() > 0); // focus the new container - container->currentWidget()->setFocus(); - - // ensure that the active view is focused after the split / unsplit - TabbedViewContainer *activeContainer = _viewSplitter->activeContainer(); - QWidget *activeView = activeContainer != nullptr ? activeContainer->currentWidget() : nullptr; - - if (activeView != nullptr) { - activeView->setFocus(Qt::OtherFocusReason); - } + terminalDisplay->setFocus(); } void ViewManager::removeContainer(TabbedViewContainer *container) { + qDebug() << "Remove Container Called"; +#if 0 // remove session map entries for views in this container for(int i = 0, end = container->count(); i < end; i++) { auto view = container->widget(i); @@ -509,41 +474,21 @@ container->deleteLater(); emit splitViewToggle(_viewSplitter->containers().count() > 1); +#endif } void ViewManager::expandActiveContainer() { - _viewSplitter->adjustContainerSize(_viewSplitter->activeContainer(), 10); + auto activeSplitter = _viewContainer->activeViewSplitter(); + auto activeTerminalDisplay = activeSplitter->activeTerminalDisplay(); + activeSplitter->adjustTerminalDisplaySize(activeTerminalDisplay, 10); } void ViewManager::shrinkActiveContainer() { - _viewSplitter->adjustContainerSize(_viewSplitter->activeContainer(), -10); -} - -void ViewManager::closeActiveContainer() -{ - // only do something if there is more than one container active - if (_viewSplitter->containers().count() > 1) { - TabbedViewContainer *container = _viewSplitter->activeContainer(); - - removeContainer(container); - - // focus next container so that user can continue typing - // without having to manually focus it themselves - nextContainer(); - } -} - -void ViewManager::closeOtherContainers() -{ - TabbedViewContainer *active = _viewSplitter->activeContainer(); - - foreach (TabbedViewContainer *container, _viewSplitter->containers()) { - if (container != active) { - removeContainer(container); - } - } + auto activeSplitter = _viewContainer->activeViewSplitter(); + auto activeTerminalDisplay = activeSplitter->activeTerminalDisplay(); + activeSplitter->adjustTerminalDisplaySize(activeTerminalDisplay, -10); } SessionController *ViewManager::createController(Session *session, TerminalDisplay *view) @@ -576,7 +521,8 @@ return; } - _viewSplitter->setFocusProxy(controller->view()); + //TODO: Verify This. + // _viewSplitter->setFocusProxy(controller->view()); _pluggedController = controller; emit activeViewChanged(controller); @@ -587,7 +533,7 @@ return _pluggedController; } -void ViewManager::createView(Session *session, TabbedViewContainer *container, int index) +TerminalDisplay *ViewManager::createView(Session *session) { // notify this view manager when the session finishes so that its view // can be deleted @@ -607,29 +553,18 @@ createController(session, display); _sessionMap[display] = session; - container->addView(display, index); session->addView(display); // tell the session whether it has a light or dark background session->setDarkBackground(colorSchemeForProfile(profile)->hasDarkBackground()); - container->setCurrentWidget(display); display->setFocus(Qt::OtherFocusReason); - updateDetachViewState(); -} - -void ViewManager::createView(TabbedViewContainer *tabWidget, Session *session) -{ - const int index = _newTabBehavior == PutNewTabAfterCurrentTab ? - _viewSplitter->activeContainer()->currentIndex() + 1 : -1; - - createView(session, tabWidget, index); + return display; } TabbedViewContainer *ViewManager::createContainer() { - - auto *container = new TabbedViewContainer(this, _viewSplitter); + auto *container = new TabbedViewContainer(this, nullptr); container->setNavigationVisibility(_navigationVisibility); //TODO: Fix Detaching. connect(container, &TabbedViewContainer::detachTab, this, &ViewManager::detachView); @@ -661,12 +596,14 @@ void ViewManager::containerMoveViewRequest(int index, int id) { + Q_UNUSED(index); + auto *container = qobject_cast(sender()); auto *controller = qobject_cast(ViewProperties::propertiesById(id)); Q_ASSERT(container); Q_ASSERT(controller); - createView(controller->session(), container, index); + createView(controller->session()); controller->session()->refresh(); container->currentWidget()->setFocus(); } @@ -718,13 +655,13 @@ void ViewManager::containerViewsChanged(TabbedViewContainer *container) { - if ((!_viewSplitter.isNull()) && container == _viewSplitter->activeContainer()) { - emit viewPropertiesChanged(viewProperties()); - } + // TODO: Verify that this is right. + emit viewPropertiesChanged(viewProperties()); } void ViewManager::viewDestroyed(QWidget *view) { + qDebug() << "TerminalDisplay destroyed"; // Note: the received QWidget has already been destroyed, so // using dynamic_cast<> or qobject_cast<> does not work here // We only need the pointer address to look it up below @@ -740,13 +677,17 @@ } } //we only update the focus if the splitter is still alive + // TODO: Verify. +#if 0 if (!_viewSplitter.isNull()) { updateDetachViewState(); } +#endif // The below causes the menus to be messed up // Only happens when using the tab bar close button // if (_pluggedController) // emit unplugController(_pluggedController); + qDebug() << "End of view destroyed"; } TerminalDisplay *ViewManager::createTerminalDisplay(Session *session) @@ -874,18 +815,16 @@ { QList list; - TabbedViewContainer *container = _viewSplitter->activeContainer(); + TabbedViewContainer *container = _viewContainer; if (container == nullptr) { return {}; } - list.reserve(container->count()); + auto terminalContainers = _viewContainer->findChildren(); + list.reserve(terminalContainers.size()); - for(int i = 0, end = container->count(); i < end; i++) { - auto view = container->terminalAt(i); - ViewProperties *properties = view->sessionController(); - Q_ASSERT(properties); - list << properties; + for(auto terminalDisplay : _viewContainer->findChildren()) { + list.append(terminalDisplay->sessionController()); } return list; @@ -898,15 +837,17 @@ QSet unique; int tab = 1; - TabbedViewContainer *container = _viewSplitter->activeContainer(); + TabbedViewContainer *container = _viewContainer; // first: sessions in the active container, preserving the order Q_ASSERT(container); if (container == nullptr) { return; } ids.reserve(container->count()); + //TODO: Handle sessions +#if 0 auto *activeview = qobject_cast(container->currentWidget()); for (int i = 0, end = container->count(); i < end; i++) { auto *view = qobject_cast(container->widget(i)); @@ -920,6 +861,7 @@ } tab++; } +#endif // second: all other sessions, in random order // we don't want to have sessions restored that are not connected @@ -935,7 +877,7 @@ TabbedViewContainer *ViewManager::activeContainer() { - return _viewSplitter->activeContainer(); + return _viewContainer; } void ViewManager::restoreSessions(const KConfigGroup &group) @@ -955,7 +897,7 @@ break; } - createView(activeContainer(), session); + createView(session); if (!session->isRunning()) { session->run(); } @@ -965,14 +907,14 @@ } if (display != nullptr) { - _viewSplitter->activeContainer()->setCurrentWidget(display); + activeContainer()->setCurrentWidget(display); display->setFocus(Qt::OtherFocusReason); } if (ids.isEmpty()) { // Session file is unusable, start default Profile Profile::Ptr profile = ProfileManager::instance()->defaultProfile(); Session *session = SessionManager::instance()->createSession(profile); - createView(activeContainer(), session); + createView(session); if (!session->isRunning()) { session->run(); } @@ -1012,7 +954,7 @@ QHash::const_iterator i; for (i = _sessionMap.constBegin(); i != _sessionMap.constEnd(); ++i) { if (i.value()->sessionId() == sessionId) { - TabbedViewContainer *container = _viewSplitter->activeContainer(); + TabbedViewContainer *container = activeContainer(); if (container != nullptr) { container->setCurrentWidget(i.key()); } @@ -1027,7 +969,7 @@ session->addEnvironmentEntry(QStringLiteral("KONSOLE_DBUS_WINDOW=/Windows/%1").arg(managerId())); - createView(activeContainer(), session); + createView(session); session->run(); return session->sessionId(); @@ -1049,7 +991,7 @@ session->addEnvironmentEntry(QStringLiteral("KONSOLE_DBUS_WINDOW=/Windows/%1").arg(managerId())); - createView(activeContainer(), session); + createView(session); session->run(); return session->sessionId(); @@ -1072,7 +1014,7 @@ session->addEnvironmentEntry(QStringLiteral("KONSOLE_DBUS_WINDOW=/Windows/%1").arg(managerId())); - createView(activeContainer(), session); + createView(session); session->run(); return session->sessionId(); @@ -1110,18 +1052,14 @@ void ViewManager::setTabWidthToText(bool setTabWidthToText) { - for(auto container : _viewSplitter->containers()) { - container->tabBar()->setExpanding(!setTabWidthToText); - container->tabBar()->update(); - } + _viewContainer->tabBar()->setExpanding(!setTabWidthToText); + _viewContainer->tabBar()->update(); } void ViewManager::setNavigationVisibility(NavigationVisibility navigationVisibility) { if (_navigationVisibility != navigationVisibility) { _navigationVisibility = navigationVisibility; - for(auto *container : _viewSplitter->containers()) { - container->setNavigationVisibility(navigationVisibility); - } + _viewContainer->setNavigationVisibility(navigationVisibility); } } diff --git a/src/ViewSplitter.h b/src/ViewSplitter.h --- a/src/ViewSplitter.h +++ b/src/ViewSplitter.h @@ -29,7 +29,7 @@ class QFocusEvent; namespace Konsole { -class TabbedViewContainer; +class TerminalDisplay; /** * A splitter which holds a number of ViewContainer objects and allows @@ -65,10 +65,10 @@ * will be created, into which the container will * be inserted. */ - void addContainer(TabbedViewContainer *container, Qt::Orientation orientation); + void addTerminalDisplay(TerminalDisplay *terminalDisplay, Qt::Orientation orientation); /** Removes a container from the splitter. The container is not deleted. */ - void removeContainer(TabbedViewContainer *container); + void removeTerminalDisplay(TerminalDisplay *terminalDisplay); /** Returns the child ViewSplitter widget which currently has the focus */ ViewSplitter *activeSplitter(); @@ -84,25 +84,25 @@ * mySplitter->activeSplitter()->activeContainer() where mySplitter * is the ViewSplitter widget at the top of the hierarchy. */ - TabbedViewContainer *activeContainer() const; + TerminalDisplay *activeTerminalDisplay() const; - /** - * Gives the focus to the active view in the specified container + /** Makes the current TerminalDisplay expanded to 100% of the view */ - void setActiveContainer(TabbedViewContainer *container); + void maximizeCurrentTerminal(); - /** - * Returns a list of the containers held by this splitter + /** Restore the sizes of the terminals. */ - QList containers() const - { - return _containers; - } + void restoreOtherTerminals(); + + void handleMinimizeMaximize(bool maximize); + + /** returns the splitter that has no splitter as a parent. */ + ViewSplitter *getToplevelSplitter(); /** - * Gives the focus to the active view in the next container + * Gives the focus to the active view in the specified container */ - void activateNextContainer(); + void setActiveTerminalDisplay(TerminalDisplay *container); /** * Changes the size of the specified @p container by a given @p percentage. @@ -113,73 +113,19 @@ * The sizes of the remaining containers are increased or decreased * uniformly to maintain the width of the splitter. */ - void adjustContainerSize(TabbedViewContainer *container, int percentage); + void adjustTerminalDisplaySize(TerminalDisplay *container, int percentage); - /** - * Gives the focus to the active view in the previous container - */ - void activatePreviousContainer(); + void focusUp(); + void focusDown(); + void focusLeft(); + void focusRight(); - /** - * Specifies whether the view may be split recursively. - * - * If this is false, all containers will be placed into the same - * top-level splitter. Adding a container with an orientation - * which is different to that specified when adding the previous - * containers will change the orientation for all dividers - * between containers. - * - * If this is true, adding a container to the view splitter with - * an orientation different to the orientation of the previous - * area will result in the previously active container being - * replaced with a new splitter containing the active container - * and the newly added container. - */ - void setRecursiveSplitting(bool recursive); + void handleFocusDirection(Qt::Orientation orientation, int direction); - /** - * Returns whether the view may be split recursively. - * See setRecursiveSplitting() - */ - bool recursiveSplitting() const; - -Q_SIGNALS: - /** Signal emitted when the last child widget is removed from the splitter */ - void empty(ViewSplitter *splitter); - - /** - * Signal emitted when the containers held by this splitter become empty, this - * differs from the empty() signal which is only emitted when all of the containers - * are deleted. This signal is emitted even if there are still container widgets. - * - * TODO: This does not yet work recursively (ie. when splitters inside splitters have empty containers) - */ - void allContainersEmpty(); - -protected: - //virtual void focusEvent(QFocusEvent* event); + void childEvent(QChildEvent* event) override; private: - // Adds container to splitter's internal list and - // connects signals and slots - void registerContainer(TabbedViewContainer *container); - // Removes container from splitter's internal list and - // removes signals and slots - void unregisterContainer(TabbedViewContainer *container); - void updateSizes(); - -private Q_SLOTS: - // Called to indicate that a child ViewContainer is empty - void containerEmpty(TabbedViewContainer *container); - - // Called to indicate that a child ViewSplitter is empty - // (ie. all child widgets have been deleted) - void childEmpty(ViewSplitter *splitter); - -private: - QList _containers; - bool _recursiveSplitting; }; } #endif //VIEWSPLITTER_H diff --git a/src/ViewSplitter.cpp b/src/ViewSplitter.cpp --- a/src/ViewSplitter.cpp +++ b/src/ViewSplitter.cpp @@ -24,30 +24,23 @@ // Qt #include +#include // Konsole #include "ViewContainer.h" +#include "TerminalDisplay.h" using Konsole::ViewSplitter; -using Konsole::TabbedViewContainer; +using Konsole::TerminalDisplay; -ViewSplitter::ViewSplitter(QWidget *parent) : - QSplitter(parent), - _containers(QList()), - _recursiveSplitting(true) -{ -} +//TODO: Connect the TerminalDisplay destroyed signal here. -void ViewSplitter::childEmpty(ViewSplitter *splitter) +ViewSplitter::ViewSplitter(QWidget *parent) : + QSplitter(parent) { - delete splitter; - - if (count() == 0) { - emit empty(this); - } } -void ViewSplitter::adjustContainerSize(TabbedViewContainer *container, int percentage) +void ViewSplitter::adjustTerminalDisplaySize(TerminalDisplay *container, int percentage) { int containerIndex = indexOf(container); @@ -86,18 +79,6 @@ return splitter; } -void ViewSplitter::registerContainer(TabbedViewContainer *container) -{ - _containers << container; - connect(container, SIGNAL(empty(TabbedViewContainer*)), this, SLOT(containerEmpty(TabbedViewContainer*))); -} - -void ViewSplitter::unregisterContainer(TabbedViewContainer *container) -{ - _containers.removeAll(container); - disconnect(container, nullptr, this, nullptr); -} - void ViewSplitter::updateSizes() { int space; @@ -118,162 +99,153 @@ setSizes(widgetSizes); } -void ViewSplitter::setRecursiveSplitting(bool recursive) -{ - _recursiveSplitting = recursive; -} - -bool ViewSplitter::recursiveSplitting() const -{ - return _recursiveSplitting; -} - -void ViewSplitter::removeContainer(TabbedViewContainer *container) -{ - Q_ASSERT(containers().contains(container)); - - unregisterContainer(container); -} - -void ViewSplitter::addContainer(TabbedViewContainer *container, Qt::Orientation containerOrientation) +void ViewSplitter::addTerminalDisplay(TerminalDisplay *terminalDisplay, Qt::Orientation containerOrientation) { ViewSplitter *splitter = activeSplitter(); if (splitter->count() < 2 - || containerOrientation == splitter->orientation() - || !_recursiveSplitting) { - splitter->registerContainer(container); - splitter->addWidget(container); + || containerOrientation == splitter->orientation()) { + splitter->addWidget(terminalDisplay); if (splitter->orientation() != containerOrientation) { splitter->setOrientation(containerOrientation); } - splitter->updateSizes(); } else { - auto newSplitter = new ViewSplitter(this); - connect(newSplitter, &Konsole::ViewSplitter::empty, splitter, - &Konsole::ViewSplitter::childEmpty); - - TabbedViewContainer *oldContainer = splitter->activeContainer(); - const int oldContainerIndex = splitter->indexOf(oldContainer); + auto newSplitter = new ViewSplitter(); - splitter->unregisterContainer(oldContainer); - - newSplitter->registerContainer(oldContainer); - newSplitter->registerContainer(container); - - newSplitter->addWidget(oldContainer); - newSplitter->addWidget(container); + TerminalDisplay *oldTerminalDisplay = splitter->activeTerminalDisplay(); + const int oldContainerIndex = splitter->indexOf(oldTerminalDisplay); + newSplitter->addWidget(oldTerminalDisplay); + newSplitter->addWidget(terminalDisplay); newSplitter->setOrientation(containerOrientation); newSplitter->updateSizes(); newSplitter->show(); splitter->insertWidget(oldContainerIndex, newSplitter); } } -void ViewSplitter::containerEmpty(TabbedViewContainer * myContainer) +void ViewSplitter::childEvent(QChildEvent *event) { - _containers.removeAll(myContainer); - if (count() == 0) { - emit empty(this); - } + QSplitter::childEvent(event); - int children = 0; - foreach (auto container, _containers) { - children += container->count(); + if (event->removed()) { + if (count() == 0) { + deleteLater(); + } + if (!findChild()) { + deleteLater(); + } } +} - if (children == 0) { - emit allContainersEmpty(); - } +void ViewSplitter::handleFocusDirection(Qt::Orientation orientation, int direction) +{ + auto terminalDisplay = activeTerminalDisplay(); + auto activeViewSplitter = qobject_cast(terminalDisplay->parentWidget()); + auto idx = activeViewSplitter->indexOf(terminalDisplay); - // This container is no more, try to find another container to focus. - ViewSplitter *currentSplitter = activeSplitter(); - while(qobject_cast(currentSplitter->parent())) { - currentSplitter = qobject_cast(currentSplitter->parent()); - } + // Easy, the orientation of this splitter is the same as we are looking for. + if (activeViewSplitter->orientation() == orientation && + ((direction < 0 && idx > 0) || (direction > 0 && idx < activeViewSplitter->count() - 1))) { + auto nextPossibleTerminal = qobject_cast(activeViewSplitter->widget(idx + direction)); + if (nextPossibleTerminal) { + nextPossibleTerminal->setFocus(Qt::OtherFocusReason); + return; + } - for(auto tabWidget : currentSplitter->findChildren()) { - if (tabWidget != myContainer && tabWidget->count()) { - tabWidget->setCurrentIndex(0); + // element is not a terminal display but a splitter with perhaps more splitters and terminals. + // choose one element and focus it. + auto nextPossibleSplitter = qobject_cast(activeViewSplitter->widget(idx + direction)); + if (nextPossibleSplitter) { + nextPossibleTerminal = nextPossibleSplitter->findChild(); + if (nextPossibleTerminal) { + nextPossibleTerminal->setFocus(Qt::OtherFocusReason); + } + return; } + return; } -} -void ViewSplitter::activateNextContainer() -{ - TabbedViewContainer *active = activeContainer(); + // Hard, we are in a horizontal splitter or we are in the top of the vertical splitter. + // we need to get a splitter parent that we can to, following the parent chain. + ViewSplitter *parentTerminalWidget = nullptr; + ViewSplitter *oldParent = activeViewSplitter; + do { + parentTerminalWidget = qobject_cast( + parentTerminalWidget ? parentTerminalWidget->parentWidget() + : activeViewSplitter->parentWidget()); - int index = _containers.indexOf(active); + if (parentTerminalWidget) { + idx = parentTerminalWidget->indexOf(oldParent); + } + oldParent = parentTerminalWidget; + } while (parentTerminalWidget && parentTerminalWidget->orientation() != orientation); - if (index == -1) { + if (!parentTerminalWidget) { return; } - if (index == _containers.count() - 1) { - index = 0; - } else { - index++; + if ((direction < 0 && idx > 0) || (direction > 0 && idx < parentTerminalWidget->count() - 1)) { + parentTerminalWidget->widget(idx + direction)->setFocus(Qt::OtherFocusReason); } - - setActiveContainer(_containers.at(index)); } -void ViewSplitter::activatePreviousContainer() +void ViewSplitter::focusUp() { - TabbedViewContainer *active = activeContainer(); + handleFocusDirection(Qt::Vertical, -1); +} - int index = _containers.indexOf(active); +void ViewSplitter::focusDown() +{ + handleFocusDirection(Qt::Vertical, +1); +} - if (index == 0) { - index = _containers.count() - 1; - } else { - index--; - } +void ViewSplitter::focusLeft() +{ + handleFocusDirection(Qt::Horizontal, -1); +} - setActiveContainer(_containers.at(index)); +void ViewSplitter::focusRight() +{ + handleFocusDirection(Qt::Horizontal, +1); } -void ViewSplitter::setActiveContainer(TabbedViewContainer *container) +TerminalDisplay *ViewSplitter::activeTerminalDisplay() const { - QWidget *activeView = container->currentWidget(); + auto focusedWidget = qobject_cast(focusWidget()); + return focusedWidget ? focusedWidget : findChild(); +} - if (activeView != nullptr) { - activeView->setFocus(Qt::OtherFocusReason); - } +void ViewSplitter::maximizeCurrentTerminal() +{ + handleMinimizeMaximize(true); } -TabbedViewContainer *ViewSplitter::activeContainer() const +void ViewSplitter::restoreOtherTerminals() { - if (QWidget *focusW = focusWidget()) { - TabbedViewContainer *focusContainer = nullptr; - - while (focusW != nullptr) { - foreach (TabbedViewContainer *container, _containers) { - if (container == focusW) { - focusContainer = container; - break; - } - } - focusW = focusW->parentWidget(); - } + handleMinimizeMaximize(false); +} - if (focusContainer != nullptr) { - return focusContainer; +void ViewSplitter::handleMinimizeMaximize(bool maximize) +{ + auto viewSplitter = getToplevelSplitter(); + auto terminalDisplays = viewSplitter->findChildren(); + auto currentActiveTerminal = viewSplitter->activeTerminalDisplay(); + auto method = maximize ? &QWidget::hide : &QWidget::show; + for(auto terminal : terminalDisplays) { + if (Q_LIKELY(currentActiveTerminal != terminal)) { + (terminal->*method)(); } } +} - QList splitters = findChildren(); - - if (!splitters.isEmpty()) { - return splitters.last()->activeContainer(); - } else { - if (!_containers.isEmpty()) { - return _containers.last(); - } else { - return nullptr; - } +ViewSplitter *ViewSplitter::getToplevelSplitter() +{ + ViewSplitter *current = this; + while(qobject_cast(current->parentWidget())) { + current = qobject_cast(current->parentWidget()); } + return current; }