on xenial help sign in
Merged trunk.
commit808987a0d48f4b90ca9fa4ca53f6fd20ed8f05b6 authorPawel Stolowski <pawel.stolowski@canonical.com> dateTue 1 Oct 2013, 12:48 (13 years ago) parentdeafa96bfc301c
302 files changed+7351−2544
Applications/Application.qml+1−1 Bottombar/Bottombar.qml+5−3 CMakeLists.txt+4 Components/ApplicationManagerWrapper.qml+89−42 Components/ApplicationScreenshot.qml+2−2 Components/ApplicationsModelStageFiltered.qml+49 Components/CrossFadeImage.qml−151 Components/EdgeDemo.qml+29−22 Components/EdgeDemoOverlay.qml+9−1 Components/IconUtil.js−42 Components/LazyImage.qml+172 Components/ResponsiveGridView.qml+1−1 Components/Stage.qml+1−1 Components/VolumeControl.qml+5−20 Components/graphics/close@20.png Dash/Apps/AppPreview.qml+12−2 Dash/Apps/AppReviews.qml+3 Dash/Apps/ApplicationsFilterGrid.qml+1−2 Dash/Apps/RunningApplicationTile.qml+2−3 Dash/Apps/RunningApplicationsGrid.qml+4−4 Dash/DashBar.qml+2−3 Dash/DashPreview.qml+13 Dash/Generic/GenericCarousel.qml+1−2 Dash/Generic/GenericFilterGrid.qml+1−2 Dash/Generic/GenericPreview.qml+1−2 Dash/GenericScopeView.qml+28−13 Dash/Music/MusicFilterGrid.qml+12−2 Dash/graphics/phone/home.png Dash/graphics/phone/music.png Dash/graphics/phone/videos.png Dash/graphics/tablet/apps.png Dash/graphics/tablet/home.png Dash/graphics/tablet/music.png Dash/graphics/tablet/people.png Dash/graphics/tablet/videos.png Greeter/Greeter.qml+2 Greeter/GreeterContent.qml+21−3 Greeter/Infographics.qml+1−2 Greeter/graphics/infographic_circle.png Greeter/graphics/infographic_circle_back.png Launcher/Launcher.qml+4−4 Launcher/LauncherDelegate.qml+21−10 Launcher/LauncherPanel.qml+12−5 Launcher/graphics/focused_app_arrow@30.png MouseTouchAdaptor.cpp+29−12 MouseTouchAdaptor.h+2−5 Panel/IndicatorItem.qml+2−3 Panel/IndicatorRow.qml+19−1 Panel/Indicators.qml+18−2 Panel/Indicators/DatetimeIndicatorWidget.qml+4−2 Panel/Indicators/DefaultIndicatorWidget.qml+3−6 Panel/Indicators/DefaultIndicatorWidget2.qml+43−16 Panel/Indicators/MessagingIndicatorWidget.qml+1−1 Panel/Indicators/NetworkIndicatorWidget.qml+10−7 Panel/Indicators/SoundIndicatorWidget.qml+2−1 Panel/IndicatorsDataModel.qml+2−2 Panel/MenuContent.qml+37−9 Shell.qml+60−28 SideStage/SideStage.qml+1−1 build+9 debian/changelog+318 debian/control+11−8 debian/unity8-private.install+1 debian/unity8.install−1 main.cpp+76−9 plugins/AccountsService/AccountsService.cpp+67−37 plugins/AccountsService/AccountsService.h+34−8 plugins/AccountsService/AccountsServiceDBusAdaptor.cpp+126 plugins/AccountsService/AccountsServiceDBusAdaptor.h+54 plugins/AccountsService/CMakeLists.txt+1 plugins/AccountsService/com.canonical.unity.AccountsService.xml+7 plugins/AccountsService/plugin.cpp+2 plugins/CMakeLists.txt+1 plugins/ListViewWithPageHeader/listviewwithpageheader.cpp+20−1 plugins/ListViewWithPageHeader/listviewwithpageheader.h+1 plugins/SessionBroadcast/CMakeLists.txt+13 plugins/SessionBroadcast/SessionBroadcast.cpp+41 plugins/SessionBroadcast/SessionBroadcast.h+41 plugins/SessionBroadcast/plugin.cpp+35 plugins/SessionBroadcast/plugin.h+33 plugins/SessionBroadcast/qmldir+3 plugins/Unity/CMakeLists.txt+3 plugins/Unity/Indicators/CMakeLists.txt+10 plugins/Unity/IndicatorsLegacy/Messaging/CMakeLists.txt → plugins/Unity/Indicators/Messaging/CMakeLists.txt plugins/Unity/IndicatorsLegacy/Messaging/qml/ActionButton.qml → plugins/Unity/Indicators/Messaging/qml/ActionButton.qml plugins/Unity/IndicatorsLegacy/Messaging/qml/ActionTextField.qml → plugins/Unity/Indicators/Messaging/qml/ActionTextField.qml+10−7 plugins/Unity/Indicators/Messaging/qml/CMakeLists.txt+5 plugins/Unity/IndicatorsLegacy/Messaging/qml/GroupedMessage.qml → plugins/Unity/Indicators/Messaging/qml/GroupedMessage.qml+13−18 plugins/Unity/IndicatorsLegacy/Messaging/qml/HeroMessage.qml → plugins/Unity/Indicators/Messaging/qml/HeroMessage.qml+25−22 plugins/Unity/IndicatorsLegacy/Messaging/qml/HeroMessageHeader.qml → plugins/Unity/Indicators/Messaging/qml/HeroMessageHeader.qml plugins/Unity/Indicators/Messaging/qml/MessageMenuItemFactory.qml+180 plugins/Unity/IndicatorsLegacy/Messaging/qml/QuickReply.qml → plugins/Unity/Indicators/Messaging/qml/QuickReply.qml+10−5 plugins/Unity/IndicatorsLegacy/Messaging/qml/SimpleTextMessage.qml → plugins/Unity/Indicators/Messaging/qml/SimpleTextMessage.qml+7−4 plugins/Unity/IndicatorsLegacy/Messaging/qml/SnapDecision.qml → plugins/Unity/Indicators/Messaging/qml/SnapDecision.qml+33−14 plugins/Unity/IndicatorsLegacy/Messaging/qml/TextMessage.qml → plugins/Unity/Indicators/Messaging/qml/TextMessage.qml+12−4 plugins/Unity/IndicatorsLegacy/Messaging/qml/qmldir → plugins/Unity/Indicators/Messaging/qml/qmldir+2−2 plugins/Unity/IndicatorsLegacy/Messaging/qml/utils.js → plugins/Unity/Indicators/Messaging/qml/utils.js 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+4 plugins/Unity/Indicators/qml/BaseMenuItem.qml+1−1 plugins/Unity/Indicators/qml/IndicatorBase.qml−5 plugins/Unity/Indicators/qml/IndicatorPage.qml+33−6 plugins/Unity/Indicators/qml/IndicatorWidget.qml+1 plugins/Unity/Indicators/qml/MenuItemFactory.qml+68−33 plugins/Unity/IndicatorsLegacy/resources/artwork/messaging/default_app.svg → plugins/Unity/Indicators/resources/artwork/messaging/default_app.svg plugins/Unity/IndicatorsLegacy/resources/artwork/messaging/default_contact.png → plugins/Unity/Indicators/resources/artwork/messaging/default_contact.png plugins/Unity/IndicatorsLegacy/resources/artwork/messaging/message_sms01_54px.png → plugins/Unity/Indicators/resources/artwork/messaging/message_sms01_54px.png plugins/Unity/Indicators/resources/artwork/network/secure.svg+71 plugins/Unity/Indicators/resources/indicators.qrc+8 plugins/Unity/Indicators/rootactionstate.cpp+52−22 plugins/Unity/Indicators/rootactionstate.h+9−6 plugins/Unity/Indicators/visibleindicatorsmodel.cpp+94 plugins/Unity/Indicators/visibleindicatorsmodel.h+56 plugins/Unity/IndicatorsLegacy/CMakeLists.txt−1 plugins/Unity/IndicatorsLegacy/Messaging/qml/CMakeLists.txt−5 plugins/Unity/IndicatorsLegacy/Messaging/qml/MessageMenuItem.qml−96 plugins/Unity/IndicatorsLegacy/Network/qml/AccessPoint.qml+2−2 plugins/Unity/IndicatorsLegacy/qml/IndicatorWidget.qml+2−2 plugins/Unity/IndicatorsLegacy/qml/MenuItemFactory.qml−8 plugins/Unity/IndicatorsLegacy/resources/indicators.qrc−3 plugins/Unity/Launcher/CMakeLists.txt+11−2 plugins/Unity/Launcher/backend/launcherbackend.cpp+261−59 plugins/Unity/Launcher/backend/launcherbackend.h+36−5 plugins/Unity/Launcher/launcheritem.cpp+15−7 plugins/Unity/Launcher/launcheritem.h+5−3 plugins/Unity/Launcher/launchermodel.cpp+129−12 plugins/Unity/Launcher/launchermodel.h+11−1 plugins/Unity/applicationpreview.cpp+5−1 plugins/Unity/categories.cpp+12−4 plugins/Unity/categories.h+1−2 plugins/Unity/categoryresults.cpp+5−2 plugins/Unity/categoryresults.h+1−1 plugins/Unity/checkoptionfilter.cpp+3−1 plugins/Unity/filter.h+3−2 plugins/Unity/genericoptionsmodel.cpp+20−3 plugins/Unity/genericoptionsmodel.h+4−2 plugins/Unity/iconutils.cpp+91 plugins/Unity/iconutils.h+27 plugins/Unity/multirangefilter.cpp+3−1 plugins/Unity/plugin.cpp+2 plugins/Unity/preview.cpp+22−3 plugins/Unity/preview.h+7 plugins/Unity/radiooptionfilter.cpp+3−1 plugins/Unity/ratingoptionsmodel.cpp+3−3 plugins/Unity/ratingoptionsmodel.h+1−1 plugins/Unity/ratingsfilter.cpp+2−1 plugins/Unity/result.cpp+82 plugins/Unity/result.h+69 plugins/Unity/scope.cpp+20−1 plugins/Unity/scope.h+3 plugins/Unity/showallfilteroption.cpp+60 plugins/Unity/showallfilteroption.h+51 plugins/Unity/socialpreview.cpp+5−1 plugins/Unity/unityoptionsmodel.cpp+5−4 plugins/Unity/unityoptionsmodel.h+2−1 plugins/Unity/variantutils.cpp+9 plugins/Unity/variantutils.h+1 plugins/Utils/qsortfilterproxymodelqml.cpp+32 plugins/Utils/qsortfilterproxymodelqml.h+4 po/ar.po+2−29 po/az.po+2−8 po/bg.po+2−11 po/ca.po+52−73 po/de.po+2−29 po/el.po+2−8 po/en_AU.po+27−53 po/en_GB.po+2−29 po/eo.po+2−2 po/es.po+26−51 po/fi.po+15−42 po/fo.po+2−8 po/fr.po+2−5 po/gd.po+266 po/gl.po+29−56 po/he.po+2−8 po/hr.po+2−8 po/hu.po+2−17 po/hy.po+2−29 po/id.po+2−2 po/is.po+256 po/it.po+55−54 po/ja.po+2−2 po/kn.po+2−8 po/ko.po+2−23 po/ky.po+2−8 po/lv.po+21−27 po/my.po+2−8 po/nb.po+2−17 po/nl.po+2−8 po/pl.po+2−29 po/pt_BR.po+49−53 po/ro.po+2−8 po/ru.po+32−53 po/si.po+2−2 po/sl.po+32−48 po/sr.po+2−8 po/sv.po+2−2 po/te.po+2−5 po/tr.po+2−29 po/ug.po+2−29 po/uk.po+26−48 po/xh.po+255 po/zh_CN.po+2−29 po/zh_TW.po+2−29 run_on_device+2−1 src/Panel/Indicators/CMakeLists.txt−1 src/Panel/Indicators/servicefiles/CMakeLists.txt−14 src/Panel/Indicators/servicefiles/com.canonical.indicator.messages−10 tests/autopilot/unity8/application_lifecycle/__init__.py+20 tests/autopilot/unity8/application_lifecycle/tests/__init__.py tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.py+136 tests/autopilot/unity8/shell/__init__.py+10 tests/autopilot/unity8/shell/tests/__init__.py+4−1 tests/autopilot/unity8/shell/tests/test_hud.py+7−2 tests/mocks/AccountsService/AccountsService.cpp+27−4 tests/mocks/AccountsService/AccountsService.h+27−3 tests/mocks/AccountsService/CMakeLists.txt+2 tests/mocks/LightDM/demo/GreeterPrivate.cpp+4−2 tests/mocks/Ubuntu/Application/CMakeLists.txt−29 tests/mocks/Ubuntu/Application/qmldir−3 tests/mocks/Ubuntu/CMakeLists.txt−1 tests/mocks/Ubuntu/DownloadDaemonListener/MockDownloadTracker.cpp+5 tests/mocks/Ubuntu/Application/ApplicationImage.cpp → tests/mocks/Unity/Application/ApplicationImage.cpp tests/mocks/Ubuntu/Application/ApplicationImage.h → tests/mocks/Unity/Application/ApplicationImage.h tests/mocks/Ubuntu/Application/ApplicationInfo.cpp → tests/mocks/Unity/Application/ApplicationInfo.cpp+15−2 tests/mocks/Ubuntu/Application/ApplicationInfo.h → tests/mocks/Unity/Application/ApplicationInfo.h+12−18 tests/mocks/Ubuntu/Application/ApplicationListModel.cpp → tests/mocks/Unity/Application/ApplicationListModel.cpp tests/mocks/Ubuntu/Application/ApplicationListModel.h → tests/mocks/Unity/Application/ApplicationListModel.h tests/mocks/Ubuntu/Application/ApplicationManager.cpp → tests/mocks/Unity/Application/ApplicationManager.cpp+185−153 tests/mocks/Ubuntu/Application/ApplicationManager.h → tests/mocks/Unity/Application/ApplicationManager.h+26−26 tests/mocks/Unity/Application/CMakeLists.txt+37 tests/mocks/Ubuntu/Application/InputFilterArea.qml → tests/mocks/Unity/Application/InputFilterArea.qml tests/mocks/Unity/Application/OSKController.qml+20 tests/mocks/Ubuntu/Application/plugin.cpp → tests/mocks/Unity/Application/plugin.cpp+6−5 tests/mocks/Ubuntu/Application/plugin.h → tests/mocks/Unity/Application/plugin.h+1−1 tests/mocks/Unity/Application/qmldir+4 tests/mocks/Unity/CMakeLists.txt+4 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/mocks/Unity/Launcher/CMakeLists.txt+3−1 tests/mocks/Unity/Launcher/MockLauncherItem.cpp+17−1 tests/mocks/Unity/Launcher/MockLauncherItem.h+4 tests/mocks/Unity/Launcher/MockLauncherModel.cpp+14−2 tests/mocks/Unity/Launcher/MockLauncherModel.h+3 tests/mocks/Unity/fake_applications_scope.cpp+68 tests/mocks/Unity/fake_applications_scope.h+33 tests/mocks/Unity/fake_categories.cpp+84−12 tests/mocks/Unity/fake_categories.h+7−3 tests/mocks/Unity/fake_preview.cpp+68 tests/mocks/Unity/fake_preview.h+62 tests/mocks/Unity/fake_scope.cpp+33−9 tests/mocks/Unity/fake_scope.h+17−1 tests/mocks/Unity/fake_scopes.cpp+4−1 tests/plugins/AccountsService/CMakeLists.txt+1 tests/plugins/AccountsService/client.cpp+19−7 tests/plugins/ListViewWithPageHeader/CMakeLists.txt+6 tests/plugins/ListViewWithPageHeader/listviewwithpageheadertest.cpp+161 tests/plugins/ListViewWithPageHeader/listviewwithpageheadertestsectionexternalmodel.cpp+251 tests/plugins/ListViewWithPageHeader/test_sectionexternalmodel.qml+74 tests/plugins/Unity/CMakeLists.txt+5 tests/plugins/Unity/Launcher/CMakeLists.txt+71 tests/plugins/Unity/Launcher/abs-icon.desktop+3 tests/plugins/Unity/Launcher/click-icon.desktop+4 tests/plugins/Unity/Launcher/click-icon.svg tests/plugins/Unity/Launcher/launcherbackendtest.cpp+93 tests/plugins/Unity/Launcher/launchermodeltest.cpp+275 tests/plugins/Unity/Launcher/no-icon.desktop+2 tests/plugins/Unity/Launcher/no-name.desktop+2 tests/plugins/Unity/Launcher/rel-icon.desktop+3 tests/plugins/Unity/Launcher/rel-icon.svg tests/plugins/Unity/filtersbindingstest.cpp+61−30 tests/plugins/Unity/filtersbindingstest.h+1−1 tests/plugins/Unity/previewbindingstest.cpp+27 tests/plugins/Unity/resultstest.cpp+105 tests/plugins/Unity/resultstest.h+35 tests/qmltests/CMakeLists.txt+2−2 tests/qmltests/Components/tst_CrossFadeImage.qml−125 tests/qmltests/Components/tst_LazyImage.qml+156 tests/qmltests/Components/tst_LazyImage/ImageControls.qml+67 tests/qmltests/Components/tst_LazyImage/portrait.png tests/qmltests/Components/tst_LazyImage/square.png tests/qmltests/Components/tst_LazyImage/wide.png tests/qmltests/Components/tst_Stage.qml+1−1 tests/qmltests/Dash/Apps/tst_AppPreview.qml+75−2 tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml+55−37 tests/qmltests/Dash/tst_DashContent.qml+1−1 tests/qmltests/Dash/tst_GenericScopeView.qml+17 tests/qmltests/Greeter/tst_Phone.qml+19−1 tests/qmltests/Launcher/tst_Launcher.qml+10−2 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 tests/qmltests/tst_Shell.qml+33−9 tests/uqmlscene/main.cpp−2
Applications/Application.qml+1−1
@@ -16,7 +16,7 @@
1616
1717import QtQuick 2.0
1818import "applications.js" as ApplicationsModel
19−import Ubuntu.Application 0.1
19+import Unity.Application 0.1
2020
2121/* This class is temporary. It is meant to be API compatible with qthybris' Application
2222 class.
Bottombar/Bottombar.qml+5−3
@@ -18,7 +18,7 @@ import QtQuick 2.0
1818import "../Components"
1919import "../Components/Math.js" as MathLocal
2020import Unity 0.1
21−import Ubuntu.Application 0.1
21+import Unity.Application 0.1
2222import Ubuntu.Gestures 0.1
2323
2424Item {
@@ -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) {
@@ -142,7 +144,7 @@ Item {
142144
143145 InputFilterArea {
144146 anchors.fill: parent
145− blockInput: hudButton.visible
147+ blockInput: (hudButton.opacity == 1)
146148 }
147149
148150 states: [
CMakeLists.txt+4
@@ -62,10 +62,13 @@ set(SHELL_PRIVATE_LIBDIR ${CMAKE_INSTALL_LIBDIR}/unity8)
6262
6363configure_file(paths.h.in ${CMAKE_CURRENT_BINARY_DIR}/paths.h @ONLY)
6464
65+pkg_check_modules(UNITY-MIR REQUIRED unity-mir)
66+
6567include_directories(
6668 ${CMAKE_CURRENT_BINARY_DIR}
6769 ${CMAKE_CURRENT_SOURCE_DIR}
6870 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
71+ ${UNITY-MIR_INCLUDE_DIRS}
6972 )
7073
7174set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
@@ -118,6 +121,7 @@ target_link_libraries(${SHELL_APP}
118121 ${Qt5Qml_LIBRARIES}
119122 ${Qt5Quick_LIBRARIES}
120123 ${XCB_LDFLAGS}
124+ ${CMAKE_DL_LIBS}
121125 )
122126
123127# install binaries
Components/ApplicationManagerWrapper.qml+89−42
@@ -15,15 +15,15 @@
1515 */
1616
1717import QtQuick 2.0
18−import Ubuntu.Application 0.1
18+import Unity.Application 0.1
1919
2020Item {
2121 id: applicationManager
2222
23− property var mainStageApplications: ApplicationManager.mainStageApplications
24− property var sideStageApplications: ApplicationManager.sideStageApplications
25− property var mainStageFocusedApplication: ApplicationManager.mainStageFocusedApplication
26− property var sideStageFocusedApplication: ApplicationManager.sideStageFocusedApplication
23+ property alias mainStageApplications: mainStageModel
24+ property alias sideStageApplications: sideStageModel
25+ property variant mainStageFocusedApplication: null
26+ property variant sideStageFocusedApplication: null
2727 property bool sideStageEnabled: true
2828 signal focusRequested(string desktopFile)
2929 property bool keyboardVisible: ApplicationManager.keyboardVisible
@@ -31,32 +31,76 @@ Item {
3131
3232 property bool fake: ApplicationManager.fake ? ApplicationManager.fake : false
3333
34− Component.onCompleted: {
35− // Start the watcher so that the ApplicationManager applications model can be populated.
36− ApplicationManager.startWatcher();
34+ ApplicationsModelStageFiltered {
35+ id: mainStageModel
36+ stage: ApplicationInfo.MainStage
37+ }
38+
39+ ApplicationsModelStageFiltered {
40+ id: sideStageModel
41+ stage: ApplicationInfo.SideStage
42+ }
43+
44+ Connections {
45+ target: ApplicationManager
46+ onFocusedApplicationIdChanged: {
47+ var app = ApplicationManager.findApplication(ApplicationManager.focusedApplicationId)
48+ if (!app) { //nothing at all focused, so clear all
49+ mainStageFocusedApplication = null;
50+ sideStageFocusedApplication = null;
51+ } else {
52+ if (app.stage == ApplicationInfo.MainStage) {
53+ mainStageFocusedApplication = app;
54+ // possible the side stage app being unfocused fired this signal, so check for it
55+ if (sideStageFocusedApplication && !sideStageFocusedApplication.focused)
56+ sideStageFocusedApplication = null;
57+ } else {
58+ sideStageFocusedApplication = app;
59+ // possible the main stage app being unfocused fired this signal, so check for it
60+ if (mainStageFocusedApplication && !mainStageFocusedApplication.focused)
61+ mainStageFocusedApplication = null;
62+ }
63+ }
64+ }
3765 }
3866
3967 function activateApplication(desktopFile, argument) {
40− var application;
41− application = getApplicationFromDesktopFile(desktopFile, ApplicationInfo.MainStage);
42− if (application == null) {
43− application = getApplicationFromDesktopFile(desktopFile, ApplicationInfo.SideStage);
68+ var appId;
69+
70+ // HACK: Applications identified sometimes with with appId, but mostly with desktopFile.
71+ // TODO: convert entire shell to use appId only.
72+ if (desktopFile.indexOf(".desktop") >= 0) {
73+ appId = desktopFileToAppId(desktopFile);
74+ } else {
75+ appId = desktopFile;
4476 }
45− if (application != null) {
77+
78+ var application = ApplicationManager.findApplication(appId);
79+ if (application !== null) {
4680 return application;
4781 }
4882
4983 var execFlags = sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
5084
5185 if (argument) {
52− return ApplicationManager.startProcess(desktopFile, execFlags, [argument]);
86+ return ApplicationManager.startApplication(appId, execFlags, [argument]);
5387 } else {
54− return ApplicationManager.startProcess(desktopFile, execFlags);
88+ return ApplicationManager.startApplication(appId, execFlags);
5589 }
5690 }
5791
58− function stopProcess(application) {
59− ApplicationManager.stopProcess(application)
92+ function stopApplication(application) {
93+ var appId;
94+
95+ // HACK: Applications identified sometimes with with appId, but mostly with desktopFile.
96+ // TODO: convert entire shell to use appId only.
97+ if (typeof application == "string") {
98+ appId = application;
99+ } else {
100+ appId = desktopFileToAppId(application.desktopFile);
101+ }
102+
103+ ApplicationManager.stopApplication(appId);
60104 }
61105
62106 function focusApplication(application) {
@@ -64,51 +108,54 @@ Item {
64108 return;
65109 }
66110
67− ApplicationManager.focusApplication(application.handle);
111+ ApplicationManager.focusApplication(application.appId);
68112 }
69113
70114 function unfocusCurrentApplication() {
71− ApplicationManager.unfocusCurrentApplication(ApplicationInfo.MainStage);
115+ ApplicationManager.unfocusCurrentApplication();
72116 }
73117
74118 function moveRunningApplicationStackPosition(from, to, stage) {
75− var applications;
119+ if (from == to || from < 0 || to < 0) return;
120+
76121 if (stage == ApplicationInfo.SideStage) {
77− applications = ApplicationManager.sideStageApplications;
122+ sideStageModel.move(from, to);
78123 } else {
79− applications = ApplicationManager.mainStageApplications;
124+ mainStageModel.move(from, to);
80125 }
81− // FIXME: applications.move(0, 0) crashes
82− if (from !== to && from >= 0 && to >= 0) applications.move(from, to);
83126 }
84127
85128 function getApplicationFromDesktopFile(desktopFile, stage) {
86− var foundSideStageApp, foundMainStageApp;
129+ var appId;
87130
88− foundMainStageApp = __find(desktopFile, ApplicationManager.mainStageApplications)
89− if (stage == ApplicationInfo.MainStage) {
90− return foundMainStageApp;
91− }
92− foundSideStageApp = __find(desktopFile, ApplicationManager.sideStageApplications)
93− if (stage == ApplicationInfo.SideStage) {
94− return foundSideStageApp;
131+ // HACK: Applications identified sometimes with with appId, but mostly with desktopFile.
132+ // TODO: convert entire shell to use appId only.
133+ if (desktopFile.indexOf(".desktop") >= 0) {
134+ appId = desktopFileToAppId(desktopFile);
135+ } else {
136+ appId = desktopFile;
95137 }
96138
97− // if stage not specified, return whichever app running on either stage
98− return (foundMainStageApp) ? foundMainStageApp : foundSideStageApp;
99−
139+ for (var i = 0, len = ApplicationManager.count; i < len; i++ ) {
140+ var app = ApplicationManager.get(i);
100141
101− function __find(desktopFile, applications) {
102− for (var i = 0; i < applications.count; i++ ) {
103− var application = applications.get(i);
104− if (application.desktopFile == desktopFile) {
105− return application;
106− }
142+ // if stage not specified, return whichever app running on either stage
143+ if (app.appId == appId && (stage == undefined || app.stage == stage)) {
144+ return app;
107145 }
108− return null;
109146 }
110147 }
111148
149+ function desktopFileToAppId(desktopFile) {
150+ var right = desktopFile.lastIndexOf(".desktop");
151+ var left = desktopFile.lastIndexOf("/");
152+ if (left == -1 || right == -1 || left == right) {
153+ console.log("ApplicationManagerWrapper: unable to extract appId from '" + desktopFile + "'");
154+ return "";
155+ }
156+ return desktopFile.substring(left+1, right);
157+ }
158+
112159 Connections {
113160 target: ApplicationManager
114161 onFocusRequested: {
Components/ApplicationScreenshot.qml+2−2
@@ -16,7 +16,7 @@
1616
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
19−import Ubuntu.Application 0.1
19+import Unity.Application 0.1
2020
2121Item {
2222 id: applicationScreenshot
@@ -56,6 +56,6 @@ Item {
5656 width: applicationScreenshot.application ? parent.width : 0
5757 height: applicationScreenshot.application ? parent.height : 0
5858 visible: applicationScreenshot.application != null && ready
59− source: applicationScreenshot.application
59+ source: ApplicationManager.findApplication((application) ? application.appId : "")
6060 }
6161}
Components/ApplicationsModelStageFiltered.qmlnew file+49
@@ -0,0 +1,49 @@
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 Utils 0.1
19+import Unity.Application 0.1
20+
21+SortFilterProxyModel {
22+ id: root
23+ property int stage
24+
25+ function get(index) {
26+ return model.get(mapRowToSource(index));
27+ }
28+
29+ function move(from, to) {
30+ var realFrom = mapRowToSource(from);
31+ if (realFrom == -1) {
32+ console.log("ERROR; invalid from=" + from + " index in move operation");
33+ return;
34+ }
35+ var realTo = mapRowToSource(to);
36+ if (realTo == -1) {
37+ // assuming wanting to move to end of list
38+ realTo = model.count - 1;
39+ }
40+
41+ if (realFrom == realTo) return;
42+ model.move(realFrom, realTo);
43+ }
44+
45+ model: ApplicationManager
46+ dynamicSortFilter: true
47+ filterRole: ApplicationManager.RoleStage
48+ filterRegExp: RegExp(stage)
49+}
Components/CrossFadeImage.qmldeleted−151
@@ -1,151 +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−import QtQuick 2.0
18−
19−Item {
20− property url source
21−
22− /*
23− * true: fade out old image in parallel with fading in the new one.
24− * false: fade in new image above old one.
25− *
26− * The reason why this is required is that crossfading has the isse that in
27− * the middle of the animation, both images are only 50% opaque which make
28− * any background shine through. Not wanted for background images etc, but
29− * wanted for overlays.
30− */
31− property bool crossFade: true
32−
33− /*
34− * true: the very first source url should be faded in already.
35− * false: the very first source url should just be shown without animation.
36− */
37− property bool fadeInFirst: true
38−
39− readonly property size sourceSize: __currentImage.sourceSize
40− readonly property var status: __currentImage ? __currentImage.status : Image.Null
41− readonly property bool running: crossFadeImages.running || nextImageFadeIn.running
42−
43− property Image __currentImage: image1
44− property Image __nextImage: image2
45−
46− function swapImages() {
47− __currentImage.z = 0
48− __nextImage.z = 1
49− if (crossFade) {
50− crossFadeImages.start();
51− } else {
52− nextImageFadeIn.start();
53− }
54−
55− var tmpImage = __currentImage
56− __currentImage = __nextImage
57− __nextImage = tmpImage
58− }
59−
60− onSourceChanged: {
61− // On creation, the souce handler is called before image pointers are set.
62− if (__currentImage === null) {
63− __currentImage = image1;
64− __nextImage = image2;
65− }
66−
67− crossFadeImages.stop();
68− nextImageFadeIn.stop();
69−
70− // Don't fade in initial picture, only fade changes
71− if (__currentImage.source == "" && !fadeInFirst) {
72− __currentImage.source = source;
73− } else {
74− nextImageFadeIn.stop();
75− __nextImage.opacity = 0.0;
76− __nextImage.source = source;
77−
78− // If case the image is still in QML's cache, status will be "Ready" immediately
79− if (__nextImage.status == Image.Ready || __nextImage.source == "") {
80− swapImages();
81− }
82− }
83− }
84−
85− Connections {
86− target: __nextImage
87− onStatusChanged: {
88− if (__nextImage.status == Image.Ready || __nextImage.status == Image.Error) {
89− swapImages();
90− }
91− }
92− }
93−
94− Image {
95− id: image1
96− anchors.fill: parent
97− cache: false
98− asynchronous: true
99− fillMode: Image.PreserveAspectCrop
100− z: 1
101− }
102−
103− Image {
104− id: image2
105− anchors.fill: parent
106− cache: false
107− asynchronous: true
108− fillMode: Image.PreserveAspectCrop
109− z: 0
110− }
111−
112− NumberAnimation {
113− id: nextImageFadeIn
114− target: __nextImage
115− property: "opacity"
116− duration: 400
117− to: 1.0
118− easing.type: Easing.InOutQuad
119−
120− onRunningChanged: {
121− if (!running) {
122− __nextImage.source = "";
123− }
124− }
125− }
126−
127− ParallelAnimation {
128− id: crossFadeImages
129− NumberAnimation {
130− target: __nextImage
131− property: "opacity"
132− duration: 400
133− to: 1.0
134− easing.type: Easing.InOutQuad
135− }
136−
137− NumberAnimation {
138− target: __currentImage
139− property: "opacity"
140− duration: 400
141− to: 0
142− easing.type: Easing.InOutQuad
143− }
144−
145− onRunningChanged: {
146− if (!running) {
147− __nextImage.source = "";
148− }
149− }
150− }
151−}
Components/EdgeDemo.qml+29−22
@@ -43,15 +43,12 @@ Item {
4343 }
4444
4545 function hideEdgeDemoInShell() {
46− var user = LightDM.Users.data(greeter.currentIndex, LightDM.UserRoles.NameRole);
47− AccountsService.setUserProperty(user, "demo-edges", false);
48− d.showEdgeDemo = false;
46+ AccountsService.demoEdges = false;
4947 stopDemo();
5048 }
5149
5250 function hideEdgeDemoInGreeter() {
53− // TODO: AccountsService.setUserProperty("lightdm", "demo-edges", false);
54− d.showEdgeDemoInGreeter = false;
51+ // TODO: AccountsService.demoEdges = false as lightdm user
5552 }
5653
5754 function hideEdgeDemos() {
@@ -71,6 +68,24 @@ Item {
7168 if (d.finalEdgeDemo) d.finalEdgeDemo.destroy()
7269 }
7370
71+ function startDemo() {
72+ if (!d.overlay) {
73+ d.overlay = Qt.createComponent("EdgeDemoOverlay.qml")
74+ }
75+
76+ launcherEnabled = false;
77+ dashEnabled = false;
78+ panelEnabled = false;
79+ panelContentEnabled = false;
80+
81+ // Begin with either greeter or dash, depending on which is visible
82+ if (greeter && greeter.shown) {
83+ startRightEdgeDemo()
84+ } else {
85+ startTopEdgeDemo()
86+ }
87+ }
88+
7489 QtObject {
7590 id: d
7691 property Component overlay
@@ -79,22 +94,18 @@ Item {
7994 property QtObject bottomEdgeDemo
8095 property QtObject leftEdgeDemo
8196 property QtObject finalEdgeDemo
82− property bool showEdgeDemo: false
83− property bool showEdgeDemoInGreeter: d.showEdgeDemo // TODO: AccountsService.getUserProperty("lightdm", "demo-edges")
97+ property bool showEdgeDemo: AccountsService.demoEdges
98+ property bool showEdgeDemoInGreeter: AccountsService.demoEdges // TODO: AccountsService.demoEdges as lightdm user
8499
85− onShowEdgeDemoInGreeterChanged: {
86− if (!d.overlay && d.showEdgeDemoInGreeter) {
87− d.overlay = Qt.createComponent("EdgeDemoOverlay.qml")
88− startRightEdgeDemo()
100+ onShowEdgeDemoChanged: {
101+ stopDemo()
102+ if (d.showEdgeDemo) {
103+ startDemo()
89104 }
90105 }
91106 }
92107
93108 function startRightEdgeDemo() {
94− launcherEnabled = false;
95− demo.dashEnabled = false;
96− demo.panelEnabled = false;
97− demo.panelContentEnabled = false;
98109 if (demo.greeter) {
99110 d.rightEdgeDemo = d.overlay.createObject(demo.greeter, {
100111 "edge": "right",
@@ -123,11 +134,6 @@ Item {
123134
124135 onUnlocked: hide()
125136 onShownChanged: if (!greeter.shown) hide()
126−
127− onSelected: {
128− var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole)
129− d.showEdgeDemo = AccountsService.getUserProperty(user, "demo-edges")
130− }
131137 }
132138
133139 function startTopEdgeDemo() {
@@ -163,7 +169,7 @@ Item {
163169 "edge": "bottom",
164170 "title": i18n.tr("Close"),
165171 "text": i18n.tr("Swipe up again to close the settings screen"),
166− "anchors.fill": demo.indicators,
172+ "anchors.fill": demo.indicators.content,
167173 });
168174 }
169175 if (d.bottomEdgeDemo) {
@@ -218,8 +224,9 @@ Item {
218224 d.finalEdgeDemo = d.overlay.createObject(demo.underlay, {
219225 "edge": "none",
220226 "title": i18n.tr("Well done"),
221− "text": i18n.tr("You have now mastered the edge gestures and can start using the phone"),
227+ "text": i18n.tr("You have now mastered the edge gestures and can start using the phone<br><br>Tap anywhere to start"),
222228 "anchors.fill": demo.dash,
229+ "showSkip": false,
223230 });
224231 }
225232 if (d.finalEdgeDemo) {
Components/EdgeDemoOverlay.qml+9−1
@@ -17,7 +17,7 @@
1717import Powerd 0.1
1818import QtQuick 2.0
1919import QtGraphicalEffects 1.0
20−import Ubuntu.Application 0.1
20+import Unity.Application 0.1
2121import Ubuntu.Components 0.1
2222
2323Showable {
@@ -43,6 +43,11 @@ Showable {
4343 */
4444 property alias skipText: skipLabel.text
4545
46+ /*
47+ * This is the visible status of the skip button.
48+ */
49+ property alias showSkip: skipLabel.visible
50+
4651 /*
4752 * Whether this demo is running currently.
4853 */
@@ -148,7 +153,10 @@ Showable {
148153 font.underline: true
149154
150155 MouseArea {
156+ // Make clickable area bigger than just the link because
157+ // otherwise, the edge demo will feel hard to dismiss.
151158 anchors.fill: parent
159+ anchors.margins: -units.gu(5)
152160 onClicked: overlay.doSkip()
153161 }
154162 }
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−}
Components/LazyImage.qmlnew file+172
@@ -0,0 +1,172 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Michał Sawicz <michal.sawicz@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+import QtQuick 2.0
21+import Ubuntu.Components 0.1
22+
23+Item {
24+ id: root
25+
26+ property url source
27+ // TODO convert into enums when available in QML
28+ property string scaleTo
29+
30+ property real initialWidth: units.gu(10)
31+ property real initialHeight: units.gu(10)
32+
33+ property alias sourceSize: image.sourceSize
34+ property alias fillMode: image.fillMode
35+ property alias asynchronous: image.asynchronous
36+ property alias cache: image.cache
37+ property alias horizontalAlignment: image.horizontalAlignment
38+ property alias verticalAlignment: image.verticalAlignment
39+
40+ state: "default"
41+
42+ onSourceChanged: {
43+ if (state === "ready") {
44+ state = "default";
45+ image.nextSource = source;
46+ } else {
47+ image.source = source;
48+ }
49+ }
50+
51+ UbuntuShape {
52+ id: placeholder
53+ objectName: "placeholder"
54+ color: "#22FFFFFF"
55+ anchors.fill: parent
56+ visible: opacity != 0
57+
58+ ActivityIndicator {
59+ id: activity
60+ anchors.centerIn: parent
61+ opacity: 0
62+ visible: opacity != 0
63+
64+ running: visible
65+ }
66+
67+ Image {
68+ id: errorImage
69+ objectName: "errorImage"
70+ anchors.centerIn: parent
71+ opacity: 0
72+ visible: opacity != 0
73+
74+ source: "graphics/close.png"
75+ sourceSize { width: units.gu(3); height: units.gu(3) }
76+ }
77+ }
78+
79+ UbuntuShape {
80+ id: shape
81+ objectName: "shape"
82+ anchors.fill: parent
83+ opacity: 0
84+ visible: opacity != 0
85+
86+ image: Image {
87+ id: image
88+ objectName: "image"
89+
90+ property url nextSource
91+
92+ width: root.scaleTo == "height" ? implicitWidth * root.height / implicitHeight : implicitWidth
93+ height: root.scaleTo == "width" ? implicitHeight * root.width / implicitWidth : implicitHeight
94+ fillMode: Image.PreserveAspectCrop
95+ asynchronous: true
96+ cache: false
97+ horizontalAlignment: Image.AlignHCenter
98+ verticalAlignment: Image.AlignVCenter
99+ sourceSize.width: root.scaleTo == "width" ? root.width : 0
100+ sourceSize.height: root.scaleTo == "height" ? root.height : 0
101+ }
102+ }
103+
104+ states: [
105+ State {
106+ name: "default"
107+ when: image.source == ""
108+ PropertyChanges { target: root; implicitWidth: root.initialWidth; implicitHeight: root.initialHeight }
109+ PropertyChanges { target: errorImage; opacity: 0 }
110+ },
111+ State {
112+ name: "loading"
113+ extend: "default"
114+ when: image.status === Image.Loading
115+ PropertyChanges { target: activity; opacity: 1 }
116+ },
117+ State {
118+ name: "ready"
119+ when: image.status === Image.Ready && image.source != ""
120+ PropertyChanges { target: root; implicitWidth: image.width; implicitHeight: image.height }
121+ PropertyChanges { target: shape; opacity: 1 }
122+ PropertyChanges { target: placeholder; opacity: 0 }
123+ },
124+ State {
125+ name: "error"
126+ extend: "default"
127+ when: image.status === Image.Error
128+ PropertyChanges { target: errorImage; opacity: 1.0 }
129+ }
130+ ]
131+
132+ transitions: [
133+ Transition {
134+ to: "ready"
135+ objectName: "readyTransition"
136+ SequentialAnimation {
137+ PropertyAction { target: shape; property: "visible" }
138+ ParallelAnimation {
139+ NumberAnimation { target: shape; property: "opacity"; easing.type: Easing.Linear }
140+ UbuntuNumberAnimation { target: root; properties: "implicitWidth,implicitHeight" }
141+ NumberAnimation {
142+ targets: [placeholder, activity, errorImage]; property: "opacity";
143+ easing.type: Easing.Linear; duration: UbuntuAnimation.SnapDuration
144+ }
145+ }
146+ }
147+ },
148+
149+ Transition {
150+ to: "*"
151+ objectName: "genericTransition"
152+ SequentialAnimation {
153+ ParallelAnimation {
154+ NumberAnimation { target: shape; property: "opacity"; easing.type: Easing.Linear }
155+ NumberAnimation {
156+ targets: [placeholder, activity, errorImage]; property: "opacity";
157+ easing.type: Easing.Linear; duration: UbuntuAnimation.SnapDuration
158+ }
159+ UbuntuNumberAnimation { target: root; properties: "implicitWidth,implicitHeight" }
160+ }
161+ PropertyAction { target: shape; property: "visible" }
162+ }
163+
164+ onRunningChanged: {
165+ if (!running && state === "default" && image.nextSource !== "") {
166+ image.source = image.nextSource;
167+ image.nextSource = "";
168+ }
169+ }
170+ }
171+ ]
172+}
Components/ResponsiveGridView.qml+1−1
@@ -67,7 +67,7 @@ Item {
6767
6868 function columnsForSpacing(spacing) {
6969 // minimum margin is half of the spacing
70− return Math.floor((parent.width - spacing/2) / (delegateWidth + spacing));
70+ return Math.max(1, Math.floor((parent.width - spacing/2) / (delegateWidth + spacing)));
7171 }
7272
7373 property real allocatableHorizontalSpace: parent.width - columns * delegateWidth
Components/Stage.qml+1−1
@@ -15,7 +15,7 @@
1515 */
1616
1717import QtQuick 2.0
18−import Ubuntu.Application 0.1
18+import Unity.Application 0.1
1919import Ubuntu.Components 0.1
2020import Ubuntu.Gestures 0.1
2121
Components/VolumeControl.qml+5−20
@@ -21,37 +21,22 @@ Item {
2121 id: root
2222 objectName: "volumeControl"
2323 visible: false
24− property int volume
2524
2625 QDBusActionGroup {
2726 id: actionGroup
2827 busType: 1
29− busName: "com.canonical.settings.sound"
30− objectPath: "/com/canonical/settings/sound"
28+ busName: "com.canonical.indicator.sound"
29+ objectPath: "/com/canonical/indicator/sound"
3130
32− property variant actionObject: action("volume")
33− property variant serverVolume: actionObject.valid ? actionObject.state: 0
34− }
35−
36− Binding {
37− target: root
38− property: "volume"
39− value: actionGroup.serverVolume * 100
40− }
41−
42− onVolumeChanged: {
43− if (actionGroup.serverVolume != volume) {
44− var targetVolume = Math.min(1, Math.max(0, volume / 100));
45− actionGroup.actionObject.updateState(targetVolume);
46− }
31+ property variant actionObject: action("scroll")
4732 }
4833
4934 function volumeUp() {
50− actionGroup.actionObject.updateState(Math.min(1, volume/100 + 0.10));
35+ actionGroup.actionObject.activate(1);
5136 }
5237
5338 function volumeDown() {
54− actionGroup.actionObject.updateState(Math.max(0, volume/100 - 0.10));
39+ actionGroup.actionObject.activate(-1);
5540 }
5641
5742 Component.onCompleted: actionGroup.start()
Components/graphics/close@20.pngnew file

Binary file not shown.

Dash/Apps/AppPreview.qml+12−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
@@ -111,6 +110,10 @@ DashPreview {
111110 onFinished: {
112111 root.previewData.execute(progressBar.model[0].id, { })
113112 }
113+
114+ onError: {
115+ root.previewData.execute(progressBar.model[1].id, { "error": error });
116+ }
114117 }
115118
116119 }
@@ -137,7 +140,7 @@ DashPreview {
137140 anchors { left: parent.left; right: parent.right }
138141
139142 appName: root.previewData.title
140− icon: IconUtil.from_gicon(root.previewData.appIcon)
143+ icon: root.previewData.appIcon
141144 rating: Math.round(root.previewData.rating * 10)
142145 reviews: root.previewData.numRatings
143146 rated: root.previewData.infoMap["rated"] ? root.previewData.infoMap["rated"].value : 0
@@ -188,12 +191,19 @@ DashPreview {
188191 ListItem.ThinDivider { }
189192
190193 AppReviews {
194+ id: appReviews
191195 objectName: "appReviews"
196+ // TODO: This should make this visible when the feature for reviews/comments is complete.
197+ visible: false
192198 anchors { left: parent.left; right: parent.right }
193199
194200 model: root.previewData.infoMap["comments"] ? root.previewData.infoMap["comments"].value : undefined
195201
196202 onSendReview: root.sendUserReview(review);
203+
204+ onEditing: {
205+ root.ensureVisible(appReviews.textArea);
206+ }
197207 }
198208 }
199209 }
Dash/Apps/AppReviews.qml+3
@@ -23,8 +23,10 @@ Column {
2323 id: root
2424
2525 property var model
26+ property alias textArea: reviewField
2627
2728 signal sendReview(string review)
29+ signal editing
2830
2931 spacing: units.gu(2)
3032 state: ""
@@ -93,6 +95,7 @@ Column {
9395 if(reviewField.focus){
9496 root.state = "editing";
9597 reviewField.selectAll();
98+ root.editing();
9699 }
97100 }
98101
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/Apps/RunningApplicationTile.qml+2−3
@@ -16,7 +16,7 @@
1616
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
19−import Ubuntu.Application 0.1
19+import Unity.Application 0.1
2020import "../../Components/"
2121import "../../Components/ListItems"
2222
@@ -76,10 +76,9 @@ AbstractButton {
7676
7777 ApplicationImage {
7878 id: applicationImage
79− source: application
79+ source: ApplicationManager.findApplication((application) ? application.appId : "")
8080 width: shapedApplicationImage.width
8181 height: shapedApplicationImage.height
82− fillMode: ApplicationImage.PreserveAspectCrop
8382 }
8483
8584 UbuntuShape {
Dash/Apps/RunningApplicationsGrid.qml+4−4
@@ -52,22 +52,22 @@ ResponsiveFlowView {
5252
5353 RunningApplicationTile {
5454 id: runningAppTile
55− objectName: "runningAppTile " + model.application.name
55+ objectName: "runningAppTile " + model.name
5656 anchors {
5757 top: parent.top
5858 horizontalCenter: parent.horizontalCenter
5959 }
60− application: model.application
60+ application: model
6161 onRequestedActivationMode: { root.terminationModeEnabled = false }
6262 onRequestedTerminationMode: {
6363 if (canEnableTerminationMode)
6464 root.terminationModeEnabled = true
6565 }
6666 onRequestedApplicationTermination: {
67− shell.applicationManager.stopProcess(application)
67+ shell.applicationManager.stopApplication(model.appId)
6868 }
6969 onRequestedApplicationActivation: {
70− shell.activateApplication(application.desktopFile)
70+ shell.activateApplication(model.appId)
7171 }
7272
7373 terminationModeEnabled: root.terminationModeEnabled
Dash/DashBar.qml+2−3
@@ -83,9 +83,8 @@ Item {
8383 }
8484
8585 delegate:
86− Item {
87− signal clicked()
88−
86+ // FIXME: Use Panel's integrated trigger() once that works again.
87+ MouseArea {
8988 width: itemSize
9089 height: dashBar.height
9190 anchors.top: parent.top
Dash/DashPreview.qml+13
@@ -20,6 +20,7 @@ import Ubuntu.Components 0.1
2020Rectangle {
2121 id: root
2222
23+ property int keyboardSize: Qt.inputMethod.visible ? Qt.inputMethod.keyboardRectangle.height : 0
2324 property var previewData
2425
2526 property string title: ""
@@ -38,6 +39,14 @@ Rectangle {
3839 color: Qt.rgba(0, 0, 0, .3)
3940 clip: true
4041
42+ function ensureVisible(item) {
43+ var o = leftFlickable.mapFromItem(item, 0, 0, item.width, item.height);
44+ var keyboardY = shell.height - root.keyboardSize;
45+ if ((o.y + o.height) > keyboardY) {
46+ leftFlickable.contentY += o.y + o.height - keyboardY;
47+ }
48+ }
49+
4150 Connections {
4251 target: shell.applicationManager
4352 onMainStageFocusedApplicationChanged: {
@@ -128,12 +137,16 @@ Rectangle {
128137
129138 Flickable {
130139 id: leftFlickable
140+ objectName: "leftFlickable"
131141 anchors.top: parent.top
132142 anchors.bottom: parent.bottom
133143 width: root.narrowMode ? contentRow.width : contentRow.width * root.previewWidthRatio
134144 contentHeight: leftColumn.height
145+ anchors.bottomMargin: root.keyboardSize
135146 clip: true
136147
148+ Behavior on contentY { NumberAnimation { duration: 300 } }
149+
137150 Column {
138151 id: leftColumn
139152 objectName: "leftColumn"
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+28−13
@@ -18,14 +18,14 @@ 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
25− property alias previewShown: previewLoader.onScreen
24+ readonly property alias previewShown: previewLoader.onScreen
2625
2726 onIsCurrentChanged: {
2827 pageHeader.resetSearch();
28+ previewLoader.open = false;
2929 }
3030
3131 onMovementStarted: categoryView.showHeader()
@@ -36,6 +36,12 @@ ScopeView {
3636 value: pageHeader.searchQuery
3737 }
3838
39+ Binding {
40+ target: pageHeader
41+ property: "searchQuery"
42+ value: scopeView.scope.searchQuery
43+ }
44+
3945 Connections {
4046 target: panel
4147 onSearchClicked: if (isCurrent) {
@@ -44,6 +50,12 @@ ScopeView {
4450 }
4551 }
4652
53+ Connections {
54+ target: scopeView.scope
55+ onShowDash: previewLoader.open = false;
56+ onHideDash: previewLoader.open = false;
57+ }
58+
4759 ScopeListView {
4860 id: categoryView
4961 anchors.fill: parent
@@ -53,13 +65,14 @@ ScopeView {
5365 onAtYEndChanged: if (atYEnd) endReached()
5466 onMovingChanged: if (moving && atYEnd) endReached()
5567
56− property int expandedIndex: -1
68+ property string expandedCategoryId: ""
5769
5870 delegate: ListItems.Base {
5971 highlightWhenPressed: false
6072
6173 readonly property bool expandable: rendererLoader.item ? rendererLoader.item.expandable : false
6274 readonly property bool filtered: rendererLoader.item ? rendererLoader.item.filter : true
75+ readonly property string category: categoryId
6376
6477 Loader {
6578 id: rendererLoader
@@ -74,14 +87,14 @@ ScopeView {
7487 onLoaded: {
7588 if (source.toString().indexOf("Apps/RunningApplicationsGrid.qml") != -1) {
7689 // TODO: the running apps grid doesn't support standard scope results model yet
77− item.firstModel = results.firstModel
78− item.secondModel = results.secondModel
90+ item.firstModel = Qt.binding(function() { return results.firstModel })
91+ item.secondModel = Qt.binding(function() { return results.secondModel })
7992 } else {
80− item.model = results
93+ item.model = Qt.binding(function() { return results })
8194 }
82− item.objectName = categoryId
95+ item.objectName = Qt.binding(function() { return categoryId })
8396 if (item.expandable) {
84− var shouldFilter = index != categoryView.expandedIndex;
97+ var shouldFilter = categoryId != categoryView.expandedCategoryId;
8598 if (shouldFilter != item.filter) {
8699 item.filter = shouldFilter;
87100 }
@@ -117,10 +130,10 @@ ScopeView {
117130 }
118131 Connections {
119132 target: categoryView
120− onExpandedIndexChanged: {
133+ onExpandedCategoryIdChanged: {
121134 var item = rendererLoader.item;
122135 if (item.expandable) {
123− var shouldFilter = index != categoryView.expandedIndex;
136+ var shouldFilter = categoryId != categoryView.expandedCategoryId;
124137 if (shouldFilter != item.filter) {
125138 // If the filter animation will be seen start it, otherwise, just flip the switch
126139 var shrinkingVisible = shouldFilter && y + item.collapsedHeight < categoryView.height;
@@ -151,10 +164,10 @@ ScopeView {
151164 return "";
152165 }
153166 onClicked: {
154− if (categoryView.expandedIndex != delegateIndex)
155− categoryView.expandedIndex = delegateIndex;
167+ if (categoryView.expandedCategoryId != delegate.category)
168+ categoryView.expandedCategoryId = delegate.category;
156169 else
157− categoryView.expandedIndex = -1;
170+ categoryView.expandedCategoryId = "";
158171 }
159172 }
160173 pageHeader: PageHeader {
@@ -180,6 +193,7 @@ ScopeView {
180193 case "grid": {
181194 switch (contentType) {
182195 case "video": return "Generic/GenericFilterGridPotrait.qml";
196+ case "music": return "Music/MusicFilterGrid.qml";
183197 default: return "Generic/GenericFilterGrid.qml";
184198 }
185199 }
@@ -247,6 +261,7 @@ ScopeView {
247261 }
248262
249263 Loader {
264+ objectName: "previewLoader"
250265 id: previewLoader
251266 property var previewData
252267 height: effect.bottomGapPx - effect.topGapPx
Dash/Music/MusicFilterGrid.qml+12−2
@@ -29,19 +29,29 @@ FilterGrid {
2929 readonly property int iconWidth: (width / columns) * 0.8
3030 readonly property int iconHeight: iconWidth
3131
32− signal clicked(int index)
32+ signal clicked(int index, var delegateItem, real itemY)
33+ signal pressAndHold(int index, var delegateItem, real itemY)
3334
3435 delegate: AlbumTile {
36+ id: tile
3537 objectName: "delegate" + index
3638 width: filterGrid.cellWidth
3739 height: filterGrid.cellHeight
3840 iconWidth: filterGrid.iconWidth
3941 iconHeight: filterGrid.iconHeight
42+
4043 artist: model.title
4144 album: model.comment
4245 source: model.icon
46+
4347 onClicked: {
44− filterGrid.clicked(index);
48+ var data = { model: model }
49+ filterGrid.clicked(index, data, tile.y)
50+ }
51+
52+ onPressAndHold: {
53+ var data = { model: model }
54+ filterGrid.pressAndHold(index, data, tile.y)
4555 }
4656 }
4757}
Dash/graphics/phone/home.pngdeleted

Binary file not shown.

Dash/graphics/phone/music.pngdeleted

Binary file not shown.

Dash/graphics/phone/videos.pngdeleted

Binary file not shown.

Dash/graphics/tablet/apps.pngdeleted

Binary file not shown.

Dash/graphics/tablet/home.pngdeleted

Binary file not shown.

Dash/graphics/tablet/music.pngdeleted

Binary file not shown.

Dash/graphics/tablet/people.pngdeleted

Binary file not shown.

Dash/graphics/tablet/videos.pngdeleted

Binary file not shown.

Greeter/Greeter.qml+2
@@ -26,6 +26,8 @@ Showable {
2626 enabled: shown
2727 created: greeterContentLoader.status == Loader.Ready && greeterContentLoader.item.ready
2828
29+ property url defaultBackground
30+
2931 // 1 when fully shown and 0 when fully hidden
3032 property real showProgress: MathLocal.clamp((width + x) / width, 0, 1)
3133
Greeter/GreeterContent.qml+21−3
@@ -15,6 +15,7 @@
1515 */
1616
1717import QtQuick 2.0
18+import AccountsService 0.1
1819import Ubuntu.Components 0.1
1920import LightDM 0.1 as LightDM
2021import "../Components"
@@ -39,12 +40,29 @@ MouseArea {
3940 color: "black"
4041 }
4142
43+ property url backgroundValue: AccountsService.backgroundFile != undefined && AccountsService.backgroundFile.length > 0 ? AccountsService.backgroundFile : greeter.defaultBackground
44+ onBackgroundValueChanged: wallpaper.source = backgroundValue
45+
4246 CrossFadeImage {
4347 id: wallpaper
44−
45− source: shell.background
48+ objectName: "wallpaper"
4649 anchors.fill: parent
47− fadeInFirst: false
50+ fillMode: Image.PreserveAspectCrop
51+ }
52+
53+ // See Shell.qml's backgroundSettings treatment for why we need a separate
54+ // Image, but it boils down to avoiding binding loop detection.
55+ Image {
56+ source: wallpaper.source
57+ height: 0
58+ width: 0
59+ sourceSize.height: 0
60+ sourceSize.width: 0
61+ onStatusChanged: {
62+ if (status == Image.Error && source != greeter.defaultBackground) {
63+ wallpaper.source = greeter.defaultBackground
64+ }
65+ }
4866 }
4967
5068 Rectangle {
Greeter/Infographics.qml+1−2
@@ -286,9 +286,8 @@ Item {
286286 objectName: "backgroundCircle"
287287
288288 anchors.fill: parent
289− opacity: 0.9
290289
291− source: "graphics/infographic_circle.png"
290+ source: "graphics/infographic_circle_back.png"
292291 }
293292
294293 Timer {
Greeter/graphics/infographic_circle.pngdeleted

Binary file not shown.

Greeter/graphics/infographic_circle_back.pngnew file

Binary file not shown.

Launcher/Launcher.qml+4−4
@@ -35,7 +35,7 @@ Item {
3535 readonly property bool shown: panel.x > -panel.width
3636
3737 // emitted when an application is selected
38− signal launcherApplicationSelected(string desktopFile)
38+ signal launcherApplicationSelected(string appId)
3939
4040 // emitted when the apps dash should be shown because of a swipe gesture
4141 signal dash()
@@ -159,7 +159,7 @@ Item {
159159
160160 onApplicationSelected: {
161161 root.state = ""
162− launcherApplicationSelected(desktopFile)
162+ launcherApplicationSelected(appId)
163163 }
164164 onDashItemSelected: {
165165 root.state = ""
@@ -192,12 +192,12 @@ Item {
192192
193193 direction: Direction.Rightwards
194194
195− enabled: root.available && root.state !== "visible"
195+ enabled: root.available
196196 width: root.dragAreaWidth
197197 height: root.height
198198
199199 onTouchXChanged: {
200− if (status !== DirectionalDragArea.Recognized)
200+ if (status !== DirectionalDragArea.Recognized || launcher.state == "visible")
201201 return;
202202
203203 // When the gesture finally gets recognized, the finger will likely be
Launcher/LauncherDelegate.qml+21−10
@@ -24,6 +24,7 @@ Item {
2424 property int count: -1
2525 property int progress: -1
2626 property bool highlighted: false
27+ property bool itemFocused: false
2728 property real maxAngle: 0
2829 property bool inverted: false
2930
@@ -43,24 +44,25 @@ Item {
4344 onCountChanged: shaderEffectSource.scheduleUpdate();
4445 onProgressChanged: shaderEffectSource.scheduleUpdate();
4546 onHighlightedChanged: shaderEffectSource.scheduleUpdate();
47+ onItemFocusedChanged: shaderEffectSource.scheduleUpdate();
4648
4749 Item {
4850 id: iconItem
49− width: parent.itemWidth
50− height: parent.itemHeight
51+ width: parent.itemWidth + units.gu(1)
52+ height: parent.itemHeight + units.gu(1)
5153 anchors.centerIn: parent
5254
5355 UbuntuShape {
5456 id: iconShape
5557 anchors.fill: parent
56− anchors.margins: units.gu(0.5)
58+ anchors.margins: units.gu(1)
5759 radius: "medium"
5860
5961 image: Image {
6062 id: iconImage
6163 sourceSize.width: iconShape.width
6264 sourceSize.height: iconShape.height
63− source: "../graphics/applicationIcons/" + root.iconName + ".png"
65+ source: root.iconName
6466 }
6567 }
6668
@@ -78,7 +80,7 @@ Item {
7880 anchors {
7981 right: parent.right
8082 top: parent.top
81− margins: -units.dp(1)
83+ margins: units.dp(3)
8284 }
8385 width: Math.min(root.itemWidth, Math.max(units.gu(3), countLabel.implicitWidth + units.gu(2.5)))
8486 height: units.gu(3)
@@ -105,9 +107,9 @@ Item {
105107 left: iconItem.left
106108 right: iconItem.right
107109 bottom: iconItem.bottom
108− leftMargin: units.gu(0.5)
109− rightMargin: units.gu(0.5)
110− bottomMargin: units.gu(0.5)
110+ leftMargin: units.gu(1)
111+ rightMargin: units.gu(1)
112+ bottomMargin: units.gu(1)
111113 }
112114 height: units.gu(1.5)
113115 visible: root.progress > -1
@@ -136,14 +138,23 @@ Item {
136138 }
137139 }
138140 }
141+ Image {
142+ objectName: "focusedHighlight"
143+ anchors {
144+ right: parent.right
145+ verticalCenter: parent.verticalCenter
146+ }
147+ visible: root.itemFocused
148+ source: "graphics/focused_app_arrow.png"
149+ }
139150 }
140151
141152 ShaderEffect {
142153 id: transformEffect
143154 anchors.centerIn: parent
144155 anchors.verticalCenterOffset: root.offset
145− width: parent.itemWidth
146− height: parent.itemHeight
156+ width: iconItem.width
157+ height: iconItem.height
147158 property real itemOpacity: root.itemOpacity
148159 property real brightness: Math.max(-1, root.brightness)
149160 property real angle: root.angle
Launcher/LauncherPanel.qml+12−5
@@ -34,7 +34,7 @@ Item {
3434 property bool preventHiding: moving || dndArea.draggedIndex >= 0 || dndArea.quickListPopover !== null || dndArea.pressed
3535 property int highlightIndex: -1
3636
37− signal applicationSelected(string desktopFile)
37+ signal applicationSelected(string appId)
3838 signal dashItemSelected(int index)
3939
4040 BorderImage {
@@ -50,8 +50,6 @@ Item {
5050 id: mainColumn
5151 anchors {
5252 fill: parent
53− leftMargin: units.gu(0.5)
54− rightMargin: units.gu(0.5)
5553 }
5654
5755 MouseArea {
@@ -94,6 +92,8 @@ Item {
9492 fill: parent
9593 topMargin: -extensionSize + units.gu(0.5)
9694 bottomMargin: -extensionSize + units.gu(1)
95+ leftMargin: units.gu(0.5)
96+ rightMargin: units.gu(0.5)
9797 }
9898 topMargin: extensionSize
9999 bottomMargin: extensionSize
@@ -156,6 +156,7 @@ Item {
156156 iconName: model.icon
157157 count: model.count
158158 progress: model.progress
159+ itemFocused: model.focused
159160 inverted: root.inverted
160161 z: -Math.abs(offset)
161162 maxAngle: 55
@@ -299,7 +300,7 @@ Item {
299300 } else if (clickedItem.angle < -12) {
300301 launcherListView.flick(0, launcherListView.clickFlickSpeed);
301302 } else {
302− root.applicationSelected(LauncherModel.get(index).desktopFile);
303+ root.applicationSelected(LauncherModel.get(index).appId);
303304 }
304305 return;
305306 }
@@ -310,7 +311,7 @@ Item {
310311 } else if (clickedItem.angle < -30) {
311312 launcherListView.flick(0, launcherListView.clickFlickSpeed);
312313 } else {
313− root.applicationSelected(LauncherModel.get(index).desktopFile);
314+ root.applicationSelected(LauncherModel.get(index).appId);
314315 }
315316 }
316317
@@ -512,6 +513,12 @@ Item {
512513 objectName: "quickListEntry" + index
513514 text: (model.clickable ? "" : "<b>") + model.label + (model.clickable ? "" : "</b>")
514515 highlightWhenPressed: model.clickable
516+
517+ // FIXME: This is a workaround for the theme not being context sensitive. I.e. the
518+ // ListItems don't know that they are sitting in a themed Popover where the color
519+ // needs to be inverted.
520+ __foregroundColor: Theme.palette.selected.backgroundText
521+
515522 onClicked: {
516523 if (!model.clickable) {
517524 return;
Launcher/graphics/focused_app_arrow@30.pngnew file

Binary file not shown.

MouseTouchAdaptor.cpp+29−12
@@ -39,24 +39,16 @@ Qt::MouseButton translateMouseButton(xcb_button_t detail)
3939} // end of anonymous namespace
4040
4141MouseTouchAdaptor::MouseTouchAdaptor()
42− : m_targetWindow(0)
43− , m_leftButtonIsPressed(false)
42+ : m_leftButtonIsPressed(false)
4443{
4544 m_touchDevice = new QTouchDevice;
4645 m_touchDevice->setType(QTouchDevice::TouchScreen);
4746 QWindowSystemInterface::registerTouchDevice(m_touchDevice);
4847}
4948
50−void MouseTouchAdaptor::setTargetWindow(QWindow *window)
51−{
52− m_targetWindow = window;
53−}
54−
5549bool MouseTouchAdaptor::nativeEventFilter(const QByteArray & eventType,
5650 void * message, long * /*result*/)
5751{
58− Q_ASSERT(m_targetWindow);
59−
6052 if (eventType != "xcb_generic_event_t") {
6153 // wrong backend.
6254 qWarning("MouseTouchAdaptor: XCB backend not in use. Adaptor inoperative!");
@@ -91,7 +83,9 @@ bool MouseTouchAdaptor::handleButtonPress(xcb_button_press_event_t *pressEvent)
9183
9284 QPoint windowPos(pressEvent->event_x, pressEvent->event_y);
9385
94− QTouchEventSequence touchEvent = QTest::touchEvent(m_targetWindow, m_touchDevice,
86+ QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(pressEvent->event));
87+
88+ QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
9589 false /* autoCommit */);
9690 touchEvent.press(0 /* touchId */, windowPos);
9791 touchEvent.commit(false /* processEvents */);
@@ -110,7 +104,9 @@ bool MouseTouchAdaptor::handleButtonRelease(xcb_button_release_event_t *releaseE
110104
111105 QPoint windowPos(releaseEvent->event_x, releaseEvent->event_y);
112106
113− QTouchEventSequence touchEvent = QTest::touchEvent(m_targetWindow, m_touchDevice,
107+ QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(releaseEvent->event));
108+
109+ QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
114110 false /* autoCommit */);
115111 touchEvent.release(0 /* touchId */, windowPos);
116112 touchEvent.commit(false /* processEvents */);
@@ -127,10 +123,31 @@ bool MouseTouchAdaptor::handleMotionNotify(xcb_motion_notify_event_t *event)
127123
128124 QPoint windowPos(event->event_x, event->event_y);
129125
130− QTouchEventSequence touchEvent = QTest::touchEvent(m_targetWindow, m_touchDevice,
126+ QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(event->event));
127+
128+ QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
131129 false /* autoCommit */);
132130 touchEvent.move(0 /* touchId */, windowPos);
133131 touchEvent.commit(false /* processEvents */);
134132
135133 return true;
136134}
135+
136+QWindow *MouseTouchAdaptor::findQWindowWithXWindowID(WId windowId)
137+{
138+ QWindowList windowList = QGuiApplication::topLevelWindows();
139+ QWindow *foundWindow = nullptr;
140+
141+ int i = 0;
142+ while (!foundWindow && i < windowList.count()) {
143+ QWindow *window = windowList[i];
144+ if (window->winId() == windowId) {
145+ foundWindow = window;
146+ } else {
147+ ++i;
148+ }
149+ }
150+
151+ Q_ASSERT(foundWindow);
152+ return foundWindow;
153+}
MouseTouchAdaptor.h+2−5
@@ -20,11 +20,11 @@
2020#define MOUSE_TOUCH_ADAPTOR_H
2121
2222#include <QtCore/QAbstractNativeEventFilter>
23+#include <QWindow>
2324#include <xcb/xcb.h>
2425
2526class QMouseEvent;
2627class QTouchDevice;
27−class QWindow;
2828
2929// Transforms QMouseEvents into single-finger QTouchEvents.
3030class MouseTouchAdaptor : public QAbstractNativeEventFilter {
@@ -32,9 +32,6 @@ class MouseTouchAdaptor : public QAbstractNativeEventFilter {
3232public:
3333 MouseTouchAdaptor();
3434
35− // The window that will receive the generated QTouchEvents
36− void setTargetWindow(QWindow *window);
37−
3835 // Filters mouse events and posts the equivalent QTouchEvents.
3936 virtual bool nativeEventFilter(const QByteArray & eventType, void *message, long *result);
4037
@@ -43,8 +40,8 @@ private:
4340 bool handleButtonPress(xcb_button_press_event_t *pressEvent);
4441 bool handleButtonRelease(xcb_button_release_event_t *releaseEvent);
4542 bool handleMotionNotify(xcb_motion_notify_event_t *event);
43+ QWindow *findQWindowWithXWindowID(WId windowId);
4644
47− QWindow *m_targetWindow;
4845 QTouchDevice *m_touchDevice;
4946 bool m_leftButtonIsPressed;
5047};
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+18−2
@@ -35,6 +35,7 @@ Showable {
3535 property bool partiallyOpened: height > panelHeight && !fullyOpened
3636 property real visualBottom: Math.max(y+height, y+indicatorRow.y+indicatorRow.height)
3737 property bool contentEnabled: true
38+ readonly property alias content: menuContent
3839
3940 // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
4041 // use its own values. Need to ask design about this.
@@ -180,11 +181,19 @@ Showable {
180181 clip: !indicators.fullyOpened
181182 activeHeader: indicators.state == "hint" || indicators.state == "reveal"
182183 enabled: contentEnabled
184+ visibleIndicators: indicatorRow.visibleIndicators
183185
184186 Connections {
185− target: indicatorRow
187+ property bool enableIndexChangeSignal: true
188+
189+ target: enableIndexChangeSignal ? indicatorRow : null
186190 onCurrentItemIndexChanged: {
191+ var oldActive = enableIndexChangeSignal;
192+ enableIndexChangeSignal = false;
193+
187194 menuContent.setCurrentMenuIndex(indicatorRow.currentItemIndex);
195+
196+ enableIndexChangeSignal = oldActive;
188197 }
189198 }
190199
@@ -256,9 +265,16 @@ Showable {
256265 state: indicators.state
257266
258267 Connections {
259− target: menuContent
268+ property bool enableIndexChangeSignal: true
269+
270+ target: enableIndexChangeSignal ? menuContent : null
260271 onCurrentMenuIndexChanged: {
272+ var oldActive = enableIndexChangeSignal;
273+ enableIndexChangeSignal = false;
274+
261275 indicatorRow.setCurrentItem(menuContent.currentMenuIndex);
276+
277+ enableIndexChangeSignal = oldActive;
262278 }
263279 }
264280 }
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+3−6
@@ -24,7 +24,8 @@ import Unity.IndicatorsLegacy 0.1 as Indicators
2424Indicators.IndicatorWidget {
2525 id: indicatorWidget
2626
27− width: itemRow.width + units.gu(1)
27+ enabled:true
28+ width: itemRow.width + units.gu(0.5)
2829
2930 property alias label: itemLabel.text
3031 property alias iconSource: itemImage.source
@@ -67,14 +68,10 @@ Indicators.IndicatorWidget {
6768 }
6869
6970 if (action.state == undefined) {
70− label = "";
71− iconSource = "";
72− enabled = false;
7371 return;
7472 }
7573
7674 label = action.state[Indicators.ActionState.Label];
77− iconSource = "image://gicon/" + action.state[Indicators.ActionState.IconSource];
78− enabled = action.state[Indicators.ActionState.Visible];
75+ iconSource = "image://theme/" + action.state[Indicators.ActionState.IconSource];
7976 }
8077}
Panel/Indicators/DefaultIndicatorWidget2.qml+43−16
@@ -24,10 +24,11 @@ import Unity.Indicators 0.1 as Indicators
2424Indicators.IndicatorWidget {
2525 id: indicatorWidget
2626
27− width: itemRow.width + units.gu(1)
27+ width: itemRow.width + units.gu(0.5)
2828
29− property alias label: itemLabel.text
30− property alias iconSource: itemImage.source
29+ property alias leftLabel: itemLeftLabel.text
30+ property alias rightLabel: itemRightLabel.text
31+ property var icons: undefined
3132
3233 Row {
3334 id: itemRow
@@ -39,19 +40,43 @@ Indicators.IndicatorWidget {
3940 }
4041 spacing: units.gu(0.5)
4142
42− // FIXME : Should us Ubuntu.Icon . results in low res images
43− Image {
44− id: itemImage
45− objectName: "itemImage"
46− visible: source != ""
47− height: indicatorWidget.iconSize
48− width: indicatorWidget.iconSize
43+ Label {
44+ id: itemLeftLabel
45+ objectName: "leftLabel"
46+ color: Theme.palette.selected.backgroundText
47+ opacity: 0.8
48+ font.family: "Ubuntu"
49+ fontSize: "medium"
4950 anchors.verticalCenter: parent.verticalCenter
51+ visible: text != ""
52+ }
53+
54+ Row {
55+ width: childrenRect.width
56+ anchors {
57+ top: parent.top
58+ bottom: parent.bottom
59+ }
60+ spacing: units.gu(0.5)
61+
62+ Repeater {
63+ model: indicatorWidget.icons
64+
65+ Image {
66+ id: itemImage
67+ objectName: "itemImage"
68+ visible: source != ""
69+ source: modelData
70+ height: indicatorWidget.iconSize
71+ width: indicatorWidget.iconSize
72+ anchors.verticalCenter: parent.verticalCenter
73+ }
74+ }
5075 }
5176
5277 Label {
53− id: itemLabel
54− objectName: "itemLabel"
78+ id: itemRightLabel
79+ objectName: "rightLabel"
5580 color: Theme.palette.selected.backgroundText
5681 opacity: 0.8
5782 font.family: "Ubuntu"
@@ -63,14 +88,16 @@ Indicators.IndicatorWidget {
6388
6489 onActionStateChanged: {
6590 if (actionState == undefined) {
66− label = "";
67− iconSource = "";
91+ leftLabel = "";
92+ rightLabel = "";
93+ icons = undefined;
6894 enabled = false;
6995 return;
7096 }
7197
72− label = actionState.label;
73− iconSource = actionState.icon;
98+ leftLabel = actionState.leftLabel ? actionState.leftLabel : "";
99+ rightLabel = actionState.rightLabel ? actionState.rightLabel : "";
100+ icons = actionState.icons;
74101 enabled = actionState.visible;
75102 }
76103}
Panel/Indicators/MessagingIndicatorWidget.qml+1−1
@@ -21,5 +21,5 @@ import QtQuick 2.0
2121
2222DefaultIndicatorWidget {
2323 // default the icon so we have something to show when we don't have the bus.
24− iconSource: "image://gicon/indicator-messages"
24+ iconSource: "image://theme/indicator-messages"
2525}
Panel/Indicators/NetworkIndicatorWidget.qml+10−7
@@ -24,7 +24,7 @@ import Unity.IndicatorsLegacy 0.1 as Indicators
2424Indicators.IndicatorWidget {
2525 id: indicatorWidget
2626
27− width: networkIcon.width + units.gu(1)
27+ width: networkIcon.width + units.gu(0.5)
2828
2929 property int signalStrength: 0
3030 property int connectionState: Indicators.NetworkConnection.Initial
@@ -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];
@@ -94,16 +97,16 @@ Indicators.IndicatorWidget {
9497 function get_icon_for_signal(con_state, value) {
9598 if (con_state >= Indicators.NetworkConnection.Activating && con_state <= Indicators.NetworkConnection.Deactivating) {
9699 if (value == 0) {
97− return "image://gicon/nm-signal-00";
100+ return "image://theme/nm-signal-00";
98101 } else if (value <= 25) {
99− return "image://gicon/nm-signal-25";
102+ return "image://theme/nm-signal-25";
100103 } else if (value <= 50) {
101− return "image://gicon/nm-signal-50";
104+ return "image://theme/nm-signal-50";
102105 } else if (value <= 75) {
103− return "image://gicon/nm-signal-75";
106+ return "image://theme/nm-signal-75";
104107 }
105− return "image://gicon/nm-signal-100";
108+ return "image://theme/nm-signal-100";
106109 }
107− return "image://gicon/wifi-none";
110+ return "image://theme/wifi-none";
108111 }
109112}
Panel/Indicators/SoundIndicatorWidget.qml+2−1
@@ -21,5 +21,6 @@ import QtQuick 2.0
2121
2222DefaultIndicatorWidget {
2323 // default the icon so we have something to show when we don't have the bus.
24− iconSource: "image://gicon/audio-volume-high"
24+ iconSource: "image://theme/audio-volume-high"
25+ enabled: true
2526}
Panel/IndicatorsDataModel.qml+2−2
@@ -42,8 +42,8 @@ Indicators.IndicatorsModel {
4242 'indicator-messages' : {
4343 'title': 'Messaging',
4444 'description' : '',
45− 'widgetSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/MessagingIndicatorWidget.qml',
46− 'pageSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/MessagingIndicatorPage.qml'
45+ 'widgetSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/DefaultIndicatorWidget2.qml',
46+ 'pageSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/DefaultIndicatorPage2.qml'
4747 },
4848 'indicator-sound' : {
4949 'title': 'Sound',
Panel/MenuContent.qml+37−9
@@ -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.
@@ -91,7 +109,7 @@ MainView {
91109 source: pageSource
92110 asynchronous: true
93111
94− property bool contentActive: content.__contentActive
112+ property bool contentActive: content.__contentActive && menuActivator.content[index].active
95113
96114 onContentActiveChanged: {
97115 if (contentActive && item) {
@@ -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 }
@@ -128,6 +146,16 @@ MainView {
128146 id: contentReleaseTimer
129147
130148 interval: contentReleaseInterval
131− onTriggered: content.__contentActive = false
149+ onTriggered: {
150+ content.__contentActive = false;
151+ menuActivator.clear();
152+ }
153+ }
154+
155+ Indicators.MenuContentActivator {
156+ id: menuActivator
157+ running: content.__contentActive
158+ baseIndex: content.currentMenuIndex
159+ count: indicatorsModel.count
132160 }
133161}
Shell.qml+60−28
@@ -15,12 +15,15 @@
1515 */
1616
1717import QtQuick 2.0
18+import AccountsService 0.1
1819import GSettings 1.0
19−import Ubuntu.Application 0.1
20+import Unity.Application 0.1
2021import Ubuntu.Components 0.1
2122import Ubuntu.Gestures 0.1
23+import Unity.Launcher 0.1
2224import LightDM 0.1 as LightDM
2325import Powerd 0.1
26+import SessionBroadcast 0.1
2427import "Dash"
2528import "Greeter"
2629import "Launcher"
@@ -63,6 +66,12 @@ FocusScope {
6366
6467 property var applicationManager: ApplicationManagerWrapper {}
6568
69+ Binding {
70+ target: LauncherModel
71+ property: "applicationManager"
72+ value: ApplicationManager
73+ }
74+
6675 Component.onCompleted: {
6776 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
6877
@@ -73,6 +82,11 @@ FocusScope {
7382 applicationManager.unfocusCurrentApplication();
7483 }
7584
85+ readonly property bool applicationFocused: !!applicationManager.mainStageFocusedApplication
86+ || !!applicationManager.sideStageFocusedApplication
87+ // Used for autopilot testing.
88+ readonly property string currentFocusedAppId: ApplicationManager.focusedApplicationId
89+
7690 readonly property bool fullscreenMode: {
7791 if (greeter.shown || lockscreen.shown) {
7892 return false;
@@ -146,6 +160,10 @@ FocusScope {
146160 }
147161 }
148162
163+ OSKController {
164+ anchors.fill: parent // as needs to know the geometry of the shell
165+ }
166+
149167 VolumeControl {
150168 id: volumeControl
151169 }
@@ -180,6 +198,7 @@ FocusScope {
180198
181199 anchors.fill: parent
182200 source: shell.background
201+ fillMode: Image.PreserveAspectCrop
183202 }
184203
185204 Rectangle {
@@ -244,7 +263,7 @@ FocusScope {
244263 property bool fullyShown: shown && x == 0 && parent.x == 0
245264 property bool fullyHidden: !shown && x == width
246265 available: !greeter.shown
247− hides: [launcher, panel.indicators]
266+ hides: [panel.indicators]
248267 shown: false
249268 opacity: 1.0
250269 showAnimation: StandardAnimation { property: "x"; duration: 350; to: 0; easing.type: Easing.OutCubic }
@@ -445,6 +464,8 @@ FocusScope {
445464 hides: [launcher, panel.indicators, hud]
446465 shown: true
447466
467+ defaultBackground: shell.background
468+
448469 y: panel.panelHeight
449470 width: parent.width
450471 height: parent.height - panel.panelHeight
@@ -465,6 +486,12 @@ FocusScope {
465486 }
466487
467488 onUnlocked: greeter.hide()
489+ onSelected: {
490+ // Update launcher items for new user
491+ var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
492+ AccountsService.user = user;
493+ LauncherModel.setUser(user);
494+ }
468495
469496 onLeftTeaserPressedChanged: {
470497 if (leftTeaserPressed) {
@@ -475,7 +502,8 @@ FocusScope {
475502
476503 InputFilterArea {
477504 anchors.fill: parent
478− blockInput: greeter.shown || lockscreen.shown
505+ blockInput: !applicationFocused || greeter.shown || lockscreen.shown || launcher.shown
506+ || panel.indicators.shown || hud.shown
479507 }
480508
481509 Connections {
@@ -487,10 +515,8 @@ FocusScope {
487515
488516 function setFocused(focused) {
489517 if (!focused) {
490− // FIXME: *FocusedApplication are not updated when unfocused, hence the need to check whether
491− // the stage was actually shown
492− if (mainStage.fullyShown) powerConnection.previousMainApp = applicationManager.mainStageFocusedApplication;
493− if (sideStage.fullyShown) powerConnection.previousSideApp = applicationManager.sideStageFocusedApplication;
518+ powerConnection.previousMainApp = applicationManager.mainStageFocusedApplication;
519+ powerConnection.previousSideApp = applicationManager.sideStageFocusedApplication;
494520 applicationManager.unfocusCurrentApplication();
495521 } else {
496522 if (powerConnection.previousMainApp) {
@@ -523,6 +549,17 @@ FocusScope {
523549 }
524550 }
525551
552+ function showHome() {
553+ greeter.hide()
554+ // Animate if moving between application and dash
555+ if (!stages.shown) {
556+ dash.setCurrentScope("home.scope", true, false)
557+ } else {
558+ dash.setCurrentScope("home.scope", false, false)
559+ }
560+ stages.hide()
561+ }
562+
526563 Item {
527564 id: overlay
528565
@@ -541,8 +578,13 @@ FocusScope {
541578 searchVisible: !greeter.shown && !lockscreen.shown
542579
543580 InputFilterArea {
544− anchors.fill: parent
545− blockInput: panel.indicators.shown
581+ anchors {
582+ top: parent.top
583+ left: parent.left
584+ right: parent.right
585+ }
586+ height: (panel.fullscreenMode) ? shell.edgeSize : panel.panelHeight
587+ blockInput: true
546588 }
547589 }
548590
@@ -562,11 +604,6 @@ FocusScope {
562604 onMainStageFocusedApplicationChanged: hud.hide()
563605 onSideStageFocusedApplicationChanged: hud.hide()
564606 }
565−
566− InputFilterArea {
567− anchors.fill: parent
568− blockInput: hud.shown
569− }
570607 }
571608
572609 Revealer {
@@ -588,9 +625,8 @@ FocusScope {
588625 Bottombar {
589626 theHud: hud
590627 anchors.fill: parent
591− enabled: !panel.indicators.shown
592− applicationIsOnForeground: applicationManager.mainStageFocusedApplication
593− || applicationManager.sideStageFocusedApplication
628+ enabled: hud.available
629+ applicationIsOnForeground: applicationFocused
594630 }
595631
596632 InputFilterArea {
@@ -611,16 +647,7 @@ FocusScope {
611647 width: parent.width
612648 dragAreaWidth: shell.edgeSize
613649 available: (!greeter.shown || greeter.narrowMode) && edgeDemo.launcherEnabled
614− onDashItemSelected: {
615− greeter.hide()
616− // Animate if moving between application and dash
617− if (!stages.shown) {
618− dash.setCurrentScope("home.scope", true, false)
619− } else {
620− dash.setCurrentScope("home.scope", false, false)
621− }
622− stages.hide();
623− }
650+ onDashItemSelected: showHome()
624651 onDash: {
625652 if (stages.shown) {
626653 dash.setCurrentScope("applications.scope", true, false)
@@ -630,7 +657,7 @@ FocusScope {
630657 }
631658 onLauncherApplicationSelected:{
632659 greeter.hide()
633− shell.activateApplication(desktopFile)
660+ shell.activateApplication(appId)
634661 }
635662 onShownChanged: {
636663 if (shown) {
@@ -728,4 +755,9 @@ FocusScope {
728755 indicators: panel.indicators
729756 underlay: underlay
730757 }
758+
759+ Connections {
760+ target: SessionBroadcast
761+ onShowHome: showHome()
762+ }
731763}
SideStage/SideStage.qml+1−1
@@ -15,7 +15,7 @@
1515 */
1616
1717import QtQuick 2.0
18−import Ubuntu.Application 0.1
18+import Unity.Application 0.1
1919import Ubuntu.Components 0.1
2020import "../Components"
2121
build+9
@@ -57,6 +57,15 @@ mk_build_deps() {
5757 [ ! -f unity8-build-deps*deb -o $CODE_DIR/debian/control -nt unity8-build-deps*deb ] && mk-build-deps --install --root-cmd sudo $CODE_DIR/debian/control
5858}
5959
60+if [ -f "/usr/bin/ccache" ] ; then
61+ if [ "x$CC" = "x" ]; then
62+ export CC='ccache gcc'
63+ fi
64+ if [ "x$CXX" = "x" ] ; then
65+ export CXX='ccache g++'
66+ fi
67+fi
68+
6069if [ -f "/usr/bin/ninja" ] ; then
6170 GENERATOR="-G Ninja"
6271 # Ninja does not need -j, it parallelizes automatically.
debian/changelog+318
@@ -1,3 +1,321 @@
1+unity8 (7.81.3+13.10.20130927.3-0ubuntu1) saucy; urgency=low
2+
3+ [ Michal Hruby ]
4+ * Correctly handle image URI scheme in results.
5+
6+ [ Michał Sawicz ]
7+ * Make SHOW_DASH and HIDE_DASH close the current preview. (LP:
8+ #1231404)
9+ * Add a LazyImage component that shows an activity spinner for long-
10+ loading images and handles aspect ratio properly.
11+ * Fix Qt 5.1 FTBFS and suppress some build warnings.
12+
13+ [ Albert Astals ]
14+ * Make sure we always have least have one column in the gridview. (LP:
15+ #1225391)
16+ * LVWPH: Make sure we always overshoot vertically. (LP: #1229851)
17+ * Remember the expanded categoryId and not the expanded index The
18+ index can change on search, and we still want to maintain it
19+ expanded in that case. (LP: #1230216)
20+ * Fix showHeader in an edge case of notShownByItsOwn Not all the tests
21+ i've added fail without the code fix, but i've added them just to be
22+ more covered . (LP: #1230187)
23+
24+ [ Diego Sarmentero ]
25+ * Handling error signal from the DownloadTracker plugin (BUG:
26+ #1229744). (LP: #1229744)
27+ * Remove "Reviews and Comments" section from Application Preview until
28+ the feature is ready (BUG: #1226632) - Detect when the keyboard is
29+ being shown to allow the user to scroll the Preview even more if
30+ necessary to interact with the components at the bottom of that
31+ preview, and don't leave those components obscured behind the
32+ keyboard (BUG: #1226638). (LP: #1226632, #1224717, #1226638)
33+
34+ [ Nick Dedekind ]
35+ * Brought messaging indicator inline with UnityMenuModel &
36+ UnityMenuAction. (LP: #1217676, #1217678)
37+
38+ [ Pawel Stolowski ]
39+ * Support canned search queries returned by Home Scope.
40+ * Cancel previous actions and previews on new activation / preview.
41+ Expose previewed data row in Preview object.
42+
43+ [ Michael Terry ]
44+ * Only enable the Bottombar when the HUD is available. (LP: #1220306)
45+ * Increase the "Skip intro" clickable area, making dismissing the edge
46+ demo intro feel more natural. (LP: #1220632)
47+
48+ [ Michael Zanetti ]
49+ * drop our CrossFadeImage in favor of the SDK one. (LP: #1227783)
50+
51+ [ Ubuntu daily release ]
52+ * Automatic snapshot from revision 358
53+
54+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 27 Sep 2013 14:13:22 +0000
55+
56+unity8 (7.81.3+13.10.20130924.2-0ubuntu1) saucy; urgency=low
57+
58+ [ Michal Hruby ]
59+ * Fix the signal prototypes on music grid renderer. (LP: #1228390)
60+
61+ [ Michael Zanetti ]
62+ * use less auto variables, align coding style, constify and Qt'ify API
63+ in AccountsService plugin.
64+
65+ [ Nick Dedekind ]
66+ * Re-enable MenuContentActivator in Indicators.
67+
68+ [ Albert Astals ]
69+ * LVWPH: Update the section header on list change events.
70+
71+ [ Pawel Stolowski ]
72+ * Check results model ptr returned by GetResultsFromCategory method
73+ from UnityCore. (LP: #1228097, #1211595)
74+
75+ [ Ubuntu daily release ]
76+ * Automatic snapshot from revision 340
77+
78+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 24 Sep 2013 14:40:01 +0000
79+
80+unity8 (7.81.3+13.10.20130919.3-0ubuntu1) saucy; urgency=low
81+
82+ [ Michal Hruby ]
83+ * Add support for music grid renderer to GenericScopeView.
84+
85+ [ Nick Dedekind ]
86+ * Fixed the removal of messaging widget due to incompatible action
87+ state. (LP: #1225017)
88+
89+ [ Christopher Lee ]
90+ * Addition of initial autopilot tests for the application lifecycle.
91+
92+ [ Lars Uebernickel ]
93+ * VolumeControl: use action of the new indicator indicator-sound
94+ recently gained an action to increase and decrease the volume. This
95+ patch makes use of that to get rid of a bus round trip (to get the
96+ current volume) and a race (when the volume gets set between
97+ fetching the current volume and setting the new volume). (LP:
98+ #1219057)
99+
100+ [ Michael Terry ]
101+ * When AccountsService.backgroundFile is unset/invalid, have the
102+ greeter fall back to whatever the shell background is.
103+ * Add a tiny SessionBroadcast plugin that listens to unity-greeter-
104+ session-broadcast for the ShowHome signal.
105+
106+ [ Daniel d'Andrada ]
107+ * Remove obsolete, unused graphics.
108+ * Make MouseTouchAdaptor work with multiple QWindows.
109+
110+ [ Michael Zanetti ]
111+ * change how icons are searched a) try to find it the Icon as is b)
112+ prepend with Path if a Path variable is given c) fall back to the
113+ image://theme/ with just the icon name . (LP: #1225186)
114+ * fix an issue with removing a running app from the launcher and
115+ always store pinning to the config.
116+ * collapse any open preview when programmatically switching current
117+ dash index. (LP: #1221137)
118+
119+ [ Ubuntu daily release ]
120+ * Automatic snapshot from revision 333
121+
122+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 19 Sep 2013 15:15:07 +0000
123+
124+unity8 (7.81.3+13.10.20130916-0ubuntu1) saucy; urgency=low
125+
126+ [ Michael Zanetti ]
127+ * allow left edge gesture to minimize apps even when launcher is
128+ already visible.
129+ * Don't hide the launcher on changes in the stages.
130+ * ssh is now installed per default, but it's set to manual in the
131+ ssh.override.
132+
133+ [ Ubuntu daily release ]
134+ * Automatic snapshot from revision 320
135+
136+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 16 Sep 2013 11:49:28 +0000
137+
138+unity8 (7.81.3+13.10.20130912-0ubuntu1) saucy; urgency=low
139+
140+ [ Michael Zanetti ]
141+ * add support for finding icons from click package apps in the
142+ launcher.
143+ * update to latest launcher API for better integration with the
144+ AppManager.
145+
146+ [ Ricardo Mendoza ]
147+ * Fixes problems related to image 20130912.0, amongst: * Fix autopilot
148+ tests by preventing blocking of input during HUD button animations,
149+ only when fully visible * Fix loading of unity-mir library, major
150+ version wasn't specified so unless the dev package was there it
151+ would fail.
152+
153+ [ Ubuntu daily release ]
154+ * Automatic snapshot from revision 316
155+
156+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 12 Sep 2013 13:47:59 +0000
157+
158+unity8 (7.81.3+13.10.20130911.1-0ubuntu1) saucy; urgency=low
159+
160+ [ Michael Terry ]
161+ * Switch from deprecated image://gicon/ to new image://theme/.
162+
163+ [ Gerry Boland ]
164+ * Add OSKController so shell can control OSK correctly on Mir.
165+ * Remove InputFilterArea for bottom edge swipes, as applications also
166+ listen for such swipes for Toolbar reveal.
167+
168+ [ Ricardo Mendoza ]
169+ * Select the backend to use dynamically on runtime according to the
170+ QPA selected by the system.
171+
172+ [ Ubuntu daily release ]
173+ * Automatic snapshot from revision 311
174+
175+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 11 Sep 2013 16:22:55 +0000
176+
177+unity8 (7.81.3+13.10.20130911-0ubuntu1) saucy; urgency=low
178+
179+ [ Michal Hruby ]
180+ * Hide all gicon strings from the shell and use the image://theme icon
181+ provider that was recently added to the SDK.
182+
183+ [ Gerry Boland ]
184+ * Convert to new ApplicationManager API.
185+
186+ [ Nick Dedekind ]
187+ * Updated access point design as per spec.
188+ * Indicator visibility based on connection with backend service.
189+
190+ [ Albert Astals ]
191+ * Dash: Make assignments bindings This way if the model changes the
192+ item value also changes.
193+
194+ [ Michael Zanetti ]
195+ * adds support for highlighting the currently focused application in
196+ the launcher, adds tests.
197+ * include ~/.local/share/applications in launcher's .desktop file
198+ search path.
199+ * shrink size of area for revealing the HUD button and make it
200+ disappear on release again. fixes 1219035. (LP: #1219035)
201+ * revert revision 304 as it makes the Shell crash.
202+
203+ [ Michael Terry ]
204+ * Allow testers to set custom password or pin in demo mode, rather
205+ than hardcoding them.
206+ * Have the greeter use AccountsService to determine its background.
207+ (LP: #1218402)
208+ * Listen to changes in the "show edge demo" AccountsService setting.
209+
210+ [ Daniel d'Andrada ]
211+ * Update fake/mock plugins so that "./run --fake" works well again -
212+ You can now see the thumbnails of the fake running applications once
213+ again. - You no longer get hundreds of warnings due to icons not
214+ found.
215+ * Reset apps scope when returning from app to dash (LP #1193419) If an
216+ app is on foreground and you perform a long left-edge swipe to
217+ minimize it, and therefore return to the dash, the dash should be in
218+ the Applications scope and showing the running/recents applications.
219+ (LP: #1193419)
220+
221+ [ Ubuntu daily release ]
222+ * Automatic snapshot from revision 306
223+
224+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 11 Sep 2013 00:54:31 +0000
225+
226+unity8 (7.81.3+13.10.20130905.2-0ubuntu1) saucy; urgency=low
227+
228+ [ Michael Zanetti ]
229+ * Integrate Launcher with AppManager.
230+
231+ [ Nick Dedekind ]
232+ * Removed FIXME from slider int->double conversion.
233+
234+ [ Ubuntu daily release ]
235+ * Automatic snapshot from revision 291
236+
237+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 05 Sep 2013 10:48:02 +0000
238+
239+unity8 (7.81.3+13.10.20130904.1-0ubuntu1) saucy; urgency=low
240+
241+ [ Nicolas d'Offay ]
242+ * Switched infographic background at design's request.
243+
244+ [ Ubuntu daily release ]
245+ * Automatic snapshot from revision 287
246+
247+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 04 Sep 2013 07:34:57 +0000
248+
249+unity8 (7.81.3+13.10.20130904-0ubuntu1) saucy; urgency=low
250+
251+ [ mhall119 ]
252+ * Add a little bit of text to the last step of the tour telling the
253+ user how to end it and get to their phone.
254+
255+ [ Jussi Pakkanen ]
256+ * Use CCache if it is installed.
257+
258+ [ Nick Dedekind ]
259+ * Multiple icon/label support for indicators.
260+
261+ [ Albert Astals ]
262+ * Remove unneeded role.
263+
264+ [ Lars Uebernickel ]
265+ * Fall back to "ubuntu-mobile" icon theme if $UBUNTU_ICON_THEME is
266+ unset.
267+
268+ [ Michael Zanetti ]
269+ * Use MouseAreas in DashBar to enable clicking again.
270+ * load launcher default config from existing dconf key.
271+
272+ [ Ubuntu daily release ]
273+ * Automatic snapshot from revision 285
274+
275+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 04 Sep 2013 03:02:57 +0000
276+
277+unity8 (7.81.3+13.10.20130903.1-0ubuntu1) saucy; urgency=low
278+
279+ [ Michael Zanetti ]
280+ * workaround quicklist text color.
281+
282+ [ Ubuntu daily release ]
283+ * Automatic snapshot from revision 277
284+
285+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 03 Sep 2013 06:09:36 +0000
286+
287+unity8 (7.81.3+13.10.20130830-0ubuntu1) saucy; urgency=low
288+
289+ [ Pawel Stolowski ]
290+ * Implement a virtual 'All' filter option.
291+
292+ [ Ubuntu daily release ]
293+ * Automatic snapshot from revision 275
294+
295+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 30 Aug 2013 12:44:40 +0000
296+
297+unity8 (7.81.3+13.10.20130829.2-0ubuntu1) saucy; urgency=low
298+
299+ [ Michael Terry ]
300+ * Implement launcher item backend via AccountsService.
301+
302+ [ Ubuntu daily release ]
303+ * Automatic snapshot from revision 272
304+
305+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 29 Aug 2013 19:09:44 +0000
306+
307+unity8 (7.81.3+13.10.20130829.1-0ubuntu1) saucy; urgency=low
308+
309+ [ Michael Terry ]
310+ * Make sure greeter and lockscreen backgrounds are always defined,
311+ even if the wallpaper preference string is bogus. (LP: #1208889,
312+ #1208894)
313+
314+ [ Ubuntu daily release ]
315+ * Automatic snapshot from revision 270
316+
317+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 29 Aug 2013 11:09:43 +0000
318+
1319unity8 (7.81.3+13.10.20130829-0ubuntu1) saucy; urgency=low
2320
3321 [ Andrea Cimitan ]
debian/control+11−8
@@ -9,6 +9,7 @@ Build-Depends: cmake,
99 libgl1-mesa-dev[!armhf] | libgl-dev[!armhf],
1010 libgl1-mesa-dri,
1111 libgles2-mesa-dev[armhf],
12+ libgsettings-qt-dev,
1213 libhud-client2-dev,
1314 libjson-perl,
1415 libnih-dbus-dev,
@@ -20,8 +21,9 @@ Build-Depends: cmake,
2021 libqt5v8-5-private-dev,
2122 libsigc++-2.0-dev,
2223 libunity-api-dev (>= 7.80.3),
23− libunity-core-6.0-dev (<< 7.80),
24+ libunity-core-6.0-dev (>= 7.1.1),
2425 libunity-dev (>= 7.0.12),
26+ libunity-mir-dev,
2527 libunity-scopes-json-def-phone,
2628 libupstart-dev,
2729 libusermetricsoutput1-dev,
@@ -53,7 +55,7 @@ Vcs-Browser: https://bazaar.launchpad.net/~unity-team/unity8/trunk
5355Package: indicators-client
5456Architecture: amd64 armhf i386
5557Depends: qmenumodel-qml (>= 0.2.7),
56− qtdeclarative5-ubuntu-ui-toolkit-plugin | qt-components-ubuntu,
58+ qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 0.1.46+13.10.20130829.1-0ubuntu1),
5759 unity8 (= ${binary:Version}),
5860 ${misc:Depends},
5961 ${shlibs:Depends},
@@ -64,13 +66,14 @@ Package: unity8
6466Architecture: any
6567Provides: indicator-renderer,
6668Depends: gsettings-desktop-schemas,
69+ libunity-mir1,
6770 qmenumodel-qml (>= 0.2.7),
6871 qtdeclarative5-dee-plugin,
6972 qtdeclarative5-gsettings1.0,
70− qtdeclarative5-ubuntu-ui-toolkit-plugin,
73+ qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 0.1.46+13.10.20130829.1-0ubuntu1),
7174 qtdeclarative5-unity-notifications-plugin | unity-notifications-impl,
7275 qtdeclarative5-xmllistmodel-plugin,
73− unity-launcher-impl-2,
76+ unity-launcher-impl-3,
7477 unity-notifications-impl-1,
7578 unity8-fake-env | qtubuntu-shell,
7679 unity8-private (= ${binary:Version}),
@@ -86,18 +89,18 @@ Description: Unity 8 shell
8689
8790Package: unity8-autopilot
8891Architecture: all
89−Depends: indicators-client (>= ${source:Version}),
92+Depends: gir1.2-glib-2.0,
93+ indicators-client (>= ${source:Version}),
9094 libautopilot-qt,
9195 libqt5test5,
9296 libqt5widgets5,
9397 python-evdev,
98+ python-gi,
9499 unity8 (>= ${source:Version}),
95100 unity8-fake-env (>= ${source:Version}),
96101 ${misc:Depends},
97102 ${python:Depends},
98103 ${shlibs:Depends},
99−Recommends: gir1.2-glib-2.0,
100− python-gi,
101104Description: Test package for Unity 8 shell
102105 Autopilot tests for the unity8 package
103106
@@ -119,7 +122,7 @@ Pre-Depends: ${misc:Pre-Depends},
119122Depends: ${misc:Depends},
120123 ${shlibs:Depends},
121124Provides: unity-launcher-impl,
122− unity-launcher-impl-2,
125+ unity-launcher-impl-3,
123126Description: Unity 8 private libs
124127 The Unity 8 shell is the primary user interface for Ubuntu devices.
125128 .
debian/unity8-private.install+1
@@ -3,6 +3,7 @@ usr/lib/*/unity8/qml/HudClient
33usr/lib/*/unity8/qml/LightDM
44usr/lib/*/unity8/qml/ListViewWithPageHeader
55usr/lib/*/unity8/qml/Powerd
6+usr/lib/*/unity8/qml/SessionBroadcast
67usr/lib/*/unity8/qml/Ubuntu
78usr/lib/*/unity8/qml/Unity
89usr/lib/*/unity8/qml/Utils
debian/unity8.install−1
@@ -13,4 +13,3 @@ usr/share/unity8/Panel
1313usr/share/unity8/Shell.qml
1414usr/share/unity8/SideStage
1515usr/share/unity8/graphics
16−usr/share/unity8/unity/indicators/*
main.cpp+76−9
@@ -25,13 +25,17 @@
2525#include <QtQml/QQmlContext>
2626#include <qpa/qplatformnativeinterface.h>
2727#include <QLibrary>
28+#include <QDebug>
2829#include <libintl.h>
30+#include <dlfcn.h>
2931
3032// local
3133#include "paths.h"
3234#include "MouseTouchAdaptor.h"
3335#include "ApplicationArguments.h"
3436
37+#include <unity-mir/qmirserver.h>
38+
3539namespace {
3640
3741void prependImportPaths(QQmlEngine *engine, const QStringList &paths)
@@ -65,13 +69,14 @@ void appendImportPaths(QQmlEngine *engine, const QStringList &paths)
6569
6670void resolveIconTheme() {
6771 const char *ubuntuIconTheme = getenv("UBUNTU_ICON_THEME");
68− if (ubuntuIconTheme != NULL) {
69− QIcon::setThemeName(ubuntuIconTheme);
72+ if (ubuntuIconTheme == NULL) {
73+ ubuntuIconTheme = "ubuntu-mobile";
7074 }
75+ QIcon::setThemeName(ubuntuIconTheme);
7176}
7277} // namespace {
7378
74−int main(int argc, char** argv)
79+int startShell(int argc, const char** argv, void* server)
7580{
7681 /* Workaround Qt platform integration plugin not advertising itself
7782 as having the following capabilities:
@@ -81,12 +86,29 @@ int main(int argc, char** argv)
8186 setenv("QML_FORCE_THREADED_RENDERER", "1", 1);
8287 setenv("QML_FIXED_ANIMATION_STEP", "1", 1);
8388
89+ const bool isUbuntuMirServer = qgetenv("QT_QPA_PLATFORM") == "ubuntumirserver";
90+
8491 QGuiApplication::setApplicationName("Unity 8");
85− QGuiApplication application(argc, argv);
92+ QGuiApplication *application;
93+ if (isUbuntuMirServer) {
94+ QLibrary unityMir("unity-mir", 1);
95+ unityMir.load();
96+
97+ typedef QGuiApplication* (*createServerApplication_t)(int&, const char **, void*);
98+ createServerApplication_t createQMirServerApplication = (createServerApplication_t) unityMir.resolve("createQMirServerApplication");
99+ if (!createQMirServerApplication) {
100+ qDebug() << "unable to resolve symbol: createQMirServerApplication";
101+ return 4;
102+ }
103+
104+ application = createQMirServerApplication(argc, argv, server);
105+ } else {
106+ application = new QGuiApplication(argc, (char**)argv);
107+ }
86108
87109 resolveIconTheme();
88110
89− QStringList args = application.arguments();
111+ QStringList args = application->arguments();
90112 ApplicationArguments qmlArgs(args);
91113
92114 // The testability driver is only loaded by QApplication but not by QGuiApplication.
@@ -122,8 +144,7 @@ int main(int argc, char** argv)
122144 MouseTouchAdaptor *mouseTouchAdaptor = 0;
123145 if (args.contains(QLatin1String("-mousetouch"))) {
124146 mouseTouchAdaptor = new MouseTouchAdaptor;
125− mouseTouchAdaptor->setTargetWindow(view);
126− application.installNativeEventFilter(mouseTouchAdaptor);
147+ application->installNativeEventFilter(mouseTouchAdaptor);
127148 }
128149
129150 QPlatformNativeInterface* nativeInterface = QGuiApplication::platformNativeInterface();
@@ -138,18 +159,64 @@ int main(int argc, char** argv)
138159 QUrl source("Shell.qml");
139160 prependImportPaths(view->engine(), ::overrideImportPaths());
140161 appendImportPaths(view->engine(), ::fallbackImportPaths());
162+
163+ QStringList importPath = view->engine()->importPathList().filter("qt5/imports");
164+ if (isUbuntuMirServer) {
165+ importPath.first().append("/Unity-Mir");
166+ view->engine()->addImportPath(importPath.first());
167+ }
168+
141169 view->setSource(source);
142170 view->setColor("transparent");
143171
144− if (qgetenv("QT_QPA_PLATFORM") == "ubuntu" || args.contains(QLatin1String("-fullscreen"))) {
172+ if (qgetenv("QT_QPA_PLATFORM") == "ubuntu" || isUbuntuMirServer || args.contains(QLatin1String("-fullscreen"))) {
145173 view->showFullScreen();
146174 } else {
147175 view->show();
148176 }
149177
150− int result = application.exec();
178+ int result = application->exec();
151179
152180 delete mouseTouchAdaptor;
181+ delete application;
153182
154183 return result;
155184}
185+
186+int main(int argc, const char *argv[])
187+{
188+ // For ubuntumirserver/ubuntumirclient
189+ if (qgetenv("QT_QPA_PLATFORM").startsWith("ubuntumir")) {
190+ setenv("QT_QPA_PLATFORM", "ubuntumirserver", 1);
191+
192+ // If we use unity-mir directly, we automatically link to the Mir-server
193+ // platform-api bindings, which result in unexpected behaviour when
194+ // running the non-Mir scenario.
195+ QLibrary unityMir("unity-mir", 1);
196+ unityMir.load();
197+ if (!unityMir.isLoaded()) {
198+ qDebug() << "Library unity-mir not found/loaded";
199+ return 1;
200+ }
201+
202+ typedef QMirServer* (*createServer_t)(int, const char **);
203+ createServer_t createQMirServer = (createServer_t) unityMir.resolve("createQMirServer");
204+ if (!createQMirServer) {
205+ qDebug() << "unable to resolve symbol: createQMirServer";
206+ return 2;
207+ }
208+
209+ QMirServer* mirServer = createQMirServer(argc, argv);
210+
211+ typedef int (*runWithClient_t)(QMirServer*, std::function<int(int, const char**, void*)>);
212+ runWithClient_t runWithClient = (runWithClient_t) unityMir.resolve("runQMirServerWithClient");
213+ if (!runWithClient) {
214+ qDebug() << "unable to resolve symbol: runWithClient";
215+ return 3;
216+ }
217+
218+ return runWithClient(mirServer, startShell);
219+ } else {
220+ return startShell(argc, argv, nullptr);
221+ }
222+}
plugins/AccountsService/AccountsService.cpp+67−37
@@ -17,58 +17,88 @@
1717 */
1818
1919#include "AccountsService.h"
20−#include <QDBusConnection>
21−#include <QDBusConnectionInterface>
22−#include <QDBusMessage>
23−#include <QDBusVariant>
20+#include "AccountsServiceDBusAdaptor.h"
21+
22+#include <QStringList>
2423
2524AccountsService::AccountsService(QObject* parent)
2625 : QObject(parent),
27− accounts_manager(NULL),
28− users()
26+ m_service(new AccountsServiceDBusAdaptor(this)),
27+ m_user(qgetenv("USER"))
2928{
30− auto connection = QDBusConnection::SM_BUSNAME();
31− auto interface = connection.interface();
32− interface->startService("org.freedesktop.Accounts");
33− accounts_manager = new QDBusInterface("org.freedesktop.Accounts",
34− "/org/freedesktop/Accounts",
35− "org.freedesktop.Accounts",
36− connection, this);
29+ connect(m_service, SIGNAL(propertiesChanged(const QString &, const QString &, const QStringList &)),
30+ this, SLOT(propertiesChanged(const QString &, const QString &, const QStringList &)));
31+ connect(m_service, SIGNAL(maybeChanged(const QString &)),
32+ this, SLOT(maybeChanged(const QString &)));
3733}
3834
39−QVariant AccountsService::getUserProperty(const QString &user, const QString &property)
35+QString AccountsService::user() const
4036{
41− auto iface = getUserInterface(user);
42− if (iface != nullptr && iface->isValid()) {
43− auto answer = iface->call("Get", "com.canonical.unity.AccountsService", property);
44− if (answer.type() == QDBusMessage::ReplyMessage) {
45− return answer.arguments()[0].value<QDBusVariant>().variant();
46− }
37+ return m_user;
38+}
39+
40+void AccountsService::setUser(const QString &user)
41+{
42+ m_user = user;
43+ Q_EMIT userChanged();
44+
45+ updateDemoEdges();
46+ updateBackgroundFile();
47+}
48+
49+bool AccountsService::demoEdges() const
50+{
51+ return m_demoEdges;
52+}
53+
54+void AccountsService::setDemoEdges(bool demoEdges)
55+{
56+ m_demoEdges = demoEdges;
57+ m_service->setUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges", demoEdges);
58+}
59+
60+QString AccountsService::backgroundFile() const
61+{
62+ return m_backgroundFile;
63+}
64+
65+void AccountsService::updateDemoEdges()
66+{
67+ auto demoEdges = m_service->getUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges").toBool();
68+ if (m_demoEdges != demoEdges) {
69+ m_demoEdges = demoEdges;
70+ Q_EMIT demoEdgesChanged();
4771 }
48− return QVariant();
4972}
5073
51−void AccountsService::setUserProperty(const QString &user, const QString &property, const QVariant &value)
74+void AccountsService::updateBackgroundFile()
5275{
53− auto iface = getUserInterface(user);
54− if (iface != nullptr && iface->isValid()) {
55− // The value needs to be carefully wrapped
56− iface->call("Set", "com.canonical.unity.AccountsService", property, QVariant::fromValue(QDBusVariant(value)));
76+ auto backgroundFile = m_service->getUserProperty(m_user, "org.freedesktop.Accounts.User", "BackgroundFile").toString();
77+ if (m_backgroundFile != backgroundFile) {
78+ m_backgroundFile = backgroundFile;
79+ Q_EMIT backgroundFileChanged();
5780 }
5881}
5982
60−QDBusInterface *AccountsService::getUserInterface(const QString &user)
83+void AccountsService::propertiesChanged(const QString &user, const QString &interface, const QStringList &changed)
6184{
62− auto iface = users.value(user);
63− if (iface == nullptr && accounts_manager->isValid()) {
64− auto answer = accounts_manager->call("FindUserByName", user);
65− if (answer.type() == QDBusMessage::ReplyMessage) {
66− iface = new QDBusInterface("org.freedesktop.Accounts",
67− answer.arguments()[0].value<QDBusObjectPath>().path(),
68− "org.freedesktop.DBus.Properties",
69− accounts_manager->connection(), this);
70− users.insert(user, iface);
85+ if (m_user != user) {
86+ return;
87+ }
88+
89+ if (interface == "com.canonical.unity.AccountsService") {
90+ if (changed.contains("demo-edges")) {
91+ updateDemoEdges();
7192 }
7293 }
73− return iface;
94+}
95+
96+void AccountsService::maybeChanged(const QString &user)
97+{
98+ if (m_user != user) {
99+ return;
100+ }
101+
102+ // Standard properties might have changed
103+ updateBackgroundFile();
74104}
plugins/AccountsService/AccountsService.h+34−8
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2012,2013 Canonical, Ltd.
2+ * Copyright (C) 2013 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -19,26 +19,52 @@
1919#ifndef UNITY_ACCOUNTSSERVICE_H
2020#define UNITY_ACCOUNTSSERVICE_H
2121
22−#include <QDBusInterface>
23−#include <QMap>
2422#include <QObject>
2523#include <QString>
2624
25+class AccountsServiceDBusAdaptor;
26+
2727class AccountsService: public QObject
2828{
2929 Q_OBJECT
30+ Q_PROPERTY (QString user
31+ READ user
32+ WRITE setUser
33+ NOTIFY userChanged)
34+ Q_PROPERTY (bool demoEdges
35+ READ demoEdges
36+ WRITE setDemoEdges
37+ NOTIFY demoEdgesChanged)
38+ Q_PROPERTY (QString backgroundFile
39+ READ backgroundFile
40+ NOTIFY backgroundFileChanged)
3041
3142public:
3243 explicit AccountsService(QObject *parent = 0);
3344
34− Q_INVOKABLE QVariant getUserProperty(const QString &user, const QString &property);
35− Q_INVOKABLE void setUserProperty(const QString &user, const QString &property, const QVariant &value);
45+ QString user() const;
46+ void setUser(const QString &user);
47+ bool demoEdges() const;
48+ void setDemoEdges(bool demoEdges);
49+ QString backgroundFile() const;
50+
51+Q_SIGNALS:
52+ void userChanged();
53+ void demoEdgesChanged();
54+ void backgroundFileChanged();
55+
56+private Q_SLOTS:
57+ void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
58+ void maybeChanged(const QString &user);
3659
3760private:
38− QDBusInterface *getUserInterface(const QString &user);
61+ void updateDemoEdges();
62+ void updateBackgroundFile();
3963
40− QDBusInterface *accounts_manager;
41− QMap<QString, QDBusInterface *> users;
64+ AccountsServiceDBusAdaptor *m_service;
65+ QString m_user;
66+ bool m_demoEdges;
67+ QString m_backgroundFile;
4268};
4369
4470#endif
plugins/AccountsService/AccountsServiceDBusAdaptor.cppnew file+126
@@ -0,0 +1,126 @@
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+ * Author: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#include "AccountsServiceDBusAdaptor.h"
20+#include <QDBusConnection>
21+#include <QDBusConnectionInterface>
22+#include <QDBusMessage>
23+#include <QDBusVariant>
24+
25+AccountsServiceDBusAdaptor::AccountsServiceDBusAdaptor(QObject* parent)
26+ : QObject(parent),
27+ m_accountsManager(NULL),
28+ m_users()
29+{
30+ QDBusConnection connection = QDBusConnection::SM_BUSNAME();
31+ QDBusConnectionInterface *interface = connection.interface();
32+ interface->startService("org.freedesktop.Accounts");
33+ m_accountsManager = new QDBusInterface("org.freedesktop.Accounts",
34+ "/org/freedesktop/Accounts",
35+ "org.freedesktop.Accounts",
36+ connection, this);
37+}
38+
39+QVariant AccountsServiceDBusAdaptor::getUserProperty(const QString &user, const QString &interface, const QString &property)
40+{
41+ QDBusInterface *iface = getUserInterface(user);
42+ if (iface != nullptr && iface->isValid()) {
43+ QDBusMessage answer = iface->call("Get", interface, property);
44+ if (answer.type() == QDBusMessage::ReplyMessage) {
45+ return answer.arguments()[0].value<QDBusVariant>().variant();
46+ }
47+ }
48+ return QVariant();
49+}
50+
51+void AccountsServiceDBusAdaptor::setUserProperty(const QString &user, const QString &interface, const QString &property, const QVariant &value)
52+{
53+ QDBusInterface *iface = getUserInterface(user);
54+ if (iface != nullptr && iface->isValid()) {
55+ // The value needs to be carefully wrapped
56+ iface->call("Set", interface, property, QVariant::fromValue(QDBusVariant(value)));
57+ }
58+}
59+
60+void AccountsServiceDBusAdaptor::propertiesChangedSlot(const QString &interface, const QVariantMap &changed, const QStringList &invalid)
61+{
62+ // Merge changed and invalidated together
63+ QStringList combined;
64+ combined << invalid;
65+ combined << changed.keys();
66+ combined.removeDuplicates();
67+
68+ Q_EMIT propertiesChanged(getUserForPath(message().path()), interface, combined);
69+}
70+
71+void AccountsServiceDBusAdaptor::maybeChangedSlot()
72+{
73+ Q_EMIT maybeChanged(getUserForPath(message().path()));
74+}
75+
76+QString AccountsServiceDBusAdaptor::getUserForPath(const QString &path)
77+{
78+ QMap<QString, QDBusInterface *>::const_iterator i;
79+ for (i = m_users.constBegin(); i != m_users.constEnd(); ++i) {
80+ if (i.value()->path() == path) {
81+ return i.key();
82+ }
83+ }
84+ return QString();
85+}
86+
87+QDBusInterface *AccountsServiceDBusAdaptor::getUserInterface(const QString &user)
88+{
89+ QDBusInterface *iface = m_users.value(user);
90+ if (iface == nullptr && m_accountsManager->isValid()) {
91+ QDBusMessage answer = m_accountsManager->call("FindUserByName", user);
92+ if (answer.type() == QDBusMessage::ReplyMessage) {
93+ QString path = answer.arguments()[0].value<QDBusObjectPath>().path();
94+
95+ iface = new QDBusInterface("org.freedesktop.Accounts",
96+ path,
97+ "org.freedesktop.DBus.Properties",
98+ m_accountsManager->connection(), this);
99+
100+ // With its own pre-defined properties, AccountsService is oddly
101+ // close-lipped. It won't send out proper DBus.Properties notices,
102+ // but it does have one catch-all Changed() signal. So let's
103+ // listen to that.
104+ iface->connection().connect(
105+ iface->service(),
106+ path,
107+ "org.freedesktop.Accounts.User",
108+ "Changed",
109+ this,
110+ SLOT(maybeChangedSlot()));
111+
112+ // But custom properties do send out the right notifications, so
113+ // let's still listen there.
114+ iface->connection().connect(
115+ iface->service(),
116+ path,
117+ "org.freedesktop.DBus.Properties",
118+ "PropertiesChanged",
119+ this,
120+ SLOT(propertiesChangedSlot(QString, QVariantMap, QStringList)));
121+
122+ m_users.insert(user, iface);
123+ }
124+ }
125+ return iface;
126+}
plugins/AccountsService/AccountsServiceDBusAdaptor.hnew file+54
@@ -0,0 +1,54 @@
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: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#ifndef UNITY_ACCOUNTSSERVICEDBUSADAPTOR_H
20+#define UNITY_ACCOUNTSSERVICEDBUSADAPTOR_H
21+
22+#include <QDBusContext>
23+#include <QDBusInterface>
24+#include <QMap>
25+#include <QObject>
26+#include <QString>
27+
28+class AccountsServiceDBusAdaptor: public QObject, public QDBusContext
29+{
30+ Q_OBJECT
31+
32+public:
33+ explicit AccountsServiceDBusAdaptor(QObject *parent = 0);
34+
35+ Q_INVOKABLE QVariant getUserProperty(const QString &user, const QString &interface, const QString &property);
36+ Q_INVOKABLE void setUserProperty(const QString &user, const QString &interface, const QString &property, const QVariant &value);
37+
38+Q_SIGNALS:
39+ void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
40+ void maybeChanged(const QString &user); // Standard properties might have changed
41+
42+private Q_SLOTS:
43+ void propertiesChangedSlot(const QString &interface, const QVariantMap &changed, const QStringList &invalid);
44+ void maybeChangedSlot();
45+
46+private:
47+ QDBusInterface *getUserInterface(const QString &user);
48+ QString getUserForPath(const QString &path);
49+
50+ QDBusInterface *m_accountsManager;
51+ QMap<QString, QDBusInterface *> m_users;
52+};
53+
54+#endif
plugins/AccountsService/CMakeLists.txt+1
@@ -4,6 +4,7 @@ add_definitions(-DSM_BUSNAME=systemBus)
44
55add_library(AccountsService-qml MODULE
66 AccountsService.cpp
7+ AccountsServiceDBusAdaptor.cpp
78 plugin.cpp
89 )
910
plugins/AccountsService/com.canonical.unity.AccountsService.xml+7
@@ -6,6 +6,9 @@
66 <annotation name="org.freedesktop.Accounts.Authentication.ChangeOwn"
77 value="com.canonical.unity.AccountsService.ModifyOwnUser"/>
88
9+ <annotation name="org.freedesktop.Accounts.Authentication.ReadAny"
10+ value="com.canonical.unity.AccountsService.ModifyAnyUser"/>
11+
912 <annotation name="org.freedesktop.Accounts.Authentication.ChangeAny"
1013 value="com.canonical.unity.AccountsService.ModifyAnyUser"/>
1114
@@ -13,5 +16,9 @@
1316 <annotation name="org.freedesktop.Accounts.DefaultValue" value="true"/>
1417 </property>
1518
19+ <property name="launcher-items" type="aa{sv}" access="readwrite">
20+ <annotation name="org.freedesktop.Accounts.DefaultValue" value="[{'defaults': <true>}]"/>
21+ </property>
22+
1623 </interface>
1724</node>
plugins/AccountsService/plugin.cpp+2
@@ -19,6 +19,7 @@
1919#include "plugin.h"
2020#include "AccountsService.h"
2121
22+#include <QDBusMetaType>
2223#include <QtQml>
2324
2425static QObject *service_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
@@ -31,5 +32,6 @@ static QObject *service_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
3132void AccountsServicePlugin::registerTypes(const char *uri)
3233{
3334 Q_ASSERT(uri == QLatin1String("AccountsService"));
35+ qDBusRegisterMetaType<QList<QVariantMap>>();
3436 qmlRegisterSingletonType<AccountsService>(uri, 0, 1, "AccountsService", service_provider);
3537}
plugins/CMakeLists.txt+1
@@ -3,6 +3,7 @@ add_subdirectory(HudClient)
33add_subdirectory(LightDM)
44add_subdirectory(ListViewWithPageHeader)
55add_subdirectory(Powerd)
6+add_subdirectory(SessionBroadcast)
67add_subdirectory(Ubuntu)
78add_subdirectory(Unity)
89add_subdirectory(Utils)
plugins/ListViewWithPageHeader/listviewwithpageheader.cpp+20−1
@@ -170,6 +170,8 @@ ListViewWithPageHeader::ListViewWithPageHeader()
170170 connect(this, SIGNAL(contentHeightChanged()), this, SLOT(onContentHeightChanged()));
171171 connect(this, SIGNAL(heightChanged()), this, SLOT(onHeightChanged()));
172172 connect(m_contentYAnimation, SIGNAL(stopped()), this, SLOT(onShowHeaderAnimationFinished()));
173+
174+ setFlickableDirection(VerticalFlick);
173175}
174176
175177ListViewWithPageHeader::~ListViewWithPageHeader()
@@ -199,6 +201,7 @@ void ListViewWithPageHeader::setModel(QAbstractItemModel *model)
199201 connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
200202#endif
201203 Q_EMIT modelChanged();
204+ polish();
202205 // TODO?
203206// Q_EMIT contentHeightChanged();
204207// Q_EMIT contentYChanged();
@@ -482,7 +485,7 @@ void ListViewWithPageHeader::viewportMoved(Qt::Orientations orient)
482485 // or the header is partially shown and we are not doing a maximizeVisibleArea either
483486 const bool scrolledUp = m_previousContentY > contentY();
484487 const bool notRebounding = contentY() + height() < contentHeight();
485− const bool notShownByItsOwn = contentY() + diff > m_headerItem->y() + m_headerItem->height();
488+ const bool notShownByItsOwn = contentY() + diff >= m_headerItem->y() + m_headerItem->height();
486489 const bool maximizeVisibleAreaRunning = m_contentYAnimation->isRunning() && contentYAnimationType == ContentYAnimationMaximizeVisibleArea;
487490
488491 if (!scrolledUp && contentY() == -m_minYExtent) {
@@ -1006,6 +1009,22 @@ void ListViewWithPageHeader::onModelUpdated(const QQmlChangeSet &changeSet, bool
10061009 }
10071010 }
10081011
1012+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
1013+ Q_FOREACH(const QQuickChangeSet::Change &change, changeSet.changes()) {
1014+#else
1015+ Q_FOREACH(const QQmlChangeSet::Change &change, changeSet.changes()) {
1016+#endif
1017+// qDebug() << "ListViewWithPageHeader::onModelUpdated Change" << change.index << change.count;
1018+ for (int i = change.index; i < change.count; ++i) {
1019+ ListItem *item = itemAtIndex(i);
1020+ if (item && item->m_sectionItem) {
1021+ QQmlContext *context = QQmlEngine::contextForObject(item->m_sectionItem)->parentContext();
1022+ const QString sectionText = m_delegateModel->stringValue(i, m_sectionProperty);
1023+ context->setContextProperty(QLatin1String("section"), sectionText);
1024+ }
1025+ }
1026+ }
1027+
10091028 if (m_firstVisibleIndex != oldFirstVisibleIndex) {
10101029 adjustMinYExtent();
10111030 }
plugins/ListViewWithPageHeader/listviewwithpageheader.h+1
@@ -63,6 +63,7 @@ class ListViewWithPageHeader : public QQuickFlickable, public QQuickItemChangeLi
6363
6464 friend class ListViewWithPageHeaderTest;
6565 friend class ListViewWithPageHeaderTestSection;
66+ friend class ListViewWithPageHeaderTestExternalModel;
6667
6768public:
6869 ListViewWithPageHeader();
plugins/SessionBroadcast/CMakeLists.txtnew file+13
@@ -0,0 +1,13 @@
1+include(Plugins)
2+
3+add_definitions(-DSM_BUSNAME=systemBus)
4+
5+add_library(SessionBroadcast-qml MODULE
6+ SessionBroadcast.cpp
7+ plugin.cpp
8+ )
9+
10+qt5_use_modules(SessionBroadcast-qml DBus Qml)
11+
12+export_qmlfiles(SessionBroadcast SessionBroadcast)
13+export_qmlplugin(SessionBroadcast 0.1 SessionBroadcast TARGETS SessionBroadcast-qml)
plugins/SessionBroadcast/SessionBroadcast.cppnew file+41
@@ -0,0 +1,41 @@
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+ * Author: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#include "SessionBroadcast.h"
20+#include <QDBusConnection>
21+
22+SessionBroadcast::SessionBroadcast(QObject* parent)
23+ : QObject(parent)
24+{
25+ auto connection = QDBusConnection::SM_BUSNAME();
26+
27+ connection.connect("com.canonical.Unity.Greeter.Broadcast",
28+ "/com/canonical/Unity/Greeter/Broadcast",
29+ "com.canonical.Unity.Greeter.Broadcast",
30+ "ShowHome",
31+ this,
32+ SLOT(onShowHome(const QString &)));
33+}
34+
35+void SessionBroadcast::onShowHome(const QString &username)
36+{
37+ // Only listen to requests meant for us
38+ if (username == qgetenv("USER")) {
39+ Q_EMIT showHome();
40+ }
41+}
plugins/SessionBroadcast/SessionBroadcast.hnew file+41
@@ -0,0 +1,41 @@
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: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#ifndef UNITY_SESSIONBROADCAST_H
20+#define UNITY_SESSIONBROADCAST_H
21+
22+#include <QObject>
23+#include <QString>
24+
25+class QDBusInterface;
26+
27+class SessionBroadcast: public QObject
28+{
29+ Q_OBJECT
30+
31+public:
32+ explicit SessionBroadcast(QObject *parent = 0);
33+
34+Q_SIGNALS:
35+ void showHome();
36+
37+private Q_SLOTS:
38+ void onShowHome(const QString &username);
39+};
40+
41+#endif
plugins/SessionBroadcast/plugin.cppnew 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: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#include "plugin.h"
20+#include "SessionBroadcast.h"
21+
22+#include <QtQml>
23+
24+static QObject *broadcast_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
25+{
26+ Q_UNUSED(engine)
27+ Q_UNUSED(scriptEngine)
28+ return new SessionBroadcast();
29+}
30+
31+void SessionBroadcastPlugin::registerTypes(const char *uri)
32+{
33+ Q_ASSERT(uri == QLatin1String("SessionBroadcast"));
34+ qmlRegisterSingletonType<SessionBroadcast>(uri, 0, 1, "SessionBroadcast", broadcast_provider);
35+}
plugins/SessionBroadcast/plugin.hnew file+33
@@ -0,0 +1,33 @@
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: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#ifndef UNITY_SESSIONBROADCAST_PLUGIN_H
20+#define UNITY_SESSIONBROADCAST_PLUGIN_H
21+
22+#include <QQmlExtensionPlugin>
23+
24+class SessionBroadcastPlugin : public QQmlExtensionPlugin
25+{
26+ Q_OBJECT
27+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28+
29+public:
30+ void registerTypes(const char *uri);
31+};
32+
33+#endif
plugins/SessionBroadcast/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module SessionBroadcast
2+plugin SessionBroadcast-qml
3+typeinfo plugin.qmltypes
plugins/Unity/CMakeLists.txt+3
@@ -43,9 +43,12 @@ set(QMLPLUGIN_SRC
4343 preview.cpp
4444 previewaction.cpp
4545 previewinfohint.cpp
46+ result.cpp
47+ showallfilteroption.cpp
4648 signalslist.cpp
4749 socialpreview.cpp
4850 socialpreviewcomment.cpp
51+ iconutils.cpp
4952 variantutils.cpp
5053)
5154
plugins/Unity/Indicators/CMakeLists.txt+10
@@ -12,6 +12,7 @@ find_package(Qt5Core REQUIRED)
1212find_package(Qt5Quick REQUIRED)
1313
1414add_subdirectory(qml)
15+add_subdirectory(Messaging)
1516add_subdirectory(Network)
1617
1718include_directories(
@@ -34,11 +35,20 @@ set(IndicatorsQML_SOURCES
3435 rootactionstate.cpp
3536 unitymenumodelcache.cpp
3637 unitymenumodelstack.cpp
38+ visibleindicatorsmodel.cpp
3739)
3840add_definitions(-DUNITYINDICATORS_LIBRARY)
3941
42+set(IndicatorsQML_RESOURCES
43+ resources/indicators.qrc
44+)
45+
46+qt5_add_resources(IndicatorsQML_RESOURCES_RCC
47+ ${IndicatorsQML_RESOURCES}
48+)
4049
4150add_library(IndicatorsQml SHARED
51+ ${IndicatorsQML_RESOURCES_RCC}
4252 ${IndicatorsQML_SOURCES}
4353)
4454
plugins/Unity/IndicatorsLegacy/Messaging/CMakeLists.txt → plugins/Unity/Indicators/Messaging/CMakeLists.txtrenamed

The content is the same.

plugins/Unity/IndicatorsLegacy/Messaging/qml/ActionButton.qml → plugins/Unity/Indicators/Messaging/qml/ActionButton.qmlrenamed

The content is the same.

plugins/Unity/IndicatorsLegacy/Messaging/qml/ActionTextField.qml → plugins/Unity/Indicators/Messaging/qml/ActionTextField.qmlrenamed+10−7
@@ -22,11 +22,12 @@ import QtQuick 2.0
2222import Ubuntu.Components 0.1
2323
2424Item {
25− property alias actionGroup: sendButton.actionGroup
26− property alias action: sendButton.action
27−
25+ id: textField
2826 property alias text: replyField.text
2927 property alias buttonText: sendButton.text
28+ property bool activateEnabled: false
29+
30+ signal activate(var value)
3031
3132 TextField {
3233 id: replyField
@@ -50,17 +51,19 @@ Item {
5051 }
5152 }
5253
53− ActionButton {
54+ Button {
5455 id: sendButton
55−
56− actionParameter: replyField.text
5756 anchors {
5857 top: parent.top
5958 bottom: parent.bottom
6059 right: parent.right
6160 }
6261 width: units.gu(9)
63− enabled: replyField.text !== ""
62+ enabled: replyField.text !== "" && textField.activateEnabled
6463 color: enabled ? "#c94212" : "#bababa"
64+
65+ onClicked: {
66+ textField.activate(replyField.text);
67+ }
6568 }
6669}
plugins/Unity/Indicators/Messaging/qml/CMakeLists.txtnew file+5
@@ -0,0 +1,5 @@
1+# export_qmlfiles macro
2+include(Plugins)
3+
4+# export the qmldir, *.qml files.
5+export_qmlfiles(Unity.Indicators.Messaging Unity/Indicators/Messaging)
plugins/Unity/IndicatorsLegacy/Messaging/qml/GroupedMessage.qml → plugins/Unity/Indicators/Messaging/qml/GroupedMessage.qmlrenamed+13−18
@@ -20,20 +20,19 @@
2020
2121import QtQuick 2.0
2222import Ubuntu.Components 0.1
23−import Unity.IndicatorsLegacy 0.1 as Indicators
23+import Unity.Indicators 0.1 as Indicators
2424
25−Indicators.BasicMenuItem {
25+Indicators.BaseMenuItem {
2626 id: groupedMessage
27+
28+ property alias title: __title.text
2729 property alias count: label.text
30+ property string appIcon: "qrc:/indicators/artwork/messaging/default_app.svg"
2831
29− color: "#221e1b"
30− implicitHeight: units.gu(10)
32+ signal activateApp()
33+ signal dismiss()
3134
32− Indicators.MenuAction {
33− id: menuAction
34− actionGroup: groupedMessage.actionGroup
35− action: menu ? menu.action : ""
36− }
35+ implicitHeight: units.gu(10)
3736
3837 Row {
3938 anchors.fill: parent
@@ -44,17 +43,17 @@ Indicators.BasicMenuItem {
4443 height: units.gu(6)
4544 width: units.gu(6)
4645 image: Image {
47− source: menu && (menu.extra.canonical_icon.length > 0) ? "image://gicon/" + encodeURI(menu.extra.canonical_icon) : "qrc:/indicators/artwork/messaging/default_app.svg"
46+ source: groupedMessage.appIcon
4847 fillMode: Image.PreserveAspectFit
4948 }
5049 }
5150
5251 Label {
52+ id: __title
5353 anchors.verticalCenter: parent.verticalCenter
5454 color: "#e8e1d0"
5555 font.weight: Font.DemiBold
5656 fontSize: "medium"
57− text: menu && menu.label ? menu.label : ""
5857 }
5958
6059 Label {
@@ -65,7 +64,7 @@ Indicators.BasicMenuItem {
6564 color: "#e8e1d0"
6665 font.weight: Font.DemiBold
6766 fontSize: "medium"
68− text: menuAction.valid ? menuAction.state[0] : "0"
67+ text: "0"
6968 }
7069 }
7170
@@ -82,15 +81,11 @@ Indicators.BasicMenuItem {
8281 MouseArea {
8382 anchors.fill: parent
8483 onClicked: {
85− if (menuAction.valid) {
86− menuAction.activate(true);
87− }
84+ groupedMessage.activateApp();
8885 }
8986 }
9087
9188 onItemRemoved: {
92− if (menuAction.valid) {
93− menuAction.activate(false);
94− }
89+ groupedMessage.dismiss();
9590 }
9691}
plugins/Unity/IndicatorsLegacy/Messaging/qml/HeroMessage.qml → plugins/Unity/Indicators/Messaging/qml/HeroMessage.qmlrenamed+25−22
@@ -20,25 +20,30 @@
2020
2121import QtQuick 2.0
2222import Ubuntu.Components 0.1
23−import Unity.IndicatorsLegacy 0.1 as Indicators
23+import Unity.Indicators 0.1 as Indicators
2424
25−Indicators.BasicMenuItem {
25+Indicators.BaseMenuItem {
2626 id: heroMessage
2727
28− property variant actionsDescription: null
2928 property alias heroMessageHeader: __heroMessageHeader
3029 property real collapsedHeight: heroMessageHeader.y + heroMessageHeader.bodyBottom + units.gu(2)
3130 property real expandedHeight: collapsedHeight
3231
33− color: "#221e1c"
32+ property alias avatar: __heroMessageHeader.avatar
33+ property alias appIcon: __heroMessageHeader.icon
34+
35+ signal activateApp
36+ signal dismiss
3437
3538 removable: state !== "expanded"
3639 implicitHeight: collapsedHeight
3740
38− Indicators.MenuAction {
39− id: menuAction
40− actionGroup: heroMessage.actionGroup
41− action: menu ? menu.action : ""
41+ Rectangle {
42+ id: background
43+ property real alpha: 0.0
44+ anchors.fill: parent
45+ color: Qt.rgba(1.0, 1.0, 1.0, alpha)
46+ z: -1
4247 }
4348
4449 HeroMessageHeader {
@@ -48,25 +53,22 @@ Indicators.BasicMenuItem {
4853 anchors.left: parent.left
4954 anchors.right: parent.right
5055
51− avatar: menu && (menu.extra.canonical_icon.length > 0) ? "image://gicon/" + encodeURI(menu.extra.canonical_icon) : "qrc:/indicators/artwork/messaging/default_contact.png"
52− icon: menu && (menu.extra.canonical_app_icon.length > 0) ? "image://gicon/" + encodeURI(menu.extra.canonical_app_icon) : ""
56+ avatar: "qrc:/indicators/artwork/messaging/default_contact.png"
5357 appIcon: icon
5458
5559 state: heroMessage.state
5660
5761 onAppIconClicked: {
58− if (menuAction.valid) {
59− deactivateMenu();
60− action.activate(true);
61− }
62+ deselectMenu();
63+ heroMessage.activateApp();
6264 }
6365 }
6466
6567 onClicked: {
66− if (menuActivated) {
67− deactivateMenu();
68+ if (menuSelected) {
69+ deselectMenu();
6870 } else {
69− activateMenu();
71+ selectMenu();
7072 }
7173 }
7274
@@ -84,13 +86,16 @@ Indicators.BasicMenuItem {
8486
8587 states: State {
8688 name: "expanded"
87− when: menuActivated
89+ when: menuSelected
8890
8991 PropertyChanges {
9092 target: heroMessage
91− color: "#333130"
9293 implicitHeight: heroMessage.expandedHeight
9394 }
95+ PropertyChanges {
96+ target: background
97+ alpha: 0.05
98+ }
9499 PropertyChanges {
95100 target: __topHLine
96101 opacity: 0.0
@@ -113,8 +118,6 @@ Indicators.BasicMenuItem {
113118 }
114119
115120 onItemRemoved: {
116− if (menuAction.valid) {
117− menuAction.activate(false);
118− }
121+ heroMessage.dismiss();
119122 }
120123}
plugins/Unity/IndicatorsLegacy/Messaging/qml/HeroMessageHeader.qml → plugins/Unity/Indicators/Messaging/qml/HeroMessageHeader.qmlrenamed

The content is the same.

plugins/Unity/Indicators/Messaging/qml/MessageMenuItemFactory.qmlnew file+180
@@ -0,0 +1,180 @@
1+/*
2+ * Copyright 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 Lesser 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 Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Renato Araujo Oliveira Filho <renato@canonical.com>
18+ * Olivier Tilloy <olivier.tilloy@canonical.com>
19+ */
20+
21+import QtQuick 2.0
22+import Ubuntu.Components 0.1
23+import Unity.Indicators 0.1 as Indicators
24+import QMenuModel 0.1 as QMenuModel
25+import "utils.js" as Utils
26+
27+Indicators.BaseMenuItem {
28+ id: menuItem
29+ property var actionsDescription: menu ? menu.ext.xCanonicalMessageActions : undefined
30+
31+ implicitHeight: contents.status == Loader.Ready ? contents.item.implicitHeight : 0
32+
33+ property var model: null
34+
35+ Loader {
36+ id: contents
37+ anchors.fill: parent
38+
39+ sourceComponent: loadMessage(actionsDescription);
40+
41+ // Binding all properties for the item, to make sure that any change in the
42+ // property will be propagated to the contents.item at any time
43+ Binding {
44+ target: contents.item
45+ property: "menuSelected"
46+ value: menuSelected
47+ when: (contents.status == Loader.Ready)
48+ }
49+
50+ Binding {
51+ target: contents.item
52+ property: "menu"
53+ value: menu
54+ when: (contents.status == Loader.Ready)
55+ }
56+
57+ Connections {
58+ target: contents.item ? contents.item : null
59+ onSelectMenu: selectMenu()
60+ onDeselectMenu: deselectMenu()
61+ }
62+
63+ Component {
64+ id: simpleTextMessage
65+ SimpleTextMessage {
66+ // text
67+ title: menu && menu.label ? menu.label : ""
68+ time: menu ? Utils.formatDate(menu.ext.xCanonicalTime) : ""
69+ message: menu && menu.ext.xCanonicalText ? menu.ext.xCanonicalText : ""
70+ // icons
71+ avatar: menu && menu.ext.icon !== undefined ? menu.ext.icon : "qrc:/indicators/artwork/messaging/default_contact.png"
72+ appIcon: menu && menu.ext.xCanonicalAppIcon !== undefined ? menu.ext.xCanonicalAppIcon : "qrc:/indicators/artwork/messaging/default_app.svg"
73+
74+ onActivateApp: {
75+ menuItem.model.activate(modelIndex, true);
76+ }
77+ onDismiss: {
78+ menuItem.model.activate(modelIndex, false);
79+ }
80+ }
81+ }
82+ Component {
83+ id: textMessage
84+ TextMessage {
85+ property var replyAction: QMenuModel.UnityMenuAction {
86+ model: menuItem.model
87+ index: modelIndex
88+ name: menu && actionsDescription[0].name ? actionsDescription[0].name : ""
89+ }
90+
91+ // text
92+ title: menu && menu.label ? menu.label : ""
93+ time: menu ? Utils.formatDate(menu.ext.xCanonicalTime) : ""
94+ message: menu && menu.ext.xCanonicalText ? menu.ext.xCanonicalText : ""
95+ replyButtonText: actionsDescription && actionsDescription[0].label ? actionsDescription[0].label : "Send"
96+ // icons
97+ avatar: menu && menu.ext.icon !== undefined ? menu.ext.icon : "qrc:/indicators/artwork/messaging/default_contact.png"
98+ appIcon: menu && menu.ext.xCanonicalAppIcon !== undefined ? menu.ext.xCanonicalAppIcon : "qrc:/indicators/artwork/messaging/default_app.svg"
99+ // actions
100+ replyEnabled: replyAction.valid && replyAction.enabled
101+
102+ onActivateApp: {
103+ menuItem.model.activate(modelIndex, true);
104+ }
105+ onDismiss: {
106+ menuItem.model.activate(modelIndex, false);
107+ }
108+ onReply: {
109+ replyAction.activate(value);
110+ }
111+ }
112+ }
113+ Component {
114+ id: snapDecision
115+ SnapDecision {
116+ property var activateAction: QMenuModel.UnityMenuAction {
117+ model: menuItem.model
118+ index: modelIndex
119+ name: menu && actionsDescription[0].name ? actionsDescription[0].name : ""
120+ }
121+ property var replyAction: QMenuModel.UnityMenuAction {
122+ model: menuItem.model
123+ index: modelIndex
124+ name: menu && actionsDescription[1].name ? actionsDescription[1].name : ""
125+ }
126+
127+ // text
128+ title: menu && menu.label ? menu.label : ""
129+ time: menu ? Utils.formatDate(menu.ext.xCanonicalTime) : ""
130+ message: menu && menu.ext.xCanonicalText ? menu.ext.xCanonicalText : ""
131+ actionButtonText: actionsDescription && actionsDescription[0].label ? actionsDescription[0].label : "Call back"
132+ replyButtonText: actionsDescription && actionsDescription[1].label ? actionsDescription[1].label : "Send"
133+ replyMessages: actionsDescription && actionsDescription[1]["parameter-hint"] ? actionsDescription[1]["parameter-hint"] : ""
134+ // icons
135+ avatar: menu && menu.ext.icon !== undefined ? menu.ext.icon : "qrc:/indicators/artwork/messaging/default_contact.png"
136+ appIcon: menu && menu.ext.xCanonicalAppIcon !== undefined ? menu.ext.xCanonicalAppIcon : "qrc:/indicators/artwork/messaging/default_app.svg"
137+ // actions
138+ activateEnabled: activateAction.valid && activateAction.enabled
139+ replyEnabled: replyAction.valid && replyAction.enabled
140+
141+ onActivateApp: {
142+ menuItem.model.activate(modelIndex, true);
143+ }
144+ onDismiss: {
145+ menuItem.model.activate(modelIndex, false);
146+ }
147+ onActivate: {
148+ activateAction.activate();
149+ }
150+ onReply: {
151+ replyAction.activate(value);
152+ }
153+ }
154+ }
155+ }
156+
157+ function loadMessage(actions)
158+ {
159+ var parameterType = ""
160+ for (var actIndex in actions) {
161+ var desc = actions[actIndex];
162+ if (desc["parameter-type"] !== undefined) {
163+ parameterType += desc["parameter-type"];
164+ } else {
165+ parameterType += "_";
166+ }
167+ }
168+
169+ if (parameterType === "") {
170+ return simpleTextMessage;
171+ } else if (parameterType === "s") {
172+ return textMessage;
173+ } else if (parameterType === "_s") {
174+ return snapDecision;
175+ } else {
176+ console.debug("Unknown paramater type: " + parameterType);
177+ }
178+ return undefined;
179+ }
180+}
plugins/Unity/IndicatorsLegacy/Messaging/qml/QuickReply.qml → plugins/Unity/Indicators/Messaging/qml/QuickReply.qmlrenamed+10−5
@@ -23,12 +23,13 @@ import Ubuntu.Components 0.1
2323import Unity.IndicatorsLegacy 0.1 as Indicators
2424
2525Item {
26− property alias actionGroup: actionTextField.actionGroup
27− property alias action: actionTextField.action
28−
26+ id: quickReply
2927 property alias buttonText: actionTextField.buttonText
3028 property real expandedHeight: childrenRect.height
3129 property alias messages : messagelistRepeater.model
30+ property alias replyEnabled: actionTextField.activateEnabled
31+
32+ signal reply(var value)
3233
3334 Item {
3435 id: header
@@ -83,10 +84,9 @@ Item {
8384
8485 height: childrenRect.height
8586
86− Rectangle {
87+ Item {
8788 width: messagelist.width
8889 height: units.gu(5)
89− color: "#333230"
9090
9191 Label {
9292 id: __label
@@ -150,6 +150,11 @@ Item {
150150
151151 anchors.fill: parent
152152 anchors.margins: units.gu(1)
153+ activateEnabled: replyEnabled
154+
155+ onActivate: {
156+ quickReply.reply(value)
157+ }
153158 }
154159
155160 Indicators.HLine {
plugins/Unity/IndicatorsLegacy/Messaging/qml/SimpleTextMessage.qml → plugins/Unity/Indicators/Messaging/qml/SimpleTextMessage.qmlrenamed+7−4
@@ -20,17 +20,20 @@
2020
2121import QtQuick 2.0
2222import Ubuntu.Components 0.1
23−import "utils.js" as Utils
2423
2524HeroMessage {
2625 id: __heroMessage
2726
27+ property string title: ""
28+ property string time: ""
29+ property string message: ""
30+
2831 property alias footer: footerLoader.sourceComponent
2932
3033 expandedHeight: fullMessage.y + fullMessage.height + units.gu(2)
31− heroMessageHeader.titleText.text: menu ? menu.label : ""
32− heroMessageHeader.subtitleText.text: menu ? Utils.formatDate(menu.extra.canonical_time) : ""
33− heroMessageHeader.bodyText.text: menu ? menu.extra.canonical_text : ""
34+ heroMessageHeader.titleText.text: title
35+ heroMessageHeader.subtitleText.text: time
36+ heroMessageHeader.bodyText.text: message
3437
3538 Item {
3639 id: fullMessage
plugins/Unity/IndicatorsLegacy/Messaging/qml/SnapDecision.qml → plugins/Unity/Indicators/Messaging/qml/SnapDecision.qmlrenamed+33−14
@@ -20,19 +20,33 @@
2020
2121import QtQuick 2.0
2222import Ubuntu.Components 0.1
23−import Unity.IndicatorsLegacy 0.1 as Indicators
23+import Unity.Indicators 0.1 as Indicators
2424import "utils.js" as Utils
2525
2626HeroMessage {
2727 id: snapDecision
2828
29+ property string title: ""
30+ property string time: ""
31+ property string message: ""
32+
33+ property bool activateEnabled: true
34+ property alias actionButtonText: actionButton.text
35+
36+ property bool replyEnabled: true
37+ property alias replyMessages: quickreply.messages
38+ property alias replyButtonText: quickreply.buttonText
39+
2940 expandedHeight: buttons.y + buttons.height + quickreply.height + units.gu(2)
30− heroMessageHeader.titleText.text: menu ? menu.label : ""
31− heroMessageHeader.subtitleText.text: menu ? menu.extra.canonical_text : ""
41+ heroMessageHeader.titleText.text: title
42+ heroMessageHeader.subtitleText.text: message
3243 heroMessageHeader.subtitleText.color: "#e8e1d0"
33− heroMessageHeader.bodyText.text: menu ? Utils.formatDate(menu.extra.canonical_time) : ""
44+ heroMessageHeader.bodyText.text: time
3445 heroMessageHeader.bodyText.color: "#8f8f88"
3546
47+ signal activate
48+ signal reply(string value)
49+
3650 Item {
3751 id: buttons
3852
@@ -62,16 +76,19 @@ HeroMessage {
6276 }
6377 }
6478
65− ActionButton {
66− actionGroup: snapDecision.actionGroup
67− action: actionsDescription[0].name
68−
69− text: actionsDescription ? actionsDescription[0].label : "Call back"
70− color: "#c94212"
79+ Button {
80+ id: actionButton
81+ text: "Call back"
82+ color: enabled ? "#c94212" : "#bababa"
7183 anchors.right: parent.right
7284 anchors.top: parent.top
7385 anchors.bottom: parent.bottom
7486 width: (parent.width - units.gu(1)) / 2
87+ enabled: snapDecision.activateEnabled
88+
89+ onClicked: {
90+ snapDecision.activate();
91+ }
7592 }
7693
7794 states: State {
@@ -95,11 +112,12 @@ HeroMessage {
95112 QuickReply {
96113 id: quickreply
97114
98− actionGroup: snapDecision.actionGroup
99− action: actionsDescription[1].name
115+ onReply: {
116+ snapDecision.reply(value);
117+ }
100118
101− messages: actionsDescription ? actionsDescription[1]["parameter-hint"] : ""
102− buttonText: actionsDescription ? actionsDescription[1].label : "send"
119+ messages: ""
120+ buttonText: "Send"
103121 anchors {
104122 top: buttons.bottom
105123 topMargin: units.gu(2)
@@ -109,6 +127,7 @@ HeroMessage {
109127 height: 0
110128 opacity: 0.0
111129 enabled: false
130+ replyEnabled: snapDecision.replyEnabled
112131
113132 states: State {
114133 name: "expanded"
plugins/Unity/IndicatorsLegacy/Messaging/qml/TextMessage.qml → plugins/Unity/Indicators/Messaging/qml/TextMessage.qmlrenamed+12−4
@@ -20,16 +20,24 @@
2020
2121import QtQuick 2.0
2222import Ubuntu.Components 0.1
23−import Unity.IndicatorsLegacy 0.1 as Indicators
23+import Unity.Indicators 0.1 as Indicators
2424
2525SimpleTextMessage {
2626 id: simpleMessage
2727
28+ property bool replyEnabled: false
29+ property string replyButtonText: "Send"
30+
31+ signal reply(string value)
32+
2833 footer: ActionTextField {
2934 anchors.fill: parent
30− actionGroup: simpleMessage.actionGroup
31− action: actionsDescription[0].name
3235
33− buttonText: actionsDescription ? actionsDescription[0].label : "Send"
36+ activateEnabled: simpleMessage.replyEnabled
37+ buttonText: simpleMessage.replyButtonText
38+
39+ onActivate: {
40+ simpleMessage.reply(value);
41+ }
3442 }
3543}
plugins/Unity/IndicatorsLegacy/Messaging/qml/qmldir → plugins/Unity/Indicators/Messaging/qml/qmldirrenamed+2−2
@@ -1,11 +1,11 @@
1−module Unity.IndicatorsLegacy.Messaging
1+module Unity.Indicators.Messaging
22
33ActionButton 0.1 ActionButton.qml
44ActionTextField 0.1 ActionTextField.qml
55GroupedMessage 0.1 GroupedMessage.qml
66HeroMessage 0.1 HeroMessage.qml
77HeroMessageHeader 0.1 HeroMessageHeader.qml
8−MessageMenuItem 0.1 MessageMenuItem.qml
8+MessageMenuItemFactory 0.1 MessageMenuItemFactory.qml
99QuickReply 0.1 QuickReply.qml
1010SimpleTextMessage 0.1 SimpleTextMessage.qml
1111SnapDecision 0.1 SnapDecision.qml
plugins/Unity/IndicatorsLegacy/Messaging/qml/utils.js → plugins/Unity/Indicators/Messaging/qml/utils.jsrenamed

The content is the same.

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+4
@@ -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);
@@ -41,12 +42,15 @@ static QObject* menuModelCacheSingleton(QQmlEngine* engine, QJSEngine* scriptEng
4142
4243void Indicators2Plugin::registerTypes(const char *uri)
4344{
45+ Q_INIT_RESOURCE(indicators);
46+
4447 qmlRegisterType<IndicatorsManager>(uri, 0, 1, "IndicatorsManager");
4548 qmlRegisterType<IndicatorsModel>(uri, 0, 1, "IndicatorsModel");
4649 qmlRegisterType<MenuContentActivator>(uri, 0, 1, "MenuContentActivator");
4750 qmlRegisterType<UnityMenuModelStack>(uri, 0, 1, "UnityMenuModelStack");
4851 qmlRegisterType<RootActionState>(uri, 0, 1, "RootActionState");
4952 qmlRegisterType<ModelPrinter>(uri, 0, 1, "ModelPrinter");
53+ qmlRegisterType<VisibleIndicatorsModel>(uri, 0, 1, "VisibleIndicatorsModel");
5054
5155 qmlRegisterSingletonType<UnityMenuModelCache>(uri, 0, 1, "UnityMenuModelCache", menuModelCacheSingleton);
5256
plugins/Unity/Indicators/qml/BaseMenuItem.qml+1−1
@@ -24,7 +24,7 @@ import Ubuntu.Components.ListItems 0.1 as ListItem
2424ListItem.Standard {
2525 id: baseMenu
2626
27− property bool menuActivated: false
27+ property bool menuSelected: false
2828
2929 signal selectMenu()
3030 signal deselectMenu()
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/IndicatorPage.qml+33−6
@@ -60,7 +60,34 @@ IndicatorBase {
6060 // Only allow flicking if the content doesn't fit on the page
6161 interactive: contentHeight > height
6262
63− currentIndex: -1
63+ property int selectedIndex: -1
64+ property bool blockCurrentIndexChange: false
65+ // for count = 0
66+ onCountChanged: {
67+ if (count == 0 && selectedIndex != -1) {
68+ selectedIndex = -1;
69+ }
70+ }
71+ // for highlight following
72+ onSelectedIndexChanged: {
73+ if (currentIndex != selectedIndex) {
74+ var blocked = blockCurrentIndexChange;
75+ blockCurrentIndexChange = true;
76+
77+ currentIndex = selectedIndex;
78+
79+ blockCurrentIndexChange = blocked;
80+ }
81+ }
82+ // for item addition/removal
83+ onCurrentIndexChanged: {
84+ if (!blockCurrentIndexChange) {
85+ if (selectedIndex != -1 && selectedIndex != currentIndex) {
86+ selectedIndex = currentIndex;
87+ }
88+ }
89+ }
90+
6491 delegate: Item {
6592 id: menuDelegate
6693
@@ -89,10 +116,10 @@ IndicatorBase {
89116 menuStack.push(mainMenu.model.submenu(index));
90117 }
91118
92− if (item.hasOwnProperty("menuActivated")) {
93− item.menuActivated = Qt.binding(function() { return ListView.isCurrentItem; });
94− item.selectMenu.connect(function() { ListView.view.currentIndex = index });
95− item.deselectMenu.connect(function() { ListView.view.currentIndex = -1 });
119+ if (item.hasOwnProperty("menuSelected")) {
120+ item.menuSelected = Qt.binding(function() { return mainMenu.selectedIndex == index; });
121+ item.selectMenu.connect(function() { mainMenu.selectedIndex = index; });
122+ item.deselectMenu.connect(function() { mainMenu.selectedIndex = -1; });
96123 }
97124 if (item.hasOwnProperty("menu")) {
98125 item.menu = Qt.binding(function() { return model; });
@@ -149,7 +176,7 @@ IndicatorBase {
149176
150177 function reset()
151178 {
152− mainMenu.currentIndex = -1;
179+ mainMenu.selectedIndex = -1;
153180 mainMenu.positionViewAtBeginning();
154181 }
155182}
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+68−33
@@ -20,6 +20,7 @@
2020import QtQuick 2.0
2121import Unity.Indicators 0.1 as Indicators
2222import Unity.Indicators.Network 0.1 as ICNetwork
23+import Unity.Indicators.Messaging 0.1 as ICMessaging
2324import QMenuModel 0.1 as QMenuModel
2425
2526Item {
@@ -38,6 +39,9 @@ Item {
3839 "com.canonical.indicator.slider" : sliderMenu,
3940 "com.canonical.indicator.switch" : switchMenu,
4041
42+ "com.canonical.indicator.messages.messageitem" : messageItem,
43+ "com.canonical.indicator.messages.sourceitem" : groupedMessage,
44+
4145 "com.canonical.unity.slider" : sliderMenu,
4246 "com.canonical.unity.switch" : switchMenu,
4347
@@ -45,15 +49,17 @@ Item {
4549 "unity.widgets.systemsettings.tablet.accesspoint" : accessPoint,
4650 }
4751
52+ Component { id: divMenu; Indicators.DivMenuItem {} }
53+
4854 Component {
4955 id: sliderMenu;
5056 Indicators.SliderMenuItem {
5157 property QtObject menu: null
5258
5359 text: menu && menu.label ? menu.label : ""
54− icon: menu ? menu.icon : ""
55− minIcon: menu.ext.minIcon
56− maxIcon: menu.ext.maxIcon
60+ icon: menu && menu.icon ? menu.icon : ""
61+ minIcon: menu && menu.ext.minIcon ? menu.ext.minIcon : ""
62+ maxIcon: menu && menu.ext.maxIcon ? menu.ext.maxIcon : ""
5763
5864 minimumValue: menu.ext.minValue ? menu.ext.minValue : 0.0
5965 maximumValue: {
@@ -73,29 +79,12 @@ Item {
7379 'max-icon': 'icon'});
7480 }
7581
76− // FIXME: The interval should be [0.0 - 1.0]. Unfortunately, when
77− // reaching the boundaries (0.0 or 1.0), the value is converted
78− // to an integer when automatically wrapped in a variant when
79− // passed to QStateAction::updateState(…). The server chokes on
80− // those values, complaining that they’re not of the right type…
8182 onChangeState: {
82− if (value == Math.round(value)) {
83− if (value >= maximumValue) {
84− model.changeState(modelIndex, maximumValue - 0.000001);
85− } else if (value <= minimumValue) {
86− model.changeState(modelIndex, minimumValue + 0.000001);
87− } else {
88− model.changeState(modelIndex, value * 1.000001);
89− }
90− } else {
91− model.changeState(modelIndex, value);
92− }
83+ model.changeState(modelIndex, value);
9384 }
9485 }
9586 }
9687
97− Component { id: divMenu; Indicators.DivMenuItem {} }
98−
9988 Component {
10089 id: buttonMenu;
10190 Indicators.ButtonMenuItem {
@@ -104,7 +93,9 @@ Item {
10493 text: menu && menu.label ? menu.label : ""
10594 enabled: menu ? menu.sensitive : false
10695
107− onActivate: model.activate(modelIndex);
96+ onActivate: {
97+ model.activate(modelIndex);
98+ }
10899 }
109100 }
110101 Component {
@@ -133,12 +124,14 @@ Item {
133124 property QtObject menu: null
134125
135126 text: menu && menu.label ? menu.label : ""
136− icon: menu ? menu.icon : ""
127+ icon: menu && menu.icon ? menu.icon : ""
137128 checkable: menu ? (menu.isCheck || menu.isRadio) : false
138129 checked: checkable ? menu.isToggled : false
139130 enabled: menu ? menu.sensitive : false
140131
141− onActivate: model.activate(modelIndex);
132+ onActivate: {
133+ model.activate(modelIndex);
134+ }
142135 }
143136 }
144137
@@ -148,11 +141,13 @@ Item {
148141 property QtObject menu: null
149142
150143 text: menu && menu.label ? menu.label : ""
151− icon: menu ? menu.icon : ""
144+ icon: menu && menu.icon ? menu.icon : ""
152145 checked: menu ? menu.isToggled : false
153146 enabled: menu ? menu.sensitive : false
154147
155− onActivate: model.activate(modelIndex);
148+ onActivate: {
149+ model.activate(modelIndex);
150+ }
156151 }
157152 }
158153
@@ -174,17 +169,17 @@ Item {
174169 id: accessPoint;
175170 ICNetwork.AccessPoint {
176171 property QtObject menu: null
177−// property var strenthAction: QMenuModel.UnityMenuAction {
178−// model: menuFactory.model ? menuFactory.model : null
179−// name: menu ? menu.ext.xCanonicalWifiApStrengthAction : ""
180−// }
172+ property var strengthAction: QMenuModel.UnityMenuAction {
173+ model: menuFactory.model ? menuFactory.model : null
174+ index: modelIndex
175+ name: menu ? menu.ext.xCanonicalWifiApStrengthAction : ""
176+ }
181177
182178 text: menu && menu.label ? menu.label : ""
183− icon: menu ? menu.icon : ""
184179 secure: menu ? menu.ext.xCanonicalWifiApIsSecure : false
185180 adHoc: menu ? menu.ext.xCanonicalWifiApIsAdhoc : false
186181 checked: menu ? menu.isToggled : false
187−// signalStrength: strenthAction.valid ? strenthAction.state : 0
182+ signalStrength: strengthAction.valid ? strengthAction.state : 0
188183 enabled: menu ? menu.sensitive : false
189184
190185 Component.onCompleted: {
@@ -192,7 +187,47 @@ Item {
192187 'x-canonical-wifi-ap-is-secure': 'bool',
193188 'x-canonical-wifi-ap-strength-action': 'string'});
194189 }
195− onActivate: model.activate(modelIndex);
190+ onActivate: {
191+ model.activate(modelIndex);
192+ }
193+ }
194+ }
195+
196+ Component {
197+ id: messageItem
198+ ICMessaging.MessageMenuItemFactory {
199+
200+ property QtObject menu: null
201+ model: menuFactory.model ? menuFactory.model : null
202+
203+ Component.onCompleted: {
204+ model.loadExtendedAttributes(modelIndex, {'x-canonical-time': 'int64',
205+ 'x-canonical-text': 'string',
206+ 'x-canonical-message-actions': 'variant',
207+ 'icon': 'icon',
208+ 'x-canonical-app-icon': 'icon'});
209+ }
210+ }
211+ }
212+
213+ Component {
214+ id: groupedMessage
215+ ICMessaging.GroupedMessage {
216+ property QtObject menu: null
217+
218+ title: menu && menu.label ? menu.label : ""
219+ count: menu && menu.actionState[0] ? menu.actionState[0] : "0"
220+ appIcon: menu && menu.ext.icon !== undefined ? menu.ext.icon : "qrc:/indicators/artwork/messaging/default_app.svg"
221+
222+ Component.onCompleted: {
223+ model.loadExtendedAttributes(modelIndex, {'icon': 'icon'});
224+ }
225+ onActivateApp: {
226+ model.activate(modelIndex, true);
227+ }
228+ onDismiss: {
229+ model.activate(modelIndex, false);
230+ }
196231 }
197232 }
198233
plugins/Unity/IndicatorsLegacy/resources/artwork/messaging/default_app.svg → plugins/Unity/Indicators/resources/artwork/messaging/default_app.svgrenamed

The content is the same.

plugins/Unity/IndicatorsLegacy/resources/artwork/messaging/default_contact.png → plugins/Unity/Indicators/resources/artwork/messaging/default_contact.pngrenamed

Binary file not shown.

plugins/Unity/IndicatorsLegacy/resources/artwork/messaging/message_sms01_54px.png → plugins/Unity/Indicators/resources/artwork/messaging/message_sms01_54px.pngrenamed

Binary file not shown.

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+8
@@ -0,0 +1,8 @@
1+<RCC>
2+ <qresource prefix="/indicators">
3+ <file>artwork/network/secure.svg</file>
4+ <file>artwork/messaging/default_contact.png</file>
5+ <file>artwork/messaging/default_app.svg</file>
6+ <file>artwork/messaging/message_sms01_54px.png</file>
7+ </qresource>
8+</RCC>
plugins/Unity/Indicators/rootactionstate.cpp+52−22
@@ -108,25 +108,32 @@ bool RootActionState::isValid() const
108108 return m_menu && m_menu->rowCount() > 0;
109109}
110110
111−QString RootActionState::label() const
111+QString RootActionState::leftLabel() const
112112{
113113 if (!isValid()) return QString();
114114
115− return m_cachedState.value("label", QVariant::fromValue(QString())).toString();
115+ return m_cachedState.value("pre-label", QVariant::fromValue(QString())).toString();
116116}
117117
118−QString RootActionState::icon() const
118+QString RootActionState::rightLabel() const
119119{
120120 if (!isValid()) return QString();
121121
122− return m_cachedState.value("icon", QVariant::fromValue(QString())).toString();
122+ return m_cachedState.value("label", QVariant::fromValue(QString())).toString();
123+}
124+
125+QStringList RootActionState::icons() const
126+{
127+ if (!isValid()) return QStringList();
128+
129+ return m_cachedState.value("icons", QVariant::fromValue(QStringList())).toStringList();
123130}
124131
125132QString RootActionState::accessibleName() const
126133{
127134 if (!isValid()) return QString();
128135
129− return m_cachedState.value("accessible-name", QVariant::fromValue(QString())).toString();
136+ return m_cachedState.value("accessible-desc", QVariant::fromValue(QString())).toString();
130137}
131138
132139bool RootActionState::isVisible() const
@@ -141,15 +148,15 @@ static QString iconUri(GIcon *icon)
141148 QString uri;
142149
143150 if (G_IS_THEMED_ICON (icon)) {
144−
145151 const gchar* const* iconNames = g_themed_icon_get_names (G_THEMED_ICON (icon));
146− guint index = 0;
147− while(iconNames[index] != NULL) {
148− if (QIcon::hasThemeIcon(iconNames[index])) {
149− uri = QString("image://theme/%1").arg(iconNames[index]);
150− break;
151− }
152− index++;
152+
153+ QStringList iconNameList;
154+ for (uint index = 0; iconNames[index] != NULL; index++) {
155+ iconNameList << iconNames[index];
156+ }
157+
158+ if (!iconNameList.empty()) {
159+ uri = QString("image://theme/%1").arg(iconNameList.join(","));
153160 }
154161 }
155162 else if (G_IS_FILE_ICON (icon)) {
@@ -198,16 +205,39 @@ QVariant RootActionState::toQVariant(GVariant* state) const
198205 while (g_variant_iter_loop (&iter, "{sv}", &key, &vvalue))
199206 {
200207 QString str = QString::fromUtf8(key);
201− if (str == "icon") {
208+ if (str == "icon" && !qmap.contains("icons")) {
209+ QStringList icons;
210+
202211 // FIXME - should be sending a url.
203− GIcon *icon = g_icon_deserialize (vvalue);
204− if (icon) {
205− qmap.insert(str, iconUri(icon));
206− g_object_unref (icon);
212+ GIcon *gicon = g_icon_deserialize (vvalue);
213+ if (gicon) {
214+ icons << iconUri(gicon);
215+ g_object_unref (gicon);
207216 }
208− else {
209− qmap.insert(str, QVariant(""));
217+ qmap.insert("icons", icons);
218+
219+ } else if (str == "icons") {
220+
221+ QStringList icons;
222+
223+ if (g_variant_type_is_array(g_variant_get_type(vvalue))) {
224+
225+
226+ for (int i = 0, iMax = g_variant_n_children(vvalue); i < iMax; i++) {
227+ GVariant *child = g_variant_get_child_value(vvalue, i);
228+
229+ // FIXME - should be sending a url.
230+ GIcon *gicon = g_icon_deserialize (child);
231+ if (gicon) {
232+ icons << iconUri(gicon);
233+ g_object_unref (gicon);
234+ }
235+ g_variant_unref(child);
236+ }
210237 }
238+ // will overwrite icon.
239+ qmap.insert("icons", icons);
240+
211241 } else {
212242 qmap.insert(str, ActionStateParser::toQVariant(vvalue));
213243 }
@@ -230,12 +260,12 @@ QVariant RootActionState::toQVariant(GVariant* state) const
230260 &visible);
231261
232262 qmap["label"] = label ? QString::fromUtf8(label) : "";
233− qmap["accessible-name"] = accessible_name ? QString::fromUtf8(accessible_name) : "";
263+ qmap["accessible-desc"] = accessible_name ? QString::fromUtf8(accessible_name) : "";
234264 qmap["visible"] = visible;
235265
236266 gicon = g_icon_new_for_string (icon, NULL);
237267 if (gicon) {
238− qmap["icon"] = iconUri(gicon);
268+ qmap["icons"] = QStringList() << iconUri(gicon);
239269 g_object_unref (gicon);
240270 }
241271
plugins/Unity/Indicators/rootactionstate.h+9−6
@@ -32,8 +32,9 @@ class UNITYINDICATORS_EXPORT RootActionState : public ActionStateParser
3232 Q_PROPERTY(UnityMenuModel* menu READ menu WRITE setMenu NOTIFY menuChanged)
3333
3434 Q_PROPERTY(bool valid READ isValid NOTIFY validChanged)
35− Q_PROPERTY(QString label READ label NOTIFY labelChanged)
36− Q_PROPERTY(QString icon READ icon NOTIFY iconChanged)
35+ Q_PROPERTY(QString leftLabel READ leftLabel NOTIFY leftLabelChanged)
36+ Q_PROPERTY(QString rightLabel READ rightLabel NOTIFY rightLabelChanged)
37+ Q_PROPERTY(QStringList icons READ icons NOTIFY iconsChanged)
3738 Q_PROPERTY(QString accessibleName READ accessibleName NOTIFY accessibleNameChanged)
3839 Q_PROPERTY(bool visible READ isVisible NOTIFY visibleChanged)
3940public:
@@ -47,8 +48,9 @@ public:
4748 void setIndex(int index);
4849
4950 bool isValid() const;
50− QString label() const;
51− QString icon() const;
51+ QString leftLabel() const;
52+ QString rightLabel() const;
53+ QStringList icons() const;
5254 QString accessibleName() const;
5355 bool isVisible() const;
5456
@@ -62,8 +64,9 @@ Q_SIGNALS:
6264 void indexChanged();
6365
6466 void validChanged();
65− void labelChanged();
66− void iconChanged();
67+ void leftLabelChanged();
68+ void rightLabelChanged();
69+ void iconsChanged();
6770 void accessibleNameChanged();
6871 void visibleChanged();
6972
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/CMakeLists.txt−1
@@ -8,7 +8,6 @@ find_package(Qt5Core REQUIRED)
88find_package(Qt5Quick REQUIRED)
99
1010add_subdirectory(qml)
11−add_subdirectory(Messaging)
1211add_subdirectory(Network)
1312
1413include_directories(
plugins/Unity/IndicatorsLegacy/Messaging/qml/CMakeLists.txtdeleted−5
@@ -1,5 +0,0 @@
1−# export_qmlfiles macro
2−include(Plugins)
3−
4−# export the qmldir, *.qml files.
5−export_qmlfiles(Unity.IndicatorsLegacy.Messaging Unity/IndicatorsLegacy/Messaging)
plugins/Unity/IndicatorsLegacy/Messaging/qml/MessageMenuItem.qmldeleted−96
@@ -1,96 +0,0 @@
1−/*
2− * Copyright 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 Lesser 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 Lesser General Public License for more details.
12− *
13− * You should have received a copy of the GNU Lesser General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Authors:
17− * Renato Araujo Oliveira Filho <renato@canonical.com>
18− * Olivier Tilloy <olivier.tilloy@canonical.com>
19− */
20−
21−import QtQuick 2.0
22−import Ubuntu.Components 0.1
23−import Unity.IndicatorsLegacy 0.1 as Indicators
24−
25−Indicators.BasicMenuItem {
26− property variant actionsDescription: menu ? menu.extra.canonical_message_actions : undefined
27−
28− onActionGroupChanged: loadItem()
29− onActionsDescriptionChanged: loadItem()
30− implicitHeight: contents.status == Loader.Ready ? contents.item.implicitHeight : 0
31−
32− Loader {
33− id: contents
34−
35− anchors.fill: parent
36− // Binding all properties for the item, to make sure that any change in the
37− // property will be propagated to the contents.item at any time
38− Binding {
39− target: contents.item
40− property: "menuActivated"
41− value: menuActivated
42− when: (contents.status == Loader.Ready)
43− }
44−
45− Binding {
46− target: contents.item
47− property: "actionGroup"
48− value: actionGroup
49− when: (contents.status == Loader.Ready)
50− }
51−
52− Binding {
53− target: contents.item
54− property: "menu"
55− value: menu
56− when: (contents.status == Loader.Ready)
57− }
58−
59− Binding {
60− target: contents.item
61− property: "actionsDescription"
62− value: actionsDescription
63− when: (contents.status == Loader.Ready)
64− }
65−
66− Connections {
67− target: contents.item ? contents.item : null
68− onActivateMenu: activateMenu()
69− onDeactivateMenu: deactivateMenu()
70− }
71− }
72−
73−
74− function loadItem()
75− {
76− var parameterType = ""
77− for (var actIndex in actionsDescription) {
78− var desc = actionsDescription[actIndex];
79− if (desc["parameter-type"] !== undefined) {
80− parameterType += desc["parameter-type"];
81− } else {
82− parameterType += "_";
83− }
84− }
85−
86− if (parameterType === "") {
87− contents.source = "SimpleTextMessage.qml";
88− } else if (parameterType === "s") {
89− contents.source = "TextMessage.qml";
90− } else if (parameterType === "_s") {
91− contents.source = "SnapDecision.qml";
92− } else {
93− console.debug("Unknown paramater type: " + parameterType);
94− }
95− }
96−}
plugins/Unity/IndicatorsLegacy/Network/qml/AccessPoint.qml+2−2
@@ -47,10 +47,10 @@ Indicators.MenuItem {
4747 imageName += "-secure";
4848 }
4949
50− return "image://gicon/" + imageName;
50+ return "image://theme/" + imageName;
5151 }
5252
53− icon: menu && wifiApStrength ? getNetworkIcon(menu) : "image://gicon/wifi-none"
53+ icon: menu && wifiApStrength ? getNetworkIcon(menu) : "image://theme/wifi-none"
5454 iconFrame: false
5555 control: CheckBox {
5656 id: checkBoxActive
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/IndicatorsLegacy/qml/MenuItemFactory.qml−8
@@ -19,7 +19,6 @@
1919
2020import QtQuick 2.0
2121import Unity.IndicatorsLegacy 0.1 as Indicators
22−import Unity.IndicatorsLegacy.Messaging 0.1 as ICMessaging
2322import Unity.IndicatorsLegacy.Network 0.1 as ICNetwork
2423
2524Item {
@@ -47,10 +46,6 @@ Item {
4746 "com.canonical.indicator.slider" : sliderMenu,
4847 "com.canonical.indicator.switch" : switchMenu,
4948
50− "com.canonical.indicator.messages.messageitem" : messageItem,
51− "com.canonical.indicator.messages.snapdecision" : snapDecision,
52− "com.canonical.indicator.messages.sourceitem" : groupedMessage,
53−
5449 "unity.widget.systemsettings.tablet.sectiontitle" : wifiSection,
5550 "unity.widgets.systemsettings.tablet.wifisection" : wifiSection,
5651 "unity.widgets.systemsettings.tablet.accesspoint" : accessPoint,
@@ -62,9 +57,6 @@ Item {
6257 Component { id: divMenu; Indicators.DivMenuItem {} }
6358 Component { id: sectionMenu; Indicators.SectionMenuItem {} }
6459 Component { id: progressMenu; Indicators.ProgressMenuItem {} }
65− Component { id: messageItem; ICMessaging.MessageMenuItem {} }
66− Component { id: snapDecision; ICMessaging.SnapDecision {} }
67− Component { id: groupedMessage; ICMessaging.GroupedMessage {} }
6860 Component { id: wifiSection; ICNetwork.WifiSection {} }
6961 Component { id: accessPoint; ICNetwork.AccessPoint {} }
7062 Component { id: indicatorMenu; Indicators.MenuItem {} }
plugins/Unity/IndicatorsLegacy/resources/indicators.qrc−3
@@ -1,7 +1,4 @@
11<RCC>
22 <qresource prefix="/indicators">
3− <file>artwork/messaging/default_contact.png</file>
4− <file>artwork/messaging/default_app.svg</file>
5− <file>artwork/messaging/message_sms01_54px.png</file>
63 </qresource>
74</RCC>
plugins/Unity/Launcher/CMakeLists.txt+11−2
@@ -1,8 +1,14 @@
11include(FindPkgConfig)
2−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=2)
2+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=3)
3+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=1)
4+pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
5+
6+add_definitions(-DSM_BUSNAME=systemBus)
37
48include_directories(
59 ${CMAKE_CURRENT_SOURCE_DIR}
10+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService
11+ ${GSETTINGS_QT_INCLUDE_DIRS}
612)
713
814set(QMLLAUNCHERPLUGIN_SRC
@@ -12,6 +18,7 @@ set(QMLLAUNCHERPLUGIN_SRC
1218 quicklistmodel.cpp
1319 common/quicklistentry.cpp
1420 backend/launcherbackend.cpp
21+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
1522 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
1623 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
1724 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
@@ -21,7 +28,9 @@ add_library(UnityLauncher-qml MODULE
2128 ${QMLLAUNCHERPLUGIN_SRC}
2229 )
2330
24−qt5_use_modules(UnityLauncher-qml Qml)
31+target_link_libraries(UnityLauncher-qml ${GSETTINGS_QT_LDFLAGS})
32+
33+qt5_use_modules(UnityLauncher-qml DBus Qml)
2534
2635# export the qmldir and qmltypes files
2736export_qmlfiles(Unity.Launcher Unity/Launcher)
plugins/Unity/Launcher/backend/launcherbackend.cpp+261−59
@@ -2,6 +2,7 @@
22 * Copyright (C) 2013 Canonical, Ltd.
33 *
44 * Authors:
5+ * Michael Terry <michael.terry@canonical.com>
56 * Michael Zanetti <michael.zanetti@canonical.com>
67 *
78 * This program is free software; you can redistribute it and/or modify
@@ -17,63 +18,45 @@
1718 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1819 */
1920
21+#include "AccountsServiceDBusAdaptor.h"
2022#include "launcherbackend.h"
2123
22−#include <QHash>
23−
24−LauncherBackend::LauncherBackend(QObject *parent):
25− QObject(parent)
26−{
27−
28− // TODO: load default pinned ones from default config, instead of hardcoding here...
29−
30− m_storedApps <<
31− QLatin1String("dialer-app.desktop") <<
32− QLatin1String("messaging-app.desktop") <<
33− QLatin1String("address-book-app.desktop") <<
34− QLatin1String("camera-app.desktop") <<
35− QLatin1String("gallery-app.desktop") <<
36− QLatin1String("facebook-webapp.desktop") <<
37− QLatin1String("webbrowser-app.desktop") <<
38− QLatin1String("twitter-webapp.desktop") <<
39− QLatin1String("gmail-webapp.desktop") <<
40− QLatin1String("ubuntu-weather-app.desktop") <<
41− QLatin1String("notes-app.desktop") <<
42− QLatin1String("calendar-app.desktop");
43−
44− // TODO: get stuff from desktop files instead this hardcoded map
45− m_displayNameMap.insert("dialer-app.desktop", "Dialer");
46− m_displayNameMap.insert("messaging-app.desktop", "Messaging");
47− m_displayNameMap.insert("address-book-app.desktop", "Contacts");
48− m_displayNameMap.insert("camera-app.desktop", "Camera");
49− m_displayNameMap.insert("gallery-app.desktop", "Gallery");
50− m_displayNameMap.insert("facebook-webapp.desktop", "Facebook");
51− m_displayNameMap.insert("webbrowser-app.desktop", "Browser");
52− m_displayNameMap.insert("twitter-webapp.desktop", "Twitter");
53− m_displayNameMap.insert("gmail-webapp.desktop", "GMail");
54− m_displayNameMap.insert("ubuntu-weather-app.desktop", "Weather");
55− m_displayNameMap.insert("notes-app.desktop", "Notes");
56− m_displayNameMap.insert("calendar-app.desktop", "Calendar");
57−
58− // TODO: get stuff from desktop files instead this hardcoded map
59− m_iconMap.insert("dialer-app.desktop", "phone-app");
60− m_iconMap.insert("messaging-app.desktop", "messages-app");
61− m_iconMap.insert("address-book-app.desktop", "contacts-app");
62− m_iconMap.insert("camera-app.desktop", "camera");
63− m_iconMap.insert("gallery-app.desktop", "gallery");
64− m_iconMap.insert("facebook-webapp.desktop", "facebook");
65− m_iconMap.insert("webbrowser-app.desktop", "browser");
66− m_iconMap.insert("twitter-webapp.desktop", "twitter");
67− m_iconMap.insert("gmail-webapp.desktop", "gmail");
68− m_iconMap.insert("ubuntu-weather-app.desktop", "weather");
69− m_iconMap.insert("notes-app.desktop", "notepad");
70− m_iconMap.insert("calendar-app.desktop", "calendar");
24+#include <QDir>
25+#include <QDBusArgument>
26+#include <QFileInfo>
27+#include <QGSettings>
28+#include <QDebug>
7129
30+class LauncherBackendItem
31+{
32+public:
33+ LauncherBackendItem(): pinned(false) {}
34+
35+ QString desktopFile;
36+ QString displayName;
37+ QString icon;
38+ bool pinned;
39+};
40+
41+LauncherBackend::LauncherBackend(bool useStorage, QObject *parent):
42+ QObject(parent),
43+ m_accounts(nullptr)
44+{
45+ if (useStorage) {
46+ m_accounts = new AccountsServiceDBusAdaptor(this);
47+ }
48+ m_user = qgetenv("USER");
49+ syncFromAccounts();
7250}
7351
7452LauncherBackend::~LauncherBackend()
7553{
54+ m_storedApps.clear();
7655
56+ Q_FOREACH(LauncherBackendItem *item, m_itemCache) {
57+ delete item;
58+ }
59+ m_itemCache.clear();
7760}
7861
7962QStringList LauncherBackend::storedApplications() const
@@ -83,38 +66,99 @@ QStringList LauncherBackend::storedApplications() const
8366
8467void LauncherBackend::setStoredApplications(const QStringList &appIds)
8568{
69+ if (appIds.count() < m_storedApps.count()) {
70+ Q_FOREACH(const QString &appId, m_storedApps) {
71+ if (!appIds.contains(appId)) {
72+ delete m_itemCache.take(appId);
73+ }
74+ }
75+ }
8676 m_storedApps = appIds;
87− // TODO: Cleanup pinned state from settings for apps not in list any more.
77+ Q_FOREACH(const QString &appId, appIds) {
78+ if (!m_itemCache.contains(appId)) {
79+ QString df = findDesktopFile(appId);
80+ if (!df.isEmpty()) {
81+ LauncherBackendItem *item = parseDesktopFile(df);
82+ m_itemCache.insert(appId, item);
83+ } else {
84+ // Cannot find any data for that app... ignoring it.
85+ qWarning() << "cannot find desktop file for" << appId << ". discarding app.";
86+ m_storedApps.removeAll(appId);
87+ }
88+ }
89+ }
90+ syncToAccounts();
8891}
8992
9093QString LauncherBackend::desktopFile(const QString &appId) const
9194{
92− // TODO: return real path instead of this hardcoded one
93− return QLatin1String("/usr/share/applications/") + appId;
95+ LauncherBackendItem *item = m_itemCache.value(appId);
96+ if (item) {
97+ return item->desktopFile;
98+ }
99+
100+ return findDesktopFile(appId);
94101}
95102
96103QString LauncherBackend::displayName(const QString &appId) const
97104{
98− return m_displayNameMap.value(appId);
105+ LauncherBackendItem *item = m_itemCache.value(appId);
106+ if (item) {
107+ return item->displayName;
108+ }
109+
110+ QString df = findDesktopFile(appId);
111+ if (!df.isEmpty()) {
112+ LauncherBackendItem *item = parseDesktopFile(df);
113+ m_itemCache.insert(appId, item);
114+ return item->displayName;
115+ }
116+
117+ return QString();
99118}
100119
101120QString LauncherBackend::icon(const QString &appId) const
102121{
103− return m_iconMap.value(appId);
122+ QString iconName;
123+ LauncherBackendItem *item = m_itemCache.value(appId);
124+ if (item) {
125+ iconName = item->icon;
126+ } else {
127+ QString df = findDesktopFile(appId);
128+ if (!df.isEmpty()) {
129+ LauncherBackendItem *item = parseDesktopFile(df);
130+ m_itemCache.insert(appId, item);
131+ iconName = item->icon;
132+ }
133+ }
134+
135+ return iconName;
104136}
105137
106138bool LauncherBackend::isPinned(const QString &appId) const
107139{
108− // TODO: return app's pinned state from settings
109− Q_UNUSED(appId)
140+ LauncherBackendItem *item = m_itemCache.value(appId);
141+ if (item) {
142+ return item->pinned;
143+ }
110144 return false;
111145}
112146
113147void LauncherBackend::setPinned(const QString &appId, bool pinned)
114148{
115− // TODO: Store pinned state in settings.
116− Q_UNUSED(appId)
117− Q_UNUSED(pinned)
149+ if (!m_storedApps.contains(appId)) {
150+ return;
151+ }
152+
153+ LauncherBackendItem *item = m_itemCache.value(appId);
154+ if (!item) {
155+ item = new LauncherBackendItem();
156+ m_itemCache.insert(appId, item);
157+ }
158+ if (item->pinned != pinned) {
159+ item->pinned = pinned;
160+ syncToAccounts();
161+ }
118162}
119163
120164QList<QuickListEntry> LauncherBackend::quickList(const QString &appId) const
@@ -143,9 +187,167 @@ int LauncherBackend::count(const QString &appId) const
143187 return 0;
144188}
145189
190+void LauncherBackend::setUser(const QString &username)
191+{
192+ if (qgetenv("USER") == "lightdm" && m_user != username) {
193+ m_user = username;
194+ syncFromAccounts();
195+ }
196+}
197+
146198void LauncherBackend::triggerQuickListAction(const QString &appId, const QString &quickListId)
147199{
148200 // TODO: execute the given quicklist action
149201 Q_UNUSED(appId)
150202 Q_UNUSED(quickListId)
151203}
204+
205+void LauncherBackend::syncFromAccounts()
206+{
207+ QList<QVariantMap> apps;
208+ bool defaults = true;
209+
210+ m_storedApps.clear();
211+
212+ if (m_accounts && !m_user.isEmpty()) {
213+ QVariant variant = m_accounts->getUserProperty(m_user, "com.canonical.unity.AccountsService", "launcher-items");
214+ apps = qdbus_cast<QList<QVariantMap>>(variant.value<QDBusArgument>());
215+ defaults = isDefaultsItem(apps);
216+ }
217+
218+ if (m_accounts && defaults) { // Checking accounts as it'll be null when !useStorage
219+ QGSettings gSettings("com.canonical.Unity.Launcher", "/com/canonical/unity/launcher/");
220+ Q_FOREACH(const QString &entry, gSettings.get("favorites").toStringList()) {
221+ if (entry.startsWith("application://")) {
222+ QString appId = entry;
223+ // Transform "application://foobar.desktop" to "foobar"
224+ appId.remove("application://");
225+ if (appId.endsWith(".desktop")) {
226+ appId.chop(8);
227+ }
228+ QString df = findDesktopFile(appId);
229+
230+ if (!df.isEmpty()) {
231+ m_storedApps << appId;
232+
233+ if (!m_itemCache.contains(appId)) {
234+ m_itemCache.insert(appId, parseDesktopFile(df));
235+ }
236+ m_itemCache.value(appId)->pinned = true;
237+ }
238+ }
239+ }
240+ } else {
241+ for (const QVariant &app: apps) {
242+ loadFromVariant(app.toMap());
243+ }
244+ }
245+}
246+
247+void LauncherBackend::syncToAccounts()
248+{
249+ if (m_accounts && !m_user.isEmpty()) {
250+ QList<QVariantMap> items;
251+
252+ Q_FOREACH(const QString &appId, m_storedApps) {
253+ items << itemToVariant(appId);
254+ }
255+
256+ m_accounts->setUserProperty(m_user, "com.canonical.unity.AccountsService", "launcher-items", QVariant::fromValue(items));
257+ }
258+}
259+
260+QString LauncherBackend::findDesktopFile(const QString &appId) const
261+{
262+ int dashPos = -1;
263+ QString helper = appId;
264+
265+ QStringList searchDirs;
266+ searchDirs << QDir::homePath() + "/.local/share/applications";
267+ searchDirs << "/usr/share/applications";
268+
269+#ifdef LAUNCHER_TESTING
270+ searchDirs << "";
271+#endif
272+
273+ do {
274+ if (dashPos != -1) {
275+ helper = helper.replace(dashPos, 1, '/');
276+ }
277+
278+ Q_FOREACH(const QString &searchDir, searchDirs) {
279+ QFileInfo fileInfo(QDir(searchDir), helper + ".desktop");
280+ if (fileInfo.exists()) {
281+ return fileInfo.absoluteFilePath();
282+ }
283+ }
284+
285+ dashPos = helper.indexOf("-");
286+ } while (dashPos != -1);
287+
288+ return QString();
289+}
290+
291+LauncherBackendItem* LauncherBackend::parseDesktopFile(const QString &desktopFile) const
292+{
293+ QSettings settings(desktopFile, QSettings::IniFormat);
294+
295+ LauncherBackendItem* item = new LauncherBackendItem();
296+ item->desktopFile = desktopFile;
297+ item->displayName = settings.value("Desktop Entry/Name").toString();
298+
299+ QString iconString = settings.value("Desktop Entry/Icon").toString();
300+ QString pathString = settings.value("Desktop Entry/Path").toString();
301+ if (QFileInfo(iconString).exists()) {
302+ item->icon = QFileInfo(iconString).absoluteFilePath();
303+ } else if (QFileInfo(pathString + '/' + iconString).exists()) {
304+ item->icon = pathString + '/' + iconString;
305+ } else {
306+ item->icon = "image://theme/" + iconString;
307+ }
308+ item->pinned = false;
309+ return item;
310+}
311+
312+void LauncherBackend::loadFromVariant(const QVariantMap &details)
313+{
314+ if (!details.contains("id")) {
315+ return;
316+ }
317+ QString appId = details.value("id").toString();
318+
319+ LauncherBackendItem *item = m_itemCache.value(appId);
320+ if (item) {
321+ delete item;
322+ }
323+
324+ item = new LauncherBackendItem();
325+
326+ item->desktopFile = details.value("desktopFile").toString();
327+ item->displayName = details.value("name").toString();
328+ item->icon = details.value("icon").toString();
329+ item->pinned = details.value("is-pinned").toBool();
330+
331+ m_itemCache.insert(appId, item);
332+ m_storedApps.append(appId);
333+}
334+
335+QVariantMap LauncherBackend::itemToVariant(const QString &appId) const
336+{
337+ LauncherBackendItem *item = m_itemCache.value(appId);
338+ QVariantMap details;
339+ details.insert("id", appId);
340+ details.insert("name", item->displayName);
341+ details.insert("icon", item->icon);
342+ details.insert("desktopFile", item->desktopFile);
343+ details.insert("is-pinned", item->pinned);
344+ return details;
345+}
346+
347+bool LauncherBackend::isDefaultsItem(const QList<QVariantMap> &apps) const
348+{
349+ // To differentiate between an empty list and a list that hasn't been set
350+ // yet (and should thus be populated with the defaults), we use a special
351+ // list of one item with the 'defaults' field set to true.
352+ return (apps.size() == 1 && apps[0].value("defaults").toBool());
353+}
plugins/Unity/Launcher/backend/launcherbackend.h+36−5
@@ -22,20 +22,24 @@
2222#include "common/quicklistentry.h"
2323
2424#include <QObject>
25+#include <QSettings>
2526#include <QStringList>
26−#include <QHash>
27+
28+class AccountsServiceDBusAdaptor;
2729
2830/**
2931 * @brief An interface that provides all the data needed by the launcher.
3032 */
3133
34+class LauncherBackendItem;
35+
3236class LauncherBackend : public QObject
3337{
3438 Q_OBJECT
3539
3640
3741public:
38− LauncherBackend(QObject *parent = 0);
42+ LauncherBackend(bool useStorage = true, QObject *parent = 0);
3943 virtual ~LauncherBackend();
4044
4145 /**
@@ -57,12 +61,18 @@ public:
5761
5862 /**
5963 * @brief Get the full path to the .desktop file.
64+ *
65+ * The application does not need to be in the list of stored applications.
66+ *
6067 * @returns The full path to the .dekstop file.
6168 */
6269 QString desktopFile(const QString &appId) const;
6370
6471 /**
6572 * @brief Get the user friendly name of an application.
73+ *
74+ * The application does not need to be in the list of stored applications.
75+ *
6676 * @param appId The ID of the application.
6777 * @returns The user friendly name of the application.
6878 */
@@ -70,6 +80,9 @@ public:
7080
7181 /**
7282 * @brief Get the icon of an application.
83+ *
84+ * The application does not need to be in the list of stored applications.
85+ *
7386 * @param appId The ID of the application.
7487 * @returns The full path to the icon for the application.
7588 */
@@ -118,15 +131,33 @@ public:
118131 */
119132 int count(const QString &appId) const;
120133
134+ /**
135+ * @brief Sets the username for which to look up launcher items.
136+ * @param username The username to use.
137+ */
138+ void setUser(const QString &username);
139+
121140Q_SIGNALS:
122141 void quickListChanged(const QString &appId, const QList<QuickListEntry> &quickList);
123142 void progressChanged(const QString &appId, int progress);
124143 void countChanged(const QString &appId, int count);
125144
126145private:
127− QStringList m_storedApps;
128− QHash<QString, QString> m_displayNameMap;
129− QHash<QString, QString> m_iconMap;
146+ QString findDesktopFile(const QString &appId) const;
147+ LauncherBackendItem* parseDesktopFile(const QString &desktopFile) const;
148+
149+ QVariantMap itemToVariant(const QString &appId) const;
150+ void loadFromVariant(const QVariantMap &details);
151+
152+ bool isDefaultsItem(const QList<QVariantMap> &apps) const;
153+ void syncFromAccounts();
154+ void syncToAccounts();
155+
156+ QList<QString> m_storedApps;
157+ mutable QHash<QString, LauncherBackendItem*> m_itemCache;
158+
159+ AccountsServiceDBusAdaptor *m_accounts;
160+ QString m_user;
130161};
131162
132163#endif // LAUNCHERBACKEND_H
plugins/Unity/Launcher/launcheritem.cpp+15−7
@@ -20,10 +20,9 @@
2020#include "launcheritem.h"
2121#include "quicklistmodel.h"
2222
23−LauncherItem::LauncherItem(const QString &appId, const QString &desktopFile, const QString &name, const QString &icon, QObject *parent) :
23+LauncherItem::LauncherItem(const QString &appId, const QString &name, const QString &icon, QObject *parent) :
2424 LauncherItemInterface(parent),
2525 m_appId(appId),
26− m_desktopFile(desktopFile),
2726 m_name(name),
2827 m_icon(icon),
2928 m_pinned(false),
@@ -31,6 +30,7 @@ LauncherItem::LauncherItem(const QString &appId, const QString &desktopFile, con
3130 m_recent(false),
3231 m_progress(-1),
3332 m_count(0),
33+ m_focused(false),
3434 m_quickList(new QuickListModel(this))
3535{
3636 QuickListEntry nameAction;
@@ -47,11 +47,6 @@ QString LauncherItem::appId() const
4747 return m_appId;
4848}
4949
50−QString LauncherItem::desktopFile() const
51−{
52− return m_desktopFile;
53−}
54−
5550QString LauncherItem::name() const
5651{
5752 return m_name;
@@ -131,6 +126,19 @@ void LauncherItem::setCount(int count)
131126 }
132127}
133128
129+bool LauncherItem::focused() const
130+{
131+ return m_focused;
132+}
133+
134+void LauncherItem::setFocused(bool focused)
135+{
136+ if (m_focused != focused) {
137+ m_focused = focused;
138+ Q_EMIT focusedChanged(focused);
139+ }
140+}
141+
134142unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
135143{
136144 return m_quickList;
plugins/Unity/Launcher/launcheritem.h+5−3
@@ -32,10 +32,9 @@ class LauncherItem: public LauncherItemInterface
3232{
3333 Q_OBJECT
3434public:
35− LauncherItem(const QString &appId, const QString &desktopFile, const QString &name, const QString &icon, QObject *parent = 0);
35+ LauncherItem(const QString &appId, const QString &name, const QString &icon, QObject *parent = 0);
3636
3737 QString appId() const;
38− QString desktopFile() const;
3938 QString name() const;
4039 QString icon() const;
4140
@@ -54,6 +53,9 @@ public:
5453 int count() const;
5554 void setCount(int count);
5655
56+ bool focused() const;
57+ void setFocused(bool focused);
58+
5759 unity::shell::launcher::QuickListModelInterface *quickList() const;
5860
5961Q_SIGNALS:
@@ -62,7 +64,6 @@ Q_SIGNALS:
6264
6365private:
6466 QString m_appId;
65− QString m_desktopFile;
6667 QString m_name;
6768 QString m_icon;
6869 bool m_pinned;
@@ -70,6 +71,7 @@ private:
7071 bool m_recent;
7172 int m_progress;
7273 int m_count;
74+ bool m_focused;
7375 QuickListModel *m_quickList;
7476};
7577
plugins/Unity/Launcher/launchermodel.cpp+129−12
@@ -21,16 +21,20 @@
2121#include "launcheritem.h"
2222#include "backend/launcherbackend.h"
2323
24+#include <unity/shell/application/ApplicationInfoInterface.h>
25+
26+using namespace unity::shell::application;
27+
2428LauncherModel::LauncherModel(QObject *parent):
2529 LauncherModelInterface(parent),
26− m_backend(new LauncherBackend(this))
30+ m_backend(new LauncherBackend(true, this)),
31+ m_appManager(0)
2732{
2833 connect(m_backend, SIGNAL(countChanged(QString,int)), SLOT(countChanged(QString,int)));
2934 connect(m_backend, SIGNAL(progressChanged(QString,int)), SLOT(progressChanged(QString,int)));
3035
3136 Q_FOREACH (const QString &entry, m_backend->storedApplications()) {
3237 LauncherItem *item = new LauncherItem(entry,
33− m_backend->desktopFile(entry),
3438 m_backend->displayName(entry),
3539 m_backend->icon(entry),
3640 this);
@@ -61,9 +65,7 @@ QVariant LauncherModel::data(const QModelIndex &index, int role) const
6165 LauncherItem *item = m_list.at(index.row());
6266 switch(role) {
6367 case RoleAppId:
64− return item->desktopFile();
65− case RoleDesktopFile:
66− return item->desktopFile();
68+ return item->appId();
6769 case RoleName:
6870 return item->name();
6971 case RoleIcon:
@@ -74,6 +76,8 @@ QVariant LauncherModel::data(const QModelIndex &index, int role) const
7476 return item->count();
7577 case RoleProgress:
7678 return item->progress();
79+ case RoleFocused:
80+ return item->focused();
7781 }
7882
7983 return QVariant();
@@ -111,9 +115,11 @@ void LauncherModel::move(int oldIndex, int newIndex)
111115 m_list.move(oldIndex, newIndex);
112116 endMoveRows();
113117
114− storeAppList();
115−
116− pin(m_list.at(newIndex)->appId());
118+ if (!m_list.at(newIndex)->pinned()) {
119+ pin(m_list.at(newIndex)->appId());
120+ } else {
121+ storeAppList();
122+ }
117123}
118124
119125void LauncherModel::pin(const QString &appId, int index)
@@ -123,6 +129,7 @@ void LauncherModel::pin(const QString &appId, int index)
123129 if (currentIndex >= 0) {
124130 if (index == -1 || index == currentIndex) {
125131 m_list.at(currentIndex)->setPinned(true);
132+ m_backend->setPinned(appId, true);
126133 QModelIndex modelIndex = this->index(currentIndex);
127134 Q_EMIT dataChanged(modelIndex, modelIndex);
128135 } else {
@@ -134,13 +141,15 @@ void LauncherModel::pin(const QString &appId, int index)
134141 }
135142 beginInsertRows(QModelIndex(), index, index);
136143 LauncherItem *item = new LauncherItem(appId,
137− m_backend->desktopFile(appId),
138144 m_backend->displayName(appId),
139145 m_backend->icon(appId));
140146 item->setPinned(true);
147+ m_backend->setPinned(appId, true);
141148 m_list.insert(index, item);
142149 endInsertRows();
143150 }
151+
152+ storeAppList();
144153}
145154
146155void LauncherModel::requestRemove(const QString &appId)
@@ -150,6 +159,11 @@ void LauncherModel::requestRemove(const QString &appId)
150159 return;
151160 }
152161
162+ if (m_appManager->findApplication(appId)) {
163+ m_list.at(index)->setPinned(false);
164+ return;
165+ }
166+
153167 beginRemoveRows(QModelIndex(), index, index);
154168 m_list.takeAt(index)->deleteLater();
155169 endRemoveRows();
@@ -186,15 +200,58 @@ void LauncherModel::quickListActionInvoked(const QString &appId, int actionIndex
186200
187201void LauncherModel::setUser(const QString &username)
188202{
189− Q_UNUSED(username)
190− // TODO: Implement this...
203+ m_backend->setUser(username);
191204}
192205
206+ApplicationManagerInterface *LauncherModel::applicationManager() const
207+{
208+ return m_appManager;
209+}
210+
211+void LauncherModel::setApplicationManager(unity::shell::application::ApplicationManagerInterface *appManager)
212+{
213+ // Is there already another appmanager set?
214+ if (m_appManager) {
215+ // Disconnect any signals
216+ disconnect(this, SLOT(applicationAdded(QModelIndex,int)));
217+ disconnect(this, SLOT(applicationRemoved(QModelIndex,int)));
218+ disconnect(this, SLOT(focusedAppIdChanged()));
219+
220+ // remove any recent/running apps from the launcher
221+ QList<int> recentAppIndices;
222+ for (int i = 0; i < m_list.count(); ++i) {
223+ if (m_list.at(i)->recent()) {
224+ recentAppIndices << i;
225+ }
226+ }
227+ int run = 0;
228+ while (recentAppIndices.count() > 0) {
229+ beginRemoveRows(QModelIndex(), recentAppIndices.first() - run, recentAppIndices.first() - run);
230+ m_list.takeAt(recentAppIndices.first() - run)->deleteLater();
231+ endRemoveRows();
232+ recentAppIndices.takeFirst();
233+ ++run;
234+ }
235+ }
236+
237+ m_appManager = appManager;
238+ connect(m_appManager, SIGNAL(rowsInserted(QModelIndex, int, int)), SLOT(applicationAdded(QModelIndex,int)));
239+ connect(m_appManager, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), SLOT(applicationRemoved(QModelIndex,int)));
240+ connect(m_appManager, SIGNAL(focusedApplicationIdChanged()), SLOT(focusedAppIdChanged()));
241+
242+ Q_EMIT applicationManagerChanged();
243+
244+ for (int i = 0; i < appManager->count(); ++i) {
245+ applicationAdded(QModelIndex(), i);
246+ }
247+}
248+
249+
193250void LauncherModel::storeAppList()
194251{
195252 QStringList appIds;
196253 Q_FOREACH(LauncherItem *item, m_list) {
197− if (item->pinned() || item->recent()) {
254+ if (item->pinned()) {
198255 appIds << item->appId();
199256 }
200257 }
@@ -232,3 +289,63 @@ void LauncherModel::countChanged(const QString &appId, int count)
232289 Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleCount);
233290 }
234291}
292+
293+void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
294+{
295+ Q_UNUSED(parent);
296+
297+ ApplicationInfoInterface *app = m_appManager->get(row);
298+
299+ bool found = false;
300+ Q_FOREACH(LauncherItem *item, m_list) {
301+ if (app->appId() == item->appId()) {
302+ found = true;
303+ break;
304+ }
305+ }
306+ if (found) {
307+ // Shall we paint some running/recent app highlight? If yes, do it here.
308+ } else {
309+ LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString());
310+ item->setRecent(true);
311+ item->setFocused(app->focused());
312+
313+ beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
314+ m_list.append(item);
315+ endInsertRows();
316+ }
317+}
318+
319+void LauncherModel::applicationRemoved(const QModelIndex &parent, int row)
320+{
321+ Q_UNUSED(parent)
322+
323+ int appIndex = -1;
324+ for (int i = 0; i < m_list.count(); ++i) {
325+ if (m_list.at(i)->appId() == m_appManager->get(row)->appId()) {
326+ appIndex = i;
327+ break;
328+ }
329+ }
330+
331+ if (appIndex > -1 && !m_list.at(appIndex)->pinned()) {
332+ beginRemoveRows(QModelIndex(), appIndex, appIndex);
333+ m_list.takeAt(appIndex)->deleteLater();
334+ endRemoveRows();
335+ }
336+}
337+
338+void LauncherModel::focusedAppIdChanged()
339+{
340+ QString appId = m_appManager->focusedApplicationId();
341+ for (int i = 0; i < m_list.count(); ++i) {
342+ LauncherItem *item = m_list.at(i);
343+ if (!item->focused() && item->appId() == appId) {
344+ item->setFocused(true);
345+ Q_EMIT dataChanged(index(i), index(i), QVector<int>() << RoleFocused);
346+ } else if (item->focused() && item->appId() != appId) {
347+ item->setFocused(false);
348+ Q_EMIT dataChanged(index(i), index(i), QVector<int>() << RoleFocused);
349+ }
350+ }
351+}
plugins/Unity/Launcher/launchermodel.h+11−1
@@ -17,11 +17,12 @@
1717 * Michael Zanetti <michael.zanetti@canonical.com>
1818 */
1919
20−#ifndef LAUNCHERMODELH
20+#ifndef LAUNCHERMODEL_H
2121#define LAUNCHERMODEL_H
2222
2323// unity-api
2424#include <unity/shell/launcher/LauncherModelInterface.h>
25+#include <unity/shell/application/ApplicationManagerInterface.h>
2526
2627// Qt
2728#include <QAbstractListModel>
@@ -30,6 +31,7 @@ class LauncherItem;
3031class LauncherBackend;
3132
3233using namespace unity::shell::launcher;
34+using namespace unity::shell::application;
3335
3436class LauncherModel: public LauncherModelInterface
3537{
@@ -50,6 +52,9 @@ public:
5052 Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
5153 Q_INVOKABLE void setUser(const QString &username);
5254
55+ unity::shell::application::ApplicationManagerInterface* applicationManager() const;
56+ void setApplicationManager(unity::shell::application::ApplicationManagerInterface *appManager);
57+
5358private:
5459 void storeAppList();
5560 int findApplication(const QString &appId);
@@ -58,9 +63,14 @@ private Q_SLOTS:
5863 void progressChanged(const QString &appId, int progress);
5964 void countChanged(const QString &appId, int count);
6065
66+ void applicationAdded(const QModelIndex &parent, int row);
67+ void applicationRemoved(const QModelIndex &parent, int row);
68+ void focusedAppIdChanged();
69+
6170private:
6271 QList<LauncherItem*> m_list;
6372 LauncherBackend *m_backend;
73+ ApplicationManagerInterface *m_appManager;
6474};
6575
6676#endif // LAUNCHERMODEL_H
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/categories.cpp+12−4
@@ -21,6 +21,7 @@
2121// self
2222#include "categories.h"
2323#include "categoryresults.h"
24+#include <QDebug>
2425
2526// Qt
2627#include <QDebug>
@@ -46,7 +47,6 @@ Categories::Categories(QObject* parent)
4647 m_roles[Categories::RoleHints] = "hints";
4748 m_roles[Categories::RoleResults] = "results";
4849 m_roles[Categories::RoleCount] = "count";
49− m_roles[Categories::RoleCategoryIndex] = "categoryIndex";
5050
5151 // TODO This should not be needed but accumulatting the count changes
5252 // makes the visualization more stable and also makes crashes on fast
@@ -66,7 +66,17 @@ Categories::getResults(int index) const
6666
6767 unsigned categoryIndex = static_cast<unsigned>(index);
6868 auto unity_results = m_unityScope->GetResultsForCategory(categoryIndex);
69− results->setModel(unity_results->model());
69+ if (unity_results) {
70+ results->setModel(unity_results->model());
71+ } else {
72+ // No results model returned by unity core; this can be the case when the global
73+ // results model of this scope is still not set in unity core. Don't set backend
74+ // model in DeeListModel - it will still beahve properly as an empty model. Since
75+ // we're connected to the category model change signal, and it is set by unity core
76+ // at the same time as results model (on channel opening), we'll reset category
77+ // results models with proper models when we're notifed again.
78+ qWarning() << "No results model for category" << categoryIndex;
79+ }
7080
7181 m_results.insert(index, results);
7282 }
@@ -291,8 +301,6 @@ Categories::data(const QModelIndex& index, int role) const
291301 }
292302 qDebug() << "Get count of cat" << DeeListModel::data(realIndex, CategoryColumn::ID).toString() << realRow << "at pos" << index.row() << "Count=" << getResults(realIndex.row())->rowCount();
293303 return QVariant::fromValue(getResults(realRow)->rowCount());
294− case RoleCategoryIndex:
295− return QVariant::fromValue(index.row()); // no remapping to realIndex
296304 default:
297305 return QVariant();
298306 }
plugins/Unity/categories.h+1−2
@@ -53,8 +53,7 @@ public:
5353 RoleProgressSource,
5454 RoleHints,
5555 RoleResults,
56− RoleCount,
57− RoleCategoryIndex
56+ RoleCount
5857 };
5958
6059 Q_INVOKABLE void overrideResults(const QString& categoryId, QAbstractItemModel* model);
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/checkoptionfilter.cpp+3−1
@@ -52,9 +52,11 @@ void CheckOptionFilter::onOptionsChanged(unity::dash::CheckOptionFilter::CheckOp
5252
5353 m_options = new UnityOptionsModel(this, options,
5454 m_unityCheckOptionFilter->option_added,
55− m_unityCheckOptionFilter->option_removed);
55+ m_unityCheckOptionFilter->option_removed,
56+ m_unityCheckOptionFilter->show_all_button);
5657
5758 connect(m_options, SIGNAL(activeChanged(AbstractFilterOption *)), m_options, SLOT(ensureTheOnlyActive(AbstractFilterOption *)));
59+ connect(m_options, SIGNAL(showAllActivated()), this, SLOT(clear()));
5860
5961 /* Property change signals */
6062 m_signals << m_unityCheckOptionFilter->options.changed.connect(sigc::mem_fun(this, &CheckOptionFilter::onOptionsChanged));
plugins/Unity/filter.h+3−2
@@ -56,11 +56,12 @@ public:
5656 bool filtering() const;
5757 virtual GenericOptionsModel* options() const = 0;
5858
59− Q_INVOKABLE void clear();
60−
6159 static Filter* newFromUnityFilter(unity::dash::Filter::Ptr unityFilter);
6260 bool hasUnityFilter(unity::dash::Filter::Ptr unityFilter) const;
6361
62+public Q_SLOTS:
63+ void clear();
64+
6465Q_SIGNALS:
6566 void optionsChanged();
6667
plugins/Unity/genericoptionsmodel.cpp+20−3
@@ -22,10 +22,18 @@
2222
2323// local
2424#include "abstractfilteroption.h"
25+#include "showallfilteroption.h"
2526
26−GenericOptionsModel::GenericOptionsModel(QObject *parent)
27+GenericOptionsModel::GenericOptionsModel(bool showAllOption, QObject *parent)
2728 : QAbstractListModel(parent)
2829{
30+ if (showAllOption)
31+ {
32+ auto showAll = new ShowAllFilterOption(this);
33+ connect(showAll, SIGNAL(activeChanged(bool)), this, SLOT(onOptionChanged()));
34+ connect(showAll, SIGNAL(activeChanged(bool)), this, SLOT(onShowAllClicked(bool)));
35+ addOption(showAll);
36+ }
2937}
3038
3139GenericOptionsModel::~GenericOptionsModel()
@@ -73,7 +81,7 @@ QVariant GenericOptionsModel::data(const QModelIndex& index, int role) const
7381
7482int GenericOptionsModel::rowCount(const QModelIndex& /* parent */) const
7583{
76− return m_options.size ();
84+ return m_options.size();
7785}
7886
7987void GenericOptionsModel::setActive(int idx, bool value)
@@ -117,7 +125,10 @@ void GenericOptionsModel::ensureTheOnlyActive(AbstractFilterOption *activeOption
117125
118126void GenericOptionsModel::addOption(AbstractFilterOption *option, int index)
119127{
120− m_options.insert(index, option);
128+ if (index >= 0)
129+ m_options.insert(index, option);
130+ else
131+ m_options.append(option);
121132
122133 connect(option, SIGNAL(idChanged(const QString &)), this, SLOT(onOptionChanged()));
123134 connect(option, SIGNAL(nameChanged(const QString &)), this, SLOT(onOptionChanged()));
@@ -168,3 +179,9 @@ void GenericOptionsModel::onActiveChanged()
168179 Q_EMIT activeChanged(option);
169180 }
170181}
182+
183+void GenericOptionsModel::onShowAllClicked(bool active)
184+{
185+ if (active)
186+ Q_EMIT showAllActivated();
187+}
plugins/Unity/genericoptionsmodel.h+4−2
@@ -35,7 +35,7 @@ class Q_DECL_EXPORT GenericOptionsModel : public QAbstractListModel
3535 Q_ENUMS(Roles)
3636
3737public:
38− GenericOptionsModel(QObject *parent = nullptr);
38+ GenericOptionsModel(bool showAllOption = false, QObject *parent = nullptr);
3939 ~GenericOptionsModel();
4040
4141 enum Roles {
@@ -59,13 +59,15 @@ public Q_SLOTS:
5959
6060Q_SIGNALS:
6161 void activeChanged(AbstractFilterOption *option);
62+ void showAllActivated();
6263
6364protected Q_SLOTS:
6465 void onOptionChanged();
6566 void onActiveChanged();
67+ void onShowAllClicked(bool active);
6668
6769protected:
68− void addOption(AbstractFilterOption *option, int index);
70+ void addOption(AbstractFilterOption *option, int index = -1);
6971 void removeOption(int index);
7072 int indexOf(const QString &option_id);
7173
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:")) || giconString.startsWith(QLatin1String("image:"))) {
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/multirangefilter.cpp+3−1
@@ -52,9 +52,11 @@ void MultiRangeFilter::onOptionsChanged(unity::dash::MultiRangeFilter::Options o
5252
5353 m_options = new UnityOptionsModel(this, options,
5454 m_unityMultiRangeFilter->option_added,
55− m_unityMultiRangeFilter->option_removed);
55+ m_unityMultiRangeFilter->option_removed,
56+ m_unityMultiRangeFilter->show_all_button);
5657
5758 connect(m_options, SIGNAL(activeChanged(AbstractFilterOption *)), m_options, SLOT(ensureTheOnlyActive(AbstractFilterOption *)));
59+ connect(m_options, SIGNAL(showAllActivated()), this, SLOT(clear()));
5860
5961 /* Property change signals */
6062 m_signals << m_unityMultiRangeFilter->options.changed.connect(sigc::mem_fun(this, &MultiRangeFilter::onOptionsChanged));
plugins/Unity/plugin.cpp+2
@@ -35,6 +35,7 @@
3535#include "categoryresults.h"
3636#include "bottombarvisibilitycommunicatorshell.h"
3737#include "genericoptionsmodel.h"
38+#include "result.h"
3839
3940// libqtdee
4041#include "deelistmodel.h"
@@ -50,6 +51,7 @@ void UnityPlugin::registerTypes(const char *uri)
5051 qmlRegisterUncreatableType<PreviewInfoHint>(uri, 0, 1, "PreviewInfoHint", "Can't create PreviewInfoHint object in QML.");
5152 qmlRegisterUncreatableType<SocialPreviewComment>(uri, 0, 1, "SocialPreviewComment", "Can't create SocialPreviewComment object in QML.");
5253 qmlRegisterUncreatableType<GenericOptionsModel>(uri, 0, 1, "GenericOptionsModel", "Can't create options model in QML.");
54+ qmlRegisterUncreatableType<Result>(uri, 0, 1, "Result", "Can't create result object in QML.");
5355 qmlRegisterType<Scope>(uri, 0, 1, "Scope");
5456 qmlRegisterType<Scopes>(uri, 0, 1, "Scopes");
5557 qmlRegisterType<Categories>(uri, 0, 1, "Categories");
plugins/Unity/preview.cpp+22−3
@@ -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
@@ -38,9 +39,12 @@
3839#include <UnityCore/MusicPreview.h>
3940#include <UnityCore/SocialPreview.h>
4041
42+#include <UnityCore/GLibWrapper.h>
43+
4144Preview::Preview(QObject *parent):
4245 QObject(parent),
43− m_unityPreview(nullptr)
46+ m_unityPreview(nullptr),
47+ m_result(new Result(this))
4448{
4549}
4650
@@ -102,7 +106,10 @@ QVariantMap Preview::infoHintsHash() const
102106QString Preview::image() const
103107{
104108 if (m_unityPreview) {
105− return QString::fromUtf8(g_icon_to_string(m_unityPreview->image()));
109+ auto giconString = g_icon_to_string(m_unityPreview->image());
110+ QString result(gIconToDeclarativeImageProviderString(QString::fromUtf8(giconString)));
111+ g_free(giconString);
112+ return result;
106113 } else {
107114 qWarning() << "Preview not set";
108115 }
@@ -119,6 +126,11 @@ QString Preview::imageSourceUri() const
119126 return QString::null;
120127}
121128
129+QVariant Preview::result() const
130+{
131+ return QVariant::fromValue(m_result);
132+}
133+
122134Preview* Preview::newFromUnityPreview(unity::dash::Preview::Ptr unityPreview)
123135{
124136 Preview* preview = nullptr;
@@ -147,6 +159,7 @@ Preview* Preview::newFromUnityPreview(unity::dash::Preview::Ptr unityPreview)
147159void Preview::setUnityPreviewBase(unity::dash::Preview::Ptr unityPreview)
148160{
149161 m_unityPreview = unityPreview;
162+ m_result->setPreview(unityPreview);
150163
151164 qDeleteAll(m_infoHints);
152165 m_infoHints.clear();
@@ -177,8 +190,14 @@ void Preview::execute(const QString& actionId, const QHash<QString, QVariant>& h
177190{
178191 if (m_unityPreview) {
179192 auto unityHints = convertToHintsMap(hints);
180− m_unityPreview->PerformAction(actionId.toStdString(), unityHints);
193+ m_actionCancellable.Renew();
194+ m_unityPreview->PerformAction(actionId.toStdString(), unityHints, nullptr, m_actionCancellable);
181195 } else {
182196 qWarning() << "Preview not set";
183197 }
184198}
199+
200+void Preview::cancelAction()
201+{
202+ m_actionCancellable.Cancel();
203+}
plugins/Unity/preview.h+7
@@ -31,7 +31,9 @@
3131#include <UnityCore/Preview.h>
3232
3333// local
34+#include "result.h"
3435#include "previewaction.h"
36+#include <UnityCore/GLibWrapper.h>
3537
3638class Q_DECL_EXPORT Preview : public QObject
3739{
@@ -46,6 +48,7 @@ class Q_DECL_EXPORT Preview : public QObject
4648 Q_PROPERTY(QVariantMap infoMap READ infoHintsHash NOTIFY previewChanged)
4749 Q_PROPERTY(QString image READ image NOTIFY previewChanged)
4850 Q_PROPERTY(QString imageSourceUri READ imageSourceUri NOTIFY previewChanged)
51+ Q_PROPERTY(QVariant result READ result NOTIFY previewChanged)
4952
5053public:
5154 explicit Preview(QObject *parent = 0);
@@ -60,8 +63,10 @@ public:
6063 QVariantMap infoHintsHash() const;
6164 QString image() const;
6265 QString imageSourceUri() const;
66+ QVariant result() const;
6367
6468 Q_INVOKABLE void execute(const QString& actionId, const QHash<QString, QVariant>& hints);
69+ Q_INVOKABLE void cancelAction();
6570
6671Q_SIGNALS:
6772 void previewChanged();
@@ -70,6 +75,7 @@ protected:
7075 virtual void setUnityPreview(unity::dash::Preview::Ptr unityPreview);
7176
7277 unity::dash::Preview::Ptr m_unityPreview;
78+ Result* m_result;
7379
7480private:
7581 void setUnityPreviewBase(unity::dash::Preview::Ptr unityPreview);
@@ -77,6 +83,7 @@ private:
7783 QList<QObject *> m_actions;
7884 QList<QObject *> m_infoHints;
7985 QVariantMap m_infoHintsHash;
86+ unity::glib::Cancellable m_actionCancellable;
8087};
8188
8289Q_DECLARE_METATYPE(Preview *)
plugins/Unity/radiooptionfilter.cpp+3−1
@@ -51,7 +51,9 @@ void RadioOptionFilter::onOptionsChanged(unity::dash::RadioOptionFilter::RadioOp
5151 }
5252 m_options = new UnityOptionsModel(this, m_unityRadioOptionFilter->options,
5353 m_unityRadioOptionFilter->option_added,
54− m_unityRadioOptionFilter->option_removed);
54+ m_unityRadioOptionFilter->option_removed,
55+ m_unityRadioOptionFilter->show_all_button);
56+ connect(m_options, SIGNAL(showAllActivated()), this, SLOT(clear()));
5557
5658 m_signals << m_unityRadioOptionFilter->options.changed.connect(sigc::mem_fun(this, &RadioOptionFilter::onOptionsChanged));
5759
plugins/Unity/ratingoptionsmodel.cpp+3−3
@@ -23,11 +23,11 @@
2323// local
2424#include "ratingfilteroption.h"
2525
26−RatingOptionsModel::RatingOptionsModel(QObject *parent) :
27− GenericOptionsModel(parent)
26+RatingOptionsModel::RatingOptionsModel(bool showAllOption, QObject *parent) :
27+ GenericOptionsModel(showAllOption, parent)
2828{
2929 for (int i=1; i<=5; i++) {
3030 auto opt = new RatingFilterOption(QString::number(i), i*0.2f, this);
31− addOption(opt, i-1);
31+ addOption(opt);
3232 }
3333}
plugins/Unity/ratingoptionsmodel.h+1−1
@@ -27,7 +27,7 @@ class RatingOptionsModel : public GenericOptionsModel
2727 Q_OBJECT
2828
2929public:
30− RatingOptionsModel(QObject *parent);
30+ RatingOptionsModel(bool showAllOption, QObject *parent);
3131};
3232
3333#endif // RATINGOPTIONSMODEL_H
plugins/Unity/ratingsfilter.cpp+2−1
@@ -53,9 +53,10 @@ void RatingsFilter::setUnityFilter(unity::dash::Filter::Ptr filter)
5353
5454 delete m_options;
5555
56− m_options = new RatingOptionsModel(this);
56+ m_options = new RatingOptionsModel(m_unityRatingsFilter->show_all_button, this);
5757 connect(m_options, SIGNAL(activeChanged(AbstractFilterOption *)), m_options, SLOT(ensureTheOnlyActive(AbstractFilterOption *)));
5858 connect(m_options, SIGNAL(activeChanged(AbstractFilterOption *)), this, SLOT(onActiveChanged(AbstractFilterOption *)));
59+ connect(m_options, SIGNAL(showAllActivated()), this, SLOT(clear()));
5960
6061 Q_EMIT optionsChanged();
6162}
plugins/Unity/result.cppnew file+82
@@ -0,0 +1,82 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@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+#include "result.h"
21+#include "variantutils.h"
22+
23+Result::Result(QObject *parent) :
24+ QObject(parent)
25+{
26+}
27+
28+Result::Result(unity::dash::Preview::Ptr preview, QObject *parent) :
29+ QObject(parent),
30+ m_preview(preview)
31+{
32+}
33+
34+void Result::setPreview(unity::dash::Preview::Ptr preview)
35+{
36+ m_preview = preview;
37+}
38+
39+QString Result::uri() const
40+{
41+ return m_preview != nullptr ? QString::fromStdString(m_preview->preview_result.uri) : QString::null;
42+}
43+
44+QString Result::iconHint() const
45+{
46+ return m_preview != nullptr ? QString::fromStdString(m_preview->preview_result.icon_hint) : QString::null;
47+}
48+
49+unsigned Result::categoryIndex() const
50+{
51+ return m_preview != nullptr ? m_preview->preview_result.category_index : 0;
52+}
53+
54+unsigned Result::resultType() const
55+{
56+ return m_preview != nullptr ? m_preview->preview_result.result_type : 0;
57+}
58+
59+QString Result::mimeType() const
60+{
61+ return m_preview != nullptr ? QString::fromStdString(m_preview->preview_result.mimetype) : QString::null;
62+}
63+
64+QString Result::title() const
65+{
66+ return m_preview != nullptr ? QString::fromStdString(m_preview->preview_result.name) : QString::null;
67+}
68+
69+QString Result::comment() const
70+{
71+ return m_preview != nullptr ? QString::fromStdString(m_preview->preview_result.comment) : QString::null;
72+}
73+
74+QString Result::dndUri() const
75+{
76+ return m_preview != nullptr ? QString::fromStdString(m_preview->preview_result.dnd_uri) : QString::null;
77+}
78+
79+QVariant Result::metadata() const
80+{
81+ return m_preview != nullptr ? convertToQVariantHash(m_preview->preview_result.hints) : QVariant();
82+}
plugins/Unity/result.hnew file+69
@@ -0,0 +1,69 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@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+#ifndef RESULT_H
21+#define RESULT_H
22+
23+// Qt
24+#include <QObject>
25+#include <QVariant>
26+
27+// libunity-core
28+#include <UnityCore/Preview.h>
29+
30+class Q_DECL_EXPORT Result : public QObject
31+{
32+ Q_OBJECT
33+
34+ Q_PROPERTY(QString uri READ uri CONSTANT)
35+ Q_PROPERTY(QString iconHint READ iconHint CONSTANT)
36+ Q_PROPERTY(unsigned categoryIndex READ categoryIndex CONSTANT)
37+ Q_PROPERTY(unsigned resultType READ resultType CONSTANT)
38+ Q_PROPERTY(QString mimeType READ mimeType CONSTANT)
39+ Q_PROPERTY(QString title READ title CONSTANT)
40+ Q_PROPERTY(QString comment READ comment CONSTANT)
41+ Q_PROPERTY(QString dndUri READ dndUri CONSTANT)
42+ Q_PROPERTY(QVariant metadata READ metadata CONSTANT)
43+
44+public:
45+ Result(QObject *parent = nullptr);
46+ Result(unity::dash::Preview::Ptr preview, QObject *parent = nullptr);
47+
48+ void setPreview(unity::dash::Preview::Ptr preview);
49+
50+ QString uri() const;
51+ QString iconHint() const;
52+ unsigned categoryIndex() const;
53+ unsigned resultType() const;
54+ QString mimeType() const;
55+ QString title() const;
56+ QString comment() const;
57+ QString dndUri() const;
58+ QVariant metadata() const;
59+
60+private:
61+ /* Keep reference to the original preview to access result attributes via it, rather than keeping copies of them;
62+ this will save us a bit on copying, especially as UI is mostly interested in just uri.
63+ */
64+ unity::dash::Preview::Ptr m_preview;
65+};
66+
67+Q_DECLARE_METATYPE(Result *)
68+
69+#endif
plugins/Unity/scope.cpp+20−1
@@ -175,7 +175,19 @@ void Scope::preview(const QVariant &uri, const QVariant &icon_hint, const QVaria
175175 const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
176176{
177177 auto res = createLocalResult(uri, icon_hint, category, result_type, mimetype, title, comment, dnd_uri, metadata);
178− m_unityScope->Preview(res);
178+ m_previewCancellable.Renew();
179+
180+ // canned queries don't have previews, must be activated
181+ if (uri.toString().startsWith("x-unity-no-preview-scopes-query://")) {
182+ m_unityScope->Activate(res);
183+ } else {
184+ m_unityScope->Preview(res, nullptr, m_previewCancellable);
185+ }
186+}
187+
188+void Scope::cancelActivation()
189+{
190+ m_previewCancellable.Cancel();
179191}
180192
181193void Scope::onActivated(unity::dash::LocalResult const& result, unity::dash::ScopeHandledType type, unity::glib::HintsMap const& hints)
@@ -199,6 +211,13 @@ void Scope::onActivated(unity::dash::LocalResult const& result, unity::dash::Sco
199211 qWarning() << "Missing goto-uri hint for GOTO_DASH_URI activation reply";
200212 }
201213 break;
214+ case unity::dash::PERFORM_SEARCH:
215+ if (hints.find("query") != hints.end()) {
216+ // note: this will emit searchQueryChanged, and shell will call setSearchQuery back with a new query,
217+ // but it will get ignored.
218+ setSearchQuery(QString::fromStdString(g_variant_get_string(hints.at("query"), nullptr)));
219+ }
220+ break;
202221 default:
203222 qWarning() << "Unhandled activation response:" << type;
204223 }
plugins/Unity/scope.h+3
@@ -82,6 +82,8 @@ public:
8282 Q_INVOKABLE void preview(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
8383 const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
8484 const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata);
85+ Q_INVOKABLE void cancelActivation();
86+
8587 void setUnityScope(const unity::dash::Scope::Ptr& scope);
8688 unity::dash::Scope::Ptr unityScope() const;
8789
@@ -131,6 +133,7 @@ private:
131133 QString m_searchQuery;
132134 QString m_noResultsHint;
133135 QString m_formFactor;
136+ unity::glib::Cancellable m_previewCancellable;
134137};
135138
136139Q_DECLARE_METATYPE(Scope*)
plugins/Unity/showallfilteroption.cppnew file+60
@@ -0,0 +1,60 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@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+// self
21+#include "showallfilteroption.h"
22+
23+#include <libintl.h>
24+
25+unsigned int ShowAllFilterOption::m_showAllCount = 0;
26+
27+ShowAllFilterOption::ShowAllFilterOption(QObject *parent) :
28+ AbstractFilterOption(parent),
29+ m_active(false)
30+{
31+ m_id = QString("show_all::%1").arg(m_showAllCount++);
32+}
33+
34+QString ShowAllFilterOption::id() const
35+{
36+ return m_id;
37+}
38+
39+QString ShowAllFilterOption::name() const
40+{
41+ return QString::fromUtf8(dgettext("unity", "All"));
42+}
43+
44+QString ShowAllFilterOption::iconHint() const
45+{
46+ return QString::Null();
47+}
48+
49+bool ShowAllFilterOption::active() const
50+{
51+ return m_active;
52+}
53+
54+void ShowAllFilterOption::setActive(bool active)
55+{
56+ if (active != m_active) {
57+ m_active = active;
58+ Q_EMIT activeChanged(m_active);
59+ }
60+}
plugins/Unity/showallfilteroption.hnew file+51
@@ -0,0 +1,51 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@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+#ifndef SHOWALLFILTEROPTION_H
21+#define SHOWALLFILTEROPTION_H
22+
23+// local
24+#include "abstractfilteroption.h"
25+
26+class Q_DECL_EXPORT ShowAllFilterOption : public AbstractFilterOption
27+{
28+ Q_OBJECT
29+
30+public:
31+ explicit ShowAllFilterOption(QObject *parent = nullptr);
32+
33+ /* getters */
34+ QString id() const override;
35+ QString name() const override;
36+ QString iconHint() const override;
37+ bool active() const override;
38+
39+ /* setters */
40+ void setActive(bool active) override;
41+
42+private:
43+ bool m_active;
44+ QString m_id;
45+
46+ static unsigned int m_showAllCount;
47+};
48+
49+Q_DECLARE_METATYPE(ShowAllFilterOption*)
50+
51+#endif // SHOWALLFILTEROPTION_H
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/Unity/unityoptionsmodel.cpp+5−4
@@ -26,8 +26,9 @@
2626UnityOptionsModel::UnityOptionsModel(QObject *parent,
2727 const std::vector<unity::dash::FilterOption::Ptr> options,
2828 sigc::signal<void, unity::dash::FilterOption::Ptr> optionAdded,
29− sigc::signal<void, unity::dash::FilterOption::Ptr> optionRemoved) :
30− GenericOptionsModel(parent)
29+ sigc::signal<void, unity::dash::FilterOption::Ptr> optionRemoved,
30+ bool showAllOption) :
31+ GenericOptionsModel(showAllOption, parent)
3132{
3233 setOptions(options, optionAdded, optionRemoved);
3334}
@@ -38,7 +39,7 @@ void UnityOptionsModel::setOptions(const std::vector<unity::dash::FilterOption::
3839{
3940 for (unsigned int i=0; i<options.size(); i++)
4041 {
41− addOption(new FilterOption(options[i], this), i);
42+ addOption(new FilterOption(options[i], this));
4243 }
4344 optionAdded.connect(sigc::mem_fun(this, &UnityOptionsModel::onOptionAdded));
4445 optionRemoved.connect(sigc::mem_fun(this, &UnityOptionsModel::onOptionRemoved));
@@ -50,7 +51,7 @@ void UnityOptionsModel::onOptionAdded(unity::dash::FilterOption::Ptr option)
5051 if (index >= 0)
5152 {
5253 beginInsertRows(QModelIndex(), index, index);
53− addOption(new FilterOption(option, this), index);
54+ addOption(new FilterOption(option, this));
5455 endInsertRows();
5556 }
5657}
plugins/Unity/unityoptionsmodel.h+2−1
@@ -35,7 +35,8 @@ public:
3535 UnityOptionsModel(QObject *parent,
3636 const std::vector<unity::dash::FilterOption::Ptr> options,
3737 sigc::signal<void, unity::dash::FilterOption::Ptr> optionAdded,
38− sigc::signal<void, unity::dash::FilterOption::Ptr> optionRemoved);
38+ sigc::signal<void, unity::dash::FilterOption::Ptr> optionRemoved,
39+ bool showAllOption);
3940
4041private:
4142 void setOptions(const std::vector<unity::dash::FilterOption::Ptr> options,
plugins/Unity/variantutils.cpp+9
@@ -40,3 +40,12 @@ unity::glib::HintsMap convertToHintsMap(const QVariant &var)
4040 }
4141 return unity::glib::HintsMap();
4242}
43+
44+QVariantHash convertToQVariantHash(const unity::glib::HintsMap& var)
45+{
46+ QVariantHash hash;
47+ for (auto hint: var) {
48+ hash.insert(QString::fromStdString(hint.first), DeeListModel::VariantForData(hint.second));
49+ }
50+ return hash;
51+}
plugins/Unity/variantutils.h+1
@@ -28,5 +28,6 @@
2828
2929unity::glib::HintsMap convertToHintsMap(const QHash<QString, QVariant> &val);
3030unity::glib::HintsMap convertToHintsMap(const QVariant &var);
31+QVariantHash convertToQVariantHash(const unity::glib::HintsMap& var);
3132
3233#endif
plugins/Utils/qsortfilterproxymodelqml.cpp+32
@@ -29,6 +29,17 @@ QSortFilterProxyModelQML::QSortFilterProxyModelQML(QObject *parent)
2929 connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(countChanged()));
3030}
3131
32+/*
33+ * Enter row index of filtered/sorted model, returns row index of source model
34+ */
35+int QSortFilterProxyModelQML::mapRowToSource(int row)
36+{
37+ if (sourceModel() == NULL)
38+ return -1;
39+
40+ return QSortFilterProxyModel::mapToSource(index(row, 0)).row();
41+}
42+
3243QHash<int, QByteArray> QSortFilterProxyModelQML::roleNames() const
3344{
3445 return sourceModel() ? sourceModel()->roleNames() : QHash<int, QByteArray>();
@@ -51,6 +62,7 @@ QSortFilterProxyModelQML::setModel(QAbstractItemModel *itemModel)
5162 connect(itemModel, SIGNAL(modelReset()), SIGNAL(totalCountChanged()));
5263 connect(itemModel, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(totalCountChanged()));
5364 connect(itemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(totalCountChanged()));
65+
5466 Q_EMIT totalCountChanged();
5567 Q_EMIT modelChanged();
5668 }
@@ -121,3 +133,23 @@ QSortFilterProxyModelQML::findFirst(int role, const QVariant& value) const
121133 return -1;
122134 }
123135}
136+
137+int
138+QSortFilterProxyModelQML::mapFromSource(int row)
139+{
140+ if (sourceModel() != NULL) {
141+ return QSortFilterProxyModel::mapFromSource(sourceModel()->index(row, 0)).row();
142+ } else {
143+ return -1;
144+ }
145+}
146+
147+int
148+QSortFilterProxyModelQML::mapToSource(int row)
149+{
150+ if (sourceModel() != NULL) {
151+ return QSortFilterProxyModel::mapToSource(index(row, 0)).row();
152+ } else {
153+ return -1;
154+ }
155+}
plugins/Utils/qsortfilterproxymodelqml.h+4
@@ -34,6 +34,7 @@ public:
3434 Q_INVOKABLE QVariant data(int row, int role);
3535 Q_INVOKABLE int count();
3636 Q_INVOKABLE int findFirst(int role, const QVariant& value) const;
37+ Q_INVOKABLE int mapRowToSource(int row);
3738 virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
3839
3940 /* getters */
@@ -45,6 +46,9 @@ public:
4546 void setModel(QAbstractItemModel *model);
4647 void setInvertMatch(bool invertMatch);
4748
49+ Q_INVOKABLE int mapFromSource(int row);
50+ Q_INVOKABLE int mapToSource(int row);
51+
4852Q_SIGNALS:
4953 void totalCountChanged();
5054 void countChanged();
po/ar.po+2−29
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n % 100 >= "
1818"3 && n % 100 <= 10 ? 3 : n % 100 >= 11 && n % 100 <= 99 ? 4 : 5;\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
19+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20+"X-Generator: Launchpad (build 16750)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
@@ -254,30 +254,3 @@ msgstr "عذراً، لا يوجد ما يطابق بحثك."
254254#, qt-format
255255msgid "Please enter %1"
256256msgstr ""
257−
258−#~ msgid "Running apps"
259−#~ msgstr "البرامج المُشغّلة"
260−
261−#~ msgid "Frequently used"
262−#~ msgstr "مُستخدمة بكثرة"
263−
264−#~ msgid "Installed"
265−#~ msgstr "مُثبّتة"
266−
267−#~ msgid "Available for download"
268−#~ msgstr "متوفرة للتنزيل"
269−
270−#~ msgid "Apps"
271−#~ msgstr "تطبيقات"
272−
273−#~ msgid "Frequent Apps"
274−#~ msgstr "تطبيقات مألوفة"
275−
276−#~ msgid "Recent Music"
277−#~ msgstr "آخر الصوتيات المشغلة"
278−
279−#~ msgid "Videos Popular Online"
280−#~ msgstr "فيديوهات رائجة على الإنترنت"
281−
282−#~ msgid "Home"
283−#~ msgstr "الرئيسية"
po/az.po+2−8
@@ -15,8 +15,8 @@ msgstr ""
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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "Bağışlayın, amma axtarışınıza heç bir nəticə uyğun gəlmir."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Tətbiqlər"
259−
260−#~ msgid "Home"
261−#~ msgstr "Ev"
po/bg.po+2−11
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Type: text/plain; charset=UTF-8\n"
1717"Content-Transfer-Encoding: 8bit\n"
1818"Plural-Forms: nplurals=2; plural=n != 1;\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
19+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20+"X-Generator: Launchpad (build 16750)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
@@ -254,12 +254,3 @@ msgstr "Съжаляваме, няма нищо, което да отговар
254254#, qt-format
255255msgid "Please enter %1"
256256msgstr ""
257−
258−#~ msgid "Installed"
259−#~ msgstr "Инсталирани"
260−
261−#~ msgid "Apps"
262−#~ msgstr "Приложения"
263−
264−#~ msgid "Home"
265−#~ msgstr "Начало"
po/ca.po+52−73
@@ -8,123 +8,129 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-06-27 00:24+0000\n"
12−"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
11+"PO-Revision-Date: 2013-09-28 07:38+0000\n"
12+"Last-Translator: David Planella <david.planella@ubuntu.com>\n"
1313"Language-Team: Catalan <ca@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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-09-29 06:18+0000\n"
19+"X-Generator: Launchpad (build 16774)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
23−msgstr ""
23+msgstr "Telèfon"
2424
2525#: Applications/applications.js:29
2626msgid "Camera"
27−msgstr ""
27+msgstr "Càmera"
2828
2929#: Applications/applications.js:35
3030msgid "Gallery"
31−msgstr ""
31+msgstr "Galeria"
3232
3333#: Applications/applications.js:40
3434msgid "Facebook"
35−msgstr ""
35+msgstr "Facebook"
3636
3737#: Applications/applications.js:46
3838msgid "Browser"
39−msgstr ""
39+msgstr "Navegador"
4040
4141#: Applications/applications.js:51
4242msgid "Twitter"
43−msgstr ""
43+msgstr "Twitter"
4444
4545#: Applications/applications.js:57
4646msgid "GMail"
47−msgstr ""
47+msgstr "GMail"
4848
4949#: Applications/applications.js:62
5050msgid "Weather"
51−msgstr ""
51+msgstr "El temps"
5252
5353#: Applications/applications.js:68
5454msgid "Notepad"
55−msgstr ""
55+msgstr "Bloc de notes"
5656
5757#: Applications/applications.js:74
5858msgid "Calendar"
59−msgstr ""
59+msgstr "Calendari"
6060
6161#: Applications/applications.js:80
6262msgid "Media Player"
63−msgstr ""
63+msgstr "Reproductor multimèdia"
6464
6565#: Applications/applications.js:86
6666msgid "Evernote"
67−msgstr ""
67+msgstr "Evernote"
6868
6969#: Applications/applications.js:91
7070msgid "Map"
71−msgstr ""
71+msgstr "Mapa"
7272
7373#: Applications/applications.js:96
7474msgid "Pinterest"
75−msgstr ""
75+msgstr "Pinterest"
7676
7777#: Applications/applications.js:101
7878msgid "SoundCloud"
79−msgstr ""
79+msgstr "SoundCloud"
8080
8181#: Applications/applications.js:106
8282msgid "Wikipedia"
83−msgstr ""
83+msgstr "Viquipèdia"
8484
8585#: Applications/applications.js:111
8686msgid "YouTube"
87−msgstr ""
87+msgstr "YouTube"
8888
8989#: Components/EdgeDemoOverlay.qml:145
9090msgid "Skip intro"
91−msgstr ""
91+msgstr "Omet la introducció"
9292
9393#: Components/EdgeDemo.qml:98
9494msgid "Right edge"
95−msgstr ""
95+msgstr "Vora dreta"
9696
9797#: Components/EdgeDemo.qml:99
9898msgid "Try swiping from the right edge to unlock the phone"
9999msgstr ""
100+"Proveu de lliscar el dit des de la vora dreta per desblocar el telèfon"
100101
101102#: Components/EdgeDemo.qml:135
102103msgid "Top edge"
103−msgstr ""
104+msgstr "Vora superior"
104105
105106#: Components/EdgeDemo.qml:136
106107msgid "Try swiping from the top edge to access the indicators"
107108msgstr ""
109+"Proveu de lliscar el dit des de la vora superior per accedir als indicadors"
108110
109111#: Components/EdgeDemo.qml:161
110112msgid "Close"
111−msgstr ""
113+msgstr "Tanca"
112114
113115#: Components/EdgeDemo.qml:162
114116msgid "Swipe up again to close the settings screen"
115117msgstr ""
118+"Llisqueu el dit cap amunt una altra vegada per tancar la pantalla de "
119+"configuració"
116120
117121#: Components/EdgeDemo.qml:189
118122msgid "Left edge"
119−msgstr ""
123+msgstr "Vora esquerra"
120124
121125#: Components/EdgeDemo.qml:190
122126msgid "Swipe from the left to reveal the launcher for quick access to apps"
123127msgstr ""
128+"Llisqueu el dit des de la vora esquerra per mostrar el llançador i accedir "
129+"ràpidament a les aplicacions"
124130
125131#: Components/EdgeDemo.qml:217
126132msgid "Well done"
127−msgstr ""
133+msgstr "Enhorabona!"
128134
129135#: Components/EdgeDemo.qml:218
130136msgid "You have now mastered the edge gestures and can start using the phone"
@@ -138,15 +144,15 @@ msgstr "Cerques recents"
138144#: Dash/Apps/AppInfo.qml:73
139145#, qt-format
140146msgid "(%1)"
141−msgstr ""
147+msgstr "(%1)"
142148
143149#. TRANSLATORS: Number of persons who wrote reviews for this app
144150#: Dash/Apps/AppInfo.qml:85
145151#, qt-format
146152msgid "%1 review"
147153msgid_plural "%1 reviews"
148−msgstr[0] ""
149−msgstr[1] ""
154+msgstr[0] "%1 ressenya"
155+msgstr[1] "%1 ressenyes"
150156
151157#: Dash/Apps/AppPreview.qml:175
152158msgid "Rate this"
@@ -154,35 +160,35 @@ msgstr ""
154160
155161#: Dash/Apps/AppReviews.qml:72
156162msgid "Add a review"
157−msgstr ""
163+msgstr "Afegiu una ressenya"
158164
159165#: Dash/Apps/AppReviews.qml:84
160166msgid "Review"
161−msgstr ""
167+msgstr "Ressenya"
162168
163169#: Dash/Apps/AppReviews.qml:118
164170msgid "Send"
165−msgstr ""
171+msgstr "Envia"
166172
167173#: Dash/Apps/AppReviews.qml:136
168174msgid "Comments:"
169−msgstr ""
175+msgstr "Comentaris:"
170176
171177#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
172178msgid "Featured"
173−msgstr ""
179+msgstr "Destacats"
174180
175181#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
176182msgid "Recent"
177−msgstr ""
183+msgstr "Recents"
178184
179185#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
180186msgid "New Releases"
181−msgstr ""
187+msgstr "Novetats"
182188
183189#: Dash/DashMusic.qml:30
184190msgid "Top Charting"
185−msgstr ""
191+msgstr "El millor de les llistes"
186192
187193#: Dash/DashMusic.qml:91
188194msgid "Music"
@@ -190,7 +196,7 @@ msgstr "Música"
190196
191197#: Dash/DashVideos.qml:31
192198msgid "Popular Online"
193−msgstr ""
199+msgstr "Popular a la xarxa"
194200
195201#: Dash/DashVideos.qml:146
196202msgid "Videos"
@@ -198,28 +204,28 @@ msgstr "Vídeos"
198204
199205#: Dash/Video/VideoPreview.qml:130
200206msgid "Directed by:"
201−msgstr ""
207+msgstr "Dirigit per:"
202208
203209#: Dash/Video/VideoPreview.qml:153
204210msgid "Starring:"
205−msgstr ""
211+msgstr "Protagonistes:"
206212
207213#: Dash/Video/VideoPreview.qml:176
208214msgid "Author:"
209−msgstr ""
215+msgstr "Autor:"
210216
211217#: Greeter/Lockscreen.qml:134
212218msgid "Emergency Call"
213−msgstr ""
219+msgstr "Trucada d'emergència"
214220
215221#: Greeter/PassphraseLockscreen.qml:59
216222#, qt-format
217223msgid "Hello %1"
218−msgstr ""
224+msgstr "Hola %1"
219225
220226#: Greeter/PassphraseLockscreen.qml:59
221227msgid "Hello"
222−msgstr ""
228+msgstr "Hola"
223229
224230#: Hud/HudParametrizedActionsPage.qml:132
225231msgid "Confirm"
@@ -252,31 +258,4 @@ msgstr "No hi ha res que coincideixi amb la cerca"
252258#: Shell.qml:429
253259#, qt-format
254260msgid "Please enter %1"
255−msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "Aplications actives"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "Les més freqüents"
262−
263−#~ msgid "Installed"
264−#~ msgstr "Instal·lades"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "Disponibles per baixar"
268−
269−#~ msgid "Apps"
270−#~ msgstr "Aplicacions"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "Aplicacions freqüents"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "Música recent"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "Vídeos populars en línia"
280−
281−#~ msgid "Home"
282−#~ msgstr "Inici"
261+msgstr "Introduïu %1"
po/de.po+2−29
@@ -15,8 +15,8 @@ msgstr ""
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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "Entschuldigung, es wurden keine Treffer erzielt."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "Aktive Anwendungen"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "Häufig verwendet"
262−
263−#~ msgid "Installed"
264−#~ msgstr "Installiert"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "Zum Herunterladen verfügbar"
268−
269−#~ msgid "Apps"
270−#~ msgstr "Anwendungen"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "Häufig genutzte Anwendungen"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "Zuletzt gehörte Musik"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "Beliebte Online-Videos"
280−
281−#~ msgid "Home"
282−#~ msgstr "Start"
po/el.po+2−8
@@ -15,8 +15,8 @@ msgstr ""
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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "Λυπούμαστε, δεν υπάρχει τίποτα που να τ
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Εφαρμογές"
259−
260−#~ msgid "Home"
261−#~ msgstr "Αρχή"
po/en_AU.po+27−53
@@ -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-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-06-27 01:13+0000\n"
12−"Last-Translator: Jackson Doak <Doak.jackson@gmail.com>\n"
11+"PO-Revision-Date: 2013-09-28 07:46+0000\n"
12+"Last-Translator: Jared Norris <jarednorris@ubuntu.com>\n"
1313"Language-Team: English (Australia) <en_AU@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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-09-29 06:18+0000\n"
19+"X-Generator: Launchpad (build 16774)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -88,47 +88,48 @@ msgstr "YouTube"
8888
8989#: Components/EdgeDemoOverlay.qml:145
9090msgid "Skip intro"
91−msgstr ""
91+msgstr "Skip intro"
9292
9393#: Components/EdgeDemo.qml:98
9494msgid "Right edge"
95−msgstr ""
95+msgstr "Right edge"
9696
9797#: Components/EdgeDemo.qml:99
9898msgid "Try swiping from the right edge to unlock the phone"
99−msgstr ""
99+msgstr "Try swiping from the right edge to unlock the phone"
100100
101101#: Components/EdgeDemo.qml:135
102102msgid "Top edge"
103−msgstr ""
103+msgstr "Top edge"
104104
105105#: Components/EdgeDemo.qml:136
106106msgid "Try swiping from the top edge to access the indicators"
107−msgstr ""
107+msgstr "Try swiping from the top edge to access the indicators"
108108
109109#: Components/EdgeDemo.qml:161
110110msgid "Close"
111−msgstr ""
111+msgstr "Close"
112112
113113#: Components/EdgeDemo.qml:162
114114msgid "Swipe up again to close the settings screen"
115−msgstr ""
115+msgstr "Swipe up again to close the settings screen"
116116
117117#: Components/EdgeDemo.qml:189
118118msgid "Left edge"
119−msgstr ""
119+msgstr "Left edge"
120120
121121#: Components/EdgeDemo.qml:190
122122msgid "Swipe from the left to reveal the launcher for quick access to apps"
123−msgstr ""
123+msgstr "Swipe from the left to reveal the launcher for quick access to apps"
124124
125125#: Components/EdgeDemo.qml:217
126126msgid "Well done"
127−msgstr ""
127+msgstr "Well done"
128128
129129#: Components/EdgeDemo.qml:218
130130msgid "You have now mastered the edge gestures and can start using the phone"
131131msgstr ""
132+"You have now mastered the edge gestures and can start using the phone"
132133
133134#: Components/PageHeader.qml:298
134135msgid "Recent searches"
@@ -138,35 +139,35 @@ msgstr "Recent searches"
138139#: Dash/Apps/AppInfo.qml:73
139140#, qt-format
140141msgid "(%1)"
141−msgstr ""
142+msgstr "(%1)"
142143
143144#. TRANSLATORS: Number of persons who wrote reviews for this app
144145#: Dash/Apps/AppInfo.qml:85
145146#, qt-format
146147msgid "%1 review"
147148msgid_plural "%1 reviews"
148−msgstr[0] ""
149−msgstr[1] ""
149+msgstr[0] "%1 review"
150+msgstr[1] "%1 reviews"
150151
151152#: Dash/Apps/AppPreview.qml:175
152153msgid "Rate this"
153−msgstr ""
154+msgstr "Rate this"
154155
155156#: Dash/Apps/AppReviews.qml:72
156157msgid "Add a review"
157−msgstr ""
158+msgstr "Add a review"
158159
159160#: Dash/Apps/AppReviews.qml:84
160161msgid "Review"
161−msgstr ""
162+msgstr "Review"
162163
163164#: Dash/Apps/AppReviews.qml:118
164165msgid "Send"
165−msgstr ""
166+msgstr "Send"
166167
167168#: Dash/Apps/AppReviews.qml:136
168169msgid "Comments:"
169−msgstr ""
170+msgstr "Comments:"
170171
171172#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
172173msgid "Featured"
@@ -210,16 +211,16 @@ msgstr "Author:"
210211
211212#: Greeter/Lockscreen.qml:134
212213msgid "Emergency Call"
213−msgstr ""
214+msgstr "Emergency Call"
214215
215216#: Greeter/PassphraseLockscreen.qml:59
216217#, qt-format
217218msgid "Hello %1"
218−msgstr ""
219+msgstr "Hello %1"
219220
220221#: Greeter/PassphraseLockscreen.qml:59
221222msgid "Hello"
222−msgstr ""
223+msgstr "Hello"
223224
224225#: Hud/HudParametrizedActionsPage.qml:132
225226msgid "Confirm"
@@ -252,31 +253,4 @@ msgstr "Sorry, there is nothing that matches your search."
252253#: Shell.qml:429
253254#, qt-format
254255msgid "Please enter %1"
255−msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "Running apps"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "Frequently used"
262−
263−#~ msgid "Installed"
264−#~ msgstr "Installed"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "Available for download"
268−
269−#~ msgid "Apps"
270−#~ msgstr "Apps"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "Frequent Apps"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "Recent Music"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "Videos Popular Online"
280−
281−#~ msgid "Home"
282−#~ msgstr "Home"
256+msgstr "Please enter %1"
po/en_GB.po+2−29
@@ -15,8 +15,8 @@ msgstr ""
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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "Sorry, there is nothing that matches your search."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr "Please enter %1"
256−
257−#~ msgid "Running apps"
258−#~ msgstr "Running apps"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "Frequently used"
262−
263−#~ msgid "Installed"
264−#~ msgstr "Installed"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "Available for download"
268−
269−#~ msgid "Apps"
270−#~ msgstr "Apps"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "Frequent Apps"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "Recent Music"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "Videos Popular Online"
280−
281−#~ msgid "Home"
282−#~ msgstr "Home"
po/eo.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/es.po+26−51
@@ -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-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-07-08 07:25+0000\n"
12−"Last-Translator: Adolfo Jayme Barrientos <fitoschido@gmail.com>\n"
11+"PO-Revision-Date: 2013-09-28 07:35+0000\n"
12+"Last-Translator: Paco Molinero <paco@byasl.com>\n"
1313"Language-Team: Spanish <es@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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-09-29 06:18+0000\n"
19+"X-Generator: Launchpad (build 16774)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -48,7 +48,7 @@ msgstr "GMail"
4848
4949#: Applications/applications.js:62
5050msgid "Weather"
51−msgstr "Metereología"
51+msgstr "Meteorología"
5252
5353#: Applications/applications.js:68
5454msgid "Notepad"
@@ -88,47 +88,49 @@ msgstr "YouTube"
8888
8989#: Components/EdgeDemoOverlay.qml:145
9090msgid "Skip intro"
91−msgstr ""
91+msgstr "Omitir la introducción"
9292
9393#: Components/EdgeDemo.qml:98
9494msgid "Right edge"
95−msgstr ""
95+msgstr "Borde derecho"
9696
9797#: Components/EdgeDemo.qml:99
9898msgid "Try swiping from the right edge to unlock the phone"
99−msgstr ""
99+msgstr "Deslice el dedo desde el borde derecho para desbloquear el teléfono"
100100
101101#: Components/EdgeDemo.qml:135
102102msgid "Top edge"
103−msgstr ""
103+msgstr "Borde superior"
104104
105105#: Components/EdgeDemo.qml:136
106106msgid "Try swiping from the top edge to access the indicators"
107−msgstr ""
107+msgstr "Deslice el dedo desde el borde superior para acceder a los menús"
108108
109109#: Components/EdgeDemo.qml:161
110110msgid "Close"
111−msgstr ""
111+msgstr "Cerrar"
112112
113113#: Components/EdgeDemo.qml:162
114114msgid "Swipe up again to close the settings screen"
115−msgstr ""
115+msgstr "Deslice hacia arriba para cerrar la pantalla de configuración"
116116
117117#: Components/EdgeDemo.qml:189
118118msgid "Left edge"
119−msgstr ""
119+msgstr "Borde izquierdo"
120120
121121#: Components/EdgeDemo.qml:190
122122msgid "Swipe from the left to reveal the launcher for quick access to apps"
123123msgstr ""
124+"Deslice el dedo desde la izquierda para mostrar el lanzador y acceder "
125+"rápidamente a las aplicaciones"
124126
125127#: Components/EdgeDemo.qml:217
126128msgid "Well done"
127−msgstr ""
129+msgstr "Bien hecho"
128130
129131#: Components/EdgeDemo.qml:218
130132msgid "You have now mastered the edge gestures and can start using the phone"
131−msgstr ""
133+msgstr "Ahora domina el uso de gestos de los bordes. Puede usar el teléfono"
132134
133135#: Components/PageHeader.qml:298
134136msgid "Recent searches"
@@ -138,35 +140,35 @@ msgstr "Búsquedas recientes"
138140#: Dash/Apps/AppInfo.qml:73
139141#, qt-format
140142msgid "(%1)"
141−msgstr ""
143+msgstr "(%1)"
142144
143145#. TRANSLATORS: Number of persons who wrote reviews for this app
144146#: Dash/Apps/AppInfo.qml:85
145147#, qt-format
146148msgid "%1 review"
147149msgid_plural "%1 reviews"
148−msgstr[0] ""
149−msgstr[1] ""
150+msgstr[0] "%1 reseña"
151+msgstr[1] "%1 reseñas"
150152
151153#: Dash/Apps/AppPreview.qml:175
152154msgid "Rate this"
153−msgstr ""
155+msgstr "Valorar esto"
154156
155157#: Dash/Apps/AppReviews.qml:72
156158msgid "Add a review"
157−msgstr ""
159+msgstr "Añadir una reseña"
158160
159161#: Dash/Apps/AppReviews.qml:84
160162msgid "Review"
161−msgstr ""
163+msgstr "Reseñar"
162164
163165#: Dash/Apps/AppReviews.qml:118
164166msgid "Send"
165−msgstr ""
167+msgstr "Enviar"
166168
167169#: Dash/Apps/AppReviews.qml:136
168170msgid "Comments:"
169−msgstr ""
171+msgstr "Comentarios:"
170172
171173#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
172174msgid "Featured"
@@ -210,7 +212,7 @@ msgstr "Autor:"
210212
211213#: Greeter/Lockscreen.qml:134
212214msgid "Emergency Call"
213−msgstr ""
215+msgstr "Llamada de emergencia"
214216
215217#: Greeter/PassphraseLockscreen.qml:59
216218#, qt-format
@@ -253,30 +255,3 @@ msgstr "No hay nada que coincida con su búsqueda."
253255#, qt-format
254256msgid "Please enter %1"
255257msgstr "Introduzca %1"
256−
257−#~ msgid "Running apps"
258−#~ msgstr "Aplicaciones en ejecución"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "Usadas frecuentemente"
262−
263−#~ msgid "Installed"
264−#~ msgstr "Instaladas"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "Disponibles para descargar"
268−
269−#~ msgid "Apps"
270−#~ msgstr "Aplicaciones"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "Aplicaciones frecuentes"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "Música reciente"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "Vídeos populares en línea"
280−
281−#~ msgid "Home"
282−#~ msgstr "Inicio"
po/fi.po+15−42
@@ -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-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-08-23 16:15+0000\n"
12−"Last-Translator: Timo Jyrinki <timo.jyrinki@canonical.com>\n"
11+"PO-Revision-Date: 2013-09-26 09:25+0000\n"
12+"Last-Translator: Jiri Grönroos <Unknown>\n"
1313"Language-Team: Finnish <fi@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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-09-27 06:43+0000\n"
19+"X-Generator: Launchpad (build 16774)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -88,47 +88,47 @@ msgstr "YouTube"
8888
8989#: Components/EdgeDemoOverlay.qml:145
9090msgid "Skip intro"
91−msgstr ""
91+msgstr "Ohita esittely"
9292
9393#: Components/EdgeDemo.qml:98
9494msgid "Right edge"
95−msgstr ""
95+msgstr "Oikea reuna"
9696
9797#: Components/EdgeDemo.qml:99
9898msgid "Try swiping from the right edge to unlock the phone"
99−msgstr ""
99+msgstr "Vedä oikealta avataksesi puhelimen lukituksen"
100100
101101#: Components/EdgeDemo.qml:135
102102msgid "Top edge"
103−msgstr ""
103+msgstr "Yläreuna"
104104
105105#: Components/EdgeDemo.qml:136
106106msgid "Try swiping from the top edge to access the indicators"
107−msgstr ""
107+msgstr "Vedä yläreunasta käyttääksesi ilmaisimia"
108108
109109#: Components/EdgeDemo.qml:161
110110msgid "Close"
111−msgstr ""
111+msgstr "Sulje"
112112
113113#: Components/EdgeDemo.qml:162
114114msgid "Swipe up again to close the settings screen"
115−msgstr ""
115+msgstr "Vedä uudestaan sulkeaksesi asetusnäkymän"
116116
117117#: Components/EdgeDemo.qml:189
118118msgid "Left edge"
119−msgstr ""
119+msgstr "Vasen reuna"
120120
121121#: Components/EdgeDemo.qml:190
122122msgid "Swipe from the left to reveal the launcher for quick access to apps"
123−msgstr ""
123+msgstr "Vedä vasemmalta saattaaksesi sovellusten käynnistimen esiin"
124124
125125#: Components/EdgeDemo.qml:217
126126msgid "Well done"
127−msgstr ""
127+msgstr "Hyvin tehty"
128128
129129#: Components/EdgeDemo.qml:218
130130msgid "You have now mastered the edge gestures and can start using the phone"
131−msgstr ""
131+msgstr "Hallitset nyt reunaeleet, joten voit aloittaa puhelimen käytön"
132132
133133#: Components/PageHeader.qml:298
134134msgid "Recent searches"
@@ -253,30 +253,3 @@ msgstr "Hakuun täsmääviä tuloksia ei löydy."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr "Kirjoita %1"
256−
257−#~ msgid "Running apps"
258−#~ msgstr "Käynnissä olevat sovellukset"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "Usein käytetyt"
262−
263−#~ msgid "Installed"
264−#~ msgstr "Asennetut"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "Ladattavissa"
268−
269−#~ msgid "Apps"
270−#~ msgstr "Sovellukset"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "Yleisimmät sovellukset"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "Viimeisin musiikki"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "Suositut verkkovideot"
280−
281−#~ msgid "Home"
282−#~ msgstr "Kotinäyttö"
po/fo.po+2−8
@@ -15,8 +15,8 @@ msgstr ""
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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "Tíanverri er tað einki sum hóskar til tína leiting."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Nýtsluskipanir"
259−
260−#~ msgid "Home"
261−#~ msgstr "Heim"
po/fr.po+2−5
@@ -15,8 +15,8 @@ msgstr ""
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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,6 +253,3 @@ msgstr ""
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Applications"
po/gd.ponew file+266
@@ -0,0 +1,266 @@
1+# Gaelic; Scottish translation for unity8
2+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
3+# This file is distributed under the same license as the unity8 package.
4+# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
5+#
6+msgid ""
7+msgstr ""
8+"Project-Id-Version: unity8\n"
9+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10+"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11+"PO-Revision-Date: 2013-09-30 10:34+0000\n"
12+"Last-Translator: Akerbeltz <fios@akerbeltz.org>\n"
13+"Language-Team: Gaelic; Scottish <gd@li.org>\n"
14+"MIME-Version: 1.0\n"
15+"Content-Type: text/plain; charset=UTF-8\n"
16+"Content-Transfer-Encoding: 8bit\n"
17+"Plural-Forms: nplurals=4; plural=(n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : "
18+"(n > 2 && n < 20) ? 2 : 3;\n"
19+"X-Launchpad-Export-Date: 2013-10-01 05:53+0000\n"
20+"X-Generator: Launchpad (build 16774)\n"
21+
22+#: Applications/applications.js:23
23+msgid "Phone"
24+msgstr "Fòn"
25+
26+#: Applications/applications.js:29
27+msgid "Camera"
28+msgstr "Camara"
29+
30+#: Applications/applications.js:35
31+msgid "Gallery"
32+msgstr "Gailearaidh"
33+
34+#: Applications/applications.js:40
35+msgid "Facebook"
36+msgstr "Facebook"
37+
38+#: Applications/applications.js:46
39+msgid "Browser"
40+msgstr "Brabhsair"
41+
42+#: Applications/applications.js:51
43+msgid "Twitter"
44+msgstr "Twitter"
45+
46+#: Applications/applications.js:57
47+msgid "GMail"
48+msgstr "GMail"
49+
50+#: Applications/applications.js:62
51+msgid "Weather"
52+msgstr "An aimsir"
53+
54+#: Applications/applications.js:68
55+msgid "Notepad"
56+msgstr "Pada nan nòtaichean"
57+
58+#: Applications/applications.js:74
59+msgid "Calendar"
60+msgstr "Am mìosachan"
61+
62+#: Applications/applications.js:80
63+msgid "Media Player"
64+msgstr "Cluicheadair mheadhanan"
65+
66+#: Applications/applications.js:86
67+msgid "Evernote"
68+msgstr "Evernote"
69+
70+#: Applications/applications.js:91
71+msgid "Map"
72+msgstr "Mapa"
73+
74+#: Applications/applications.js:96
75+msgid "Pinterest"
76+msgstr "Pinterest"
77+
78+#: Applications/applications.js:101
79+msgid "SoundCloud"
80+msgstr "SoundCloud"
81+
82+#: Applications/applications.js:106
83+msgid "Wikipedia"
84+msgstr "An Uicipeid"
85+
86+#: Applications/applications.js:111
87+msgid "YouTube"
88+msgstr "YouTube"
89+
90+#: Components/EdgeDemoOverlay.qml:145
91+msgid "Skip intro"
92+msgstr "Gearr leum thairis air an ro-ràdh"
93+
94+#: Components/EdgeDemo.qml:98
95+msgid "Right edge"
96+msgstr "An oir dheas"
97+
98+#: Components/EdgeDemo.qml:99
99+msgid "Try swiping from the right edge to unlock the phone"
100+msgstr ""
101+"Feuch is dèan grad-shlaighdeadh a-steach on oir dheas gus a' ghlas a thoirt "
102+"far an fhòn"
103+
104+#: Components/EdgeDemo.qml:135
105+msgid "Top edge"
106+msgstr "An oir aig a' bharr"
107+
108+#: Components/EdgeDemo.qml:136
109+msgid "Try swiping from the top edge to access the indicators"
110+msgstr ""
111+"Feuch is dèan grad-shlaighdeadh a-steach on oir aig a' bharr gus greim "
112+"fhaighinn air na taisbeanairean"
113+
114+#: Components/EdgeDemo.qml:161
115+msgid "Close"
116+msgstr "Dùin"
117+
118+#: Components/EdgeDemo.qml:162
119+msgid "Swipe up again to close the settings screen"
120+msgstr "Dèan grad-shlaighdeadh a-nìos gus sgrìn nan roghainnean a dhùnadh"
121+
122+#: Components/EdgeDemo.qml:189
123+msgid "Left edge"
124+msgstr "An oir chlì"
125+
126+#: Components/EdgeDemo.qml:190
127+msgid "Swipe from the left to reveal the launcher for quick access to apps"
128+msgstr ""
129+"Dèan grad-shlaighdeadh on oir chlì air an lòinseir a bheir dhut cothrom "
130+"luath air na h-aplacaidean"
131+
132+#: Components/EdgeDemo.qml:217
133+msgid "Well done"
134+msgstr "Gasta!"
135+
136+#: Components/EdgeDemo.qml:218
137+msgid "You have now mastered the edge gestures and can start using the phone"
138+msgstr ""
139+"Dh'ionnsaich thu mar a dh'obraicheas na gluasadan air an oir agus is urrainn "
140+"dhut am fòn a chleachdadh a-nis"
141+
142+#: Components/PageHeader.qml:298
143+msgid "Recent searches"
144+msgstr "Na lorg thu o chionn goirid"
145+
146+#. TRANSLATORS: Number of persons who rated this app
147+#: Dash/Apps/AppInfo.qml:73
148+#, qt-format
149+msgid "(%1)"
150+msgstr "(%1)"
151+
152+#. TRANSLATORS: Number of persons who wrote reviews for this app
153+#: Dash/Apps/AppInfo.qml:85
154+#, qt-format
155+msgid "%1 review"
156+msgid_plural "%1 reviews"
157+msgstr[0] "%1 lèirmheas"
158+msgstr[1] "%1 lèirmheas"
159+msgstr[2] "%1 lèirmheasan"
160+msgstr[3] "%1 lèirmheas"
161+
162+#: Dash/Apps/AppPreview.qml:175
163+msgid "Rate this"
164+msgstr "Rangaich seo"
165+
166+#: Dash/Apps/AppReviews.qml:72
167+msgid "Add a review"
168+msgstr "Cuir lèirmheas ris"
169+
170+#: Dash/Apps/AppReviews.qml:84
171+msgid "Review"
172+msgstr "Lèirmheas"
173+
174+#: Dash/Apps/AppReviews.qml:118
175+msgid "Send"
176+msgstr "Cuir"
177+
178+#: Dash/Apps/AppReviews.qml:136
179+msgid "Comments:"
180+msgstr "Beachdan"
181+
182+#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
183+msgid "Featured"
184+msgstr "Brosnaichte"
185+
186+#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
187+msgid "Recent"
188+msgstr "O chionn goirid"
189+
190+#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
191+msgid "New Releases"
192+msgstr "Air ùr-sgaoileadh"
193+
194+#: Dash/DashMusic.qml:30
195+msgid "Top Charting"
196+msgstr "Gràinnean-mullaich nan cairt"
197+
198+#: Dash/DashMusic.qml:91
199+msgid "Music"
200+msgstr "Ceòl"
201+
202+#: Dash/DashVideos.qml:31
203+msgid "Popular Online"
204+msgstr "Fèill mhòr air air loidhne"
205+
206+#: Dash/DashVideos.qml:146
207+msgid "Videos"
208+msgstr "Videothan"
209+
210+#: Dash/Video/VideoPreview.qml:130
211+msgid "Directed by:"
212+msgstr "Air a stiùireadh le:"
213+
214+#: Dash/Video/VideoPreview.qml:153
215+msgid "Starring:"
216+msgstr "Leis na daoine a leanas:"
217+
218+#: Dash/Video/VideoPreview.qml:176
219+msgid "Author:"
220+msgstr "Ùghdar:"
221+
222+#: Greeter/Lockscreen.qml:134
223+msgid "Emergency Call"
224+msgstr "Gairm èiginn"
225+
226+#: Greeter/PassphraseLockscreen.qml:59
227+#, qt-format
228+msgid "Hello %1"
229+msgstr "Shin thu, %1"
230+
231+#: Greeter/PassphraseLockscreen.qml:59
232+msgid "Hello"
233+msgstr "Shin thu"
234+
235+#: Hud/HudParametrizedActionsPage.qml:132
236+msgid "Confirm"
237+msgstr "Dearbhaich"
238+
239+#: Hud/Hud.qml:61 Hud/Hud.qml:99 Hud/Hud.qml:372
240+msgid "Type or say a command"
241+msgstr "Sgrìobh no can àithne"
242+
243+#: Hud/Hud.qml:84
244+msgid "Loading. Please Wait..."
245+msgstr "'Ga luchdadh, fuirich ort..."
246+
247+#: Hud/Hud.qml:89
248+msgid "Speak Now..."
249+msgstr "Can rud a-nis..."
250+
251+#: Hud/Hud.qml:94
252+msgid "Speaking..."
253+msgstr "A' bruidhinn..."
254+
255+#: Panel/SearchIndicator.qml:27
256+msgid "Search"
257+msgstr "Lorg"
258+
259+#: plugins/Unity/scope.cpp:317
260+msgid "Sorry, there is nothing that matches your search."
261+msgstr "Tha sinn duilich ach chan eil dad a' freagairt ris na lorg thu."
262+
263+#: Shell.qml:429
264+#, qt-format
265+msgid "Please enter %1"
266+msgstr "Cuir a-steach %1"
po/gl.po+29−56
@@ -8,99 +8,99 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-06-27 03:38+0000\n"
12−"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
11+"PO-Revision-Date: 2013-09-29 11:14+0000\n"
12+"Last-Translator: Marcos Lans <Unknown>\n"
1313"Language-Team: Galician <gl@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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-09-30 05:57+0000\n"
19+"X-Generator: Launchpad (build 16774)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
23−msgstr ""
23+msgstr "Teléfono"
2424
2525#: Applications/applications.js:29
2626msgid "Camera"
27−msgstr ""
27+msgstr "Cámara"
2828
2929#: Applications/applications.js:35
3030msgid "Gallery"
31−msgstr ""
31+msgstr "Galería"
3232
3333#: Applications/applications.js:40
3434msgid "Facebook"
35−msgstr ""
35+msgstr "Facebook"
3636
3737#: Applications/applications.js:46
3838msgid "Browser"
39−msgstr ""
39+msgstr "Navegador"
4040
4141#: Applications/applications.js:51
4242msgid "Twitter"
43−msgstr ""
43+msgstr "Twitter"
4444
4545#: Applications/applications.js:57
4646msgid "GMail"
47−msgstr ""
47+msgstr "GMail"
4848
4949#: Applications/applications.js:62
5050msgid "Weather"
51−msgstr ""
51+msgstr "O tempo"
5252
5353#: Applications/applications.js:68
5454msgid "Notepad"
55−msgstr ""
55+msgstr "Bloc de notas"
5656
5757#: Applications/applications.js:74
5858msgid "Calendar"
59−msgstr ""
59+msgstr "Calendario"
6060
6161#: Applications/applications.js:80
6262msgid "Media Player"
63−msgstr ""
63+msgstr "Reprodutor multimedia"
6464
6565#: Applications/applications.js:86
6666msgid "Evernote"
67−msgstr ""
67+msgstr "Evernote"
6868
6969#: Applications/applications.js:91
7070msgid "Map"
71−msgstr ""
71+msgstr "Mapa"
7272
7373#: Applications/applications.js:96
7474msgid "Pinterest"
75−msgstr ""
75+msgstr "Pinterest"
7676
7777#: Applications/applications.js:101
7878msgid "SoundCloud"
79−msgstr ""
79+msgstr "SoundCloud"
8080
8181#: Applications/applications.js:106
8282msgid "Wikipedia"
83−msgstr ""
83+msgstr "Wikipedia"
8484
8585#: Applications/applications.js:111
8686msgid "YouTube"
87−msgstr ""
87+msgstr "YouTube"
8888
8989#: Components/EdgeDemoOverlay.qml:145
9090msgid "Skip intro"
91−msgstr ""
91+msgstr "Saltar introdución"
9292
9393#: Components/EdgeDemo.qml:98
9494msgid "Right edge"
95−msgstr ""
95+msgstr "Bordo dereito"
9696
9797#: Components/EdgeDemo.qml:99
9898msgid "Try swiping from the right edge to unlock the phone"
99−msgstr ""
99+msgstr "Probe a arrastrar desde o bordo dereito para desbloquear o teléfono"
100100
101101#: Components/EdgeDemo.qml:135
102102msgid "Top edge"
103−msgstr ""
103+msgstr "Bordo superior"
104104
105105#: Components/EdgeDemo.qml:136
106106msgid "Try swiping from the top edge to access the indicators"
@@ -108,7 +108,7 @@ msgstr ""
108108
109109#: Components/EdgeDemo.qml:161
110110msgid "Close"
111−msgstr ""
111+msgstr "Pechar"
112112
113113#: Components/EdgeDemo.qml:162
114114msgid "Swipe up again to close the settings screen"
@@ -116,7 +116,7 @@ msgstr ""
116116
117117#: Components/EdgeDemo.qml:189
118118msgid "Left edge"
119−msgstr ""
119+msgstr "Bordo esquerdo"
120120
121121#: Components/EdgeDemo.qml:190
122122msgid "Swipe from the left to reveal the launcher for quick access to apps"
@@ -124,7 +124,7 @@ msgstr ""
124124
125125#: Components/EdgeDemo.qml:217
126126msgid "Well done"
127−msgstr ""
127+msgstr "Ben feito"
128128
129129#: Components/EdgeDemo.qml:218
130130msgid "You have now mastered the edge gestures and can start using the phone"
@@ -138,7 +138,7 @@ msgstr "Buscas recentes"
138138#: Dash/Apps/AppInfo.qml:73
139139#, qt-format
140140msgid "(%1)"
141−msgstr ""
141+msgstr "(%1)"
142142
143143#. TRANSLATORS: Number of persons who wrote reviews for this app
144144#: Dash/Apps/AppInfo.qml:85
@@ -253,30 +253,3 @@ msgstr "Sentímolo, non hai nada que coincida con esta busca."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "Aplicativos en execución"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "Usadas frecuentemente"
262−
263−#~ msgid "Installed"
264−#~ msgstr "Instalado"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "Dispoñíbel para descargar"
268−
269−#~ msgid "Apps"
270−#~ msgstr "Aplicativos"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "Aplicativos frecuentes"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "Música recente"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "Vídeos populares en liña"
280−
281−#~ msgid "Home"
282−#~ msgstr "Cartafol persoal"
po/he.po+2−8
@@ -15,8 +15,8 @@ msgstr ""
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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "שום דבר אינו תואם לחיפוש שלך, עמך הסליחה
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "יישומים"
259−
260−#~ msgid "Home"
261−#~ msgstr "בית"
po/hr.po+2−8
@@ -16,8 +16,8 @@ msgstr ""
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-08-29 05:41+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
19+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20+"X-Generator: Launchpad (build 16750)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
@@ -254,9 +254,3 @@ msgstr "Nažalost, ne postoji ništa što odgovara vašoj pretrazi."
254254#, qt-format
255255msgid "Please enter %1"
256256msgstr ""
257−
258−#~ msgid "Apps"
259−#~ msgstr "Aplikacije"
260−
261−#~ msgid "Home"
262−#~ msgstr "Početna"
po/hu.po+2−17
@@ -15,8 +15,8 @@ msgstr ""
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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,18 +253,3 @@ msgstr "Elnézést, nincs találat a keresésre."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "Futó alkalmazások"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "Gyakran használt"
262−
263−#~ msgid "Installed"
264−#~ msgstr "Telepített"
265−
266−#~ msgid "Apps"
267−#~ msgstr "Alkalmazások"
268−
269−#~ msgid "Home"
270−#~ msgstr "Kezdőoldal"
po/hy.po+2−29
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "Կներերք, բայց Ձեր հարցումով ոչինչ չկար"
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "Բացած ծրագրեր"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "Վերջին բացածները"
262−
263−#~ msgid "Installed"
264−#~ msgstr "Տեղադրված"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "Հասանելի ծրագրեր"
268−
269−#~ msgid "Apps"
270−#~ msgstr "Ծրագրեր"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "Հաճախակի ծրագրերը"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "Վերջին երգերը"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "Հայտնի օնլայն վիդեոներ"
280−
281−#~ msgid "Home"
282−#~ msgstr "Տուն"
po/id.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/is.ponew file+256
@@ -0,0 +1,256 @@
1+# Icelandic translation for unity8
2+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
3+# This file is distributed under the same license as the unity8 package.
4+# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
5+#
6+msgid ""
7+msgstr ""
8+"Project-Id-Version: unity8\n"
9+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10+"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11+"PO-Revision-Date: 2013-09-18 16:22+0000\n"
12+"Last-Translator: Andri Thorlacius <Unknown>\n"
13+"Language-Team: Icelandic <is@li.org>\n"
14+"MIME-Version: 1.0\n"
15+"Content-Type: text/plain; charset=UTF-8\n"
16+"Content-Transfer-Encoding: 8bit\n"
17+"Plural-Forms: nplurals=2; plural=n != 1;\n"
18+"X-Launchpad-Export-Date: 2013-09-19 05:14+0000\n"
19+"X-Generator: Launchpad (build 16765)\n"
20+
21+#: Applications/applications.js:23
22+msgid "Phone"
23+msgstr "Sími"
24+
25+#: Applications/applications.js:29
26+msgid "Camera"
27+msgstr "Myndavél"
28+
29+#: Applications/applications.js:35
30+msgid "Gallery"
31+msgstr "Myndasafn"
32+
33+#: Applications/applications.js:40
34+msgid "Facebook"
35+msgstr "Facebook"
36+
37+#: Applications/applications.js:46
38+msgid "Browser"
39+msgstr "Vafri"
40+
41+#: Applications/applications.js:51
42+msgid "Twitter"
43+msgstr "Twitter"
44+
45+#: Applications/applications.js:57
46+msgid "GMail"
47+msgstr "GMail"
48+
49+#: Applications/applications.js:62
50+msgid "Weather"
51+msgstr "Veður"
52+
53+#: Applications/applications.js:68
54+msgid "Notepad"
55+msgstr "Skrifblokk"
56+
57+#: Applications/applications.js:74
58+msgid "Calendar"
59+msgstr "Dagatal"
60+
61+#: Applications/applications.js:80
62+msgid "Media Player"
63+msgstr "Margmiðlunarspilari"
64+
65+#: Applications/applications.js:86
66+msgid "Evernote"
67+msgstr "Evernote"
68+
69+#: Applications/applications.js:91
70+msgid "Map"
71+msgstr "Kort"
72+
73+#: Applications/applications.js:96
74+msgid "Pinterest"
75+msgstr "Pinterest"
76+
77+#: Applications/applications.js:101
78+msgid "SoundCloud"
79+msgstr "SoundCloud"
80+
81+#: Applications/applications.js:106
82+msgid "Wikipedia"
83+msgstr "Wikipedia"
84+
85+#: Applications/applications.js:111
86+msgid "YouTube"
87+msgstr "YouTube"
88+
89+#: Components/EdgeDemoOverlay.qml:145
90+msgid "Skip intro"
91+msgstr "Hoppa yfir kynningu"
92+
93+#: Components/EdgeDemo.qml:98
94+msgid "Right edge"
95+msgstr "Hægri brún"
96+
97+#: Components/EdgeDemo.qml:99
98+msgid "Try swiping from the right edge to unlock the phone"
99+msgstr ""
100+"Prufaðu að renna puttanum frá hægri brúninni til að aflæsa símanum þínum."
101+
102+#: Components/EdgeDemo.qml:135
103+msgid "Top edge"
104+msgstr "Efri brún"
105+
106+#: Components/EdgeDemo.qml:136
107+msgid "Try swiping from the top edge to access the indicators"
108+msgstr ""
109+
110+#: Components/EdgeDemo.qml:161
111+msgid "Close"
112+msgstr "Loka"
113+
114+#: Components/EdgeDemo.qml:162
115+msgid "Swipe up again to close the settings screen"
116+msgstr ""
117+
118+#: Components/EdgeDemo.qml:189
119+msgid "Left edge"
120+msgstr "Vinstri brún"
121+
122+#: Components/EdgeDemo.qml:190
123+msgid "Swipe from the left to reveal the launcher for quick access to apps"
124+msgstr ""
125+
126+#: Components/EdgeDemo.qml:217
127+msgid "Well done"
128+msgstr "Vel gert"
129+
130+#: Components/EdgeDemo.qml:218
131+msgid "You have now mastered the edge gestures and can start using the phone"
132+msgstr ""
133+
134+#: Components/PageHeader.qml:298
135+msgid "Recent searches"
136+msgstr "Nýlegar leitir"
137+
138+#. TRANSLATORS: Number of persons who rated this app
139+#: Dash/Apps/AppInfo.qml:73
140+#, qt-format
141+msgid "(%1)"
142+msgstr "(%1)"
143+
144+#. TRANSLATORS: Number of persons who wrote reviews for this app
145+#: Dash/Apps/AppInfo.qml:85
146+#, qt-format
147+msgid "%1 review"
148+msgid_plural "%1 reviews"
149+msgstr[0] "%1 ummæli"
150+msgstr[1] "%1 ummæli"
151+
152+#: Dash/Apps/AppPreview.qml:175
153+msgid "Rate this"
154+msgstr "Gefa þessu einkunn"
155+
156+#: Dash/Apps/AppReviews.qml:72
157+msgid "Add a review"
158+msgstr "Gefa umsögn"
159+
160+#: Dash/Apps/AppReviews.qml:84
161+msgid "Review"
162+msgstr "Umsögn"
163+
164+#: Dash/Apps/AppReviews.qml:118
165+msgid "Send"
166+msgstr "Senda"
167+
168+#: Dash/Apps/AppReviews.qml:136
169+msgid "Comments:"
170+msgstr "Athugasemdir:"
171+
172+#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
173+msgid "Featured"
174+msgstr "Efst á baugi"
175+
176+#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
177+msgid "Recent"
178+msgstr "Nýlegt"
179+
180+#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
181+msgid "New Releases"
182+msgstr "Nýjar Útgáfur"
183+
184+#: Dash/DashMusic.qml:30
185+msgid "Top Charting"
186+msgstr "Topp Listi"
187+
188+#: Dash/DashMusic.qml:91
189+msgid "Music"
190+msgstr "Tónlist"
191+
192+#: Dash/DashVideos.qml:31
193+msgid "Popular Online"
194+msgstr "Vinsælt á Netinu"
195+
196+#: Dash/DashVideos.qml:146
197+msgid "Videos"
198+msgstr "Myndbönd"
199+
200+#: Dash/Video/VideoPreview.qml:130
201+msgid "Directed by:"
202+msgstr "Leikstýrt af:"
203+
204+#: Dash/Video/VideoPreview.qml:153
205+msgid "Starring:"
206+msgstr "Meðal leikara eru:"
207+
208+#: Dash/Video/VideoPreview.qml:176
209+msgid "Author:"
210+msgstr "Höfundur:"
211+
212+#: Greeter/Lockscreen.qml:134
213+msgid "Emergency Call"
214+msgstr "Neyðarsímtal"
215+
216+#: Greeter/PassphraseLockscreen.qml:59
217+#, qt-format
218+msgid "Hello %1"
219+msgstr "Hæ %1"
220+
221+#: Greeter/PassphraseLockscreen.qml:59
222+msgid "Hello"
223+msgstr "Hæ"
224+
225+#: Hud/HudParametrizedActionsPage.qml:132
226+msgid "Confirm"
227+msgstr "Staðfesta"
228+
229+#: Hud/Hud.qml:61 Hud/Hud.qml:99 Hud/Hud.qml:372
230+msgid "Type or say a command"
231+msgstr "Skrifaðu eða segðu eitthvað"
232+
233+#: Hud/Hud.qml:84
234+msgid "Loading. Please Wait..."
235+msgstr "Hleð. Vinsamlegast Bíðið..."
236+
237+#: Hud/Hud.qml:89
238+msgid "Speak Now..."
239+msgstr "Talaðu Núna..."
240+
241+#: Hud/Hud.qml:94
242+msgid "Speaking..."
243+msgstr "Tala..."
244+
245+#: Panel/SearchIndicator.qml:27
246+msgid "Search"
247+msgstr "Leita"
248+
249+#: plugins/Unity/scope.cpp:317
250+msgid "Sorry, there is nothing that matches your search."
251+msgstr "Því miður, það var ekkert sem passaði við leitarorðið þitt."
252+
253+#: Shell.qml:429
254+#, qt-format
255+msgid "Please enter %1"
256+msgstr ""
po/it.po+55−54
@@ -8,127 +8,134 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-06-27 05:14+0000\n"
12−"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
11+"PO-Revision-Date: 2013-09-28 10:05+0000\n"
12+"Last-Translator: Claudio Arseni <claudio.arseni@gmail.com>\n"
1313"Language-Team: Italian <it@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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-09-29 06:18+0000\n"
19+"X-Generator: Launchpad (build 16774)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
23−msgstr ""
23+msgstr "Telefono"
2424
2525#: Applications/applications.js:29
2626msgid "Camera"
27−msgstr ""
27+msgstr "Fotocamera"
2828
2929#: Applications/applications.js:35
3030msgid "Gallery"
31−msgstr ""
31+msgstr "Galleria"
3232
3333#: Applications/applications.js:40
3434msgid "Facebook"
35−msgstr ""
35+msgstr "Facebook"
3636
3737#: Applications/applications.js:46
3838msgid "Browser"
39−msgstr ""
39+msgstr "Browser"
4040
4141#: Applications/applications.js:51
4242msgid "Twitter"
43−msgstr ""
43+msgstr "Twitter"
4444
4545#: Applications/applications.js:57
4646msgid "GMail"
47−msgstr ""
47+msgstr "GMail"
4848
4949#: Applications/applications.js:62
5050msgid "Weather"
51−msgstr ""
51+msgstr "Meteo"
5252
5353#: Applications/applications.js:68
5454msgid "Notepad"
55−msgstr ""
55+msgstr "Blocco note"
5656
5757#: Applications/applications.js:74
5858msgid "Calendar"
59−msgstr ""
59+msgstr "Calendario"
6060
6161#: Applications/applications.js:80
6262msgid "Media Player"
63−msgstr ""
63+msgstr "Riproduttore multimediale"
6464
6565#: Applications/applications.js:86
6666msgid "Evernote"
67−msgstr ""
67+msgstr "Evernote"
6868
6969#: Applications/applications.js:91
7070msgid "Map"
71−msgstr ""
71+msgstr "Mappa"
7272
7373#: Applications/applications.js:96
7474msgid "Pinterest"
75−msgstr ""
75+msgstr "Pinterest"
7676
7777#: Applications/applications.js:101
7878msgid "SoundCloud"
79−msgstr ""
79+msgstr "SoundCloud"
8080
8181#: Applications/applications.js:106
8282msgid "Wikipedia"
83−msgstr ""
83+msgstr "Wikipedia"
8484
8585#: Applications/applications.js:111
8686msgid "YouTube"
87−msgstr ""
87+msgstr "YouTube"
8888
8989#: Components/EdgeDemoOverlay.qml:145
9090msgid "Skip intro"
91−msgstr ""
91+msgstr "Salta introduzione"
9292
9393#: Components/EdgeDemo.qml:98
9494msgid "Right edge"
95−msgstr ""
95+msgstr "Bordo destro"
9696
9797#: Components/EdgeDemo.qml:99
9898msgid "Try swiping from the right edge to unlock the phone"
99−msgstr ""
99+msgstr "Provare a far scorrere dal bordo destro per sbloccare il telefono"
100100
101101#: Components/EdgeDemo.qml:135
102102msgid "Top edge"
103−msgstr ""
103+msgstr "Bordo superiore"
104104
105105#: Components/EdgeDemo.qml:136
106106msgid "Try swiping from the top edge to access the indicators"
107107msgstr ""
108+"Provare a far scorrere dal bordo in alto per accedere agli indicatori"
108109
109110#: Components/EdgeDemo.qml:161
110111msgid "Close"
111−msgstr ""
112+msgstr "Chiudi"
112113
113114#: Components/EdgeDemo.qml:162
114115msgid "Swipe up again to close the settings screen"
115116msgstr ""
117+"Far scorrere verso l'alto nuovamente per chiudere la schermata delle "
118+"impostazioni"
116119
117120#: Components/EdgeDemo.qml:189
118121msgid "Left edge"
119−msgstr ""
122+msgstr "Bordo sinistro"
120123
121124#: Components/EdgeDemo.qml:190
122125msgid "Swipe from the left to reveal the launcher for quick access to apps"
123126msgstr ""
127+"Far scorrere il bordo sinistro per mostrare il Launcher e avere un rapido "
128+"accesso alle applicazioni"
124129
125130#: Components/EdgeDemo.qml:217
126131msgid "Well done"
127−msgstr ""
132+msgstr "Ben fatto"
128133
129134#: Components/EdgeDemo.qml:218
130135msgid "You have now mastered the edge gestures and can start using the phone"
131136msgstr ""
137+"I gesti sui bordi dello schermo sono ora configurato ed è possibile usare il "
138+"telefono"
132139
133140#: Components/PageHeader.qml:298
134141msgid "Recent searches"
@@ -138,51 +145,51 @@ msgstr "Ricerche recenti"
138145#: Dash/Apps/AppInfo.qml:73
139146#, qt-format
140147msgid "(%1)"
141−msgstr ""
148+msgstr "(%1)"
142149
143150#. TRANSLATORS: Number of persons who wrote reviews for this app
144151#: Dash/Apps/AppInfo.qml:85
145152#, qt-format
146153msgid "%1 review"
147154msgid_plural "%1 reviews"
148−msgstr[0] ""
149−msgstr[1] ""
155+msgstr[0] "%1 recensione"
156+msgstr[1] "%1 recensioni"
150157
151158#: Dash/Apps/AppPreview.qml:175
152159msgid "Rate this"
153−msgstr ""
160+msgstr "Valuta"
154161
155162#: Dash/Apps/AppReviews.qml:72
156163msgid "Add a review"
157−msgstr ""
164+msgstr "Aggiungi una recensione"
158165
159166#: Dash/Apps/AppReviews.qml:84
160167msgid "Review"
161−msgstr ""
168+msgstr "Recensisci"
162169
163170#: Dash/Apps/AppReviews.qml:118
164171msgid "Send"
165−msgstr ""
172+msgstr "Invia"
166173
167174#: Dash/Apps/AppReviews.qml:136
168175msgid "Comments:"
169−msgstr ""
176+msgstr "Commenti:"
170177
171178#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
172179msgid "Featured"
173−msgstr ""
180+msgstr "In evidenza"
174181
175182#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
176183msgid "Recent"
177−msgstr ""
184+msgstr "Recenti"
178185
179186#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
180187msgid "New Releases"
181−msgstr ""
188+msgstr "Nuovi rilasci"
182189
183190#: Dash/DashMusic.qml:30
184191msgid "Top Charting"
185−msgstr ""
192+msgstr "Più votate"
186193
187194#: Dash/DashMusic.qml:91
188195msgid "Music"
@@ -190,7 +197,7 @@ msgstr "Musica"
190197
191198#: Dash/DashVideos.qml:31
192199msgid "Popular Online"
193−msgstr ""
200+msgstr "Popolari online"
194201
195202#: Dash/DashVideos.qml:146
196203msgid "Videos"
@@ -198,28 +205,28 @@ msgstr "Video"
198205
199206#: Dash/Video/VideoPreview.qml:130
200207msgid "Directed by:"
201−msgstr ""
208+msgstr "Diretto da:"
202209
203210#: Dash/Video/VideoPreview.qml:153
204211msgid "Starring:"
205−msgstr ""
212+msgstr "Valutazioni:"
206213
207214#: Dash/Video/VideoPreview.qml:176
208215msgid "Author:"
209−msgstr ""
216+msgstr "Autore:"
210217
211218#: Greeter/Lockscreen.qml:134
212219msgid "Emergency Call"
213−msgstr ""
220+msgstr "Chiamata di emergenza"
214221
215222#: Greeter/PassphraseLockscreen.qml:59
216223#, qt-format
217224msgid "Hello %1"
218−msgstr ""
225+msgstr "Ciao %1"
219226
220227#: Greeter/PassphraseLockscreen.qml:59
221228msgid "Hello"
222−msgstr ""
229+msgstr "Ciao"
223230
224231#: Hud/HudParametrizedActionsPage.qml:132
225232msgid "Confirm"
@@ -252,10 +259,4 @@ msgstr "Nessun risultato corrispondente alla ricerca."
252259#: Shell.qml:429
253260#, qt-format
254261msgid "Please enter %1"
255−msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Applicazioni"
259−
260−#~ msgid "Home"
261−#~ msgstr "Home"
262+msgstr "Inserire %1"
po/ja.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/kn.po+2−8
@@ -15,8 +15,8 @@ msgstr ""
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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "ಕ್ಷಮಿಸಿ ನಿಮ್ಮ ಶೋಧನೆಗೆ ಸರಿಯ
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"
259−
260−#~ msgid "Home"
261−#~ msgstr "ಮನೆ (Home)"
po/ko.po+2−23
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,24 +253,3 @@ msgstr ""
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "돌아가고 있는 앱"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "자주 쓰는 것들"
262−
263−#~ msgid "Installed"
264−#~ msgstr "깔림"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "내려받을 수 있음"
268−
269−#~ msgid "Apps"
270−#~ msgstr "앱"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "자주 쓰는 앱"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "요즈음 찾는 음악"
po/ky.po+2−8
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "Тилекке каршы, сиздин издөөңүзгө эч нер
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Тиркемелер"
259−
260−#~ msgid "Home"
261−#~ msgstr "Үй папкасы"
po/lv.po+21−27
@@ -8,59 +8,59 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-06-27 06:31+0000\n"
12−"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
11+"PO-Revision-Date: 2013-09-28 16:29+0000\n"
12+"Last-Translator: Jānis-Marks Gailis <jeanmarc.gailis@gmail.com>\n"
1313"Language-Team: Latvian <lv@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 != 0 ? 1 : 2;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-09-29 06:18+0000\n"
19+"X-Generator: Launchpad (build 16774)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
23−msgstr ""
23+msgstr "Tālrunis"
2424
2525#: Applications/applications.js:29
2626msgid "Camera"
27−msgstr ""
27+msgstr "Fotokamera"
2828
2929#: Applications/applications.js:35
3030msgid "Gallery"
31−msgstr ""
31+msgstr "Galerija"
3232
3333#: Applications/applications.js:40
3434msgid "Facebook"
35−msgstr ""
35+msgstr "Facebook"
3636
3737#: Applications/applications.js:46
3838msgid "Browser"
39−msgstr ""
39+msgstr "Pārlūkprogramma"
4040
4141#: Applications/applications.js:51
4242msgid "Twitter"
43−msgstr ""
43+msgstr "Twitter"
4444
4545#: Applications/applications.js:57
4646msgid "GMail"
47−msgstr ""
47+msgstr "GMail"
4848
4949#: Applications/applications.js:62
5050msgid "Weather"
51−msgstr ""
51+msgstr "Laikapstākļi"
5252
5353#: Applications/applications.js:68
5454msgid "Notepad"
55−msgstr ""
55+msgstr "Bloknots"
5656
5757#: Applications/applications.js:74
5858msgid "Calendar"
59−msgstr ""
59+msgstr "Kalendārs"
6060
6161#: Applications/applications.js:80
6262msgid "Media Player"
63−msgstr ""
63+msgstr "Mēdiju Atskaņotājs"
6464
6565#: Applications/applications.js:86
6666msgid "Evernote"
@@ -68,23 +68,23 @@ msgstr ""
6868
6969#: Applications/applications.js:91
7070msgid "Map"
71−msgstr ""
71+msgstr "Karte"
7272
7373#: Applications/applications.js:96
7474msgid "Pinterest"
75−msgstr ""
75+msgstr "Pinterest"
7676
7777#: Applications/applications.js:101
7878msgid "SoundCloud"
79−msgstr ""
79+msgstr "SoundCloud"
8080
8181#: Applications/applications.js:106
8282msgid "Wikipedia"
83−msgstr ""
83+msgstr "Vikipēdija"
8484
8585#: Applications/applications.js:111
8686msgid "YouTube"
87−msgstr ""
87+msgstr "YouTube"
8888
8989#: Components/EdgeDemoOverlay.qml:145
9090msgid "Skip intro"
@@ -92,7 +92,7 @@ msgstr ""
9292
9393#: Components/EdgeDemo.qml:98
9494msgid "Right edge"
95−msgstr ""
95+msgstr "Labā mala"
9696
9797#: Components/EdgeDemo.qml:99
9898msgid "Try swiping from the right edge to unlock the phone"
@@ -253,9 +253,3 @@ msgstr "Diemžēl nekas neatbilst jūsu meklētajam."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Lietotnes"
259−
260−#~ msgid "Home"
261−#~ msgstr "Mājas"
po/my.po+2−8
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "ဆောရီး၊ သင်၏ရှာဖွေမူနှင့
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Apps"
259−
260−#~ msgid "Home"
261−#~ msgstr "ပင်မ"
po/nb.po+2−17
@@ -15,8 +15,8 @@ msgstr ""
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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,18 +253,3 @@ msgstr "Søket ga ingen treff."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Frequently used"
258−#~ msgstr "Ofte brukt"
259−
260−#~ msgid "Installed"
261−#~ msgstr "Installert"
262−
263−#~ msgid "Available for download"
264−#~ msgstr "Tilgjengelig for nedlasting"
265−
266−#~ msgid "Apps"
267−#~ msgstr "Programmer"
268−
269−#~ msgid "Home"
270−#~ msgstr "Hjem"
po/nl.po+2−8
@@ -15,8 +15,8 @@ msgstr ""
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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "Er is helaas niets dat met uw zoekopdracht overeenkomt."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Apps"
259−
260−#~ msgid "Home"
261−#~ msgstr "Hoofdvenster"
po/pl.po+2−29
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
1818"|| n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
19+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20+"X-Generator: Launchpad (build 16750)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
@@ -254,30 +254,3 @@ msgstr "Nie znaleziono pasujących wyników."
254254#, qt-format
255255msgid "Please enter %1"
256256msgstr "Wprowadź %1"
257−
258−#~ msgid "Running apps"
259−#~ msgstr "Uruchomione aplikacje"
260−
261−#~ msgid "Frequently used"
262−#~ msgstr "Najczęściej używane"
263−
264−#~ msgid "Installed"
265−#~ msgstr "Zainstalowane"
266−
267−#~ msgid "Available for download"
268−#~ msgstr "Dostępne do pobrania"
269−
270−#~ msgid "Apps"
271−#~ msgstr "Aplikacje"
272−
273−#~ msgid "Frequent Apps"
274−#~ msgstr "Często używane aplikacje"
275−
276−#~ msgid "Recent Music"
277−#~ msgstr "Najnowsza muzyka"
278−
279−#~ msgid "Videos Popular Online"
280−#~ msgstr "Wideo popularne online"
281−
282−#~ msgid "Home"
283−#~ msgstr "Dom"
po/pt_BR.po+49−53
@@ -8,119 +8,121 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-06-27 07:39+0000\n"
12−"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
11+"PO-Revision-Date: 2013-09-30 13:01+0000\n"
12+"Last-Translator: Rafael Neri <Unknown>\n"
1313"Language-Team: Brazilian Portuguese <pt_BR@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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-10-01 05:53+0000\n"
19+"X-Generator: Launchpad (build 16774)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
23−msgstr ""
23+msgstr "Telefone"
2424
2525#: Applications/applications.js:29
2626msgid "Camera"
27−msgstr ""
27+msgstr "Câmera"
2828
2929#: Applications/applications.js:35
3030msgid "Gallery"
31−msgstr ""
31+msgstr "Galeria"
3232
3333#: Applications/applications.js:40
3434msgid "Facebook"
35−msgstr ""
35+msgstr "Facebook"
3636
3737#: Applications/applications.js:46
3838msgid "Browser"
39−msgstr ""
39+msgstr "Navegador"
4040
4141#: Applications/applications.js:51
4242msgid "Twitter"
43−msgstr ""
43+msgstr "Twitter"
4444
4545#: Applications/applications.js:57
4646msgid "GMail"
47−msgstr ""
47+msgstr "GMail"
4848
4949#: Applications/applications.js:62
5050msgid "Weather"
51−msgstr ""
51+msgstr "Clima"
5252
5353#: Applications/applications.js:68
5454msgid "Notepad"
55−msgstr ""
55+msgstr "Bloco de notas"
5656
5757#: Applications/applications.js:74
5858msgid "Calendar"
59−msgstr ""
59+msgstr "Calendário"
6060
6161#: Applications/applications.js:80
6262msgid "Media Player"
63−msgstr ""
63+msgstr "Media Player"
6464
6565#: Applications/applications.js:86
6666msgid "Evernote"
67−msgstr ""
67+msgstr "Evernote"
6868
6969#: Applications/applications.js:91
7070msgid "Map"
71−msgstr ""
71+msgstr "Mapa"
7272
7373#: Applications/applications.js:96
7474msgid "Pinterest"
75−msgstr ""
75+msgstr "Pinterest"
7676
7777#: Applications/applications.js:101
7878msgid "SoundCloud"
79−msgstr ""
79+msgstr "SoundCloud"
8080
8181#: Applications/applications.js:106
8282msgid "Wikipedia"
83−msgstr ""
83+msgstr "Wikipédia"
8484
8585#: Applications/applications.js:111
8686msgid "YouTube"
87−msgstr ""
87+msgstr "YouTube"
8888
8989#: Components/EdgeDemoOverlay.qml:145
9090msgid "Skip intro"
91−msgstr ""
91+msgstr "Pular introdução"
9292
9393#: Components/EdgeDemo.qml:98
9494msgid "Right edge"
95−msgstr ""
95+msgstr "Borda direita"
9696
9797#: Components/EdgeDemo.qml:99
9898msgid "Try swiping from the right edge to unlock the phone"
99−msgstr ""
99+msgstr "Tente deslizar da borda direita para desbloquear o telefone"
100100
101101#: Components/EdgeDemo.qml:135
102102msgid "Top edge"
103−msgstr ""
103+msgstr "Borda superior"
104104
105105#: Components/EdgeDemo.qml:136
106106msgid "Try swiping from the top edge to access the indicators"
107−msgstr ""
107+msgstr "Tente deslizar da borda superior para acessar os indicadores"
108108
109109#: Components/EdgeDemo.qml:161
110110msgid "Close"
111−msgstr ""
111+msgstr "Fechar"
112112
113113#: Components/EdgeDemo.qml:162
114114msgid "Swipe up again to close the settings screen"
115−msgstr ""
115+msgstr "Deslize novamente para cima para fechar a tela de configurações"
116116
117117#: Components/EdgeDemo.qml:189
118118msgid "Left edge"
119−msgstr ""
119+msgstr "Borda esquerda"
120120
121121#: Components/EdgeDemo.qml:190
122122msgid "Swipe from the left to reveal the launcher for quick access to apps"
123123msgstr ""
124+"Deslize da esquerda para revelar o lançador para acesso rápido aos "
125+"aplicativos"
124126
125127#: Components/EdgeDemo.qml:217
126128msgid "Well done"
@@ -138,47 +140,47 @@ msgstr "Pesquisas recentes"
138140#: Dash/Apps/AppInfo.qml:73
139141#, qt-format
140142msgid "(%1)"
141−msgstr ""
143+msgstr "(%1)"
142144
143145#. TRANSLATORS: Number of persons who wrote reviews for this app
144146#: Dash/Apps/AppInfo.qml:85
145147#, qt-format
146148msgid "%1 review"
147149msgid_plural "%1 reviews"
148−msgstr[0] ""
149−msgstr[1] ""
150+msgstr[0] "%1 análise"
151+msgstr[1] "%1 análises"
150152
151153#: Dash/Apps/AppPreview.qml:175
152154msgid "Rate this"
153−msgstr ""
155+msgstr "Avaliar isto"
154156
155157#: Dash/Apps/AppReviews.qml:72
156158msgid "Add a review"
157−msgstr ""
159+msgstr "Adicionar uma análise"
158160
159161#: Dash/Apps/AppReviews.qml:84
160162msgid "Review"
161−msgstr ""
163+msgstr "Revisão"
162164
163165#: Dash/Apps/AppReviews.qml:118
164166msgid "Send"
165−msgstr ""
167+msgstr "Enviar"
166168
167169#: Dash/Apps/AppReviews.qml:136
168170msgid "Comments:"
169−msgstr ""
171+msgstr "Comentários:"
170172
171173#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
172174msgid "Featured"
173−msgstr ""
175+msgstr "Em destaque"
174176
175177#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
176178msgid "Recent"
177−msgstr ""
179+msgstr "Recente"
178180
179181#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
180182msgid "New Releases"
181−msgstr ""
183+msgstr "Lançamentos"
182184
183185#: Dash/DashMusic.qml:30
184186msgid "Top Charting"
@@ -198,28 +200,28 @@ msgstr "Vídeos"
198200
199201#: Dash/Video/VideoPreview.qml:130
200202msgid "Directed by:"
201−msgstr ""
203+msgstr "Realizado por:"
202204
203205#: Dash/Video/VideoPreview.qml:153
204206msgid "Starring:"
205−msgstr ""
207+msgstr "Estrelando:"
206208
207209#: Dash/Video/VideoPreview.qml:176
208210msgid "Author:"
209−msgstr ""
211+msgstr "Autor:"
210212
211213#: Greeter/Lockscreen.qml:134
212214msgid "Emergency Call"
213−msgstr ""
215+msgstr "Chamada de emergência"
214216
215217#: Greeter/PassphraseLockscreen.qml:59
216218#, qt-format
217219msgid "Hello %1"
218−msgstr ""
220+msgstr "Olá %1"
219221
220222#: Greeter/PassphraseLockscreen.qml:59
221223msgid "Hello"
222−msgstr ""
224+msgstr "Olá"
223225
224226#: Hud/HudParametrizedActionsPage.qml:132
225227msgid "Confirm"
@@ -252,10 +254,4 @@ msgstr "Desculpe, não há nada que corresponda à sua pesquisa."
252254#: Shell.qml:429
253255#, qt-format
254256msgid "Please enter %1"
255−msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Aplicativos"
259−
260−#~ msgid "Home"
261−#~ msgstr "Início"
257+msgstr "Por favor, digite %1"
po/ro.po+2−8
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=(n == 1 ? 0: (((n % 100 > 19) || ((n % 100 "
1818"== 0) && (n != 0))) ? 2: 1));\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
19+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20+"X-Generator: Launchpad (build 16750)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
@@ -255,9 +255,3 @@ msgstr ""
255255#, qt-format
256256msgid "Please enter %1"
257257msgstr ""
258−
259−#~ msgid "Apps"
260−#~ msgstr "Aplicații"
261−
262−#~ msgid "Home"
263−#~ msgstr "Acasă"
po/ru.po+32−53
@@ -8,16 +8,16 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-06-28 06:40+0000\n"
12−"Last-Translator: Eugene Marshal <Unknown>\n"
11+"PO-Revision-Date: 2013-09-29 09:11+0000\n"
12+"Last-Translator: Устин <ustinershovskiy@yandex.ru>\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-08-29 05:41+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
19+"X-Launchpad-Export-Date: 2013-09-30 05:57+0000\n"
20+"X-Generator: Launchpad (build 16774)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
@@ -89,47 +89,54 @@ msgstr "YouTube"
8989
9090#: Components/EdgeDemoOverlay.qml:145
9191msgid "Skip intro"
92−msgstr ""
92+msgstr "Пропустить обучение"
9393
9494#: Components/EdgeDemo.qml:98
9595msgid "Right edge"
96−msgstr ""
96+msgstr "Правый край"
9797
9898#: Components/EdgeDemo.qml:99
9999msgid "Try swiping from the right edge to unlock the phone"
100100msgstr ""
101+"Попробуйте переместить палец от правого края к левому для разблокировки "
102+"устройства"
101103
102104#: Components/EdgeDemo.qml:135
103105msgid "Top edge"
104−msgstr ""
106+msgstr "Верхний край"
105107
106108#: Components/EdgeDemo.qml:136
107109msgid "Try swiping from the top edge to access the indicators"
108110msgstr ""
111+"Попробуйте переместить палец от верхнего края вниз для доступа к индикаторам"
109112
110113#: Components/EdgeDemo.qml:161
111114msgid "Close"
112−msgstr ""
115+msgstr "Закрыть"
113116
114117#: Components/EdgeDemo.qml:162
115118msgid "Swipe up again to close the settings screen"
116−msgstr ""
119+msgstr "Снова переместите палец вверх для закрытия экрана настроек"
117120
118121#: Components/EdgeDemo.qml:189
119122msgid "Left edge"
120−msgstr ""
123+msgstr "Левый край"
121124
122125#: Components/EdgeDemo.qml:190
123126msgid "Swipe from the left to reveal the launcher for quick access to apps"
124127msgstr ""
128+"Переместите палец от левого края вправо для открытия лаунчера для быстрого "
129+"доступа к приложениям"
125130
126131#: Components/EdgeDemo.qml:217
127132msgid "Well done"
128−msgstr ""
133+msgstr "Великолепно"
129134
130135#: Components/EdgeDemo.qml:218
131136msgid "You have now mastered the edge gestures and can start using the phone"
132137msgstr ""
138+"Теперь вы научились экранным жестам и можете приступить к использованию "
139+"устройства"
133140
134141#: Components/PageHeader.qml:298
135142msgid "Recent searches"
@@ -139,39 +146,38 @@ msgstr "Последние поисковые запросы"
139146#: Dash/Apps/AppInfo.qml:73
140147#, qt-format
141148msgid "(%1)"
142−msgstr ""
149+msgstr "(%1)"
143150
144151#. TRANSLATORS: Number of persons who wrote reviews for this app
145152#: Dash/Apps/AppInfo.qml:85
146153#, qt-format
147154msgid "%1 review"
148155msgid_plural "%1 reviews"
149−msgstr[0] ""
150−msgstr[1] ""
156+msgstr[0] "%1 отзыв"
151157
152158#: Dash/Apps/AppPreview.qml:175
153159msgid "Rate this"
154−msgstr ""
160+msgstr "Оцените это"
155161
156162#: Dash/Apps/AppReviews.qml:72
157163msgid "Add a review"
158−msgstr ""
164+msgstr "Добавьте отзыв"
159165
160166#: Dash/Apps/AppReviews.qml:84
161167msgid "Review"
162−msgstr ""
168+msgstr "Отзыв"
163169
164170#: Dash/Apps/AppReviews.qml:118
165171msgid "Send"
166−msgstr ""
172+msgstr "Отправить"
167173
168174#: Dash/Apps/AppReviews.qml:136
169175msgid "Comments:"
170−msgstr ""
176+msgstr "Комментарии:"
171177
172178#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
173179msgid "Featured"
174−msgstr ""
180+msgstr "Рекомендованное"
175181
176182#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
177183msgid "Recent"
@@ -183,7 +189,7 @@ msgstr "Новые релизы"
183189
184190#: Dash/DashMusic.qml:30
185191msgid "Top Charting"
186−msgstr ""
192+msgstr "Наиболее популярное"
187193
188194#: Dash/DashMusic.qml:91
189195msgid "Music"
@@ -191,7 +197,7 @@ msgstr "Музыка"
191197
192198#: Dash/DashVideos.qml:31
193199msgid "Popular Online"
194−msgstr ""
200+msgstr "Популярное в Интернете"
195201
196202#: Dash/DashVideos.qml:146
197203msgid "Videos"
@@ -211,20 +217,20 @@ msgstr "Автор:"
211217
212218#: Greeter/Lockscreen.qml:134
213219msgid "Emergency Call"
214−msgstr ""
220+msgstr "Экстренный вызов"
215221
216222#: Greeter/PassphraseLockscreen.qml:59
217223#, qt-format
218224msgid "Hello %1"
219−msgstr ""
225+msgstr "Привет, %1"
220226
221227#: Greeter/PassphraseLockscreen.qml:59
222228msgid "Hello"
223−msgstr ""
229+msgstr "Привет"
224230
225231#: Hud/HudParametrizedActionsPage.qml:132
226232msgid "Confirm"
227−msgstr "Подвердить"
233+msgstr "Подтвердить"
228234
229235#: Hud/Hud.qml:61 Hud/Hud.qml:99 Hud/Hud.qml:372
230236msgid "Type or say a command"
@@ -254,30 +260,3 @@ msgstr "Извините, поиск не дал результатов."
254260#, qt-format
255261msgid "Please enter %1"
256262msgstr "Пожалуйста, введите %1"
257−
258−#~ msgid "Running apps"
259−#~ msgstr "Запущенные приложения"
260−
261−#~ msgid "Frequently used"
262−#~ msgstr "Часто используемые"
263−
264−#~ msgid "Installed"
265−#~ msgstr "Установленные"
266−
267−#~ msgid "Available for download"
268−#~ msgstr "Доступно для загрузки"
269−
270−#~ msgid "Apps"
271−#~ msgstr "Приложения"
272−
273−#~ msgid "Frequent Apps"
274−#~ msgstr "Часто используемые приложения"
275−
276−#~ msgid "Recent Music"
277−#~ msgstr "Недавно прослушанная музыка"
278−
279−#~ msgid "Videos Popular Online"
280−#~ msgstr "Популярные видео из сети"
281−
282−#~ msgid "Home"
283−#~ msgstr "Главная"
po/si.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/sl.po+32−48
@@ -8,7 +8,7 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-07-02 12:59+0000\n"
11+"PO-Revision-Date: 2013-09-28 09:53+0000\n"
1212"Last-Translator: Damir Jerovšek <Unknown>\n"
1313"Language-Team: Slovenian <sl@li.org>\n"
1414"MIME-Version: 1.0\n"
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || "
1818"n%100==4 ? 3 : 0);\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
19+"X-Launchpad-Export-Date: 2013-09-29 06:18+0000\n"
20+"X-Generator: Launchpad (build 16774)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
@@ -25,7 +25,7 @@ msgstr "Telefon"
2525
2626#: Applications/applications.js:29
2727msgid "Camera"
28−msgstr ""
28+msgstr "Fotoaparat"
2929
3030#: Applications/applications.js:35
3131msgid "Gallery"
@@ -89,47 +89,50 @@ msgstr "YouTube"
8989
9090#: Components/EdgeDemoOverlay.qml:145
9191msgid "Skip intro"
92−msgstr ""
92+msgstr "Preskoči uvod"
9393
9494#: Components/EdgeDemo.qml:98
9595msgid "Right edge"
96−msgstr ""
96+msgstr "Desni rob"
9797
9898#: Components/EdgeDemo.qml:99
9999msgid "Try swiping from the right edge to unlock the phone"
100−msgstr ""
100+msgstr "Poskusite povleči od desnega roba za odklep telefona"
101101
102102#: Components/EdgeDemo.qml:135
103103msgid "Top edge"
104−msgstr ""
104+msgstr "Zgornji rob"
105105
106106#: Components/EdgeDemo.qml:136
107107msgid "Try swiping from the top edge to access the indicators"
108−msgstr ""
108+msgstr "Poskusite povleči od zgornjega roba za dostop do kazalnikov"
109109
110110#: Components/EdgeDemo.qml:161
111111msgid "Close"
112−msgstr ""
112+msgstr "Zapri"
113113
114114#: Components/EdgeDemo.qml:162
115115msgid "Swipe up again to close the settings screen"
116−msgstr ""
116+msgstr "Povlecite ponovno navzgor za zaprtje zaslona z nastavitvami"
117117
118118#: Components/EdgeDemo.qml:189
119119msgid "Left edge"
120−msgstr ""
120+msgstr "Levi rob"
121121
122122#: Components/EdgeDemo.qml:190
123123msgid "Swipe from the left to reveal the launcher for quick access to apps"
124124msgstr ""
125+"Poskusite povleči od leve za razkritje zaganjalnika za hiter dostop do "
126+"programov"
125127
126128#: Components/EdgeDemo.qml:217
127129msgid "Well done"
128−msgstr ""
130+msgstr "Odlično"
129131
130132#: Components/EdgeDemo.qml:218
131133msgid "You have now mastered the edge gestures and can start using the phone"
132134msgstr ""
135+"Zdaj, ko ste osvojili kretnje z robovi, lahko začnete uporabljati telefon"
133136
134137#: Components/PageHeader.qml:298
135138msgid "Recent searches"
@@ -139,35 +142,37 @@ msgstr "Nedavna iskanja"
139142#: Dash/Apps/AppInfo.qml:73
140143#, qt-format
141144msgid "(%1)"
142−msgstr ""
145+msgstr "(%1)"
143146
144147#. TRANSLATORS: Number of persons who wrote reviews for this app
145148#: Dash/Apps/AppInfo.qml:85
146149#, qt-format
147150msgid "%1 review"
148151msgid_plural "%1 reviews"
149−msgstr[0] ""
150−msgstr[1] ""
152+msgstr[0] "%1 ocen"
153+msgstr[1] "%1 ocena"
154+msgstr[2] "%1 oceni"
155+msgstr[3] "%1 ocene"
151156
152157#: Dash/Apps/AppPreview.qml:175
153158msgid "Rate this"
154−msgstr ""
159+msgstr "Ocenite"
155160
156161#: Dash/Apps/AppReviews.qml:72
157162msgid "Add a review"
158−msgstr ""
163+msgstr "Dodaj oceno"
159164
160165#: Dash/Apps/AppReviews.qml:84
161166msgid "Review"
162−msgstr ""
167+msgstr "Ocena"
163168
164169#: Dash/Apps/AppReviews.qml:118
165170msgid "Send"
166−msgstr ""
171+msgstr "Pošlji"
167172
168173#: Dash/Apps/AppReviews.qml:136
169174msgid "Comments:"
170−msgstr ""
175+msgstr "Opombe:"
171176
172177#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
173178msgid "Featured"
@@ -199,19 +204,19 @@ msgstr "Videi"
199204
200205#: Dash/Video/VideoPreview.qml:130
201206msgid "Directed by:"
202−msgstr ""
207+msgstr "Režija:"
203208
204209#: Dash/Video/VideoPreview.qml:153
205210msgid "Starring:"
206−msgstr ""
211+msgstr "Igrajo:"
207212
208213#: Dash/Video/VideoPreview.qml:176
209214msgid "Author:"
210−msgstr ""
215+msgstr "Avtor:"
211216
212217#: Greeter/Lockscreen.qml:134
213218msgid "Emergency Call"
214−msgstr ""
219+msgstr "Klic v sili"
215220
216221#: Greeter/PassphraseLockscreen.qml:59
217222#, qt-format
@@ -220,7 +225,7 @@ msgstr "Pozdravljeni, %1"
220225
221226#: Greeter/PassphraseLockscreen.qml:59
222227msgid "Hello"
223−msgstr ""
228+msgstr "Pozdravljeni"
224229
225230#: Hud/HudParametrizedActionsPage.qml:132
226231msgid "Confirm"
@@ -253,25 +258,4 @@ msgstr "Nič se ne ujema z vašim iskalnim nizom."
253258#: Shell.qml:429
254259#, qt-format
255260msgid "Please enter %1"
256−msgstr ""
257−
258−#~ msgid "Frequently used"
259−#~ msgstr "Pogosto uporabljano"
260−
261−#~ msgid "Installed"
262−#~ msgstr "Nameščeno"
263−
264−#~ msgid "Available for download"
265−#~ msgstr "Na voljo za prejem"
266−
267−#~ msgid "Apps"
268−#~ msgstr "Programi"
269−
270−#~ msgid "Recent Music"
271−#~ msgstr "Nedavna glasba"
272−
273−#~ msgid "Home"
274−#~ msgstr "Domov"
275−
276−#~ msgid "Frequent Apps"
277−#~ msgstr "Pogosto uporabljani programi"
261+msgstr "Vnesite %1"
po/sr.po+2−8
@@ -16,8 +16,8 @@ msgstr ""
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-08-29 05:41+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
19+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20+"X-Generator: Launchpad (build 16750)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
@@ -254,9 +254,3 @@ msgstr "Нажалост, претрага није наишла на икакв
254254#, qt-format
255255msgid "Please enter %1"
256256msgstr ""
257−
258−#~ msgid "Apps"
259−#~ msgstr "Програми"
260−
261−#~ msgid "Home"
262−#~ msgstr "Почетна"
po/sv.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/te.po+2−5
@@ -15,8 +15,8 @@ msgstr ""
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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,6 +253,3 @@ msgstr ""
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Home"
258−#~ msgstr "నివాసం"
po/tr.po+2−29
@@ -15,8 +15,8 @@ msgstr ""
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-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "Üzgünüz, aramanızla eşleşen hiçbir şey yok."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "Çalışan uygulamalar"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "Sıkça kullanılanlar"
262−
263−#~ msgid "Installed"
264−#~ msgstr "Yüklenenler"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "İndirilebilir durumda"
268−
269−#~ msgid "Apps"
270−#~ msgstr "Uygulamalar"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "Sıkça Kullanılan Uygulamalar"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "En Son Müzik"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "Çevrimiçi Yaygın Videolar"
280−
281−#~ msgid "Home"
282−#~ msgstr "Ana Sayfa"
po/ug.po+2−29
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "كەچۈرۈڭ، ئىزدىگىنىڭىزگە ماس نەتىجە تېپ
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "ئىجرا بولۇۋاتقان ئەپلەر"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "كوپ ئىشلىتىلگەنلىرى"
262−
263−#~ msgid "Installed"
264−#~ msgstr "ئورنىتىلغانلىرى"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "چۈشۈرگىلى بولىدىغانلىرى"
268−
269−#~ msgid "Apps"
270−#~ msgstr "ئەپلەر"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "دائىم ئىشلىتىلىدىغان ئەپلەر"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "يېقىندا ئاڭلىغان مۇزىكىلار"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "توردىكى ئالقىشقا ئېرىشكەن سىنلار"
280−
281−#~ msgid "Home"
282−#~ msgstr "ماكان"
po/uk.po+26−48
@@ -8,16 +8,16 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-07-21 05:47+0000\n"
12−"Last-Translator: Ярослав Смук <Smuk.Slavko@yandex.ua>\n"
11+"PO-Revision-Date: 2013-09-28 07:54+0000\n"
12+"Last-Translator: Yuri Chornoivan <yurchor@gmail.com>\n"
1313"Language-Team: Ukrainian <uk@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-08-29 05:41+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
19+"X-Launchpad-Export-Date: 2013-09-29 06:18+0000\n"
20+"X-Generator: Launchpad (build 16774)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
@@ -89,47 +89,51 @@ msgstr "YouTube"
8989
9090#: Components/EdgeDemoOverlay.qml:145
9191msgid "Skip intro"
92−msgstr ""
92+msgstr "Пропустити вступ"
9393
9494#: Components/EdgeDemo.qml:98
9595msgid "Right edge"
96−msgstr ""
96+msgstr "Правий край"
9797
9898#: Components/EdgeDemo.qml:99
9999msgid "Try swiping from the right edge to unlock the phone"
100−msgstr ""
100+msgstr "Спробуйте провести пальцем від правою краю, щоб розблокувати телефон"
101101
102102#: Components/EdgeDemo.qml:135
103103msgid "Top edge"
104−msgstr ""
104+msgstr "Верхній край"
105105
106106#: Components/EdgeDemo.qml:136
107107msgid "Try swiping from the top edge to access the indicators"
108108msgstr ""
109+"Спробуйте провести пальцем від верхнього краю, щоб розблокувати телефон"
109110
110111#: Components/EdgeDemo.qml:161
111112msgid "Close"
112−msgstr ""
113+msgstr "Закрити"
113114
114115#: Components/EdgeDemo.qml:162
115116msgid "Swipe up again to close the settings screen"
116−msgstr ""
117+msgstr "Проведіть пальцем ще раз, щоб закрити вікно параметрів"
117118
118119#: Components/EdgeDemo.qml:189
119120msgid "Left edge"
120−msgstr ""
121+msgstr "Лівий край"
121122
122123#: Components/EdgeDemo.qml:190
123124msgid "Swipe from the left to reveal the launcher for quick access to apps"
124125msgstr ""
126+"Проведіть пальцем від лівого краю, щоб відкрити панель запуску для "
127+"пришвидшення доступу до програм"
125128
126129#: Components/EdgeDemo.qml:217
127130msgid "Well done"
128−msgstr ""
131+msgstr "Добре"
129132
130133#: Components/EdgeDemo.qml:218
131134msgid "You have now mastered the edge gestures and can start using the phone"
132135msgstr ""
136+"Вами налаштовано жести від країв, ви можете почати користуватися телефоном"
133137
134138#: Components/PageHeader.qml:298
135139msgid "Recent searches"
@@ -139,35 +143,36 @@ msgstr "Нещодавні пошуки"
139143#: Dash/Apps/AppInfo.qml:73
140144#, qt-format
141145msgid "(%1)"
142−msgstr ""
146+msgstr "(%1)"
143147
144148#. TRANSLATORS: Number of persons who wrote reviews for this app
145149#: Dash/Apps/AppInfo.qml:85
146150#, qt-format
147151msgid "%1 review"
148152msgid_plural "%1 reviews"
149−msgstr[0] ""
150−msgstr[1] ""
153+msgstr[0] "%1 рецензія"
154+msgstr[1] "%1 рецензії"
155+msgstr[2] "%1 рецензій"
151156
152157#: Dash/Apps/AppPreview.qml:175
153158msgid "Rate this"
154−msgstr ""
159+msgstr "Оцінити"
155160
156161#: Dash/Apps/AppReviews.qml:72
157162msgid "Add a review"
158−msgstr ""
163+msgstr "Додати рецензію"
159164
160165#: Dash/Apps/AppReviews.qml:84
161166msgid "Review"
162−msgstr ""
167+msgstr "Рецензія"
163168
164169#: Dash/Apps/AppReviews.qml:118
165170msgid "Send"
166−msgstr ""
171+msgstr "Надіслати"
167172
168173#: Dash/Apps/AppReviews.qml:136
169174msgid "Comments:"
170−msgstr ""
175+msgstr "Коментарі:"
171176
172177#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
173178msgid "Featured"
@@ -211,7 +216,7 @@ msgstr "Автор:"
211216
212217#: Greeter/Lockscreen.qml:134
213218msgid "Emergency Call"
214−msgstr ""
219+msgstr "Терміновий виклик"
215220
216221#: Greeter/PassphraseLockscreen.qml:59
217222#, qt-format
@@ -254,30 +259,3 @@ msgstr "Вибачте, для вказаних вами ключових слі
254259#, qt-format
255260msgid "Please enter %1"
256261msgstr "Будь ласка, введіть %1"
257−
258−#~ msgid "Running apps"
259−#~ msgstr "Запущені програми"
260−
261−#~ msgid "Frequently used"
262−#~ msgstr "Найчастіше використовувані"
263−
264−#~ msgid "Installed"
265−#~ msgstr "Встановлені"
266−
267−#~ msgid "Available for download"
268−#~ msgstr "Доступно до завантаження"
269−
270−#~ msgid "Apps"
271−#~ msgstr "Програми"
272−
273−#~ msgid "Frequent Apps"
274−#~ msgstr "Часто використовувані програми"
275−
276−#~ msgid "Recent Music"
277−#~ msgstr "Нещодавно прослухана музика"
278−
279−#~ msgid "Videos Popular Online"
280−#~ msgstr "Популярні в мережі відео"
281−
282−#~ msgid "Home"
283−#~ msgstr "Домівка"
po/xh.ponew file+255
@@ -0,0 +1,255 @@
1+# Xhosa translation for unity8
2+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
3+# This file is distributed under the same license as the unity8 package.
4+# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
5+#
6+msgid ""
7+msgstr ""
8+"Project-Id-Version: unity8\n"
9+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10+"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11+"PO-Revision-Date: 2013-09-28 13:20+0000\n"
12+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13+"Language-Team: Xhosa <xh@li.org>\n"
14+"MIME-Version: 1.0\n"
15+"Content-Type: text/plain; charset=UTF-8\n"
16+"Content-Transfer-Encoding: 8bit\n"
17+"Plural-Forms: nplurals=2; plural=n != 1;\n"
18+"X-Launchpad-Export-Date: 2013-09-29 06:18+0000\n"
19+"X-Generator: Launchpad (build 16774)\n"
20+
21+#: Applications/applications.js:23
22+msgid "Phone"
23+msgstr ""
24+
25+#: Applications/applications.js:29
26+msgid "Camera"
27+msgstr ""
28+
29+#: Applications/applications.js:35
30+msgid "Gallery"
31+msgstr ""
32+
33+#: Applications/applications.js:40
34+msgid "Facebook"
35+msgstr ""
36+
37+#: Applications/applications.js:46
38+msgid "Browser"
39+msgstr ""
40+
41+#: Applications/applications.js:51
42+msgid "Twitter"
43+msgstr ""
44+
45+#: Applications/applications.js:57
46+msgid "GMail"
47+msgstr ""
48+
49+#: Applications/applications.js:62
50+msgid "Weather"
51+msgstr ""
52+
53+#: Applications/applications.js:68
54+msgid "Notepad"
55+msgstr ""
56+
57+#: Applications/applications.js:74
58+msgid "Calendar"
59+msgstr ""
60+
61+#: Applications/applications.js:80
62+msgid "Media Player"
63+msgstr ""
64+
65+#: Applications/applications.js:86
66+msgid "Evernote"
67+msgstr ""
68+
69+#: Applications/applications.js:91
70+msgid "Map"
71+msgstr ""
72+
73+#: Applications/applications.js:96
74+msgid "Pinterest"
75+msgstr ""
76+
77+#: Applications/applications.js:101
78+msgid "SoundCloud"
79+msgstr ""
80+
81+#: Applications/applications.js:106
82+msgid "Wikipedia"
83+msgstr ""
84+
85+#: Applications/applications.js:111
86+msgid "YouTube"
87+msgstr ""
88+
89+#: Components/EdgeDemoOverlay.qml:145
90+msgid "Skip intro"
91+msgstr ""
92+
93+#: Components/EdgeDemo.qml:98
94+msgid "Right edge"
95+msgstr ""
96+
97+#: Components/EdgeDemo.qml:99
98+msgid "Try swiping from the right edge to unlock the phone"
99+msgstr ""
100+
101+#: Components/EdgeDemo.qml:135
102+msgid "Top edge"
103+msgstr ""
104+
105+#: Components/EdgeDemo.qml:136
106+msgid "Try swiping from the top edge to access the indicators"
107+msgstr ""
108+
109+#: Components/EdgeDemo.qml:161
110+msgid "Close"
111+msgstr ""
112+
113+#: Components/EdgeDemo.qml:162
114+msgid "Swipe up again to close the settings screen"
115+msgstr ""
116+
117+#: Components/EdgeDemo.qml:189
118+msgid "Left edge"
119+msgstr ""
120+
121+#: Components/EdgeDemo.qml:190
122+msgid "Swipe from the left to reveal the launcher for quick access to apps"
123+msgstr ""
124+
125+#: Components/EdgeDemo.qml:217
126+msgid "Well done"
127+msgstr ""
128+
129+#: Components/EdgeDemo.qml:218
130+msgid "You have now mastered the edge gestures and can start using the phone"
131+msgstr ""
132+
133+#: Components/PageHeader.qml:298
134+msgid "Recent searches"
135+msgstr ""
136+
137+#. TRANSLATORS: Number of persons who rated this app
138+#: Dash/Apps/AppInfo.qml:73
139+#, qt-format
140+msgid "(%1)"
141+msgstr ""
142+
143+#. TRANSLATORS: Number of persons who wrote reviews for this app
144+#: Dash/Apps/AppInfo.qml:85
145+#, qt-format
146+msgid "%1 review"
147+msgid_plural "%1 reviews"
148+msgstr[0] ""
149+msgstr[1] ""
150+
151+#: Dash/Apps/AppPreview.qml:175
152+msgid "Rate this"
153+msgstr ""
154+
155+#: Dash/Apps/AppReviews.qml:72
156+msgid "Add a review"
157+msgstr ""
158+
159+#: Dash/Apps/AppReviews.qml:84
160+msgid "Review"
161+msgstr ""
162+
163+#: Dash/Apps/AppReviews.qml:118
164+msgid "Send"
165+msgstr ""
166+
167+#: Dash/Apps/AppReviews.qml:136
168+msgid "Comments:"
169+msgstr ""
170+
171+#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
172+msgid "Featured"
173+msgstr ""
174+
175+#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
176+msgid "Recent"
177+msgstr ""
178+
179+#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
180+msgid "New Releases"
181+msgstr ""
182+
183+#: Dash/DashMusic.qml:30
184+msgid "Top Charting"
185+msgstr ""
186+
187+#: Dash/DashMusic.qml:91
188+msgid "Music"
189+msgstr ""
190+
191+#: Dash/DashVideos.qml:31
192+msgid "Popular Online"
193+msgstr ""
194+
195+#: Dash/DashVideos.qml:146
196+msgid "Videos"
197+msgstr ""
198+
199+#: Dash/Video/VideoPreview.qml:130
200+msgid "Directed by:"
201+msgstr ""
202+
203+#: Dash/Video/VideoPreview.qml:153
204+msgid "Starring:"
205+msgstr ""
206+
207+#: Dash/Video/VideoPreview.qml:176
208+msgid "Author:"
209+msgstr ""
210+
211+#: Greeter/Lockscreen.qml:134
212+msgid "Emergency Call"
213+msgstr ""
214+
215+#: Greeter/PassphraseLockscreen.qml:59
216+#, qt-format
217+msgid "Hello %1"
218+msgstr ""
219+
220+#: Greeter/PassphraseLockscreen.qml:59
221+msgid "Hello"
222+msgstr ""
223+
224+#: Hud/HudParametrizedActionsPage.qml:132
225+msgid "Confirm"
226+msgstr ""
227+
228+#: Hud/Hud.qml:61 Hud/Hud.qml:99 Hud/Hud.qml:372
229+msgid "Type or say a command"
230+msgstr ""
231+
232+#: Hud/Hud.qml:84
233+msgid "Loading. Please Wait..."
234+msgstr ""
235+
236+#: Hud/Hud.qml:89
237+msgid "Speak Now..."
238+msgstr ""
239+
240+#: Hud/Hud.qml:94
241+msgid "Speaking..."
242+msgstr ""
243+
244+#: Panel/SearchIndicator.qml:27
245+msgid "Search"
246+msgstr ""
247+
248+#: plugins/Unity/scope.cpp:317
249+msgid "Sorry, there is nothing that matches your search."
250+msgstr ""
251+
252+#: Shell.qml:429
253+#, qt-format
254+msgid "Please enter %1"
255+msgstr ""
po/zh_CN.po+2−29
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "对不起,没有找到您想要的结果。"
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "正在运行的应用程序"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "常用"
262−
263−#~ msgid "Installed"
264−#~ msgstr "已安装"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "可供下载"
268−
269−#~ msgid "Apps"
270−#~ msgstr "应用程序"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "常用软件"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "近期听过的音乐"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "热门在线视频"
280−
281−#~ msgid "Home"
282−#~ msgstr "主页"
po/zh_TW.po+2−29
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "很抱歉,找不到符合您想搜尋的結果。"
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "執行中的程式"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "最常使用"
262−
263−#~ msgid "Installed"
264−#~ msgstr "已安裝"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "可供下載"
268−
269−#~ msgid "Apps"
270−#~ msgstr "程式"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "常用的程式"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "最近聽過的音樂"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "線上熱門的影片"
280−
281−#~ msgid "Home"
282−#~ msgstr "家屋"
run_on_device+2−1
@@ -65,8 +65,9 @@ setup_adb_forwarding() {
6565}
6666
6767install_dependencies() {
68+ exec_with_adb rm /etc/init/ssh.override
69+ exec_with_adb service ssh start
6870 exec_with_adb apt-get update
69− exec_with_adb apt-get -y install openssh-server
7071 exec_with_ssh $SUDO apt-get -y install build-essential rsync bzr ccache gdb ninja-build devscripts equivs
7172}
7273
src/Panel/Indicators/CMakeLists.txt−1
@@ -1,2 +1 @@
11add_subdirectory(client)
2−add_subdirectory(servicefiles)
src/Panel/Indicators/servicefiles/CMakeLists.txtdeleted−14
@@ -1,14 +0,0 @@
1−file(GLOB INDICATOR_SERVICE_FILES
2− ${CMAKE_CURRENT_SOURCE_DIR}/com.canonical.indicator.messages
3−)
4−
5−# copy indicators files into build directory for shadow builds
6−add_custom_target(IndicatorsServiceFiles ALL
7− COMMAND mkdir -p ${CMAKE_BINARY_DIR}/share/unity/indicators
8− COMMAND cp ${INDICATOR_SERVICE_FILES} ${CMAKE_BINARY_DIR}/share/unity/indicators
9− DEPENDS ${INDICATOR_SERVICE_FILES}
10−)
11−
12−install(FILES ${INDICATOR_SERVICE_FILES}
13− DESTINATION ${SHELL_APP_DIR}/unity/indicators
14−)
src/Panel/Indicators/servicefiles/com.canonical.indicator.messagesdeleted−10
@@ -1,10 +0,0 @@
1−[Indicator Service]
2−Name=indicator-messages
3−ObjectPath=/com/canonical/indicator/messages
4−Position=50
5−
6−[phone]
7−ObjectPath=/com/canonical/indicator/messages/phone
8−
9−[desktop]
10−ObjectPath=/com/canonical/indicator/messages/menu
tests/autopilot/unity8/application_lifecycle/__init__.pynew file+20
@@ -0,0 +1,20 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
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+"""Tests for the application lifecycle base package."""
tests/autopilot/unity8/application_lifecycle/tests/__init__.pynew file

No changes to the content.

tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.pynew file+136
@@ -0,0 +1,136 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
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+"""Tests for the application lifecycle."""
21+
22+from __future__ import absolute_import
23+
24+from unity8.shell import disable_qml_mocking
25+from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
26+
27+from autopilot.matchers import Eventually
28+from autopilot.platform import model
29+from testtools.matchers import Equals, NotEquals
30+
31+import logging
32+
33+logger = logging.getLogger(__name__)
34+
35+
36+class ApplicationLifecycleTests(UnityTestCase):
37+
38+ scenarios = _get_device_emulation_scenarios()
39+
40+ def setUp(self):
41+ super(ApplicationLifecycleTests, self).setUp()
42+ if model() == "Desktop":
43+ self.skipTest("Test cannot be run on the desktop.")
44+
45+ def swipe_screen_from_right(self):
46+ qml_view = self.main_window.get_qml_view()
47+ width = qml_view.width
48+ height = qml_view.height
49+ start_x = width
50+ start_y = int(height/2)
51+ end_x = int(width/2)
52+ end_y = start_y
53+
54+ logger.info("Swiping screen from the right edge")
55+ self.touch.drag(start_x, start_y, end_x, end_y)
56+
57+ def _get_current_focused_app_id(self):
58+ return self._proxy.select_single("Shell").currentFocusedAppId
59+
60+ def _launch_app(self, app_name):
61+ """Launches the application *app_name*
62+
63+ Assumes that the desktop file resides at:
64+ /usr/share/applications/{app_name}.desktop
65+
66+ """
67+ desktop_file = "--desktop_file_hint="\
68+ "/usr/share/applications/{app_name}.desktop".format(
69+ app_name=app_name
70+ )
71+ return self.launch_test_application(
72+ app_name,
73+ desktop_file,
74+ "--stage_hint=main_stage",
75+ app_type='qt'
76+ )
77+
78+ @disable_qml_mocking
79+ def test_can_launch_application(self):
80+ """Must be able to launch an application."""
81+ self.launch_unity()
82+ self.main_window.get_greeter().swipe()
83+
84+ app = self._launch_app("messaging-app")
85+
86+ self.assertThat(app, NotEquals(None))
87+ self.assertThat(
88+ self._get_current_focused_app_id(),
89+ Eventually(Equals("messaging-app"))
90+ )
91+
92+ @disable_qml_mocking
93+ def test_can_launch_multiple_applications(self):
94+ """A second application launched must be focused."""
95+ self.launch_unity()
96+ self.main_window.get_greeter().swipe()
97+
98+ self._launch_app("messaging-app")
99+ self.assertThat(
100+ self._get_current_focused_app_id(),
101+ Eventually(Equals("messaging-app"))
102+ )
103+
104+ self._launch_app("address-book-app")
105+ self.assertThat(
106+ self._get_current_focused_app_id(),
107+ Eventually(Equals("address-book-app"))
108+ )
109+
110+ @disable_qml_mocking
111+ def test_app_moves_from_unfocused_to_focused(self):
112+ """An application that is in the unfocused state must be able to be
113+ brought back to the focused state.
114+
115+ """
116+ self.launch_unity()
117+ self.main_window.get_greeter().swipe()
118+
119+ self._launch_app("messaging-app")
120+ self.assertThat(
121+ self._get_current_focused_app_id(),
122+ Eventually(Equals("messaging-app"))
123+ )
124+
125+ self._launch_app("address-book-app")
126+ self.assertThat(
127+ self._get_current_focused_app_id(),
128+ Eventually(Equals("address-book-app"))
129+ )
130+
131+ self.swipe_screen_from_right()
132+
133+ self.assertThat(
134+ self._get_current_focused_app_id(),
135+ Eventually(Equals("messaging-app"))
136+ )
tests/autopilot/unity8/shell/__init__.py+10
@@ -36,3 +36,13 @@ def with_lightdm_mock(mock_type):
3636 return fn(*args, **kwargs)
3737 return wrapper
3838 return with_lightdm_mock_internal
39+
40+
41+def disable_qml_mocking(fn):
42+ """Simple decorator that disables the QML mocks from being loaded."""
43+ @wraps(fn)
44+ def wrapper(*args, **kwargs):
45+ tests_self = args[0]
46+ tests_self._qml_mock_enabled = False
47+ return fn(*args, **kwargs)
48+ return wrapper
tests/autopilot/unity8/shell/tests/__init__.py+4−1
@@ -86,6 +86,7 @@ class UnityTestCase(AutopilotTestCase):
8686
8787 self._proxy = None
8888 self._lightdm_mock_type = None
89+ self._qml_mock_enabled = True
8990 self.touch = Touch.create()
9091 self._setup_display_details()
9192
@@ -160,7 +161,9 @@ class UnityTestCase(AutopilotTestCase):
160161
161162 if self._lightdm_mock_type is None:
162163 self.patch_lightdm_mock()
163− self._setup_extra_mock_environment_patch()
164+
165+ if self._qml_mock_enabled:
166+ self._setup_extra_mock_environment_patch()
164167
165168 app_proxy = self.launch_test_application(
166169 binary_path,
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/AccountsService/AccountsService.cpp+27−4
@@ -19,15 +19,38 @@
1919#include "AccountsService.h"
2020
2121AccountsService::AccountsService(QObject* parent)
22− : QObject(parent)
22+ : QObject(parent),
23+ m_backgroundFile(TOP_SRCDIR "/graphics/phone_background.jpg")
2324{
2425}
2526
26−QVariant AccountsService::getUserProperty(const QString &, const QString &)
27+QString AccountsService::user() const
2728{
28− return QVariant(false);
29+ return "testuser";
2930}
3031
31−void AccountsService::setUserProperty(const QString &, const QString &, const QVariant &)
32+void AccountsService::setUser(const QString &user)
3233{
34+ Q_UNUSED(user)
35+}
36+
37+bool AccountsService::demoEdges() const
38+{
39+ return false;
40+}
41+
42+void AccountsService::setDemoEdges(bool demoEdges)
43+{
44+ Q_UNUSED(demoEdges)
45+}
46+
47+QString AccountsService::backgroundFile() const
48+{
49+ return m_backgroundFile;
50+}
51+
52+void AccountsService::setBackgroundFile(const QString &backgroundFile)
53+{
54+ m_backgroundFile = backgroundFile;
55+ backgroundFileChanged();
3356}
tests/mocks/AccountsService/AccountsService.h+27−3
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2012,2013 Canonical, Ltd.
2+ * Copyright (C) 2013 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -27,12 +27,36 @@
2727class AccountsService: public QObject
2828{
2929 Q_OBJECT
30+ Q_PROPERTY (QString user
31+ READ user
32+ WRITE setUser
33+ NOTIFY userChanged)
34+ Q_PROPERTY (bool demoEdges
35+ READ demoEdges
36+ WRITE setDemoEdges
37+ NOTIFY demoEdgesChanged)
38+ Q_PROPERTY (QString backgroundFile
39+ READ backgroundFile
40+ WRITE setBackgroundFile // only available in mock
41+ NOTIFY backgroundFileChanged)
3042
3143public:
3244 explicit AccountsService(QObject *parent = 0);
3345
34− Q_INVOKABLE QVariant getUserProperty(const QString &user, const QString &property);
35− Q_INVOKABLE void setUserProperty(const QString &user, const QString &property, const QVariant &value);
46+ QString user() const;
47+ void setUser(const QString &user);
48+ bool demoEdges() const;
49+ void setDemoEdges(bool demoEdges);
50+ QString backgroundFile() const;
51+ void setBackgroundFile(const QString &backgroundFile);
52+
53+Q_SIGNALS:
54+ void userChanged();
55+ void demoEdgesChanged();
56+ void backgroundFileChanged();
57+
58+private:
59+ QString m_backgroundFile;
3660};
3761
3862#endif
tests/mocks/AccountsService/CMakeLists.txt+2
@@ -1,3 +1,5 @@
1+add_definitions(-DTOP_SRCDIR="${CMAKE_SOURCE_DIR}")
2+
13add_library(MockAccountsService-qml MODULE
24 AccountsService.cpp
35 plugin.cpp
tests/mocks/LightDM/demo/GreeterPrivate.cpp+4−2
@@ -55,11 +55,13 @@ void GreeterPrivate::handleRespond(const QString &response)
5555 QSettings settings(QDir::homePath() + "/.unity8-greeter-demo", QSettings::NativeFormat);
5656 QVariant password = settings.value("password", "none");
5757
58+ QString passwordValue;
5859 if (password == "pin") {
59− authenticated = (response == "1234");
60+ passwordValue = settings.value("passwordValue", "1234").toString();
6061 } else {
61− authenticated = (response == "password");
62+ passwordValue = settings.value("passwordValue", "password").toString();
6263 }
64+ authenticated = (response == passwordValue);
6365 Q_EMIT q->authenticationComplete();
6466}
6567
tests/mocks/Ubuntu/Application/CMakeLists.txtdeleted−29
@@ -1,29 +0,0 @@
1−set(FakeUbuntuApplicationQml_SOURCES
2− plugin.cpp
3− ApplicationInfo.cpp
4− ApplicationImage.cpp
5− ApplicationListModel.cpp
6− ApplicationManager.cpp
7−)
8−
9−add_library(FakeUbuntuApplicationQml MODULE ${FakeUbuntuApplicationQml_SOURCES})
10−
11−qt5_use_modules(FakeUbuntuApplicationQml Core Quick)
12−
13−# copy files into build directory for shadow builds
14−add_custom_target(UbuntuAppQmlDirFile ALL
15− COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/qmldir" ${CMAKE_CURRENT_BINARY_DIR}
16− DEPENDS qmldir
17−)
18−add_custom_target(InputFilterAreaQmlFile ALL
19− COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/InputFilterArea.qml" ${CMAKE_CURRENT_BINARY_DIR}
20− DEPENDS InputFilterArea.qml
21−)
22−
23−install(TARGETS FakeUbuntuApplicationQml
24− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/mocks/Ubuntu/Application
25− )
26−
27−install(FILES qmldir InputFilterArea.qml
28− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/mocks/Ubuntu/Application
29− )
tests/mocks/Ubuntu/Application/qmldirdeleted−3
@@ -1,3 +0,0 @@
1−module Ubuntu.Application
2−plugin FakeUbuntuApplicationQml
3−InputFilterArea 0.1 InputFilterArea.qml
tests/mocks/Ubuntu/CMakeLists.txt−1
@@ -1,2 +1 @@
1−add_subdirectory(Application)
21add_subdirectory(DownloadDaemonListener)
tests/mocks/Ubuntu/DownloadDaemonListener/MockDownloadTracker.cpp+5
@@ -63,5 +63,10 @@ void MockDownloadTracker::startService()
6363 if(!m_service.isEmpty() && !m_dbusPath.isEmpty()) {
6464 m_active = true;
6565 Q_EMIT serviceReadyChanged(m_active);
66+ if(m_dbusPath == "finish") {
67+ Q_EMIT finished("downloadComplete");
68+ }else if(m_dbusPath == "error") {
69+ Q_EMIT error("DOWNLOAD ERROR");
70+ }
6671 }
6772}
tests/mocks/Ubuntu/Application/ApplicationImage.cpp → tests/mocks/Unity/Application/ApplicationImage.cpprenamed

The content is the same.

tests/mocks/Ubuntu/Application/ApplicationImage.h → tests/mocks/Unity/Application/ApplicationImage.hrenamed

The content is the same.

tests/mocks/Ubuntu/Application/ApplicationInfo.cpp → tests/mocks/Unity/Application/ApplicationInfo.cpprenamed+15−2
@@ -21,11 +21,24 @@
2121#include <QQuickView>
2222#include <QQmlComponent>
2323
24+ApplicationInfo::ApplicationInfo(const QString &appId, QObject *parent)
25+ : ApplicationInfoInterface(appId, parent)
26+ ,m_appId(appId)
27+ ,m_stage(MainStage)
28+ ,m_state(Starting)
29+ ,m_focused(false)
30+ ,m_fullscreen(false)
31+ ,m_windowItem(0)
32+ ,m_windowComponent(0)
33+ ,m_parentItem(0)
34+{
35+}
36+
2437ApplicationInfo::ApplicationInfo(QObject *parent)
25− : QObject(parent)
26− ,m_handle(0)
38+ : ApplicationInfoInterface(QString(), parent)
2739 ,m_stage(MainStage)
2840 ,m_state(Starting)
41+ ,m_focused(false)
2942 ,m_fullscreen(false)
3043 ,m_windowItem(0)
3144 ,m_windowComponent(0)
tests/mocks/Ubuntu/Application/ApplicationInfo.h → tests/mocks/Unity/Application/ApplicationInfo.hrenamed+12−18
@@ -22,21 +22,18 @@
2222
2323class QQuickItem;
2424
25+// unity-api
26+#include <unity/shell/application/ApplicationInfoInterface.h>
27+
2528// A pretty dumb file. Just a container for properties.
2629// Implemented in C++ instead of QML just because of the enumerations
2730// See QTBUG-14861
28−class ApplicationInfo : public QObject {
31+
32+using namespace unity::shell::application;
33+
34+class ApplicationInfo : public ApplicationInfoInterface {
2935 Q_OBJECT
30− Q_ENUMS(Stage)
31− Q_ENUMS(State)
32− Q_PROPERTY(QString desktopFile READ desktopFile WRITE setDesktopFile NOTIFY desktopFileChanged)
33− Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
34− Q_PROPERTY(QString comment READ comment WRITE setComment NOTIFY commentChanged)
35− Q_PROPERTY(QString icon READ icon WRITE setIcon NOTIFY iconChanged)
36− Q_PROPERTY(QString exec READ exec WRITE setExec NOTIFY execChanged)
37− Q_PROPERTY(qint64 handle READ handle WRITE setHandle NOTIFY handleChanged)
38− Q_PROPERTY(Stage stage READ stage WRITE setStage NOTIFY stageChanged)
39− Q_PROPERTY(State state READ state WRITE setState NOTIFY stateChanged)
36+
4037 Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged)
4138
4239 // Only exists in this fake implementation
@@ -48,10 +45,8 @@ class ApplicationInfo : public QObject {
4845 Q_PROPERTY(QString windowQml READ windowQml WRITE setWindowQml NOTIFY windowQmlChanged)
4946
5047 public:
51− enum Stage { MainStage, SideStage };
52− enum State { Starting, Running };
53−
5448 ApplicationInfo(QObject *parent = NULL);
49+ ApplicationInfo(const QString &appId, QObject *parent = NULL);
5550
5651 #define IMPLEMENT_PROPERTY(name, Name, type) \
5752 public: \
@@ -68,14 +63,13 @@ class ApplicationInfo : public QObject {
6863 private: \
6964 type m_##name;
7065
71− IMPLEMENT_PROPERTY(desktopFile, DesktopFile, QString)
66+ IMPLEMENT_PROPERTY(appId, AppId, QString)
7267 IMPLEMENT_PROPERTY(name, Name, QString)
7368 IMPLEMENT_PROPERTY(comment, Comment, QString)
74− IMPLEMENT_PROPERTY(icon, Icon, QString)
75− IMPLEMENT_PROPERTY(exec, Exec, QString)
76− IMPLEMENT_PROPERTY(handle, Handle, qint64)
69+ IMPLEMENT_PROPERTY(icon, Icon, QUrl)
7770 IMPLEMENT_PROPERTY(stage, Stage, Stage)
7871 IMPLEMENT_PROPERTY(state, State, State)
72+ IMPLEMENT_PROPERTY(focused, Focused, bool)
7973 IMPLEMENT_PROPERTY(fullscreen, Fullscreen, bool)
8074 IMPLEMENT_PROPERTY(imageQml, ImageQml, QString)
8175 IMPLEMENT_PROPERTY(windowQml, WindowQml, QString)
tests/mocks/Ubuntu/Application/ApplicationListModel.cpp → tests/mocks/Unity/Application/ApplicationListModel.cpprenamed

The content is the same.

tests/mocks/Ubuntu/Application/ApplicationListModel.h → tests/mocks/Unity/Application/ApplicationListModel.hrenamed

The content is the same.

tests/mocks/Ubuntu/Application/ApplicationManager.cpp → tests/mocks/Unity/Application/ApplicationManager.cpprenamed+185−153
@@ -16,7 +16,6 @@
1616
1717#include "ApplicationManager.h"
1818#include "ApplicationInfo.h"
19−#include "ApplicationListModel.h"
2019#include "paths.h"
2120
2221#include <QDir>
@@ -26,11 +25,7 @@
2625#include <QQmlComponent>
2726
2827ApplicationManager::ApplicationManager(QObject *parent)
29− : QObject(parent)
30− , m_mainStageApplications(new ApplicationListModel())
31− , m_sideStageApplications(new ApplicationListModel())
32− , m_mainStageFocusedApplication(0)
33− , m_sideStageFocusedApplication(0)
28+ : ApplicationManagerInterface(parent)
3429 , m_mainStageComponent(0)
3530 , m_mainStage(0)
3631 , m_sideStageComponent(0)
@@ -41,8 +36,84 @@ ApplicationManager::ApplicationManager(QObject *parent)
4136
4237ApplicationManager::~ApplicationManager()
4338{
44− delete m_mainStageApplications;
45− delete m_sideStageApplications;
39+}
40+
41+int ApplicationManager::rowCount(const QModelIndex& parent) const {
42+ return !parent.isValid() ? m_runningApplications.size() : 0;
43+}
44+
45+QVariant ApplicationManager::data(const QModelIndex& index, int role) const {
46+ if (index.row() < 0 || index.row() >= m_runningApplications.size())
47+ return QVariant();
48+
49+ auto app = m_runningApplications.at(index.row());
50+ switch(role) {
51+ case RoleAppId:
52+ return app->appId();
53+ case RoleName:
54+ return app->name();
55+ case RoleComment:
56+ return app->comment();
57+ case RoleIcon:
58+ return app->icon();
59+ case RoleStage:
60+ return app->stage();
61+ case RoleState:
62+ return app->state();
63+ case RoleFocused:
64+ return app->focused();
65+ default:
66+ return QVariant();
67+ }
68+}
69+
70+ApplicationInfo *ApplicationManager::get(int row) const {
71+ if (row < 0 || row >= m_runningApplications.size())
72+ return nullptr;
73+ return m_runningApplications.at(row);
74+}
75+
76+ApplicationInfo *ApplicationManager::findApplication(const QString &appId) const {
77+ for (ApplicationInfo *app : m_runningApplications) {
78+ if (app->appId() == appId) {
79+ return app;
80+ }
81+ }
82+ return nullptr;
83+}
84+
85+void ApplicationManager::add(ApplicationInfo *application) {
86+ if (!application)
87+ return;
88+
89+ beginInsertRows(QModelIndex(), m_runningApplications.size(), m_runningApplications.size());
90+ m_runningApplications.append(application);
91+ endInsertRows();
92+ Q_EMIT countChanged();
93+}
94+
95+void ApplicationManager::remove(ApplicationInfo *application) {
96+ int i = m_runningApplications.indexOf(application);
97+ if (i != -1) {
98+ beginRemoveRows(QModelIndex(), i, i);
99+ m_runningApplications.removeAt(i);
100+ endRemoveRows();
101+ Q_EMIT countChanged();
102+ }
103+}
104+
105+void ApplicationManager::move(int from, int to) {
106+ if (from == to) return;
107+
108+ if (from >= 0 && from < m_runningApplications.size() && to >= 0 && to < m_runningApplications.size()) {
109+ QModelIndex parent;
110+ /* When moving an item down, the destination index needs to be incremented
111+ * by one, as explained in the documentation:
112+ * http://qt-project.org/doc/qt-5.0/qtcore/qabstractitemmodel.html#beginMoveRows */
113+ beginMoveRows(parent, from, from, parent, to + (to > from ? 1 : 0));
114+ m_runningApplications.move(from, to);
115+ endMoveRows();
116+ }
46117}
47118
48119int ApplicationManager::keyboardHeight() const
@@ -70,36 +141,21 @@ ApplicationManager::FormFactorHint ApplicationManager::formFactorHint() const
70141 return PhoneFormFactor;
71142}
72143
73−ApplicationListModel* ApplicationManager::mainStageApplications() const
74−{
75− return m_mainStageApplications;
76−}
77−
78−ApplicationListModel* ApplicationManager::sideStageApplications() const
144+ApplicationInfo* ApplicationManager::startApplication(const QString &appId,
145+ const QStringList &arguments)
79146{
80− return m_sideStageApplications;
147+ return startApplication(appId, NoFlag, arguments);
81148}
82149
83−ApplicationInfo* ApplicationManager::mainStageFocusedApplication() const
84−{
85− return m_mainStageFocusedApplication;
86−}
87−
88−ApplicationInfo* ApplicationManager::sideStageFocusedApplication() const
89−{
90− return m_sideStageFocusedApplication;
91−}
92−
93−ApplicationInfo* ApplicationManager::startProcess(QString desktopFile,
150+ApplicationInfo* ApplicationManager::startApplication(const QString &appId,
94151 ExecFlags flags,
95− QStringList arguments)
152+ const QStringList &arguments)
96153{
97154 Q_UNUSED(arguments)
98155 ApplicationInfo *application = 0;
99156
100− for (int i = 0; i < m_availableApplications.count(); ++i) {
101− ApplicationInfo *availableApp = m_availableApplications[i];
102− if (availableApp->desktopFile() == desktopFile) {
157+ for (ApplicationInfo *availableApp : m_availableApplications) {
158+ if (availableApp->appId() == appId) {
103159 application = availableApp;
104160 break;
105161 }
@@ -109,86 +165,91 @@ ApplicationInfo* ApplicationManager::startProcess(QString desktopFile,
109165 return 0;
110166
111167 if (flags.testFlag(ApplicationManager::ForceMainStage)
112− || application->stage() == ApplicationInfo::MainStage) {
113− m_mainStageApplications->add(application);
114− } else {
115− m_sideStageApplications->add(application);
168+ && application->stage() == ApplicationInfo::SideStage) {
169+ application->setStage(ApplicationInfo::MainStage);
116170 }
171+ add(application);
117172
118173 return application;
119174}
120175
121−void ApplicationManager::stopProcess(ApplicationInfo* application)
176+bool ApplicationManager::stopApplication(const QString &appId)
122177{
123− if (m_mainStageApplications->contains(application)) {
124− m_mainStageApplications->remove(application);
178+ ApplicationInfo *application = findApplication(appId);
179+ if (application == nullptr)
180+ return false;
125181
126− if (m_mainStageFocusedApplication == application) {
127− m_mainStageFocusedApplication = 0;
128− Q_EMIT mainStageFocusedApplicationChanged();
129− }
130− } else if (m_sideStageApplications->contains(application)){
131− m_sideStageApplications->remove(application);
182+ remove(application);
183+ Q_EMIT focusedApplicationIdChanged();
184+ return true;
185+}
132186
133− if (m_sideStageFocusedApplication == application) {
134− m_sideStageFocusedApplication = 0;
135− Q_EMIT sideStageFocusedApplicationChanged();
187+QString ApplicationManager::focusedApplicationId() const {
188+ for (ApplicationInfo *app : m_runningApplications) {
189+ if (app->focused()) {
190+ return app->appId();
136191 }
137192 }
193+ return QString();
138194}
139195
140−void ApplicationManager::focusApplication(int handle)
196+bool ApplicationManager::focusApplication(const QString &appId)
141197{
142− for (int i = 0; i < m_mainStageApplications->m_applications.count(); ++i) {
143− ApplicationInfo *application = m_mainStageApplications->m_applications[i];
144− if (application->handle() == handle) {
145− if (m_mainStageFocusedApplication)
146− m_mainStageFocusedApplication->hideWindow();
147− m_mainStageFocusedApplication = application;
148− if (!m_mainStage)
149− createMainStage();
150− application->showWindow(m_mainStage);
151− m_mainStage->setZ(-1000);
152− if (m_sideStage)
153− m_sideStage->setZ(-2000);
154− Q_EMIT mainStageFocusedApplicationChanged();
155− return;
198+ ApplicationInfo *application = findApplication(appId);
199+ if (application == nullptr)
200+ return false;
201+
202+ if (application->stage() == ApplicationInfo::MainStage) {
203+ // unfocus currently focused mainstage app
204+ for (ApplicationInfo *app : m_runningApplications) {
205+ if (app->focused() && app->stage() == ApplicationInfo::MainStage) {
206+ app->setFocused(false);
207+ app->hideWindow();
208+ }
156209 }
157− }
158210
159− for (int i = 0; i < m_sideStageApplications->m_applications.count(); ++i) {
160− ApplicationInfo *application = m_sideStageApplications->m_applications[i];
161− if (application->handle() == handle) {
162− if (m_sideStageFocusedApplication)
163− m_sideStageFocusedApplication->hideWindow();
164− m_sideStageFocusedApplication = application;
165− if (!m_sideStage)
166− createSideStage();
167− application->showWindow(m_sideStage);
168− m_sideStage->setZ(-1000);
169− if (m_mainStage)
170− m_mainStage->setZ(-2000);
171− Q_EMIT sideStageFocusedApplicationChanged();
172− return;
211+ // focus this app
212+ application->setFocused(true);
213+ if (!m_mainStage)
214+ createMainStage();
215+ application->showWindow(m_mainStage);
216+ m_mainStage->setZ(-1000);
217+ if (m_sideStage)
218+ m_sideStage->setZ(-2000);
219+ } else if (application->stage() == ApplicationInfo::SideStage) {
220+ // unfocus currently focused sidestage app
221+ for (ApplicationInfo *app : m_runningApplications) {
222+ if (app->focused() && app->stage() == ApplicationInfo::SideStage) {
223+ app->setFocused(false);
224+ app->hideWindow();
225+ }
173226 }
227+
228+ // focus this app
229+ application->setFocused(true);
230+ if (!m_sideStage)
231+ createSideStage();
232+ application->showWindow(m_sideStage);
233+ m_sideStage->setZ(-1000);
234+ if (m_mainStage)
235+ m_mainStage->setZ(-2000);
174236 }
237+
238+ // move app to top of stack
239+ move(m_runningApplications.indexOf(application), 0);
240+ Q_EMIT focusedApplicationIdChanged();
241+ return true;
175242}
176243
177−void ApplicationManager::unfocusCurrentApplication(StageHint stageHint)
244+void ApplicationManager::unfocusCurrentApplication()
178245{
179− if (stageHint == SideStage) {
180− if (m_sideStageFocusedApplication) {
181− m_sideStageFocusedApplication->hideWindow();
182− m_sideStageFocusedApplication = 0;
183− Q_EMIT sideStageFocusedApplicationChanged();
184− }
185− } else {
186− if (m_mainStageFocusedApplication) {
187− m_mainStageFocusedApplication->hideWindow();
188− m_mainStageFocusedApplication = 0;
189− Q_EMIT mainStageFocusedApplicationChanged();
246+ for (ApplicationInfo *app : m_runningApplications) {
247+ if (app->focused()) {
248+ app->hideWindow();
249+ app->setFocused(false);
190250 }
191251 }
252+ Q_EMIT focusedApplicationIdChanged();
192253}
193254
194255void ApplicationManager::generateQmlStrings(ApplicationInfo *application)
@@ -213,7 +274,7 @@ void ApplicationManager::generateQmlStrings(ApplicationInfo *application)
213274 " fillMode: Image.PreserveAspectCrop\n"
214275 "}").arg(topMargin)
215276 .arg(shellAppDirectory())
216− .arg(application->icon());
277+ .arg(application->icon().toString());
217278 application->setWindowQml(windowQml);
218279
219280 QString imageQml = QString(
@@ -224,159 +285,130 @@ void ApplicationManager::generateQmlStrings(ApplicationInfo *application)
224285 " smooth: true\n"
225286 " fillMode: Image.PreserveAspectCrop\n"
226287 "}").arg(shellAppDirectory())
227− .arg(application->icon());
288+ .arg(application->icon().toString());
228289 application->setImageQml(imageQml);
229290}
230291
231292void ApplicationManager::buildListOfAvailableApplications()
232293{
233294 ApplicationInfo *application;
234− qint64 nextHandle = 1;
235295
236296 application = new ApplicationInfo(this);
237− application->setDesktopFile("/usr/share/applications/phone-app.desktop");
297+ application->setAppId("phone-app");
238298 application->setName("Phone");
239− application->setIcon("phone");
240− application->setExec("/usr/bin/phone-app");
299+ application->setIcon(QUrl("phone"));
241300 application->setStage(ApplicationInfo::SideStage);
242− application->setHandle(nextHandle++);
243301 generateQmlStrings(application);
244302 m_availableApplications.append(application);
245303
246304 application = new ApplicationInfo(this);
247− application->setDesktopFile("/usr/share/applications/camera-app.desktop");
305+ application->setAppId("camera-app");
248306 application->setName("Camera");
249− application->setIcon("camera");
307+ application->setIcon(QUrl("camera"));
250308 application->setFullscreen(true);
251− application->setExec("/usr/bin/camera-app --fullscreen");
252− application->setHandle(nextHandle++);
253309 generateQmlStrings(application);
254310 m_availableApplications.append(application);
255311
256312 application = new ApplicationInfo(this);
257− application->setDesktopFile("/usr/share/applications/gallery-app.desktop");
313+ application->setAppId("gallery-app");
258314 application->setName("Gallery");
259− application->setIcon("gallery");
260− application->setExec("/usr/bin/gallery-app");
261− application->setHandle(nextHandle++);
315+ application->setIcon(QUrl("gallery"));
262316 generateQmlStrings(application);
263317 m_availableApplications.append(application);
264318
265319 application = new ApplicationInfo(this);
266− application->setDesktopFile("/usr/share/applications/facebook-webapp.desktop");
320+ application->setAppId("facebook-webapp");
267321 application->setName("Facebook");
268− application->setIcon("facebook");
269− application->setExec("/usr/bin/webbrowser-app --chromeless http://m.facebook.com");
322+ application->setIcon(QUrl("facebook"));
270323 application->setStage(ApplicationInfo::SideStage);
271− application->setHandle(nextHandle++);
272324 generateQmlStrings(application);
273325 m_availableApplications.append(application);
274326
275327 application = new ApplicationInfo(this);
276− application->setDesktopFile("/usr/share/applications/webbrowser-app.desktop");
328+ application->setAppId("webbrowser-app");
277329 application->setName("Browser");
278− application->setIcon("browser");
279− application->setExec("/usr/bin/webbrowser-app");
280− application->setHandle(nextHandle++);
330+ application->setIcon(QUrl("browser"));
281331 generateQmlStrings(application);
282332 m_availableApplications.append(application);
283333
284334 application = new ApplicationInfo(this);
285− application->setDesktopFile("/usr/share/applications/twitter-webapp.desktop");
335+ application->setAppId("twitter-webapp");
286336 application->setName("Twitter");
287− application->setIcon("twitter");
288− application->setExec("/usr/bin/webbrowser-app --chromeless http://www.twitter.com");
337+ application->setIcon(QUrl("twitter"));
289338 application->setStage(ApplicationInfo::SideStage);
290− application->setHandle(nextHandle++);
291339 generateQmlStrings(application);
292340 m_availableApplications.append(application);
293341
294342 application = new ApplicationInfo(this);
295− application->setDesktopFile("/usr/share/applications/gmail-webapp.desktop");
343+ application->setAppId("gmail-webapp");
296344 application->setName("GMail");
297− application->setIcon("gmail");
298− application->setExec("/usr/bin/webbrowser-app --chromeless http://m.gmail.com");
299− application->setHandle(nextHandle++);
345+ application->setIcon(QUrl("gmail"));
300346 m_availableApplications.append(application);
301347
302348 application = new ApplicationInfo(this);
303− application->setDesktopFile("/usr/share/applications/ubuntu-weather-app.desktop");
349+ application->setAppId("ubuntu-weather-app");
304350 application->setName("Weather");
305− application->setIcon("weather");
306− application->setExec("/usr/bin/qmlscene /usr/share/ubuntu-weather-app/ubuntu-weather-app.qml");
351+ application->setIcon(QUrl("weather"));
307352 application->setStage(ApplicationInfo::SideStage);
308− application->setHandle(nextHandle++);
309353 generateQmlStrings(application);
310354 m_availableApplications.append(application);
311355
312356 application = new ApplicationInfo(this);
313− application->setDesktopFile("/usr/share/applications/notes-app.desktop");
357+ application->setAppId("notes-app");
314358 application->setName("Notepad");
315− application->setIcon("notepad");
316− application->setExec("/usr/bin/qmlscene /usr/share/notes-app/NotesApp.qml");
359+ application->setIcon(QUrl("notepad"));
317360 application->setStage(ApplicationInfo::SideStage);
318− application->setHandle(nextHandle++);
319361 m_availableApplications.append(application);
320362
321363 application = new ApplicationInfo(this);
322− application->setDesktopFile("/usr/share/applications/calendar-app.desktop");
364+ application->setAppId("calendar-app");
323365 application->setName("Calendar");
324− application->setIcon("calendar");
325− application->setExec("/usr/bin/qmlscene /usr/share/calendar-app/calendar.qml");
366+ application->setIcon(QUrl("calendar"));
326367 application->setStage(ApplicationInfo::SideStage);
327− application->setHandle(nextHandle++);
328368 m_availableApplications.append(application);
329369
330370 application = new ApplicationInfo(this);
331− application->setDesktopFile("/usr/share/applications/mediaplayer-app.desktop");
371+ application->setAppId("mediaplayer-app");
332372 application->setName("Media Player");
333− application->setIcon("mediaplayer-app");
373+ application->setIcon(QUrl("mediaplayer-app"));
334374 application->setFullscreen(true);
335− application->setExec("/usr/bin/mediaplayer-app");
336− application->setHandle(nextHandle++);
337375 m_availableApplications.append(application);
338376
339377 application = new ApplicationInfo(this);
340− application->setDesktopFile("/usr/share/applications/evernote.desktop");
378+ application->setAppId("evernote");
341379 application->setName("Evernote");
342− application->setIcon("evernote");
343− application->setHandle(nextHandle++);
380+ application->setIcon(QUrl("evernote"));
344381 m_availableApplications.append(application);
345382
346383 application = new ApplicationInfo(this);
347− application->setDesktopFile("/usr/share/applications/map.desktop");
384+ application->setAppId("map");
348385 application->setName("Map");
349− application->setIcon("map");
350− application->setHandle(nextHandle++);
386+ application->setIcon(QUrl("map"));
351387 generateQmlStrings(application);
352388 m_availableApplications.append(application);
353389
354390 application = new ApplicationInfo(this);
355− application->setDesktopFile("/usr/share/applications/pinterest.desktop");
391+ application->setAppId("pinterest");
356392 application->setName("Pinterest");
357− application->setIcon("pinterest");
358− application->setHandle(nextHandle++);
393+ application->setIcon(QUrl("pinterest"));
359394 m_availableApplications.append(application);
360395
361396 application = new ApplicationInfo(this);
362− application->setDesktopFile("/usr/share/applications/soundcloud.desktop");
397+ application->setAppId("soundcloud");
363398 application->setName("SoundCloud");
364− application->setIcon("soundcloud");
365− application->setHandle(nextHandle++);
399+ application->setIcon(QUrl("soundcloud"));
366400 m_availableApplications.append(application);
367401
368402 application = new ApplicationInfo(this);
369− application->setDesktopFile("/usr/share/applications/wikipedia.desktop");
403+ application->setAppId("wikipedia");
370404 application->setName("Wikipedia");
371− application->setIcon("wikipedia");
372− application->setHandle(nextHandle++);
405+ application->setIcon(QUrl("wikipedia"));
373406 m_availableApplications.append(application);
374407
375408 application = new ApplicationInfo(this);
376− application->setDesktopFile("/usr/share/applications/youtube.desktop");
409+ application->setAppId("youtube");
377410 application->setName("YouTube");
378− application->setIcon("youtube");
379− application->setHandle(nextHandle++);
411+ application->setIcon(QUrl("youtube"));
380412 m_availableApplications.append(application);
381413}
382414
tests/mocks/Ubuntu/Application/ApplicationManager.h → tests/mocks/Unity/Application/ApplicationManager.hrenamed+26−26
@@ -20,12 +20,15 @@
2020#include <QObject>
2121#include <QList>
2222#include <QStringList>
23−#include "ApplicationListModel.h"
2423#include "ApplicationInfo.h"
2524
25+// unity-api
26+#include <unity/shell/application/ApplicationManagerInterface.h>
27+
2628class QQuickItem;
29+using namespace unity::shell::application;
2730
28−class ApplicationManager : public QObject {
31+class ApplicationManager : public ApplicationManagerInterface {
2932 Q_OBJECT
3033 Q_ENUMS(Role)
3134 Q_ENUMS(StageHint)
@@ -39,12 +42,6 @@ class ApplicationManager : public QObject {
3942 Q_PROPERTY(int sideStageWidth READ sideStageWidth)
4043 Q_PROPERTY(StageHint stageHint READ stageHint)
4144 Q_PROPERTY(FormFactorHint formFactorHint READ formFactorHint)
42− Q_PROPERTY(ApplicationListModel* mainStageApplications READ mainStageApplications)
43− Q_PROPERTY(ApplicationListModel* sideStageApplications READ sideStageApplications)
44− Q_PROPERTY(ApplicationInfo* mainStageFocusedApplication READ mainStageFocusedApplication
45− NOTIFY mainStageFocusedApplicationChanged)
46− Q_PROPERTY(ApplicationInfo* sideStageFocusedApplication READ sideStageFocusedApplication
47− NOTIFY sideStageFocusedApplicationChanged)
4845
4946 Q_PROPERTY(bool fake READ fake CONSTANT)
5047
@@ -64,7 +61,8 @@ class ApplicationManager : public QObject {
6461 DesktopFormFactor, PhoneFormFactor, TabletFormFactor
6562 };
6663 enum FavoriteApplication {
67− CameraApplication, GalleryApplication, BrowserApplication, ShareApplication
64+ CameraApplication, GalleryApplication, BrowserApplication, ShareApplication,
65+ PhoneApplication, DialerApplication, MessagingApplication, AddressbookApplication
6866 };
6967 enum Flag {
7068 NoFlag = 0x0,
@@ -77,29 +75,34 @@ class ApplicationManager : public QObject {
7775 int sideStageWidth() const;
7876 StageHint stageHint() const;
7977 FormFactorHint formFactorHint() const;
80− ApplicationListModel* mainStageApplications() const;
81− ApplicationListModel* sideStageApplications() const;
82− ApplicationInfo* mainStageFocusedApplication() const;
83− ApplicationInfo* sideStageFocusedApplication() const;
8478
8579 bool fake() { return true; }
8680
87− Q_INVOKABLE void focusApplication(int handle);
88− Q_INVOKABLE void unfocusCurrentApplication(StageHint stageHint);
89− Q_INVOKABLE ApplicationInfo* startProcess(QString desktopFile,
90− ExecFlags flags,
91− QStringList arguments = QStringList());
92− Q_INVOKABLE void stopProcess(ApplicationInfo* application);
93− Q_INVOKABLE void startWatcher() {}
81+ // QAbstractItemModel methods.
82+ int rowCount(const QModelIndex& parent = QModelIndex()) const override;
83+ QVariant data(const QModelIndex& index, int role) const override;
84+ Q_INVOKABLE ApplicationInfo *get(int index) const override;
85+ Q_INVOKABLE ApplicationInfo *findApplication(const QString &appId) const override;
86+
87+ Q_INVOKABLE void move(int from, int to);
88+
89+ // Application control methods
90+ Q_INVOKABLE bool focusApplication(const QString &appId) override;
91+ Q_INVOKABLE void unfocusCurrentApplication() override;
92+ Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, const QStringList &arguments = QStringList()) override;
93+ Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, ExecFlags flags, const QStringList &arguments = QStringList());
94+ Q_INVOKABLE bool stopApplication(const QString &appId) override;
95+
96+ QString focusedApplicationId() const override;
9497
9598 Q_SIGNALS:
9699 void keyboardHeightChanged();
97100 void keyboardVisibleChanged();
98− void mainStageFocusedApplicationChanged();
99− void sideStageFocusedApplicationChanged();
100101 void focusRequested(FavoriteApplication favoriteApplication);
101102
102103 private:
104+ void add(ApplicationInfo *application);
105+ void remove(ApplicationInfo* application);
103106 void showApplicationWindow(ApplicationInfo *application);
104107 void buildListOfAvailableApplications();
105108 void generateQmlStrings(ApplicationInfo *application);
@@ -109,10 +112,7 @@ class ApplicationManager : public QObject {
109112 void createSideStage();
110113 int m_keyboardHeight;
111114 bool m_keyboardVisible;
112− ApplicationListModel* m_mainStageApplications;
113− ApplicationListModel* m_sideStageApplications;
114− ApplicationInfo* m_mainStageFocusedApplication;
115− ApplicationInfo* m_sideStageFocusedApplication;
115+ QList<ApplicationInfo*> m_runningApplications;
116116 QList<ApplicationInfo*> m_availableApplications;
117117 QQmlComponent *m_mainStageComponent;
118118 QQuickItem *m_mainStage;
tests/mocks/Unity/Application/CMakeLists.txtnew file+37
@@ -0,0 +1,37 @@
1+include(FindPkgConfig)
2+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application)
3+
4+set(FakeUnityApplicationQml_SOURCES
5+ plugin.cpp
6+ ApplicationInfo.cpp
7+ ApplicationImage.cpp
8+ ApplicationManager.cpp
9+ ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
10+ ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
11+)
12+
13+add_library(FakeUnityApplicationQml MODULE ${FakeUnityApplicationQml_SOURCES})
14+
15+qt5_use_modules(FakeUnityApplicationQml Core Quick)
16+
17+# copy files into build directory for shadow builds
18+add_custom_target(UnityAppQmlDirFile ALL
19+ COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/qmldir" ${CMAKE_CURRENT_BINARY_DIR}
20+ DEPENDS qmldir
21+)
22+add_custom_target(InputFilterAreaQmlFile ALL
23+ COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/InputFilterArea.qml" ${CMAKE_CURRENT_BINARY_DIR}
24+ DEPENDS InputFilterArea.qml
25+)
26+add_custom_target(OSKControllerQmlFile ALL
27+ COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/OSKController.qml" ${CMAKE_CURRENT_BINARY_DIR}
28+ DEPENDS OSKController.qml
29+)
30+
31+install(TARGETS FakeUnityApplicationQml
32+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/mocks/Unity/Application
33+ )
34+
35+install(FILES qmldir InputFilterArea.qml OSKController.qml
36+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/mocks/Unity/Application
37+ )
tests/mocks/Ubuntu/Application/InputFilterArea.qml → tests/mocks/Unity/Application/InputFilterArea.qmlrenamed

The content is the same.

tests/mocks/Unity/Application/OSKController.qmlnew file+20
@@ -0,0 +1,20 @@
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+
19+Item {
20+}
tests/mocks/Ubuntu/Application/plugin.cpp → tests/mocks/Unity/Application/plugin.cpprenamed+6−5
@@ -17,7 +17,6 @@
1717#include "plugin.h"
1818#include "ApplicationInfo.h"
1919#include "ApplicationImage.h"
20−#include "ApplicationListModel.h"
2120#include "ApplicationManager.h"
2221
2322#include <qqml.h>
@@ -28,11 +27,13 @@ static QObject* applicationManagerSingleton(QQmlEngine* engine, QJSEngine* scrip
2827 return new ApplicationManager();
2928}
3029
31−void FakeUbuntuApplicationQmlPlugin::registerTypes(const char *uri)
30+void FakeUnityApplicationQmlPlugin::registerTypes(const char *uri)
3231{
33− qmlRegisterSingletonType<ApplicationManager>(
34− uri, 0, 1, "ApplicationManager", applicationManagerSingleton);
32+ qmlRegisterUncreatableType<unity::shell::application::ApplicationManagerInterface>(uri, 0, 1, "ApplicationManagerInterface", "Abstract interface. Cannot be created in QML");
33+ qmlRegisterSingletonType<ApplicationManager>(uri, 0, 1, "ApplicationManager", applicationManagerSingleton);
34+
35+ qmlRegisterUncreatableType<unity::shell::application::ApplicationInfoInterface>(uri, 0, 1, "ApplicationInfoInterface", "Abstract interface. Cannot be created in QML");
3536 qmlRegisterType<ApplicationInfo>(uri, 0, 1, "ApplicationInfo");
37+
3638 qmlRegisterType<ApplicationImage>(uri, 0, 1, "ApplicationImage");
37− qmlRegisterType<ApplicationListModel>(uri, 0, 1, "ApplicationListModel");
3839}
tests/mocks/Ubuntu/Application/plugin.h → tests/mocks/Unity/Application/plugin.hrenamed+1−1
@@ -19,7 +19,7 @@
1919
2020#include <QQmlExtensionPlugin>
2121
22−class FakeUbuntuApplicationQmlPlugin : public QQmlExtensionPlugin
22+class FakeUnityApplicationQmlPlugin : public QQmlExtensionPlugin
2323{
2424 Q_OBJECT
2525 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
tests/mocks/Unity/Application/qmldirnew file+4
@@ -0,0 +1,4 @@
1+module Unity.Application
2+plugin FakeUnityApplicationQml
3+InputFilterArea 0.1 InputFilterArea.qml
4+OSKController 0.1 OSKController.qml
tests/mocks/Unity/CMakeLists.txt+4
@@ -1,3 +1,4 @@
1+add_subdirectory(Application)
12add_subdirectory(Indicators)
23
34pkg_search_module(DEE dee-1.0 REQUIRED)
@@ -17,6 +18,9 @@ add_definitions(-DQT_NO_KEYWORDS)
1718
1819set(UnityQML_SOURCES
1920 ${CMAKE_SOURCE_DIR}/plugins/Unity/categoryresults.cpp
21+ ${CMAKE_SOURCE_DIR}/plugins/Unity/iconutils.cpp
22+ fake_applications_scope.cpp
23+ fake_preview.cpp
2024 fake_scope.cpp
2125 fake_scopes.cpp
2226 fake_categories.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/mocks/Unity/Launcher/CMakeLists.txt+3−1
@@ -1,5 +1,7 @@
11include(FindPkgConfig)
2−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=2)
2+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=3)
3+
4+add_definitions(-DTOP_SRCDIR="${CMAKE_SOURCE_DIR}")
35
46include_directories(
57 ${CMAKE_CURRENT_SOURCE_DIR}
tests/mocks/Unity/Launcher/MockLauncherItem.cpp+17−1
@@ -27,12 +27,13 @@ MockLauncherItem::MockLauncherItem(const QString &appId, const QString& desktopF
2727 m_appId(appId),
2828 m_desktopFile(desktopFile),
2929 m_name(name),
30− m_icon(icon),
30+ m_icon(TOP_SRCDIR "/graphics/applicationIcons/" + icon + ".png"),
3131 m_pinned(false),
3232 m_running(false),
3333 m_recent(false),
3434 m_progress(-1),
3535 m_count(0),
36+ m_focused(false),
3637 m_quickList(new MockQuickListModel(this))
3738{
3839
@@ -128,6 +129,21 @@ void MockLauncherItem::setCount(int count)
128129 }
129130}
130131
132+bool MockLauncherItem::focused() const
133+{
134+ return m_focused;
135+}
136+
137+void MockLauncherItem::setFocused(bool focused)
138+{
139+ if (m_focused != focused)
140+ {
141+ m_focused = focused;
142+ Q_EMIT focusedChanged(focused);
143+ }
144+}
145+
146+
131147unity::shell::launcher::QuickListModelInterface *MockLauncherItem::quickList() const
132148{
133149 return m_quickList;
tests/mocks/Unity/Launcher/MockLauncherItem.h+4
@@ -52,6 +52,9 @@ public:
5252 int count() const;
5353 void setCount(int count);
5454
55+ bool focused() const;
56+ void setFocused(bool focused);
57+
5558 unity::shell::launcher::QuickListModelInterface *quickList() const;
5659
5760private:
@@ -64,6 +67,7 @@ private:
6467 bool m_recent;
6568 int m_progress;
6669 int m_count;
70+ bool m_focused;
6771 MockQuickListModel *m_quickList;
6872};
6973
tests/mocks/Unity/Launcher/MockLauncherModel.cpp+14−2
@@ -25,6 +25,7 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
2525 MockLauncherItem *item = new MockLauncherItem("phone-app", "/usr/share/applications/phone-app.desktop", "Phone", "phone-app", this);
2626 item->setProgress(0);
2727 m_list.append(item);
28+ item->setFocused(true);
2829 item = new MockLauncherItem("camera-app", "/usr/share/applications/camera-app.desktop", "Camera", "camera", this);
2930 item->setProgress(10);
3031 m_list.append(item);
@@ -49,6 +50,7 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
4950 item = new MockLauncherItem("notes-app", "/usr/share/applications/notes-app.desktop", "Notepad", "notepad", this);
5051 item->setProgress(50);
5152 item->setCount(5);
53+ item->setFocused(true);
5254 m_list.append(item);
5355 item = new MockLauncherItem("calendar-app", "/usr/share/applications/calendar-app.desktop","Calendar", "calendar", this);
5456 m_list.append(item);
@@ -69,8 +71,6 @@ QVariant MockLauncherModel::data(const QModelIndex& index, int role) const
6971 LauncherItemInterface *item = m_list.at(index.row());
7072 switch(role)
7173 {
72− case RoleDesktopFile:
73− return item->desktopFile();
7474 case RoleName:
7575 return item->name();
7676 case RoleIcon:
@@ -85,6 +85,8 @@ QVariant MockLauncherModel::data(const QModelIndex& index, int role) const
8585 return item->progress();
8686 case RoleCount:
8787 return item->count();
88+ case RoleFocused:
89+ return item->focused();
8890 }
8991
9092 return QVariant();
@@ -180,3 +182,13 @@ void MockLauncherModel::setUser(const QString &username)
180182 Q_UNUSED(username)
181183 // TODO: implement this...
182184}
185+
186+void MockLauncherModel::setApplicationManager(unity::shell::application::ApplicationManagerInterface *applicationManager)
187+{
188+ Q_UNUSED(applicationManager)
189+}
190+
191+unity::shell::application::ApplicationManagerInterface *MockLauncherModel::applicationManager() const
192+{
193+ return nullptr;
194+}
tests/mocks/Unity/Launcher/MockLauncherModel.h+3
@@ -45,6 +45,9 @@ public:
4545 Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
4646 Q_INVOKABLE void setUser(const QString &username);
4747
48+ unity::shell::application::ApplicationManagerInterface *applicationManager() const;
49+ void setApplicationManager(unity::shell::application::ApplicationManagerInterface *applicationManager);
50+
4851Q_SIGNALS:
4952 void quickListTriggered(const QString &appId, int index);
5053
tests/mocks/Unity/fake_applications_scope.cppnew file+68
@@ -0,0 +1,68 @@
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+#include "fake_applications_scope.h"
18+
19+static const gchar * categories_model_schema[] = {
20+ "s", //ID
21+ "s", // DISPLAY_NAME
22+ "s", // ICON_HINT
23+ "s", // RENDERER_NAME
24+ "a{sv}" // HINTS
25+};
26+
27+ApplicationsScope::ApplicationsScope(bool visible, QObject* parent)
28+ : Scope(parent)
29+{
30+ m_id = "applications.scope";
31+ m_name = "Applications";
32+ m_visible = visible;
33+ m_categories->setModel(createCategoriesModel());
34+}
35+
36+DeeModel* ApplicationsScope::createCategoriesModel()
37+{
38+ DeeModel* category_model = dee_sequence_model_new();
39+ dee_model_set_schema_full(category_model, categories_model_schema, G_N_ELEMENTS(categories_model_schema));
40+ GVariant* hints = g_variant_new_array(g_variant_type_element(G_VARIANT_TYPE_VARDICT), NULL, 0);
41+
42+ GVariant* children[1];
43+ children[0] = g_variant_new_dict_entry(g_variant_new_string("content-type"),
44+ g_variant_new_variant(g_variant_new_string("apps")));
45+ GVariant* recentHints = g_variant_new_array(g_variant_type_element(G_VARIANT_TYPE_VARDICT), children, 1);
46+ dee_model_append(category_model,
47+ "recent",
48+ "Recent",
49+ "gtk-apply",
50+ "special",
51+ recentHints);
52+
53+ dee_model_append(category_model,
54+ "installed",
55+ "Installed",
56+ "gtk-apply",
57+ "grid",
58+ hints);
59+
60+ dee_model_append(category_model,
61+ "suggested",
62+ "Suggested",
63+ "gtk-apply",
64+ "grid",
65+ hints);
66+
67+ return category_model;
68+}
tests/mocks/Unity/fake_applications_scope.hnew file+33
@@ -0,0 +1,33 @@
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+#ifndef FAKE_APPLICATIONS_SCOPE_H
18+#define FAKE_APPLICATIONS_SCOPE_H
19+
20+#include "fake_scope.h"
21+
22+class ApplicationsScope : public Scope
23+{
24+ Q_OBJECT
25+
26+public:
27+ ApplicationsScope(bool visible, QObject* parent = 0);
28+
29+private:
30+ DeeModel* createCategoriesModel();
31+};
32+
33+#endif // FAKE_APPLICATIONS_SCOPE_H
tests/mocks/Unity/fake_categories.cpp+84−12
@@ -24,11 +24,20 @@
2424
2525#define CATEGORY_COLUMN 2
2626
27+// TODO: use something from libunity once it's public
28+enum CategoryColumn {
29+ ID,
30+ DISPLAY_NAME,
31+ ICON_HINT,
32+ RENDERER_NAME,
33+ HINTS
34+};
35+
2736Categories::Categories(QObject* parent)
2837 : DeeListModel(parent)
2938{
3039 // FIXME: need to clean up unused filters on countChanged
31− m_roles[Categories::RoleId] = "id";
40+ m_roles[Categories::RoleCategoryId] = "categoryId";
3241 m_roles[Categories::RoleName] = "name";
3342 m_roles[Categories::RoleIcon] = "icon";
3443 m_roles[Categories::RoleRenderer] = "renderer";
@@ -36,7 +45,6 @@ Categories::Categories(QObject* parent)
3645 m_roles[Categories::RoleHints] = "hints";
3746 m_roles[Categories::RoleResults] = "results";
3847 m_roles[Categories::RoleCount] = "count";
39− m_roles[Categories::RoleCategoryIndex] = "categoryIndex";
4048
4149 // TODO This should not be needed but accumulatting the count changes
4250 // makes the visualization more stable and also makes crashes on fast
@@ -74,6 +82,25 @@ Categories::onCountChanged()
7482 }
7583}
7684
85+void Categories::onRowCountChanged()
86+{
87+ QAbstractItemModel* model = qobject_cast<QAbstractItemModel*>(sender());
88+ // find the corresponding category index
89+ for (auto iter = m_overriddenCategories.begin(); iter != m_overriddenCategories.end(); ++iter) {
90+ if (iter.value() == model) {
91+ for (int i = 0; i < rowCount(); i++) {
92+ auto id = data(index(i), RoleCategoryId).toString();
93+ if (id != iter.key()) continue;
94+ QVector<int> roles;
95+ roles.append(RoleCount);
96+ QModelIndex changedIndex = index(i);
97+ Q_EMIT dataChanged(changedIndex, changedIndex, roles);
98+ break;
99+ }
100+ }
101+ }
102+}
103+
77104void
78105Categories::onEmitCountChanged()
79106{
@@ -93,6 +120,41 @@ Categories::roleNames() const
93120 return m_roles;
94121}
95122
123+void Categories::onOverrideModelDestroyed()
124+{
125+ QObject* model = sender();
126+ auto iter = m_overriddenCategories.begin();
127+ while (iter != m_overriddenCategories.end()) {
128+ if (iter.value() == model) {
129+ iter = m_overriddenCategories.erase(iter);
130+ continue;
131+ }
132+ ++iter;
133+ }
134+}
135+
136+void Categories::overrideResults(const QString& categoryId, QAbstractItemModel* model)
137+{
138+ m_overriddenCategories[categoryId] = model;
139+ // watch the model
140+ connect(model, &QObject::destroyed, this, &Categories::onOverrideModelDestroyed);
141+ connect(model, &QAbstractItemModel::rowsInserted, this, &Categories::onRowCountChanged);
142+ connect(model, &QAbstractItemModel::rowsRemoved, this, &Categories::onRowCountChanged);
143+ connect(model, &QAbstractItemModel::modelReset, this, &Categories::onRowCountChanged);
144+
145+ // emit the dataChanged signal if the category is already in the model
146+ for (int i = 0; i < rowCount(); i++) {
147+ auto id = data(index(i), RoleCategoryId).toString();
148+ if (id != categoryId) continue;
149+ QVector<int> roles;
150+ roles.append(RoleCount);
151+ roles.append(RoleResults);
152+ QModelIndex changedIndex = index(i);
153+ Q_EMIT dataChanged(changedIndex, changedIndex, roles);
154+ break;
155+ }
156+}
157+
96158void Categories::setResultModel(DeeModel* model)
97159{
98160 // FIXME: should ref it
@@ -154,27 +216,37 @@ Categories::data(const QModelIndex& index, int role) const
154216 }
155217
156218 switch (role) {
157− case RoleId:
158− return DeeListModel::data(index, 0); //ID
219+ case RoleCategoryId:
220+ return DeeListModel::data(index, CategoryColumn::ID);
159221 case RoleName:
160− return DeeListModel::data(index, 1); //DISPLAY_NAME
222+ return DeeListModel::data(index, CategoryColumn::DISPLAY_NAME);
161223 case RoleIcon:
162− return DeeListModel::data(index, 2); //ICON_HINT
224+ return DeeListModel::data(index, CategoryColumn::ICON_HINT);
163225 case RoleRenderer:
164− return DeeListModel::data(index, 3); //RENDERER_NAME
226+ return DeeListModel::data(index, CategoryColumn::RENDERER_NAME);
165227 case RoleContentType:
166228 {
167− auto hints = DeeListModel::data(index, 4).toHash();
168− return hints.contains("content-type") ? hints["content-type"] : QVariant(QString("default"));
229+ auto hints = DeeListModel::data(index, CategoryColumn::HINTS).toHash();
230+ return hints.contains("content-type") ? hints["content-type"] : QVariant(QString("default"));
169231 }
170232 case RoleHints:
171− return DeeListModel::data(index, 4); //HINTS
233+ return DeeListModel::data(index, CategoryColumn::HINTS);
172234 case RoleResults:
235+ if (m_overriddenCategories.size() > 0)
236+ {
237+ auto id = DeeListModel::data(index, CategoryColumn::ID).toString();
238+ if (m_overriddenCategories.find(id) != m_overriddenCategories.end())
239+ return QVariant::fromValue(m_overriddenCategories[id]);
240+ }
173241 return QVariant::fromValue(getFilter(index.row()));
174242 case RoleCount:
243+ if (m_overriddenCategories.size() > 0)
244+ {
245+ auto id = DeeListModel::data(index, CategoryColumn::ID).toString();
246+ if (m_overriddenCategories.find(id) != m_overriddenCategories.end())
247+ return QVariant::fromValue(m_overriddenCategories[id]->rowCount());
248+ }
175249 return QVariant::fromValue(getFilter(index.row())->rowCount());
176− case RoleCategoryIndex:
177− return QVariant::fromValue(index.row());
178250 default:
179251 return QVariant();
180252 }
tests/mocks/Unity/fake_categories.h+7−3
@@ -34,17 +34,18 @@ class Categories : public DeeListModel
3434public:
3535 Categories(QObject* parent = 0);
3636 enum Roles {
37− RoleId,
37+ RoleCategoryId,
3838 RoleName,
3939 RoleIcon,
4040 RoleRenderer,
4141 RoleContentType,
4242 RoleHints,
4343 RoleResults,
44− RoleCount,
45− RoleCategoryIndex
44+ RoleCount
4645 };
4746
47+ Q_INVOKABLE void overrideResults(const QString& categoryId, QAbstractItemModel* model);
48+
4849 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
4950
5051 QHash<int, QByteArray> roleNames() const;
@@ -54,7 +55,9 @@ public:
5455
5556private Q_SLOTS:
5657 void onCountChanged();
58+ void onRowCountChanged();
5759 void onEmitCountChanged();
60+ void onOverrideModelDestroyed();
5861
5962private:
6063 DeeModel* getResultsForCategory(unsigned index) const;
@@ -64,6 +67,7 @@ private:
6467 QTimer m_timer;
6568 QSet<DeeListModel*> m_timerFilters;
6669 QHash<int, QByteArray> m_roles;
70+ QMap<QString, QAbstractItemModel*> m_overriddenCategories;
6771 mutable QMap<int, DeeListModel*> m_filters;
6872};
6973
tests/mocks/Unity/fake_preview.cppnew file+68
@@ -0,0 +1,68 @@
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+#include "fake_preview.h"
18+
19+QString Preview::rendererName() const
20+{
21+ return "foo";
22+}
23+
24+QString Preview::title() const
25+{
26+ return "Title";
27+}
28+
29+QString Preview::subtitle() const
30+{
31+ return "Subtitle";
32+}
33+
34+QString Preview::description() const
35+{
36+ return "Description";
37+}
38+
39+QVariant Preview::actions()
40+{
41+ return QVariant();
42+}
43+
44+QVariant Preview::infoHints()
45+{
46+ return QVariant();
47+}
48+
49+QVariantMap Preview::infoHintsHash() const
50+{
51+ return QVariantMap();
52+}
53+
54+QString Preview::image() const
55+{
56+ return "";
57+}
58+
59+QString Preview::imageSourceUri() const
60+{
61+ return "";
62+}
63+
64+void Preview::execute(const QString& actionId, const QHash<QString, QVariant>& hints)
65+{
66+ Q_UNUSED(actionId);
67+ Q_UNUSED(hints);
68+}
tests/mocks/Unity/fake_preview.hnew file+62
@@ -0,0 +1,62 @@
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+#ifndef FAKE_PREVIEW_H
18+#define FAKE_PREVIEW_H
19+
20+// Qt
21+#include <QObject>
22+#include <QString>
23+#include <QMetaType>
24+#include <QList>
25+#include <QVariantMap>
26+
27+class Q_DECL_EXPORT Preview : public QObject
28+{
29+ Q_OBJECT
30+
31+ Q_PROPERTY(QString rendererName READ rendererName NOTIFY previewChanged)
32+ Q_PROPERTY(QString title READ title NOTIFY previewChanged)
33+ Q_PROPERTY(QString subtitle READ subtitle NOTIFY previewChanged)
34+ Q_PROPERTY(QString description READ description NOTIFY previewChanged)
35+ Q_PROPERTY(QVariant actions READ actions NOTIFY previewChanged)
36+ Q_PROPERTY(QVariant infoHints READ infoHints NOTIFY previewChanged)
37+ Q_PROPERTY(QVariantMap infoMap READ infoHintsHash NOTIFY previewChanged)
38+ Q_PROPERTY(QString image READ image NOTIFY previewChanged)
39+ Q_PROPERTY(QString imageSourceUri READ imageSourceUri NOTIFY previewChanged)
40+
41+public:
42+ explicit Preview(QObject *parent = 0);
43+
44+ QString rendererName() const;
45+ QString title() const;
46+ QString subtitle() const;
47+ QString description() const;
48+ QVariant actions();
49+ QVariant infoHints();
50+ QVariantMap infoHintsHash() const;
51+ QString image() const;
52+ QString imageSourceUri() const;
53+
54+ Q_INVOKABLE void execute(const QString& actionId, const QHash<QString, QVariant>& hints);
55+
56+Q_SIGNALS:
57+ void previewChanged();
58+};
59+
60+Q_DECLARE_METATYPE(Preview *)
61+
62+#endif // FAKE_PREVIEW_H
tests/mocks/Unity/fake_scope.cpp+33−9
@@ -20,6 +20,8 @@
2020#include <dee.h>
2121#include "paths.h"
2222
23+#include "fake_preview.h"
24+
2325static DeeModel* create_categories_model(unsigned category_count);
2426static DeeModel* create_results_model(unsigned category_count, unsigned result_count);
2527
@@ -127,6 +129,36 @@ void Scope::setNoResultsHint(const QString& str) {
127129 }
128130}
129131
132+void Scope::activate(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
133+ const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
134+ const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
135+{
136+ Q_UNUSED(uri);
137+ Q_UNUSED(icon_hint);
138+ Q_UNUSED(category);
139+ Q_UNUSED(result_type);
140+ Q_UNUSED(mimetype);
141+ Q_UNUSED(title);
142+ Q_UNUSED(comment);
143+ Q_UNUSED(dnd_uri);
144+ Q_UNUSED(metadata);
145+}
146+
147+void Scope::preview(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
148+ const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
149+ const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
150+{
151+ Q_UNUSED(uri);
152+ Q_UNUSED(icon_hint);
153+ Q_UNUSED(category);
154+ Q_UNUSED(result_type);
155+ Q_UNUSED(mimetype);
156+ Q_UNUSED(title);
157+ Q_UNUSED(comment);
158+ Q_UNUSED(dnd_uri);
159+ Q_UNUSED(metadata);
160+}
161+
130162static const gchar * categories_model_schema[] = {
131163 "s", //ID
132164 "s", // DISPLAY_NAME
@@ -168,14 +200,6 @@ static const gchar * results_model_schema[] = {
168200 "a{sv}" // METADATA
169201};
170202
171−static const gchar * icons[] = {
172− "Applications.png",
173− "Home.png",
174− "Music.png",
175− "People.png",
176− "Videos.png",
177−};
178−
179203DeeModel* create_results_model(unsigned category_count, unsigned result_count) {
180204 DeeModel* results_model = dee_sequence_model_new();
181205 dee_model_set_schema_full(results_model, results_model_schema, G_N_ELEMENTS(results_model_schema));
@@ -187,7 +211,7 @@ DeeModel* create_results_model(unsigned category_count, unsigned result_count) {
187211
188212 dee_model_append(results_model,
189213 ("uri://result."+std::to_string(i)).c_str(),
190− (shellAppDirectory() + "Dash/graphics/scopeIcons/" + (icons[i%G_N_ELEMENTS(icons)])).toLatin1().data(),
214+ (shellAppDirectory() + "graphics/applicationIcons/dash.png").toLatin1().data(),
191215 category,
192216 0,
193217 "application/x-desktop",
tests/mocks/Unity/fake_scope.h+17−1
@@ -21,6 +21,8 @@
2121#include <QObject>
2222#include "fake_categories.h"
2323
24+class Preview;
25+
2426class Scope : public QObject
2527{
2628 Q_OBJECT
@@ -63,6 +65,13 @@ public:
6365 void setNoResultsHint(const QString& hint);
6466 void setFormFactor(const QString& form_factor);
6567
68+ Q_INVOKABLE void activate(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
69+ const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
70+ const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata);
71+ Q_INVOKABLE void preview(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
72+ const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
73+ const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata);
74+
6675Q_SIGNALS:
6776 void idChanged(const QString&);
6877 void nameChanged(const QString&);
@@ -78,7 +87,14 @@ Q_SIGNALS:
7887 void noResultsHintChanged();
7988 void formFactorChanged();
8089
81−private:
90+ // signals triggered by activate(..) or preview(..) requests.
91+ void previewReady(Preview *preview);
92+ void activateApplication(const QString &desktop);
93+ void showDash();
94+ void hideDash();
95+
96+protected:
97+
8298 QString m_id;
8399 QString m_iconHint;
84100 QString m_description;
tests/mocks/Unity/fake_scopes.cpp+4−1
@@ -19,6 +19,9 @@
1919// Self
2020#include "fake_scopes.h"
2121
22+// Local
23+#include "fake_applications_scope.h"
24+
2225// TODO: Implement remaining pieces, like Categories (i.e. LensView now gives warnings)
2326
2427// Qt
@@ -53,7 +56,7 @@ void Scopes::updateScopes()
5356 addScope(new Scope("MockScope1", "People", true, this));
5457 addScope(new Scope("MockScope2", "Music", false, this));
5558 addScope(new Scope("home.scope", "Home", true, this));
56− addScope(new Scope("applications.scope", "Applications", true, this));
59+ addScope(new ApplicationsScope(true, this));
5760 addScope(new Scope("MockScope5", "Videos", true, this));
5861
5962 if (!m_loaded) {
tests/plugins/AccountsService/CMakeLists.txt+1
@@ -25,6 +25,7 @@ qt5_use_modules(mock-server Core DBus)
2525
2626add_executable(test-accountsservice
2727 ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsService.cpp
28+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
2829 client.cpp
2930 )
3031qt5_use_modules(test-accountsservice Core DBus Test)
tests/plugins/AccountsService/client.cpp+19−7
@@ -18,6 +18,7 @@
1818 */
1919
2020#include "AccountsService.h"
21+#include "AccountsServiceDBusAdaptor.h"
2122#include <QSignalSpy>
2223#include <QTest>
2324
@@ -30,17 +31,28 @@ private Q_SLOTS:
3031 void testInvalids()
3132 {
3233 // Test various invalid calls
33− AccountsService session;
34− QCOMPARE(session.getUserProperty("NOPE", "demo-edges"), QVariant());
35− QCOMPARE(session.getUserProperty("testuser", "NOPE"), QVariant());
34+ AccountsServiceDBusAdaptor session;
35+ QCOMPARE(session.getUserProperty("NOPE", "com.canonical.unity.AccountsService", "demo-edges"), QVariant());
36+ QCOMPARE(session.getUserProperty("testuser", "com.canonical.unity.AccountsService", "NOPE"), QVariant());
37+ }
38+
39+ void testGetSetServiceDBusAdaptor()
40+ {
41+ AccountsServiceDBusAdaptor session;
42+ session.setUserProperty("testuser", "com.canonical.unity.AccountsService", "demo-edges", QVariant(true));
43+ QCOMPARE(session.getUserProperty("testuser", "com.canonical.unity.AccountsService", "demo-edges"), QVariant(true));
44+ session.setUserProperty("testuser", "com.canonical.unity.AccountsService", "demo-edges", QVariant(false));
45+ QCOMPARE(session.getUserProperty("testuser", "com.canonical.unity.AccountsService", "demo-edges"), QVariant(false));
3646 }
3747
38− void testGetSet()
48+ void testGetSetService()
3949 {
4050 AccountsService session;
41− QCOMPARE(session.getUserProperty("testuser", "demo-edges"), QVariant(true));
42− session.setUserProperty("testuser", "demo-edges", QVariant(false));
43− QCOMPARE(session.getUserProperty("testuser", "demo-edges"), QVariant(false));
51+ session.setUser("testuser");
52+ session.setDemoEdges(true);
53+ QCOMPARE(session.demoEdges(), true);
54+ session.setDemoEdges(false);
55+ QCOMPARE(session.demoEdges(), false);
4456 }
4557};
4658
tests/plugins/ListViewWithPageHeader/CMakeLists.txt+6
@@ -32,5 +32,11 @@ qt5_use_modules(listviewwithpageheadertestsectionExec Test Core Qml)
3232target_link_libraries(listviewwithpageheadertestsectionExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
3333add_custom_target(testlistviewwithpageheadersection ${CMAKE_CURRENT_BINARY_DIR}/listviewwithpageheadertestsectionExec -o ${CMAKE_BINARY_DIR}/testlistviewwithpageheadersection.xml,xunitxml -o -,txt)
3434
35+add_executable(listviewwithpageheadertestsectionexternalmodelExec listviewwithpageheadertestsectionexternalmodel.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/ListViewWithPageHeader/listviewwithpageheader.cpp)
36+qt5_use_modules(listviewwithpageheadertestsectionexternalmodelExec Test Core Qml)
37+target_link_libraries(listviewwithpageheadertestsectionexternalmodelExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
38+add_custom_target(testlistviewwithpageheadersectionexternalmodel ${CMAKE_CURRENT_BINARY_DIR}/listviewwithpageheadertestsectionexternalmodelExec -o ${CMAKE_BINARY_DIR}/testlistviewwithpageheadersectionexternalmodel.xml,xunitxml -o -,txt)
39+
3540add_dependencies(qmluitests testlistviewwithpageheader)
3641add_dependencies(qmluitests testlistviewwithpageheadersection)
42+add_dependencies(qmluitests testlistviewwithpageheadersectionexternalmodel)
tests/plugins/ListViewWithPageHeader/listviewwithpageheadertest.cpp+161
@@ -1655,6 +1655,167 @@ private Q_SLOTS:
16551655 QCOMPARE(spy.count(), 0);
16561656 }
16571657
1658+ void testOvershootOnSameSize()
1659+ {
1660+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 6));
1661+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 0);
1662+ QCOMPARE(lvwph->m_minYExtent, 0.);
1663+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
1664+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1665+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1666+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1667+ QCOMPARE(lvwph->contentY(), 0.);
1668+
1669+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 100));
1670+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 392));
1671+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1672+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1673+ verifyItem(0, 50., 392., false);
1674+ verifyItem(1, 442., 100., false);
1675+
1676+ QCOMPARE(lvwph->contentHeight(), lvwph->height());
1677+
1678+ QTest::mousePress(view, Qt::LeftButton, Qt::NoModifier, QPoint(0, 0));
1679+ QTest::qWait(100);
1680+ QTest::mouseMove(view, QPoint(0, 5));
1681+ QTest::qWait(100);
1682+ QTest::mouseMove(view, QPoint(0, 10));
1683+ QTest::qWait(100);
1684+ QTest::mouseMove(view, QPoint(0, 15));
1685+ QTest::qWait(100);
1686+ QTest::mouseMove(view, QPoint(0, 20));
1687+ QTest::qWait(100);
1688+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1689+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1690+ verifyItem(0, 55., 392., false);
1691+ verifyItem(1, 447., 100., false);
1692+ QCOMPARE(lvwph->m_minYExtent, 0.);
1693+ QCOMPARE(lvwph->m_clipItem->y(), -5.);
1694+
1695+ QTest::mouseRelease(view, Qt::LeftButton, Qt::NoModifier, QPoint(0, 15));
1696+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1697+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1698+ verifyItem(0, 50., 392., false);
1699+ verifyItem(1, 442., 100., false);
1700+ }
1701+
1702+ void testMaximizeVisibleAreaMoveDownAndShowHeader()
1703+ {
1704+ model->setProperty(0, "size", 800);
1705+ verifyItem(0, 50., 800., false);
1706+
1707+ lvwph->maximizeVisibleArea(0);
1708+ QTRY_COMPARE(lvwph->contentY(), 50.);
1709+
1710+ changeContentY(10);
1711+ QTRY_COMPARE(lvwph->contentY(), 60.);
1712+
1713+ lvwph->showHeader();
1714+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1715+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1716+ QCOMPARE(lvwph->m_minYExtent, 50.);
1717+ QCOMPARE(lvwph->m_clipItem->y(), 60.);
1718+ QCOMPARE(lvwph->m_clipItem->clip(), true);
1719+ QCOMPARE(lvwph->m_headerItem->y(), 10.);
1720+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1721+ QCOMPARE(lvwph->contentY(), 10.);
1722+ verifyItem(0, -60., 800., false);
1723+ }
1724+
1725+ void testMaximizeVisibleAreaMoveUpAndShowHeader()
1726+ {
1727+ model->setProperty(0, "size", 800);
1728+ verifyItem(0, 50., 800., false);
1729+
1730+ lvwph->maximizeVisibleArea(0);
1731+ QTRY_COMPARE(lvwph->contentY(), 50.);
1732+
1733+ changeContentY(-10);
1734+ QTRY_COMPARE(lvwph->contentY(), 40.);
1735+
1736+ lvwph->showHeader();
1737+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1738+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1739+ QCOMPARE(lvwph->m_minYExtent, 40.);
1740+ QCOMPARE(lvwph->m_clipItem->y(), 50.);
1741+ QCOMPARE(lvwph->m_clipItem->clip(), true);
1742+ QTRY_COMPARE(lvwph->m_headerItem->y(), 0.);
1743+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1744+ QCOMPARE(lvwph->contentY(), 0.);
1745+ verifyItem(0, -40., 800., false);
1746+ }
1747+
1748+ void testMaximizeVisibleAreaMoveDownAndUpAndShowHeader()
1749+ {
1750+ model->setProperty(0, "size", 800);
1751+ verifyItem(0, 50., 800., false);
1752+
1753+ lvwph->maximizeVisibleArea(0);
1754+ QTRY_COMPARE(lvwph->contentY(), 50.);
1755+
1756+ changeContentY(-10);
1757+ QTRY_COMPARE(lvwph->contentY(), 40.);
1758+ changeContentY(10);
1759+ QTRY_COMPARE(lvwph->contentY(), 50.);
1760+
1761+ lvwph->showHeader();
1762+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1763+
1764+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1765+ QCOMPARE(lvwph->m_minYExtent, 50.);
1766+ QCOMPARE(lvwph->m_clipItem->y(), 50.);
1767+ QCOMPARE(lvwph->m_clipItem->clip(), true);
1768+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1769+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1770+ QCOMPARE(lvwph->contentY(), 0.);
1771+ verifyItem(0, -50., 800., false);
1772+ }
1773+
1774+ void testMaximizeVisibleAreaMoveUpAndDownAndShowHeader()
1775+ {
1776+ model->setProperty(0, "size", 800);
1777+ verifyItem(0, 50., 800., false);
1778+
1779+ lvwph->maximizeVisibleArea(0);
1780+ QTRY_COMPARE(lvwph->contentY(), 50.);
1781+
1782+ changeContentY(10);
1783+ QTRY_COMPARE(lvwph->contentY(), 60.);
1784+ changeContentY(-10);
1785+ QTRY_COMPARE(lvwph->contentY(), 50.);
1786+
1787+ lvwph->showHeader();
1788+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1789+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1790+ QCOMPARE(lvwph->m_minYExtent, 40.);
1791+ QCOMPARE(lvwph->m_clipItem->y(), 60.);
1792+ QCOMPARE(lvwph->m_clipItem->clip(), true);
1793+ QCOMPARE(lvwph->m_headerItem->y(), 10.);
1794+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1795+ QCOMPARE(lvwph->contentY(), 10.);
1796+ verifyItem(0, -50., 800., false);
1797+ }
1798+
1799+ void testMaximizeVisibleAreaAndShowHeader()
1800+ {
1801+ model->setProperty(0, "size", 800);
1802+ verifyItem(0, 50., 800., false);
1803+
1804+ lvwph->maximizeVisibleArea(0);
1805+ QTRY_COMPARE(lvwph->contentY(), 50.);
1806+
1807+ lvwph->showHeader();
1808+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1809+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1810+ QCOMPARE(lvwph->m_minYExtent, 50.);
1811+ QCOMPARE(lvwph->m_clipItem->y(), 50.);
1812+ QCOMPARE(lvwph->m_clipItem->clip(), true);
1813+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1814+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1815+ QCOMPARE(lvwph->contentY(), 0.);
1816+ verifyItem(0, -50., 800., false);
1817+ }
1818+
16581819private:
16591820 QQuickView *view;
16601821 ListViewWithPageHeader *lvwph;
tests/plugins/ListViewWithPageHeader/listviewwithpageheadertestsectionexternalmodel.cppnew file+251
@@ -0,0 +1,251 @@
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+#include "listviewwithpageheader.h"
18+
19+#include <QAbstractItemModel>
20+#include <QQmlEngine>
21+#include <QQuickView>
22+#include <QSignalSpy>
23+#include <QSortFilterProxyModel>
24+#include <QtTestGui>
25+#pragma GCC diagnostic push
26+#pragma GCC diagnostic ignored "-pedantic"
27+#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
28+#include <private/qquicklistmodel_p.h>
29+#else
30+#include <private/qqmllistmodel_p.h>
31+#endif
32+#include <private/qquickanimation_p.h>
33+#include <private/qquickitem_p.h>
34+#pragma GCC diagnostic pop
35+
36+class StringListModel : public QAbstractListModel
37+{
38+public:
39+ StringListModel()
40+ {
41+ list << "A" << "B" << "C" << "D" << "E" << "F" << "G" << "H";
42+ }
43+
44+ int rowCount(const QModelIndex &parent) const
45+ {
46+ if (parent.isValid())
47+ return 0;
48+ else
49+ return list.count();
50+ }
51+
52+ QVariant data(const QModelIndex &index, int role) const
53+ {
54+ if (role == Qt::SizeHintRole) return 50;
55+ else if (role == Qt::DisplayRole) return list[index.row()];
56+ return QVariant();
57+ }
58+
59+ QHash<int, QByteArray> roleNames() const
60+ {
61+ QHash<int, QByteArray> hash;
62+ hash.insert(Qt::DisplayRole, "type");
63+ hash.insert(Qt::SizeHintRole, "size");
64+ return hash;
65+ }
66+
67+ void moveLastToFirst()
68+ {
69+ const int last = list.count() - 1;
70+ beginMoveRows(QModelIndex(), last, last, QModelIndex(), 0);
71+ list.move(last, 0);
72+ endMoveRows();
73+ }
74+
75+ QStringList list;
76+};
77+
78+class ListViewWithPageHeaderTestSection : public QObject
79+{
80+ Q_OBJECT
81+
82+private:
83+ void verifyItem(int visibleIndex, qreal pos, qreal height, bool culled, const QString &sectionHeader, bool sectionHeaderCulled)
84+ {
85+ QTRY_VERIFY(visibleIndex < lvwph->m_visibleItems.count());
86+ QTRY_COMPARE(lvwph->m_visibleItems[visibleIndex]->y(), pos);
87+ QTRY_COMPARE(lvwph->m_visibleItems[visibleIndex]->height(), height);
88+ QCOMPARE(QQuickItemPrivate::get(lvwph->m_visibleItems[visibleIndex]->m_item)->culled, culled);
89+ QCOMPARE(section(lvwph->m_visibleItems[visibleIndex]->m_sectionItem), sectionHeader);
90+ if (!sectionHeader.isNull()) {
91+ QCOMPARE(QQuickItemPrivate::get(lvwph->m_visibleItems[visibleIndex]->m_sectionItem)->culled, sectionHeaderCulled);
92+ QCOMPARE(sectionDelegateIndex(lvwph->m_visibleItems[visibleIndex]->m_sectionItem), lvwph->m_firstVisibleIndex + visibleIndex);
93+ }
94+ }
95+
96+ void changeContentY(qreal change)
97+ {
98+ const qreal dest = lvwph->contentY() + change;
99+ if (dest > lvwph->contentY()) {
100+ const qreal jump = 25;
101+ while (lvwph->contentY() + jump < dest) {
102+ lvwph->setContentY(lvwph->contentY() + jump);
103+ QTest::qWait(1);
104+ }
105+ } else {
106+ const qreal jump = -25;
107+ while (lvwph->contentY() + jump > dest) {
108+ lvwph->setContentY(lvwph->contentY() + jump);
109+ QTest::qWait(1);
110+ }
111+ }
112+ lvwph->setContentY(dest);
113+ QTest::qWait(1);
114+ }
115+
116+ void scrollToTop()
117+ {
118+ const qreal jump = -25;
119+ while (!lvwph->isAtYBeginning()) {
120+ if (lvwph->contentY() + jump > -lvwph->minYExtent()) {
121+ lvwph->setContentY(lvwph->contentY() + jump);
122+ } else {
123+ lvwph->setContentY(lvwph->contentY() - 1);
124+ }
125+ QTest::qWait(1);
126+ }
127+ }
128+
129+ void scrollToBottom()
130+ {
131+ const qreal jump = 25;
132+ while (!lvwph->isAtYEnd()) {
133+ if (lvwph->contentY() + lvwph->height() + jump < lvwph->contentHeight()) {
134+ lvwph->setContentY(lvwph->contentY() + jump);
135+ } else {
136+ lvwph->setContentY(lvwph->contentY() + 1);
137+ }
138+ QTest::qWait(1);
139+ }
140+ }
141+
142+ void verifyInitialTopPosition()
143+ {
144+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 0);
145+ QCOMPARE(lvwph->m_firstVisibleIndex, -1);
146+ QCOMPARE(lvwph->m_minYExtent, 0.);
147+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
148+ QCOMPARE(lvwph->m_clipItem->clip(), false);
149+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
150+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
151+ QCOMPARE(lvwph->contentY(), 0.);
152+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
153+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
154+ }
155+
156+ QString section(QQuickItem *item)
157+ {
158+ return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("section")).toString() : QString();
159+ }
160+
161+ int sectionDelegateIndex(QQuickItem *item)
162+ {
163+ return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("delegateIndex")).toInt() : -1;
164+ }
165+
166+private Q_SLOTS:
167+
168+ void initTestCase()
169+ {
170+ }
171+
172+ void init()
173+ {
174+ view = new QQuickView();
175+ view->engine()->addImportPath(BUILT_PLUGINS_DIR);
176+ view->setSource(QUrl::fromLocalFile(LISTVIEWWITHPAGEHEADER_FOLDER "/test_sectionexternalmodel.qml"));
177+ lvwph = dynamic_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
178+ QVERIFY(lvwph);
179+ view->show();
180+ QTest::qWaitForWindowExposed(view);
181+
182+ verifyInitialTopPosition();
183+ }
184+
185+ void cleanup()
186+ {
187+ delete view;
188+ }
189+
190+ void testCreationDeletion()
191+ {
192+ // Nothing, init/cleanup already tests this
193+ }
194+
195+ void testMoveWithProxy()
196+ {
197+ StringListModel m;
198+ QSortFilterProxyModel proxy;
199+ proxy.setSourceModel(&m);
200+
201+ lvwph->setModel(&proxy);
202+
203+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 8);
204+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
205+ verifyItem(0, 50., 90., false, "A", false);
206+ verifyItem(1, 140., 90., false, "B", false);
207+ verifyItem(2, 230., 90., false, "C", false);
208+ verifyItem(3, 320., 90., false, "D", false);
209+ verifyItem(4, 410., 90., false, "E", false);
210+ verifyItem(5, 500., 90., false, "F", false);
211+ verifyItem(6, 590., 90., true, "G", true);
212+ verifyItem(7, 680., 90., true, "H", true);
213+ QCOMPARE(lvwph->m_minYExtent, 0.);
214+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
215+ QCOMPARE(lvwph->m_clipItem->clip(), false);
216+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
217+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
218+ QCOMPARE(lvwph->contentY(), 0.);
219+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
220+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
221+
222+ m.moveLastToFirst();
223+
224+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 8);
225+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
226+ verifyItem(0, 50., 90., false, "H", false);
227+ verifyItem(1, 140., 90., false, "A", false);
228+ verifyItem(2, 230., 90., false, "B", false);
229+ verifyItem(3, 320., 90., false, "C", false);
230+ verifyItem(4, 410., 90., false, "D", false);
231+ verifyItem(5, 500., 90., false, "E", false);
232+ verifyItem(6, 590., 90., true, "F", true);
233+ verifyItem(7, 680., 90., true, "G", true);
234+ QCOMPARE(lvwph->m_minYExtent, 0.);
235+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
236+ QCOMPARE(lvwph->m_clipItem->clip(), false);
237+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
238+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
239+ QCOMPARE(lvwph->contentY(), 0.);
240+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
241+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
242+ }
243+
244+private:
245+ QQuickView *view;
246+ ListViewWithPageHeader *lvwph;
247+};
248+
249+QTEST_MAIN(ListViewWithPageHeaderTestSection)
250+
251+#include "listviewwithpageheadertestsectionexternalmodel.moc"
tests/plugins/ListViewWithPageHeader/test_sectionexternalmodel.qmlnew file+74
@@ -0,0 +1,74 @@
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 ListViewWithPageHeader 0.1
19+
20+Rectangle {
21+ width: 300
22+ height: 542
23+ color: "lightblue"
24+
25+ ListViewWithPageHeader {
26+ id: listView
27+ width: parent.width
28+ anchors.top: parent.top
29+ anchors.bottom: parent.bottom
30+ model: model
31+ delegate: Rectangle {
32+ property bool timerDone: false
33+ width: parent.width - 20
34+ x: 10
35+ color: index % 2 == 0 ? "red" : "blue"
36+ height: timerDone ? size : 350
37+ Text {
38+ text: index
39+ }
40+ Timer {
41+ id: sizeTimer
42+ interval: 10;
43+ onTriggered: {
44+ timerDone = true
45+ }
46+ }
47+ Component.onCompleted: {
48+ sizeTimer.start()
49+ }
50+ }
51+
52+ pageHeader: Rectangle {
53+ color: "transparent"
54+ width: parent.width
55+ height: 50
56+ implicitHeight: 50
57+ Text {
58+ anchors.fill: parent
59+ text: "APPS"
60+ font.pixelSize: 40
61+ }
62+ }
63+
64+ sectionProperty: "type"
65+ sectionDelegate: Component {
66+ Rectangle {
67+ color: "green"
68+ height: 40
69+ Text { text: section; font.pixelSize: 34 }
70+ anchors { left: parent.left; right: parent.right }
71+ }
72+ }
73+ }
74+}
tests/plugins/Unity/CMakeLists.txt+5
@@ -1,9 +1,11 @@
11add_subdirectory(Indicators)
2+add_subdirectory(Launcher)
23
34pkg_check_modules(UNITYCORE REQUIRED unity-core-6.0)
45pkg_check_modules(LIBUNITYPROTO REQUIRED unity-protocol-private)
56pkg_check_modules(LIBUNITY REQUIRED unity)
67pkg_check_modules(LIBSIGCPP REQUIRED sigc++-2.0)
8+pkg_check_modules(QTDEE REQUIRED libdee-qt5>=3.2)
79
810include_directories(
911 ${Unity-qml_SOURCE_DIR}
@@ -13,6 +15,7 @@ include_directories(
1315 ${LIBUNITY_INCLUDE_DIRS}
1416 ${LIBSIGCPP_INCLUDE_DIRS}
1517 ${UNITYCORE_INCLUDE_DIRS}
18+ ${QTDEE_INCLUDE_DIRS}
1619 )
1720
1821macro(run_tests)
@@ -35,6 +38,7 @@ macro(run_tests)
3538 ${LIBUNITY_LDFLAGS}
3639 ${LIBUNITYPROTO_LDFLAGS}
3740 ${LIBSIGCPP_LDFLAGS}
41+ ${QTDEE_LDFLAGS}
3842 )
3943
4044 set(_test_list "${_test_list};${_test}")
@@ -45,4 +49,5 @@ run_tests(
4549 signalslisttest
4650 previewbindingstest
4751 filtersbindingstest
52+ resultstest
4853 )
tests/plugins/Unity/Launcher/CMakeLists.txtnew file+71
@@ -0,0 +1,71 @@
1+pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
2+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=3)
3+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=1)
4+
5+include_directories(
6+ ${CMAKE_CURRENT_BINARY_DIR}
7+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService
8+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher
9+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/backend
10+ ${GSETTINGS_QT_INCLUDE_DIRS}
11+ )
12+
13+add_definitions(-DSM_BUSNAME=sessionBus)
14+add_definitions(-DSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}")
15+add_definitions(-DLAUNCHER_TESTING)
16+
17+### LauncherBackendTest
18+set(testBackendCommand ${CMAKE_CURRENT_BINARY_DIR}/launcherbackendtestExec
19+ -o ${CMAKE_BINARY_DIR}/launcherbackendtest.xml,xunitxml
20+ -o -,txt)
21+add_test(NAME launcherbackendtest COMMAND ${testBackendCommand})
22+add_custom_target(launcherbackendtest ${testBackendCommand})
23+add_executable(launcherbackendtestExec
24+ launcherbackendtest.cpp
25+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
26+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/backend/launcherbackend.cpp
27+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/common/quicklistentry.cpp
28+ )
29+target_link_libraries(launcherbackendtestExec ${GSETTINGS_QT_LDFLAGS})
30+qt5_use_modules(launcherbackendtestExec Test Core DBus)
31+
32+### LauncherModelTest
33+set(testModelCommand ${CMAKE_CURRENT_BINARY_DIR}/launchermodeltestExec
34+ -o ${CMAKE_BINARY_DIR}/launchermodeltest.xml,xunitxml
35+ -o -,txt)
36+add_test(NAME launchermodeltest COMMAND ${testModelCommand})
37+add_custom_target(launchermodeltest ${testModelCommand})
38+add_executable(launchermodeltestExec
39+ launchermodeltest.cpp
40+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/launchermodel.cpp
41+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/launcheritem.cpp
42+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/quicklistmodel.cpp
43+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
44+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/backend/launcherbackend.cpp
45+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/common/quicklistentry.cpp
46+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
47+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
48+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
49+ ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
50+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
51+ )
52+target_link_libraries(launchermodeltestExec ${GSETTINGS_QT_LDFLAGS} )
53+qt5_use_modules(launchermodeltestExec Test Core DBus)
54+
55+# copy .desktop files into build directory for shadow builds
56+file(GLOB DESKTOP_FILES *.desktop)
57+
58+foreach(DESKTOP_FILE ${DESKTOP_FILES})
59+ file(COPY "${DESKTOP_FILE}"
60+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
61+ )
62+endforeach()
63+
64+# copy .svg files into build directory for shadow builds
65+file(GLOB DESKTOP_FILES *.svg)
66+
67+foreach(DESKTOP_FILE ${DESKTOP_FILES})
68+ file(COPY "${DESKTOP_FILE}"
69+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
70+ )
71+endforeach()
tests/plugins/Unity/Launcher/abs-icon.desktopnew file+3
@@ -0,0 +1,3 @@
1+[Desktop Entry]
2+Name=Absolute Icon
3+Icon=/path/to/icon.png
tests/plugins/Unity/Launcher/click-icon.desktopnew file+4
@@ -0,0 +1,4 @@
1+[Desktop Entry]
2+Name=Click Package Icon
3+Icon=click-icon.svg
4+Path=/path/to/some/click/app
tests/plugins/Unity/Launcher/click-icon.svgnew file

No changes to the content.

tests/plugins/Unity/Launcher/launcherbackendtest.cppnew file+93
@@ -0,0 +1,93 @@
1+/*
2+ * Copyright 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 Lesser 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 Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#include "launcherbackend.h"
21+
22+#include <QtTest>
23+
24+class LauncherBackendTest : public QObject
25+{
26+ Q_OBJECT
27+
28+private Q_SLOTS:
29+
30+ void initTestCase()
31+ {
32+ // As we want to test absolute file paths in the .desktop file, we need to modify the
33+ // sample file and replace the path in there with the current build dir.
34+ QSettings settings(QDir::currentPath() + "/click-icon.desktop", QSettings::IniFormat);
35+ settings.setValue("Desktop Entry/Path", QDir::currentPath());
36+ }
37+
38+ void testFileNames()
39+ {
40+ LauncherBackend backend(false);
41+
42+ backend.setStoredApplications(QStringList() << "rel-icon" << "abs-icon" << "invalid");
43+ QCOMPARE(backend.storedApplications(), QStringList() << "rel-icon" << "abs-icon");
44+ }
45+
46+ void testPinning()
47+ {
48+ LauncherBackend backend(false);
49+
50+ backend.setStoredApplications(QStringList() << "rel-icon" << "abs-icon");
51+ QCOMPARE(backend.isPinned("rel-icon"), false);
52+ QCOMPARE(backend.isPinned("abs-icon"), false);
53+
54+ backend.setPinned("rel-icon", true);
55+ QCOMPARE(backend.isPinned("rel-icon"), true);
56+
57+ backend.setStoredApplications(QStringList() << "rel-icon" << "abs-icon" << "no-name");
58+ QCOMPARE(backend.isPinned("rel-icon"), true);
59+ QCOMPARE(backend.isPinned("no-name"), false);
60+
61+ backend.setPinned("no-name", true);
62+ backend.setStoredApplications(QStringList() << "rel-icon" << "abs-icon");
63+ QCOMPARE(backend.isPinned("rel-icon"), true);
64+ QCOMPARE(backend.isPinned("no-name"), false); // doesn't exist anymore!
65+ }
66+
67+ void testIcon_data() {
68+ QTest::addColumn<QString>("appId");
69+ QTest::addColumn<QString>("expectedIcon");
70+
71+ // Needs to expand a relative icon to the absolute path
72+ QTest::newRow("relative icon path") << "rel-icon" << QDir::currentPath() + "/rel-icon.svg";
73+
74+ // In case an icon is not found on disk, it needs to fallback on image://theme/ for it
75+ QTest::newRow("fallback on theme") << "abs-icon" << "image://theme//path/to/icon.png";
76+
77+ // Click packages have a relative icon path but an absolute path as a separate entry
78+ QTest::newRow("click package icon") << "click-icon" << QDir::currentPath() + "/click-icon.svg";
79+ }
80+
81+ void testIcon() {
82+ QFETCH(QString, appId);
83+ QFETCH(QString, expectedIcon);
84+
85+ LauncherBackend backend(false);
86+ backend.setStoredApplications(QStringList() << appId);
87+
88+ QCOMPARE(backend.icon(appId), expectedIcon);
89+ }
90+};
91+
92+QTEST_GUILESS_MAIN(LauncherBackendTest)
93+#include "launcherbackendtest.moc"
tests/plugins/Unity/Launcher/launchermodeltest.cppnew file+275
@@ -0,0 +1,275 @@
1+/*
2+ * Copyright 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 Lesser 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 Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Michael Zanetti <michael.zanetti@canonical.com>
18+ */
19+
20+// unity-api
21+#include <unity/shell/launcher/LauncherModelInterface.h>
22+#include <unity/shell/application/ApplicationInfoInterface.h>
23+
24+#include "launcheritem.h"
25+#include "launchermodel.h"
26+
27+#include <QtTest>
28+
29+// This is a mock, specifically to test the LauncherModel
30+class MockApp: public unity::shell::application::ApplicationInfoInterface
31+{
32+ Q_OBJECT
33+public:
34+ MockApp(const QString &appId, QObject *parent = 0): ApplicationInfoInterface(appId, parent), m_appId(appId), m_focused(false) { }
35+ QString appId() const { return m_appId; }
36+ QString name() const { return "mock"; }
37+ QString comment() const { return "this is a mock"; }
38+ QUrl icon() const { return QUrl(); }
39+ ApplicationInfoInterface::Stage stage() const { return ApplicationInfoInterface::MainStage; }
40+ ApplicationInfoInterface::State state() const { return ApplicationInfoInterface::Running; }
41+ bool focused() const { return m_focused; }
42+
43+ // Methods used for mocking (not in the interface)
44+ void setFocused(bool focused) { m_focused = focused; Q_EMIT focusedChanged(focused); }
45+private:
46+ QString m_appId;
47+ bool m_focused;
48+};
49+
50+// This is a mock, specifically to test the LauncherModel
51+class MockAppManager: public unity::shell::application::ApplicationManagerInterface
52+{
53+ Q_OBJECT
54+public:
55+ MockAppManager(QObject *parent = 0): ApplicationManagerInterface(parent) {}
56+ int rowCount(const QModelIndex &) const { return m_list.count(); }
57+ QVariant data(const QModelIndex &, int ) const { return QVariant(); }
58+ QString focusedApplicationId() const {
59+ Q_FOREACH(MockApp *app, m_list) {
60+ if (app->focused()) return app->appId();
61+ }
62+ return QString();
63+ }
64+ unity::shell::application::ApplicationInfoInterface *get(int index) const { return m_list.at(index); }
65+ unity::shell::application::ApplicationInfoInterface *findApplication(const QString &appId) const {
66+ Q_FOREACH(MockApp* app, m_list) {
67+ if (app->appId() == appId) {
68+ return app;
69+ }
70+ }
71+ return nullptr;
72+ }
73+ unity::shell::application::ApplicationInfoInterface *startApplication(const QString &, const QStringList &) { return nullptr; }
74+ bool stopApplication(const QString &) { return false; }
75+ bool focusApplication(const QString &appId) {
76+ Q_FOREACH(MockApp* app, m_list) {
77+ app->setFocused(app->appId() == appId);
78+ }
79+ Q_EMIT focusedApplicationIdChanged();
80+ return true;
81+ }
82+
83+ void unfocusCurrentApplication() { }
84+
85+ void addApplication(MockApp *app) {
86+ beginInsertRows(QModelIndex(), count(), count());
87+ m_list.append(app);
88+ endInsertRows();
89+ }
90+ void removeApplication(int index) {
91+ beginRemoveRows(QModelIndex(), index, index);
92+ m_list.takeAt(index)->deleteLater();
93+ endRemoveRows();
94+ }
95+
96+private:
97+ QList<MockApp*> m_list;
98+};
99+
100+class LauncherModelTest : public QObject
101+{
102+ Q_OBJECT
103+
104+private:
105+ LauncherModel *launcherModel;
106+ MockAppManager *appManager;
107+
108+private Q_SLOTS:
109+
110+ void initTestCase() {
111+ launcherModel = new LauncherModel(this);
112+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 0);
113+
114+ appManager = new MockAppManager(this);
115+ launcherModel->setApplicationManager(appManager);
116+ }
117+
118+ // Adding 2 apps to the mock appmanager. Both should appear in the launcher.
119+ void init() {
120+ appManager->addApplication(new MockApp("abs-icon"));
121+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
122+
123+ appManager->addApplication(new MockApp("no-icon"));
124+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
125+ }
126+
127+ // Removing apps from appmanager and launcher as pinned ones would stick
128+ void cleanup() {
129+ while (appManager->count() > 0) {
130+ appManager->removeApplication(0);
131+ }
132+ while (launcherModel->rowCount(QModelIndex()) > 0) {
133+ launcherModel->requestRemove(launcherModel->get(0)->appId());
134+ }
135+ }
136+
137+ void testMove() {
138+ QCOMPARE(launcherModel->get(0)->pinned(), false);
139+ QCOMPARE(launcherModel->get(1)->pinned(), false);
140+
141+ LauncherItemInterface *item0BeforeMove = launcherModel->get(0);
142+ LauncherItemInterface *item1BeforeMove = launcherModel->get(1);
143+ launcherModel->move(1, 0);
144+
145+ QCOMPARE(item0BeforeMove, launcherModel->get(1));
146+ QCOMPARE(item1BeforeMove, launcherModel->get(0));
147+
148+ // moved item must be pinned now
149+ QCOMPARE(item0BeforeMove->pinned(), false);
150+ QCOMPARE(item1BeforeMove->pinned(), true);
151+ }
152+
153+ void testPinning() {
154+ QCOMPARE(launcherModel->get(0)->pinned(), false);
155+ QCOMPARE(launcherModel->get(1)->pinned(), false);
156+ launcherModel->pin(launcherModel->get(0)->appId());
157+ QCOMPARE(launcherModel->get(0)->pinned(), true);
158+ QCOMPARE(launcherModel->get(1)->pinned(), false);
159+ }
160+
161+ void testRemove_data() {
162+
163+ QTest::addColumn<bool>("pinned");
164+ QTest::addColumn<bool>("running");
165+
166+ QTest::newRow("non-pinned, running") << false << true;
167+ QTest::newRow("pinned, running") << true << false;
168+ QTest::newRow("pinned, non-running") << true << false;
169+ }
170+
171+ void testRemove() {
172+ QFETCH(bool, pinned);
173+ QFETCH(bool, running);
174+
175+ // In the beginning we always have two items
176+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
177+
178+ // pin one if required
179+ if (pinned) {
180+ launcherModel->pin(launcherModel->get(1)->appId());
181+ }
182+
183+ // stop it if required
184+ if (!running) {
185+ appManager->removeApplication(1);
186+ }
187+
188+ // Now remove it
189+ launcherModel->requestRemove(launcherModel->get(1)->appId());
190+
191+ if (running) {
192+ // both apps are running, both apps must still be here
193+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
194+
195+ // Item must be unpinned now
196+ QCOMPARE(launcherModel->get(1)->pinned(), false);
197+
198+ } else if (pinned) {
199+ // Item 1 must go away, item 0 is here to stay
200+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
201+ }
202+
203+ // done our checks. now stop the app if was still running
204+ if (running) {
205+ appManager->removeApplication(1);
206+ }
207+
208+ // It needs to go away in any case now
209+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
210+ }
211+
212+ void testQuickListPinningRemoving() {
213+ // we start with 2 unpinned items
214+ QCOMPARE(launcherModel->get(0)->pinned(), false);
215+ QCOMPARE(launcherModel->get(1)->pinned(), false);
216+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
217+
218+ // find the Pin item in the quicklist
219+ QuickListModel *model = qobject_cast<QuickListModel*>(launcherModel->get(0)->quickList());
220+ int pinActionIndex = -1;
221+ for (int i = 0; i < model->rowCount(QModelIndex()); ++i) {
222+ if (model->get(i).actionId() == "pin_item") {
223+ pinActionIndex = i;
224+ break;
225+ }
226+ }
227+ QVERIFY(pinActionIndex >= 0);
228+
229+ // trigger pin item quicklist action => Item must be pinned now.
230+ launcherModel->quickListActionInvoked(launcherModel->get(0)->appId(), pinActionIndex);
231+ QCOMPARE(launcherModel->get(0)->pinned(), true);
232+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
233+
234+ // quicklist needs to transform to remove item. trigger it and check it item goes away
235+ launcherModel->quickListActionInvoked(launcherModel->get(0)->appId(), pinActionIndex);
236+ QCOMPARE(launcherModel->get(0)->pinned(), false);
237+
238+ // still needs to be here as the app is still here
239+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
240+ // close the app
241+ appManager->removeApplication(0);
242+ // Now it needs to go away
243+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
244+ }
245+
246+ void testApplicationFocused() {
247+ // all apps unfocused at beginning...
248+ QCOMPARE(launcherModel->get(0)->focused(), false);
249+ QCOMPARE(launcherModel->get(1)->focused(), false);
250+
251+ appManager->focusApplication("abs-icon");
252+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
253+ QCOMPARE(launcherModel->get(0)->focused(), true);
254+ QCOMPARE(launcherModel->get(1)->focused(), false);
255+
256+ appManager->focusApplication("no-icon");
257+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
258+ QCOMPARE(launcherModel->get(0)->focused(), false);
259+ QCOMPARE(launcherModel->get(1)->focused(), true);
260+ }
261+
262+ void testClosingApps() {
263+ // At the start there are 2 items. Let's pin one.
264+ launcherModel->pin("abs-icon");
265+ while (appManager->count() > 0) {
266+ appManager->removeApplication(0);
267+ }
268+ // The pinned one needs to stay, the other needs to disappear
269+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
270+ QCOMPARE(launcherModel->get(0)->appId(), QLatin1String("abs-icon"));
271+ }
272+};
273+
274+QTEST_GUILESS_MAIN(LauncherModelTest)
275+#include "launchermodeltest.moc"
tests/plugins/Unity/Launcher/no-icon.desktopnew file+2
@@ -0,0 +1,2 @@
1+[Desktop Entry]
2+Name=No Icon
tests/plugins/Unity/Launcher/no-name.desktopnew file+2
@@ -0,0 +1,2 @@
1+[Desktop Entry]
2+Icon=no-name
tests/plugins/Unity/Launcher/rel-icon.desktopnew file+3
@@ -0,0 +1,3 @@
1+[Desktop Entry]
2+Name=Relative Icon
3+Icon=rel-icon.svg
tests/plugins/Unity/Launcher/rel-icon.svgnew file

No changes to the content.

tests/plugins/Unity/filtersbindingstest.cpp+61−30
@@ -65,17 +65,17 @@ DeeModel* FiltersBindingsTest::createFilterModel()
6565
6666void FiltersBindingsTest::createMultiRangeFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount)
6767{
68− createFilter(model, "filter-multirange", id, name, optionCount);
68+ createFilter(model, "filter-multirange", id, name, optionCount, true);
6969}
7070
7171void FiltersBindingsTest::createRadioOptionFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount)
7272{
73− createFilter(model, "filter-radiooption", id, name, optionCount);
73+ createFilter(model, "filter-radiooption", id, name, optionCount, true);
7474}
7575
7676void FiltersBindingsTest::createCheckOptionFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount)
7777{
78− createFilter(model, "filter-checkoption", id, name, optionCount);
78+ createFilter(model, "filter-checkoption", id, name, optionCount, true);
7979}
8080
8181void FiltersBindingsTest::createRatingsFilter(DeeModel *model, const std::string &id, const std::string &name)
@@ -90,7 +90,7 @@ void FiltersBindingsTest::createRatingsFilter(DeeModel *model, const std::string
9090 GVariant *children[2];
9191 GVariant *key1 = g_variant_new_string("show-all-button");
9292 GVariant *key2 = g_variant_new_string("rating");
93− children[0] = g_variant_new_dict_entry(key1, g_variant_new_variant(g_variant_new_boolean(false)));
93+ children[0] = g_variant_new_dict_entry(key1, g_variant_new_variant(g_variant_new_boolean(true)));
9494 children[1] = g_variant_new_dict_entry(key2, g_variant_new_variant(g_variant_new_double(0.0f)));
9595 auto fhints = g_variant_new_array(G_VARIANT_TYPE("{sv}"), children, 2);
9696
@@ -102,7 +102,7 @@ void FiltersBindingsTest::createRatingsFilter(DeeModel *model, const std::string
102102 dee_model_append_row(model, row);
103103}
104104
105−void FiltersBindingsTest::createFilter(DeeModel *model, const std::string &renderer, const std::string &id, const std::string &name, int optionCount)
105+void FiltersBindingsTest::createFilter(DeeModel *model, const std::string &renderer, const std::string &id, const std::string &name, int optionCount, bool showAll)
106106{
107107 GVariant* row[8];
108108
@@ -114,7 +114,7 @@ void FiltersBindingsTest::createFilter(DeeModel *model, const std::string &rende
114114 GVariant *children[2];
115115 GVariant *key1 = g_variant_new_string("show-all-button");
116116 GVariant *key2 = g_variant_new_string("options");
117− children[0] = g_variant_new_dict_entry(key1, g_variant_new_variant(g_variant_new_boolean(false)));
117+ children[0] = g_variant_new_dict_entry(key1, g_variant_new_variant(g_variant_new_boolean(showAll)));
118118 children[1] = g_variant_new_dict_entry(key2, g_variant_new_variant(createOptions(optionCount)));
119119 auto fhints = g_variant_new_array(G_VARIANT_TYPE("{sv}"), children, 2);
120120
@@ -143,9 +143,9 @@ void FiltersBindingsTest::testMultiRangeFilter()
143143 auto multi_filter = dynamic_cast<MultiRangeFilter*>(bind_filter);
144144 QVERIFY(multi_filter != nullptr);
145145 auto options = multi_filter->options();
146− QCOMPARE(options->rowCount(), 1);
146+ QCOMPARE(options->rowCount(), 2);
147147
148− auto idx = options->index(0);
148+ auto idx = options->index(1);
149149 QVariant id_var = options->data(idx, GenericOptionsModel::RoleId);
150150 QVariant name_var = options->data(idx, GenericOptionsModel::RoleName);
151151 QVariant icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
@@ -168,9 +168,9 @@ void FiltersBindingsTest::testMultiRangeFilter()
168168 auto multi_filter = dynamic_cast<MultiRangeFilter*>(bind_filter);
169169 QVERIFY(multi_filter != nullptr);
170170 auto options = multi_filter->options();
171− QCOMPARE(options->rowCount(), 2);
171+ QCOMPARE(options->rowCount(), 3);
172172
173− auto idx = options->index(0);
173+ auto idx = options->index(1);
174174 QVariant id_var = options->data(idx, GenericOptionsModel::RoleId);
175175 QVariant name_var = options->data(idx, GenericOptionsModel::RoleName);
176176 QVariant icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
@@ -181,10 +181,10 @@ void FiltersBindingsTest::testMultiRangeFilter()
181181 QCOMPARE(icon_var.toString(), QString(""));
182182 QCOMPARE(active_var.toBool(), false);
183183
184− AbstractFilterOption* opt1 = options->getRawOption(0);
184+ AbstractFilterOption* opt1 = options->getRawOption(1);
185185 QCOMPARE(opt1->id(), QString("opt0"));
186186
187− AbstractFilterOption* opt2 = options->getRawOption(1);
187+ AbstractFilterOption* opt2 = options->getRawOption(2);
188188 QCOMPARE(opt2->id(), QString("opt1"));
189189
190190 delete multi_filter;
@@ -199,18 +199,21 @@ void FiltersBindingsTest::testMultiRangeFilter()
199199 auto multi_filter = dynamic_cast<MultiRangeFilter*>(bind_filter);
200200 QVERIFY(multi_filter != nullptr);
201201 auto options = multi_filter->options();
202− QCOMPARE(options->rowCount(), 3);
202+ QCOMPARE(options->rowCount(), 4);
203+
204+ AbstractFilterOption* showAll = options->getRawOption(0);
205+ QVERIFY(showAll->id().startsWith("show_all::"));
203206
204− AbstractFilterOption* opt0 = options->getRawOption(0);
207+ AbstractFilterOption* opt0 = options->getRawOption(1);
205208 QCOMPARE(opt0->id(), QString("opt0"));
206209
207− AbstractFilterOption* opt1 = options->getRawOption(1);
210+ AbstractFilterOption* opt1 = options->getRawOption(2);
208211 QCOMPARE(opt1->id(), QString("opt1"));
209212
210− AbstractFilterOption* opt2 = options->getRawOption(2);
213+ AbstractFilterOption* opt2 = options->getRawOption(3);
211214 QCOMPARE(opt2->id(), QString("opt2"));
212215
213− // verify combined filter options are bound to correct underlying unity options
216+ // verify filter options are bound to correct underlying unity options
214217 auto core_multi_filter = std::dynamic_pointer_cast<unity::dash::MultiRangeFilter>(core_filter);
215218 QCOMPARE(QString::fromStdString(core_multi_filter->options()[0]->id()), QString("opt0"));
216219 QCOMPARE(QString::fromStdString(core_multi_filter->options()[1]->id()), QString("opt1"));
@@ -274,7 +277,7 @@ void FiltersBindingsTest::testCheckOptionFilter()
274277 auto check_filter = dynamic_cast<CheckOptionFilter*>(bind_filter);
275278 QVERIFY(check_filter != nullptr);
276279 auto options = check_filter->options();
277− QCOMPARE(options->rowCount(), 3);
280+ QCOMPARE(options->rowCount(), 4);
278281
279282 QCOMPARE(check_filter->id(), QString("f1"));
280283 QCOMPARE(check_filter->name(), QString("Filter1"));
@@ -284,7 +287,7 @@ void FiltersBindingsTest::testCheckOptionFilter()
284287 QCOMPARE(check_filter->collapsed(), false);
285288 QCOMPARE(check_filter->filtering(), false);
286289
287− auto idx = options->index(0);
290+ auto idx = options->index(1);
288291 QVariant id_var = options->data(idx, GenericOptionsModel::RoleId);
289292 QVariant name_var = options->data(idx, GenericOptionsModel::RoleName);
290293 QVariant icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
@@ -295,7 +298,7 @@ void FiltersBindingsTest::testCheckOptionFilter()
295298 QCOMPARE(icon_var.toString(), QString(""));
296299 QCOMPARE(active_var.toBool(), false);
297300
298− idx = options->index(1);
301+ idx = options->index(2);
299302 id_var = options->data(idx, GenericOptionsModel::RoleId);
300303 name_var = options->data(idx, GenericOptionsModel::RoleName);
301304 icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
@@ -306,38 +309,55 @@ void FiltersBindingsTest::testCheckOptionFilter()
306309 QCOMPARE(icon_var.toString(), QString(""));
307310 QCOMPARE(active_var.toBool(), false);
308311
309− AbstractFilterOption* opt0 = options->getRawOption(0);
310− AbstractFilterOption* opt1 = options->getRawOption(1);
311− AbstractFilterOption* opt2 = options->getRawOption(2);
312+ AbstractFilterOption* showAll = options->getRawOption(0);
313+ AbstractFilterOption* opt0 = options->getRawOption(1);
314+ AbstractFilterOption* opt1 = options->getRawOption(2);
315+ AbstractFilterOption* opt2 = options->getRawOption(3);
312316
317+ QSignalSpy showAllSpy(showAll, SIGNAL(activeChanged(bool)));
313318 QSignalSpy opt0spy(opt0, SIGNAL(activeChanged(bool)));
314319 QSignalSpy opt1spy(opt1, SIGNAL(activeChanged(bool)));
315320 QSignalSpy opt2spy(opt2, SIGNAL(activeChanged(bool)));
316321 QSignalSpy dataChangedSpy(options, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)));
317322
318323 // test active property changes
324+ QCOMPARE(showAll->active(), false);
319325 QCOMPARE(opt0->active(), false);
320326 QCOMPARE(opt1->active(), false);
321327 QCOMPARE(opt2->active(), false);
322328
323329 opt0->setActive(true);
330+ QCOMPARE(showAllSpy.count(), 0);
324331 QCOMPARE(opt0spy.count(), 1);
325332 QCOMPARE(opt1spy.count(), 0);
326333 QCOMPARE(opt2spy.count(), 0);
334+ QCOMPARE(showAll->active(), false);
327335 QCOMPARE(opt0->active(), true);
328336 QCOMPARE(opt1->active(), false);
329337 QCOMPARE(opt2->active(), false);
330338
331339 opt1->setActive(true);
340+ QCOMPARE(showAllSpy.count(), 0);
332341 QCOMPARE(opt0spy.count(), 2);
333342 QCOMPARE(opt1spy.count(), 1);
334343 QCOMPARE(opt2spy.count(), 0);
344+ QCOMPARE(showAll->active(), false);
335345 QCOMPARE(opt0->active(), false);
336346 QCOMPARE(opt1->active(), true);
337347 QCOMPARE(opt2->active(), false);
338348
339349 QCOMPARE(dataChangedSpy.count(), 3);
340350
351+ showAll->setActive(true);
352+ QCOMPARE(showAllSpy.count(), 1);
353+ QCOMPARE(opt0spy.count(), 2);
354+ QCOMPARE(opt1spy.count(), 2);
355+ QCOMPARE(opt2spy.count(), 0);
356+ QCOMPARE(showAll->active(), true);
357+ QCOMPARE(opt0->active(), false);
358+ QCOMPARE(opt1->active(), false);
359+ QCOMPARE(opt2->active(), false);
360+
341361 delete check_filter;
342362 }
343363}
@@ -357,7 +377,7 @@ void FiltersBindingsTest::testRadioOptionFilter()
357377 auto radio_filter = dynamic_cast<RadioOptionFilter*>(bind_filter);
358378 QVERIFY(radio_filter != nullptr);
359379 auto options = radio_filter->options();
360− QCOMPARE(options->rowCount(), 3);
380+ QCOMPARE(options->rowCount(), 4);
361381
362382 auto idx = options->index(0);
363383 QVariant id_var = options->data(idx, GenericOptionsModel::RoleId);
@@ -365,12 +385,23 @@ void FiltersBindingsTest::testRadioOptionFilter()
365385 QVariant icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
366386 QVariant active_var = options->data(idx, GenericOptionsModel::RoleActive);
367387
388+ QVERIFY(id_var.toString().startsWith("show_all::"));
389+ QVERIFY(name_var.toString().size() > 0);
390+ QCOMPARE(icon_var.toString(), QString(""));
391+ QCOMPARE(active_var.toBool(), false);
392+
393+ idx = options->index(1);
394+ id_var = options->data(idx, GenericOptionsModel::RoleId);
395+ name_var = options->data(idx, GenericOptionsModel::RoleName);
396+ icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
397+ active_var = options->data(idx, GenericOptionsModel::RoleActive);
398+
368399 QCOMPARE(id_var.toString(), QString("opt0"));
369400 QCOMPARE(name_var.toString(), QString("Option 0"));
370401 QCOMPARE(icon_var.toString(), QString(""));
371402 QCOMPARE(active_var.toBool(), false);
372403
373− idx = options->index(1);
404+ idx = options->index(2);
374405 id_var = options->data(idx, GenericOptionsModel::RoleId);
375406 name_var = options->data(idx, GenericOptionsModel::RoleName);
376407 icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
@@ -381,9 +412,9 @@ void FiltersBindingsTest::testRadioOptionFilter()
381412 QCOMPARE(icon_var.toString(), QString(""));
382413 QCOMPARE(active_var.toBool(), false);
383414
384− AbstractFilterOption* opt0 = options->getRawOption(0);
385− AbstractFilterOption* opt1 = options->getRawOption(1);
386− AbstractFilterOption* opt2 = options->getRawOption(2);
415+ AbstractFilterOption* opt0 = options->getRawOption(1);
416+ AbstractFilterOption* opt1 = options->getRawOption(2);
417+ AbstractFilterOption* opt2 = options->getRawOption(3);
387418
388419 QSignalSpy opt0spy(opt0, SIGNAL(activeChanged(bool)));
389420 QSignalSpy opt1spy(opt1, SIGNAL(activeChanged(bool)));
@@ -432,11 +463,11 @@ void FiltersBindingsTest::testRatingsFilter()
432463 auto rating_filter = dynamic_cast<RatingsFilter*>(bind_filter);
433464 QVERIFY(rating_filter != nullptr);
434465 auto options = rating_filter->options();
435− QCOMPARE(options->rowCount(), 5);
466+ QCOMPARE(options->rowCount(), 6);
436467
437468 RatingFilterOption* opt[5];
438469 for (int i = 0; i<5; i++) {
439− opt[i] = dynamic_cast<RatingFilterOption *>(options->getRawOption(i));
470+ opt[i] = dynamic_cast<RatingFilterOption *>(options->getRawOption(i+1));
440471 }
441472
442473 QSignalSpy opt0spy(opt[0], SIGNAL(activeChanged(bool)));
tests/plugins/Unity/filtersbindingstest.h+1−1
@@ -41,7 +41,7 @@ class FiltersBindingsTest : public QObject
4141 void createCheckOptionFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount);
4242 void createRadioOptionFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount);
4343 void createRatingsFilter(DeeModel *model, const std::string &id, const std::string &name);
44− void createFilter(DeeModel *model, const std::string &renderer, const std::string &id, const std::string &name, int optionCount);
44+ void createFilter(DeeModel *model, const std::string &renderer, const std::string &id, const std::string &name, int optionCount, bool showAll);
4545};
4646
4747#endif // FILTERSBINDINGSTEST_H
tests/plugins/Unity/previewbindingstest.cpp+27
@@ -19,6 +19,7 @@
1919
2020#include <UnityCore/Preview.h>
2121#include <UnityCore/GLibWrapper.h>
22+#include <UnityCore/Variant.h>
2223#include <unity-protocol.h>
2324
2425#include "genericpreview.h"
@@ -48,7 +49,23 @@ void PreviewBindingsTest::testGenericPreview()
4849 UNITY_PROTOCOL_LAYOUT_HINT_LEFT);
4950 unity::glib::Object<GObject> genPrv(rawPreview);
5051
52+ // create local result
53+ unity::glib::HintsMap hints;
54+ hints["a"] = unity::glib::Variant(g_variant_new_string("b"));
55+ unity::dash::LocalResult localResult;
56+ localResult.uri = "http://foo";
57+ localResult.icon_hint = "xyz";
58+ localResult.category_index = 1;
59+ localResult.result_type = 2;
60+ localResult.mimetype = "abc";
61+ localResult.name = "baz";
62+ localResult.comment = "qwerty";
63+ localResult.dnd_uri = "zzz";
64+ localResult.hints = hints;
65+
5166 auto corePrv = unity::dash::Preview::PreviewForProtocolObject(genPrv);
67+ corePrv->preview_result = localResult;
68+
5269 auto prv = Preview::newFromUnityPreview(corePrv);
5370
5471 QCOMPARE(prv != nullptr, true);
@@ -64,6 +81,16 @@ void PreviewBindingsTest::testGenericPreview()
6481 QCOMPARE(act->displayName(), QString("Action1"));
6582 QCOMPARE(act->iconHint(), QString("/foo.png"));
6683
84+ Result* res = prv->result().value<Result*>();
85+ QCOMPARE(res->uri(), QString("http://foo"));
86+ QCOMPARE(res->iconHint(), QString("xyz"));
87+ QCOMPARE(res->categoryIndex(), 1u);
88+ QCOMPARE(res->resultType(), 2u);
89+ QCOMPARE(res->mimeType(), QString("abc"));
90+ QCOMPARE(res->title(), QString("baz"));
91+ QCOMPARE(res->dndUri(), QString("zzz"));
92+ QCOMPARE(res->metadata().toHash()["a"].toString(), QString("b"));
93+
6794 g_object_unref(icon);
6895 g_object_unref(iconFile);
6996}
tests/plugins/Unity/resultstest.cppnew file+105
@@ -0,0 +1,105 @@
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("image uri") << "image://thumbnail/with/arguments?passed_to=ImageProvider" << "image://thumbnail/with/arguments?passed_to=ImageProvider";
75+ QTest::newRow("themed icon") << "accessories-other" << "image://theme/accessories-other";
76+ QTest::newRow("fileicon") << ". GFileIcon http://example.org/resource.gif" << "http://example.org/resource.gif";
77+ QTest::newRow("themedicon") << ". GThemedIcon accessories-other accessories generic" << "image://theme/accessories-other,accessories,generic";
78+ QTest::newRow("annotatedicon") << ". UnityProtocolAnnotatedIcon %7B'base-icon':%20%3C'.%20GThemedIcon%20accessories-other%20accessories%20generic'%3E%7D" << "image://theme/accessories-other,accessories,generic";
79+}
80+
81+void ResultsTest::testIconColumn()
82+{
83+ QFETCH(QString, giconString);
84+ QFETCH(QString, result);
85+ auto deeModel = createBackendModel();
86+ dee_model_append (deeModel,
87+ "test:uri",
88+ giconString.toLocal8Bit().constData(),
89+ 0,
90+ 0,
91+ "application/octet-stream",
92+ "Test",
93+ "",
94+ "test:dnd-uri",
95+ g_variant_new_array(g_variant_type_element(G_VARIANT_TYPE_VARDICT), NULL, 0));
96+
97+ CategoryResults* results = new CategoryResults(this);
98+ results->setModel(deeModel);
99+
100+ auto index = results->index(0, 0); // there's just one result
101+ auto transformedIcon = index.data(CategoryResults::Roles::RoleIconHint).toString();
102+ QCOMPARE(transformedIcon, result);
103+}
104+
105+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+2−2
@@ -13,7 +13,6 @@ set(qmltest_DEFAULT_NO_ADD_TEST FALSE)
1313set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
1414add_qml_test(Components AnimationControllerWithSignals)
1515add_qml_test(Components Carousel)
16−add_qml_test(Components CrossFadeImage)
1716add_qml_test(Components MathLocal)
1817add_qml_test(Components OpenEffect)
1918add_qml_test(Components RatingStars)
@@ -32,6 +31,7 @@ add_manual_qml_test(Components DragHandle IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugi
3231add_qml_test(Components DraggingArea)
3332add_qml_test(Components EdgeDemoOverlay)
3433add_qml_test(Components FilterGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
34+add_qml_test(Components LazyImage)
3535add_qml_test(Components ResponsiveFlowView)
3636add_qml_test(Components ResponsiveGridView)
3737add_qml_test(Components Revealer)
@@ -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/Components/tst_CrossFadeImage.qmldeleted−125
@@ -1,125 +0,0 @@
1−/*
2− * Copyright 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 QtTest 1.0
19−import "../../../Components"
20−
21−TestCase {
22− name: "CrossFadeImage"
23−
24− property alias status: crossFadeImage.status
25− property alias source: crossFadeImage.source
26− property alias crossFade: crossFadeImage.crossFade
27− property alias fadeInFirst: crossFadeImage.fadeInFirst
28− property alias running: crossFadeImage.running
29−
30− CrossFadeImage {
31− id: crossFadeImage
32− }
33−
34− SignalSpy {
35− id: signalSpy
36− target: crossFadeImage
37− }
38−
39− function initTestFunction(argCrossFade, argFadeInFirst) {
40− source = ""
41− crossFade = argCrossFade
42− fadeInFirst = argFadeInFirst
43− compare(status, Image.Null, "Could not reset CrossFadeImage")
44− }
45−
46− function loadImage(url) {
47− console.log("Loading image...")
48− source = url
49−
50− signalSpy.signalName = "statusChanged"
51− signalSpy.wait()
52−
53− if (status == Image.Null) {
54− signalSpy.clear()
55− signalSpy.wait()
56− }
57−
58− if (status == Image.Loading) {
59− signalSpy.clear()
60− signalSpy.wait()
61− }
62−
63− compare(status, Image.Ready, "Image not ready")
64− console.log("Image loaded.")
65− }
66−
67− function waitForAnimation() {
68− signalSpy.signalName = "runningChanged"
69−
70− if (!running) {
71− signalSpy.clear()
72− signalSpy.wait()
73− compare(running, true, "Animation did not start")
74− }
75−
76− signalSpy.clear()
77− console.log("Waiting for animation to finish...")
78− signalSpy.wait()
79− compare(running, false, "Animation did not stop within 5 seconds.")
80− }
81−
82− function cleanupTest() {
83− compare(running, false, "Animation is running after testcase")
84− compare(crossFadeImage.__nextImage.source, "", "nextimage source is not reset")
85− }
86−
87− function test_fadeFirst() {
88− initTestFunction(true, true)
89−
90− loadImage("../../../graphics/phone_background.jpg")
91−
92− waitForAnimation()
93−
94− cleanupTest()
95− }
96−
97− function test_no_fadeFirst() {
98− initTestFunction(true, false)
99−
100− loadImage("../../../graphics/phone_background.jpg")
101−
102− cleanupTest()
103− }
104−
105− function test_crossFade() {
106− initTestFunction(true, false)
107−
108− loadImage("../../../graphics/phone_background.jpg")
109−
110− loadImage("../../../graphics/tablet_background.jpg")
111−
112− // Due to the internal implementation, __currentImage and __nextImage are swapped before the animation starts
113− // Make sure z order reflects that too.
114− compare(crossFadeImage.__currentImage.z > crossFadeImage.__nextImage.z, true, "new image should be above old image")
115− compare(crossFadeImage.__currentImage.opacity < 0.5, true)
116− compare(crossFadeImage.__nextImage.opacity > 0.5, true)
117−
118− waitForAnimation()
119−
120− compare(crossFadeImage.__currentImage.opacity > 0.5, true)
121− compare(crossFadeImage.__nextImage.opacity < 0.5, true)
122−
123− cleanupTest()
124− }
125−}
tests/qmltests/Components/tst_LazyImage.qmlnew file+156
@@ -0,0 +1,156 @@
1+/*
2+ * Copyright 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 QtTest 1.0
19+import "../../../Components"
20+import Ubuntu.Components 0.1
21+import Unity.Test 0.1 as UT
22+import "tst_LazyImage"
23+
24+Rectangle {
25+ width: units.gu(120)
26+ height: units.gu(70)
27+
28+ Rectangle {
29+ id: baseRect
30+ anchors {
31+ fill: parent
32+ rightMargin: 2 * parent.width / 3
33+ }
34+
35+ color: "grey"
36+
37+ Column {
38+ anchors { fill: parent; margins: units.gu(5) }
39+
40+ Label {
41+ height: units.gu(4)
42+ text: "Unbound"
43+ color: "white"
44+ verticalAlignment: Text.AlignBottom
45+ }
46+
47+ LazyImage {
48+ id: lazy1
49+ }
50+
51+ Label {
52+ height: units.gu(4)
53+ text: "Width-bound"
54+ color: "white"
55+ verticalAlignment: Text.AlignBottom
56+ }
57+
58+ LazyImage {
59+ id: lazy2
60+ width: units.gu(30)
61+ scaleTo: "width"
62+ }
63+
64+ Label {
65+ height: units.gu(4)
66+ text: "Height-bound"
67+ color: "white"
68+ verticalAlignment: Text.AlignBottom
69+ }
70+
71+ LazyImage {
72+ id: lazy3
73+ height: units.gu(10)
74+ scaleTo: "height"
75+ }
76+ }
77+ }
78+
79+ Rectangle {
80+ id: controlsRect
81+ anchors {
82+ fill: parent
83+ leftMargin: parent.width / 3
84+ }
85+
86+ color: "lightgrey"
87+
88+ Column {
89+ id: controls
90+ spacing: units.gu(1)
91+
92+ anchors { fill: parent; margins: units.gu(3) }
93+
94+ ImageControls { id: controls1; image: lazy1 }
95+ ImageControls { id: controls2; image: lazy2 }
96+ ImageControls { id: controls3; image: lazy3 }
97+ }
98+ }
99+
100+ UT.UnityTestCase {
101+ name: "Stage"
102+ when: windowShown
103+
104+ function cleanup() {
105+ controls1.blank();
106+ tryCompare(lazy1, "width", units.gu(10));
107+ controls2.blank();
108+ tryCompare(lazy2, "height", units.gu(10));
109+ controls3.blank();
110+ tryCompare(lazy3, "width", units.gu(10));
111+ }
112+
113+ function test_lazyimage_data() {
114+ return [
115+ {tag: "Unbound Blank", image: lazy1, func: controls1.blank, width: units.gu(10), height: units.gu(10), placeholder: true},
116+ {tag: "Unbound Wide", image: lazy1, func: controls1.wide, transition: "readyTransition", width: 160, height: 80},
117+ {tag: "Unbound Square", image: lazy1, func: controls1.square, transition: "readyTransition", width: 160, height: 160},
118+ {tag: "Unbound Portrait", image: lazy1, func: controls1.portrait, transition: "readyTransition", width: 80, height: 160},
119+ {tag: "Unbound Bad path", image: lazy1, func: controls1.badpath, transition: "genericTransition", width: units.gu(10), height: units.gu(10), placeholder: true, error: true},
120+ {tag: "Width-bound Blank", image: lazy2, func: controls2.blank, width: units.gu(30), height: units.gu(10), placeholder: true},
121+ {tag: "Width-bound Wide", image: lazy2, func: controls2.wide, transition: "readyTransition", width: units.gu(30), height: units.gu(15)},
122+ {tag: "Width-bound Square", image: lazy2, func: controls2.square, transition: "readyTransition", width: units.gu(30), height: units.gu(30)},
123+ {tag: "Width-bound Portrait", image: lazy2, func: controls2.portrait, transition: "readyTransition", width: units.gu(30), height: units.gu(60)},
124+ {tag: "Width-bound Bad path", image: lazy2, func: controls2.badpath, transition: "genericTransition", width: units.gu(30), height: units.gu(10), placeholder: true, error: true},
125+ {tag: "Height-bound Blank", image: lazy3, func: controls3.blank, width: units.gu(10), height: units.gu(10), placeholder: true},
126+ {tag: "Height-bound Wide", image: lazy3, func: controls3.wide, transition: "readyTransition", width: units.gu(20), height: units.gu(10)},
127+ {tag: "Height-bound Square", image: lazy3, func: controls3.square, transition: "readyTransition", width: units.gu(10), height: units.gu(10)},
128+ {tag: "Height-bound Portrait", image: lazy3, func: controls3.portrait, transition: "readyTransition", width: units.gu(5), height: units.gu(10)},
129+ {tag: "Height-bound Bad path", image: lazy3, func: controls3.badpath, transition: "genericTransition", width: units.gu(10), height: units.gu(10), placeholder: true, error: true},
130+ ]
131+ }
132+
133+ function test_lazyimage(data) {
134+ data.func();
135+
136+ if (data.transition) {
137+ // wait for the transition to complete
138+ var transition = findInvisibleChild(data.image, data.transition);
139+ tryCompare(transition, "running", true);
140+ tryCompare(transition, "running", false);
141+ }
142+
143+ // check the dimensions
144+ compare(data.image.width, data.width);
145+ compare(data.image.height, data.height);
146+
147+ // check the placeholder
148+ var placeholder = findChild(data.image, "placeholder");
149+ compare(placeholder.visible, data.placeholder ? true : false);
150+
151+ // check the error image
152+ var error = findChild(data.image, "errorImage");
153+ compare(error.visible, data.error ? true : false);
154+ }
155+ }
156+}
tests/qmltests/Components/tst_LazyImage/ImageControls.qmlnew file+67
@@ -0,0 +1,67 @@
1+/*
2+ * Copyright 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 "../../../../Components"
20+
21+Row {
22+ property LazyImage image
23+
24+ anchors { left: parent.left; right: parent.right }
25+ spacing: units.gu(1)
26+
27+ function blank() { blankButton.clicked() }
28+ function wide() { wideButton.clicked() }
29+ function square() { squareButton.clicked() }
30+ function portrait() { portraitButton.clicked() }
31+ function badpath() { badpathButton.clicked() }
32+
33+ Button {
34+ id: blankButton
35+ width: parent / 5
36+ text: "Blank"
37+ onClicked: image.source = ""
38+ }
39+
40+ Button {
41+ id: wideButton
42+ width: parent / 5
43+ text: "Wide"
44+ onClicked: image.source = "wide.png"
45+ }
46+
47+ Button {
48+ id: squareButton
49+ width: parent / 5
50+ text: "Square"
51+ onClicked: image.source = "square.png"
52+ }
53+
54+ Button {
55+ id: portraitButton
56+ width: parent / 5
57+ text: "Portrait"
58+ onClicked: image.source = "portrait.png"
59+ }
60+
61+ Button {
62+ id: badpathButton
63+ width: parent / 5
64+ text: "Bad path"
65+ onClicked: image.source = "bad/path"
66+ }
67+}
tests/qmltests/Components/tst_LazyImage/portrait.pngnew file

Binary file not shown.

tests/qmltests/Components/tst_LazyImage/square.pngnew file

Binary file not shown.

tests/qmltests/Components/tst_LazyImage/wide.pngnew file

Binary file not shown.

tests/qmltests/Components/tst_Stage.qml+1−1
@@ -18,7 +18,7 @@ import QtQuick 2.0
1818import QtTest 1.0
1919import ".."
2020import "../../../Components"
21−import Ubuntu.Application 0.1
21+import Unity.Application 0.1
2222import Ubuntu.Components 0.1
2323import Unity.Test 0.1 as UT
2424import "tst_Stage"
tests/qmltests/Dash/Apps/tst_AppPreview.qml+75−2
@@ -25,6 +25,9 @@ Item {
2525 width: units.gu(60)
2626 height: units.gu(80)
2727
28+ // Fake shell
29+ QtObject { id: shell; property int height: appPreview.height }
30+
2831 property var calls: []
2932
3033 SignalSpy {
@@ -45,6 +48,8 @@ Item {
4548 ["Unity User", 10, "10/02/2013", root.commentary],
4649 ]
4750 }
51+ QtObject { id: showProgress; property bool value: true }
52+ QtObject { id: progressSource; property string value: "service" }
4853
4954 QtObject {
5055 id: data
@@ -66,8 +71,30 @@ Item {
6671 ]
6772 }
6873
74+ QtObject {
75+ id: dataProgress
76+ property string title: "Unity App"
77+ property string appIcon: "fake_image.png"
78+ property string description: "This is an Application description"
79+ property real rating: rating.value
80+ property int numRatings: reviews.value
81+ property var execute: root.fake_call
82+ property var infoMap: {
83+ "show_progressbar": showProgress,
84+ "more-screenshots": screenshots,
85+ "rated": rated,
86+ "comments": comments,
87+ "progressbar_source": progressSource
88+ }
89+ property var actions: [
90+ { "id": 123, "displayName": "action1" },
91+ { "id": 456, "displayName": "action2" },
92+ { "id": 789, "displayName": "action3" },
93+ ]
94+ }
95+
6996 function fake_call(id, data){
70− root.calls[root.calls.length] = id;
97+ root.calls[root.calls.length] = [id, data];
7198 }
7299
73100 // The component under test
@@ -89,6 +116,10 @@ Item {
89116 reviewField.focus = false;
90117 reviewField.text = "";
91118 data.rating = rating.value;
119+ dataProgress.infoMap["progressbar_source"].value = "service";
120+ var appReviews = findChild(appPreview, "appReviews");
121+ appReviews.visible = false;
122+ appPreview.keyboardSize = 0;
92123 }
93124
94125 function test_actions() {
@@ -102,7 +133,7 @@ Item {
102133
103134 var actions = data.actions;
104135 for(var i = 0; i < actions.length; i++) {
105− compare(root.calls[i], actions[i].id, "Id of action not found.");
136+ compare(root.calls[i][0], actions[i].id, "Id of action not found.");
106137 }
107138 }
108139
@@ -124,6 +155,7 @@ Item {
124155
125156 function test_review_focus() {
126157 var appReviews = findChild(appPreview, "appReviews");
158+ appReviews.visible = true;
127159 var sendButton = findChild(appReviews, "sendButton");
128160 var reviewField = findChild(appReviews, "reviewField");
129161
@@ -162,5 +194,46 @@ Item {
162194 verify(buttons.visible == true);
163195 }
164196
197+ function test_progress_show() {
198+ appPreview.previewData = dataProgress;
199+ var progress = findChild(appPreview, "progressBar");
200+ verify(progress.visible == true);
201+ }
202+
203+ function test_progress_download_finish() {
204+ appPreview.previewData = dataProgress;
205+ var progress = findChild(appPreview, "progressBar");
206+ dataProgress.infoMap["progressbar_source"].value = "finish";
207+
208+ var actions = dataProgress.actions;
209+ compare(root.calls[0][0], actions[0].id, "Id of action not found.");
210+ compare(root.calls[0][1], {}, "Data of action not found.");
211+ }
212+
213+ function test_progress_download_error() {
214+ appPreview.previewData = dataProgress;
215+ var progress = findChild(appPreview, "progressBar");
216+ dataProgress.infoMap["progressbar_source"].value = "error";
217+
218+ var actions = dataProgress.actions;
219+ compare(root.calls[0][0], actions[1].id, "Id of action not found.");
220+ compare(root.calls[0][1], {"error": "DOWNLOAD ERROR"}, "Data of action not found.");
221+ }
222+
223+ function test_automatic_scroll_on_keyboard_shown() {
224+ waitForRendering(appPreview);
225+ var appReviews = findChild(appPreview, "appReviews");
226+ appReviews.visible = true;
227+
228+ var leftFlickable = findChild(appPreview, "leftFlickable");
229+ leftFlickable.contentY = leftFlickable.contentHeight;
230+ var reviewField = findChild(appReviews, "reviewField");
231+ appPreview.keyboardSize = 400;
232+ appReviews.editing(reviewField);
233+ var newFlickPos = leftFlickable.contentY;
234+ var keyboardY = shell.height - appPreview.keyboardSize;
235+ verify(newFlickPos < keyboardY);
236+ }
237+
165238 }
166239}
tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml+55−37
@@ -16,7 +16,6 @@
1616
1717import QtQuick 2.0
1818import QtTest 1.0
19−import Ubuntu.Application 0.1
2019import "../../../../Dash/Apps"
2120import Unity.Test 0.1 as UT
2221
@@ -29,8 +28,12 @@ Item {
2928
3029 property bool sideStageEnabled: false
3130
32− function stopProcess(application) {
33− fakeRunningAppsModel.remove(application)
31+ function stopApplication(appId) {
32+ for (var i=0, len=fakeRunningAppsModel.count; i<len; i++) {
33+ if (appId == fakeRunningAppsModel.get(i).appId) {
34+ fakeRunningAppsModel.remove(i)
35+ }
36+ }
3437 }
3538 }
3639
@@ -40,47 +43,62 @@ Item {
4043 property bool stageScreenshotsReady: false
4144 property var applicationManager: fakeApplicationManager
4245
43− function activateApplication(desktopFile) {
46+ function activateApplication(appId) {
4447 }
4548 }
4649
47− ApplicationListModel { id: fakeRunningAppsModel }
48−
49− ApplicationInfo {
50− id: phoneApp
51− name: "Phone"
52− icon: "phone-app"
53− exec: "/usr/bin/phone-app"
54− stage: ApplicationInfo.MainStage
55− desktopFile: "phone.desktop"
56− imageQml: "import QtQuick 2.0\n" +
57− "Rectangle { \n" +
58− " anchors.fill:parent \n" +
59− " color:'darkgreen' \n" +
60− " Text { anchors.centerIn: parent; text: 'PHONE' } \n" +
61− "}"
50+ ListModel {
51+ id: fakeRunningAppsModel
52+
53+ function contains(appId) {
54+ for (var i=0, len=fakeRunningAppsModel.count; i<len; i++) {
55+ if (appId == fakeRunningAppsModel.get(i).appId) {
56+ return true;
57+ }
58+ }
59+ return false;
60+ }
61+
62+ function rePopulate() {
63+ for (var i=0, len=availableAppsModel.count; i<len; i++) {
64+ fakeRunningAppsModel.append(availableAppsModel.get(i));
65+ }
66+ }
6267 }
6368
64− ApplicationInfo {
65− id: calendarApp
66− name: "Calendar"
67− icon: "calendar-app"
68− exec: "/usr/bin/calendar-app"
69− stage: ApplicationInfo.MainStage
70− desktopFile: "calendar.desktop"
71− imageQml: "import QtQuick 2.0\n" +
72− "Rectangle { \n" +
73− " anchors.fill:parent \n" +
74− " color:'darkblue' \n" +
75− " Text { anchors.centerIn: parent; text: 'CALENDAR'\n" +
76− " color:'white'} \n" +
77− "}"
69+ ListModel {
70+ id: availableAppsModel
71+ ListElement {
72+ name: "Phone"
73+ icon: "phone-app"
74+ exec: "/usr/bin/phone-app"
75+ appId: "phone"
76+ imageQml: "import QtQuick 2.0\n \
77+ Rectangle { \n \
78+ anchors.fill:parent \n \
79+ color:'darkgreen' \n \
80+ Text { anchors.centerIn: parent; text: 'PHONE' } \n \
81+ }"
82+ }
83+
84+ ListElement {
85+ name: "Calendar"
86+ icon: "calendar-app"
87+ exec: "/usr/bin/calendar-app"
88+ appId: "calendar"
89+ imageQml: "import QtQuick 2.0\n \
90+ Rectangle { \n \
91+ anchors.fill:parent \n \
92+ color:'darkblue' \n \
93+ Text { anchors.centerIn: parent; text: 'CALENDAR'\n \
94+ color:'white'} \n \
95+ }"
96+ }
7897 }
7998
8099 function resetRunningApplications() {
81100 fakeRunningAppsModel.clear()
82− fakeRunningAppsModel.add(phoneApp)
83− fakeRunningAppsModel.add(calendarApp)
101+ fakeRunningAppsModel.rePopulate()
84102 }
85103
86104 Component.onCompleted: {
@@ -185,11 +203,11 @@ Item {
185203 var calendarTile = findChild(runningApplicationsGrid, "runningAppTile Calendar")
186204 verify(calendarTile != undefined)
187205
188− verify(fakeRunningAppsModel.contains(calendarApp))
206+ verify(fakeRunningAppsModel.contains("calendar"))
189207
190208 mouseClick(calendarTile, calendarTile.width/2, calendarTile.height/2)
191209
192− verify(!fakeRunningAppsModel.contains(calendarApp))
210+ verify(!fakeRunningAppsModel.contains("calendar"))
193211
194212 // The tile for the Calendar app should eventually vanish since the
195213 // application has been terminated
tests/qmltests/Dash/tst_DashContent.qml+1−1
@@ -106,7 +106,7 @@ Item {
106106 contentEndReachedSpy.clear()
107107 clear_scope_status();
108108
109− // clear, wait for dahs to empty and load scopes.
109+ // clear, wait for dash to empty and load scopes.
110110 var dashContentList = findChild(dashContent, "dashContentList");
111111 verify(dashContentList != undefined)
112112 scopesModel.clear();
tests/qmltests/Dash/tst_GenericScopeView.qml+17
@@ -44,10 +44,27 @@ Item {
4444
4545 function test_isCurrent() {
4646 var pageHeader = findChild(genericScopeView, "pageHeader");
47+ var previewLoader = findChild(genericScopeView, "previewLoader");
4748 genericScopeView.isCurrent = true
4849 pageHeader.searchQuery = "test"
50+ previewLoader.open = true
4951 genericScopeView.isCurrent = false
5052 tryCompare(pageHeader, "searchQuery", "")
53+ tryCompare(genericScopeView, "previewShown", false);
54+ }
55+
56+ function test_showDash() {
57+ var previewLoader = findChild(genericScopeView, "previewLoader");
58+ previewLoader.open = true;
59+ scopes.get(0).showDash();
60+ tryCompare(genericScopeView, "previewShown", false);
61+ }
62+
63+ function test_hideDash() {
64+ var previewLoader = findChild(genericScopeView, "previewLoader");
65+ previewLoader.open = true;
66+ scopes.get(0).hideDash();
67+ tryCompare(genericScopeView, "previewShown", false);
5168 }
5269 }
5370 }
tests/qmltests/Greeter/tst_Phone.qml+19−1
@@ -18,8 +18,8 @@ import QtQuick 2.0
1818import QtTest 1.0
1919import ".."
2020import "../../../Greeter"
21+import AccountsService 0.1
2122import Ubuntu.Components 0.1
22−import LightDM 0.1 as LightDM
2323import Unity.Test 0.1 as UT
2424
2525Item {
@@ -32,6 +32,8 @@ Item {
3232 height: parent.height
3333 x: 0; y: 0
3434
35+ defaultBackground: "../../../graphics/phone_background.jpg"
36+
3537 property int minX: 0
3638
3739 onXChanged: {
@@ -102,5 +104,21 @@ Item {
102104 // Wait until we're back to 0
103105 tryCompareFunction(function() { return greeter.x;}, 0);
104106 }
107+
108+ function test_wallpaper_data() {
109+ return [
110+ {tag: "set", accounts: "../tests/data/unity/backgrounds/blue.png", expected: "blue.png"},
111+ {tag: "unset", accounts: "", expected: "background.jpg"},
112+ {tag: "invalid", accounts: "invalid", expected: "background.jpg"},
113+ ]
114+ }
115+
116+ function test_wallpaper(data) {
117+ var loader = findChild(greeter, "greeterContentLoader")
118+ var wallpaper = findChild(loader.item, "wallpaper")
119+ AccountsService.backgroundFile = data.accounts
120+ tryCompareFunction(function() { return wallpaper.source.toString().indexOf(data.expected) !== -1; }, true)
121+ tryCompare(wallpaper, "status", Image.Ready)
122+ }
105123 }
106124}
tests/qmltests/Launcher/tst_Launcher.qml+10−2
@@ -38,7 +38,7 @@ Item {
3838 property string lastSelectedApplication
3939
4040 onLauncherApplicationSelected: {
41− lastSelectedApplication = desktopFile
41+ lastSelectedApplication = appId
4242 }
4343
4444 property int dashItemSelected_count: 0
@@ -131,7 +131,7 @@ Item {
131131 mouseClick(appIcon, appIcon.width/2, appIcon.height/2)
132132
133133 tryCompare(launcher, "lastSelectedApplication",
134− "/usr/share/applications/phone-app.desktop")
134+ "phone-app")
135135
136136 // Tapping on an application icon also dismisses the launcher
137137 revealer.waitUntilLauncherDisappears()
@@ -198,6 +198,14 @@ Item {
198198 compare(findChild(delegate, "progressOverlay").visible, LauncherModel.get(i).progress >= 0)
199199 }
200200 }
201+
202+ function test_focusedHighlight() {
203+ var launcherListView = findChild(launcher, "launcherListView");
204+ for (var i = 0; i < launcherListView.count; ++i) {
205+ var delegate = findChild(launcherListView, "launcherDelegate" + i)
206+ compare(findChild(delegate, "focusedHighlight").visible, LauncherModel.get(i).focused)
207+ }
208+ }
201209 }
202210
203211 UT.UnityTestCase {
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,
tests/qmltests/tst_Shell.qml+33−9
@@ -20,7 +20,7 @@
2020import QtQuick 2.0
2121import QtTest 1.0
2222import GSettings 1.0
23−import Ubuntu.Application 0.1
23+import Unity.Application 0.1
2424import Unity.Test 0.1 as UT
2525import Powerd 0.1
2626
@@ -66,16 +66,16 @@ Item {
6666 }
6767
6868 // kill all (fake) running apps
69− killApps(ApplicationManager.mainStageApplications);
70− killApps(ApplicationManager.sideStageApplications);
69+ killApps(ApplicationManager);
7170
7271 var dashHome = findChild(shell, "DashHome");
7372 swipeUntilScopeViewIsReached(dashHome);
7473 }
7574
7675 function killApps(apps) {
76+ if (!apps) return;
7777 while (apps.count > 0) {
78− ApplicationManager.stopProcess(apps.get(0));
78+ ApplicationManager.stopApplication(apps.get(0).appId);
7979 }
8080 }
8181
@@ -114,6 +114,26 @@ Item {
114114 checkRightEdgeDragWithNoRunningApps();
115115 }
116116
117+ function test_leftEdgeDrag_data() {
118+ return [
119+ {tag: "without launcher", revealLauncher: false},
120+ {tag: "with launcher", revealLauncher: true},
121+ ];
122+ }
123+
124+ function test_leftEdgeDrag(data) {
125+ dragLauncherIntoView();
126+ tapOnAppIconInLauncher();
127+ waitUntilApplicationWindowIsFullyVisible();
128+
129+ if (data.revealLauncher) {
130+ dragLauncherIntoView();
131+ }
132+
133+ swipeFromLeftEdge();
134+ waitUntilApplicationWindowIsFullyHidden();
135+ }
136+
117137 function test_suspend() {
118138 var greeter = findChild(shell, "greeter");
119139
@@ -122,8 +142,8 @@ Item {
122142 tapOnAppIconInLauncher();
123143 waitUntilApplicationWindowIsFullyVisible();
124144
125− var mainApp = ApplicationManager.mainStageFocusedApplication;
126− tryCompareFunction(function() { return mainApp != null; }, true);
145+ var mainApp = ApplicationManager.focusedApplicationId;
146+ tryCompareFunction(function() { return mainApp != ""; }, true);
127147
128148 // Try to suspend while proximity is engaged...
129149 Powerd.displayPowerStateChange(Powerd.Off, Powerd.UseProximity);
@@ -132,11 +152,11 @@ Item {
132152 // Now really suspend
133153 Powerd.displayPowerStateChange(Powerd.Off, 0);
134154 tryCompare(greeter, "showProgress", 1);
135− tryCompare(ApplicationManager, "mainStageFocusedApplication", null);
155+ tryCompare(ApplicationManager, "focusedApplicationId", "");
136156
137157 // And wake up
138158 Powerd.displayPowerStateChange(Powerd.On, 0);
139− tryCompare(ApplicationManager, "mainStageFocusedApplication", mainApp);
159+ tryCompare(ApplicationManager, "focusedApplicationId", mainApp);
140160 tryCompare(greeter, "showProgress", 1);
141161 }
142162
@@ -223,7 +243,11 @@ Item {
223243 function dragLauncherIntoView() {
224244 var launcherPanel = findChild(shell, "launcherPanel");
225245 verify(launcherPanel.x = - launcherPanel.width);
226− swipeFromLeftEdge();
246+
247+ var touchStartX = 2;
248+ var touchStartY = shell.height / 2;
249+ touchFlick(shell, touchStartX, touchStartY, launcherPanel.width + units.gu(1), touchStartY);
250+
227251 tryCompare(launcherPanel, "x", 0);
228252 }
229253
tests/uqmlscene/main.cpp−2
@@ -497,8 +497,6 @@ int main(int argc, char ** argv)
497497 }
498498
499499 if (window) {
500− mouseTouchAdaptor.setTargetWindow(window);
501−
502500 QSurfaceFormat surfaceFormat = window->requestedFormat();
503501 if (options.multisample)
504502 surfaceFormat.setSamples(16);