diff --git a/src/SessionManager.h b/src/SessionManager.h --- a/src/SessionManager.h +++ b/src/SessionManager.h @@ -91,6 +91,7 @@ void restoreSessions(KConfig *config); int getRestoreId(Session *session); Session *idToSession(int id); + bool isClosingAllSessions() const; Q_SIGNALS: /** @@ -132,6 +133,7 @@ QHash _sessionProfiles; QHash _sessionRuntimeProfiles; QHash _restoreMapping; + bool _isClosingAllSessions; }; /** Utility class to simplify code in SessionManager::applyProfile(). */ diff --git a/src/SessionManager.cpp b/src/SessionManager.cpp --- a/src/SessionManager.cpp +++ b/src/SessionManager.cpp @@ -45,7 +45,8 @@ _sessions(QList()), _sessionProfiles(QHash()), _sessionRuntimeProfiles(QHash()), - _restoreMapping(QHash()) + _restoreMapping(QHash()), + _isClosingAllSessions(false) { ProfileManager *profileMananger = ProfileManager::instance(); connect(profileMananger, &Konsole::ProfileManager::profileChanged, this, @@ -72,9 +73,14 @@ return theSessionManager; } +bool SessionManager::isClosingAllSessions() const +{ + return _isClosingAllSessions; +} + void SessionManager::closeAllSessions() { - // close remaining sessions + _isClosingAllSessions = true; foreach (Session *session, _sessions) { session->close(); } diff --git a/src/ViewContainer.h b/src/ViewContainer.h --- a/src/ViewContainer.h +++ b/src/ViewContainer.h @@ -81,9 +81,6 @@ /** splits the currently focused Splitter */ void splitView(TerminalDisplay *view, Qt::Orientation orientation); - /** Removes a view from the container */ - void removeView(TerminalDisplay *view); - void setTabActivity(int index, bool activity); void updateTitle(ViewProperties *item); diff --git a/src/ViewContainer.cpp b/src/ViewContainer.cpp --- a/src/ViewContainer.cpp +++ b/src/ViewContainer.cpp @@ -277,9 +277,13 @@ insertTab(index, viewSplitter, QString()); } connect(viewSplitter, &ViewSplitter::destroyed, this, &TabbedViewContainer::viewDestroyed); - foreach(TerminalDisplay* terminal, viewSplitter->findChildren()) { + auto terminalDisplays = viewSplitter->findChildren(); + foreach(TerminalDisplay* terminal, terminalDisplays) { connectTerminalDisplay(terminal); } + if (terminalDisplays.count() > 0) { + updateTitle(qobject_cast(terminalDisplays.at(0)->sessionController())); + } setCurrentIndex(index); } @@ -356,15 +360,6 @@ } } -void TabbedViewContainer::removeView(TerminalDisplay *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() { QWidget *active = currentWidget(); diff --git a/src/ViewManager.cpp b/src/ViewManager.cpp --- a/src/ViewManager.cpp +++ b/src/ViewManager.cpp @@ -468,13 +468,18 @@ auto view = _sessionMap.key(session); _sessionMap.remove(view); + if (SessionManager::instance()->isClosingAllSessions()){ + return; + } + // Before deleting the view, let's unmaximize if it's maximized. auto splitter = qobject_cast(view->parentWidget()); auto toplevelSplitter = splitter->getToplevelSplitter(); + toplevelSplitter->restoreOtherTerminals(); - _viewContainer->removeView(view); view->deleteLater(); + // Only remove the controller from factory() if it's actually controlling // the session from the sender. // This fixes BUG: 348478 - messed up menus after a detached tab is closed @@ -484,14 +489,20 @@ emit unplugController(_pluggedController); } - updateTerminalDisplayHistory(view, true); - focusAnotherTerminal(toplevelSplitter); - updateDetachViewState(); + if (_sessionMap.size() > 0) { + updateTerminalDisplayHistory(view, true); + focusAnotherTerminal(toplevelSplitter); + updateDetachViewState(); + } } void ViewManager::focusAnotherTerminal(ViewSplitter *toplevelSplitter) { auto tabTterminalDisplays = toplevelSplitter->findChildren(); + if (tabTterminalDisplays.count() == 0) { + return; + } + if (tabTterminalDisplays.count() > 1) { // Give focus to the last used terminal in this tab for (auto *historyItem : _terminalDisplayHistory) { @@ -837,88 +848,92 @@ return list; } -void ViewManager::saveSessions(KConfigGroup &group) +namespace { +QJsonObject saveSessionTerminal(TerminalDisplay *terminalDisplay) { - // find all unique session restore IDs - QList ids; - QSet unique; - int tab = 1; + QJsonObject thisTerminal; + auto terminalSession = terminalDisplay->sessionController()->session(); + const int sessionRestoreId = SessionManager::instance()->getRestoreId(terminalSession); + thisTerminal.insert(QStringLiteral("SessionRestoreId"), sessionRestoreId); + return thisTerminal; +} - TabbedViewContainer *container = _viewContainer; +QJsonObject saveSessionsRecurse(QSplitter *splitter) { + QJsonObject thisSplitter; + thisSplitter.insert( + QStringLiteral("Orientation"), + splitter->orientation() == Qt::Horizontal ? QStringLiteral("Horizontal") + : QStringLiteral("Vertical") + ); - // 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)); - Q_ASSERT(view); - - Session *session = _sessionMap[view]; - ids << SessionManager::instance()->getRestoreId(session); - unique.insert(session); - if (view == activeview) { - group.writeEntry("Active", tab); - } - tab++; - } -#endif + QJsonArray internalWidgets; + for (int i = 0; i < splitter->count(); i++) { + auto *widget = splitter->widget(i); + auto *maybeSplitter = qobject_cast(widget); + auto *maybeTerminalDisplay = qobject_cast(widget); - // second: all other sessions, in random order - // we don't want to have sessions restored that are not connected - foreach (Session *session, _sessionMap) { - if (!unique.contains(session)) { - ids << SessionManager::instance()->getRestoreId(session); - unique.insert(session); + if (maybeSplitter != nullptr) { + internalWidgets.append(saveSessionsRecurse(maybeSplitter)); + } else if (maybeTerminalDisplay) { + internalWidgets.append(saveSessionTerminal(maybeTerminalDisplay)); } } - - group.writeEntry("Sessions", ids); + thisSplitter.insert(QStringLiteral("Widgets"), internalWidgets); + return thisSplitter; } -TabbedViewContainer *ViewManager::activeContainer() +} // namespace + +void ViewManager::saveSessions(KConfigGroup &group) { - return _viewContainer; + QJsonArray rootArray; + for(int i = 0; i < _viewContainer->count(); i++) { + QSplitter *splitter = qobject_cast(_viewContainer->widget(i)); + rootArray.append(saveSessionsRecurse(splitter)); + } + + group.writeEntry("Tabs", QJsonDocument(rootArray).toJson(QJsonDocument::Compact)); + group.writeEntry("Active", _viewContainer->currentIndex()); } -void ViewManager::restoreSessions(const KConfigGroup &group) +namespace { + +ViewSplitter *restoreSessionsSplitterRecurse(const QJsonObject& jsonSplitter, ViewManager *manager) { - QList ids = group.readEntry("Sessions", QList()); - int activeTab = group.readEntry("Active", 0); - TerminalDisplay *display = nullptr; + auto splitterWidgets = jsonSplitter[QStringLiteral("Widgets")].toArray(); + auto orientation = (jsonSplitter[QStringLiteral("Orientation")].toString() == QStringLiteral("Horizontal")) + ? Qt::Horizontal : Qt::Vertical; - int tab = 1; - foreach (int id, ids) { - Session *session = SessionManager::instance()->idToSession(id); + auto *currentSplitter = new ViewSplitter(); + currentSplitter->setOrientation(orientation); - if (session == nullptr) { - qWarning() << "Unable to load session with id" << id; - // Force a creation of a default session below - ids.clear(); - break; - } + for (const auto& widgetJsonValue : splitterWidgets) { + const auto widgetJsonObject = widgetJsonValue.toObject(); + const auto sessionIterator = widgetJsonObject.constFind(QStringLiteral("SessionRestoreId")); - createView(session); - if (!session->isRunning()) { - session->run(); - } - if (tab++ == activeTab) { - display = qobject_cast(activeView()); + if (sessionIterator != widgetJsonObject.constEnd()) { + Session *session = SessionManager::instance()->idToSession(sessionIterator->toInt()); + auto newView = manager->createView(session); + currentSplitter->addWidget(newView); + } else { + auto nextSplitter = restoreSessionsSplitterRecurse(widgetJsonObject, manager); + currentSplitter->addWidget(nextSplitter); } } + return currentSplitter; +} - if (display != nullptr) { - activeContainer()->setCurrentWidget(display); - display->setFocus(Qt::OtherFocusReason); +} // namespace +void ViewManager::restoreSessions(const KConfigGroup &group) +{ + const auto tabList = group.readEntry("Tabs", QByteArray("[]")); + const auto jsonTabs = QJsonDocument::fromJson(tabList).array(); + for (const auto& jsonSplitter : jsonTabs) { + auto topLevelSplitter = restoreSessionsSplitterRecurse(jsonSplitter.toObject(), this); + _viewContainer->addSplitter(topLevelSplitter, _viewContainer->count()); } - if (ids.isEmpty()) { // Session file is unusable, start default Profile + if (jsonTabs.isEmpty()) { // Session file is unusable, start default Profile Profile::Ptr profile = ProfileManager::instance()->defaultProfile(); Session *session = SessionManager::instance()->createSession(profile); createView(session); @@ -928,6 +943,11 @@ } } +TabbedViewContainer *ViewManager::activeContainer() +{ + return _viewContainer; +} + int ViewManager::sessionCount() { return _sessionMap.size(); @@ -961,10 +981,8 @@ QHash::const_iterator i; for (i = _sessionMap.constBegin(); i != _sessionMap.constEnd(); ++i) { if (i.value()->sessionId() == sessionId) { - TabbedViewContainer *container = activeContainer(); - if (container != nullptr) { - container->setCurrentWidget(i.key()); - } + i.key()->setFocus(Qt::OtherFocusReason); + return; } } } diff --git a/src/ViewSplitter.cpp b/src/ViewSplitter.cpp --- a/src/ViewSplitter.cpp +++ b/src/ViewSplitter.cpp @@ -60,6 +60,7 @@ setSizes(containerSizes); } +// Get the first splitter that's a parent of the current focused widget. ViewSplitter *ViewSplitter::activeSplitter() { QWidget *widget = focusWidget() != nullptr ? focusWidget() : this;