2 * Copyright (C) 2013 Canonical, Ltd.
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.
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.
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/>.
17#include "ApplicationManager.h"
18#include "ApplicationInfo.h"
23#include <QGuiApplication>
26#include <QQmlComponent>
31ApplicationManager::ApplicationManager(QObject *parent)
32 : ApplicationManagerInterface(parent)
34 , m_mainStageComponent(0)
36 , m_sideStageComponent(0)
40 buildListOfAvailableApplications();
43ApplicationManager::~ApplicationManager()
47int ApplicationManager::rowCount(const QModelIndex& parent) const {
48 return !parent.isValid() ? m_runningApplications.size() : 0;
51QVariant ApplicationManager::data(const QModelIndex& index, int role) const {
52 if (index.row() < 0 || index.row() >= m_runningApplications.size())
55 auto app = m_runningApplications.at(index.row());
62 return app->comment();
70 return app->focused();
72 return app->screenshot();
78ApplicationInfo *ApplicationManager::get(int row) const {
79 if (row < 0 || row >= m_runningApplications.size())
81 return m_runningApplications.at(row);
84ApplicationInfo *ApplicationManager::findApplication(const QString &appId) const {
85 for (ApplicationInfo *app : m_runningApplications) {
86 if (app->appId() == appId) {
93void ApplicationManager::add(ApplicationInfo *application) {
97 qDebug() << "add() " << application->appId();
99 beginInsertRows(QModelIndex(), m_runningApplications.size(), m_runningApplications.size());
100 m_runningApplications.append(application);
102 Q_EMIT applicationAdded(application->appId());
103 Q_EMIT countChanged();
104 Q_EMIT focusRequested(application->appId());
107void ApplicationManager::remove(ApplicationInfo *application) {
108 int i = m_runningApplications.indexOf(application);
110 beginRemoveRows(QModelIndex(), i, i);
111 m_runningApplications.removeAt(i);
113 Q_EMIT applicationRemoved(application->appId());
114 Q_EMIT countChanged();
118void ApplicationManager::move(int from, int to) {
119 if (from == to) return;
121 if (from >= 0 && from < m_runningApplications.size() && to >= 0 && to < m_runningApplications.size()) {
123 /* When moving an item down, the destination index needs to be incremented
124 * by one, as explained in the documentation:
125 * http://qt-project.org/doc/qt-5.0/qtcore/qabstractitemmodel.html#beginMoveRows */
126 beginMoveRows(parent, from, from, parent, to + (to > from ? 1 : 0));
127 m_runningApplications.move(from, to);
132int ApplicationManager::keyboardHeight() const
137bool ApplicationManager::keyboardVisible() const
142int ApplicationManager::sideStageWidth() const
147ApplicationManager::StageHint ApplicationManager::stageHint() const
152ApplicationManager::FormFactorHint ApplicationManager::formFactorHint() const
154 return PhoneFormFactor;
157ApplicationInfo* ApplicationManager::startApplication(const QString &appId,
158 const QStringList &arguments)
160 return startApplication(appId, NoFlag, arguments);
163ApplicationInfo* ApplicationManager::startApplication(const QString &appId,
165 const QStringList &arguments)
168 ApplicationInfo *application = 0;
170 for (ApplicationInfo *availableApp : m_availableApplications) {
171 if (availableApp->appId() == appId) {
172 application = availableApp;
180 if (flags.testFlag(ApplicationManager::ForceMainStage)
181 && application->stage() == ApplicationInfo::SideStage) {
182 application->setStage(ApplicationInfo::MainStage);
186 QMetaObject::invokeMethod(this, "focusApplication", Qt::QueuedConnection, Q_ARG(QString, appId));
191bool ApplicationManager::stopApplication(const QString &appId)
193 ApplicationInfo *application = findApplication(appId);
194 if (application == nullptr)
197 if (application->appId() == focusedApplicationId()) {
198 unfocusCurrentApplication();
201 qDebug() << Q_FUNC_INFO << "emitting focusedAppChanged" << focusedApplicationId();
205bool ApplicationManager::updateScreenshot(const QString &appId)
207 qDebug() << "updating screenshot for" << appId;
209 ApplicationInfo *application = nullptr;
210 for (int i = 0; i < m_availableApplications.count(); ++i) {
211 application = m_availableApplications.at(i);
212 if (application->appId() == appId) {
222 application->setScreenshot(QString("image://application/%1/%2").arg(appId).arg(QDateTime::currentMSecsSinceEpoch()));
223 QModelIndex appIndex = index(idx);
224 qDebug() << "emitting dataChanged for RoleScreenshot on" << appId;
225 Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << RoleScreenshot);
229QString ApplicationManager::focusedApplicationId() const {
230 for (ApplicationInfo *app : m_runningApplications) {
231 if (app->focused()) {
238bool ApplicationManager::suspended() const
243void ApplicationManager::setSuspended(bool suspended)
245 ApplicationInfo *focusedApp = findApplication(focusedApplicationId());
248 focusedApp->setState(ApplicationInfo::Suspended);
250 focusedApp->setState(ApplicationInfo::Running);
253 m_suspended = suspended;
254 Q_EMIT suspendedChanged();
257bool ApplicationManager::focusApplication(const QString &appId)
259 ApplicationInfo *application = findApplication(appId);
260 if (application == nullptr)
263 if (application->stage() == ApplicationInfo::MainStage) {
264 // unfocus currently focused mainstage app
265 for (ApplicationInfo *app : m_runningApplications) {
266 if (app->focused() && app->stage() == ApplicationInfo::MainStage) {
267 app->setFocused(false);
273 application->setFocused(true);
276 application->showWindow(m_mainStage);
277 m_mainStage->setZ(-1000);
279 m_sideStage->setZ(-2000);
280 } else if (application->stage() == ApplicationInfo::SideStage) {
281 // unfocus currently focused sidestage app
282 for (ApplicationInfo *app : m_runningApplications) {
283 if (app->focused() && app->stage() == ApplicationInfo::SideStage) {
284 app->setFocused(false);
290 application->setFocused(true);
293 application->showWindow(m_sideStage);
294 m_sideStage->setZ(-1000);
296 m_mainStage->setZ(-2000);
299 // move app to top of stack
300 move(m_runningApplications.indexOf(application), 0);
301 qDebug() << Q_FUNC_INFO << "emitting focusedAppChanged" << focusedApplicationId();
302 Q_EMIT focusedApplicationIdChanged();
306bool ApplicationManager::requestFocusApplication(const QString &appId)
308 if (appId != focusedApplicationId()) {
309 QMetaObject::invokeMethod(this, "focusRequested", Qt::QueuedConnection, Q_ARG(QString, appId));
315void ApplicationManager::unfocusCurrentApplication()
317 for (ApplicationInfo *app : m_runningApplications) {
318 if (app->focused()) {
320 app->setFocused(false);
323 qDebug() << Q_FUNC_INFO << "emitting focusedAppChanged" << focusedApplicationId();
324 Q_EMIT focusedApplicationIdChanged();
327void ApplicationManager::generateQmlStrings(ApplicationInfo *application)
329 // TODO: Is there a better way of solving this fullscreen vs. regular
330 // application height?
332 if (application->fullscreen()) {
333 topMargin.append("0");
335 // Taken from Panel.panelHeight
336 topMargin.append("units.gu(3) + units.dp(2)");
339 QString windowQml = QString(
340 "import QtQuick 2.0\n"
342 " anchors.fill: parent\n"
343 " anchors.topMargin: %1\n"
344 " anchors.rightMargin: %2\n"
345 " source: \"file://%3/Dash/graphics/phone/screenshots/%4.png\"\n"
347 " fillMode: Image.PreserveAspectCrop\n"
351 .arg(application->icon().toString());
352 application->setWindowQml(windowQml);
354 QString imageQml = QString(
355 "import QtQuick 2.0\n"
357 " anchors.fill: parent\n"
358 " source: \"file://%1/Dash/graphics/phone/screenshots/%2.png\"\n"
360 " fillMode: Image.PreserveAspectCrop\n"
361 "}").arg(qmlDirectory())
362 .arg(application->icon().toString());
363 application->setImageQml(imageQml);
366void ApplicationManager::buildListOfAvailableApplications()
368 ApplicationInfo *application;
370 application = new ApplicationInfo(this);
371 application->setAppId("phone-app");
372 application->setName("Phone");
373 application->setIcon(QUrl("phone"));
374 application->setStage(ApplicationInfo::SideStage);
375 application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch()));
376 generateQmlStrings(application);
377 m_availableApplications.append(application);
379 application = new ApplicationInfo(this);
380 application->setAppId("camera-app");
381 application->setName("Camera");
382 application->setIcon(QUrl("camera"));
383 application->setFullscreen(true);
384 application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch()));
385 generateQmlStrings(application);
386 m_availableApplications.append(application);
388 application = new ApplicationInfo(this);
389 application->setAppId("gallery-app");
390 application->setName("Gallery");
391 application->setIcon(QUrl("gallery"));
392 application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch()));
393 generateQmlStrings(application);
394 m_availableApplications.append(application);
396 application = new ApplicationInfo(this);
397 application->setAppId("facebook-webapp");
398 application->setName("Facebook");
399 application->setIcon(QUrl("facebook"));
400 application->setStage(ApplicationInfo::SideStage);
401 application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch()));
402 generateQmlStrings(application);
403 m_availableApplications.append(application);
405 application = new ApplicationInfo(this);
406 application->setAppId("webbrowser-app");
407 application->setFullscreen(true);
408 application->setName("Browser");
409 application->setIcon(QUrl("browser"));
410 application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch()));
411 generateQmlStrings(application);
412 m_availableApplications.append(application);
414 application = new ApplicationInfo(this);
415 application->setAppId("twitter-webapp");
416 application->setName("Twitter");
417 application->setIcon(QUrl("twitter"));
418 application->setStage(ApplicationInfo::SideStage);
419 application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch()));
420 generateQmlStrings(application);
421 m_availableApplications.append(application);
423 application = new ApplicationInfo(this);
424 application->setAppId("gmail-webapp");
425 application->setName("GMail");
426 application->setIcon(QUrl("gmail"));
427 application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch()));
428 m_availableApplications.append(application);
430 application = new ApplicationInfo(this);
431 application->setAppId("ubuntu-weather-app");
432 application->setName("Weather");
433 application->setIcon(QUrl("weather"));
434 application->setStage(ApplicationInfo::SideStage);
435 application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch()));
436 generateQmlStrings(application);
437 m_availableApplications.append(application);
439 application = new ApplicationInfo(this);
440 application->setAppId("notes-app");
441 application->setName("Notepad");
442 application->setIcon(QUrl("notepad"));
443 application->setStage(ApplicationInfo::SideStage);
444 application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch()));
445 m_availableApplications.append(application);
447 application = new ApplicationInfo(this);
448 application->setAppId("calendar-app");
449 application->setName("Calendar");
450 application->setIcon(QUrl("calendar"));
451 application->setStage(ApplicationInfo::SideStage);
452 application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch()));
453 m_availableApplications.append(application);
455 application = new ApplicationInfo(this);
456 application->setAppId("mediaplayer-app");
457 application->setName("Media Player");
458 application->setIcon(QUrl("mediaplayer-app"));
459 application->setFullscreen(true);
460 application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch()));
461 m_availableApplications.append(application);
463 application = new ApplicationInfo(this);
464 application->setAppId("evernote");
465 application->setName("Evernote");
466 application->setIcon(QUrl("evernote"));
467 application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch()));
468 m_availableApplications.append(application);
470 application = new ApplicationInfo(this);
471 application->setAppId("map");
472 application->setName("Map");
473 application->setIcon(QUrl("map"));
474 application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch()));
475 generateQmlStrings(application);
476 m_availableApplications.append(application);
478 application = new ApplicationInfo(this);
479 application->setAppId("pinterest");
480 application->setName("Pinterest");
481 application->setIcon(QUrl("pinterest"));
482 application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch()));
483 m_availableApplications.append(application);
485 application = new ApplicationInfo(this);
486 application->setAppId("soundcloud");
487 application->setName("SoundCloud");
488 application->setIcon(QUrl("soundcloud"));
489 application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch()));
490 m_availableApplications.append(application);
492 application = new ApplicationInfo(this);
493 application->setAppId("wikipedia");
494 application->setName("Wikipedia");
495 application->setIcon(QUrl("wikipedia"));
496 application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch()));
497 m_availableApplications.append(application);
499 application = new ApplicationInfo(this);
500 application->setAppId("youtube");
501 application->setName("YouTube");
502 application->setIcon(QUrl("youtube"));
503 application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch()));
504 m_availableApplications.append(application);
507void ApplicationManager::createMainStageComponent()
509 // The assumptions I make here really should hold.
510 QQuickView *quickView =
511 qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
513 QQmlEngine *engine = quickView->engine();
515 m_mainStageComponent = new QQmlComponent(engine, this);
516 QString mainStageQml =
517 "import QtQuick 2.0\n"
519 " anchors.fill: parent\n"
523 m_mainStageComponent->setData(mainStageQml.toLatin1(), QUrl());
526void ApplicationManager::createMainStage()
528 if (!m_mainStageComponent)
529 createMainStageComponent();
531 // The assumptions I make here really should hold.
532 QQuickView *quickView =
533 qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
535 QQuickItem *shell = quickView->rootObject();
537 m_mainStage = qobject_cast<QQuickItem *>(m_mainStageComponent->create());
538 m_mainStage->setParentItem(shell);
541void ApplicationManager::createSideStageComponent()
543 // The assumptions I make here really should hold.
544 QQuickView *quickView =
545 qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
547 QQmlEngine *engine = quickView->engine();
549 m_sideStageComponent = new QQmlComponent(engine, this);
550 QString sideStageQml =
551 "import QtQuick 2.0\n"
552 "import Ubuntu.Components 0.1\n"
554 " width: units.gu(40)\n" // from SideStage in Shell.qml
555 " anchors.top: parent.top\n"
556 " anchors.bottom: parent.bottom\n"
557 " anchors.right: parent.right\n"
560 m_sideStageComponent->setData(sideStageQml.toLatin1(), QUrl());
563void ApplicationManager::createSideStage()
565 if (!m_sideStageComponent)
566 createSideStageComponent();
568 // The assumptions I make here really should hold.
569 QQuickView *quickView =
570 qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
572 QQuickItem *shell = quickView->rootObject();
574 m_sideStage = qobject_cast<QQuickItem *>(m_sideStageComponent->create());
575 m_sideStage->setParentItem(shell);
576 m_sideStage->setFlag(QQuickItem::ItemHasContents, false);
579QStringList ApplicationManager::availableApplications()
582 Q_FOREACH(ApplicationInfo *app, m_availableApplications) {
583 appIds << app->appId();
588int ApplicationManager::rightMargin() const
590 return m_rightMargin;
593void ApplicationManager::setRightMargin(int rightMargin)
595 m_rightMargin = rightMargin;
596 Q_FOREACH(ApplicationInfo *app, m_availableApplications) {
597 generateQmlStrings(app);
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list