on xenial help sign in
merge launcher-appmanager branch
98fb59fMichael Zanetti
Shell.qml+5
@@ -95,6 +95,11 @@ FocusScope {
95 greeter.hide();
95 greeter.hide();
96 shell.activateApplication(desktopFile);
96 shell.activateApplication(desktopFile);
97 }
97 }
98+
99+ onMainStageFocusedApplicationChanged: {
100+ var app = applicationManager.mainStageFocusedApplication
101+ LauncherModel.applicationFocused(app.desktopFile);
102+ }
98 }
103 }
99
104
100 function activateApplication(desktopFile, argument) {
105 function activateApplication(desktopFile, argument) {
plugins/Unity/Launcher/backend/launcherbackend.cpp+36−4
@@ -25,6 +25,7 @@
25#include <QDBusArgument>
25#include <QDBusArgument>
26#include <QFileInfo>
26#include <QFileInfo>
27#include <QGSettings>
27#include <QGSettings>
28+#include <QDebug>
28
29
29class LauncherBackendItem
30class LauncherBackendItem
30{
31{
@@ -73,6 +74,19 @@ void LauncherBackend::setStoredApplications(const QStringList &appIds)
73 }
74 }
74 }
75 }
75 m_storedApps = appIds;
76 m_storedApps = appIds;
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+ }
76 syncToAccounts();
90 syncToAccounts();
77}
91}
78
92
@@ -199,7 +213,7 @@ void LauncherBackend::syncFromAccounts()
199
213
200 m_storedApps.clear();
214 m_storedApps.clear();
201
215
202− if (m_accounts && m_user.isEmpty()) {
216+ if (m_accounts && !m_user.isEmpty()) {
203 QVariant variant = m_accounts->getUserProperty(m_user, "launcher-items");
217 QVariant variant = m_accounts->getUserProperty(m_user, "launcher-items");
204 apps = qdbus_cast<QList<QVariantMap>>(variant.value<QDBusArgument>());
218 apps = qdbus_cast<QList<QVariantMap>>(variant.value<QDBusArgument>());
205 defaults = isDefaultsItem(apps);
219 defaults = isDefaultsItem(apps);
@@ -248,14 +262,32 @@ QString LauncherBackend::findDesktopFile(const QString &appId) const
248 int dashPos = -1;
262 int dashPos = -1;
249 QString helper = appId;
263 QString helper = appId;
250
264
265+ QStringList searchDirs;
266+ searchDirs << "/usr/share/applications";
267+
268+// FIXME: Right now the appId can be (or rather is) a full path
269+// to a .desktop file. This will change in the future.
270+// Once the ApplicationManager has been switched over to use appIds,
271+// remove this chop() and enable the ifdef to only search the current
272+// working dir for testing. Also, this is the place to add the search
273+// paths for click apps in the next step.
274+ if (helper.endsWith(".desktop")) {
275+ helper.chop(8);
276+ }
277+//#ifdef LAUNCHER_TESTING
278+ searchDirs << "";
279+//#endif
280+
251 do {
281 do {
252 if (dashPos != -1) {
282 if (dashPos != -1) {
253 helper = helper.replace(dashPos, 1, '/');
283 helper = helper.replace(dashPos, 1, '/');
254 }
284 }
255
285
286+ Q_FOREACH(const QString &searchDir, searchDirs) {
256− QFileInfo fileInfo(QDir("/usr/share/applications"), helper);
287+ QFileInfo fileInfo(QDir(searchDir), helper + ".desktop");
257− if (fileInfo.exists()) {
288+ if (fileInfo.exists()) {
258− return fileInfo.absoluteFilePath();
289+ return fileInfo.absoluteFilePath();
290+ }
259 }
291 }
260
292
261 dashPos = helper.indexOf("-");
293 dashPos = helper.indexOf("-");
plugins/Unity/Launcher/launchermodel.cpp+37
@@ -191,6 +191,43 @@ void LauncherModel::setUser(const QString &username)
191 m_backend->setUser(username);
191 m_backend->setUser(username);
192}
192}
193
193
194+void LauncherModel::applicationFocused(const QString &appId)
195+{
196+ int index = findApplication(appId);
197+
198+ if (index >= 0) {
199+ // TODO: Mark application as focued
200+ } else {
201+ // Add app to recent apps
202+ QString desktopFile = m_backend->desktopFile(appId);
203+ QString appName = m_backend->displayName(appId);
204+ QString icon = m_backend->icon(appId);
205+
206+ LauncherItem *item = new LauncherItem(appId, desktopFile, appName, icon);
207+ item->setRecent(true);
208+ beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
209+ m_list.append(item);
210+ endInsertRows();
211+
212+ // Clean up old recent apps
213+ QList<int> recentAppIndices;
214+ for (int i = 0; i < m_list.count(); ++i) {
215+ if (m_list.at(i)->recent()) {
216+ recentAppIndices << i;
217+ }
218+ }
219+ int run = 0;
220+ while (recentAppIndices.count() > 5) {
221+ beginRemoveRows(QModelIndex(), recentAppIndices.first() - run, recentAppIndices.first() - run);
222+ m_list.takeAt(recentAppIndices.first() - run)->deleteLater();
223+ endRemoveRows();
224+ recentAppIndices.takeFirst();
225+ ++run;
226+ }
227+ storeAppList();
228+ }
229+}
230+
194void LauncherModel::storeAppList()
231void LauncherModel::storeAppList()
195{
232{
196 QStringList appIds;
233 QStringList appIds;
plugins/Unity/Launcher/launchermodel.h+1
@@ -49,6 +49,7 @@ public:
49 Q_INVOKABLE void requestRemove(const QString &appId);
49 Q_INVOKABLE void requestRemove(const QString &appId);
50 Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
50 Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
51 Q_INVOKABLE void setUser(const QString &username);
51 Q_INVOKABLE void setUser(const QString &username);
52+ Q_INVOKABLE void applicationFocused(const QString &appId);
52
53
53private:
54private:
54 void storeAppList();
55 void storeAppList();
tests/mocks/Unity/Launcher/MockLauncherModel.cpp+5
@@ -180,3 +180,8 @@ void MockLauncherModel::setUser(const QString &username)
180 Q_UNUSED(username)
180 Q_UNUSED(username)
181 // TODO: implement this...
181 // TODO: implement this...
182}
182}
183+
184+void MockLauncherModel::applicationFocused(const QString &appId)
185+{
186+ Q_UNUSED(appId)
187+}
tests/mocks/Unity/Launcher/MockLauncherModel.h+1
@@ -44,6 +44,7 @@ public:
44 Q_INVOKABLE void requestRemove(const QString &appId);
44 Q_INVOKABLE void requestRemove(const QString &appId);
45 Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
45 Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
46 Q_INVOKABLE void setUser(const QString &username);
46 Q_INVOKABLE void setUser(const QString &username);
47+ Q_INVOKABLE void applicationFocused(const QString &appId);
47
48
48Q_SIGNALS:
49Q_SIGNALS:
49 void quickListTriggered(const QString &appId, int index);
50 void quickListTriggered(const QString &appId, int index);
tests/plugins/Unity/Launcher/CMakeLists.txt+10
@@ -10,6 +10,7 @@ include_directories(
10
10
11add_definitions(-DSM_BUSNAME=sessionBus)
11add_definitions(-DSM_BUSNAME=sessionBus)
12add_definitions(-DSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}")
12add_definitions(-DSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}")
13+add_definitions(-DLAUNCHER_TESTING)
13
14
14set(testCommand ${CMAKE_CURRENT_BINARY_DIR}/launcherbackendtestExec
15set(testCommand ${CMAKE_CURRENT_BINARY_DIR}/launcherbackendtestExec
15 -o ${CMAKE_BINARY_DIR}/launcherbackendtest.xml,xunitxml
16 -o ${CMAKE_BINARY_DIR}/launcherbackendtest.xml,xunitxml
@@ -24,3 +25,12 @@ add_executable(launcherbackendtestExec
24 )
25 )
25target_link_libraries(launcherbackendtestExec ${GSETTINGS_QT_LDFLAGS})
26target_link_libraries(launcherbackendtestExec ${GSETTINGS_QT_LDFLAGS})
26qt5_use_modules(launcherbackendtestExec Test Core DBus)
27qt5_use_modules(launcherbackendtestExec Test Core DBus)
28+
29+# copy .desktop files into build directory for shadow builds
30+file(GLOB DESKTOP_FILES *.desktop)
31+
32+foreach(DESKTOP_FILE ${DESKTOP_FILES})
33+ file(COPY "${DESKTOP_FILE}"
34+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
35+ )
36+endforeach()
tests/plugins/Unity/Launcher/launcherbackendtest.cpp+14−15
@@ -20,7 +20,6 @@
20#include "launcherbackend.h"
20#include "launcherbackend.h"
21
21
22#include <QtTest>
22#include <QtTest>
23−#include <QDebug>
24
23
25class LauncherBackendTest : public QObject
24class LauncherBackendTest : public QObject
26{
25{
@@ -31,29 +30,29 @@ private Q_SLOTS:
31 {
30 {
32 LauncherBackend backend(false);
31 LauncherBackend backend(false);
33
32
34− backend.setStoredApplications(QStringList() << "relative.path" << "/full/path");
33+ backend.setStoredApplications(QStringList() << "rel-icon.desktop" << "abs-icon" << "invalid");
35− QCOMPARE(backend.storedApplications(), QStringList() << "relative.path" << "/full/path");
34+ QCOMPARE(backend.storedApplications(), QStringList() << "rel-icon.desktop" << "abs-icon");
36 }
35 }
37
36
38 void testPinning()
37 void testPinning()
39 {
38 {
40 LauncherBackend backend(false);
39 LauncherBackend backend(false);
41
40
42− backend.setStoredApplications(QStringList() << "one" << "two");
41+ backend.setStoredApplications(QStringList() << "rel-icon" << "abs-icon");
43− QCOMPARE(backend.isPinned("one"), false);
42+ QCOMPARE(backend.isPinned("rel-icon"), false);
44− QCOMPARE(backend.isPinned("two"), false);
43+ QCOMPARE(backend.isPinned("abs-icon"), false);
45
44
46− backend.setPinned("two", true);
45+ backend.setPinned("rel-icon", true);
47− QCOMPARE(backend.isPinned("two"), true);
46+ QCOMPARE(backend.isPinned("rel-icon"), true);
48
47
49− backend.setStoredApplications(QStringList() << "one" << "two" << "three");
48+ backend.setStoredApplications(QStringList() << "rel-icon" << "abs-icon" << "no-name");
50− QCOMPARE(backend.isPinned("two"), true);
49+ QCOMPARE(backend.isPinned("rel-icon"), true);
51− QCOMPARE(backend.isPinned("three"), false);
50+ QCOMPARE(backend.isPinned("no-name"), false);
52
51
53− backend.setPinned("three", true);
52+ backend.setPinned("no-name", true);
54− backend.setStoredApplications(QStringList() << "one" << "two");
53+ backend.setStoredApplications(QStringList() << "rel-icon" << "abs-icon");
55− QCOMPARE(backend.isPinned("two"), true);
54+ QCOMPARE(backend.isPinned("rel-icon"), true);
56− QCOMPARE(backend.isPinned("three"), false); // doesn't exist anymore!
55+ QCOMPARE(backend.isPinned("no-name"), false); // doesn't exist anymore!
57 }
56 }
58};
57};
59
58