on xenial help sign in
Merge
commit2be1452d13712001346a3c36cce41ba25cb2b352 authorAlbert Astals <albert.astals@canonical.com> dateTue 7 Jan 2014, 16:01 (13 years ago) parent3d5310904de85d
23 files changed+597−98
CMakeLists.txt+2 data/CMakeLists.txt+3−2 data/unity-scope-tool.desktop.in+8 debian/control+9 debian/unity-scope-tool.install+3 po/hu.po+30−26 po/ru.po+8−7 qml/Components/PageHeader.qml+1−2 qml/Notifications/Notification.qml+5−2 qml/Panel/IndicatorItem.qml−13 qml/Panel/IndicatorRow.qml+39−8 qml/Panel/Indicators.qml+22−11 qml/Panel/MenuContent.qml+3−1 qml/Panel/Panel.qml+1−1 qml/ScopeTool.qml+177 tests/qmltests/Dash/tst_GenericScopeView.qml+9 tests/qmltests/Notifications/tst_Notifications.qml+4−10 tests/qmltests/Panel/tst_IndicatorItem.qml−11 tests/qmltests/Panel/tst_IndicatorRow.qml+18−4 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
po/hu.po+30−26
@@ -8,61 +8,65 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2013-11-29 09:21+0100\n"
11−"PO-Revision-Date: 2013-06-27 04:28+0000\n"
12−"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
11+"PO-Revision-Date: 2014-01-04 15:30+0000\n"
12+"Last-Translator: Péter MÁTÓ <mato.peter@gmail.com>\n"
1313"Language-Team: Hungarian <hu@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-12-29 06:04+0000\n"
18+"X-Launchpad-Export-Date: 2014-01-05 05:50+0000\n"
1919"X-Generator: Launchpad (build 16877)\n"
2020
2121#: Components/EdgeDemoOverlay.qml:151
2222msgid "Skip intro"
23−msgstr ""
23+msgstr "A bemutató kihagyása"
2424
2525#: Components/EdgeDemo.qml:112
2626msgid "Right edge"
27−msgstr ""
27+msgstr "Jobb szél"
2828
2929#: Components/EdgeDemo.qml:113
3030msgid "Try swiping from the right edge to unlock the phone"
31−msgstr ""
31+msgstr "A telefon feloldásához csúsztassa ujját a jobb szélről"
3232
3333#: Components/EdgeDemo.qml:144
3434msgid "Top edge"
35−msgstr ""
35+msgstr "Felső szél"
3636
3737#: Components/EdgeDemo.qml:145
3838msgid "Try swiping from the top edge to access the indicators"
39−msgstr ""
39+msgstr "A jelzők eléréséhez csúsztassa ujját a felső szélről"
4040
4141#: Components/EdgeDemo.qml:170
4242msgid "Close"
43−msgstr ""
43+msgstr "Bezárás"
4444
4545#: Components/EdgeDemo.qml:171
4646msgid "Swipe up again to close the settings screen"
47−msgstr ""
47+msgstr "A beállítások bezárásához csúsztassa ujját újra felfelé"
4848
4949#: Components/EdgeDemo.qml:198
5050msgid "Left edge"
51−msgstr ""
51+msgstr "Bal szél"
5252
5353#: Components/EdgeDemo.qml:199
5454msgid "Swipe from the left to reveal the launcher for quick access to apps"
5555msgstr ""
56+"Csúsztassa ujját a bal szélről az indítón található alkalmazások gyors "
57+"eléréséhez"
5658
5759#: Components/EdgeDemo.qml:226
5860msgid "Well done"
59−msgstr ""
61+msgstr "Rendben"
6062
6163#: Components/EdgeDemo.qml:227
6264msgid ""
6365"You have now mastered the edge gestures and can start using the "
6466"phone<br><br>Tap anywhere to start"
6567msgstr ""
68+"Miután megismerte a szélek használatát, nincs más hátra...<br><br>Koppintson "
69+"a folytatáshoz!"
6670
6771#: Components/PageHeader.qml:364
6872msgid "Recent searches"
@@ -70,50 +74,50 @@ msgstr "Legutóbbi keresések"
7074
7175#: Dash/Apps/AppPreview.qml:135
7276msgid "Rate this"
73−msgstr ""
77+msgstr "Osztályzás"
7478
7579#. TRANSLATORS: Number of persons who rated this app/video/whatever
7680#: Dash/Previews/Header.qml:93
7781#, qt-format
7882msgid "(%1)"
79−msgstr ""
83+msgstr "(%1)"
8084
8185#. TRANSLATORS: Number of persons who wrote reviews for this app/video/whatever
8286#: Dash/Previews/Header.qml:105
8387#, qt-format
8488msgid "%1 review"
8589msgid_plural "%1 reviews"
86−msgstr[0] ""
87−msgstr[1] ""
90+msgstr[0] "%1 értékelés"
91+msgstr[1] "%1 értékelés"
8892
8993#: Dash/Previews/Reviews.qml:74
9094msgid "Add a review"
91−msgstr ""
95+msgstr "Értékelés hozzáadása"
9296
9397#: Dash/Previews/Reviews.qml:86
9498msgid "Review"
95−msgstr ""
99+msgstr "Értékelés"
96100
97101#: Dash/Previews/Reviews.qml:121
98102msgid "Send"
99−msgstr ""
103+msgstr "Küldés"
100104
101105#: Dash/Previews/Reviews.qml:139
102106msgid "Comments:"
103−msgstr ""
107+msgstr "Hozzászólások:"
104108
105109#: Greeter/Lockscreen.qml:149
106110msgid "Emergency Call"
107−msgstr ""
111+msgstr "Vészhívás"
108112
109113#: Greeter/PassphraseLockscreen.qml:59
110114#, qt-format
111115msgid "Hello %1"
112−msgstr ""
116+msgstr "Szia %1"
113117
114118#: Greeter/PassphraseLockscreen.qml:59
115119msgid "Hello"
116−msgstr ""
120+msgstr "Szia"
117121
118122#: Hud/HudParametrizedActionsPage.qml:132
119123msgid "Confirm"
@@ -137,7 +141,7 @@ msgstr "Beszéd…"
137141
138142#: Notifications/NotificationMenuItemFactory.qml:89
139143msgid "Show password"
140−msgstr ""
144+msgstr "Jelszó megjelenítése"
141145
142146#: Panel/SearchIndicator.qml:27
143147msgid "Search"
@@ -146,11 +150,11 @@ msgstr "Keresés"
146150#: plugins/Unity/Launcher/launcheritem.cpp:43
147151#: plugins/Unity/Launcher/launcheritem.cpp:73
148152msgid "Lock to Launcher"
149−msgstr ""
153+msgstr "Indítóban tartás"
150154
151155#: plugins/Unity/Launcher/launcheritem.cpp:73
152156msgid "Unlock from Launcher"
153−msgstr ""
157+msgstr "Eltávolítás az Indítóból"
154158
155159#: Shell.qml:439
156160#, qt-format
po/ru.po+8−7
@@ -8,15 +8,15 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2013-11-29 09:21+0100\n"
11−"PO-Revision-Date: 2013-10-01 05:55+0000\n"
12−"Last-Translator: Zonov Roman <Unknown>\n"
11+"PO-Revision-Date: 2014-01-07 05:21+0000\n"
12+"Last-Translator: Ivlev Denis <Unknown>\n"
1313"Language-Team: Russian <ru@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1818"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-12-29 06:04+0000\n"
19+"X-Launchpad-Export-Date: 2014-01-07 05:33+0000\n"
2020"X-Generator: Launchpad (build 16877)\n"
2121
2222#: Components/EdgeDemoOverlay.qml:151
@@ -89,7 +89,8 @@ msgstr "(%1)"
8989#, qt-format
9090msgid "%1 review"
9191msgid_plural "%1 reviews"
92−msgstr[0] "%1 отзыв"
92+msgstr[0] "%1 отзыва"
93+msgstr[1] "%1 отзывов"
9394
9495#: Dash/Previews/Reviews.qml:74
9596msgid "Add a review"
@@ -142,7 +143,7 @@ msgstr "Говорите..."
142143
143144#: Notifications/NotificationMenuItemFactory.qml:89
144145msgid "Show password"
145−msgstr ""
146+msgstr "Показать пароль"
146147
147148#: Panel/SearchIndicator.qml:27
148149msgid "Search"
@@ -151,11 +152,11 @@ msgstr "Поиск"
151152#: plugins/Unity/Launcher/launcheritem.cpp:43
152153#: plugins/Unity/Launcher/launcheritem.cpp:73
153154msgid "Lock to Launcher"
154−msgstr ""
155+msgstr "Закрепить на панели"
155156
156157#: plugins/Unity/Launcher/launcheritem.cpp:73
157158msgid "Unlock from Launcher"
158−msgstr ""
159+msgstr "Убрать с панели"
159160
160161#: Shell.qml:439
161162#, qt-format
qml/Components/PageHeader.qml+1−2
@@ -117,9 +117,8 @@ Item {
117117
118118 function openPopover() {
119119 if (searchHistory.count > 0) {
120− searchContainer.popover = PopupUtils.open(popoverComponent, searchField,
120+ searchContainer.popover = PopupUtils.open(popoverComponent, pointerPositioner,
121121 {
122− "pointerTarget": pointerPositioner,
123122 "contentWidth": searchField.width,
124123 "edgeMargins": units.gu(1)
125124 }
qml/Notifications/Notification.qml+5−2
@@ -106,8 +106,11 @@ Item {
106106
107107 anchors.fill: contentColumn
108108 objectName: "interactiveArea"
109− enabled: notification.type == Notification.Interactive
110− onClicked: notification.notification.invokeAction(actionRepeater.itemAt(0).actionId)
109+ onClicked: {
110+ if (notification.type == Notification.Interactive) {
111+ notification.notification.invokeAction(actionRepeater.itemAt(0).actionId)
112+ }
113+ }
111114 }
112115
113116 Column {
qml/Panel/IndicatorItem.qml−13
@@ -23,7 +23,6 @@ Item {
2323 id: indicatorItem
2424
2525 property alias widgetSource: loader.source
26− property bool highlighted: false
2726 property bool dimmed: false
2827 property var indicatorProperties: undefined
2928 property bool indicatorVisible: loader.item ? loader.item.enabled : false
@@ -46,16 +45,4 @@ Item {
4645 }
4746 }
4847 }
49−
50− Rectangle {
51− color: Theme.palette.selected.foreground
52− objectName: "highlight"
53− height: units.dp(2)
54− width: parent.width
55− anchors.top: parent.bottom
56− visible: highlighted
57−
58− opacity: highlighted ? 1 : 0
59− Behavior on opacity { StandardAnimation {} }
60− }
6148}
qml/Panel/IndicatorRow.qml+39−8
@@ -29,6 +29,8 @@ Item {
2929 property var visibleIndicators: defined
3030 property int overFlowWidth: width
3131 property bool showAll: false
32+ property real currentItemOffset: 0.0
33+ property real unitProgress: 0.0
3234
3335 width: units.gu(40)
3436 height: units.gu(3)
@@ -79,23 +81,23 @@ Item {
7981 height: indicatorRow.height
8082 width: indicatorItem.width
8183 visible: indicatorItem.indicatorVisible
82− opacity: 1.0
84+ opacity: 1.0 * opacityMultiplier
8385 y: 0
8486 state: "standard"
8587
8688 property int ownIndex: index
87− property alias highlighted: indicatorItem.highlighted
88− property alias dimmed: indicatorItem.dimmed
89+ property bool highlighted: indicatorRow.state != "initial" ? ownIndex == indicatorRow.currentItemIndex : false
90+ property bool dimmed: indicatorRow.state != "initial" ? ownIndex != indicatorRow.currentItemIndex : false
8991
90− property bool hidden: !showAll && !indicatorItem.highlighted && (indicatorRow.state == "locked" || indicatorRow.state == "commit")
92+ property bool hidden: !showAll && !highlighted && (indicatorRow.state == "locked" || indicatorRow.state == "commit")
9193 property bool overflow: row.width - itemWrapper.x > overFlowWidth
94+ property real opacityMultiplier: highlighted ? 1 : (1 - indicatorRow.unitProgress)
9295
9396 IndicatorItem {
9497 id: indicatorItem
9598 height: parent.height
9699
97− highlighted: indicatorRow.state != "initial" ? itemWrapper.ownIndex == indicatorRow.currentItemIndex : false
98− dimmed: indicatorRow.state != "initial" ? itemWrapper.ownIndex != indicatorRow.currentItemIndex : false
100+ dimmed: itemWrapper.dimmed
99101
100102 widgetSource: model.widgetSource
101103 indicatorProperties : model.indicatorProperties
@@ -135,14 +137,43 @@ Item {
135137
136138 transitions: [
137139 Transition {
138− StandardAnimation {
140+ UbuntuNumberAnimation {
139141 target: itemWrapper
140142 property: "opacity"
141− duration: 300
143+ duration: UbuntuAnimation.BriskDuration
142144 }
143145 }
144146 ]
145147 }
146148 }
147149 }
150+
151+ Rectangle {
152+ id: highlight
153+ color: Theme.palette.selected.foreground
154+ objectName: "highlight"
155+ height: units.dp(2)
156+ anchors.top: row.bottom
157+ visible: indicatorRow.currentItem != null
158+ x: row.x + (indicatorRow.currentItem != null ? indicatorRow.currentItem.x + centerOffset : 0)
159+ width: indicatorRow.currentItem != null ? indicatorRow.currentItem.width : 0
160+
161+ property real centerOffset: {
162+ if (indicatorRow.currentItemOffset > 0.1) {
163+ return (indicatorRow.currentItemOffset - 0.1) * units.gu(0.4);
164+ } else if (indicatorRow.currentItemOffset < -0.1) {
165+ return (indicatorRow.currentItemOffset + 0.1) * units.gu(0.4);
166+ }
167+ return 0.0;
168+ }
169+
170+ Behavior on width {
171+ enabled: unitProgress > 0;
172+ UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
173+ }
174+ Behavior on x {
175+ enabled: unitProgress > 0;
176+ UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
177+ }
178+ }
148179}
qml/Panel/Indicators.qml+22−11
@@ -39,6 +39,7 @@ Showable {
3939 property bool contentEnabled: true
4040 property bool initalizeItem: true
4141 readonly property alias content: menuContent
42+ property real unitProgress: 0.0
4243
4344 // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
4445 // use its own values. Need to ask design about this.
@@ -128,23 +129,31 @@ Showable {
128129 rowCoordinates = indicatorRow.mapToItem(indicatorRow.row, xValue, 0);
129130 // get the current delegate
130131 currentItem = indicatorRow.row.childAt(rowCoordinates.x, 0);
131− if (currentItem && currentItem != indicatorRow.currentItem ) {
132+ if (currentItem) {
132133 itemCoordinates = indicatorRow.row.mapToItem(currentItem, rowCoordinates.x, 0);
133134 distanceFromRightEdge = (currentItem.width - itemCoordinates.x) / (currentItem.width);
134− if (Math.abs(currentItem.ownIndex - indicatorRow.currentItemIndex) > 1) {
135− bufferExceeded = true;
136− } else {
137− if (indicatorRow.currentItemIndex < currentItem.ownIndex && distanceFromRightEdge < (1 - effectiveBufferThreshold)) {
138− bufferExceeded = true;
139− } else if (indicatorRow.currentItemIndex > currentItem.ownIndex && distanceFromRightEdge > effectiveBufferThreshold) {
135+ if (currentItem != indicatorRow.currentItem) {
136+ if (Math.abs(currentItem.ownIndex - indicatorRow.currentItemIndex) > 1) {
140137 bufferExceeded = true;
138+ } else {
139+ if (indicatorRow.currentItemIndex < currentItem.ownIndex && distanceFromRightEdge < (1 - effectiveBufferThreshold)) {
140+ bufferExceeded = true;
141+ } else if (indicatorRow.currentItemIndex > currentItem.ownIndex && distanceFromRightEdge > effectiveBufferThreshold) {
142+ bufferExceeded = true;
143+ }
141144 }
145+ if ((!useBuffer || (useBuffer && bufferExceeded)) || indicatorRow.currentItemIndex < 0 || indicatorRow.currentItem == null) {
146+ indicatorRow.currentItem = currentItem;
147+ }
148+
149+ // need to re-init the distanceFromRightEdge for offset calculation
150+ itemCoordinates = indicatorRow.row.mapToItem(indicatorRow.currentItem, rowCoordinates.x, 0);
151+ distanceFromRightEdge = (indicatorRow.currentItem.width - itemCoordinates.x) / (indicatorRow.currentItem.width);
142152 }
143− if ((!useBuffer || (useBuffer && bufferExceeded)) || indicatorRow.currentItem < 0 || indicatorRow.currentItem == null) {
144− indicatorRow.currentItem = currentItem;
145− }
146− } else if (!currentItem) {
153+ indicatorRow.currentItemOffset = 1 - (distanceFromRightEdge * 2);
154+ } else {
147155 indicatorRow.setDefaultItem();
156+ indicatorRow.currentItemOffset = 0;
148157 }
149158 initalizeItem = indicatorRow.currentItem == null;
150159 }
@@ -268,6 +277,7 @@ Showable {
268277 height: indicators.panelHeight
269278 indicatorsModel: indicatorsModel
270279 state: indicators.state
280+ unitProgress: indicators.unitProgress
271281
272282 Connections {
273283 property bool enableIndexChangeSignal: true
@@ -326,6 +336,7 @@ Showable {
326336 if (hideAnimation.running) {
327337 indicators.state = "initial";
328338 initalizeItem = true;
339+ menuContent.animateNextMenuChange = false;
329340 }
330341 }
331342 }
qml/Panel/MenuContent.qml+3−1
@@ -33,6 +33,7 @@ MainView {
3333 property int contentReleaseInterval: 20000
3434 property bool activeHeader: false
3535 property alias visibleIndicators: visibleIndicatorsModel.visible
36+ property bool animateNextMenuChange: false
3637
3738 width: units.gu(40)
3839 height: units.gu(42)
@@ -41,11 +42,12 @@ MainView {
4142 var filteredIndex = filteredIndicators.mapFromSource(index)
4243
4344 if (tabs.selectedTabIndex !== filteredIndex) {
44− if (tabs.selectedTabIndex == -1) {
45+ if (tabs.selectedTabIndex == -1 || !animateNextMenuChange) {
4546 tabs.tabBar.animate = false;
4647 }
4748 tabs.selectedTabIndex = filteredIndex;
4849 tabs.tabBar.animate = true;
50+ animateNextMenuChange = true;
4951 }
5052 }
5153
qml/Panel/Panel.qml+1−1
@@ -107,7 +107,7 @@ Item {
107107 pinnedMode: !fullscreenMode
108108 overFlowWidth: search.state=="hidden" ? parent.width : parent.width - search.width
109109
110− property real unitProgress: (height - panelHeight) / (openedHeight - panelHeight)
110+ unitProgress: (height - panelHeight) / (openedHeight - panelHeight)
111111 }
112112
113113 PanelSeparatorLine {
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+}
tests/qmltests/Dash/tst_GenericScopeView.qml+9
@@ -321,6 +321,15 @@ Item {
321321
322322 categoryListView.positionAtBeginning();
323323
324+ // wait for the header0 to be on its position
325+ tryCompareFunction(
326+ function() {
327+ var header0 = findChild(genericScopeView, "dashSectionHeader0")
328+ var pageHeader = findChild(genericScopeView, "pageHeader");
329+ return header0.y == pageHeader.height;
330+ },
331+ true);
332+
324333 var header0 = findChild(genericScopeView, "dashSectionHeader0")
325334 var category0 = findChild(genericScopeView, "dashCategory0")
326335 mouseClick(header0, header0.width / 2, header0.height / 2);
tests/qmltests/Notifications/tst_Notifications.qml+4−10
@@ -225,7 +225,6 @@ Row {
225225 { id: "nada_id", label: "Nada"}],
226226 summaryVisible: true,
227227 bodyVisible: true,
228− interactiveAreaEnabled: false,
229228 iconVisible: true,
230229 shapedIcon: true,
231230 nonShapedIcon: false,
@@ -244,7 +243,6 @@ Row {
244243 actions: [],
245244 summaryVisible: true,
246245 bodyVisible: false,
247− interactiveAreaEnabled: false,
248246 iconVisible: false,
249247 shapedIcon: false,
250248 nonShapedIcon: false,
@@ -282,7 +280,6 @@ Row {
282280 actions: [{ id: "reply_id", label: "Dummy"}],
283281 summaryVisible: true,
284282 bodyVisible: true,
285− interactiveAreaEnabled: true,
286283 iconVisible: true,
287284 shapedIcon: true,
288285 nonShapedIcon: false,
@@ -302,7 +299,6 @@ Row {
302299 { id: "reject_id", label: "Reject"}],
303300 summaryVisible: true,
304301 bodyVisible: true,
305− interactiveAreaEnabled: false,
306302 iconVisible: true,
307303 shapedIcon: true,
308304 nonShapedIcon: false,
@@ -321,7 +317,6 @@ Row {
321317 actions: [],
322318 summaryVisible: true,
323319 bodyVisible: true,
324− interactiveAreaEnabled: false,
325320 iconVisible: true,
326321 shapedIcon: true,
327322 nonShapedIcon: false,
@@ -341,7 +336,6 @@ Row {
341336 actions: [],
342337 summaryVisible: true,
343338 bodyVisible: true,
344− interactiveAreaEnabled: false,
345339 iconVisible: true,
346340 shapedIcon: false,
347341 nonShapedIcon: true,
@@ -395,14 +389,14 @@ Row {
395389 compare(icon.visible, data.iconVisible, "avatar-icon visibility is incorrect")
396390 compare(shapedIcon.visible, data.shapedIcon, "shaped-icon visibility is incorrect")
397391 compare(nonShapedIcon.visible, data.nonShapedIcon, "non-shaped-icon visibility is incorrect")
398− compare(interactiveArea.enabled, data.interactiveAreaEnabled, "check for interactive area")
399392
400− if(data.interactiveAreaEnabled) {
401− mouseClick(notification, notification.width / 2, notification.height / 2)
393+ // test input does not fall through
394+ mouseClick(notification, notification.width / 2, notification.height / 2)
395+ if(data.type == Notification.Interactive) {
402396 actionSpy.wait()
403397 compare(actionSpy.signalArguments[0][0], data.actions[0]["id"], "got wrong id for interactive action")
404− compare(clickThroughSpy.count, 0, "click on interactive notification fell through")
405398 }
399+ compare(clickThroughSpy.count, 0, "click on notification fell through")
406400
407401 compare(secondaryIcon.visible, data.secondaryIconVisible, "secondary-icon visibility is incorrect")
408402 compare(summaryLabel.visible, data.summaryVisible, "summary-text visibility is incorrect")
tests/qmltests/Panel/tst_IndicatorItem.qml−11
@@ -41,17 +41,6 @@ Rectangle {
4141 tryCompareFunction(function(){return indicatorItem.opacity < 1.0}, true);
4242 }
4343
44− function test_highlight() {
45− var itemHighlight = findChild(indicatorItem, "highlight");
46− verify(itemHighlight != undefined);
47−
48− indicatorItem.highlighted = true;
49− compare(itemHighlight.visible, true, "Indicator should be highlighted");
50−
51− indicatorItem.highlighted = false;
52− compare(itemHighlight.visible, false, "Indicator should not be highlighted");
53− }
54−
5544 function test_empty() {
5645 compare(indicatorItem.indicatorVisible, false, "IndicatorItem should not be visible.");
5746 indicatorItem.widgetSource = "qrc:/tests/indciators/qml/fake_menu_widget1.qml";
tests/qmltests/Panel/tst_IndicatorRow.qml+18−4
@@ -34,6 +34,7 @@ Item {
3434 {
3535 indicatorRow.state = "initial";
3636 indicatorRow.currentItem = null;
37+ indicatorRow.unitProgress = 0.0;
3738 }
3839
3940 PanelBackground {
@@ -83,14 +84,13 @@ Item {
8384 function test_current_item_commit() {
8485 init_test();
8586
86− indicatorRow.setCurrentItem(1);
87+ indicatorRow.setCurrentItem(2);
8788 indicatorRow.state = "commit";
8889 tryCompare(get_indicator_item_at(0), "opacity", 0.0);
89− tryCompare(get_indicator_item_at(1), "opacity", 1.0);
90− tryCompare(get_indicator_item_at(2), "opacity", 0.0);
90+ tryCompare(get_indicator_item_at(1), "opacity", 0.0);
91+ tryCompare(get_indicator_item_at(2), "opacity", 1.0);
9192 tryCompare(get_indicator_item_at(3), "opacity", 0.0);
9293 tryCompare(get_indicator_item_at(4), "opacity", 0.0);
93−
9494 }
9595 }
9696
@@ -166,6 +166,20 @@ Item {
166166 compare(get_indicator_item_at(3).highlighted, false, "Other indicators should not highlight when in locked state");
167167 compare(get_indicator_item_at(4).highlighted, false, "Other indicators should not highlight when in locked state");
168168 }
169+
170+ function test_opacity() {
171+ init_test();
172+
173+ indicatorRow.state = "reveal";
174+ indicatorRow.unitProgress = 0.5;
175+ indicatorRow.setCurrentItem(2);
176+
177+ compare(get_indicator_item_at(0).opacity, 0.5, "Other indicator opacity should change in response to panel progress");
178+ compare(get_indicator_item_at(1).opacity, 0.5, "Other indicator opacity should change in response to panel progress");
179+ compare(get_indicator_item_at(2).opacity, 1.0, "Current indicator should not change in response to panel progress");
180+ compare(get_indicator_item_at(3).opacity, 0.5, "Other indicator opacity should change in response to panel progress");
181+ compare(get_indicator_item_at(4).opacity, 0.5, "Other indicator opacity should change in response to panel progress");
182+ }
169183 }
170184
171185 UT.UnityTestCase {
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+}