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>
28ApplicationManager::ApplicationManager(QObject *parent)
29 : ApplicationManagerInterface(parent)
30 , m_mainStageComponent(0)
32 , m_sideStageComponent(0)
35 buildListOfAvailableApplications();
38ApplicationManager::~ApplicationManager()
42int ApplicationManager::rowCount(const QModelIndex& parent) const {
43 return !parent.isValid() ? m_runningApplications.size() : 0;
46QVariant ApplicationManager::data(const QModelIndex& index, int role) const {
47 if (index.row() < 0 || index.row() >= m_runningApplications.size())
50 auto app = m_runningApplications.at(index.row());
57 return app->comment();
65 return app->focused();
71ApplicationInfo *ApplicationManager::get(int row) const {
72 if (row < 0 || row >= m_runningApplications.size())
74 return m_runningApplications.at(row);
77ApplicationInfo *ApplicationManager::findApplication(const QString &appId) const {
78 for (ApplicationInfo *app : m_runningApplications) {
79 if (app->appId() == appId) {
86void ApplicationManager::add(ApplicationInfo *application) {
90 beginInsertRows(QModelIndex(), m_runningApplications.size(), m_runningApplications.size());
91 m_runningApplications.append(application);
93 Q_EMIT countChanged();
96void ApplicationManager::remove(ApplicationInfo *application) {
97 int i = m_runningApplications.indexOf(application);
99 beginRemoveRows(QModelIndex(), i, i);
100 m_runningApplications.removeAt(i);
102 Q_EMIT countChanged();
106void ApplicationManager::move(int from, int to) {
107 if (from == to) return;
109 if (from >= 0 && from < m_runningApplications.size() && to >= 0 && to < m_runningApplications.size()) {
111 /* When moving an item down, the destination index needs to be incremented
112 * by one, as explained in the documentation:
113 * http://qt-project.org/doc/qt-5.0/qtcore/qabstractitemmodel.html#beginMoveRows */
114 beginMoveRows(parent, from, from, parent, to + (to > from ? 1 : 0));
115 m_runningApplications.move(from, to);
120int ApplicationManager::keyboardHeight() const
125bool ApplicationManager::keyboardVisible() const
130int ApplicationManager::sideStageWidth() const
135ApplicationManager::StageHint ApplicationManager::stageHint() const
140ApplicationManager::FormFactorHint ApplicationManager::formFactorHint() const
142 return PhoneFormFactor;
145ApplicationInfo* ApplicationManager::startApplication(const QString &appId,
146 const QStringList &arguments)
148 return startApplication(appId, NoFlag, arguments);
151ApplicationInfo* ApplicationManager::startApplication(const QString &appId,
153 const QStringList &arguments)
156 ApplicationInfo *application = 0;
158 for (ApplicationInfo *availableApp : m_availableApplications) {
159 if (availableApp->appId() == appId) {
160 application = availableApp;
168 if (flags.testFlag(ApplicationManager::ForceMainStage)
169 && application->stage() == ApplicationInfo::SideStage) {
170 application->setStage(ApplicationInfo::MainStage);
177bool ApplicationManager::stopApplication(const QString &appId)
179 ApplicationInfo *application = findApplication(appId);
180 if (application == nullptr)
184 Q_EMIT focusedApplicationIdChanged();
188QString ApplicationManager::focusedApplicationId() const {
189 for (ApplicationInfo *app : m_runningApplications) {
190 if (app->focused()) {
197bool ApplicationManager::focusApplication(const QString &appId)
199 ApplicationInfo *application = findApplication(appId);
200 if (application == nullptr)
203 if (application->stage() == ApplicationInfo::MainStage) {
204 // unfocus currently focused mainstage app
205 for (ApplicationInfo *app : m_runningApplications) {
206 if (app->focused() && app->stage() == ApplicationInfo::MainStage) {
207 app->setFocused(false);
213 application->setFocused(true);
216 application->showWindow(m_mainStage);
217 m_mainStage->setZ(-1000);
219 m_sideStage->setZ(-2000);
220 } else if (application->stage() == ApplicationInfo::SideStage) {
221 // unfocus currently focused sidestage app
222 for (ApplicationInfo *app : m_runningApplications) {
223 if (app->focused() && app->stage() == ApplicationInfo::SideStage) {
224 app->setFocused(false);
230 application->setFocused(true);
233 application->showWindow(m_sideStage);
234 m_sideStage->setZ(-1000);
236 m_mainStage->setZ(-2000);
239 // move app to top of stack
240 move(m_runningApplications.indexOf(application), 0);
241 Q_EMIT focusedApplicationIdChanged();
245void ApplicationManager::unfocusCurrentApplication()
247 for (ApplicationInfo *app : m_runningApplications) {
248 if (app->focused()) {
250 app->setFocused(false);
253 Q_EMIT focusedApplicationIdChanged();
256void ApplicationManager::generateQmlStrings(ApplicationInfo *application)
258 // TODO: Is there a better way of solving this fullscreen vs. regular
259 // application height?
261 if (application->fullscreen()) {
262 topMargin.append("0");
264 // Taken from Panel.panelHeight
265 topMargin.append("units.gu(3) + units.dp(2)");
268 QString windowQml = QString(
269 "import QtQuick 2.0\n"
271 " anchors.fill: parent\n"
272 " anchors.topMargin: %1\n"
273 " source: \"file://%2/Dash/graphics/phone/screenshots/%3.png\"\n"
275 " fillMode: Image.PreserveAspectCrop\n"
278 .arg(application->icon().toString());
279 application->setWindowQml(windowQml);
281 QString imageQml = QString(
282 "import QtQuick 2.0\n"
284 " anchors.fill: parent\n"
285 " source: \"file://%1/Dash/graphics/phone/screenshots/%2.png\"\n"
287 " fillMode: Image.PreserveAspectCrop\n"
288 "}").arg(qmlDirectory())
289 .arg(application->icon().toString());
290 application->setImageQml(imageQml);
293void ApplicationManager::buildListOfAvailableApplications()
295 ApplicationInfo *application;
297 application = new ApplicationInfo(this);
298 application->setAppId("phone-app");
299 application->setName("Phone");
300 application->setIcon(QUrl("phone"));
301 application->setStage(ApplicationInfo::SideStage);
302 generateQmlStrings(application);
303 m_availableApplications.append(application);
305 application = new ApplicationInfo(this);
306 application->setAppId("camera-app");
307 application->setName("Camera");
308 application->setIcon(QUrl("camera"));
309 application->setFullscreen(true);
310 generateQmlStrings(application);
311 m_availableApplications.append(application);
313 application = new ApplicationInfo(this);
314 application->setAppId("gallery-app");
315 application->setName("Gallery");
316 application->setIcon(QUrl("gallery"));
317 generateQmlStrings(application);
318 m_availableApplications.append(application);
320 application = new ApplicationInfo(this);
321 application->setAppId("facebook-webapp");
322 application->setName("Facebook");
323 application->setIcon(QUrl("facebook"));
324 application->setStage(ApplicationInfo::SideStage);
325 generateQmlStrings(application);
326 m_availableApplications.append(application);
328 application = new ApplicationInfo(this);
329 application->setAppId("webbrowser-app");
330 application->setName("Browser");
331 application->setIcon(QUrl("browser"));
332 generateQmlStrings(application);
333 m_availableApplications.append(application);
335 application = new ApplicationInfo(this);
336 application->setAppId("twitter-webapp");
337 application->setName("Twitter");
338 application->setIcon(QUrl("twitter"));
339 application->setStage(ApplicationInfo::SideStage);
340 generateQmlStrings(application);
341 m_availableApplications.append(application);
343 application = new ApplicationInfo(this);
344 application->setAppId("gmail-webapp");
345 application->setName("GMail");
346 application->setIcon(QUrl("gmail"));
347 m_availableApplications.append(application);
349 application = new ApplicationInfo(this);
350 application->setAppId("ubuntu-weather-app");
351 application->setName("Weather");
352 application->setIcon(QUrl("weather"));
353 application->setStage(ApplicationInfo::SideStage);
354 generateQmlStrings(application);
355 m_availableApplications.append(application);
357 application = new ApplicationInfo(this);
358 application->setAppId("notes-app");
359 application->setName("Notepad");
360 application->setIcon(QUrl("notepad"));
361 application->setStage(ApplicationInfo::SideStage);
362 m_availableApplications.append(application);
364 application = new ApplicationInfo(this);
365 application->setAppId("calendar-app");
366 application->setName("Calendar");
367 application->setIcon(QUrl("calendar"));
368 application->setStage(ApplicationInfo::SideStage);
369 m_availableApplications.append(application);
371 application = new ApplicationInfo(this);
372 application->setAppId("mediaplayer-app");
373 application->setName("Media Player");
374 application->setIcon(QUrl("mediaplayer-app"));
375 application->setFullscreen(true);
376 m_availableApplications.append(application);
378 application = new ApplicationInfo(this);
379 application->setAppId("evernote");
380 application->setName("Evernote");
381 application->setIcon(QUrl("evernote"));
382 m_availableApplications.append(application);
384 application = new ApplicationInfo(this);
385 application->setAppId("map");
386 application->setName("Map");
387 application->setIcon(QUrl("map"));
388 generateQmlStrings(application);
389 m_availableApplications.append(application);
391 application = new ApplicationInfo(this);
392 application->setAppId("pinterest");
393 application->setName("Pinterest");
394 application->setIcon(QUrl("pinterest"));
395 m_availableApplications.append(application);
397 application = new ApplicationInfo(this);
398 application->setAppId("soundcloud");
399 application->setName("SoundCloud");
400 application->setIcon(QUrl("soundcloud"));
401 m_availableApplications.append(application);
403 application = new ApplicationInfo(this);
404 application->setAppId("wikipedia");
405 application->setName("Wikipedia");
406 application->setIcon(QUrl("wikipedia"));
407 m_availableApplications.append(application);
409 application = new ApplicationInfo(this);
410 application->setAppId("youtube");
411 application->setName("YouTube");
412 application->setIcon(QUrl("youtube"));
413 m_availableApplications.append(application);
416void ApplicationManager::createMainStageComponent()
418 // The assumptions I make here really should hold.
419 QQuickView *quickView =
420 qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
422 QQmlEngine *engine = quickView->engine();
424 m_mainStageComponent = new QQmlComponent(engine, this);
425 QString mainStageQml =
426 "import QtQuick 2.0\n"
428 " anchors.fill: parent\n"
432 m_mainStageComponent->setData(mainStageQml.toLatin1(), QUrl());
435void ApplicationManager::createMainStage()
437 if (!m_mainStageComponent)
438 createMainStageComponent();
440 // The assumptions I make here really should hold.
441 QQuickView *quickView =
442 qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
444 QQuickItem *shell = quickView->rootObject();
446 m_mainStage = qobject_cast<QQuickItem *>(m_mainStageComponent->create());
447 m_mainStage->setParentItem(shell);
450void ApplicationManager::createSideStageComponent()
452 // The assumptions I make here really should hold.
453 QQuickView *quickView =
454 qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
456 QQmlEngine *engine = quickView->engine();
458 m_sideStageComponent = new QQmlComponent(engine, this);
459 QString sideStageQml =
460 "import QtQuick 2.0\n"
461 "import Ubuntu.Components 0.1\n"
463 " width: units.gu(40)\n" // from SideStage in Shell.qml
464 " anchors.top: parent.top\n"
465 " anchors.bottom: parent.bottom\n"
466 " anchors.right: parent.right\n"
469 m_sideStageComponent->setData(sideStageQml.toLatin1(), QUrl());
472void ApplicationManager::createSideStage()
474 if (!m_sideStageComponent)
475 createSideStageComponent();
477 // The assumptions I make here really should hold.
478 QQuickView *quickView =
479 qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
481 QQuickItem *shell = quickView->rootObject();
483 m_sideStage = qobject_cast<QQuickItem *>(m_sideStageComponent->create());
484 m_sideStage->setParentItem(shell);
485 m_sideStage->setFlag(QQuickItem::ItemHasContents, false);
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