@@ -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