[utilities/konsole] /: Add ability to load/save session layouts(split views) and add default layouts
Kurt Hindenburg
null at kde.org
Sat Apr 24 22:30:13 BST 2021
Git commit 29e86ddeb7b9bee1b73014a97439570dafb78f31 by Kurt Hindenburg, on behalf of Lucas Biaggi.
Committed on 24/04/2021 at 21:30.
Pushed by hindenburg into branch 'master'.
Add ability to load/save session layouts(split views) and add default layouts
Add three layouts to the toolbar; add --layout <file> to the command line.
The 3 defaults layouts are 2x2, 2x1, 1x2
GUI:
M +1 -0 data/CMakeLists.txt
A +24 -0 data/layouts/1x2-terminals.json
A +24 -0 data/layouts/2x1-terminals.json
A +27 -0 data/layouts/2x2-terminals.json
A +6 -0 data/layouts/CMakeLists.txt
M +6 -1 desktop/konsoleui.rc
M +16 -7 src/Application.cpp
M +14 -0 src/MainWindow.cpp
M +75 -4 src/ViewManager.cpp
M +5 -0 src/ViewManager.h
https://invent.kde.org/utilities/konsole/commit/29e86ddeb7b9bee1b73014a97439570dafb78f31
diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt
index b364995e..a3f8d2d8 100644
--- a/data/CMakeLists.txt
+++ b/data/CMakeLists.txt
@@ -1,5 +1,6 @@
add_subdirectory( color-schemes )
add_subdirectory( keyboard-layouts )
+add_subdirectory( layouts )
install( FILES konsole.knsrc DESTINATION ${KDE_INSTALL_KNSRCDIR})
diff --git a/data/layouts/1x2-terminals.json b/data/layouts/1x2-terminals.json
new file mode 100644
index 00000000..4762ef8d
--- /dev/null
+++ b/data/layouts/1x2-terminals.json
@@ -0,0 +1,24 @@
+{
+ "Orientation": "Vertical",
+ "Widgets": [
+ {
+ "Orientation": "Horizontal",
+ "Widgets": [
+ {
+ "SessionRestoreId": 0
+ }
+ ]
+ },
+ {
+ "Orientation": "Horizontal",
+ "Widgets": [
+ {
+ "SessionRestoreId": 0
+ },
+ {
+ "SessionRestoreId": 0
+ }
+ ]
+ }
+ ]
+}
diff --git a/data/layouts/2x1-terminals.json b/data/layouts/2x1-terminals.json
new file mode 100644
index 00000000..5de5e84e
--- /dev/null
+++ b/data/layouts/2x1-terminals.json
@@ -0,0 +1,24 @@
+{
+ "Orientation": "Vertical",
+ "Widgets": [
+ {
+ "Orientation": "Horizontal",
+ "Widgets": [
+ {
+ "SessionRestoreId": 0
+ },
+ {
+ "SessionRestoreId": 0
+ }
+ ]
+ },
+ {
+ "Orientation": "Horizontal",
+ "Widgets": [
+ {
+ "SessionRestoreId": 0
+ }
+ ]
+ }
+ ]
+}
diff --git a/data/layouts/2x2-terminals.json b/data/layouts/2x2-terminals.json
new file mode 100644
index 00000000..fbf54f87
--- /dev/null
+++ b/data/layouts/2x2-terminals.json
@@ -0,0 +1,27 @@
+{
+ "Orientation": "Vertical",
+ "Widgets": [
+ {
+ "Orientation": "Horizontal",
+ "Widgets": [
+ {
+ "SessionRestoreId": 0
+ },
+ {
+ "SessionRestoreId": 0
+ }
+ ]
+ },
+ {
+ "Orientation": "Horizontal",
+ "Widgets": [
+ {
+ "SessionRestoreId": 0
+ },
+ {
+ "SessionRestoreId": 0
+ }
+ ]
+ }
+ ]
+}
diff --git a/data/layouts/CMakeLists.txt b/data/layouts/CMakeLists.txt
new file mode 100644
index 00000000..3d912dd0
--- /dev/null
+++ b/data/layouts/CMakeLists.txt
@@ -0,0 +1,6 @@
+install (FILES
+ 1x2-terminals.json
+ 2x1-terminals.json
+ 2x2-terminals.json
+ DESTINATION
+ ${KDE_INSTALL_DATADIR}/konsole)
diff --git a/desktop/konsoleui.rc b/desktop/konsoleui.rc
index 8ff09c51..9bc62425 100644
--- a/desktop/konsoleui.rc
+++ b/desktop/konsoleui.rc
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<!DOCTYPE gui SYSTEM "kpartgui.dtd">
-<gui name="konsole" version="13">
+<gui name="konsole" version="14">
<MenuBar>
<Menu name="file"><text>File</text>
<Action name="new-window"/>
@@ -29,6 +29,8 @@
<Separator/>
<Action name="detach-tab" />
<Action name="detach-view"/>
+ <Action name="save-layout"/>
+ <Action name="load-layout"/>
<Separator/>
<DefineGroup name="session-view-operations"/>
</Menu>
@@ -53,5 +55,8 @@
<Action name="new-tab"/>
<Action name="split-view-left-right"/>
<Action name="split-view-top-bottom"/>
+ <Action name="load-terminals-layout-2x2"/>
+ <Action name="load-terminals-layout-2x1"/>
+ <Action name="load-terminals-layout-1x2"/>
</ToolBar>
</gui>
diff --git a/src/Application.cpp b/src/Application.cpp
index 9a353b38..c5a7b04a 100644
--- a/src/Application.cpp
+++ b/src/Application.cpp
@@ -51,7 +51,11 @@ void Application::populateCommandLineParser(QCommandLineParser *parser)
i18nc("@info:shell", "Name of profile to use for new Konsole instance"),
QStringLiteral("name")
},
- { { QStringLiteral("fallback-profile") },
+ { { QStringLiteral("layout") },
+ i18nc("@info:shell", "json layoutfile to be loaded to use for new Konsole instance"),
+ QStringLiteral("file")
+ },
+ { { QStringLiteral("fallback-profile") },
i18nc("@info:shell", "Use the internal FALLBACK profile")
},
{ { QStringLiteral("workdir") },
@@ -210,7 +214,6 @@ int Application::newInstance()
return 0;
}
}
-
// select profile to use
Profile::Ptr baseProfile = processProfileSelectArgs();
@@ -218,14 +221,20 @@ int Application::newInstance()
// selected profile to be changed
Profile::Ptr newProfile = processProfileChangeArgs(baseProfile);
- // create new session
- Session *session = window->createSession(newProfile, QString());
+ // if layout file is enable load it and create session from definitions,
+ // else create new session
+ if (m_parser->isSet(QStringLiteral("layout"))) {
+ window->viewManager()->loadLayout(m_parser->value(QStringLiteral("layout")));
+ } else {
+ Session *session = window->createSession(newProfile, QString());
- if (m_parser->isSet(QStringLiteral("noclose"))) {
- session->setAutoClose(false);
+ if (m_parser->isSet(QStringLiteral("noclose"))) {
+ session->setAutoClose(false);
+ }
}
- // if the background-mode argument is supplied, start the background
+
+ // if the background-mode argument is supplied, start the background
// session ( or bring to the front if it already exists )
if (m_parser->isSet(QStringLiteral("background-mode"))) {
startBackgroundMode(window);
diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp
index 4e6a4671..6774acb0 100644
--- a/src/MainWindow.cpp
+++ b/src/MainWindow.cpp
@@ -377,6 +377,20 @@ void MainWindow::setupActions()
menuAction->setText(i18nc("@item", "Activate Menu"));
collection->setDefaultShortcut(menuAction, Konsole::ACCEL | Qt::SHIFT | Qt::Key_F10);
connect(menuAction, &QAction::triggered, this, &Konsole::MainWindow::activateMenuBar);
+
+ auto action = collection->addAction(QStringLiteral("save-layout"));
+ action->setEnabled(true);
+ action->setText(i18nc("@action:inmenu", "Save tab layout to file"));
+ connect(action, &QAction::triggered, this, [this]() {
+ if (viewManager()) { viewManager()->saveLayoutFile(); }
+ });
+
+ action = collection->addAction(QStringLiteral("load-layout"));
+ action->setEnabled(true);
+ action->setText(i18nc("@action:inmenu", "Load tab layout from file"));
+ connect(action, &QAction::triggered, this, [this]() {
+ if (viewManager()) { viewManager()->loadLayoutFile(); }
+ });
}
void MainWindow::viewFullScreen(bool fullScreen)
diff --git a/src/ViewManager.cpp b/src/ViewManager.cpp
index 751684dc..856245cf 100644
--- a/src/ViewManager.cpp
+++ b/src/ViewManager.cpp
@@ -12,9 +12,17 @@
// Qt
#include <QStringList>
#include <QTabBar>
+#include <QStandardPaths>
+#include <QFile>
+#include <QFileDialog>
+
+
+#include <QJsonArray>
+#include <QJsonDocument>
// KDE
#include <KLocalizedString>
+#include <KMessageBox>
#include <KActionCollection>
#include <KConfigGroup>
@@ -113,6 +121,30 @@ void ViewManager::setupActions()
collection->setDefaultShortcut(action, Konsole::ACCEL | Qt::Key_ParenRight);
collection->addAction(QStringLiteral("split-view-top-bottom"), action);
+ action = new QAction(this);
+ action->setIcon(QIcon::fromTheme(QStringLiteral("view-split-top-bottom")));
+ action->setText(i18nc("@action:inmenu", "Load a new tab with layout 2x2 terminals"));
+ connect(action, &QAction::triggered,
+ this, [this](){
+ this->loadLayout(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("konsole/2x2-terminals.json"))); });
+ collection->addAction(QStringLiteral("load-terminals-layout-2x2"), action);
+
+ action = new QAction(this);
+ action->setIcon(QIcon::fromTheme(QStringLiteral("view-split-left-right")));
+ action->setText(i18nc("@action:inmenu", "Load a new tab with layout 2x1 terminals"));
+ connect(action, &QAction::triggered,
+ this, [this](){
+ this->loadLayout(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("konsole/2x1-terminals.json"))); });
+ collection->addAction(QStringLiteral("load-terminals-layout-2x1"), action);
+
+ action = new QAction(this);
+ action->setIcon(QIcon::fromTheme(QStringLiteral("view-split-top-bottom")));
+ action->setText(i18nc("@action:inmenu", "Load a new tab with layout 2x1 terminals"));
+ connect(action, &QAction::triggered,
+ this, [this](){
+ this->loadLayout(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("konsole/1x2-terminals.json"))); });
+ collection->addAction(QStringLiteral("load-terminals-layout-1x2"), action);
+
action = new QAction(this);
action->setText(i18nc("@action:inmenu", "Expand View"));
action->setEnabled(false);
@@ -134,6 +166,7 @@ void ViewManager::setupActions()
action->setIcon(QIcon::fromTheme(QStringLiteral("tab-detach")));
action->setText(i18nc("@action:inmenu", "Detach Current &View"));
+
connect(action, &QAction::triggered, this, &ViewManager::detachActiveView);
_multiSplitterOnlyActions << action;
@@ -895,6 +928,23 @@ QJsonObject saveSessionsRecurse(QSplitter *splitter) {
} // namespace
+void ViewManager::saveLayoutFile() {
+ QFile file(QFileDialog::getSaveFileName(this->widget(), i18n("Save File"), QStringLiteral("~/"),
+ i18n("Konsole View Layout (*.json)")));
+
+ if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ KMessageBox::sorry(this->widget(), i18n("A problem occurred when saving the Layout.\n%1", file.fileName()));
+ }
+
+ QJsonObject jsonSplit = saveSessionsRecurse(_viewContainer->activeViewSplitter());
+
+ if (!jsonSplit.isEmpty()){
+ file.write(QJsonDocument(jsonSplit).toJson());
+ qDebug() << "Maybe was saved";
+ }
+}
+
+
void ViewManager::saveSessions(KConfigGroup &group)
{
QJsonArray rootArray;
@@ -909,7 +959,7 @@ void ViewManager::saveSessions(KConfigGroup &group)
namespace {
-ViewSplitter *restoreSessionsSplitterRecurse(const QJsonObject& jsonSplitter, ViewManager *manager)
+ViewSplitter *restoreSessionsSplitterRecurse(const QJsonObject& jsonSplitter, ViewManager *manager, bool useSessionId)
{
const QJsonArray splitterWidgets = jsonSplitter[QStringLiteral("Widgets")].toArray();
auto orientation = (jsonSplitter[QStringLiteral("Orientation")].toString() == QStringLiteral("Horizontal"))
@@ -923,11 +973,14 @@ ViewSplitter *restoreSessionsSplitterRecurse(const QJsonObject& jsonSplitter, Vi
const auto sessionIterator = widgetJsonObject.constFind(QStringLiteral("SessionRestoreId"));
if (sessionIterator != widgetJsonObject.constEnd()) {
- Session *session = SessionManager::instance()->idToSession(sessionIterator->toInt());
+ Session *session = useSessionId
+ ? SessionManager::instance()->idToSession(sessionIterator->toInt())
+ : SessionManager::instance()->createSession();
+
auto newView = manager->createView(session);
currentSplitter->addWidget(newView);
} else {
- auto nextSplitter = restoreSessionsSplitterRecurse(widgetJsonObject, manager);
+ auto nextSplitter = restoreSessionsSplitterRecurse(widgetJsonObject, manager, useSessionId);
currentSplitter->addWidget(nextSplitter);
}
}
@@ -935,12 +988,30 @@ ViewSplitter *restoreSessionsSplitterRecurse(const QJsonObject& jsonSplitter, Vi
}
} // namespace
+void ViewManager::loadLayout(QString file) {
+ QFile jsonFile(file);
+
+ if (!jsonFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ KMessageBox::sorry(this->widget(), i18n("A problem occurred when loading the Layout.\n%1", jsonFile.fileName()));
+ }
+ auto json = QJsonDocument::fromJson(jsonFile.readAll());
+ if (!json.isEmpty()){
+ auto splitter = restoreSessionsSplitterRecurse(json.object(), this, false);
+ _viewContainer->addSplitter(splitter, _viewContainer->count());
+ }
+}
+void ViewManager::loadLayoutFile() {
+
+ loadLayout(QFileDialog::getOpenFileName(this->widget(), i18n("Open File"), QStringLiteral("~/"),
+ i18n("Konsole View Layout (*.json)")));
+}
+
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);
+ auto topLevelSplitter = restoreSessionsSplitterRecurse(jsonSplitter.toObject(), this, true);
_viewContainer->addSplitter(topLevelSplitter, _viewContainer->count());
}
diff --git a/src/ViewManager.h b/src/ViewManager.h
index cefa6eb2..f7cc3a09 100644
--- a/src/ViewManager.h
+++ b/src/ViewManager.h
@@ -307,6 +307,11 @@ public Q_SLOTS:
/** DBus slot that sets ALL tabs' width to match their text */
Q_SCRIPTABLE void setTabWidthToText(bool);
+ // Creates json file with split config
+ Q_SCRIPTABLE void saveLayoutFile();
+ Q_SCRIPTABLE void loadLayoutFile();
+ Q_SCRIPTABLE void loadLayout(QString File);
+
private Q_SLOTS:
// called when the "Split View Left/Right" menu item is selected
void splitLeftRight();
More information about the kde-doc-english
mailing list