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/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 @@ -145,7 +147,7 @@ * 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 +200,7 @@ void konsoleConfigChanged(); private: - void forgetView(TerminalDisplay *view); + void forgetView(ViewSplitter *view); void updateTabHistory(TerminalDisplay *view, bool remove = false); QList _tabHistory; @@ -209,6 +211,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()); + 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,24 +282,25 @@ &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); 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); } @@ -291,7 +311,7 @@ const int idx = indexOf(view); disconnect(view, &QWidget::destroyed, this, &Konsole::TabbedViewContainer::viewDestroyed); removeTab(idx); - forgetView(view); + // forgetView(view); } void TabbedViewContainer::activateNextView() @@ -387,8 +407,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 +437,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 +461,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 +534,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() 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() @@ -163,26 +144,6 @@ 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, @@ -249,52 +210,57 @@ 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); + // _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); + // _viewSplitter->addAction(previousViewAction); + + collection->setDefaultShortcut(nextContainerAction, Qt::SHIFT + Qt::CTRL + Qt::Key_Up); + connect(nextContainerAction, &QAction::triggered, this, &Konsole::ViewManager::focusUp); + _viewContainer->addAction(nextContainerAction); - collection->setDefaultShortcut(nextContainerAction, Qt::SHIFT + Qt::Key_Tab); - connect(nextContainerAction, &QAction::triggered, this, &Konsole::ViewManager::nextContainer); - _viewSplitter->addAction(nextContainerAction); + auto *action = new QAction(QStringLiteral("Focus Down")); + collection->setDefaultShortcut(action, Qt::SHIFT + Qt::CTRL + Qt::Key_Down); + connect(action, &QAction::triggered, this, &Konsole::ViewManager::focusDown); + _viewContainer->addAction(action); #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); + &Konsole::ViewManager::focusLeft); + // _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); + &Konsole::ViewManager::focusRight); + // _viewSplitter->addAction(moveViewRightAction); connect(lastViewAction, &QAction::triggered, this, &Konsole::ViewManager::lastView); - _viewSplitter->addAction(lastViewAction); + // _viewSplitter->addAction(lastViewAction); collection->setDefaultShortcut(lastUsedViewAction, Qt::CTRL + Qt::Key_Tab); connect(lastUsedViewAction, &QAction::triggered, this, &Konsole::ViewManager::lastUsedView); - _viewSplitter->addAction(lastUsedViewAction); + // _viewSplitter->addAction(lastUsedViewAction); collection->setDefaultShortcut(lastUsedViewReverseAction, Qt::CTRL + Qt::SHIFT + Qt::Key_Tab); connect(lastUsedViewReverseAction, &QAction::triggered, this, &Konsole::ViewManager::lastUsedViewReverse); - _viewSplitter->addAction(lastUsedViewReverseAction); + // _viewSplitter->addAction(lastUsedViewReverseAction); } void ViewManager::switchToView(int index) { - _viewSplitter->activeContainer()->setCurrentIndex(index); + _viewContainer->setCurrentIndex(index); } void ViewManager::updateDetachViewState() @@ -304,6 +270,7 @@ return; } +#if 0 const bool splitView = _viewSplitter->containers().count() >= 2; auto activeContainer = _viewSplitter->activeContainer(); const bool shouldEnable = splitView @@ -315,67 +282,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 +383,29 @@ // 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(); - - foreach (TerminalDisplay *view, children) { - if (_sessionMap[view] == session) { - _sessionMap.remove(view); - view->deleteLater(); - } - } + auto view = _sessionMap.key(session); + _sessionMap.remove(view); + view->deleteLater(); // Only remove the controller from factory() if it's actually controlling // the session from the sender. @@ -441,8 +415,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 +452,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 +487,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 +534,8 @@ return; } - _viewSplitter->setFocusProxy(controller->view()); + //TODO: Verify This. + // _viewSplitter->setFocusProxy(controller->view()); _pluggedController = controller; emit activeViewChanged(controller); @@ -587,7 +546,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 +566,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 +609,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 +668,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 +690,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 +828,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 +850,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 +874,7 @@ } tab++; } +#endif // second: all other sessions, in random order // we don't want to have sessions restored that are not connected @@ -935,7 +890,7 @@ TabbedViewContainer *ViewManager::activeContainer() { - return _viewSplitter->activeContainer(); + return _viewContainer; } void ViewManager::restoreSessions(const KConfigGroup &group) @@ -955,7 +910,7 @@ break; } - createView(activeContainer(), session); + createView(session); if (!session->isRunning()) { session->run(); } @@ -965,14 +920,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 +967,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 +982,7 @@ session->addEnvironmentEntry(QStringLiteral("KONSOLE_DBUS_WINDOW=/Windows/%1").arg(managerId())); - createView(activeContainer(), session); + createView(session); session->run(); return session->sessionId(); @@ -1049,7 +1004,7 @@ session->addEnvironmentEntry(QStringLiteral("KONSOLE_DBUS_WINDOW=/Windows/%1").arg(managerId())); - createView(activeContainer(), session); + createView(session); session->run(); return session->sessionId(); @@ -1072,7 +1027,7 @@ session->addEnvironmentEntry(QStringLiteral("KONSOLE_DBUS_WINDOW=/Windows/%1").arg(managerId())); - createView(activeContainer(), session); + createView(session); session->run(); return session->sessionId(); @@ -1110,18 +1065,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,17 @@ * 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 */ - void setActiveContainer(TabbedViewContainer *container); - - /** - * Returns a list of the containers held by this splitter - */ - QList containers() const - { - return _containers; - } + void setActiveTerminalDisplay(TerminalDisplay *container); /** * Gives the focus to the active view in the next container */ - void activateNextContainer(); + void activateNextTerminalDisplay(); /** * Changes the size of the specified @p container by a given @p percentage. @@ -113,73 +105,26 @@ * 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(); - - /** - * 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 activatePreviousTerminalDisplay(); - /** - * Returns whether the view may be split recursively. - * See setRecursiveSplitting() - */ - bool recursiveSplitting() const; + void focusUp(); + void focusDown(); + void focusLeft(); + void focusRight(); + void handleFocusDirection(Qt::Orientation orientation, int direction); 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); - 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; + void childDestroyed(QObject *terminalDisplay); }; } #endif //VIEWSPLITTER_H diff --git a/src/ViewSplitter.cpp b/src/ViewSplitter.cpp --- a/src/ViewSplitter.cpp +++ b/src/ViewSplitter.cpp @@ -27,27 +27,19 @@ // Konsole #include "ViewContainer.h" +#include "TerminalDisplay.h" using Konsole::ViewSplitter; -using Konsole::TabbedViewContainer; +using Konsole::TerminalDisplay; + +//TODO: Connect the TerminalDisplay destroyed signal here. ViewSplitter::ViewSplitter(QWidget *parent) : - QSplitter(parent), - _containers(QList()), - _recursiveSplitting(true) + QSplitter(parent) { } -void ViewSplitter::childEmpty(ViewSplitter *splitter) -{ - 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 +78,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 +98,154 @@ 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); } - + connect(terminalDisplay, &QObject::destroyed, this, &ViewSplitter::childDestroyed); 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(); + connect(newSplitter, &QObject::destroyed, this, &ViewSplitter::childDestroyed); + connect(terminalDisplay, &QObject::destroyed, newSplitter, &ViewSplitter::childDestroyed); - splitter->unregisterContainer(oldContainer); + TerminalDisplay *oldTerminalDisplay = splitter->activeTerminalDisplay(); + disconnect(oldTerminalDisplay, &QObject::destroyed, nullptr, nullptr); + connect(oldTerminalDisplay, &QObject::destroyed, newSplitter, &ViewSplitter::childDestroyed); - newSplitter->registerContainer(oldContainer); - newSplitter->registerContainer(container); - - newSplitter->addWidget(oldContainer); - newSplitter->addWidget(container); + 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::childDestroyed(QObject *childWidget) { - _containers.removeAll(myContainer); + // remove the parent so count() has the correct value. + childWidget->setParent(nullptr); if (count() == 0) { - emit empty(this); + deleteLater(); } +} - int children = 0; - foreach (auto container, _containers) { - children += container->count(); - } +void ViewSplitter::handleFocusDirection(Qt::Orientation orientation, int direction) +{ + auto terminalDisplay = activeTerminalDisplay(); + auto activeViewSplitter = qobject_cast(terminalDisplay->parentWidget()); + auto idx = activeViewSplitter->indexOf(terminalDisplay); - if (children == 0) { - emit allContainersEmpty(); - } + // 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; + } - // 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()); + // 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; } - for(auto tabWidget : currentSplitter->findChildren()) { - if (tabWidget != myContainer && tabWidget->count()) { - tabWidget->setCurrentIndex(0); + // 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()); + + if (parentTerminalWidget) { + idx = parentTerminalWidget->indexOf(oldParent); } + oldParent = parentTerminalWidget; + } while (parentTerminalWidget && parentTerminalWidget->orientation() != orientation); + + if (!parentTerminalWidget) { + return; + } + + if ((direction < 0 && idx > 0) || (direction > 0 && idx < parentTerminalWidget->count() - 1)) { + parentTerminalWidget->widget(idx + direction)->setFocus(Qt::OtherFocusReason); } } -void ViewSplitter::activateNextContainer() +void ViewSplitter::focusUp() { - TabbedViewContainer *active = activeContainer(); + handleFocusDirection(Qt::Vertical, -1); +} - int index = _containers.indexOf(active); +void ViewSplitter::focusDown() +{ + handleFocusDirection(Qt::Vertical, +1); +} + +void ViewSplitter::focusLeft() +{ + handleFocusDirection(Qt::Horizontal, -1); +} + +void ViewSplitter::focusRight() +{ + handleFocusDirection(Qt::Horizontal, +1); +} + +void ViewSplitter::activateNextTerminalDisplay() +{ + TerminalDisplay *active = activeTerminalDisplay(); + + int index = indexOf(active); if (index == -1) { return; } - if (index == _containers.count() - 1) { + if (index == count() - 1) { index = 0; } else { index++; } - - setActiveContainer(_containers.at(index)); + widget(index)->setFocus(Qt::OtherFocusReason); } -void ViewSplitter::activatePreviousContainer() +void ViewSplitter::activatePreviousTerminalDisplay() { - TabbedViewContainer *active = activeContainer(); + TerminalDisplay *active = activeTerminalDisplay(); - int index = _containers.indexOf(active); + int index = indexOf(active); if (index == 0) { - index = _containers.count() - 1; + index = count() - 1; } else { index--; } - - setActiveContainer(_containers.at(index)); + widget(index)->setFocus(Qt::OtherFocusReason); } -void ViewSplitter::setActiveContainer(TabbedViewContainer *container) +TerminalDisplay *ViewSplitter::activeTerminalDisplay() const { - QWidget *activeView = container->currentWidget(); - - if (activeView != nullptr) { - activeView->setFocus(Qt::OtherFocusReason); - } -} - -TabbedViewContainer *ViewSplitter::activeContainer() const -{ - if (QWidget *focusW = focusWidget()) { - TabbedViewContainer *focusContainer = nullptr; - - while (focusW != nullptr) { - foreach (TabbedViewContainer *container, _containers) { - if (container == focusW) { - focusContainer = container; - break; - } - } - focusW = focusW->parentWidget(); - } - - if (focusContainer != nullptr) { - return focusContainer; - } - } - - QList splitters = findChildren(); - - if (!splitters.isEmpty()) { - return splitters.last()->activeContainer(); - } else { - if (!_containers.isEmpty()) { - return _containers.last(); - } else { - return nullptr; - } - } + auto focusedWidget = qobject_cast(focusWidget()); + return focusedWidget ? focusedWidget : findChild(); }