Changeset View
Changeset View
Standalone View
Standalone View
src/ViewManager.cpp
Show First 20 Lines • Show All 462 Lines • ▼ Show 20 Line(s) | 458 | { | |||
---|---|---|---|---|---|
463 | } | 463 | } | ||
464 | 464 | | |||
465 | auto *session = qobject_cast<Session *>(sender()); | 465 | auto *session = qobject_cast<Session *>(sender()); | ||
466 | Q_ASSERT(session); | 466 | Q_ASSERT(session); | ||
467 | 467 | | |||
468 | auto view = _sessionMap.key(session); | 468 | auto view = _sessionMap.key(session); | ||
469 | _sessionMap.remove(view); | 469 | _sessionMap.remove(view); | ||
470 | 470 | | |||
471 | if (SessionManager::instance()->isClosingAllSessions()){ | ||||
472 | return; | ||||
473 | } | ||||
474 | | ||||
471 | // Before deleting the view, let's unmaximize if it's maximized. | 475 | // Before deleting the view, let's unmaximize if it's maximized. | ||
472 | auto splitter = qobject_cast<ViewSplitter*>(view->parentWidget()); | 476 | auto splitter = qobject_cast<ViewSplitter*>(view->parentWidget()); | ||
473 | auto toplevelSplitter = splitter->getToplevelSplitter(); | 477 | auto toplevelSplitter = splitter->getToplevelSplitter(); | ||
478 | | ||||
474 | toplevelSplitter->restoreOtherTerminals(); | 479 | toplevelSplitter->restoreOtherTerminals(); | ||
475 | _viewContainer->removeView(view); | | |||
476 | view->deleteLater(); | 480 | view->deleteLater(); | ||
477 | 481 | | |||
482 | | ||||
478 | // Only remove the controller from factory() if it's actually controlling | 483 | // Only remove the controller from factory() if it's actually controlling | ||
479 | // the session from the sender. | 484 | // the session from the sender. | ||
480 | // This fixes BUG: 348478 - messed up menus after a detached tab is closed | 485 | // This fixes BUG: 348478 - messed up menus after a detached tab is closed | ||
481 | if ((!_pluggedController.isNull()) && (_pluggedController->session() == session)) { | 486 | if ((!_pluggedController.isNull()) && (_pluggedController->session() == session)) { | ||
482 | // This is needed to remove this controller from factory() in | 487 | // This is needed to remove this controller from factory() in | ||
483 | // order to prevent BUG: 185466 - disappearing menu popup | 488 | // order to prevent BUG: 185466 - disappearing menu popup | ||
484 | emit unplugController(_pluggedController); | 489 | emit unplugController(_pluggedController); | ||
485 | } | 490 | } | ||
486 | 491 | | |||
492 | if (_sessionMap.size() > 0) { | ||||
487 | updateTerminalDisplayHistory(view, true); | 493 | updateTerminalDisplayHistory(view, true); | ||
488 | focusAnotherTerminal(toplevelSplitter); | 494 | focusAnotherTerminal(toplevelSplitter); | ||
489 | updateDetachViewState(); | 495 | updateDetachViewState(); | ||
490 | } | 496 | } | ||
497 | } | ||||
491 | 498 | | |||
492 | void ViewManager::focusAnotherTerminal(ViewSplitter *toplevelSplitter) | 499 | void ViewManager::focusAnotherTerminal(ViewSplitter *toplevelSplitter) | ||
493 | { | 500 | { | ||
494 | auto tabTterminalDisplays = toplevelSplitter->findChildren<TerminalDisplay*>(); | 501 | auto tabTterminalDisplays = toplevelSplitter->findChildren<TerminalDisplay*>(); | ||
502 | if (tabTterminalDisplays.count() == 0) { | ||||
503 | return; | ||||
504 | } | ||||
505 | | ||||
495 | if (tabTterminalDisplays.count() > 1) { | 506 | if (tabTterminalDisplays.count() > 1) { | ||
496 | // Give focus to the last used terminal in this tab | 507 | // Give focus to the last used terminal in this tab | ||
497 | for (auto *historyItem : _terminalDisplayHistory) { | 508 | for (auto *historyItem : _terminalDisplayHistory) { | ||
498 | for (auto *terminalDisplay : tabTterminalDisplays) { | 509 | for (auto *terminalDisplay : tabTterminalDisplays) { | ||
499 | if (terminalDisplay == historyItem) { | 510 | if (terminalDisplay == historyItem) { | ||
500 | terminalDisplay->setFocus(Qt::OtherFocusReason); | 511 | terminalDisplay->setFocus(Qt::OtherFocusReason); | ||
501 | return; | 512 | return; | ||
502 | } | 513 | } | ||
▲ Show 20 Lines • Show All 329 Lines • ▼ Show 20 Line(s) | 833 | { | |||
832 | 843 | | |||
833 | for(auto terminalDisplay : _viewContainer->findChildren<TerminalDisplay*>()) { | 844 | for(auto terminalDisplay : _viewContainer->findChildren<TerminalDisplay*>()) { | ||
834 | list.append(terminalDisplay->sessionController()); | 845 | list.append(terminalDisplay->sessionController()); | ||
835 | } | 846 | } | ||
836 | 847 | | |||
837 | return list; | 848 | return list; | ||
838 | } | 849 | } | ||
839 | 850 | | |||
840 | void ViewManager::saveSessions(KConfigGroup &group) | 851 | namespace { | ||
852 | QJsonObject saveSessionTerminal(TerminalDisplay *terminalDisplay) | ||||
841 | { | 853 | { | ||
842 | // find all unique session restore IDs | 854 | QJsonObject thisTerminal; | ||
843 | QList<int> ids; | 855 | auto terminalSession = terminalDisplay->sessionController()->session(); | ||
844 | QSet<Session *> unique; | 856 | const int sessionRestoreId = SessionManager::instance()->getRestoreId(terminalSession); | ||
845 | int tab = 1; | 857 | thisTerminal.insert(QStringLiteral("SessionRestoreId"), sessionRestoreId); | ||
858 | return thisTerminal; | ||||
859 | } | ||||
846 | 860 | | |||
847 | TabbedViewContainer *container = _viewContainer; | 861 | QJsonObject saveSessionsRecurse(QSplitter *splitter) { | ||
862 | QJsonObject thisSplitter; | ||||
863 | thisSplitter.insert( | ||||
864 | QStringLiteral("Orientation"), | ||||
865 | splitter->orientation() == Qt::Horizontal ? QStringLiteral("Horizontal") | ||||
866 | : QStringLiteral("Vertical") | ||||
867 | ); | ||||
848 | 868 | | |||
849 | // first: sessions in the active container, preserving the order | 869 | QJsonArray internalWidgets; | ||
850 | Q_ASSERT(container); | 870 | for (int i = 0; i < splitter->count(); i++) { | ||
851 | if (container == nullptr) { | 871 | auto *widget = splitter->widget(i); | ||
852 | return; | 872 | auto *maybeSplitter = qobject_cast<QSplitter*>(widget); | ||
853 | } | 873 | auto *maybeTerminalDisplay = qobject_cast<TerminalDisplay*>(widget); | ||
854 | ids.reserve(container->count()); | | |||
855 | 874 | | |||
856 | //TODO: Handle sessions | 875 | if (maybeSplitter != nullptr) { | ||
857 | #if 0 | 876 | internalWidgets.append(saveSessionsRecurse(maybeSplitter)); | ||
858 | auto *activeview = qobject_cast<TerminalDisplay *>(container->currentWidget()); | 877 | } else if (maybeTerminalDisplay) { | ||
859 | for (int i = 0, end = container->count(); i < end; i++) { | 878 | internalWidgets.append(saveSessionTerminal(maybeTerminalDisplay)); | ||
860 | auto *view = qobject_cast<TerminalDisplay *>(container->widget(i)); | | |||
861 | Q_ASSERT(view); | | |||
862 | | ||||
863 | Session *session = _sessionMap[view]; | | |||
864 | ids << SessionManager::instance()->getRestoreId(session); | | |||
865 | unique.insert(session); | | |||
866 | if (view == activeview) { | | |||
867 | group.writeEntry("Active", tab); | | |||
868 | } | 879 | } | ||
869 | tab++; | | |||
870 | } | | |||
871 | #endif | | |||
872 | | ||||
873 | // second: all other sessions, in random order | | |||
874 | // we don't want to have sessions restored that are not connected | | |||
875 | foreach (Session *session, _sessionMap) { | | |||
876 | if (!unique.contains(session)) { | | |||
877 | ids << SessionManager::instance()->getRestoreId(session); | | |||
878 | unique.insert(session); | | |||
879 | } | 880 | } | ||
881 | thisSplitter.insert(QStringLiteral("Widgets"), internalWidgets); | ||||
882 | return thisSplitter; | ||||
880 | } | 883 | } | ||
881 | 884 | | |||
882 | group.writeEntry("Sessions", ids); | 885 | } // namespace | ||
883 | } | | |||
884 | 886 | | |||
885 | TabbedViewContainer *ViewManager::activeContainer() | 887 | void ViewManager::saveSessions(KConfigGroup &group) | ||
886 | { | 888 | { | ||
887 | return _viewContainer; | 889 | QJsonArray rootArray; | ||
890 | for(int i = 0; i < _viewContainer->count(); i++) { | ||||
891 | QSplitter *splitter = qobject_cast<QSplitter*>(_viewContainer->widget(i)); | ||||
892 | rootArray.append(saveSessionsRecurse(splitter)); | ||||
888 | } | 893 | } | ||
889 | 894 | | |||
890 | void ViewManager::restoreSessions(const KConfigGroup &group) | 895 | group.writeEntry("Tabs", QJsonDocument(rootArray).toJson(QJsonDocument::Compact)); | ||
891 | { | 896 | group.writeEntry("Active", _viewContainer->currentIndex()); | ||
892 | QList<int> ids = group.readEntry("Sessions", QList<int>()); | | |||
893 | int activeTab = group.readEntry("Active", 0); | | |||
894 | TerminalDisplay *display = nullptr; | | |||
895 | | ||||
896 | int tab = 1; | | |||
897 | foreach (int id, ids) { | | |||
898 | Session *session = SessionManager::instance()->idToSession(id); | | |||
899 | | ||||
900 | if (session == nullptr) { | | |||
901 | qWarning() << "Unable to load session with id" << id; | | |||
902 | // Force a creation of a default session below | | |||
903 | ids.clear(); | | |||
904 | break; | | |||
905 | } | 897 | } | ||
906 | 898 | | |||
907 | createView(session); | 899 | namespace { | ||
908 | if (!session->isRunning()) { | 900 | | ||
909 | session->run(); | 901 | ViewSplitter *restoreSessionsSplitterRecurse(const QJsonObject& jsonSplitter, ViewManager *manager) | ||
902 | { | ||||
903 | auto splitterWidgets = jsonSplitter[QStringLiteral("Widgets")].toArray(); | ||||
904 | auto orientation = (jsonSplitter[QStringLiteral("Orientation")].toString() == QStringLiteral("Horizontal")) | ||||
905 | ? Qt::Horizontal : Qt::Vertical; | ||||
906 | | ||||
907 | auto *currentSplitter = new ViewSplitter(); | ||||
908 | currentSplitter->setOrientation(orientation); | ||||
909 | | ||||
910 | for (const auto& widgetJsonValue : splitterWidgets) { | ||||
hindenburg: FYI, loop variable 'widgetJsonValue' is always a copy because the range of type 'QJsonArray'… | |||||
Having the reference of a temporary is not a problem, and considering the clazy warning on your other comment I belive this is the way to go. tcanabrava: Having the reference of a temporary is not a problem, and considering the clazy warning on your… | |||||
911 | const auto widgetJsonObject = widgetJsonValue.toObject(); | ||||
912 | const auto sessionIterator = widgetJsonObject.constFind(QStringLiteral("SessionRestoreId")); | ||||
ngraham: `w` isn't a very descriptive variable name :) | |||||
913 | | ||||
914 | if (sessionIterator != widgetJsonObject.constEnd()) { | ||||
915 | Session *session = SessionManager::instance()->idToSession(sessionIterator->toInt()); | ||||
916 | auto newView = manager->createView(session); | ||||
917 | currentSplitter->addWidget(newView); | ||||
918 | } else { | ||||
919 | auto nextSplitter = restoreSessionsSplitterRecurse(widgetJsonObject, manager); | ||||
920 | currentSplitter->addWidget(nextSplitter); | ||||
910 | } | 921 | } | ||
911 | if (tab++ == activeTab) { | | |||
912 | display = qobject_cast<TerminalDisplay *>(activeView()); | | |||
913 | } | 922 | } | ||
923 | return currentSplitter; | ||||
914 | } | 924 | } | ||
915 | 925 | | |||
916 | if (display != nullptr) { | 926 | } // namespace | ||
917 | activeContainer()->setCurrentWidget(display); | 927 | void ViewManager::restoreSessions(const KConfigGroup &group) | ||
918 | display->setFocus(Qt::OtherFocusReason); | 928 | { | ||
929 | const auto tabList = group.readEntry("Tabs", QByteArray("[]")); | ||||
930 | const auto jsonTabs = QJsonDocument::fromJson(tabList).array(); | ||||
931 | for (const auto jsonSplitter : jsonTabs) { | ||||
Missing reference in range-for with non trivial type (QJsonValue) [-Wclazy-range-loop hindenburg: Missing reference in range-for with non trivial type (QJsonValue) [-Wclazy-range-loop | |||||
That's a QJsonArray too. I'll just add the reference to the temporary. tcanabrava: That's a QJsonArray too. I'll just add the reference to the temporary. | |||||
932 | auto topLevelSplitter = restoreSessionsSplitterRecurse(jsonSplitter.toObject(), this); | ||||
933 | _viewContainer->addSplitter(topLevelSplitter, _viewContainer->count()); | ||||
919 | } | 934 | } | ||
920 | 935 | | |||
921 | if (ids.isEmpty()) { // Session file is unusable, start default Profile | 936 | if (jsonTabs.isEmpty()) { // Session file is unusable, start default Profile | ||
922 | Profile::Ptr profile = ProfileManager::instance()->defaultProfile(); | 937 | Profile::Ptr profile = ProfileManager::instance()->defaultProfile(); | ||
923 | Session *session = SessionManager::instance()->createSession(profile); | 938 | Session *session = SessionManager::instance()->createSession(profile); | ||
924 | createView(session); | 939 | createView(session); | ||
925 | if (!session->isRunning()) { | 940 | if (!session->isRunning()) { | ||
926 | session->run(); | 941 | session->run(); | ||
927 | } | 942 | } | ||
928 | } | 943 | } | ||
929 | } | 944 | } | ||
930 | 945 | | |||
946 | TabbedViewContainer *ViewManager::activeContainer() | ||||
947 | { | ||||
948 | return _viewContainer; | ||||
949 | } | ||||
950 | | ||||
931 | int ViewManager::sessionCount() | 951 | int ViewManager::sessionCount() | ||
932 | { | 952 | { | ||
933 | return _sessionMap.size(); | 953 | return _sessionMap.size(); | ||
934 | } | 954 | } | ||
935 | 955 | | |||
936 | QStringList ViewManager::sessionList() | 956 | QStringList ViewManager::sessionList() | ||
937 | { | 957 | { | ||
938 | QStringList ids; | 958 | QStringList ids; | ||
Show All 17 Lines | 969 | { | |||
956 | return -1; | 976 | return -1; | ||
957 | } | 977 | } | ||
958 | 978 | | |||
959 | void ViewManager::setCurrentSession(int sessionId) | 979 | void ViewManager::setCurrentSession(int sessionId) | ||
960 | { | 980 | { | ||
961 | QHash<TerminalDisplay *, Session *>::const_iterator i; | 981 | QHash<TerminalDisplay *, Session *>::const_iterator i; | ||
962 | for (i = _sessionMap.constBegin(); i != _sessionMap.constEnd(); ++i) { | 982 | for (i = _sessionMap.constBegin(); i != _sessionMap.constEnd(); ++i) { | ||
963 | if (i.value()->sessionId() == sessionId) { | 983 | if (i.value()->sessionId() == sessionId) { | ||
964 | TabbedViewContainer *container = activeContainer(); | 984 | i.key()->setFocus(Qt::OtherFocusReason); | ||
965 | if (container != nullptr) { | 985 | return; | ||
TODOs written in the first person are weird. Who is "I"? Also we should probably just fix this (if possible) rather than adding a new TODO to the code. ngraham: TODOs written in the first person are weird. Who is "I"?
Also we should probably just fix this… | |||||
966 | container->setCurrentWidget(i.key()); | | |||
967 | } | | |||
968 | } | 986 | } | ||
969 | } | 987 | } | ||
970 | } | 988 | } | ||
971 | 989 | | |||
972 | int ViewManager::newSession() | 990 | int ViewManager::newSession() | ||
973 | { | 991 | { | ||
974 | Profile::Ptr profile = ProfileManager::instance()->defaultProfile(); | 992 | Profile::Ptr profile = ProfileManager::instance()->defaultProfile(); | ||
975 | Session *session = SessionManager::instance()->createSession(profile); | 993 | Session *session = SessionManager::instance()->createSession(profile); | ||
▲ Show 20 Lines • Show All 130 Lines • Show Last 20 Lines |
FYI, loop variable 'widgetJsonValue' is always a copy because the range of type 'QJsonArray' does not return a reference