diff --git a/src/Application.h b/src/Application.h --- a/src/Application.h +++ b/src/Application.h @@ -25,6 +25,7 @@ // Konsole #include "Profile.h" +#include "ViewSplitter.h" namespace Konsole { class MainWindow; @@ -69,6 +70,7 @@ private Q_SLOTS: void createWindow(Profile::Ptr profile, const QString &directory); void detachView(Session *session); + void detachTab(ViewSplitter *splitter); void toggleBackgroundInstance(); diff --git a/src/Application.cpp b/src/Application.cpp --- a/src/Application.cpp +++ b/src/Application.cpp @@ -43,6 +43,8 @@ #include "ViewManager.h" #include "SessionController.h" #include "WindowSystemInfo.h" +#include "ViewContainer.h" +#include "TerminalDisplay.h" using namespace Konsole; @@ -169,6 +171,7 @@ connect(window, &Konsole::MainWindow::newWindowRequest, this, &Konsole::Application::createWindow); connect(window, &Konsole::MainWindow::viewDetached, this, &Konsole::Application::detachView); + connect(window, &Konsole::MainWindow::tabDetached, this, &Konsole::Application::detachTab); return window; } @@ -181,13 +184,33 @@ finalizeNewMainWindow(window); } +void Application::detachTab(ViewSplitter *splitter) +{ + MainWindow *currentWindow = qobject_cast(sender()); + MainWindow *window = newMainWindow(); + ViewManager *manager = window->viewManager(); + + foreach(TerminalDisplay* terminal, splitter->getTerminalDisplays()) { + manager->attachView(terminal); + } + + manager->activeContainer()->addSplitter(splitter); + + // Since user is dragging and dropping, move dnd window to where + // the user has the cursor (correct multiple monitor setups). + window->move(QCursor::pos()); + window->resize(currentWindow->geometry().width(), currentWindow->geometry().height()); + window->show(); +} + void Application::detachView(Session *session) { MainWindow *currentWindow = qobject_cast(sender()); MainWindow *window = newMainWindow(); ViewManager *manager = window->viewManager(); - manager->createView(session); + auto view = manager->createView(session); + manager->activeContainer()->addView(view); // 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.h b/src/MainWindow.h --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -29,6 +29,7 @@ // Konsole #include "Profile.h" +#include "ViewSplitter.h" class QAction; class KActionMenu; @@ -126,6 +127,7 @@ * Emitted when a view for one session is detached from this window */ void viewDetached(Session *session); + void tabDetached(ViewSplitter *splitter); protected: // Reimplemented for internal reasons. diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -116,6 +116,8 @@ this, &Konsole::MainWindow::newTab); connect(_viewManager, &Konsole::ViewManager::viewDetached, this, &Konsole::MainWindow::viewDetached); + connect(_viewManager, &Konsole::ViewManager::tabDetached, this, + &Konsole::MainWindow::tabDetached); setCentralWidget(_viewManager->widget()); diff --git a/src/ViewContainer.h b/src/ViewContainer.h --- a/src/ViewContainer.h +++ b/src/ViewContainer.h @@ -76,6 +76,7 @@ /** Adds a new view to the container widget */ void addView(TerminalDisplay *view, int index = -1); + void addSplitter(ViewSplitter *splitter, int index = -1); /** splits the currently focused Splitter */ void splitView(TerminalDisplay *view, Qt::Orientation orientation); @@ -149,6 +150,7 @@ ViewSplitter *viewSplitterAt(int index); void connectTerminalDisplay(TerminalDisplay *view); + void disconnectTerminalDisplay(TerminalDisplay *view); Q_SIGNALS: /** Emitted when the container has no more children */ @@ -182,7 +184,7 @@ void viewRemoved(TerminalDisplay *view); /** detach the specific tab */ - void detachTab(TabbedViewContainer *self, TerminalDisplay *activeView); + void detachTab(TabbedViewContainer *self); protected: /** diff --git a/src/ViewContainer.cpp b/src/ViewContainer.cpp --- a/src/ViewContainer.cpp +++ b/src/ViewContainer.cpp @@ -87,10 +87,9 @@ connect(tabBar(), &QTabBar::customContextMenuRequested, this, &Konsole::TabbedViewContainer::openTabContextMenu); - //TODO: Fix Detach. - // connect(tabBarWidget, &DetachableTabBar::detachTab, this, [this](int idx) { - // emit detachTab(this, terminalAt(idx)); - //}); + connect(tabBarWidget, &DetachableTabBar::detachTab, this, [this](int idx) { + emit detachTab(this); + }); connect(this, &TabbedViewContainer::currentChanged, this, &TabbedViewContainer::currentTabChanged); @@ -107,14 +106,12 @@ }); #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)); } + [this] { emit detachTab(this); } ); detachAction->setObjectName(QStringLiteral("tab-detach")); - */ #endif auto editAction = _contextPopupMenu->addAction( @@ -266,6 +263,19 @@ setCurrentIndex(newIndex); } +void TabbedViewContainer::addSplitter(ViewSplitter *viewSplitter, int index) { + if (index == -1) { + index = addTab(viewSplitter, QString()); + } else { + insertTab(index, viewSplitter, QString()); + } + connect(viewSplitter, &ViewSplitter::destroyed, this, &TabbedViewContainer::viewDestroyed); + foreach(TerminalDisplay* terminal, viewSplitter->getTerminalDisplays()) { + connectTerminalDisplay(terminal); + } + setCurrentIndex(index); +} + void TabbedViewContainer::addView(TerminalDisplay *view, int index) { auto viewSplitter = new ViewSplitter(); @@ -306,6 +316,22 @@ &Konsole::TabbedViewContainer::updateActivity); } +void TabbedViewContainer::disconnectTerminalDisplay(TerminalDisplay *display) +{ + auto item = display->sessionController(); + disconnect(item, &Konsole::SessionController::focused, this, + &Konsole::TabbedViewContainer::currentSessionControllerChanged); + + disconnect(item, &Konsole::ViewProperties::titleChanged, this, + &Konsole::TabbedViewContainer::updateTitle); + + disconnect(item, &Konsole::ViewProperties::iconChanged, this, + &Konsole::TabbedViewContainer::updateIcon); + + disconnect(item, &Konsole::ViewProperties::activity, this, + &Konsole::TabbedViewContainer::updateActivity); +} + void TabbedViewContainer::viewDestroyed(QObject *view) { auto widget = static_cast(view); diff --git a/src/ViewManager.h b/src/ViewManager.h --- a/src/ViewManager.h +++ b/src/ViewManager.h @@ -191,6 +191,7 @@ */ TabbedViewContainer *activeContainer(); TerminalDisplay *createView(Session *session); + void attachView(TerminalDisplay *terminal); /** Reorder the terminal display history list */ void updateTerminalDisplayHistory(TerminalDisplay *terminalDisplay = nullptr, bool remove = false); @@ -201,6 +202,7 @@ /** Emitted when a session is detached from a view owned by this ViewManager */ void viewDetached(Session *session); + void tabDetached(ViewSplitter *splitter); /** * Emitted when the active view changes. @@ -387,7 +389,8 @@ // moved void containerMoveViewRequest(int index, int sessionControllerId); - void detachView(TabbedViewContainer *container, QWidget *view); + void detachView(TabbedViewContainer *container, QWidget *view); + void detachTab(TabbedViewContainer *container); private: Q_DISABLE_COPY(ViewManager) diff --git a/src/ViewManager.cpp b/src/ViewManager.cpp --- a/src/ViewManager.cpp +++ b/src/ViewManager.cpp @@ -386,12 +386,28 @@ 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()); + TabbedViewContainer *container = _viewContainer; + detachView(container, container->activeViewSplitter()->activeTerminalDisplay()); +} + +void ViewManager::detachTab(TabbedViewContainer *container) +{ +#if !defined(ENABLE_DETACHING) + return; #endif + auto splitter = container->activeViewSplitter()->getToplevelSplitter(); + emit tabDetached(splitter); + auto terminals = splitter->getTerminalDisplays(); + foreach(TerminalDisplay* terminal, terminals) { + auto session = _sessionMap[terminal]; + if (session != nullptr) { + disconnect(session, &Konsole::Session::finished, this, &Konsole::ViewManager::sessionFinished); + container->disconnectTerminalDisplay(terminal); + } + _sessionMap.remove(terminal); + } + removeContainer(container); } void ViewManager::detachView(TabbedViewContainer *container, QWidget *view) @@ -411,6 +427,9 @@ if (sessionToDetach == nullptr) { return; } + + disconnect(sessionToDetach, &Konsole::Session::finished, this, &Konsole::ViewManager::sessionFinished); + emit viewDetached(sessionToDetach); _sessionMap.remove(viewToDetach); @@ -598,16 +617,28 @@ return _pluggedController; } +void ViewManager::attachView(TerminalDisplay *terminal) +{ + auto session = terminal->sessionController()->session().data(); + connect(session, &Konsole::Session::finished, this, &Konsole::ViewManager::sessionFinished, + Qt::UniqueConnection); + _sessionMap[terminal] = session; + updateDetachViewState(); + if (_terminalDisplayHistory.isEmpty()) { + _terminalDisplayHistory.append(terminal); + } +} + TerminalDisplay *ViewManager::createView(Session *session) { // notify this view manager when the session finishes so that its view // can be deleted // // Use Qt::UniqueConnection to avoid duplicate connection connect(session, &Konsole::Session::finished, this, &Konsole::ViewManager::sessionFinished, Qt::UniqueConnection); - TerminalDisplay *display = createTerminalDisplay(session); + const Profile::Ptr profile = SessionManager::instance()->sessionProfile(session); applyProfileToView(display, profile); @@ -626,16 +657,15 @@ updateDetachViewState(); _terminalDisplayHistory.append(display); - return display; } TabbedViewContainer *ViewManager::createContainer() { auto *container = new TabbedViewContainer(this, nullptr); container->setNavigationVisibility(_navigationVisibility); //TODO: Fix Detaching. - connect(container, &TabbedViewContainer::detachTab, this, &ViewManager::detachView); + connect(container, &TabbedViewContainer::detachTab, this, &ViewManager::detachTab); // connect signals and slots connect(container, &Konsole::TabbedViewContainer::viewAdded, this, diff --git a/src/ViewSplitter.h b/src/ViewSplitter.h --- a/src/ViewSplitter.h +++ b/src/ViewSplitter.h @@ -26,6 +26,9 @@ #include #include +// Konsole +#include "konsoleprivate_export.h" + class QFocusEvent; namespace Konsole { @@ -43,7 +46,7 @@ * insert a new view container. * Containers can only be removed from the hierarchy by deleting them. */ -class ViewSplitter : public QSplitter +class KONSOLEPRIVATE_EXPORT ViewSplitter : public QSplitter { Q_OBJECT @@ -124,6 +127,8 @@ void childEvent(QChildEvent* event) override; + QList getTerminalDisplays(); + private: void updateSizes(); }; diff --git a/src/ViewSplitter.cpp b/src/ViewSplitter.cpp --- a/src/ViewSplitter.cpp +++ b/src/ViewSplitter.cpp @@ -213,3 +213,22 @@ } return current; } + +QList ViewSplitter::getTerminalDisplays() { + auto terminals = QList(); + auto count = this->count(); + for(int i=0; i < count; ++i) { + auto widget = this->widget(i); + + auto terminal = qobject_cast(widget); + if (terminal != nullptr) { + terminals.append(terminal); + } + auto splitter = qobject_cast(widget); + if (splitter != nullptr) { + terminals.append(splitter->getTerminalDisplays()); + } + } + + return terminals; +}