on xenial help sign in
Added unity-scope-tool, which will help when developing scopes.

Approved by PS Jenkins bot, Albert Astals Cid.

commit91db876b58bc357de155a469c1480665af8f3a5e authorMichał Sawicz <michal.sawicz@canonical.com> dateMon 6 Jan 2014, 16:21 (13 years ago) parent34b8737a044623
10 files changed+457−2
CMakeLists.txt+2 data/CMakeLists.txt+3−2 data/unity-scope-tool.desktop.in+8 debian/control+9 debian/unity-scope-tool.install+3 qml/ScopeTool.qml+177 tools/CMakeLists.txt+11 tools/registry-tracker.cpp+116 tools/registry-tracker.h+44 tools/scopetool.cpp+84
CMakeLists.txt+2
@@ -96,6 +96,7 @@ include(autopilot)
9696declare_autopilot_test(shell unity8.shell ${CMAKE_SOURCE_DIR}/tests/autopilot/)
9797
9898set(SHELL_APP unity8)
99+set(SCOPE_TOOL unity-scope-tool)
99100
100101include_directories(
101102 ${CMAKE_SOURCE_DIR}/include
@@ -105,6 +106,7 @@ include_directories(
105106# add subdirectories to build
106107add_subdirectory(include)
107108add_subdirectory(src)
109+add_subdirectory(tools)
108110add_subdirectory(qml)
109111add_subdirectory(tests)
110112add_subdirectory(plugins)
data/CMakeLists.txt+3−2
@@ -1,7 +1,8 @@
11# generate desktop file
22configure_file(${SHELL_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop @ONLY)
3+configure_file(${SCOPE_TOOL}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${SCOPE_TOOL}.desktop @ONLY)
34
4−# install desktop file
5−install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop
5+# install desktop files
6+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop ${CMAKE_CURRENT_BINARY_DIR}/${SCOPE_TOOL}.desktop
67 DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
78 )
data/unity-scope-tool.desktop.innew file+8
@@ -0,0 +1,8 @@
1+[Desktop Entry]
2+Type=Application
3+Name=Unity Scope Tool
4+Comment=Developer tool for Unity scopes.
5+Exec=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@/unity-scope-tool
6+Terminal=false
7+Icon=unity-scope-tool
8+X-Ubuntu-Touch=true
debian/control+9
@@ -59,6 +59,15 @@ Depends: qmenumodel-qml (>= 0.2.7),
5959Description: Indicators client test application
6060 This package contains the client application for indicators used by autopilot
6161
62+Package: unity-scope-tool
63+Architecture: any
64+Depends: unity8 (= ${binary:Version}),
65+ ${misc:Depends},
66+ ${shlibs:Depends},
67+Description: Development tool for Unity scopes
68+ This package contains the development tool for new generation Unity scopes, based
69+ on Unity8.
70+
6271Package: unity8
6372Architecture: any
6473Provides: indicator-renderer,
debian/unity-scope-tool.installnew file+3
@@ -0,0 +1,3 @@
1+usr/bin/unity-scope-tool
2+usr/share/applications/unity-scope-tool.desktop
3+usr/share/unity8/ScopeTool.qml
qml/ScopeTool.qmlnew file+177
@@ -0,0 +1,177 @@
1+/*
2+* Copyright (C) 2013 Canonical, Ltd.
3+*
4+* This program is free software; you can redistribute it and/or modify
5+* it under the terms of the GNU General Public License as published by
6+* the Free Software Foundation; version 3.
7+*
8+* This program is distributed in the hope that it will be useful,
9+* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+* GNU General Public License for more details.
12+*
13+* You should have received a copy of the GNU General Public License
14+* along with this program. If not, see <http://www.gnu.org/licenses/>.
15+*/
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+import Ubuntu.Components.Popups 0.1
20+import Unity 0.1
21+import "Dash"
22+
23+Rectangle {
24+ id: root
25+ width: units.gu(80)
26+ height: units.gu(72)
27+ color: "#88FFFFFF"
28+
29+ // Fake shell object
30+ QtObject {
31+ id: shell
32+ }
33+
34+ // Fake greeter object
35+ QtObject {
36+ id: greeter
37+ property bool shown
38+ }
39+
40+ // Fake panel object
41+ QtObject {
42+ id: panel
43+ signal searchClicked
44+ }
45+
46+
47+ Scopes {
48+ id: scopes
49+ }
50+
51+ Rectangle {
52+ anchors.fill: scopeView
53+ color: "#FCFCFC"
54+ }
55+
56+ GenericScopeView {
57+ id: scopeView
58+
59+ anchors {
60+ top: parent.top
61+ bottom: parent.bottom
62+ left: parent.left
63+ right: controls.left
64+ }
65+
66+ scope: scopes.loaded ? scopes.get(scopeSelector.selectedIndex) : undefined
67+ }
68+
69+ Rectangle {
70+ id: controls
71+ color: "lightgrey"
72+ width: units.gu(40)
73+ anchors {
74+ top: parent.top
75+ bottom: parent.bottom
76+ right: parent.right
77+ }
78+
79+ Column {
80+ anchors { fill: parent; margins: units.gu(1) }
81+ spacing: units.gu(1)
82+
83+ Label {
84+ text: "Search query"
85+ }
86+
87+ TextField {
88+ id: searchField
89+ anchors { left: parent.left; right: parent.right }
90+
91+ onTextChanged: scopeView.scope.searchQuery = text
92+
93+ Connections {
94+ target: scopeView.scope
95+ onSearchQueryChanged: searchField.text = scopeView.scope.searchQuery
96+ }
97+ }
98+
99+ Label {
100+ text: "Scope selection"
101+ height: units.gu(4)
102+ verticalAlignment: Text.AlignBottom
103+ }
104+
105+ OptionSelector {
106+ id: scopeSelector
107+ anchors { left: parent.left; right: parent.right }
108+
109+ model: scopes
110+ delegate: OptionSelectorDelegate {
111+ text: model.title
112+ }
113+ }
114+
115+ Label {
116+ text: "Category"
117+ height: units.gu(4)
118+ verticalAlignment: Text.AlignBottom
119+ }
120+
121+ OptionSelector {
122+ id: categorySelector
123+ anchors { left: parent.left; right: parent.right }
124+ model: scopeView.scope ? scopeView.scope.categories : null
125+
126+ property Item selectedItem
127+
128+ delegate: OptionSelectorDelegate {
129+ id: categoryDelegate
130+ text: model.name
131+ property string categoryId: model.categoryId
132+ property string template: JSON.stringify(JSON.parse(model.rawRendererTemplate), null, " ");
133+
134+ onSelectedChanged: if (selected) categorySelector.selectedItem = categoryDelegate
135+ }
136+ }
137+
138+ TextArea {
139+ id: categoryJson
140+ width: parent.width
141+ autoSize: true
142+ readOnly: true
143+ text: categorySelector.selectedItem && categorySelector.selectedItem.template
144+ }
145+
146+ Button {
147+ width: parent.width
148+ text: "Override category"
149+ onClicked: {
150+ PopupUtils.open(categoryEditor)
151+ }
152+ }
153+ }
154+ }
155+
156+ Component {
157+ id: categoryEditor
158+
159+ ComposerSheet {
160+ id: sheet
161+ title: "Editing category definition"
162+
163+ TextArea {
164+ id: categoryEditorArea
165+ anchors.fill: parent
166+ wrapMode: Text.WordWrap
167+ text: categoryJson.text
168+ }
169+
170+ onCancelClicked: PopupUtils.close(sheet)
171+ onConfirmClicked: {
172+ PopupUtils.close(sheet);
173+ scopeView.scope.categories.overrideCategoryJson(categorySelector.selectedItem.categoryId, categoryEditorArea.text);
174+ }
175+ }
176+ }
177+}
tools/CMakeLists.txtnew file+11
@@ -0,0 +1,11 @@
1+add_executable(${SCOPE_TOOL}
2+ scopetool.cpp
3+ registry-tracker.cpp
4+ )
5+
6+qt5_use_modules(${SCOPE_TOOL} Qml Quick)
7+
8+# install binaries
9+install(TARGETS ${SCOPE_TOOL}
10+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
11+ )
tools/registry-tracker.cppnew file+116
@@ -0,0 +1,116 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Michal Hruby <michal.hruby@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+// Qt
21+#include <QtGlobal>
22+#include <QDir>
23+
24+// local
25+#include "registry-tracker.h"
26+
27+
28+RegistryTracker::RegistryTracker(QString const& scope_dir):
29+ m_scopeDir(scope_dir),
30+ m_registry(nullptr),
31+ m_endpoints_dir(QDir::temp().filePath("scope-dev-endpoints.XXXXXX"))
32+{
33+ runRegistry();
34+}
35+
36+RegistryTracker::~RegistryTracker()
37+{
38+ if (m_registry.state() != QProcess::NotRunning) {
39+ m_registry.terminate();
40+ m_registry.waitForFinished(5000);
41+ m_registry.kill();
42+ }
43+}
44+
45+#define RUNTIME_CONFIG \
46+"[Runtime]\n" \
47+"Registry.Identity = Registry\n" \
48+"Registry.ConfigFile = %1\n" \
49+"Default.Middleware = Zmq\n" \
50+"Zmq.ConfigFile = %2\n"
51+
52+#define REGISTRY_CONFIG \
53+"[Registry]\n" \
54+"Middleware = Zmq\n" \
55+"Zmq.Endpoint = ipc://%1/Registry\n" \
56+"Zmq.EndpointDir = %2\n" \
57+"Zmq.ConfigFile = %3\n" \
58+"Scope.InstallDir = %4\n" \
59+"Scoperunner.Path = %5\n"
60+
61+#define MW_CONFIG \
62+"[Zmq]\n" \
63+"EndpointDir.Public = %1\n" \
64+"EndpointDir.Private = %2\n"
65+
66+void RegistryTracker::runRegistry()
67+{
68+ QDir tmp(QDir::temp());
69+ m_runtime_config.setFileTemplate(tmp.filePath("Runtime.ini.XXXXXX"));
70+ m_registry_config.setFileTemplate(tmp.filePath("Registry.ini.XXXXXX"));
71+ m_mw_config.setFileTemplate(tmp.filePath("Zmq.ini.XXXXXX"));
72+
73+ if (!m_runtime_config.open() || !m_registry_config.open() || !m_mw_config.open() || !m_endpoints_dir.isValid()) {
74+ qWarning("Unable to open temporary files!");
75+ return;
76+ }
77+
78+ QString scopesLibdir;
79+ {
80+ QProcess pkg_config;
81+ QStringList arguments;
82+ arguments << "--variable=libdir";
83+ arguments << "libunity-scopes";
84+ pkg_config.start("pkg-config", arguments);
85+ pkg_config.waitForFinished();
86+ QByteArray libdir = pkg_config.readAllStandardOutput();
87+ scopesLibdir = QDir(QString::fromLocal8Bit(libdir)).path().trimmed();
88+ }
89+
90+ if (scopesLibdir.size() == 0) {
91+ qWarning("Unable to find libunity-scopes package config file");
92+ return;
93+ }
94+
95+ QString scopeRunnerPath = QDir(scopesLibdir).filePath("scoperunner/scoperunner");
96+
97+ QString runtime_ini = QString(RUNTIME_CONFIG).arg(m_registry_config.fileName()).arg(m_mw_config.fileName());
98+ QString registry_ini = QString(REGISTRY_CONFIG).arg(m_endpoints_dir.path()).arg(m_endpoints_dir.path()).arg(m_mw_config.fileName()).arg(m_scopeDir).arg(scopeRunnerPath);
99+ QString mw_ini = QString(MW_CONFIG).arg(m_endpoints_dir.path()).arg(m_endpoints_dir.path());
100+
101+ m_runtime_config.write(runtime_ini.toUtf8());
102+ m_registry_config.write(registry_ini.toUtf8());
103+ m_mw_config.write(mw_ini.toUtf8());
104+
105+ m_runtime_config.flush();
106+ m_registry_config.flush();
107+ m_mw_config.flush();
108+
109+ qputenv("UNITY_SCOPES_RUNTIME_PATH", m_runtime_config.fileName().toLocal8Bit());
110+
111+ QString registryBin(QDir(scopesLibdir).filePath("scoperegistry/scoperegistry"));
112+ QStringList arguments;
113+ arguments << m_runtime_config.fileName();
114+
115+ m_registry.start(registryBin, arguments);
116+}
tools/registry-tracker.hnew file+44
@@ -0,0 +1,44 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Michal Hruby <michal.hruby@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+// Qt
21+#include <QProcess>
22+#include <QTemporaryFile>
23+#include <QTemporaryDir>
24+#include <QDebug>
25+
26+
27+class RegistryTracker
28+{
29+public:
30+ RegistryTracker(QString const&);
31+ ~RegistryTracker();
32+
33+ QProcess* registry() const;
34+
35+private:
36+ void runRegistry();
37+
38+ QString m_scopeDir;
39+ QProcess m_registry;
40+ QTemporaryDir m_endpoints_dir;
41+ QTemporaryFile m_runtime_config;
42+ QTemporaryFile m_registry_config;
43+ QTemporaryFile m_mw_config;
44+};
tools/scopetool.cppnew file+84
@@ -0,0 +1,84 @@
1+/*
2+ * Copyright (C) 2012 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Gerry Boland <gerry.boland@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+// Qt
21+#include <QtQuick/QQuickView>
22+#include <QtGui/QGuiApplication>
23+#include <QtQml/QQmlEngine>
24+#include <QtQml/QQmlContext>
25+#include <QScopedPointer>
26+#include <QDebug>
27+#include <libintl.h>
28+
29+
30+// local
31+#include <paths.h>
32+#include "registry-tracker.h"
33+
34+
35+int main(int argc, char *argv[])
36+{
37+ /* Workaround Qt platform integration plugin not advertising itself
38+ as having the following capabilities:
39+ - QPlatformIntegration::ThreadedOpenGL
40+ - QPlatformIntegration::BufferQueueingOpenGL
41+ */
42+ setenv("QML_FORCE_THREADED_RENDERER", "1", 1);
43+ setenv("QML_FIXED_ANIMATION_STEP", "1", 1);
44+
45+ QGuiApplication::setApplicationName("Unity Scope Tool");
46+ QGuiApplication *application;
47+ application = new QGuiApplication(argc, argv);
48+
49+ QStringList arguments = application->arguments();
50+ QString scopesDir;
51+ if (arguments.contains("--scope-dir")) {
52+ int idx = arguments.indexOf("--scope-dir");
53+ scopesDir = arguments[idx+1];
54+ }
55+
56+ QScopedPointer<RegistryTracker> tracker;
57+ if (!scopesDir.isEmpty()) {
58+ tracker.reset(new RegistryTracker(scopesDir));
59+ }
60+
61+ resolveIconTheme();
62+
63+ bindtextdomain("unity8", translationDirectory().toUtf8().data());
64+
65+ QQuickView* view = new QQuickView();
66+ view->setResizeMode(QQuickView::SizeRootObjectToView);
67+ view->setTitle(QGuiApplication::applicationName());
68+ view->engine()->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory()));
69+
70+ QUrl source(::qmlDirectory() + "ScopeTool.qml");
71+ prependImportPaths(view->engine(), ::overrideImportPaths());
72+ appendImportPaths(view->engine(), ::fallbackImportPaths());
73+
74+ view->setSource(source);
75+
76+ view->show();
77+
78+ int result = application->exec();
79+
80+ delete view;
81+ delete application;
82+
83+ return result;
84+}