Merge lp:~flscogna/ubuntu-terminal-app/json-keyboard-profiles into lp:~ubuntu-terminal-dev/ubuntu-terminal-app/reboot

Proposed by Filippo Scognamiglio
Status: Merged
Approved by: Alan Pope 🍺🐧🐱 πŸ¦„
Approved revision: 50
Merged at revision: 55
Proposed branch: lp:~flscogna/ubuntu-terminal-app/json-keyboard-profiles
Merge into: lp:~ubuntu-terminal-dev/ubuntu-terminal-app/reboot
Diff against target: 1141 lines (+702/-244)
19 files modified
po/com.ubuntu.terminal.pot (+2/-18)
src/app/CMakeLists.txt (+2/-1)
src/app/fileio.cpp (+37/-0)
src/app/fileio.h (+21/-0)
src/app/main.cpp (+30/-0)
src/app/qml/KeyboardBar.qml (+113/-36)
src/app/qml/KeyboardRows/KeyboardLayout.qml (+103/-0)
src/app/qml/KeyboardRows/KeyboardRow.qml (+5/-1)
src/app/qml/KeyboardRows/Layouts/ControlKeys.json (+39/-0)
src/app/qml/KeyboardRows/Layouts/ControlKeysLayout.qml (+0/-26)
src/app/qml/KeyboardRows/Layouts/FunctionKeys.json (+98/-0)
src/app/qml/KeyboardRows/Layouts/FunctionKeysLayout.qml (+0/-62)
src/app/qml/KeyboardRows/Layouts/ScrollKeys.json (+77/-0)
src/app/qml/KeyboardRows/Layouts/ScrollKeysLayout.qml (+0/-50)
src/app/qml/KeyboardRows/Layouts/SimpleCommands.json (+87/-0)
src/app/qml/KeyboardRows/Layouts/SimpleCommandsLayout.qml (+0/-48)
src/app/qml/KeyboardRows/jsonParser.js (+78/-0)
src/plugin/qmltermwidget/lib/TerminalDisplay.cpp (+9/-1)
src/plugin/qmltermwidget/lib/TerminalDisplay.h (+1/-1)
To merge this branch: bzr merge lp:~flscogna/ubuntu-terminal-app/json-keyboard-profiles
Reviewer Review Type Date Requested Status
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Nicholas Skaggs (community) Needs Fixing
Alan Pope 🍺🐧🐱 πŸ¦„ (community) Approve
Stefano Verzegnassi Approve
Review via email: mp+249754@code.launchpad.net

Commit message

Enable layout customization through json profiles.

Description of the change

Enable layout customization through json profiles.

To post a comment you must log in.
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Stefano Verzegnassi (verzegnassi-stefano) wrote :

LGTM, good work Filippo!

However, as discussed on Hangouts, the only thing that could be improved is the way you get the ConfigLocation from QStandardPaths.

Some of the returning paths are confined by the AppArmor policies, so it may be worth to use QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) which, according to Qt docs[1], "returns the directory where files of type should be written to".

Tested on utopic desktop.

[1]: http://doc.qt.io/qt-5/qstandardpaths.html#standardLocations

review: Approve
Revision history for this message
Filippo Scognamiglio (flscogna) wrote :

Thank you for the review Stefano. Your solution is good, and would save the need to look in directories where we are sure there won't be anything. I will add that in the next update, thank you.

Revision history for this message
Alan Pope 🍺🐧🐱 πŸ¦„ (popey) wrote :

Tested and works well on device! Thanks!

review: Approve
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Nicholas Skaggs (nskaggs) wrote :

Filippo, your target for this needs to be the reboot series :-)

Merge into: lp:ubuntu-terminal-app

review: Needs Fixing
Revision history for this message
Filippo Scognamiglio (flscogna) wrote :

Nicholas lp:ubuntu-terminal-app is now alias for reboot, so I thought it was the same. Should I explicitly change it to /reboot?

Revision history for this message
Nicholas Skaggs (nskaggs) wrote :

Filippo, so you are right. I swore this was different before.

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) :
review: Approve (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :

FAILED: Autolanding.
Approved revid is not set in launchpad. This is most likely a launchpad issue and re-approve should fix it. There is also a chance (although a very small one) this is a permission problem of the ps-jenkins bot.
http://91.189.93.70:8080/job/ubuntu-terminal-app-autolanding/76/
Executed test runs:
    SUCCESS: http://91.189.93.70:8080/job/generic-mediumtests-utopic/2117
        deb: http://91.189.93.70:8080/job/generic-mediumtests-utopic/2117/artifact/work/output/*zip*/output.zip
    SUCCESS: http://91.189.93.70:8080/job/ubuntu-terminal-app-vivid-amd64-autolanding/8

review: Needs Fixing (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'po/com.ubuntu.terminal.pot'
--- po/com.ubuntu.terminal.pot 2015-01-17 02:02:04 +0000
+++ po/com.ubuntu.terminal.pot 2015-02-14 14:24:37 +0000
@@ -8,7 +8,7 @@
8msgstr ""8msgstr ""
9"Project-Id-Version: \n"9"Project-Id-Version: \n"
10"Report-Msgid-Bugs-To: \n"10"Report-Msgid-Bugs-To: \n"
11"POT-Creation-Date: 2015-01-17 02:58+0100\n"11"POT-Creation-Date: 2015-02-14 13:41+0100\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"14"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -53,23 +53,7 @@
53msgid "Authentication failed"53msgid "Authentication failed"
54msgstr ""54msgstr ""
5555
56#: ../src/app/qml/KeyboardBar.qml:4156#: ../src/app/qml/KeyboardBar.qml:157
57msgid "Scroll Keys"
58msgstr ""
59
60#: ../src/app/qml/KeyboardBar.qml:46
61msgid "Functions Keys"
62msgstr ""
63
64#: ../src/app/qml/KeyboardBar.qml:51
65msgid "Command Keys"
66msgstr ""
67
68#: ../src/app/qml/KeyboardBar.qml:56
69msgid "Control Keys"
70msgstr ""
71
72#: ../src/app/qml/KeyboardBar.qml:83
73msgid "Change Keyboard"57msgid "Change Keyboard"
74msgstr ""58msgstr ""
7559
7660
=== modified file 'src/app/CMakeLists.txt'
--- src/app/CMakeLists.txt 2014-10-25 04:42:31 +0000
+++ src/app/CMakeLists.txt 2015-02-14 14:24:37 +0000
@@ -1,7 +1,8 @@
1file(GLOB_RECURSE QML_SRCS *.qml *.js)1file(GLOB_RECURSE QML_SRCS *.qml *.js *.json)
22
3set(terminal_SRCS3set(terminal_SRCS
4 main.cpp4 main.cpp
5 fileio.cpp
5 ${QML_SRCS}6 ${QML_SRCS}
6)7)
78
89
=== added file 'src/app/fileio.cpp'
--- src/app/fileio.cpp 1970-01-01 00:00:00 +0000
+++ src/app/fileio.cpp 2015-02-14 14:24:37 +0000
@@ -0,0 +1,37 @@
1#include "fileio.h"
2
3FileIO::FileIO()
4{
5}
6
7bool FileIO::write(const QString& sourceUrl, const QString& data) {
8 if (sourceUrl.isEmpty())
9 return false;
10
11 QUrl url(sourceUrl);
12 QFile file(url.toLocalFile());
13 if (!file.open(QFile::WriteOnly | QFile::Truncate))
14 return false;
15
16 QTextStream out(&file);
17 out << data;
18 file.close();
19 return true;
20}
21
22QString FileIO::read(const QString& sourceUrl) {
23 if (sourceUrl.isEmpty())
24 return "";
25
26 QUrl url(sourceUrl);
27 QFile file(url.toLocalFile());
28 if (!file.open(QFile::ReadOnly))
29 return "";
30
31 QTextStream in(&file);
32 QString result = in.readAll();
33
34 file.close();
35
36 return result;
37}
038
=== added file 'src/app/fileio.h'
--- src/app/fileio.h 1970-01-01 00:00:00 +0000
+++ src/app/fileio.h 2015-02-14 14:24:37 +0000
@@ -0,0 +1,21 @@
1#ifndef FILEIO_H
2#define FILEIO_H
3
4#include <QObject>
5#include <QFile>
6#include <QTextStream>
7#include <QUrl>
8
9class FileIO : public QObject
10{
11 Q_OBJECT
12
13public:
14 FileIO();
15
16public slots:
17 bool write(const QString& sourceUrl, const QString& data);
18 QString read(const QString& sourceUrl);
19};
20
21#endif // FILEIO_H
022
=== modified file 'src/app/main.cpp'
--- src/app/main.cpp 2014-12-05 22:52:26 +0000
+++ src/app/main.cpp 2015-02-14 14:24:37 +0000
@@ -27,14 +27,32 @@
27#include <QLibrary>27#include <QLibrary>
28#include <QDir>28#include <QDir>
2929
30#include "fileio.h"
31
30#include <QDebug>32#include <QDebug>
3133
34QStringList getProfileFromDir(const QString &path) {
35 QDir layoutDir(path);
36 layoutDir.setNameFilters(QStringList("*.json"));
37
38 QStringList jsonFiles = layoutDir.entryList();
39
40 QStringList result;
41 foreach (QString s, jsonFiles) {
42 result.append(s.prepend(path));
43 }
44 return result;
45}
46
32int main(int argc, char *argv[])47int main(int argc, char *argv[])
33{48{
34 QApplication a(argc, argv);49 QApplication a(argc, argv);
35 QQuickView view;50 QQuickView view;
36 view.setResizeMode(QQuickView::SizeRootObjectToView);51 view.setResizeMode(QQuickView::SizeRootObjectToView);
3752
53 FileIO fileIO;
54 view.engine()->rootContext()->setContextProperty("fileIO", &fileIO);
55
38 // Set up import paths56 // Set up import paths
39 QStringList importPathList = view.engine()->importPathList();57 QStringList importPathList = view.engine()->importPathList();
40 // Prepend the location of the plugin in the build dir,58 // Prepend the location of the plugin in the build dir,
@@ -135,6 +153,7 @@
135153
136 view.engine()->setImportPathList(importPathList);154 view.engine()->setImportPathList(importPathList);
137155
156 QStringList keyboardLayouts;
138 // load the qml file157 // load the qml file
139 if (qmlfile.isEmpty()) {158 if (qmlfile.isEmpty()) {
140 QStringList paths = QStandardPaths::standardLocations(QStandardPaths::DataLocation);159 QStringList paths = QStandardPaths::standardLocations(QStandardPaths::DataLocation);
@@ -146,10 +165,21 @@
146 qDebug() << "Trying to load QML from:" << path + "/qml/ubuntu-terminal-app.qml";165 qDebug() << "Trying to load QML from:" << path + "/qml/ubuntu-terminal-app.qml";
147 if (fi.exists()) {166 if (fi.exists()) {
148 qmlfile = path + "/qml/ubuntu-terminal-app.qml";167 qmlfile = path + "/qml/ubuntu-terminal-app.qml";
168 keyboardLayouts << getProfileFromDir(path + "/qml/KeyboardRows/Layouts/");
149 break;169 break;
150 }170 }
151 }171 }
152 }172 }
173
174 QStringList configLocations = QStandardPaths::standardLocations(QStandardPaths::ConfigLocation);
175 foreach (const QString &path, configLocations) {
176 QString fullPath = path + "/com.ubuntu.terminal/Layouts/";
177 qDebug() << "Retrieving keyboard profiles from folder: " << fullPath;
178 keyboardLayouts << getProfileFromDir(fullPath);
179 }
180
181 view.engine()->rootContext()->setContextProperty("keyboardLayouts", keyboardLayouts);
182
153 qDebug() << "using main qml file from:" << qmlfile;183 qDebug() << "using main qml file from:" << qmlfile;
154 view.setSource(QUrl::fromLocalFile(qmlfile));184 view.setSource(QUrl::fromLocalFile(qmlfile));
155 view.show();185 view.show();
156186
=== modified file 'src/app/qml/KeyboardBar.qml'
--- src/app/qml/KeyboardBar.qml 2015-01-16 23:04:14 +0000
+++ src/app/qml/KeyboardBar.qml 2015-02-14 14:24:37 +0000
@@ -1,10 +1,116 @@
1import QtQuick 2.01import QtQuick 2.2
2import Ubuntu.Components 1.12import Ubuntu.Components 1.1
3import "KeyboardRows"3import "KeyboardRows"
44
5import "KeyboardRows/jsonParser.js" as Parser
6
5Rectangle {7Rectangle {
8 id: rootItem
6 color: "black"9 color: "black"
710
11 property int selectedLayoutIndex: 0
12
13 signal simulateCommand(string command);
14 signal simulateKey(int key, int mod);
15
16 ListModel {
17 id: layoutsList
18 }
19
20 Component {
21 id: actionComponent
22 Action {
23 property int selectIndex
24 onTriggered: rootItem.selectLayout(selectIndex);
25 }
26 }
27
28 Component {
29 id: layoutComponent
30 KeyboardLayout {
31 anchors.fill: keyboardContainer
32 enabled: false
33 visible: false
34 }
35 }
36
37 function printLayouts() {
38 for (var i = 0; i < layoutsList.count; i++) {
39 console.log(layoutsList.get(i).layout.name);
40 }
41 }
42
43 function createLayoutObject(profileUrl) {
44 var object = layoutComponent.createObject(keyboardContainer);
45 object.loadProfile(fileIO.read(profileUrl));
46 return object;
47 }
48
49 function disableLayout(index) {
50 var layoutObject = layoutsList.get(index).layout;
51 layoutObject.visible = false;
52 layoutObject.enabled = false;
53 layoutObject.z = rootItem.z;
54 layoutObject.simulateKey.disconnect(simulateKey);
55 layoutObject.simulateCommand.disconnect(simulateCommand);
56 }
57
58 function enableLayout(index) {
59 var layoutObject = layoutsList.get(index).layout;
60 layoutObject.visible = true;
61 layoutObject.enabled = true;
62 layoutObject.z = rootItem.z + 0.01;
63 layoutObject.simulateKey.connect(simulateKey);
64 layoutObject.simulateCommand.connect(simulateCommand);
65 }
66
67 function selectLayout(index) {
68 if (index < 0 || index >= layoutsList.count)
69 return;
70
71 disableLayout(selectedLayoutIndex);
72 enableLayout(index);
73 selectedLayoutIndex = index;
74 }
75
76 function dropProfiles() {
77 for (var i = 0; i < layoutsList.count; i++) {
78 layoutsList.get(i).layout.destroy();
79 }
80 layoutsList.clear();
81 }
82
83 function updateSelector() {
84 var result = [];
85 for (var i = 0; i < layoutsList.count; i++) {
86 var layoutObject = layoutsList.get(i).layout;
87 var index = i;
88 var actionObject = actionComponent.createObject(rootItem);
89
90 actionObject.text = layoutObject.short_name;
91 actionObject.description = layoutObject.name;
92 actionObject.selectIndex = i;
93
94 result.push(actionObject);
95 }
96 keyboardSelector.actions = result;
97 }
98
99 function loadProfiles() {
100 for (var i = 0; i < keyboardLayouts.length; i++) {
101 try {
102 console.log("Loading Layout:", Qt.resolvedUrl(keyboardLayouts[i]));
103 var layoutObject = createLayoutObject(Qt.resolvedUrl(keyboardLayouts[i]));
104 layoutsList.append({layout: layoutObject});
105 } catch (e) {
106 console.error("Error in profile " + keyboardLayouts[i]);
107 console.error(e);
108 }
109 }
110 updateSelector();
111 selectLayout(0);
112 }
113
8 PressFeedback {114 PressFeedback {
9 id: pressFeedbackEffect115 id: pressFeedbackEffect
10 }116 }
@@ -34,50 +140,18 @@
34 color: "black"140 color: "black"
35 }141 }
36 }142 }
37
38 actions: [
39 Action {
40 text: "SCR"
41 description: i18n.tr("Scroll Keys")
42 onTriggered: keyboardLoader.source = "KeyboardRows/Layouts/ScrollKeysLayout.qml"
43 },
44 Action {
45 text: "FN"
46 description: i18n.tr("Functions Keys")
47 onTriggered: keyboardLoader.source = "KeyboardRows/Layouts/FunctionKeysLayout.qml"
48 },
49 Action {
50 text: "CMD"
51 description: i18n.tr("Command Keys")
52 onTriggered: keyboardLoader.source = "KeyboardRows/Layouts/SimpleCommandsLayout.qml"
53 },
54 Action {
55 text: "CTRL"
56 description: i18n.tr("Control Keys")
57 onTriggered: keyboardLoader.source = "KeyboardRows/Layouts/ControlKeysLayout.qml"
58 }
59 ]
60 }143 }
61144
62 signal simulateCommand(string command);
63 signal simulateKey(int key, int mod);
64
65 onSimulateKey: pressFeedbackEffect.start();145 onSimulateKey: pressFeedbackEffect.start();
66 onSimulateCommand: pressFeedbackEffect.start();146 onSimulateCommand: pressFeedbackEffect.start();
67147
68 Loader {148 Item {
69 id: keyboardLoader149 id: keyboardContainer
70 anchors.left: keyboardSelector.right150 anchors.left: keyboardSelector.right
71 anchors.bottom: parent.bottom151 anchors.bottom: parent.bottom
72 anchors.right: parent.right152 anchors.right: parent.right
73 anchors.top: parent.top153 anchors.top: parent.top
74 source: "KeyboardRows/Layouts/ScrollKeysLayout.qml"154 height: units.gu(5)
75
76 onLoaded: {
77 item.keyHeight = parent.height
78 item.simulateKey.connect(simulateKey);
79 item.simulateCommand.connect(simulateCommand);
80 }
81155
82 Rectangle {156 Rectangle {
83 property string defaultString: i18n.tr("Change Keyboard");157 property string defaultString: i18n.tr("Change Keyboard");
@@ -112,4 +186,7 @@
112 }186 }
113 }187 }
114 }188 }
189
190 Component.onDestruction: dropProfiles();
191 Component.onCompleted: loadProfiles();
115}192}
116193
=== added file 'src/app/qml/KeyboardRows/KeyboardLayout.qml'
--- src/app/qml/KeyboardRows/KeyboardLayout.qml 1970-01-01 00:00:00 +0000
+++ src/app/qml/KeyboardRows/KeyboardLayout.qml 2015-02-14 14:24:37 +0000
@@ -0,0 +1,103 @@
1import QtQuick 2.0
2import Ubuntu.Components 1.1
3
4import "jsonParser.js" as Parser
5
6KeyboardRow {
7 id: keyboardRow
8 keyWidth: units.gu(5)
9
10 // This label is used to compute the maximum width of all the controls.
11 Label {
12 id: hiddenLabel
13 visible: false
14 }
15
16 function dropProfile() {
17 // TODO Check if this is enough and doesn't leak.
18 for (var i = 0; i < model.length; i++)
19 model[i].destroy();
20 model = [];
21 }
22
23 function createActionString(action) {
24 switch(action.type){
25 case "key":
26 return createKeyActionString(action.key, action.mod, action.text);
27 case "string":
28 return createStringActionString(action.string, action.text);
29 }
30 }
31
32 function createOtherActionsString(actions) {
33 var result = "[";
34 for (var i = 0; i < actions.length; i++) {
35 var action = actions[i];
36 result += createActionString(action);
37
38 if (i < actions.length - 1)
39 result += ",";
40 }
41
42 return result + "]";
43 }
44
45 function createKeyActionString(key, mod, text) {
46 if (["Control", "Alt", "Shift"].indexOf(mod) === -1)
47 mod = "No";
48
49 var textString = text ? "text: \"" + text + "\";" : "";
50 return "Action { " + textString + " onTriggered: simulateKey(Qt.Key_"+ key + ", Qt." + mod + "Modifier); }";
51 }
52
53 function createStringActionString(string, text) {
54 var textString = text ? "text: \"" + text + "\";" : "";
55 return "Action { " + textString + " onTriggered: simulateCommand(\"" + string + "\"); }";
56 }
57
58 function createEntryString(text, actionString, otherActionsString) {
59 var objectString = "
60 import QtQuick 2.0
61 import Ubuntu.Components 1.1
62
63 KeyModel {
64 text: \"" + text + "\"
65 mainAction: " + actionString + "\n
66 actions:" + otherActionsString +
67 "}"
68 return objectString;
69 }
70
71 function loadProfile(profileString) {
72 dropProfile();
73
74 var maxWidth = 0;
75
76 // This function might raise exceptions which are handled in KeyboardBar.qml
77 var profile = profile = Parser.parseJson(profileString);
78
79 name = profile.name;
80 short_name = profile.short_name;
81
82 var layoutModel = []
83 for (var i = 0; i < profile.buttons.length; i++) {
84 var button = profile.buttons[i];
85 var mainActionString = createActionString(button.main_action);
86
87 var otherActionsString = button.other_actions
88 ? createOtherActionsString(button.other_actions)
89 : "[]";
90
91 var entryString = createEntryString(button.main_action.text, mainActionString, otherActionsString);
92
93 layoutModel.push(Qt.createQmlObject(entryString, keyboardRow));
94
95 hiddenLabel.text = button.main_action.text;
96 maxWidth = Math.max(hiddenLabel.width, maxWidth);
97 }
98
99 keyWidth = maxWidth + units.gu(3);
100 model = layoutModel;
101 }
102 Component.onDestruction: dropProfile();
103}
0104
=== modified file 'src/app/qml/KeyboardRows/KeyboardRow.qml'
--- src/app/qml/KeyboardRows/KeyboardRow.qml 2015-01-16 23:04:14 +0000
+++ src/app/qml/KeyboardRows/KeyboardRow.qml 2015-02-14 14:24:37 +0000
@@ -3,7 +3,11 @@
33
4Rectangle {4Rectangle {
5 id: container5 id: container
6 property list<QtObject> model6
7 property string name
8 property string short_name
9
10 property var model: []
7 property real keyWidth: units.gu(5)11 property real keyWidth: units.gu(5)
8 property real keyHeight: units.gu(5)12 property real keyHeight: units.gu(5)
913
1014
=== added file 'src/app/qml/KeyboardRows/Layouts/ControlKeys.json'
--- src/app/qml/KeyboardRows/Layouts/ControlKeys.json 1970-01-01 00:00:00 +0000
+++ src/app/qml/KeyboardRows/Layouts/ControlKeys.json 2015-02-14 14:24:37 +0000
@@ -0,0 +1,39 @@
1{
2 "name" : "Control Keys",
3 "short_name" : "CTRL",
4
5 "buttons": [
6 {
7 "main_action" : {
8 "type": "key",
9 "text" : "CTRL+R",
10 "key" : "R",
11 "mod" : "Control"
12 }
13 },
14 {
15 "main_action" : {
16 "type": "key",
17 "text" : "CTRL+C",
18 "key" : "C",
19 "mod" : "Control"
20 }
21 },
22 {
23 "main_action" : {
24 "type": "key",
25 "text" : "CTRL+A",
26 "key" : "A",
27 "mod" : "Control"
28 }
29 },
30 {
31 "main_action" : {
32 "type": "key",
33 "text" : "CTRL+Z",
34 "key" : "Z",
35 "mod" : "Control"
36 }
37 }
38 ]
39}
040
=== removed file 'src/app/qml/KeyboardRows/Layouts/ControlKeysLayout.qml'
--- src/app/qml/KeyboardRows/Layouts/ControlKeysLayout.qml 2014-12-07 16:11:58 +0000
+++ src/app/qml/KeyboardRows/Layouts/ControlKeysLayout.qml 1970-01-01 00:00:00 +0000
@@ -1,26 +0,0 @@
1import QtQuick 2.0
2import Ubuntu.Components 1.1
3
4import ".."
5
6KeyboardRow {
7 keyWidth: units.gu(10)
8 model: [
9 KeyModel {
10 text: "CTRL+R"
11 mainAction: Action { onTriggered: simulateKey(Qt.Key_R, Qt.ControlModifier);}
12 },
13 KeyModel {
14 text: "CTRL+C"
15 mainAction: Action { onTriggered: simulateKey(Qt.Key_C, Qt.ControlModifier);}
16 },
17 KeyModel {
18 text: "CTRL+Z"
19 mainAction: Action { onTriggered: simulateKey(Qt.Key_Z, Qt.ControlModifier);}
20 },
21 KeyModel {
22 text: "CTRL+A"
23 mainAction: Action { onTriggered: simulateKey(Qt.Key_A, Qt.ControlModifier);}
24 }
25 ]
26}
270
=== added file 'src/app/qml/KeyboardRows/Layouts/FunctionKeys.json'
--- src/app/qml/KeyboardRows/Layouts/FunctionKeys.json 1970-01-01 00:00:00 +0000
+++ src/app/qml/KeyboardRows/Layouts/FunctionKeys.json 2015-02-14 14:24:37 +0000
@@ -0,0 +1,98 @@
1{
2 "name" : "Function Keys",
3 "short_name" : "FNS",
4
5 "buttons": [
6 {
7 "main_action" : {
8 "type": "key",
9 "text" : "ESC",
10 "key" : "Escape"
11 }
12 },
13 {
14 "main_action" : {
15 "type": "key",
16 "text" : "F1",
17 "key" : "F1"
18 }
19 },
20 {
21 "main_action" : {
22 "type": "key",
23 "text" : "F2",
24 "key" : "F2"
25 }
26 },
27 {
28 "main_action" : {
29 "type": "key",
30 "text" : "F3",
31 "key" : "F3"
32 }
33 },
34 {
35 "main_action" : {
36 "type": "key",
37 "text" : "F4",
38 "key" : "F4"
39 }
40 },
41 {
42 "main_action" : {
43 "type": "key",
44 "text" : "F5",
45 "key" : "F5"
46 }
47 },
48 {
49 "main_action" : {
50 "type": "key",
51 "text" : "F6",
52 "key" : "F6"
53 }
54 },
55 {
56 "main_action" : {
57 "type": "key",
58 "text" : "F7",
59 "key" : "F7"
60 }
61 },
62 {
63 "main_action" : {
64 "type": "key",
65 "text" : "F8",
66 "key" : "F8"
67 }
68 },
69 {
70 "main_action" : {
71 "type": "key",
72 "text" : "F9",
73 "key" : "F9"
74 }
75 },
76 {
77 "main_action" : {
78 "type": "key",
79 "text" : "F10",
80 "key" : "F10"
81 }
82 },
83 {
84 "main_action" : {
85 "type": "key",
86 "text" : "F10",
87 "key" : "F10"
88 }
89 },
90 {
91 "main_action" : {
92 "type": "key",
93 "text" : "F11",
94 "key" : "F11"
95 }
96 }
97 ]
98}
099
=== removed file 'src/app/qml/KeyboardRows/Layouts/FunctionKeysLayout.qml'
--- src/app/qml/KeyboardRows/Layouts/FunctionKeysLayout.qml 2014-12-07 16:11:58 +0000
+++ src/app/qml/KeyboardRows/Layouts/FunctionKeysLayout.qml 1970-01-01 00:00:00 +0000
@@ -1,62 +0,0 @@
1import QtQuick 2.0
2import Ubuntu.Components 1.1
3
4import ".."
5
6KeyboardRow {
7 keyWidth: units.gu(6)
8 model: [
9 KeyModel {
10 text: "ESC"
11 mainAction: Action { onTriggered: simulateKey(Qt.Key_Escape, Qt.NoModifier); }
12 },
13 KeyModel {
14 text: "F1"
15 mainAction: Action { onTriggered: simulateKey(Qt.Key_F1, Qt.NoModifier);}
16 },
17 KeyModel {
18 text: "F2"
19 mainAction: Action { onTriggered: simulateKey(Qt.Key_F2, Qt.NoModifier);}
20 },
21 KeyModel {
22 text: "F3"
23 mainAction: Action { onTriggered: simulateKey(Qt.Key_F3, Qt.NoModifier);}
24 },
25 KeyModel {
26 text: "F4"
27 mainAction: Action { onTriggered: simulateKey(Qt.Key_F4, Qt.NoModifier);}
28 },
29 KeyModel {
30 text: "F5"
31 mainAction: Action { onTriggered: simulateKey(Qt.Key_F5, Qt.NoModifier);}
32 },
33 KeyModel {
34 text: "F6"
35 mainAction: Action { onTriggered: simulateKey(Qt.Key_F6, Qt.NoModifier);}
36 },
37 KeyModel {
38 text: "F7"
39 mainAction: Action { onTriggered: simulateKey(Qt.Key_F7, Qt.NoModifier);}
40 },
41 KeyModel {
42 text: "F8"
43 mainAction: Action { onTriggered: simulateKey(Qt.Key_F8, Qt.NoModifier);}
44 },
45 KeyModel {
46 text: "F9"
47 mainAction: Action { onTriggered: simulateKey(Qt.Key_F9, Qt.NoModifier);}
48 },
49 KeyModel {
50 text: "F10"
51 mainAction: Action { onTriggered: simulateKey(Qt.Key_F10, Qt.NoModifier);}
52 },
53 KeyModel {
54 text: "F11"
55 mainAction: Action { onTriggered: simulateKey(Qt.Key_F11, Qt.NoModifier);}
56 },
57 KeyModel {
58 text: "F12"
59 mainAction: Action { onTriggered: simulateKey(Qt.Key_F12, Qt.NoModifier);}
60 }
61 ]
62}
630
=== added file 'src/app/qml/KeyboardRows/Layouts/ScrollKeys.json'
--- src/app/qml/KeyboardRows/Layouts/ScrollKeys.json 1970-01-01 00:00:00 +0000
+++ src/app/qml/KeyboardRows/Layouts/ScrollKeys.json 2015-02-14 14:24:37 +0000
@@ -0,0 +1,77 @@
1{
2 "name" : "Scroll Keys",
3 "short_name" : "SCR",
4
5 "buttons": [
6 {
7 "main_action" : {
8 "type": "key",
9 "text" : "PG_UP",
10 "key" : "PageUp"
11 }
12 },
13 {
14 "main_action" : {
15 "type": "key",
16 "text" : "PG_DN",
17 "key" : "PageDown"
18 }
19 },
20 {
21 "main_action" : {
22 "type": "key",
23 "text" : "DEL",
24 "key" : "Delete"
25 }
26 },
27 {
28 "main_action" : {
29 "type": "key",
30 "text" : "HOME",
31 "key" : "Home"
32 }
33 },
34 {
35 "main_action" : {
36 "type": "key",
37 "text" : "END",
38 "key" : "End"
39 }
40 },
41 {
42 "main_action" : {
43 "type": "key",
44 "text" : "TAB",
45 "key" : "Tab"
46 }
47 },
48 {
49 "main_action" : {
50 "type": "key",
51 "text" : "\u2191",
52 "key" : "Up"
53 }
54 },
55 {
56 "main_action" : {
57 "type": "key",
58 "text" : "\u2193",
59 "key" : "Down"
60 }
61 },
62 {
63 "main_action" : {
64 "type": "key",
65 "text" : "\u2190",
66 "key" : "Left"
67 }
68 },
69 {
70 "main_action" : {
71 "type": "key",
72 "text" : "\u2192",
73 "key" : "Right"
74 }
75 }
76 ]
77}
078
=== removed file 'src/app/qml/KeyboardRows/Layouts/ScrollKeysLayout.qml'
--- src/app/qml/KeyboardRows/Layouts/ScrollKeysLayout.qml 2014-12-07 16:11:58 +0000
+++ src/app/qml/KeyboardRows/Layouts/ScrollKeysLayout.qml 1970-01-01 00:00:00 +0000
@@ -1,50 +0,0 @@
1import QtQuick 2.0
2import Ubuntu.Components 1.1
3
4import ".."
5
6KeyboardRow {
7 keyWidth: units.gu(8)
8 model: [
9 KeyModel {
10 text: "PG_UP"
11 mainAction: Action { onTriggered: simulateKey(Qt.Key_PageUp, Qt.NoModifier); }
12 },
13 KeyModel {
14 text: "PG_DN"
15 mainAction: Action { onTriggered: simulateKey(Qt.Key_PageDown, Qt.NoModifier); }
16 },
17 KeyModel {
18 text: "DEL"
19 mainAction: Action { onTriggered: simulateKey(Qt.Key_Delete, Qt.NoModifier); }
20 },
21 KeyModel {
22 text: "HOME"
23 mainAction: Action { onTriggered: simulateKey(Qt.Key_Home, Qt.NoModifier); }
24 },
25 KeyModel {
26 text: "END"
27 mainAction: Action { onTriggered: simulateKey(Qt.Key_End, Qt.NoModifier); }
28 },
29 KeyModel {
30 text: "TAB"
31 mainAction: Action { onTriggered: simulateKey(Qt.Key_Tab, Qt.NoModifier); }
32 },
33 KeyModel {
34 text: "\u2191"
35 mainAction: Action { onTriggered: simulateKey(Qt.Key_Up, Qt.NoModifier); }
36 },
37 KeyModel {
38 text: "\u2193"
39 mainAction: Action { onTriggered: simulateKey(Qt.Key_Down, Qt.NoModifier); }
40 },
41 KeyModel {
42 text: "\u2190"
43 mainAction: Action { onTriggered: simulateKey(Qt.Key_Left, Qt.NoModifier); }
44 },
45 KeyModel {
46 text: "\u2192"
47 mainAction: Action { onTriggered: simulateKey(Qt.Key_Right, Qt.NoModifier); }
48 }
49 ]
50}
510
=== added file 'src/app/qml/KeyboardRows/Layouts/SimpleCommands.json'
--- src/app/qml/KeyboardRows/Layouts/SimpleCommands.json 1970-01-01 00:00:00 +0000
+++ src/app/qml/KeyboardRows/Layouts/SimpleCommands.json 2015-02-14 14:24:37 +0000
@@ -0,0 +1,87 @@
1{
2 "name" : "Comamnds Key",
3 "short_name" : "CMD",
4
5 "buttons": [
6 {
7 "main_action" : {
8 "type": "string",
9 "text" : "top",
10 "string" : "top\n"
11 }
12 },
13 {
14 "main_action" : {
15 "type": "string",
16 "text" : "clear",
17 "string" : "clear\n"
18 }
19 },
20 {
21 "main_action" : {
22 "type": "string",
23 "text" : "ls",
24 "string" : "ls\n"
25 },
26 "other_actions" : [
27 {
28 "type" : "string",
29 "text" : "-l",
30 "string" : "ls -l\n"
31 },
32 {
33 "type": "string",
34 "text": "-a",
35 "string": "ls -a\n"
36 }
37 ]
38 },
39 {
40 "main_action" : {
41 "type": "string",
42 "text" : "rm",
43 "string" : "rm "
44 },
45 "other_actions" : [
46 {
47 "type" : "string",
48 "text" : "-r",
49 "string" : "rm -r "
50 }
51 ]
52 },
53 {
54 "main_action" : {
55 "type": "string",
56 "text" : "find",
57 "string" : "find "
58 },
59 "other_actions" : [
60 {
61 "type" : "string",
62 "text" : "-name",
63 "string" : "find -name "
64 }
65 ]
66 },
67 {
68 "main_action" : {
69 "type": "string",
70 "text" : "chmod",
71 "string" : "chmod "
72 },
73 "other_actions" : [
74 {
75 "type" : "string",
76 "text" : "555",
77 "string" : "chmod 555 "
78 },
79 {
80 "type": "string",
81 "text": "777",
82 "string": "chmod 777 "
83 }
84 ]
85 }
86 ]
87}
088
=== removed file 'src/app/qml/KeyboardRows/Layouts/SimpleCommandsLayout.qml'
--- src/app/qml/KeyboardRows/Layouts/SimpleCommandsLayout.qml 2014-12-07 16:46:56 +0000
+++ src/app/qml/KeyboardRows/Layouts/SimpleCommandsLayout.qml 1970-01-01 00:00:00 +0000
@@ -1,48 +0,0 @@
1import QtQuick 2.0
2import Ubuntu.Components 1.1
3
4import ".."
5
6KeyboardRow {
7 keyWidth: units.gu(8)
8 model: [
9 KeyModel {
10 text: "top"
11 mainAction: Action { onTriggered: simulateCommand("top\n"); }
12 },
13 KeyModel {
14 text: "clear"
15 mainAction: Action { onTriggered: simulateCommand("clear\n"); }
16 },
17 KeyModel {
18 text: "ls"
19 mainAction: Action { onTriggered: simulateCommand("ls\n"); }
20 actions: [
21 Action { text: "-a"; onTriggered: simulateCommand("ls -a\n"); },
22 Action { text: "-l"; onTriggered: simulateCommand("ls -l\n"); }
23 ]
24 },
25 KeyModel {
26 text: "rm"
27 mainAction: Action { onTriggered: simulateCommand("rm"); }
28 actions: [
29 Action { text: "-r"; onTriggered: simulateCommand("rm -r"); }
30 ]
31 },
32 KeyModel {
33 text: "find"
34 mainAction: Action { onTriggered: simulateCommand("find"); }
35 actions: [
36 Action { text: "-name"; onTriggered: simulateCommand("find . -name "); }
37 ]
38 },
39 KeyModel {
40 text: "chmod"
41 mainAction: Action { onTriggered: simulateCommand("chmod"); }
42 actions: [
43 Action { text: "555"; onTriggered: simulateCommand("chmod 555"); },
44 Action { text: "777"; onTriggered: simulateCommand("chmod 777"); }
45 ]
46 }
47 ]
48}
490
=== added file 'src/app/qml/KeyboardRows/jsonParser.js'
--- src/app/qml/KeyboardRows/jsonParser.js 1970-01-01 00:00:00 +0000
+++ src/app/qml/KeyboardRows/jsonParser.js 2015-02-14 14:24:37 +0000
@@ -0,0 +1,78 @@
1.pragma library
2
3// This small library prints semantic errors of bad profiles.
4
5function isAllowed(value, allowed) {
6 return allowed.indexOf(value) !== -1;
7}
8
9function raiseException(msg, obj) {
10 throw msg + "\n" + JSON.stringify(obj, null, 2);
11}
12
13function validateKeyAction(keyObject) {
14 if (!keyObject.key)
15 return raiseException("key is missing");
16 if (keyObject.mod && !isAllowed(keyObject.mod, ["Control", "Shift", "Alt"]))
17 return raiseException("mod is invalid in", keyObject);
18}
19
20function validateStringAction(stringObject) {
21 if (!stringObject.string)
22 raiseException("string is missing in", stringObject);
23}
24
25function validateAction(actionObject) {
26 if (!actionObject.type)
27 raiseException("type is missing in", actionObject);
28 if (!isAllowed(actionObject.type, ["key", "string"]))
29 raiseException("type must be either key or string in", actionObject);
30 if (!actionObject.text)
31 raiseException("text is missing in", actionObject);
32
33 switch (actionObject.type) {
34 case "key":
35 validateKeyAction(actionObject);
36 break;
37 case "string":
38 validateStringAction(actionObject);
39 break;
40 }
41}
42
43function validateButton(buttonObject) {
44 if (!buttonObject.main_action)
45 raiseException("main_action is missing", buttonObject);
46
47 validateAction(buttonObject.main_action);
48
49 var other_actions = buttonObject.other_actions;
50 if (other_actions) {
51 if (!Array.isArray(other_actions))
52 raiseException("other_actions is not an array", other_actions);
53
54 for (var i = 0; i < other_actions.length; i++) {
55 validateAction(other_actions[i]);
56 }
57 }
58}
59
60function validateLayout(layoutObject) {
61 if (!layoutObject.name)
62 raiseException("name is missing in ", layoutObject);
63 if (!layoutObject.short_name)
64 raiseException("short_name is missing in", layoutObject);
65 if (!layoutObject.buttons)
66 raiseException("buttons is missing in", layoutObject);
67
68 for (var i = 0; i < layoutObject.buttons.length; i++) {
69 validateButton(layoutObject.buttons[i]);
70 }
71}
72
73function parseJson(jsonString) {
74 var jsonObject = JSON.parse(jsonString);
75 validateLayout(jsonObject);
76
77 return jsonObject;
78}
079
=== modified file 'src/plugin/qmltermwidget/lib/TerminalDisplay.cpp'
--- src/plugin/qmltermwidget/lib/TerminalDisplay.cpp 2014-12-02 10:47:57 +0000
+++ src/plugin/qmltermwidget/lib/TerminalDisplay.cpp 2015-02-14 14:24:37 +0000
@@ -3248,9 +3248,17 @@
3248 setFillColor(cs->backgroundColor());3248 setFillColor(cs->backgroundColor());
3249}3249}
32503250
3251void TerminalDisplay::simulateKeyPress(int key, int modifiers, bool pressed, quint32 nativeScanCode, const QString &text)3251void TerminalDisplay::simulateKeyPress(int key, int modifiers, bool pressed, quint32 nativeScanCode, QString text)
3252{3252{
3253 Q_UNUSED(nativeScanCode);3253 Q_UNUSED(nativeScanCode);
3254
3255 // TODO WORKAROUND: If text is not given we try to guess it from the unicode value.
3256 // This solution is probably not complete on the domain, but works for the most common cases.
3257 if (text.isEmpty()) {
3258 bool shiftMod = modifiers & Qt::ShiftModifier;
3259 text = QString(shiftMod ? QChar(key) : QChar(key).toLower());
3260 }
3261
3254 QEvent::Type type = pressed ? QEvent::KeyPress : QEvent::KeyRelease;3262 QEvent::Type type = pressed ? QEvent::KeyPress : QEvent::KeyRelease;
3255 QKeyEvent event = QKeyEvent(type, key, (Qt::KeyboardModifier) modifiers, text);3263 QKeyEvent event = QKeyEvent(type, key, (Qt::KeyboardModifier) modifiers, text);
3256 keyPressedSignal(&event);3264 keyPressedSignal(&event);
32573265
=== modified file 'src/plugin/qmltermwidget/lib/TerminalDisplay.h'
--- src/plugin/qmltermwidget/lib/TerminalDisplay.h 2014-11-17 21:12:53 +0000
+++ src/plugin/qmltermwidget/lib/TerminalDisplay.h 2015-02-14 14:24:37 +0000
@@ -547,7 +547,7 @@
547 void setColorScheme(const QString &name);547 void setColorScheme(const QString &name);
548 QStringList availableColorSchemes();548 QStringList availableColorSchemes();
549549
550 void simulateKeyPress(int key, int modifiers, bool pressed, quint32 nativeScanCode, const QString &text);550 void simulateKeyPress(int key, int modifiers, bool pressed, quint32 nativeScanCode, QString text);
551 void simulateWheel(int x, int y, int buttons, int modifiers, QPointF angleDelta);551 void simulateWheel(int x, int y, int buttons, int modifiers, QPointF angleDelta);
552 void simulateMouseMove(int x, int y, int button, int buttons, int modifiers);552 void simulateMouseMove(int x, int y, int button, int buttons, int modifiers);
553 void simulateMousePress(int x, int y, int button, int buttons, int modifiers);553 void simulateMousePress(int x, int y, int button, int buttons, int modifiers);

Subscribers

People subscribed via source and target branches