ubuntu-touch-coreapps-reviewers team mailing list archive
-
ubuntu-touch-coreapps-reviewers team
-
Mailing list archive
-
Message #05017
[Merge] lp:~verzegnassi-stefano/ubuntu-docviewer-app/10-reboot-contenthub-switch-to-qml-apis into lp:ubuntu-docviewer-app/reboot
Stefano Verzegnassi has proposed merging lp:~verzegnassi-stefano/ubuntu-docviewer-app/10-reboot-contenthub-switch-to-qml-apis into lp:ubuntu-docviewer-app/reboot.
Commit message:
* Use QML APIs for Content Hub
* Remove toast notifications for imported documents (open documents automatically)
Requested reviews:
Ubuntu Document Viewer Developers (ubuntu-docviewer-dev)
Related bugs:
Bug #1469422 in Ubuntu Document Viewer App: "[Doc Viewer] Opening a file from content-hub should open the file or the notfication timeout should be increased"
https://bugs.launchpad.net/ubuntu-docviewer-app/+bug/1469422
For more details, see:
https://code.launchpad.net/~verzegnassi-stefano/ubuntu-docviewer-app/10-reboot-contenthub-switch-to-qml-apis/+merge/271466
* Use QML APIs for Content Hub
* Remove toast notifications for imported documents (open documents automatically)
*** NOTE ***
In DocviewerApplication and CommandLineParser classes, the argument "--pickMode" is broken.
Since we are going to move the arguments parser in QML too, that will be solved with a future commit.
At the moment, that argument is not used by Autopilot tests and the "reboot" branch is not released yet, therefore no relevant issue has been introduced.
--
Your team Ubuntu Document Viewer Developers is requested to review the proposed merge of lp:~verzegnassi-stefano/ubuntu-docviewer-app/10-reboot-contenthub-switch-to-qml-apis into lp:ubuntu-docviewer-app/reboot.
=== modified file 'src/app/CMakeLists.txt'
--- src/app/CMakeLists.txt 2015-09-02 11:31:45 +0000
+++ src/app/CMakeLists.txt 2015-09-19 11:41:47 +0000
@@ -10,7 +10,6 @@
set(docviewer_SRCS
main.cpp
- content-communicator.cpp
command-line-parser.cpp
docviewer-application.cpp
urlhandler.cpp
=== removed file 'src/app/content-communicator.cpp'
--- src/app/content-communicator.cpp 2015-07-14 01:35:59 +0000
+++ src/app/content-communicator.cpp 1970-01-01 00:00:00 +0000
@@ -1,257 +0,0 @@
-/*
- * Copyright (C) 2013 Canonical, Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 3.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "content-communicator.h"
-
-#include <QApplication>
-#include <QStandardPaths>
-#include <QMimeDatabase>
-#include <QDebug>
-#include <QFileInfo>
-
-#include <com/ubuntu/content/hub.h>
-#include <com/ubuntu/content/item.h>
-#include <com/ubuntu/content/transfer.h>
-
-
-using namespace com::ubuntu::content;
-
-/*!
- * \brief ContentCommunicator::ContentCommunicator
- * \param parent
- */
-ContentCommunicator::ContentCommunicator(QObject *parent)
- : ImportExportHandler(parent),
- m_transfer(nullptr)
-{
-}
-
-/*!
- * \brief ContentCommunicator::registerWithHub Register the handlers provided
- * by ContentCommunicator with the content hub
- */
-void ContentCommunicator::registerWithHub()
-{
- Hub *hub = Hub::Client::instance();
- hub->register_import_export_handler(this);
-}
-
-/*!
- * \brief \reimp
- */
-void ContentCommunicator::handle_import(content::Transfer *transfer)
-{
- // FIXME: If a file is imported from $HOME/Documents, a new copy of the file is created.
- // Could be use md5? http://doc.qt.io/qt-5/qml-qtqml-qt.html#md5-method
- QVariantList importedDocuments;
- QVector<Item> transferedItems = transfer->collect();
- foreach (const Item &hubItem, transferedItems) {
- QFileInfo fi(hubItem.url().toLocalFile());
-
- QString dir;
- QString destination;
- bool rejected = false;
-
- QMimeDatabase mdb;
- QMimeType mt = mdb.mimeTypeForFile(hubItem.url().toLocalFile());
-
- // Check if the item is supported by Ubuntu Document Viewer
- if (isSupportedMimetype(mt.name())) {
- /* We don't support formats that use a double extension
- (e.g. tar.gz), so we can safely use completeBaseName() and
- suffix() functions, in order to properly detect the name of
- the document even when there's a dot in the middle of the name.*/
- QString suffix = fi.suffix();
- QString filenameWithoutSuffix = fi.completeBaseName();
-
- if(suffix.isEmpty()) {
- // If the filename doesn't have an extension add one from the
- // detected mimetype
- if(!mt.preferredSuffix().isEmpty()) {
- suffix = mt.preferredSuffix();
- }
- }
-
- dir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + QDir::separator();
- destination = QString("%1.%2").arg(dir + filenameWithoutSuffix, suffix);
-
- // If we already have a file of this name reformat to "filename (copy x).png"
- // (where x is a number, incremented until we find an available filename)
- if(QFile::exists(destination)) {
- /*
- TRANSLATORS: This string is used for renaming a copied file,
- when a file with the same name already exists in user's
- Documents folder.
-
- e.g. "Manual_Aquaris_E4.5_ubuntu_EN.pdf" will become
- "Manual_Aquaris_E4.5_ubuntu_EN (copy 2).pdf"
-
- where "2" is given by the argument "%1"
- */
- QString reformattedSuffix = QString(_("copy %1"));
-
- QRegExp rx(" \\(" + reformattedSuffix.arg(QString("\\d+")) + "\\)");
- int reformattedSuffixPos = filenameWithoutSuffix.lastIndexOf(rx);
-
- // Check if the file has already a "copy" suffix
- if(reformattedSuffixPos != -1) {
- // Remove the "copy" suffix. We will re-put it later.
- filenameWithoutSuffix.truncate(reformattedSuffixPos);
- }
-
- int append = 1;
- do {
- destination = QString("%1 (%2).%3").arg(dir + filenameWithoutSuffix,
- reformattedSuffix.arg(QString::number(append)),
- suffix);
- append++;
- } while(QFile::exists(destination));
- }
-
- QFile::copy(hubItem.url().toLocalFile(), destination);
- } else {
- rejected = true;
- }
-
- // Append an entry for the imported document in the list that will be
- // emitted with the 'documentImported' signal.
- QVariantMap entry;
- if (rejected) {
- entry["fileName"] = fi.fileName();
- } else {
- entry["fileName"] = destination;
- }
- entry["rejected"] = rejected;
-
- importedDocuments.append(entry);
- }
-
- // Allow content-hub to clean up temporary files in .cache/ once we've
- // moved them
- transfer->finalize();
-
- emit documentImported(importedDocuments);
-}
-
-/*!
- * \brief \reimp
- */
-void ContentCommunicator::handle_export(content::Transfer *transfer)
-{
- if (m_transfer != nullptr) {
- qWarning() << "docviewer-app does only one content export at a time";
- transfer->abort();
- return;
- }
-
- m_transfer = transfer;
- emit documentRequested();
- emit selectionTypeChanged();
- emit singleContentPickModeChanged();
-}
-
-/*!
- * \brief \reimp
- */
-void ContentCommunicator::handle_share(content::Transfer *)
-{
- qDebug() << Q_FUNC_INFO << "docviewer does not share content";
-}
-
-/*!
- * \brief ContentCommunicator::cancelTransfer aborts the current transfer
- */
-void ContentCommunicator::cancelTransfer()
-{
- if (!m_transfer) {
- qWarning() << "No ongoing transfer to cancel";
- return;
- }
-
- m_transfer->abort();
- m_transfer = nullptr;
-}
-
-/*!
- * \brief ContentCommunicator::returnSocuments returns the given documents
- * via content hub to the requester
- * \param urls
- */
-void ContentCommunicator::returnDocuments(const QVector<QUrl> &urls)
-{
- if (!m_transfer) {
- qWarning() << "No ongoing transfer to return a document";
- return;
- }
-
- QVector<Item> items;
- items.reserve(urls.size());
- foreach (const QUrl &url, urls) {
- items.append(Item(url));
- }
-
- m_transfer->charge(items);
- m_transfer = nullptr;
-}
-
-/*!
- * \brief ContentCommunicator::selectionType return if the transfer requests
- * one single item only, or multiple
- * \return
- */
-ContentCommunicator::SelectionType ContentCommunicator::selectionType() const
-{
- if (!m_transfer)
- return SingleSelect;
-
- return static_cast<SelectionType>(m_transfer->selectionType());
-}
-
-/*!
- * \brief ContentCommunicator::singleContentPickMode
- * \return
- */
-bool ContentCommunicator::singleContentPickMode() const
-{
- if (!m_transfer)
- return true;
-
- // FIXME: Shouldn't be Transfer::SelectionType::SingleSelect?
- return m_transfer->selectionType() == Transfer::SelectionType::single;
-}
-
-/*!
- * \brief ContentCommunicator::isSupportedMimetype returns true if the given
- * mimetype is supported by Ubuntu Document Viewer
- * \param mimetype
- */
-bool ContentCommunicator::isSupportedMimetype(QString mimetype)
-{
- // TODO: We should use a common shared code for DocumentViewer.DocumentsModel
- // QML component and ContentHub. That will happen when we'll switch to
- // QML ContentHub APIs.
- return (mimetype.startsWith("text/")
- || mimetype == "application/pdf"
- || mimetype.startsWith("application/vnd.oasis.opendocument")
- || mimetype == "application/msword")
- || mimetype == "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
- || mimetype == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
- || mimetype == "application/vnd.openxmlformats-officedocument.presentationml.presentation"
- || mimetype == "application/msword"
- || mimetype == "application/vnd.ms-excel"
- || mimetype == "application/vnd.ms-powerpoint";
-}
=== removed file 'src/app/content-communicator.h'
--- src/app/content-communicator.h 2015-04-20 16:24:06 +0000
+++ src/app/content-communicator.h 1970-01-01 00:00:00 +0000
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2013 Canonical, Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 3.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef CONTENTCOMMUNICATOR_H
-#define CONTENTCOMMUNICATOR_H
-
-#include <com/ubuntu/content/import_export_handler.h>
-#include <com/ubuntu/content/transfer.h>
-
-#include <QUrl>
-#include <QVector>
-#include <libintl.h>
-
-#define _(value) dgettext(GETTEXT_PACKAGE, value)
-
-using namespace com::ubuntu;
-
-/*!
- * Class to handle the communication with the content manager
- */
-class ContentCommunicator : public content::ImportExportHandler
-{
- Q_OBJECT
- Q_PROPERTY(bool singleContentPickMode READ singleContentPickMode NOTIFY singleContentPickModeChanged)
- Q_PROPERTY(SelectionType selectionType READ selectionType NOTIFY selectionTypeChanged)
- Q_ENUMS(SelectionType)
-
-public:
- enum SelectionType {
- SingleSelect = content::Transfer::single,
- MultiSelect = content::Transfer::multiple
- };
-
- ContentCommunicator(QObject *parent = nullptr);
-
- virtual void handle_import(content::Transfer*);
- virtual void handle_export(content::Transfer *transfer);
- virtual void handle_share(content::Transfer*);
-
- void cancelTransfer();
- void returnDocuments(const QVector<QUrl> &urls);
-
- SelectionType selectionType() const;
- bool singleContentPickMode() const;
-
- void registerWithHub();
-
-signals:
- void documentRequested();
- void documentImported(QVariantList documents);
- void selectionTypeChanged();
- void singleContentPickModeChanged();
-
-private:
- content::Transfer *m_transfer;
-
- bool isSupportedMimetype(QString mimetype);
-};
-
-#endif // CONTENTCOMMUNICATOR_H
=== modified file 'src/app/docviewer-application.cpp'
--- src/app/docviewer-application.cpp 2015-04-29 15:23:32 +0000
+++ src/app/docviewer-application.cpp 2015-09-19 11:41:47 +0000
@@ -18,7 +18,6 @@
*/
#include "docviewer-application.h"
-#include "content-communicator.h"
#include "command-line-parser.h"
#include "urlhandler.h"
@@ -38,9 +37,6 @@
DocViewerApplication::DocViewerApplication(int& argc, char** argv)
: QApplication(argc, argv),
m_view(new QQuickView()),
- m_contentCommunicator(new ContentCommunicator(this)),
- m_pickModeEnabled(false),
- m_defaultUiMode(BrowseContentMode),
m_documentFile(""),
m_documentLoaded(false)
{
@@ -73,15 +69,10 @@
registerQML();
- if (m_cmdLineParser->pickModeEnabled())
+ // FIXME: Broken after removal of it.
+ /*if (m_cmdLineParser->pickModeEnabled())
setDefaultUiMode(DocViewerApplication::PickContentMode);
-
- QObject::connect(m_contentCommunicator, SIGNAL(documentRequested()),
- this, SLOT(switchToPickMode()));
-
- QObject::connect(m_contentCommunicator, SIGNAL(documentImported()),
- this, SLOT(switchToBrowseMode()));
-
+*/
return true;
}
@@ -172,7 +163,6 @@
// Set ourselves up to expose functionality to run external commands from QML...
m_view->engine()->rootContext()->setContextProperty("DOC_VIEWER", this);
- m_view->engine()->rootContext()->setContextProperty("PICKER_HUB", m_contentCommunicator);
QObject::connect(m_view->engine(), SIGNAL(quit()), this, SLOT(quit()));
@@ -201,7 +191,6 @@
qFatal("File: %s does not exist at any of the standard paths!", qPrintable(filePath));
}
- registerHub();
m_view->setSource(QUrl::fromLocalFile(qmlfile));
setDocumentFile(m_cmdLineParser->documentFile());
@@ -217,57 +206,6 @@
}
/*!
- * \brief DocViewerApplication::setDefaultUiMode set the default UI mode. This might
- * get overridden during the lifetime
- * \param mode
- */
-void DocViewerApplication::setDefaultUiMode(DocViewerApplication::UiMode mode)
-{
- m_defaultUiMode = mode;
- setUiMode(mode);
-}
-
-/*!
- * \brief DocViewerApplication::setUiMode set's the current UI mode
- * \param mode
- */
-void DocViewerApplication::setUiMode(DocViewerApplication::UiMode mode)
-{
- bool enablePickMode = (mode == PickContentMode);
-
- if (enablePickMode != m_pickModeEnabled) {
- m_pickModeEnabled = enablePickMode;
- Q_EMIT pickModeEnabledChanged();
- }
-}
-
-/*!
- * \brief DocViewerApplication::pickModeEnabled returns true if the current UI
- * mode should be for picking acontent
- * \return
- */
-bool DocViewerApplication::pickModeEnabled() const
-{
- return m_pickModeEnabled;
-}
-
-/*!
- * \brief DocViewerApplication::switchToPickMode
- */
-void DocViewerApplication::switchToPickMode()
-{
- setUiMode(PickContentMode);
-}
-
-/*!
- * \brief DocViewerApplication::switchToBrowseMode
- */
-void DocViewerApplication::switchToBrowseMode()
-{
- Q_EMIT browseModeRequested();
-}
-
-/*!
* \brief DocViewerApplication::setFullScreen
* Change window state to fullScreen or no state
*/
@@ -292,50 +230,6 @@
}
}
-/*!
- * \brief DocViewerApplication::returnPickedContent passes the selcted items to the
- * content manager
- * \param variant
- */
-void DocViewerApplication::returnPickedContent(QList<QString> paths)
-{
- QVector<QUrl> selectedMedias;
- selectedMedias.reserve(paths.size());
- foreach (const QString path, paths) {
- // We handle paths without "file://" prefix, so we need to add it when exporting to content-hub.
- selectedMedias.append(QUrl("file://" + path));
- }
- m_contentCommunicator->returnDocuments(selectedMedias);
-
- if (m_defaultUiMode == BrowseContentMode) {
- setUiMode(BrowseContentMode);
- } else {
- // give the app and content-hub some time to finish taks (run the event loop)
- QTimer::singleShot(10, this, SLOT(quit()));
- }
-}
-
-/*!
- * \brief DocViewerApplication::contentPickingCanceled tell the content manager, that
- * the picking was canceled
- */
-void DocViewerApplication::contentPickingCanceled()
-{
- m_contentCommunicator->cancelTransfer();
-
- if (m_defaultUiMode == BrowseContentMode) {
- setUiMode(BrowseContentMode);
- } else {
- // give the app and content-hub some time to finish taks (run the event loop)
- QTimer::singleShot(10, this, SLOT(quit()));
- }
-}
-
-void DocViewerApplication::registerHub()
-{
- m_contentCommunicator->registerWithHub();
-}
-
void DocViewerApplication::parseUri(const QString &arg)
{
if (m_urlHandler->processUri(arg)) {
=== modified file 'src/app/docviewer-application.h'
--- src/app/docviewer-application.h 2015-04-29 15:23:32 +0000
+++ src/app/docviewer-application.h 2015-09-19 11:41:47 +0000
@@ -37,62 +37,42 @@
class DocViewerApplication : public QApplication
{
Q_OBJECT
- Q_PROPERTY(bool pickModeEnabled READ pickModeEnabled NOTIFY pickModeEnabledChanged)
Q_PROPERTY(bool desktopMode READ isDesktopMode CONSTANT)
Q_PROPERTY(bool fullScreen READ isFullScreen WRITE setFullScreen NOTIFY fullScreenChanged)
Q_PROPERTY(QString documentFile READ getDocumentFile WRITE setDocumentFile NOTIFY documentFileChanged)
Q_PROPERTY(QString documentsDir READ getDocumentsDir CONSTANT)
public:
- enum UiMode{
- BrowseContentMode,
- PickContentMode
- };
-
explicit DocViewerApplication(int& argc, char** argv);
virtual ~DocViewerApplication();
bool init();
int exec();
- void setDefaultUiMode(UiMode mode);
- UiMode defaultUiMode() const;
- void setUiMode(UiMode mode);
- bool pickModeEnabled() const;
bool isDesktopMode() const;
bool isFullScreen() const;
const QString &getDocumentFile() const;
const QString &getDocumentsDir() const;
- Q_INVOKABLE void returnPickedContent(QList<QString> paths);
- Q_INVOKABLE void contentPickingCanceled();
Q_INVOKABLE void parseUri(const QString &arg);
Q_INVOKABLE void releaseResources();
signals:
- void pickModeEnabledChanged();
void fullScreenChanged();
void documentFileChanged();
- void browseModeRequested();
private slots:
- void switchToPickMode();
- void switchToBrowseMode();
void setFullScreen(bool fullScreen);
void setDocumentFile(const QString &documentFile);
private:
- void registerHub();
void registerQML();
void createView();
QQuickView *m_view;
CommandLineParser* m_cmdLineParser;
UrlHandler *m_urlHandler;
- ContentCommunicator *m_contentCommunicator;
- bool m_pickModeEnabled;
- UiMode m_defaultUiMode;
QString m_documentFile;
bool m_documentLoaded;
};
=== added file 'src/app/qml/common/ContentHubProxy.qml'
--- src/app/qml/common/ContentHubProxy.qml 1970-01-01 00:00:00 +0000
+++ src/app/qml/common/ContentHubProxy.qml 2015-09-19 11:41:47 +0000
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2012-2014 Canonical, Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.3
+import Ubuntu.Content 1.1
+import DocumentViewer 1.0
+
+// TODO: Show a dialog asking for the destination (internal storage or SD card)
+
+Item {
+ id: contentHubProxy
+
+ property var activeTransfer
+
+ property alias rejectedDocuments: rejectedDocsModel
+ property alias importedDocuments: importedDocsModel
+
+ property bool multipleSelection: activeTransfer ? (activeTransfer.selectionType !== ContentTransfer.Single) : true
+
+ ListModel { id: rejectedDocsModel }
+ ListModel { id: importedDocsModel }
+
+ ContentTransferHint {
+ activeTransfer: contentHubProxy.activeTransfer
+ }
+
+ Connections {
+ target: ContentHub
+
+ onImportRequested: {
+ activeTransfer = transfer;
+
+ if (activeTransfer.state === ContentTransfer.Charged) {
+ mainView.switchToBrowseMode()
+
+ internal.clearModels()
+
+ for (var i=0; i<activeTransfer.items.length; i++) {
+ var sourcePath = internal.getPathFromUrl(activeTransfer.items[i].url)
+
+ if (DocumentViewer.isFileSupported(sourcePath)) {
+ var documentsLocation = DocumentViewer.getXdgDocumentsLocation()
+ var destPath = DocumentViewer.buildDestinationPath(documentsLocation, sourcePath);
+
+ internal.importDocument(sourcePath, destPath)
+
+ } else {
+ // Document is not supported, append its entry into the
+ // rejected documents model, so that we can inform the
+ // user of what happened.
+ rejectedDocsModel.append({ path: sourcePath })
+ }
+ }
+
+ internal.finalizeImport()
+
+ internal.handleNotifications()
+ }
+ }
+
+ onExportRequested: {
+ activeTransfer = transfer;
+ mainView.switchToPickMode()
+ }
+ }
+
+ QtObject {
+ id: internal
+
+ function __openDocument() {
+ if (contentHubProxy.importedDocuments.count > 1) {
+ // If it has been imported more than a document, show
+ // a file picker when user taps the "open" action.
+ PopupUtils.open(
+ Qt.resolvedUrl("common/PickImportedDialog.qml"),
+ mainView,
+ {
+ parent: mainView,
+ model: contentHubProxy.importedDocuments
+ });
+ } else {
+ // It has been imported just a document, open it when
+ // user taps the action button.
+ mainView.openDocument(contentHubProxy.importedDocuments.get(0).path);
+ }
+ }
+
+ function clearModels() {
+ rejectedDocsModel.clear()
+ importedDocsModel.clear()
+ }
+
+ function getPathFromUrl(url) {
+ return url.toString().replace("file://", "")
+ }
+
+ function importDocument(sourcePath, destPath) {
+ DocumentViewer.copy(sourcePath, destPath);
+ importedDocsModel.append({ path: destPath })
+ }
+
+ function finalizeImport() {
+ activeTransfer.finalize()
+ }
+
+ function handleNotifications() {
+ // Check if there's any rejected document in the last transfer.
+ // If so, show an error dialog.
+ if (contentHubProxy.rejectedDocuments.count > 0) {
+ var rejectedDialog = PopupUtils.open(
+ Qt.resolvedUrl("common/RejectedImportDialog.qml"),
+ mainView,
+ {
+ parent: mainView,
+ model: contentHubProxy.rejectedDocuments
+ });
+ rejectedDialog.closed.connect(openDocument)
+ } else {
+ // Open the document, or show a pick dialog if more than one have been imported.
+ __openDocument()
+ }
+ }
+ }
+}
=== modified file 'src/app/qml/common/PickImportedDialog.qml'
--- src/app/qml/common/PickImportedDialog.qml 2015-04-10 17:00:59 +0000
+++ src/app/qml/common/PickImportedDialog.qml 2015-09-19 11:41:47 +0000
@@ -32,13 +32,13 @@
// We don't use a Flickable, since it already lives in the Dialog itself.
Repeater {
id: repeater
- delegate: ListItem.Standard {
- text: Utils.getNameOfFile(modelData)
+ ListItem.Standard {
+ text: Utils.getNameOfFile(model.path)
__foregroundColor: Theme.palette.selected.backgroundText
onClicked: {
PopupUtils.close(multipleImportDialog);
- mainView.openDocument(modelData);
+ mainView.openDocument(model.path);
}
}
}
=== modified file 'src/app/qml/common/RejectedImportDialog.qml'
--- src/app/qml/common/RejectedImportDialog.qml 2015-04-12 15:34:47 +0000
+++ src/app/qml/common/RejectedImportDialog.qml 2015-09-19 11:41:47 +0000
@@ -25,13 +25,13 @@
signal closed
- title: i18n.tr("File not supported", "Files not supported", model.length)
+ title: i18n.tr("File not supported", "Files not supported", repeater.count)
text: i18n.tr("Following document has not been imported:",
- "Following documents have not been imported:", model.length)
+ "Following documents have not been imported:", repeater.count)
Repeater {
id: repeater
- delegate: Label { text: modelData }
+ Label { text: model.path }
}
Button {
=== removed file 'src/app/qml/common/Toast.qml'
--- src/app/qml/common/Toast.qml 2015-04-07 22:03:03 +0000
+++ src/app/qml/common/Toast.qml 1970-01-01 00:00:00 +0000
@@ -1,82 +0,0 @@
-/*
- This file is part of quick-memo
- Copyright (C) 2014, 2015 Stefano Verzegnassi
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License 3 as published by
- the Free Software Foundation.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see http://www.gnu.org/licenses/.
-*/
-
-import QtQuick 2.0
-import Ubuntu.Components 1.1
-
-Rectangle {
- id: rootItem
-
- property alias text: label.text
-
- width: parent.width
- height: units.gu(8)
-
- color: "#131313"
- opacity: 0.85
- layer.enabled: true
-
- anchors {
- horizontalCenter: parent.horizontalCenter
- bottom: parent.bottom; bottomMargin: - height
- }
-
- Label {
- id: label
- anchors.centerIn: parent
-
- font.weight: Font.DemiBold
- color: "white"
- }
-
- MouseArea {
- anchors.fill: parent
-
- onClicked: {
- showAnimation.stop()
- destroyAnimation.restart()
- }
- }
-
- Rectangle {
- anchors {
- bottom: parent.bottom
- left: parent.left
- right: parent.right
- }
-
- height: units.dp(2)
- color: UbuntuColors.orange
- }
-
- SequentialAnimation {
- id: showAnimation
- running: true
-
- NumberAnimation { target: rootItem; property: "anchors.bottomMargin"; to: 0; duration: 300 }
- PauseAnimation { duration: 2000 }
- ScriptAction { script: destroyAnimation.restart() }
- }
-
- SequentialAnimation {
- id: destroyAnimation
-
- NumberAnimation { target: rootItem; property: "opacity"; to: 0; duration: 500 }
- ScriptAction { script: rootItem.destroy() }
- }
-}
-
=== removed file 'src/app/qml/common/ToastWithAction.qml'
--- src/app/qml/common/ToastWithAction.qml 2015-07-14 15:43:11 +0000
+++ src/app/qml/common/ToastWithAction.qml 1970-01-01 00:00:00 +0000
@@ -1,117 +0,0 @@
-/*
- Copyright (C) 2014, 2015 Stefano Verzegnassi
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License 3 as published by
- the Free Software Foundation.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see http://www.gnu.org/licenses/.
-*/
-
-import QtQuick 2.0
-import Ubuntu.Components 1.1
-import QtQuick.Layouts 1.1
-
-Rectangle {
- id: rootItem
-
- property alias text: label.text
- readonly property alias action: action
-
- width: parent.width
- height: units.gu(8)
-
- color: "#131313"
- opacity: 0.85
- layer.enabled: true
-
- anchors {
- horizontalCenter: parent.horizontalCenter
- bottom: parent.bottom; bottomMargin: - height
- }
-
- MouseArea {
- anchors.fill: parent
-
- onClicked: {
- showAnimation.stop()
- destroyAnimation.restart()
- }
- }
-
- RowLayout {
- anchors {
- fill: parent
- margins: units.gu(2)
- }
-
- Label {
- id: label
- Layout.fillWidth: true
-
- font.weight: Font.DemiBold
- color: "white"
- }
-
- AbstractButton {
- Layout.preferredWidth: actionLabel.paintedWidth
- Layout.fillHeight: true
-
- onClicked: {
- action.triggered("[Toast] Action %1 clicked!".arg(action.text))
- }
-
- Label {
- id: actionLabel
- text: action.text
-
- font.capitalization: Font.AllUppercase
- font.weight: Font.DemiBold
- color: UbuntuColors.orange
-
- anchors.centerIn: parent
- }
- }
- }
-
- Rectangle {
- anchors {
- bottom: parent.bottom
- left: parent.left
- right: parent.right
- }
-
- height: units.dp(2)
- color: UbuntuColors.orange
- }
-
- Action {
- id: action
-
- text: i18n.tr("Dismiss")
- onTriggered: destroyAnimation.restart()
- }
-
- SequentialAnimation {
- id: showAnimation
- running: true
-
- NumberAnimation { target: rootItem; property: "anchors.bottomMargin"; to: 0; duration: 300 }
- PauseAnimation { duration: 2000 }
- ScriptAction { script: destroyAnimation.restart() }
- }
-
- SequentialAnimation {
- id: destroyAnimation
-
- NumberAnimation { target: rootItem; property: "opacity"; to: 0; duration: 500 }
- ScriptAction { script: rootItem.destroy() }
- }
-}
-
=== modified file 'src/app/qml/documentPage/DocumentGridView.qml'
--- src/app/qml/documentPage/DocumentGridView.qml 2015-06-22 17:04:27 +0000
+++ src/app/qml/documentPage/DocumentGridView.qml 2015-09-19 11:41:47 +0000
@@ -37,6 +37,8 @@
cellWidth: (mainView.width > units.gu(50)) ? units.gu(24)
: (mainView.width - units.gu(2)) * 0.5
+ multipleSelection: contentHubProxy.multipleSelection ? contentHubProxy.multipleSelection : false
+
listDelegate: DocumentGridDelegate {
id: delegate
width: cellWidth
=== modified file 'src/app/qml/documentPage/DocumentListView.qml'
--- src/app/qml/documentPage/DocumentListView.qml 2015-06-22 17:04:27 +0000
+++ src/app/qml/documentPage/DocumentListView.qml 2015-09-19 11:41:47 +0000
@@ -48,6 +48,8 @@
}
}
+ multipleSelection: contentHubProxy.multipleSelection ? contentHubProxy.multipleSelection : false
+
listDelegate: DocumentListDelegate {
id: delegate
=== modified file 'src/app/qml/documentPage/DocumentPage.qml'
--- src/app/qml/documentPage/DocumentPage.qml 2015-06-22 16:39:07 +0000
+++ src/app/qml/documentPage/DocumentPage.qml 2015-09-19 11:41:47 +0000
@@ -77,10 +77,10 @@
]
Connections {
- target: DOC_VIEWER
+ target: mainView
- onPickModeEnabledChanged: {
- if (DOC_VIEWER.pickModeEnabled) {
+ onPickModeChanged: {
+ if (mainView.pickMode) {
viewLoader.item.startSelection()
} else {
viewLoader.item.cancelSelection()
=== modified file 'src/app/qml/documentPage/DocumentPagePickModeHeader.qml'
--- src/app/qml/documentPage/DocumentPagePickModeHeader.qml 2015-03-03 15:41:11 +0000
+++ src/app/qml/documentPage/DocumentPagePickModeHeader.qml 2015-09-19 11:41:47 +0000
@@ -16,6 +16,7 @@
import QtQuick 2.3
import Ubuntu.Components 1.1
+import Ubuntu.Content 1.1
PageHeadState {
id: rootItem
@@ -27,7 +28,12 @@
text: i18n.tr("Cancel")
objectName: "cancelButton"
iconName: "close"
- onTriggered: DOC_VIEWER.contentPickingCanceled()
+ onTriggered: {
+ if (!contentHubProxy.activeTransfer)
+ return;
+
+ contentHubProxy.activeTransfer.state = ContentTransfer.Aborted;
+ }
}
actions: [
@@ -45,17 +51,18 @@
enabled: viewLoader.item.selectedItems.count > 0
iconName: "ok"
onTriggered: {
- if (!enabled)
+ if (!enabled || !contentHubProxy.activeTransfer)
return;
var urlList = []
var items = documentPage.view.item.selectedItems;
for (var i=0; i < items.count; i++) {
- urlList.push(items.get(i).model.path);
+ urlList.push("file://" + items.get(i).model.path);
}
- DOC_VIEWER.returnPickedContent(urlList);
+ contentHubProxy.activeTransfer.items = urlList
+ contentHubProxy.activeTransfer.state = ContentTransfer.Charged
}
}
]
=== modified file 'src/app/qml/ubuntu-docviewer-app.qml'
--- src/app/qml/ubuntu-docviewer-app.qml 2015-06-22 16:45:36 +0000
+++ src/app/qml/ubuntu-docviewer-app.qml 2015-09-19 11:41:47 +0000
@@ -28,7 +28,8 @@
id: mainView
objectName: "mainView"
- property bool pickMode: DOC_VIEWER.pickModeEnabled
+ // TODO: Connect with arguments
+ property bool pickMode: false
readonly property bool isLandscape: Screen.orientation == Qt.LandscapeOrientation ||
Screen.orientation == Qt.InvertedLandscapeOrientation
@@ -66,26 +67,12 @@
mainView, { parent: mainView });
}
- function showNotification(args) {
- var component = Qt.createComponent("common/Toast.qml")
- var toast = component.createObject(mainView, args);
-
- return toast;
- }
-
- function showNotificationWithAction(args) {
- var component = Qt.createComponent("common/ToastWithAction.qml")
- var toast = component.createObject(mainView, args);
-
- return toast;
- }
-
function setFullScreen(fullScreen) {
DOC_VIEWER.fullScreen = fullScreen;
}
function toggleFullScreen() {
- DOC_VIEWER.fullScreen = !APP.fullScreen;
+ DOC_VIEWER.fullScreen = !DOC_VIEWER.fullScreen;
}
function setHeaderVisibility(visible, toggleFullscreen) {
@@ -108,6 +95,19 @@
setHeaderVisibility(!header.visible);
}
+ function setPickMode(pickMode) {
+ mainView.pickMode = pickMode
+ }
+
+ function switchToBrowseMode() {
+ setPickMode(false)
+ }
+
+ function switchToPickMode() {
+ setPickMode(true)
+ }
+
+
// On screen rotation, force updating of header/U8 indicators panel visibility
onIsLandscapeChanged: setHeaderVisibility(true);
@@ -183,6 +183,16 @@
property bool reverseOrder: false
}
+ // Content Hub support
+ property alias contentHubProxy: contentHubLoader.item
+ Loader {
+ id: contentHubLoader
+
+ asynchronous: true
+ source: Qt.resolvedUrl("common/ContentHubProxy.qml")
+ }
+
+ // Uri Handler support
Connections {
target: UriHandler
onOpened: {
@@ -198,91 +208,13 @@
onDocumentFileChanged: {
openDocument(DOC_VIEWER.documentFile);
}
-
- onPickModeEnabledChanged: {
- mainView.pickMode = DOC_VIEWER.pickModeEnabled
-
- if (mainView.pickMode) {
- // If a document is loaded, pop() its page.
- while (pageStack.depth > 1) {
- pageStack.pop()
- }
- }
- }
}
- Connections {
- target: PICKER_HUB
-
- onDocumentImported: {
- // Create two arrays: one for rejected documents, and the other
- // for imported documents.
- var importedDocuments = [];
- var rejectedDocuments = [];
- var entry;
-
- // Fill the arrays.
- for (var i=0; i<documents.length; i++) {
- entry = documents[i];
-
- if (entry.rejected) {
- rejectedDocuments.push(entry.fileName);
- break;
- }
-
- importedDocuments.push(entry.fileName);
- }
-
- // Prepare import notification
- var showImportNotification = function() {
- if (importedDocuments.length > 0) {
- var importDialog = showNotificationWithAction({
- "text": i18n.tr("Document successfully imported!",
- "Documents successfully imported!",
- importedDocuments.length),
- "action.text": i18n.tr("Open")
- })
-
- if (importedDocuments.length > 1) {
- // If it has been imported more than a document, show
- // a file picker when user taps the "open" action.
- importDialog.action.triggered.connect(function() {
- PopupUtils.open(
- Qt.resolvedUrl("common/PickImportedDialog.qml"),
- mainView,
- {
- parent: mainView,
- model: importedDocuments
- }
- );
- });
- } else {
- // It has been imported just a document, open it when
- // user taps the action button.
- importDialog.action.triggered.connect(function() {
- openDocument(importedDocuments[0]);
- });
- }
- }
- }
-
- // Check if there's any rejected document in the last transfer.
- // If so, show an error dialog.
- if (rejectedDocuments.length > 0) {
- var rejectedDialog = PopupUtils.open(
- Qt.resolvedUrl("common/RejectedImportDialog.qml"),
- mainView,
- {
- parent: mainView,
- model: rejectedDocuments
- }
- );
-
- // Show import notification after the dialog has been closed.
- rejectedDialog.closed.connect(showImportNotification)
- } else {
- // No dialog has been shown. Show the notification.
- showImportNotification.call();
+ onPickModeChanged: {
+ if (mainView.pickMode) {
+ // If a document is loaded, pop() its page.
+ while (pageStack.depth > 1) {
+ pageStack.pop()
}
}
}
=== modified file 'src/plugin/file-qml-plugin/CMakeLists.txt'
--- src/plugin/file-qml-plugin/CMakeLists.txt 2015-09-09 17:25:56 +0000
+++ src/plugin/file-qml-plugin/CMakeLists.txt 2015-09-19 11:41:47 +0000
@@ -7,6 +7,7 @@
documentmodel.cpp
fswatcher.cpp
docviewerfile.cpp
+ documentviewersingleton.cpp
)
add_library(fileqmlplugin MODULE
=== modified file 'src/plugin/file-qml-plugin/backend.cpp'
--- src/plugin/file-qml-plugin/backend.cpp 2015-04-29 15:23:32 +0000
+++ src/plugin/file-qml-plugin/backend.cpp 2015-09-19 11:41:47 +0000
@@ -21,6 +21,16 @@
#include "backend.h"
#include "documentmodel.h"
#include "docviewerfile.h"
+#include "documentviewersingleton.h"
+
+static QObject *registerDocumentViewerSingleton (QQmlEngine *engine, QJSEngine *scriptEngine)
+{
+ Q_UNUSED(engine)
+ Q_UNUSED(scriptEngine)
+
+ DocumentViewerSingleton *ch = new DocumentViewerSingleton();
+ return ch;
+}
void BackendPlugin::registerTypes(const char *uri)
{
@@ -30,6 +40,8 @@
qmlRegisterType<DocumentModel>(uri, 1, 0, "DocumentsModel");
qmlRegisterType<DocviewerFile>(uri, 1, 0, "File");
+
+ qmlRegisterSingletonType<DocumentViewerSingleton>(uri, 1, 0, "DocumentViewer", registerDocumentViewerSingleton);
}
void BackendPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
=== modified file 'src/plugin/file-qml-plugin/documentmodel.cpp'
--- src/plugin/file-qml-plugin/documentmodel.cpp 2015-09-09 17:25:56 +0000
+++ src/plugin/file-qml-plugin/documentmodel.cpp 2015-09-19 11:41:47 +0000
@@ -17,6 +17,7 @@
#include "documentmodel.h"
#include "fswatcher.h"
+#include "documentviewersingleton.h"
#include <QStandardPaths>
#include <QDir>
@@ -114,19 +115,7 @@
bool DocumentModel::isFileSupported(const QString &path)
{
- QMimeDatabase db;
- QString mimetype = db.mimeTypeForFile(path).name();
-
- return (mimetype.startsWith("text/")
- || mimetype == "application/pdf"
- || mimetype.startsWith("application/vnd.oasis.opendocument")
- || mimetype == "application/msword")
- || mimetype == "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
- || mimetype == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
- || mimetype == "application/vnd.openxmlformats-officedocument.presentationml.presentation"
- || mimetype == "application/msword"
- || mimetype == "application/vnd.ms-excel"
- || mimetype == "application/vnd.ms-powerpoint";
+ return DocumentViewerSingleton::isFileSupported(path);
}
QHash<int, QByteArray> DocumentModel::roleNames() const
=== added file 'src/plugin/file-qml-plugin/documentviewersingleton.cpp'
--- src/plugin/file-qml-plugin/documentviewersingleton.cpp 1970-01-01 00:00:00 +0000
+++ src/plugin/file-qml-plugin/documentviewersingleton.cpp 2015-09-19 11:41:47 +0000
@@ -0,0 +1,121 @@
+/*
+ Copyright (C) 2015 Canonical, Ltd.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License 3 as published by
+ the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/.
+*/
+
+#include "documentviewersingleton.h"
+
+#include <QFileInfo>
+#include <QDir>
+#include <QMimeDatabase>
+#include <QStandardPaths>
+
+bool DocumentViewerSingleton::exists(const QString &path)
+{
+ QFileInfo fi(path);
+
+ if (fi.isFile())
+ return fi.exists();
+
+ // else
+ return QDir(path).exists();
+}
+
+bool DocumentViewerSingleton::copy(const QString &source, const QString &destination)
+{
+ return QFile::copy(source, destination);
+}
+
+bool DocumentViewerSingleton::isFileSupported(const QString &path)
+{
+ QMimeDatabase mdb;
+ const QString mimetype = mdb.mimeTypeForFile(path).name();
+
+ return mimetype.startsWith("text/")
+ || mimetype == "application/pdf"
+ || mimetype.startsWith("application/vnd.oasis.opendocument")
+ || mimetype == "application/msword"
+ || mimetype == "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
+ || mimetype == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+ || mimetype == "application/vnd.openxmlformats-officedocument.presentationml.presentation"
+ || mimetype == "application/vnd.ms-excel"
+ || mimetype == "application/vnd.ms-powerpoint";
+}
+
+QString DocumentViewerSingleton::getXdgDocumentsLocation()
+{
+ return QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
+}
+
+QString DocumentViewerSingleton::buildDestinationPath(const QString &destinationDir, const QString &sourcePath)
+{
+ QFileInfo fi(sourcePath);
+
+ /*
+ We don't support formats that use a double extension
+ (e.g. tar.gz), so we can safely use completeBaseName() and
+ suffix() functions, in order to properly detect the name of
+ the document even when there's a dot in the middle of the name.
+ */
+ QString suffix = fi.suffix();
+ QString filenameWithoutSuffix = fi.completeBaseName();
+
+ QMimeDatabase mdb;
+ QMimeType mt = mdb.mimeTypeForFile(sourcePath);
+
+ // If the filename doesn't have an extension add one from the
+ // detected mimetype
+ if (suffix.isEmpty())
+ suffix = mt.preferredSuffix();
+
+ QString dir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + QDir::separator();
+ QString destination = QString("%1.%2").arg(dir + filenameWithoutSuffix, suffix);
+
+ // If there's already a file of this name, reformat it to
+ // "filename (copy x).png" where x is a number, incremented until we find an
+ // available filename.
+ if (QFile::exists(destination)) {
+ /*
+ TRANSLATORS: This string is used for renaming a copied file,
+ when a file with the same name already exists in user's
+ Documents folder.
+
+ e.g. "Manual_Aquaris_E4.5_ubuntu_EN.pdf" will become
+ "Manual_Aquaris_E4.5_ubuntu_EN (copy 2).pdf"
+
+ where "2" is given by the argument "%1"
+ */
+ QString reformattedSuffix = QString(tr("copy %1"));
+
+ // Check if the file has already a "copy" suffix
+ // If so, remove it since we will update it later.
+ QRegExp rx(" \\(" + reformattedSuffix.arg(QString("\\d+")) + "\\)");
+ int reformattedSuffixPos = filenameWithoutSuffix.lastIndexOf(rx);
+
+ if (reformattedSuffixPos != -1)
+ filenameWithoutSuffix.truncate(reformattedSuffixPos);
+
+ // Add the right "copy" suffix.
+ int append = 1;
+ while (QFile::exists(destination)) {
+ destination = QString("%1 (%2).%3").arg(
+ dir + filenameWithoutSuffix,
+ reformattedSuffix.arg(QString::number(append)),
+ suffix);
+ append++;
+ }
+ }
+
+ return destination;
+}
=== added file 'src/plugin/file-qml-plugin/documentviewersingleton.h'
--- src/plugin/file-qml-plugin/documentviewersingleton.h 1970-01-01 00:00:00 +0000
+++ src/plugin/file-qml-plugin/documentviewersingleton.h 2015-09-19 11:41:47 +0000
@@ -0,0 +1,37 @@
+/*
+ Copyright (C) 2015 Canonical, Ltd.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License 3 as published by
+ the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef DOCUMENTVIEWERSINGLETON_H
+#define DOCUMENTVIEWERSINGLETON_H
+
+#include <QObject>
+#include <QThread>
+
+class DocumentViewerSingleton : public QObject
+{
+ Q_OBJECT
+
+public:
+ Q_INVOKABLE static bool exists(const QString &path);
+ Q_INVOKABLE static bool copy(const QString &source, const QString &destination);
+
+ Q_INVOKABLE static bool isFileSupported(const QString &path);
+ Q_INVOKABLE static QString getXdgDocumentsLocation();
+
+ Q_INVOKABLE static QString buildDestinationPath(const QString &destinationDir, const QString &sourcePath);
+};
+
+#endif // DOCUMENTVIEWERSINGLETON_H
Follow ups
-
[Merge] lp:~verzegnassi-stefano/ubuntu-docviewer-app/10-reboot-contenthub-switch-to-qml-apis into lp:ubuntu-docviewer-app/reboot
From: noreply, 2015-09-21
-
[Merge] lp:~verzegnassi-stefano/ubuntu-docviewer-app/10-reboot-contenthub-switch-to-qml-apis into lp:ubuntu-docviewer-app/reboot
From: Stefano Verzegnassi, 2015-09-21
-
Re: [Merge] lp:~verzegnassi-stefano/ubuntu-docviewer-app/10-reboot-contenthub-switch-to-qml-apis into lp:ubuntu-docviewer-app/reboot
From: Stefano Verzegnassi, 2015-09-21
-
Re: [Merge] lp:~verzegnassi-stefano/ubuntu-docviewer-app/10-reboot-contenthub-switch-to-qml-apis into lp:ubuntu-docviewer-app/reboot
From: Roman Shchekin, 2015-09-21
-
Re: [Merge] lp:~verzegnassi-stefano/ubuntu-docviewer-app/10-reboot-contenthub-switch-to-qml-apis into lp:ubuntu-docviewer-app/reboot
From: Ubuntu Phone Apps Jenkins Bot, 2015-09-19
-
Re: [Merge] lp:~verzegnassi-stefano/ubuntu-docviewer-app/10-reboot-contenthub-switch-to-qml-apis into lp:ubuntu-docviewer-app/reboot
From: Stefano Verzegnassi, 2015-09-19
-
Re: [Merge] lp:~verzegnassi-stefano/ubuntu-docviewer-app/10-reboot-contenthub-switch-to-qml-apis into lp:ubuntu-docviewer-app/reboot
From: Stefano Verzegnassi, 2015-09-19
-
Re: [Merge] lp:~verzegnassi-stefano/ubuntu-docviewer-app/10-reboot-contenthub-switch-to-qml-apis into lp:ubuntu-docviewer-app/reboot
From: Roman Shchekin, 2015-09-19
-
Re: [Merge] lp:~verzegnassi-stefano/ubuntu-docviewer-app/10-reboot-contenthub-switch-to-qml-apis into lp:ubuntu-docviewer-app/reboot
From: Ubuntu Phone Apps Jenkins Bot, 2015-09-19
-
Re: [Merge] lp:~verzegnassi-stefano/ubuntu-docviewer-app/10-reboot-contenthub-switch-to-qml-apis into lp:ubuntu-docviewer-app/reboot
From: Ubuntu Phone Apps Jenkins Bot, 2015-09-19
-
Re: [Merge] lp:~verzegnassi-stefano/ubuntu-docviewer-app/10-reboot-contenthub-switch-to-qml-apis into lp:ubuntu-docviewer-app/reboot
From: Ubuntu Phone Apps Jenkins Bot, 2015-09-19
-
Re: [Merge] lp:~verzegnassi-stefano/ubuntu-docviewer-app/10-reboot-contenthub-switch-to-qml-apis into lp:ubuntu-docviewer-app/reboot
From: Ubuntu Phone Apps Jenkins Bot, 2015-09-19