on xenial help sign in
Merge from trunk
commit9e8474eceb28eee6b5e410f72f6e0208bcf00ea7 authorMichael Terry <michael.terry@canonical.com> dateMon 9 Sep 2013, 10:36 (13 years ago) parentcee0dab8970503
56 files changed+814−222
Bottombar/Bottombar.qml+3−1 Components/IconUtil.js−42 Dash/Apps/AppPreview.qml+1−2 Dash/Apps/ApplicationsFilterGrid.qml+1−2 Dash/Generic/GenericCarousel.qml+1−2 Dash/Generic/GenericFilterGrid.qml+1−2 Dash/Generic/GenericPreview.qml+1−2 Dash/GenericScopeView.qml+4−5 Panel/IndicatorItem.qml+2−3 Panel/IndicatorRow.qml+19−1 Panel/Indicators.qml+17−2 Panel/Indicators/DatetimeIndicatorWidget.qml+4−2 Panel/Indicators/DefaultIndicatorWidget.qml+1 Panel/Indicators/NetworkIndicatorWidget.qml+3 Panel/Indicators/SoundIndicatorWidget.qml+1 Panel/MenuContent.qml+25−7 plugins/Unity/CMakeLists.txt+1 plugins/Unity/Indicators/CMakeLists.txt+9 plugins/Unity/Indicators/Network/qml/AccessPoint.qml+71−26 plugins/Unity/Indicators/indicator.cpp−2 plugins/Unity/Indicators/indicator.h−4 plugins/Unity/Indicators/indicators.h+1−1 plugins/Unity/Indicators/indicatorsmodel.cpp−3 plugins/Unity/Indicators/indicatorsmodel.h+2−1 plugins/Unity/Indicators/plugin.cpp+2 plugins/Unity/Indicators/qml/IndicatorBase.qml−5 plugins/Unity/Indicators/qml/IndicatorWidget.qml+1 plugins/Unity/Indicators/qml/MenuItemFactory.qml+5−5 plugins/Unity/Indicators/resources/artwork/network/secure.svg+71 plugins/Unity/Indicators/resources/indicators.qrc+5 plugins/Unity/Indicators/visibleindicatorsmodel.cpp+94 plugins/Unity/Indicators/visibleindicatorsmodel.h+56 plugins/Unity/IndicatorsLegacy/qml/IndicatorWidget.qml+2−2 plugins/Unity/applicationpreview.cpp+5−1 plugins/Unity/categoryresults.cpp+5−2 plugins/Unity/categoryresults.h+1−1 plugins/Unity/iconutils.cpp+91 plugins/Unity/iconutils.h+27 plugins/Unity/preview.cpp+5−1 plugins/Unity/socialpreview.cpp+5−1 plugins/Utils/qsortfilterproxymodelqml.cpp+20 plugins/Utils/qsortfilterproxymodelqml.h+3 tests/autopilot/unity8/shell/tests/test_hud.py+7−2 tests/mocks/Unity/CMakeLists.txt+1 tests/mocks/Unity/Indicators/CMakeLists.txt+1 tests/mocks/Unity/Indicators/IndicatorsModel.qml+47−76 tests/mocks/Unity/Indicators/fakeplugin.cpp+2 tests/mocks/Unity/Indicators/qml/fake_menu_widget2.qml+2 tests/plugins/Unity/CMakeLists.txt+4 tests/plugins/Unity/resultstest.cpp+104 tests/plugins/Unity/resultstest.h+35 tests/qmltests/CMakeLists.txt+1−1 tests/qmltests/Panel/tst_IndicatorItem.qml+2−2 tests/qmltests/Panel/tst_Indicators.qml+30−11 tests/qmltests/Panel/tst_MenuContent.qml+9−2 tests/qmltests/Panel/tst_Panel.qml+3
Bottombar/Bottombar.qml+3−1
@@ -107,7 +107,7 @@ Item {
107107 height: distanceThreshold
108108 anchors.bottom: parent.bottom
109109
110− distanceThreshold: units.gu(8)
110+ distanceThreshold: units.gu(1)
111111 enabled: !theHud.shown && bottombar.enabled && applicationIsOnForeground
112112 direction: Direction.Upwards
113113
@@ -119,6 +119,8 @@ Item {
119119 if (previousStatus == DirectionalDragArea.Recognized) {
120120 if (hudButton.mouseOver) {
121121 hudButton.clicked()
122+ } else {
123+ bottombar.state = "hidden"
122124 }
123125 }
124126 } else if (status === DirectionalDragArea.Undecided) {
Components/IconUtil.jsdeleted−42
@@ -1,42 +0,0 @@
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−.pragma library
18−
19−// FIXME: a quick hack to get icons out of gicons and fallback to
20−// base icon for annotated icons. Doesn't correctly handle all icons.
21−// Proper global solution needed.
22−function from_gicon(name) {
23− var icon_name = name;
24− var annotated_re = /^. UnityProtocolAnnotatedIcon/;
25− if (annotated_re.test(name)) {
26− var base_icon_re = /'base-icon':.+?'(.+?)'/;
27− var base_icon = name.toString().match(base_icon_re);
28− icon_name = base_icon[1];
29− } else {
30− var themed_re = /^. GThemedIcon\s*([^\s]+)\s*/;
31− var themed = name.match(themed_re);
32− if (themed) {
33− return "image://gicon/" + themed[1];
34− }
35− }
36− var name_re = /^[a-z0-9\._-]+$/;
37− if (name_re.test(icon_name)) {
38− return "image://gicon/" + icon_name;
39− } else {
40− return icon_name;
41− }
42−}
Dash/Apps/AppPreview.qml+1−2
@@ -20,7 +20,6 @@ import Ubuntu.Components.ListItems 0.1 as ListItem
2020import Ubuntu.DownloadDaemonListener 0.1
2121import ".."
2222import "../../Components"
23−import "../../Components/IconUtil.js" as IconUtil
2423
2524DashPreview {
2625 id: root
@@ -137,7 +136,7 @@ DashPreview {
137136 anchors { left: parent.left; right: parent.right }
138137
139138 appName: root.previewData.title
140− icon: IconUtil.from_gicon(root.previewData.appIcon)
139+ icon: root.previewData.appIcon
141140 rating: Math.round(root.previewData.rating * 10)
142141 reviews: root.previewData.numRatings
143142 rated: root.previewData.infoMap["rated"] ? root.previewData.infoMap["rated"].value : 0
Dash/Apps/ApplicationsFilterGrid.qml+1−2
@@ -17,7 +17,6 @@
1717import QtQuick 2.0
1818import "../../Components"
1919import "../../Applications"
20−import "../../Components/IconUtil.js" as IconUtil
2120
2221FilterGrid {
2322 id: filterGrid
@@ -50,7 +49,7 @@ FilterGrid {
5049 text: model.title ? model.title : application.name // FIXME: this is temporary
5150 imageWidth: units.gu(8)
5251 imageHeight: units.gu(7.5)
53− source: IconUtil.from_gicon(icon)
52+ source: icon
5453 onClicked: filterGrid.clicked(index, application.desktopFile);
5554 }
5655}
Dash/Generic/GenericCarousel.qml+1−2
@@ -17,7 +17,6 @@
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919import "../../Components"
20−import "../../Components/IconUtil.js" as IconUtil
2120
2221Carousel {
2322 id: genericCarousel
@@ -42,7 +41,7 @@ Carousel {
4241 image: Image {
4342 asynchronous: true
4443 sourceSize { width: item.width; height: item.height }
45− source: model ? IconUtil.from_gicon(model.icon) : ""
44+ source: model ? model.icon : ""
4645 }
4746 }
4847
Dash/Generic/GenericFilterGrid.qml+1−2
@@ -16,7 +16,6 @@
1616
1717import QtQuick 2.0
1818import "../../Components"
19−import "../../Components/IconUtil.js" as IconUtil
2019
2120FilterGrid {
2221 id: filtergrid
@@ -41,7 +40,7 @@ FilterGrid {
4140 imageWidth: filtergrid.iconWidth
4241 imageHeight: filtergrid.iconHeight
4342
44− source: IconUtil.from_gicon(model.icon)
43+ source: model.icon
4544
4645 fillMode: Image.PreserveAspectCrop
4746
Dash/Generic/GenericPreview.qml+1−2
@@ -18,7 +18,6 @@ import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919import "../../Components"
2020import "../../Components/ListItems" as ListItems
21−import "../../Components/IconUtil.js" as IconUtil
2221import ".."
2322
2423DashPreview {
@@ -27,7 +26,7 @@ DashPreview {
2726 title: previewData.title
2827 previewWidthRatio: 0.6
2928
30− property url url: IconUtil.from_gicon(previewData.image)
29+ property url url: previewData.image
3130
3231 header: UbuntuShape {
3332 id: urlLoader
Dash/GenericScopeView.qml+4−5
@@ -18,7 +18,6 @@ import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919import "../Components"
2020import "../Components/ListItems" as ListItems
21−import "../Components/IconUtil.js" as IconUtil
2221
2322ScopeView {
2423 id: scopeView
@@ -74,12 +73,12 @@ ScopeView {
7473 onLoaded: {
7574 if (source.toString().indexOf("Apps/RunningApplicationsGrid.qml") != -1) {
7675 // TODO: the running apps grid doesn't support standard scope results model yet
77− item.firstModel = results.firstModel
78− item.secondModel = results.secondModel
76+ item.firstModel = Qt.binding(function() { return results.firstModel })
77+ item.secondModel = Qt.binding(function() { return results.secondModel })
7978 } else {
80− item.model = results
79+ item.model = Qt.binding(function() { return results })
8180 }
82− item.objectName = categoryId
81+ item.objectName = Qt.binding(function() { return categoryId })
8382 if (item.expandable) {
8483 var shouldFilter = index != categoryView.expandedIndex;
8584 if (shouldFilter != item.filter) {
Panel/IndicatorItem.qml+2−3
@@ -26,13 +26,12 @@ Item {
2626 property bool highlighted: false
2727 property bool dimmed: false
2828 property var indicatorProperties: undefined
29+ property bool indicatorVisible: loader.item ? loader.item.enabled : false
2930
3031 opacity: dimmed ? 0.4 : 1
3132 Behavior on opacity { StandardAnimation {} }
3233
33− // only visible when non-empty
34− visible: loader.item != undefined && loader.status == Loader.Ready ? loader.item.enabled : false
35− width: visible ? loader.item.width : 0
34+ width: loader.item ? loader.item.width : 0
3635
3736 Loader {
3837 id: loader
Panel/IndicatorRow.qml+19−1
@@ -16,6 +16,7 @@
1616
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
19+import Unity.Indicators 0.1 as Indicators
1920import "../Components"
2021
2122Item {
@@ -25,6 +26,7 @@ Item {
2526 readonly property int currentItemIndex: currentItem ? currentItem.ownIndex : -1
2627 property alias row: row
2728 property QtObject indicatorsModel: null
29+ property var visibleIndicators: defined
2830
2931 width: units.gu(40)
3032 height: units.gu(3)
@@ -55,7 +57,8 @@ Item {
5557 Item {
5658 id: itemWrapper
5759 height: indicatorRow.height
58− width: childrenRect.width
60+ width: indicatorItem.width
61+ visible: indicatorItem.indicatorVisible
5962
6063 property int ownIndex: index
6164 property alias highlighted: indicatorItem.highlighted
@@ -70,6 +73,21 @@ Item {
7073
7174 widgetSource: model.widgetSource
7275 indicatorProperties : model.indicatorProperties
76+
77+ Component.onCompleted: {
78+ if (visibleIndicators == undefined) {
79+ visibleIndicators = {}
80+ }
81+ indicatorRow.visibleIndicators[model.identifier] = indicatorVisible;
82+ indicatorRow.visibleIndicatorsChanged();
83+ }
84+ onIndicatorVisibleChanged: {
85+ if (visibleIndicators == undefined) {
86+ visibleIndicators = {}
87+ }
88+ indicatorRow.visibleIndicators[model.identifier] = indicatorVisible;
89+ indicatorRow.visibleIndicatorsChanged();
90+ }
7391 }
7492
7593 opacity: {
Panel/Indicators.qml+17−2
@@ -180,11 +180,19 @@ Showable {
180180 clip: !indicators.fullyOpened
181181 activeHeader: indicators.state == "hint" || indicators.state == "reveal"
182182 enabled: contentEnabled
183+ visibleIndicators: indicatorRow.visibleIndicators
183184
184185 Connections {
185− target: indicatorRow
186+ property bool enableIndexChangeSignal: true
187+
188+ target: enableIndexChangeSignal ? indicatorRow : null
186189 onCurrentItemIndexChanged: {
190+ var oldActive = enableIndexChangeSignal;
191+ enableIndexChangeSignal = false;
192+
187193 menuContent.setCurrentMenuIndex(indicatorRow.currentItemIndex);
194+
195+ enableIndexChangeSignal = oldActive;
188196 }
189197 }
190198
@@ -256,9 +264,16 @@ Showable {
256264 state: indicators.state
257265
258266 Connections {
259− target: menuContent
267+ property bool enableIndexChangeSignal: true
268+
269+ target: enableIndexChangeSignal ? menuContent : null
260270 onCurrentMenuIndexChanged: {
271+ var oldActive = enableIndexChangeSignal;
272+ enableIndexChangeSignal = false;
273+
261274 indicatorRow.setCurrentItem(menuContent.currentMenuIndex);
275+
276+ enableIndexChangeSignal = oldActive;
262277 }
263278 }
264279 }
Panel/Indicators/DatetimeIndicatorWidget.qml+4−2
@@ -25,6 +25,7 @@ Indicators.IndicatorWidget {
2525 id: indicatorWidget
2626
2727 width: timeLabel.width + units.gu(1)
28+ rootMenuType: "com.canonical.indicator.root.time"
2829
2930 property alias label: timeLabel.text
3031
@@ -52,14 +53,15 @@ Indicators.IndicatorWidget {
5253
5354 onActionStateChanged: {
5455 if (action == undefined || !action.valid) {
56+ enabled = false;
5557 return;
5658 }
5759
5860 if (action.state == undefined) {
59− visible = false;
61+ enabled = false;
6062 return;
6163 }
6264
63− indicatorWidget.visible = action.state[3];
65+ enabled = action.state[3];
6466 }
6567}
Panel/Indicators/DefaultIndicatorWidget.qml+1
@@ -63,6 +63,7 @@ Indicators.IndicatorWidget {
6363
6464 onActionStateChanged: {
6565 if (action == undefined || !action.valid) {
66+ enabled = false;
6667 return;
6768 }
6869
Panel/Indicators/NetworkIndicatorWidget.qml+3
@@ -43,14 +43,17 @@ Indicators.IndicatorWidget {
4343
4444 onActionStateChanged: {
4545 if (action == undefined || !action.valid) {
46+ enabled = false;
4647 return;
4748 }
4849
4950 if (action.state == undefined) {
51+ enabled = false;
5052 connectionState = 0;
5153 return;
5254 }
5355
56+ enabled = true;
5457 connectionState = action.state[Indicators.NetworkActionState.Connection];
5558 if (connectionState == Indicators.NetworkConnection.Activated) {
5659 signalStrength = action.state[Indicators.NetworkActionState.SignalStrength];
Panel/Indicators/SoundIndicatorWidget.qml+1
@@ -22,4 +22,5 @@ import QtQuick 2.0
2222DefaultIndicatorWidget {
2323 // default the icon so we have something to show when we don't have the bus.
2424 iconSource: "image://gicon/audio-volume-high"
25+ enabled: true
2526}
Panel/MenuContent.qml+25−7
@@ -17,6 +17,7 @@
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919import Unity.Indicators 0.1 as Indicators
20+import Utils 0.1
2021import "../Components"
2122
2223// FIXME : We dont want to use MainView.
@@ -27,20 +28,23 @@ MainView {
2728
2829 property QtObject indicatorsModel: null
2930 property bool __contentActive: false
30− readonly property int currentMenuIndex : tabs.selectedTabIndex
31+ readonly property int currentMenuIndex : filteredIndicators.mapToSource(tabs.selectedTabIndex)
3132 backgroundColor: "#221e1c" // FIXME not in palette yet
3233 property int contentReleaseInterval: 20000
3334 property bool activeHeader: false
35+ property alias visibleIndicators: visibleIndicatorsModel.visible
3436
3537 width: units.gu(40)
3638 height: units.gu(42)
3739
3840 function setCurrentMenuIndex(index) {
39− if (currentMenuIndex !== index) {
40− if (currentMenuIndex == -1) {
41+ var filteredIndex = filteredIndicators.mapFromSource(index)
42+
43+ if (tabs.selectedTabIndex !== filteredIndex) {
44+ if (tabs.selectedTabIndex == -1) {
4145 tabs.tabBar.animate = false;
4246 }
43− tabs.selectedTabIndex = index;
47+ tabs.selectedTabIndex = filteredIndex;
4448 tabs.tabBar.animate = true;
4549 }
4650 }
@@ -61,6 +65,20 @@ MainView {
6165 tabs.tabBar.alwaysSelectionMode = activeHeader;
6266 }
6367
68+ SortFilterProxyModel {
69+ id: filteredIndicators
70+ model: visibleIndicatorsModel
71+ dynamicSortFilter: true
72+
73+ filterRole: Indicators.IndicatorsModelRole.IsVisible
74+ filterRegExp: RegExp("^true$")
75+ }
76+
77+ Indicators.VisibleIndicatorsModel {
78+ id: visibleIndicatorsModel
79+ model: indicatorsModel
80+ }
81+
6482 Tabs {
6583 id: tabs
6684 objectName: "tabs"
@@ -69,8 +87,8 @@ MainView {
6987
7088 Repeater {
7189 id: repeater
72− model: indicatorsModel
73− objectName: "menus"
90+ model: filteredIndicators
91+ objectName: "tabsRepeater"
7492
7593 // FIXME: This is needed because tabs dont handle repeaters well.
7694 // Due to the child ordering happening after child insertion.
@@ -114,7 +132,7 @@ MainView {
114132 item[pName] = indicatorProperties[pName]
115133 }
116134 }
117− if (contentActive && menus.visible) {
135+ if (contentActive && tabs.visible) {
118136 item.start()
119137 }
120138 }
plugins/Unity/CMakeLists.txt+1
@@ -47,6 +47,7 @@ set(QMLPLUGIN_SRC
4747 signalslist.cpp
4848 socialpreview.cpp
4949 socialpreviewcomment.cpp
50+ iconutils.cpp
5051 variantutils.cpp
5152)
5253
plugins/Unity/Indicators/CMakeLists.txt+9
@@ -34,11 +34,20 @@ set(IndicatorsQML_SOURCES
3434 rootactionstate.cpp
3535 unitymenumodelcache.cpp
3636 unitymenumodelstack.cpp
37+ visibleindicatorsmodel.cpp
3738)
3839add_definitions(-DUNITYINDICATORS_LIBRARY)
3940
41+set(IndicatorsQML_RESOURCES
42+ resources/indicators.qrc
43+)
44+
45+qt5_add_resources(IndicatorsQML_RESOURCES_RCC
46+ ${IndicatorsQML_RESOURCES}
47+)
4048
4149add_library(IndicatorsQml SHARED
50+ ${IndicatorsQML_RESOURCES_RCC}
4251 ${IndicatorsQML_SOURCES}
4352)
4453
plugins/Unity/Indicators/Network/qml/AccessPoint.qml+71−26
@@ -22,13 +22,15 @@ import Ubuntu.Components 0.1
2222import Ubuntu.Components.ListItems 0.1 as ListItem
2323import Unity.Indicators 0.1 as Indicators
2424
25−Indicators.FramedMenuItem {
26− id: accessPoint
25+Indicators.BaseMenuItem {
26+ id: menuItem
27+ implicitHeight: units.gu(5.5)
2728
2829 property bool checked: false
2930 property bool secure: false
3031 property bool adHoc: false
3132 property int signalStrength: 0
33+ property alias text: label.text
3234
3335 signal activate()
3436
@@ -37,36 +39,79 @@ Indicators.FramedMenuItem {
3739 checkBoxActive.checked = checked;
3840 }
3941
40− icon: {
41− var imageName = "nm-signal-100"
42−
43− if (adHoc) {
44− imageName = "nm-adhoc";
45− } else if (signalStrength == 0) {
46− imageName = "nm-signal-00";
47− } else if (signalStrength <= 25) {
48− imageName = "nm-signal-25";
49− } else if (signalStrength <= 50) {
50− imageName = "nm-signal-50";
51− } else if (signalStrength <= 75) {
52− imageName = "nm-signal-75";
42+ onClicked: {
43+ checkBoxActive.clicked();
44+ }
45+
46+ CheckBox {
47+ id: checkBoxActive
48+ height: units.gu(3)
49+ width: units.gu(3)
50+
51+ anchors {
52+ left: parent.left
53+ leftMargin: menuItem.__contentsMargins
54+ verticalCenter: parent.verticalCenter
5355 }
5456
55− if (secure) {
56− imageName += "-secure";
57+ onClicked: {
58+ menuItem.activate();
5759 }
58− return "image://gicon/" + imageName;
5960 }
6061
61− iconFrame: false
62− control: CheckBox {
63− id: checkBoxActive
64− height: units.gu(4)
65− width: units.gu(4)
66− anchors.centerIn: parent
62+ Image {
63+ id: iconSignal
6764
68− onClicked: {
69− accessPoint.activate();
65+ width: height
66+ height: Math.min(units.gu(5), parent.height - units.gu(1))
67+ anchors {
68+ left: checkBoxActive.right
69+ leftMargin: units.gu(1)
70+ verticalCenter: parent.verticalCenter
71+ }
72+
73+ source: {
74+ var imageName = "nm-signal-100"
75+
76+ if (adHoc) {
77+ imageName = "nm-adhoc";
78+ } else if (signalStrength == 0) {
79+ imageName = "nm-signal-00";
80+ } else if (signalStrength <= 25) {
81+ imageName = "nm-signal-25";
82+ } else if (signalStrength <= 50) {
83+ imageName = "nm-signal-50";
84+ } else if (signalStrength <= 75) {
85+ imageName = "nm-signal-75";
86+ }
87+ return "image://theme/" + imageName;
88+ }
89+ }
90+
91+ Label {
92+ id: label
93+ anchors {
94+ left: iconSignal.right
95+ leftMargin: units.gu(1)
96+ verticalCenter: parent.verticalCenter
97+ right: iconSecure.visible ? iconSecure.left : parent.right
98+ rightMargin: menuItem.__contentsMargins
99+ }
100+ elide: Text.ElideRight
101+ opacity: label.enabled ? 1.0 : 0.5
102+ }
103+
104+ Image {
105+ id: iconSecure
106+ visible: secure
107+ source: "qrc:/indicators/artwork/network/secure.svg"
108+
109+ width: height
110+ height: Math.min(units.gu(4), parent.height - units.gu(1))
111+ anchors {
112+ right: parent.right
113+ rightMargin: units.gu(1)
114+ verticalCenter: parent.verticalCenter
70115 }
71116 }
72117}
plugins/Unity/Indicators/indicator.cpp−2
@@ -51,7 +51,6 @@ void Indicator::init(const QString& busName, const QSettings& settings)
5151 }
5252 }
5353
54−
5554 QVariantMap properties;
5655 properties.clear();
5756 properties.insert("busType", 1);
@@ -87,7 +86,6 @@ void Indicator::setPosition(int position)
8786 }
8887}
8988
90−
9189QVariant Indicator::indicatorProperties() const
9290{
9391 return m_properties;
plugins/Unity/Indicators/indicator.h−4
@@ -29,10 +29,6 @@
2929class UNITYINDICATORS_EXPORT Indicator : public QObject
3030{
3131 Q_OBJECT
32− Q_PROPERTY(QString identifier READ identifier NOTIFY identifierChanged)
33− Q_PROPERTY(int position READ position NOTIFY positionChanged)
34− Q_PROPERTY(QVariant indicatorProperties READ indicatorProperties NOTIFY indicatorPropertiesChanged)
35−
3632public:
3733 typedef QSharedPointer<Indicator> Ptr;
3834
plugins/Unity/Indicators/indicators.h+1−1
@@ -79,7 +79,7 @@ public:
7979 WidgetSource,
8080 PageSource,
8181 IndicatorProperties,
82− IsValid
82+ IsVisible
8383 };
8484
8585 IndicatorsModelRole(QObject*parent=0):QObject(parent) {}
plugins/Unity/Indicators/indicatorsmodel.cpp−3
@@ -206,7 +206,6 @@ QHash<int, QByteArray> IndicatorsModel::roleNames() const
206206 roles[IndicatorsModelRole::WidgetSource] = "widgetSource";
207207 roles[IndicatorsModelRole::PageSource] = "pageSource";
208208 roles[IndicatorsModelRole::IndicatorProperties] = "indicatorProperties";
209− roles[IndicatorsModelRole::IsValid] = "isValid";
210209 }
211210 return roles;
212211}
@@ -269,8 +268,6 @@ QVariant IndicatorsModel::data(const QModelIndex &index, int role) const
269268 return QVariant(indicator->indicatorProperties());
270269 }
271270 break;
272− case IndicatorsModelRole::IsValid:
273− return (indicator ? true : false);
274271 case IndicatorsModelRole::Title:
275272 case IndicatorsModelRole::Description:
276273 case IndicatorsModelRole::WidgetSource:
plugins/Unity/Indicators/indicatorsmodel.h+2−1
@@ -44,7 +44,7 @@ public:
4444 Q_INVOKABLE void load();
4545 Q_INVOKABLE void unload();
4646
47− Q_INVOKABLE QVariant data(int row, int role = Qt::DisplayRole) const;
47+ Q_INVOKABLE QVariant data(int row, int role) const;
4848
4949 /* QAbstractItemModel */
5050 QHash<int, QByteArray> roleNames() const;
@@ -56,6 +56,7 @@ public:
5656 void setIndicatorData(const QVariant& data);
5757 QVariant indicatorData() const;
5858
59+
5960Q_SIGNALS:
6061 void countChanged();
6162 void indicatorDataChanged(const QVariant& data);
plugins/Unity/Indicators/plugin.cpp+2
@@ -32,6 +32,7 @@
3232#include "rootactionstate.h"
3333#include "unitymenumodelcache.h"
3434#include "unitymenumodelstack.h"
35+#include "visibleindicatorsmodel.h"
3536
3637static QObject* menuModelCacheSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) {
3738 Q_UNUSED(engine);
@@ -47,6 +48,7 @@ void Indicators2Plugin::registerTypes(const char *uri)
4748 qmlRegisterType<UnityMenuModelStack>(uri, 0, 1, "UnityMenuModelStack");
4849 qmlRegisterType<RootActionState>(uri, 0, 1, "RootActionState");
4950 qmlRegisterType<ModelPrinter>(uri, 0, 1, "ModelPrinter");
51+ qmlRegisterType<VisibleIndicatorsModel>(uri, 0, 1, "VisibleIndicatorsModel");
5052
5153 qmlRegisterSingletonType<UnityMenuModelCache>(uri, 0, 1, "UnityMenuModelCache", menuModelCacheSingleton);
5254
plugins/Unity/Indicators/qml/IndicatorBase.qml−5
@@ -24,8 +24,6 @@ import Unity.Indicators 0.1 as Indicators
2424Item {
2525 id: indicatorItem
2626
27− // FIXME : should be disabled until bus available when we have desktop indicators
28− // for now, disable when we dont habe the correct profile.
2927 enabled: menuObjectPaths.hasOwnProperty(device)
3028
3129 //const
@@ -39,9 +37,6 @@ Item {
3937
4038 property string deviceMenuObjectPath: menuObjectPaths.hasOwnProperty(device) ? menuObjectPaths[device] : ""
4139
42− signal actionGroupUpdated()
43− signal modelUpdated()
44−
4540 property alias menuModel: cachedModel.model
4641
4742 CachedUnityMenuModel {
plugins/Unity/Indicators/qml/IndicatorWidget.qml+1
@@ -24,6 +24,7 @@ IndicatorBase {
2424 id: indicatorWidget
2525
2626 active: true
27+ enabled: false
2728 property int iconSize: height - units.gu(0.5)
2829
2930 property var actionState: Indicators.RootActionState {
plugins/Unity/Indicators/qml/MenuItemFactory.qml+5−5
@@ -159,17 +159,17 @@ Item {
159159 id: accessPoint;
160160 ICNetwork.AccessPoint {
161161 property QtObject menu: null
162−// property var strenthAction: QMenuModel.UnityMenuAction {
163−// model: menuFactory.model ? menuFactory.model : null
164−// name: menu ? menu.ext.xCanonicalWifiApStrengthAction : ""
165−// }
162+ property var strengthAction: QMenuModel.UnityMenuAction {
163+ model: menuFactory.model ? menuFactory.model : null
164+ name: menu ? menu.ext.xCanonicalWifiApStrengthAction : ""
165+ }
166166
167167 text: menu && menu.label ? menu.label : ""
168168 icon: menu ? menu.icon : ""
169169 secure: menu ? menu.ext.xCanonicalWifiApIsSecure : false
170170 adHoc: menu ? menu.ext.xCanonicalWifiApIsAdhoc : false
171171 checked: menu ? menu.isToggled : false
172−// signalStrength: strenthAction.valid ? strenthAction.state : 0
172+ signalStrength: strengthAction.valid ? strengthAction.state : 0
173173 enabled: menu ? menu.sensitive : false
174174
175175 Component.onCompleted: {
plugins/Unity/Indicators/resources/artwork/network/secure.svgnew file+71
@@ -0,0 +1,71 @@
1+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+<!-- Created with Inkscape (http://www.inkscape.org/) -->
3+
4+<svg
5+ xmlns:dc="http://purl.org/dc/elements/1.1/"
6+ xmlns:cc="http://creativecommons.org/ns#"
7+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8+ xmlns:svg="http://www.w3.org/2000/svg"
9+ xmlns="http://www.w3.org/2000/svg"
10+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12+ width="64"
13+ height="64"
14+ id="svg2986"
15+ version="1.1"
16+ inkscape:version="0.48.4 r9939"
17+ sodipodi:docname="secure.svg">
18+ <defs
19+ id="defs2988" />
20+ <sodipodi:namedview
21+ id="base"
22+ pagecolor="#ffffff"
23+ bordercolor="#666666"
24+ borderopacity="1.0"
25+ inkscape:pageopacity="0.0"
26+ inkscape:pageshadow="2"
27+ inkscape:zoom="7.9180415"
28+ inkscape:cx="7.5048745"
29+ inkscape:cy="29.401628"
30+ inkscape:current-layer="layer1"
31+ showgrid="true"
32+ inkscape:grid-bbox="true"
33+ inkscape:document-units="px"
34+ inkscape:snap-grids="false"
35+ inkscape:window-width="1549"
36+ inkscape:window-height="876"
37+ inkscape:window-x="51"
38+ inkscape:window-y="24"
39+ inkscape:window-maximized="1">
40+ <inkscape:grid
41+ type="xygrid"
42+ id="grid3012"
43+ empspacing="5"
44+ visible="true"
45+ enabled="true"
46+ snapvisiblegridlinesonly="true" />
47+ </sodipodi:namedview>
48+ <metadata
49+ id="metadata2991">
50+ <rdf:RDF>
51+ <cc:Work
52+ rdf:about="">
53+ <dc:format>image/svg+xml</dc:format>
54+ <dc:type
55+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
56+ <dc:title />
57+ </cc:Work>
58+ </rdf:RDF>
59+ </metadata>
60+ <g
61+ id="layer1"
62+ inkscape:label="Layer 1"
63+ inkscape:groupmode="layer"
64+ transform="translate(0,32)">
65+ <path
66+ inkscape:connector-curvature="0"
67+ d="M 29.999999,-18 C 25.568001,-18 22,-14.432 22,-10 v 6 h -2 c -1.107999,0 -2,0.892 -2,2 v 18 c 0,1.108 0.892001,2 2,2 h 24 c 1.108,0 2,-0.892 2,-2 V -2 c 0,-1.108 -0.892,-2 -2,-2 h -2 v -6 c 0,-4.432 -3.568001,-8 -8.000001,-8 h -4 z m 0,4 h 4 c 2.216,0 4,1.784 4,4 v 6 H 26.000001 v -6 c 0,-2.216 1.784,-4 3.999998,-4 z"
68+ style="fill:#dfdbd2;fill-rule:evenodd"
69+ id="path8" />
70+ </g>
71+</svg>
plugins/Unity/Indicators/resources/indicators.qrcnew file+5
@@ -0,0 +1,5 @@
1+<RCC>
2+ <qresource prefix="/indicators">
3+ <file>artwork/network/secure.svg</file>
4+ </qresource>
5+</RCC>
plugins/Unity/Indicators/visibleindicatorsmodel.cppnew file+94
@@ -0,0 +1,94 @@
1+/*
2+ * Copyright (C) 2012, 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+// self
18+#include "visibleindicatorsmodel.h"
19+#include "indicators.h"
20+
21+VisibleIndicatorsModel::VisibleIndicatorsModel(QObject *parent)
22+ : QIdentityProxyModel(parent),
23+ m_inserting(false)
24+{
25+ QObject::connect(this, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)), this, SLOT(onBeginRowInserted(QModelIndex, int, int)));
26+ QObject::connect(this, SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(onRowInserted(QModelIndex, int, int)));
27+}
28+
29+QHash<int, QByteArray> VisibleIndicatorsModel::roleNames() const
30+{
31+ static QHash<int, QByteArray> roles;
32+ if (roles.isEmpty())
33+ {
34+ roles[IndicatorsModelRole::Identifier] = "identifier";
35+ roles[IndicatorsModelRole::Position] = "position";
36+ roles[IndicatorsModelRole::Title] = "title";
37+ roles[IndicatorsModelRole::Description] = "description";
38+ roles[IndicatorsModelRole::WidgetSource] = "widgetSource";
39+ roles[IndicatorsModelRole::PageSource] = "pageSource";
40+ roles[IndicatorsModelRole::IndicatorProperties] = "indicatorProperties";
41+ roles[IndicatorsModelRole::IsVisible] = "isVisible";
42+ }
43+ return roles;
44+}
45+
46+void VisibleIndicatorsModel::setSourceModel(QAbstractItemModel *model)
47+{
48+ if (sourceModel() != model) {
49+ QIdentityProxyModel::setSourceModel(model);
50+ Q_EMIT modelChanged();
51+ }
52+}
53+
54+QVariantMap VisibleIndicatorsModel::visible() const
55+{
56+ return m_visible;
57+}
58+
59+void VisibleIndicatorsModel::onBeginRowInserted(const QModelIndex&, int, int)
60+{
61+ m_inserting = true;
62+}
63+
64+void VisibleIndicatorsModel::onRowInserted(const QModelIndex&, int, int)
65+{
66+ m_inserting = false;
67+}
68+
69+void VisibleIndicatorsModel::setVisible(const QVariantMap& visible)
70+{
71+ if (m_visible != visible) {
72+ m_visible = visible;
73+ Q_EMIT visibleChanged();
74+
75+ // need to tell the view that the visible data has changed.
76+ if (!m_inserting && rowCount() > 0) {
77+ Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, 0), QVector<int>() << IndicatorsModelRole::IsVisible);
78+ }
79+ }
80+}
81+
82+QVariant VisibleIndicatorsModel::data(const QModelIndex &index, int role) const
83+{
84+ if (role != IndicatorsModelRole::IsVisible) {
85+ return QIdentityProxyModel::data(index, role);
86+ }
87+
88+ if (!index.isValid()) {
89+ return false;
90+ }
91+
92+ QString ident = QIdentityProxyModel::data(index, IndicatorsModelRole::Identifier).toString();
93+ return m_visible.value(ident, false).toBool();
94+}
plugins/Unity/Indicators/visibleindicatorsmodel.hnew file+56
@@ -0,0 +1,56 @@
1+/*
2+ * Copyright (C) 2012, 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+ * Authors:
17+ * Nick Dedekind <nick.dedekind@canonical.com>
18+ */
19+
20+#ifndef VISIBLEINDICATORSMODEL_H
21+#define VISIBLEINDICATORSMODEL_H
22+
23+#include <QIdentityProxyModel>
24+
25+class VisibleIndicatorsModel : public QIdentityProxyModel
26+{
27+ Q_OBJECT
28+
29+ Q_PROPERTY(QAbstractItemModel* model READ sourceModel WRITE setSourceModel NOTIFY modelChanged)
30+ Q_PROPERTY(QVariantMap visible READ visible WRITE setVisible NOTIFY visibleChanged)
31+
32+public:
33+ explicit VisibleIndicatorsModel(QObject *parent = 0);
34+
35+ virtual void setSourceModel(QAbstractItemModel *model);
36+ virtual QHash<int, QByteArray> roleNames() const;
37+ virtual QVariant data(const QModelIndex &index, int role) const;
38+
39+ QVariantMap visible() const;
40+ void setVisible(const QVariantMap& visible);
41+
42+public Q_SLOTS:
43+ void onBeginRowInserted(const QModelIndex&, int start, int end);
44+ void onRowInserted(const QModelIndex&, int start, int end);
45+
46+Q_SIGNALS:
47+ void totalCountChanged();
48+ void modelChanged();
49+ void visibleChanged();
50+
51+private:
52+ QVariantMap m_visible;
53+ bool m_inserting;
54+};
55+
56+#endif // VISIBLEINDICATORSMODEL_H
plugins/Unity/IndicatorsLegacy/qml/IndicatorWidget.qml+2−2
@@ -23,7 +23,7 @@ import Unity.IndicatorsLegacy 0.1 as Indicators
2323IndicatorBase {
2424 id: indicatorWidget
2525
26−// enabled: false // FIXME : should be disabled until bus available when we have desktop indicators
26+ enabled: false
2727 property var action: undefined
2828 property bool started: (busType != 0) && (busName != "") && (deviceMenuObjectPath != "")
2929 property int iconSize: height - units.gu(0.5)
@@ -40,7 +40,6 @@ IndicatorBase {
4040 actionGroup.stop();
4141 }
4242 }
43− onActionChanged: actionStateChanged()
4443 onActionGroupUpdated: update_state()
4544 onModelUpdated: update_state()
4645
@@ -57,6 +56,7 @@ IndicatorBase {
5756
5857 if (extra.canonical_type === rootMenuType) {
5958 action = actionGroup.action(proxyModel.data(0, Indicators.FlatMenuProxyModelRole.Action));
59+ actionStateChanged();
6060 }
6161 }
6262
plugins/Unity/applicationpreview.cpp+5−1
@@ -19,6 +19,7 @@
1919
2020// local
2121#include "applicationpreview.h"
22+#include "iconutils.h"
2223
2324#include <QDebug>
2425
@@ -61,7 +62,10 @@ QString ApplicationPreview::license() const
6162QString ApplicationPreview::appIcon() const
6263{
6364 if (m_unityAppPreview) {
64− return QString::fromUtf8(g_icon_to_string(m_unityAppPreview->app_icon()));
65+ auto giconString = g_icon_to_string(m_unityAppPreview->app_icon());
66+ QString result(gIconToDeclarativeImageProviderString(QString::fromUtf8(giconString)));
67+ g_free(giconString);
68+ return result;
6569 } else {
6670 qWarning() << "Preview not set";
6771 }
plugins/Unity/categoryresults.cpp+5−2
@@ -19,6 +19,7 @@
1919
2020// self
2121#include "categoryresults.h"
22+#include "iconutils.h"
2223
2324// TODO: use something from libunity once it's public
2425enum ResultsColumn {
@@ -76,8 +77,10 @@ CategoryResults::data(const QModelIndex& index, int role) const
7677 switch (role) {
7778 case RoleUri:
7879 return DeeListModel::data(index, ResultsColumn::URI);
79− case RoleIconHint:
80− return DeeListModel::data(index, ResultsColumn::ICON_HINT);
80+ case RoleIconHint: {
81+ QString giconString(DeeListModel::data(index, ResultsColumn::ICON_HINT).toString());
82+ return QVariant::fromValue(gIconToDeclarativeImageProviderString(giconString));
83+ }
8184 case RoleCategory:
8285 return DeeListModel::data(index, ResultsColumn::CATEGORY);
8386 case RoleMimetype:
plugins/Unity/categoryresults.h+1−1
@@ -24,7 +24,7 @@
2424// dee-qt
2525#include "deelistmodel.h"
2626
27−class CategoryResults : public DeeListModel
27+class Q_DECL_EXPORT CategoryResults : public DeeListModel
2828{
2929 Q_OBJECT
3030
plugins/Unity/iconutils.cppnew file+91
@@ -0,0 +1,91 @@
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+ * Authors:
17+ * Michal Hruby <michal.hruby@canonical.com>
18+ */
19+
20+#include <QStringList>
21+#include <QUrl>
22+
23+#include <gio/gio.h>
24+#include "iconutils.h"
25+
26+#define BASE_THEME_ICON_URI "image://theme/"
27+
28+QString gIconToDeclarativeImageProviderString(QString const &giconString)
29+{
30+ if (giconString.isEmpty()) return giconString;
31+
32+ if (giconString.startsWith('/') || giconString.startsWith(QLatin1String("http")) ||
33+ giconString.startsWith(QLatin1String("file:"))) {
34+ return giconString;
35+ }
36+
37+ if (!giconString.startsWith(QLatin1String(". "))) {
38+ // must be a themed icon
39+ QString themedIcon(BASE_THEME_ICON_URI);
40+ themedIcon.append(giconString);
41+ return themedIcon;
42+ }
43+
44+ // special case annotated icon
45+ if (giconString.startsWith(QLatin1String(". UnityProtocolAnnotatedIcon "))) {
46+ QString annotatedIcon;
47+ QString serializedData(QUrl::fromPercentEncoding(giconString.mid(29).toUtf8()));
48+ GVariant *variant = g_variant_parse(G_VARIANT_TYPE_VARDICT, serializedData.toUtf8().constData(), NULL, NULL, NULL);
49+ gchar *baseUri;
50+ if (variant != NULL && g_variant_lookup(variant, "base-icon", "&s", &baseUri)) {
51+ annotatedIcon = gIconToDeclarativeImageProviderString(QString(baseUri));
52+ // FIXME: enclose in image://annotated/... once unity supports that
53+ }
54+ if (variant != NULL) g_variant_unref(variant);
55+
56+ return annotatedIcon;
57+ }
58+
59+ // handle real gicon strings
60+ QString result;
61+ GError *error = NULL;
62+ GIcon *icon = g_icon_new_for_string(giconString.toLocal8Bit().constData(), &error);
63+ if (error != NULL || icon == NULL) {
64+ qWarning("Unable to deserialize icon: %s", giconString.toLocal8Bit().constData());
65+ g_clear_error(&error);
66+ return result;
67+ }
68+
69+ if (G_IS_THEMED_ICON(icon)) {
70+ QString themedIcon(BASE_THEME_ICON_URI);
71+ QStringList list;
72+ const char* const *iconNames = g_themed_icon_get_names(G_THEMED_ICON(icon));
73+ if (iconNames != NULL) {
74+ for (const char * const *iter = iconNames; *iter != NULL; ++iter) {
75+ list << QLatin1String(*iter);
76+ }
77+ }
78+ themedIcon.append(list.join(QString(",")));
79+ result = themedIcon;
80+ } else if (G_IS_FILE_ICON(icon)) {
81+ GFile *file = g_file_icon_get_file(G_FILE_ICON(icon));
82+ gchar *uri = g_file_get_uri(file);
83+ QString iconUri(uri);
84+ g_free(uri);
85+ result = iconUri;
86+ }
87+
88+ g_object_unref(icon);
89+
90+ return result;
91+}
plugins/Unity/iconutils.hnew file+27
@@ -0,0 +1,27 @@
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+ * Authors:
17+ * Michal Hruby <michal.hruby@canonical.com>
18+ */
19+
20+#ifndef ICONUTILS_H
21+#define ICONUTILS_H
22+
23+#include <QString>
24+
25+QString gIconToDeclarativeImageProviderString(QString const &giconString);
26+
27+#endif
plugins/Unity/preview.cpp+5−1
@@ -26,6 +26,7 @@
2626#include "moviepreview.h"
2727#include "musicpreview.h"
2828#include "socialpreview.h"
29+#include "iconutils.h"
2930#include "variantutils.h"
3031
3132// Qt
@@ -102,7 +103,10 @@ QVariantMap Preview::infoHintsHash() const
102103QString Preview::image() const
103104{
104105 if (m_unityPreview) {
105− return QString::fromUtf8(g_icon_to_string(m_unityPreview->image()));
106+ auto giconString = g_icon_to_string(m_unityPreview->image());
107+ QString result(gIconToDeclarativeImageProviderString(QString::fromUtf8(giconString)));
108+ g_free(giconString);
109+ return result;
106110 } else {
107111 qWarning() << "Preview not set";
108112 }
plugins/Unity/socialpreview.cpp+5−1
@@ -19,6 +19,7 @@
1919
2020#include "socialpreview.h"
2121#include "socialpreviewcomment.h"
22+#include "iconutils.h"
2223
2324#include <QDebug>
2425
@@ -51,7 +52,10 @@ QString SocialPreview::content() const
5152QString SocialPreview::avatar() const
5253{
5354 if (m_unitySocialPreview) {
54− return QString::fromUtf8(g_icon_to_string(m_unitySocialPreview->avatar()));
55+ auto giconString = g_icon_to_string(m_unitySocialPreview->avatar());
56+ QString result(gIconToDeclarativeImageProviderString(QString::fromUtf8(giconString)));
57+ g_free(giconString);
58+ return result;
5559 } else {
5660 qWarning() << "Preview not set";
5761 }
plugins/Utils/qsortfilterproxymodelqml.cpp+20
@@ -121,3 +121,23 @@ QSortFilterProxyModelQML::findFirst(int role, const QVariant& value) const
121121 return -1;
122122 }
123123}
124+
125+int
126+QSortFilterProxyModelQML::mapFromSource(int row)
127+{
128+ if (sourceModel() != NULL) {
129+ return QSortFilterProxyModel::mapFromSource(sourceModel()->index(row, 0)).row();
130+ } else {
131+ return -1;
132+ }
133+}
134+
135+int
136+QSortFilterProxyModelQML::mapToSource(int row)
137+{
138+ if (sourceModel() != NULL) {
139+ return QSortFilterProxyModel::mapToSource(index(row, 0)).row();
140+ } else {
141+ return -1;
142+ }
143+}
plugins/Utils/qsortfilterproxymodelqml.h+3
@@ -45,6 +45,9 @@ public:
4545 void setModel(QAbstractItemModel *model);
4646 void setInvertMatch(bool invertMatch);
4747
48+ Q_INVOKABLE int mapFromSource(int row);
49+ Q_INVOKABLE int mapToSource(int row);
50+
4851Q_SIGNALS:
4952 void totalCountChanged();
5053 void countChanged();
tests/autopilot/unity8/shell/tests/test_hud.py+7−2
@@ -34,6 +34,8 @@ class TestHud(UnityTestCase):
3434
3535 def test_show_hud_button_appears(self):
3636 """Swiping up while an app is active must show the 'show hud' button.
37+ The button must disappear not opening the HUD when releasing the
38+ mouse again somewhere on the screen except on the button itself.
3739
3840 """
3941 self.launch_unity()
@@ -49,9 +51,12 @@ class TestHud(UnityTestCase):
4951 hud_show_button
5052 )
5153 self.touch.press(swipe_coords.start_x, swipe_coords.start_y)
52− self.addCleanup(self.touch.release)
53− self.touch._finger_move(swipe_coords.end_x, swipe_coords.end_y)
54+ self.addCleanup(self._maybe_release_finger)
55+ self.touch._finger_move(swipe_coords.end_x, swipe_coords.end_y + hud_show_button.height);
5456 self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
57+ self.touch.release();
58+ self.assertThat(hud_show_button.opacity, Eventually(Equals(0.0)))
59+ self.assertThat(hud.shown, Equals(False))
5560
5661 def test_show_hud_appears(self):
5762 """Releasing the touch on the 'show hud' button must display the hud.
tests/mocks/Unity/CMakeLists.txt+1
@@ -17,6 +17,7 @@ add_definitions(-DQT_NO_KEYWORDS)
1717
1818set(UnityQML_SOURCES
1919 ${CMAKE_SOURCE_DIR}/plugins/Unity/categoryresults.cpp
20+ ${CMAKE_SOURCE_DIR}/plugins/Unity/iconutils.cpp
2021 fake_applications_scope.cpp
2122 fake_preview.cpp
2223 fake_scope.cpp
tests/mocks/Unity/Indicators/CMakeLists.txt+1
@@ -13,6 +13,7 @@ set(IndicatorsFakeQml_SOURCES
1313 fakeplugin.cpp
1414 ${CMAKE_SOURCE_DIR}/plugins/Unity/Indicators/indicators.h
1515 ${CMAKE_SOURCE_DIR}/plugins/Unity/Indicators/menucontentactivator.cpp
16+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Indicators/visibleindicatorsmodel.cpp
1617)
1718
1819set(IndicatorsFakeQml_RESOURCES
tests/mocks/Unity/Indicators/IndicatorsModel.qml+47−76
@@ -23,82 +23,53 @@ ListModel {
2323
2424 function load() {}
2525
26− ListElement {
27− identifier: "indicator-fake1";
28− priority: 0
29− title: "Menu1";
30− description: "";
31− widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget1.qml";
32− pageSource: "qrc:/tests/indciators/qml/fake_menu_page1.qml";
33− indicatorProperties: "";
34− isValid: "";
35− }
36− ListElement {
37− identifier: "indicator-fake2";
38− priority: 1
39− title: "Menu2";
40− description: "";
41− widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget2.qml";
42− pageSource: "qrc:/tests/indciators/qml/fake_menu_page2.qml";
43− indicatorProperties: "";
44− isValid: "";
45− }
46− ListElement {
47− identifier: "indicator-fake3";
48− priority: 2
49− title: "Menu3";
50− description: "";
51− widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget3.qml";
52− pageSource: "qrc:/tests/indciators/qml/fake_menu_page3.qml";
53− indicatorProperties: "";
54− isValid: "";
55− }
56− ListElement {
57− identifier: "indicator-fake4";
58− priority: 3
59− title: "Menu4";
60− description: "";
61− widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget4.qml";
62− pageSource: "qrc:/tests/indciators/qml/fake_menu_page4.qml";
63− indicatorProperties: "";
64− isValid: "";
65− }
66− ListElement {
67− identifier: "indicator-fake5";
68− priority: 4
69− title: "Menu5";
70− description: "";
71− widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget5.qml";
72− pageSource: "qrc:/tests/indciators/qml/fake_menu_page5.qml";
73− indicatorProperties: "";
74− isValid: "";
75− }
26+ // Need to do this dynamically.
27+ // Apparently ListModels dont order roles visually when using ListElement
28+ // which throws off the filter for non-visible indicators.
29+ Component.onCompleted: {
30+ append({ "identifier": "indicator-fake1",
31+ "priority": 0,
32+ "title": "Menu1",
33+ "description": "",
34+ "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget1.qml",
35+ "pageSource": "qrc:/tests/indciators/qml/fake_menu_page1.qml",
36+ "indicatorProperties": ""
37+ });
7638
77− function data(row, role) {
78− if (role == Indicators.IndicatorsModelRole.Identifier) {
79− return get(row).identifier;
80− }
81− else if (role == Indicators.IndicatorsModelRole.Priority) {
82− return get(row).priority
83− }
84− else if (role == Indicators.IndicatorsModelRole.Title) {
85− return get(row).title
86− }
87− else if (role == Indicators.IndicatorsModelRole.Description) {
88− return get(row).description
89− }
90− else if (role == Indicators.IndicatorsModelRole.WidgetSource) {
91− return get(row).widgetSource
92− }
93− else if (role == Indicators.IndicatorsModelRole.PageSource) {
94− return get(row).pageSource
95− }
96− else if (role == Indicators.IndicatorsModelRole.IndicatorProperties) {
97− return get(row).indicatorProperties
98− }
99− else if (role == Indicators.IndicatorsModelRole.IsValid) {
100− return get(row).isValid
101− }
102− }
39+ append({ "identifier": "indicator-fake2",
40+ "priority": 1,
41+ "title": "Menu2",
42+ "description": "",
43+ "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget2.qml",
44+ "pageSource": "qrc:/tests/indciators/qml/fake_menu_page2.qml",
45+ "indicatorProperties": ""
46+ });
47+
48+ append({ "identifier": "indicator-fake3",
49+ "priority": 2,
50+ "title": "Menu3",
51+ "description": "",
52+ "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget3.qml",
53+ "pageSource": "qrc:/tests/indciators/qml/fake_menu_page3.qml",
54+ "indicatorProperties": ""
55+ });
10356
57+ append({ "identifier": "indicator-fake4",
58+ "priority": 3,
59+ "title": "Menu4",
60+ "description": "",
61+ "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget4.qml",
62+ "pageSource": "qrc:/tests/indciators/qml/fake_menu_page4.qml",
63+ "indicatorProperties": ""
64+ });
65+
66+ append({ "identifier": "indicator-fake5",
67+ "priority": 4,
68+ "title": "Menu5",
69+ "description": "",
70+ "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget5.qml",
71+ "pageSource": "qrc:/tests/indciators/qml/fake_menu_page5.qml",
72+ "indicatorProperties": ""
73+ });
74+ }
10475}
tests/mocks/Unity/Indicators/fakeplugin.cpp+2
@@ -25,12 +25,14 @@
2525// local
2626#include "indicators.h"
2727#include "menucontentactivator.h"
28+#include "visibleindicatorsmodel.h"
2829
2930void IndicatorsFakePlugin::registerTypes(const char * uri)
3031{
3132 Q_INIT_RESOURCE(indicators_fake);
3233
3334 qmlRegisterType<MenuContentActivator>(uri, 0, 1, "MenuContentActivator");
35+ qmlRegisterType<VisibleIndicatorsModel>(uri, 0, 1, "VisibleIndicatorsModel");
3436
3537 qmlRegisterUncreatableType<MenuContentState>(uri, 0, 1, "MenuContentState", "Can't create MenuContentState class");
3638 qmlRegisterUncreatableType<ActionState>(uri, 0, 1, "ActionState", "Can't create ActionState class");
tests/mocks/Unity/Indicators/qml/fake_menu_widget2.qml+2
@@ -20,4 +20,6 @@ Rectangle {
2020 width: 40
2121 height: 40
2222 color : "yellow"
23+
24+ enabled: false
2325}
tests/plugins/Unity/CMakeLists.txt+4
@@ -5,6 +5,7 @@ pkg_check_modules(UNITYCORE REQUIRED unity-core-6.0)
55pkg_check_modules(LIBUNITYPROTO REQUIRED unity-protocol-private)
66pkg_check_modules(LIBUNITY REQUIRED unity)
77pkg_check_modules(LIBSIGCPP REQUIRED sigc++-2.0)
8+pkg_check_modules(QTDEE REQUIRED libdee-qt5>=3.2)
89
910include_directories(
1011 ${Unity-qml_SOURCE_DIR}
@@ -14,6 +15,7 @@ include_directories(
1415 ${LIBUNITY_INCLUDE_DIRS}
1516 ${LIBSIGCPP_INCLUDE_DIRS}
1617 ${UNITYCORE_INCLUDE_DIRS}
18+ ${QTDEE_INCLUDE_DIRS}
1719 )
1820
1921macro(run_tests)
@@ -36,6 +38,7 @@ macro(run_tests)
3638 ${LIBUNITY_LDFLAGS}
3739 ${LIBUNITYPROTO_LDFLAGS}
3840 ${LIBSIGCPP_LDFLAGS}
41+ ${QTDEE_LDFLAGS}
3942 )
4043
4144 set(_test_list "${_test_list};${_test}")
@@ -46,4 +49,5 @@ run_tests(
4649 signalslisttest
4750 previewbindingstest
4851 filtersbindingstest
52+ resultstest
4953 )
tests/plugins/Unity/resultstest.cppnew file+104
@@ -0,0 +1,104 @@
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+ * Authors:
17+ * Michal Hruby <michal.hruby@canonical.com>
18+ */
19+
20+#include <QTest>
21+#include <dee.h>
22+
23+#include "resultstest.h"
24+#include "categoryresults.h"
25+
26+static DeeModel* createBackendModel()
27+{
28+ auto model = dee_sequence_model_new();
29+ dee_model_set_schema(model, "s", "s", "u", "u", "s", "s", "s", "s", "a{sv}", NULL);
30+
31+ return model;
32+}
33+
34+void ResultsTest::testAllColumns()
35+{
36+ auto deeModel = createBackendModel();
37+ GVariantBuilder builder;
38+ g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
39+ g_variant_builder_add(&builder, "{sv}", "metadata-field", g_variant_new_string("foo"));
40+ dee_model_append (deeModel,
41+ "test:uri",
42+ "themed-icon",
43+ 4,
44+ 0,
45+ "application/octet-stream",
46+ "Test",
47+ "Comment",
48+ "test:dnd-uri",
49+ g_variant_builder_end(&builder));
50+
51+ CategoryResults* results = new CategoryResults(this);
52+ results->setModel(deeModel);
53+
54+ auto index = results->index(0, 0); // there's just one result
55+ QCOMPARE(index.data(CategoryResults::Roles::RoleUri).toString(), QString("test:uri"));
56+ QCOMPARE(index.data(CategoryResults::Roles::RoleIconHint).toString(), QString("image://theme/themed-icon"));
57+ QCOMPARE(index.data(CategoryResults::Roles::RoleCategory).toInt(), 4);
58+ QCOMPARE(index.data(CategoryResults::Roles::RoleMimetype).toString(), QString("application/octet-stream"));
59+ QCOMPARE(index.data(CategoryResults::Roles::RoleTitle).toString(), QString("Test"));
60+ QCOMPARE(index.data(CategoryResults::Roles::RoleComment).toString(), QString("Comment"));
61+ QCOMPARE(index.data(CategoryResults::Roles::RoleDndUri).toString(), QString("test:dnd-uri"));
62+ auto metadata = index.data(CategoryResults::Roles::RoleMetadata).toHash();
63+ QCOMPARE(metadata["metadata-field"].toString(), QString("foo"));
64+}
65+
66+void ResultsTest::testIconColumn_data()
67+{
68+ QTest::addColumn<QString>("giconString");
69+ QTest::addColumn<QString>("result");
70+
71+ QTest::newRow("absolute path") << "/usr/share/icons/example.png" << "/usr/share/icons/example.png";
72+ QTest::newRow("file uri") << "file:///usr/share/icons/example.png" << "file:///usr/share/icons/example.png";
73+ QTest::newRow("http uri") << "http://images.ubuntu.com/example.jpg" << "http://images.ubuntu.com/example.jpg";
74+ QTest::newRow("themed icon") << "accessories-other" << "image://theme/accessories-other";
75+ QTest::newRow("fileicon") << ". GFileIcon http://example.org/resource.gif" << "http://example.org/resource.gif";
76+ QTest::newRow("themedicon") << ". GThemedIcon accessories-other accessories generic" << "image://theme/accessories-other,accessories,generic";
77+ QTest::newRow("annotatedicon") << ". UnityProtocolAnnotatedIcon %7B'base-icon':%20%3C'.%20GThemedIcon%20accessories-other%20accessories%20generic'%3E%7D" << "image://theme/accessories-other,accessories,generic";
78+}
79+
80+void ResultsTest::testIconColumn()
81+{
82+ QFETCH(QString, giconString);
83+ QFETCH(QString, result);
84+ auto deeModel = createBackendModel();
85+ dee_model_append (deeModel,
86+ "test:uri",
87+ giconString.toLocal8Bit().constData(),
88+ 0,
89+ 0,
90+ "application/octet-stream",
91+ "Test",
92+ "",
93+ "test:dnd-uri",
94+ g_variant_new_array(g_variant_type_element(G_VARIANT_TYPE_VARDICT), NULL, 0));
95+
96+ CategoryResults* results = new CategoryResults(this);
97+ results->setModel(deeModel);
98+
99+ auto index = results->index(0, 0); // there's just one result
100+ auto transformedIcon = index.data(CategoryResults::Roles::RoleIconHint).toString();
101+ QCOMPARE(transformedIcon, result);
102+}
103+
104+QTEST_MAIN(ResultsTest)
tests/plugins/Unity/resultstest.hnew file+35
@@ -0,0 +1,35 @@
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+ * Authors:
17+ * Michal Hruby <michal.hruby@canonical.com>
18+ */
19+
20+#ifndef RESULTSTEST_H
21+#define RESULTSTEST_H
22+
23+#include <QObject>
24+
25+class ResultsTest : public QObject
26+{
27+ Q_OBJECT
28+
29+ private Q_SLOTS:
30+ void testAllColumns();
31+ void testIconColumn_data();
32+ void testIconColumn();
33+};
34+
35+#endif
tests/qmltests/CMakeLists.txt+1−1
@@ -66,7 +66,7 @@ add_qml_test(Launcher Launcher IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltes
6666add_qml_test(Notifications Notifications IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_SOURCE_DIR}/tests/mocks)
6767add_qml_test(Panel IndicatorRow)
6868add_qml_test(Panel Indicators IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
69−add_qml_test(Panel MenuContent)
69+add_qml_test(Panel MenuContent IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
7070add_qml_test(Panel Panel IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
7171add_qml_test(Panel SearchIndicator)
7272add_qml_test(SideStage SideStage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS}
tests/qmltests/Panel/tst_IndicatorItem.qml+2−2
@@ -53,9 +53,9 @@ Rectangle {
5353 }
5454
5555 function test_empty() {
56− compare(indicatorItem.visible, false, "IndicatorItem should not be visible.");
56+ compare(indicatorItem.indicatorVisible, false, "IndicatorItem should not be visible.");
5757 indicatorItem.widgetSource = "qrc:/tests/indciators/qml/fake_menu_widget1.qml";
58− tryCompare(indicatorItem, "visible", true);
58+ tryCompare(indicatorItem, "indicatorVisible", true);
5959 }
6060 }
6161}
tests/qmltests/Panel/tst_Indicators.qml+30−11
@@ -100,26 +100,29 @@ Item {
100100 {
101101 // tests changing the lateral position of the revealer activates the correct indicator items.
102102
103− var indicator_row = findChild(indicators, "indicatorRow")
104− var row_repeater = findChild(indicators, "rowRepeater")
103+ var indicatorRow = findChild(indicators, "indicatorRow")
104+ var rowRepeater = findChild(indicators, "rowRepeater")
105105
106− for (var i = 0; i < row_repeater.count; i++) {
107− var indicator_item = row_repeater.itemAt(i);
106+ for (var i = 0; i < rowRepeater.count; i++) {
107+ var indicatorItem = rowRepeater.itemAt(i);
108108
109− var indicator_position = indicators.mapFromItem(indicator_item,
110− indicator_item.width/2, indicator_item.height/2)
109+ if (!indicatorItem.visible)
110+ continue;
111+
112+ var indicatorPosition = indicators.mapFromItem(indicatorItem,
113+ indicatorItem.width/2, indicatorItem.height/2)
111114
112115 touchFlick(indicators,
113− indicator_position.x, indicator_position.y,
114− indicator_position.x, indicators.openedHeight * 0.4,
116+ indicatorPosition.x, indicatorPosition.y,
117+ indicatorPosition.x, indicators.openedHeight * 0.4,
115118 true /* beginTouch */, false /* endTouch */)
116119
117− compare(indicator_row.currentItem, indicator_item,
120+ compare(indicatorRow.currentItem, indicatorItem,
118121 "Incorrect item activated at position " + i);
119122
120123 touchFlick(indicators,
121− indicator_position.x, indicators.openedHeight * 0.4,
122− indicator_position.x, indicator_position.y,
124+ indicatorPosition.x, indicators.openedHeight * 0.4,
125+ indicatorPosition.x, indicatorPosition.y,
123126 false /* beginTouch */, true /* endTouch */)
124127
125128 // wait until fully closed
@@ -158,5 +161,21 @@ Item {
158161 compare(indicators.fullyOpened, true);
159162 }
160163
164+ function test_row_visible_menuContent_visible_data() { return [
165+ {tag: "visible", index: 0, name: "indicator-fake1", visible: true },
166+ {tag: "invisible", index: 1, name: "indicator-fake2", visible: false }]
167+ }
168+
169+ function test_row_visible_menuContent_visible(data) {
170+ var indicatorTabs = findChild(indicators, "tabs");
171+ var rowRepeater = findChild(indicators, "rowRepeater");
172+
173+ var indicatorItem = rowRepeater.itemAt(data.index);
174+ tryCompareFunction(function() { return indicatorItem.width > 0}, true);
175+ tryCompare(indicatorItem, "visible", data.visible);
176+
177+ var indicatorTab = findChild(indicatorTabs, data.name)
178+ tryCompareFunction(function() { return indicatorTab !== undefined }, data.visible);
179+ }
161180 }
162181}
tests/qmltests/Panel/tst_MenuContent.qml+9−2
@@ -48,8 +48,15 @@ Item {
4848 id: menuContent
4949 indicatorsModel: indicatorsModel
5050 contentReleaseInterval: 50
51−
5251 height: parent.height - 50
52+
53+ visibleIndicators: {
54+ 'indicator-fake1': true,
55+ 'indicator-fake2': true,
56+ 'indicator-fake3': true,
57+ 'indicator-fake4': true,
58+ 'indicator-fake5': true
59+ }
5360 }
5461
5562 Rectangle {
@@ -134,7 +141,7 @@ Item {
134141 var menuIndex = i%menuCount;
135142
136143 activate_content(menuIndex);
137− testTabObjectName = indicatorsModel.data(menuIndex, Indicators.IndicatorsModelRole.Identifier);
144+ testTabObjectName = indicatorsModel.get(menuIndex).identifier;
138145 compare(tabs.selectedTabIndex, menuIndex, "Current tab index does not match selected tab index");
139146 tryCompareFunction(selected_tab_equals_test_tab, true);
140147 }
tests/qmltests/Panel/tst_Panel.qml+3
@@ -159,6 +159,9 @@ Item {
159159 var indicatorItem = get_indicator_item(i);
160160 verify(indicatorItem != undefined);
161161
162+ if (!indicatorItem.visible)
163+ continue;
164+
162165 var indicatorItemCoord = get_indicator_item_position(i);
163166
164167 touchPress(panel,