Merge lp:~verzegnassi-stefano/ubuntu-docviewer-app/10-reboot-contenthub-switch-to-qml-apis into lp:ubuntu-docviewer-app

Proposed by Stefano Verzegnassi
Status: Merged
Approved by: Stefano Verzegnassi
Approved revision: 177
Merged at revision: 180
Proposed branch: lp:~verzegnassi-stefano/ubuntu-docviewer-app/10-reboot-contenthub-switch-to-qml-apis
Merge into: lp:ubuntu-docviewer-app
Diff against target: 1563 lines (+391/-794)
21 files modified
debian/control (+3/-1)
src/app/CMakeLists.txt (+0/-7)
src/app/content-communicator.cpp (+0/-257)
src/app/content-communicator.h (+0/-74)
src/app/docviewer-application.cpp (+3/-109)
src/app/docviewer-application.h (+0/-20)
src/app/qml/common/ContentHubProxy.qml (+139/-0)
src/app/qml/common/PickImportedDialog.qml (+3/-3)
src/app/qml/common/RejectedImportDialog.qml (+3/-3)
src/app/qml/common/Toast.qml (+0/-82)
src/app/qml/common/ToastWithAction.qml (+0/-117)
src/app/qml/documentPage/DocumentGridView.qml (+11/-1)
src/app/qml/documentPage/DocumentListView.qml (+11/-1)
src/app/qml/documentPage/DocumentPage.qml (+3/-3)
src/app/qml/documentPage/DocumentPagePickModeHeader.qml (+11/-4)
src/app/qml/ubuntu-docviewer-app.qml (+31/-99)
src/plugin/file-qml-plugin/CMakeLists.txt (+1/-0)
src/plugin/file-qml-plugin/backend.cpp (+12/-0)
src/plugin/file-qml-plugin/documentmodel.cpp (+2/-13)
src/plugin/file-qml-plugin/docviewerutils.cpp (+121/-0)
src/plugin/file-qml-plugin/docviewerutils.h (+37/-0)
To merge this branch: bzr merge lp:~verzegnassi-stefano/ubuntu-docviewer-app/10-reboot-contenthub-switch-to-qml-apis
Reviewer Review Type Date Requested Status
Roman Shchekin Approve
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Review via email: mp+271466@code.launchpad.net

Commit message

* Use QML APIs for Content Hub
* Remove toast notifications for imported documents (open documents automatically)

Description of the change

* 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.

To post a comment you must log in.
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
174. By Stefano Verzegnassi

Forgotten bits

175. By Stefano Verzegnassi

Removed dependency on ContentHub C++ APIs and updated the others

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
176. By Stefano Verzegnassi

Renamed DocumentViewerSingleton as DocviewerUtils

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Roman Shchekin (mrqtros) wrote :

Left few comments in code. Overall feeling - ok.

review: Approve
Revision history for this message
Stefano Verzegnassi (verzegnassi-stefano) wrote :

> Should be rewritten as:
> property bool multipleSelection: !activeTransfer || activeTransfer.selectionType !== ContentTransfer.Single
> But looks strange anyway. Why do we allow multiple selection when transfer isn't acitve?

Good point.

Also, in DocumentGridView.qml and DocumentGrid|List)View.qml I wrote:
    multipleSelection: contentHubProxy.multipleSelection ? contentHubProxy.multipleSelection : false

That "false" is completely dumb.

We allow multiple selection to delete more files at once in the documents browser.
In the attempt of using a single property to set the multipleSelection value in the views, I've added the check for an active transfer in the ContentHubProxy.

Then I presume I forgot that ContentHubProxy is loaded asynchronously, and added that false in the views code.

I'll rewrite this piece of code, removing the property from ContentHubProxy, and setting everything directly in the views, keeping it more verbose.

Revision history for this message
Stefano Verzegnassi (verzegnassi-stefano) wrote :

Huh, I got it.

I tried to avoid to import Ubuntu.Content module in the views.

177. By Stefano Verzegnassi

Fixes as per MP review

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Roman Shchekin (mrqtros) wrote :

Should I top-approve it?

review: Approve
Revision history for this message
Stefano Verzegnassi (verzegnassi-stefano) wrote :

Sure! I forgot it.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2015-09-16 19:41:33 +0000
3+++ debian/control 2015-09-19 17:52:01 +0000
4@@ -4,7 +4,6 @@
5 Build-Depends: cmake,
6 debhelper (>= 9),
7 intltool,
8- libcontent-hub-dev (>= 0.0+13.10.20130930.1),
9 libpoppler-qt5-dev,
10 pep8,
11 pkg-config,
12@@ -28,6 +27,9 @@
13 Architecture: any
14 Depends: qtdeclarative5-qtquick2-plugin,
15 qtdeclarative5-ubuntu-ui-toolkit-plugin,
16+ qtdeclarative5-ubuntu-content1,
17+ qtdeclarative5-quicklayouts-plugin,
18+ qtdeclarative5-window-plugin,
19 suru-icon-theme (>= 14.04+15.10.20150707-0ubuntu1),
20 ${misc:Depends}
21 Description: Document Viewer application
22
23=== modified file 'src/app/CMakeLists.txt'
24--- src/app/CMakeLists.txt 2015-09-02 11:31:45 +0000
25+++ src/app/CMakeLists.txt 2015-09-19 17:52:01 +0000
26@@ -1,8 +1,6 @@
27 file(GLOB_RECURSE QML_SRCS *.qml *.js)
28 file(GLOB_RECURSE IMAGE_FILES *.qml *.js)
29
30-pkg_check_modules(CONTENTHUB REQUIRED libcontent-hub)
31-
32 add_definitions(
33 -DGETTEXT_PACKAGE=\"${PROJECT_NAME}\"
34 -DGETTEXT_LOCALEDIR=\"${CMAKE_INSTALL_LOCALEDIR}\"
35@@ -10,7 +8,6 @@
36
37 set(docviewer_SRCS
38 main.cpp
39- content-communicator.cpp
40 command-line-parser.cpp
41 docviewer-application.cpp
42 urlhandler.cpp
43@@ -21,10 +18,6 @@
44
45 qt5_use_modules(ubuntu-docviewer-app Widgets Gui Qml Quick DBus Concurrent)
46
47-target_link_libraries( ubuntu-docviewer-app
48- ${CONTENTHUB_LIBRARIES}
49-)
50-
51 if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
52 add_custom_target(docviewer-qmlfiles ALL
53 COMMAND cp -r ${CMAKE_CURRENT_SOURCE_DIR}/qml ${CMAKE_CURRENT_BINARY_DIR}
54
55=== removed file 'src/app/content-communicator.cpp'
56--- src/app/content-communicator.cpp 2015-07-14 01:35:59 +0000
57+++ src/app/content-communicator.cpp 1970-01-01 00:00:00 +0000
58@@ -1,257 +0,0 @@
59-/*
60- * Copyright (C) 2013 Canonical, Ltd.
61- *
62- * This program is free software; you can redistribute it and/or modify
63- * it under the terms of the GNU General Public License as published by
64- * the Free Software Foundation; version 3.
65- *
66- * This program is distributed in the hope that it will be useful,
67- * but WITHOUT ANY WARRANTY; without even the implied warranty of
68- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
69- * GNU General Public License for more details.
70- *
71- * You should have received a copy of the GNU General Public License
72- * along with this program. If not, see <http://www.gnu.org/licenses/>.
73- *
74- */
75-
76-#include "content-communicator.h"
77-
78-#include <QApplication>
79-#include <QStandardPaths>
80-#include <QMimeDatabase>
81-#include <QDebug>
82-#include <QFileInfo>
83-
84-#include <com/ubuntu/content/hub.h>
85-#include <com/ubuntu/content/item.h>
86-#include <com/ubuntu/content/transfer.h>
87-
88-
89-using namespace com::ubuntu::content;
90-
91-/*!
92- * \brief ContentCommunicator::ContentCommunicator
93- * \param parent
94- */
95-ContentCommunicator::ContentCommunicator(QObject *parent)
96- : ImportExportHandler(parent),
97- m_transfer(nullptr)
98-{
99-}
100-
101-/*!
102- * \brief ContentCommunicator::registerWithHub Register the handlers provided
103- * by ContentCommunicator with the content hub
104- */
105-void ContentCommunicator::registerWithHub()
106-{
107- Hub *hub = Hub::Client::instance();
108- hub->register_import_export_handler(this);
109-}
110-
111-/*!
112- * \brief \reimp
113- */
114-void ContentCommunicator::handle_import(content::Transfer *transfer)
115-{
116- // FIXME: If a file is imported from $HOME/Documents, a new copy of the file is created.
117- // Could be use md5? http://doc.qt.io/qt-5/qml-qtqml-qt.html#md5-method
118- QVariantList importedDocuments;
119- QVector<Item> transferedItems = transfer->collect();
120- foreach (const Item &hubItem, transferedItems) {
121- QFileInfo fi(hubItem.url().toLocalFile());
122-
123- QString dir;
124- QString destination;
125- bool rejected = false;
126-
127- QMimeDatabase mdb;
128- QMimeType mt = mdb.mimeTypeForFile(hubItem.url().toLocalFile());
129-
130- // Check if the item is supported by Ubuntu Document Viewer
131- if (isSupportedMimetype(mt.name())) {
132- /* We don't support formats that use a double extension
133- (e.g. tar.gz), so we can safely use completeBaseName() and
134- suffix() functions, in order to properly detect the name of
135- the document even when there's a dot in the middle of the name.*/
136- QString suffix = fi.suffix();
137- QString filenameWithoutSuffix = fi.completeBaseName();
138-
139- if(suffix.isEmpty()) {
140- // If the filename doesn't have an extension add one from the
141- // detected mimetype
142- if(!mt.preferredSuffix().isEmpty()) {
143- suffix = mt.preferredSuffix();
144- }
145- }
146-
147- dir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + QDir::separator();
148- destination = QString("%1.%2").arg(dir + filenameWithoutSuffix, suffix);
149-
150- // If we already have a file of this name reformat to "filename (copy x).png"
151- // (where x is a number, incremented until we find an available filename)
152- if(QFile::exists(destination)) {
153- /*
154- TRANSLATORS: This string is used for renaming a copied file,
155- when a file with the same name already exists in user's
156- Documents folder.
157-
158- e.g. "Manual_Aquaris_E4.5_ubuntu_EN.pdf" will become
159- "Manual_Aquaris_E4.5_ubuntu_EN (copy 2).pdf"
160-
161- where "2" is given by the argument "%1"
162- */
163- QString reformattedSuffix = QString(_("copy %1"));
164-
165- QRegExp rx(" \\(" + reformattedSuffix.arg(QString("\\d+")) + "\\)");
166- int reformattedSuffixPos = filenameWithoutSuffix.lastIndexOf(rx);
167-
168- // Check if the file has already a "copy" suffix
169- if(reformattedSuffixPos != -1) {
170- // Remove the "copy" suffix. We will re-put it later.
171- filenameWithoutSuffix.truncate(reformattedSuffixPos);
172- }
173-
174- int append = 1;
175- do {
176- destination = QString("%1 (%2).%3").arg(dir + filenameWithoutSuffix,
177- reformattedSuffix.arg(QString::number(append)),
178- suffix);
179- append++;
180- } while(QFile::exists(destination));
181- }
182-
183- QFile::copy(hubItem.url().toLocalFile(), destination);
184- } else {
185- rejected = true;
186- }
187-
188- // Append an entry for the imported document in the list that will be
189- // emitted with the 'documentImported' signal.
190- QVariantMap entry;
191- if (rejected) {
192- entry["fileName"] = fi.fileName();
193- } else {
194- entry["fileName"] = destination;
195- }
196- entry["rejected"] = rejected;
197-
198- importedDocuments.append(entry);
199- }
200-
201- // Allow content-hub to clean up temporary files in .cache/ once we've
202- // moved them
203- transfer->finalize();
204-
205- emit documentImported(importedDocuments);
206-}
207-
208-/*!
209- * \brief \reimp
210- */
211-void ContentCommunicator::handle_export(content::Transfer *transfer)
212-{
213- if (m_transfer != nullptr) {
214- qWarning() << "docviewer-app does only one content export at a time";
215- transfer->abort();
216- return;
217- }
218-
219- m_transfer = transfer;
220- emit documentRequested();
221- emit selectionTypeChanged();
222- emit singleContentPickModeChanged();
223-}
224-
225-/*!
226- * \brief \reimp
227- */
228-void ContentCommunicator::handle_share(content::Transfer *)
229-{
230- qDebug() << Q_FUNC_INFO << "docviewer does not share content";
231-}
232-
233-/*!
234- * \brief ContentCommunicator::cancelTransfer aborts the current transfer
235- */
236-void ContentCommunicator::cancelTransfer()
237-{
238- if (!m_transfer) {
239- qWarning() << "No ongoing transfer to cancel";
240- return;
241- }
242-
243- m_transfer->abort();
244- m_transfer = nullptr;
245-}
246-
247-/*!
248- * \brief ContentCommunicator::returnSocuments returns the given documents
249- * via content hub to the requester
250- * \param urls
251- */
252-void ContentCommunicator::returnDocuments(const QVector<QUrl> &urls)
253-{
254- if (!m_transfer) {
255- qWarning() << "No ongoing transfer to return a document";
256- return;
257- }
258-
259- QVector<Item> items;
260- items.reserve(urls.size());
261- foreach (const QUrl &url, urls) {
262- items.append(Item(url));
263- }
264-
265- m_transfer->charge(items);
266- m_transfer = nullptr;
267-}
268-
269-/*!
270- * \brief ContentCommunicator::selectionType return if the transfer requests
271- * one single item only, or multiple
272- * \return
273- */
274-ContentCommunicator::SelectionType ContentCommunicator::selectionType() const
275-{
276- if (!m_transfer)
277- return SingleSelect;
278-
279- return static_cast<SelectionType>(m_transfer->selectionType());
280-}
281-
282-/*!
283- * \brief ContentCommunicator::singleContentPickMode
284- * \return
285- */
286-bool ContentCommunicator::singleContentPickMode() const
287-{
288- if (!m_transfer)
289- return true;
290-
291- // FIXME: Shouldn't be Transfer::SelectionType::SingleSelect?
292- return m_transfer->selectionType() == Transfer::SelectionType::single;
293-}
294-
295-/*!
296- * \brief ContentCommunicator::isSupportedMimetype returns true if the given
297- * mimetype is supported by Ubuntu Document Viewer
298- * \param mimetype
299- */
300-bool ContentCommunicator::isSupportedMimetype(QString mimetype)
301-{
302- // TODO: We should use a common shared code for DocumentViewer.DocumentsModel
303- // QML component and ContentHub. That will happen when we'll switch to
304- // QML ContentHub APIs.
305- return (mimetype.startsWith("text/")
306- || mimetype == "application/pdf"
307- || mimetype.startsWith("application/vnd.oasis.opendocument")
308- || mimetype == "application/msword")
309- || mimetype == "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
310- || mimetype == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
311- || mimetype == "application/vnd.openxmlformats-officedocument.presentationml.presentation"
312- || mimetype == "application/msword"
313- || mimetype == "application/vnd.ms-excel"
314- || mimetype == "application/vnd.ms-powerpoint";
315-}
316
317=== removed file 'src/app/content-communicator.h'
318--- src/app/content-communicator.h 2015-04-20 16:24:06 +0000
319+++ src/app/content-communicator.h 1970-01-01 00:00:00 +0000
320@@ -1,74 +0,0 @@
321-/*
322- * Copyright (C) 2013 Canonical, Ltd.
323- *
324- * This program is free software; you can redistribute it and/or modify
325- * it under the terms of the GNU General Public License as published by
326- * the Free Software Foundation; version 3.
327- *
328- * This program is distributed in the hope that it will be useful,
329- * but WITHOUT ANY WARRANTY; without even the implied warranty of
330- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
331- * GNU General Public License for more details.
332- *
333- * You should have received a copy of the GNU General Public License
334- * along with this program. If not, see <http://www.gnu.org/licenses/>.
335- *
336- */
337-
338-#ifndef CONTENTCOMMUNICATOR_H
339-#define CONTENTCOMMUNICATOR_H
340-
341-#include <com/ubuntu/content/import_export_handler.h>
342-#include <com/ubuntu/content/transfer.h>
343-
344-#include <QUrl>
345-#include <QVector>
346-#include <libintl.h>
347-
348-#define _(value) dgettext(GETTEXT_PACKAGE, value)
349-
350-using namespace com::ubuntu;
351-
352-/*!
353- * Class to handle the communication with the content manager
354- */
355-class ContentCommunicator : public content::ImportExportHandler
356-{
357- Q_OBJECT
358- Q_PROPERTY(bool singleContentPickMode READ singleContentPickMode NOTIFY singleContentPickModeChanged)
359- Q_PROPERTY(SelectionType selectionType READ selectionType NOTIFY selectionTypeChanged)
360- Q_ENUMS(SelectionType)
361-
362-public:
363- enum SelectionType {
364- SingleSelect = content::Transfer::single,
365- MultiSelect = content::Transfer::multiple
366- };
367-
368- ContentCommunicator(QObject *parent = nullptr);
369-
370- virtual void handle_import(content::Transfer*);
371- virtual void handle_export(content::Transfer *transfer);
372- virtual void handle_share(content::Transfer*);
373-
374- void cancelTransfer();
375- void returnDocuments(const QVector<QUrl> &urls);
376-
377- SelectionType selectionType() const;
378- bool singleContentPickMode() const;
379-
380- void registerWithHub();
381-
382-signals:
383- void documentRequested();
384- void documentImported(QVariantList documents);
385- void selectionTypeChanged();
386- void singleContentPickModeChanged();
387-
388-private:
389- content::Transfer *m_transfer;
390-
391- bool isSupportedMimetype(QString mimetype);
392-};
393-
394-#endif // CONTENTCOMMUNICATOR_H
395
396=== modified file 'src/app/docviewer-application.cpp'
397--- src/app/docviewer-application.cpp 2015-04-29 15:23:32 +0000
398+++ src/app/docviewer-application.cpp 2015-09-19 17:52:01 +0000
399@@ -18,7 +18,6 @@
400 */
401
402 #include "docviewer-application.h"
403-#include "content-communicator.h"
404 #include "command-line-parser.h"
405 #include "urlhandler.h"
406
407@@ -38,9 +37,6 @@
408 DocViewerApplication::DocViewerApplication(int& argc, char** argv)
409 : QApplication(argc, argv),
410 m_view(new QQuickView()),
411- m_contentCommunicator(new ContentCommunicator(this)),
412- m_pickModeEnabled(false),
413- m_defaultUiMode(BrowseContentMode),
414 m_documentFile(""),
415 m_documentLoaded(false)
416 {
417@@ -73,15 +69,10 @@
418
419 registerQML();
420
421- if (m_cmdLineParser->pickModeEnabled())
422+ // FIXME: Broken after removal of it.
423+ /*if (m_cmdLineParser->pickModeEnabled())
424 setDefaultUiMode(DocViewerApplication::PickContentMode);
425-
426- QObject::connect(m_contentCommunicator, SIGNAL(documentRequested()),
427- this, SLOT(switchToPickMode()));
428-
429- QObject::connect(m_contentCommunicator, SIGNAL(documentImported()),
430- this, SLOT(switchToBrowseMode()));
431-
432+*/
433 return true;
434 }
435
436@@ -172,7 +163,6 @@
437
438 // Set ourselves up to expose functionality to run external commands from QML...
439 m_view->engine()->rootContext()->setContextProperty("DOC_VIEWER", this);
440- m_view->engine()->rootContext()->setContextProperty("PICKER_HUB", m_contentCommunicator);
441
442 QObject::connect(m_view->engine(), SIGNAL(quit()), this, SLOT(quit()));
443
444@@ -201,7 +191,6 @@
445 qFatal("File: %s does not exist at any of the standard paths!", qPrintable(filePath));
446 }
447
448- registerHub();
449 m_view->setSource(QUrl::fromLocalFile(qmlfile));
450 setDocumentFile(m_cmdLineParser->documentFile());
451
452@@ -217,57 +206,6 @@
453 }
454
455 /*!
456- * \brief DocViewerApplication::setDefaultUiMode set the default UI mode. This might
457- * get overridden during the lifetime
458- * \param mode
459- */
460-void DocViewerApplication::setDefaultUiMode(DocViewerApplication::UiMode mode)
461-{
462- m_defaultUiMode = mode;
463- setUiMode(mode);
464-}
465-
466-/*!
467- * \brief DocViewerApplication::setUiMode set's the current UI mode
468- * \param mode
469- */
470-void DocViewerApplication::setUiMode(DocViewerApplication::UiMode mode)
471-{
472- bool enablePickMode = (mode == PickContentMode);
473-
474- if (enablePickMode != m_pickModeEnabled) {
475- m_pickModeEnabled = enablePickMode;
476- Q_EMIT pickModeEnabledChanged();
477- }
478-}
479-
480-/*!
481- * \brief DocViewerApplication::pickModeEnabled returns true if the current UI
482- * mode should be for picking acontent
483- * \return
484- */
485-bool DocViewerApplication::pickModeEnabled() const
486-{
487- return m_pickModeEnabled;
488-}
489-
490-/*!
491- * \brief DocViewerApplication::switchToPickMode
492- */
493-void DocViewerApplication::switchToPickMode()
494-{
495- setUiMode(PickContentMode);
496-}
497-
498-/*!
499- * \brief DocViewerApplication::switchToBrowseMode
500- */
501-void DocViewerApplication::switchToBrowseMode()
502-{
503- Q_EMIT browseModeRequested();
504-}
505-
506-/*!
507 * \brief DocViewerApplication::setFullScreen
508 * Change window state to fullScreen or no state
509 */
510@@ -292,50 +230,6 @@
511 }
512 }
513
514-/*!
515- * \brief DocViewerApplication::returnPickedContent passes the selcted items to the
516- * content manager
517- * \param variant
518- */
519-void DocViewerApplication::returnPickedContent(QList<QString> paths)
520-{
521- QVector<QUrl> selectedMedias;
522- selectedMedias.reserve(paths.size());
523- foreach (const QString path, paths) {
524- // We handle paths without "file://" prefix, so we need to add it when exporting to content-hub.
525- selectedMedias.append(QUrl("file://" + path));
526- }
527- m_contentCommunicator->returnDocuments(selectedMedias);
528-
529- if (m_defaultUiMode == BrowseContentMode) {
530- setUiMode(BrowseContentMode);
531- } else {
532- // give the app and content-hub some time to finish taks (run the event loop)
533- QTimer::singleShot(10, this, SLOT(quit()));
534- }
535-}
536-
537-/*!
538- * \brief DocViewerApplication::contentPickingCanceled tell the content manager, that
539- * the picking was canceled
540- */
541-void DocViewerApplication::contentPickingCanceled()
542-{
543- m_contentCommunicator->cancelTransfer();
544-
545- if (m_defaultUiMode == BrowseContentMode) {
546- setUiMode(BrowseContentMode);
547- } else {
548- // give the app and content-hub some time to finish taks (run the event loop)
549- QTimer::singleShot(10, this, SLOT(quit()));
550- }
551-}
552-
553-void DocViewerApplication::registerHub()
554-{
555- m_contentCommunicator->registerWithHub();
556-}
557-
558 void DocViewerApplication::parseUri(const QString &arg)
559 {
560 if (m_urlHandler->processUri(arg)) {
561
562=== modified file 'src/app/docviewer-application.h'
563--- src/app/docviewer-application.h 2015-04-29 15:23:32 +0000
564+++ src/app/docviewer-application.h 2015-09-19 17:52:01 +0000
565@@ -37,62 +37,42 @@
566 class DocViewerApplication : public QApplication
567 {
568 Q_OBJECT
569- Q_PROPERTY(bool pickModeEnabled READ pickModeEnabled NOTIFY pickModeEnabledChanged)
570 Q_PROPERTY(bool desktopMode READ isDesktopMode CONSTANT)
571 Q_PROPERTY(bool fullScreen READ isFullScreen WRITE setFullScreen NOTIFY fullScreenChanged)
572 Q_PROPERTY(QString documentFile READ getDocumentFile WRITE setDocumentFile NOTIFY documentFileChanged)
573 Q_PROPERTY(QString documentsDir READ getDocumentsDir CONSTANT)
574
575 public:
576- enum UiMode{
577- BrowseContentMode,
578- PickContentMode
579- };
580-
581 explicit DocViewerApplication(int& argc, char** argv);
582 virtual ~DocViewerApplication();
583
584 bool init();
585 int exec();
586
587- void setDefaultUiMode(UiMode mode);
588- UiMode defaultUiMode() const;
589- void setUiMode(UiMode mode);
590- bool pickModeEnabled() const;
591 bool isDesktopMode() const;
592 bool isFullScreen() const;
593 const QString &getDocumentFile() const;
594 const QString &getDocumentsDir() const;
595
596- Q_INVOKABLE void returnPickedContent(QList<QString> paths);
597- Q_INVOKABLE void contentPickingCanceled();
598 Q_INVOKABLE void parseUri(const QString &arg);
599 Q_INVOKABLE void releaseResources();
600
601 signals:
602- void pickModeEnabledChanged();
603 void fullScreenChanged();
604 void documentFileChanged();
605- void browseModeRequested();
606
607 private slots:
608- void switchToPickMode();
609- void switchToBrowseMode();
610 void setFullScreen(bool fullScreen);
611 void setDocumentFile(const QString &documentFile);
612
613 private:
614- void registerHub();
615 void registerQML();
616 void createView();
617
618 QQuickView *m_view;
619 CommandLineParser* m_cmdLineParser;
620 UrlHandler *m_urlHandler;
621- ContentCommunicator *m_contentCommunicator;
622
623- bool m_pickModeEnabled;
624- UiMode m_defaultUiMode;
625 QString m_documentFile;
626 bool m_documentLoaded;
627 };
628
629=== added file 'src/app/qml/common/ContentHubProxy.qml'
630--- src/app/qml/common/ContentHubProxy.qml 1970-01-01 00:00:00 +0000
631+++ src/app/qml/common/ContentHubProxy.qml 2015-09-19 17:52:01 +0000
632@@ -0,0 +1,139 @@
633+/*
634+ * Copyright (C) 2012-2014 Canonical, Ltd.
635+ *
636+ * This program is free software; you can redistribute it and/or modify
637+ * it under the terms of the GNU General Public License as published by
638+ * the Free Software Foundation; version 3.
639+ *
640+ * This program is distributed in the hope that it will be useful,
641+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
642+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
643+ * GNU General Public License for more details.
644+ *
645+ * You should have received a copy of the GNU General Public License
646+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
647+ */
648+
649+import QtQuick 2.3
650+import Ubuntu.Content 1.1
651+import DocumentViewer 1.0
652+
653+// TODO: Show a dialog asking for the destination (internal storage or SD card)
654+
655+Item {
656+ id: contentHubProxy
657+
658+ property var activeTransfer
659+
660+ // This property is used in ../documentPage/Document(Grid|List)View.qml
661+ // so that we avoid to import Ubuntu.Content module outside this proxy.
662+ property bool multipleSelectionType: !activeTransfer || activeTransfer.selectionType == ContentTransfer.Multiple
663+
664+ property alias rejectedDocuments: rejectedDocsModel
665+ property alias importedDocuments: importedDocsModel
666+
667+ ListModel { id: rejectedDocsModel }
668+ ListModel { id: importedDocsModel }
669+
670+ ContentTransferHint {
671+ activeTransfer: contentHubProxy.activeTransfer
672+ }
673+
674+ Connections {
675+ target: ContentHub
676+
677+ onImportRequested: {
678+ activeTransfer = transfer
679+
680+ if (activeTransfer.state === ContentTransfer.Charged) {
681+ mainView.switchToBrowseMode()
682+
683+ internal.clearModels()
684+
685+ for (var i=0; i<activeTransfer.items.length; i++) {
686+ var sourcePath = internal.getPathFromUrl(activeTransfer.items[i].url)
687+
688+ if (DocumentViewer.isFileSupported(sourcePath)) {
689+ var documentsLocation = DocumentViewer.getXdgDocumentsLocation()
690+ var destPath = DocumentViewer.buildDestinationPath(documentsLocation, sourcePath)
691+
692+ internal.importDocument(sourcePath, destPath)
693+
694+ } else {
695+ // Document is not supported, append its entry into the
696+ // rejected documents model, so that we can inform the
697+ // user of what happened.
698+ rejectedDocsModel.append({ path: sourcePath })
699+ }
700+ }
701+
702+ internal.finalizeImport()
703+
704+ internal.handleNotifications()
705+ }
706+ }
707+
708+ onExportRequested: {
709+ activeTransfer = transfer
710+ mainView.switchToPickMode()
711+ }
712+ }
713+
714+ QtObject {
715+ id: internal
716+
717+ function __openDocument() {
718+ if (contentHubProxy.importedDocuments.count > 1) {
719+ // If it has been imported more than a document, show
720+ // a file picker when user taps the "open" action.
721+ PopupUtils.open(
722+ Qt.resolvedUrl("common/PickImportedDialog.qml"),
723+ mainView,
724+ {
725+ parent: mainView,
726+ model: contentHubProxy.importedDocuments
727+ })
728+ } else {
729+ // It has been imported just a document, open it when
730+ // user taps the action button.
731+ mainView.openDocument(contentHubProxy.importedDocuments.get(0).path)
732+ }
733+ }
734+
735+ function clearModels() {
736+ rejectedDocsModel.clear()
737+ importedDocsModel.clear()
738+ }
739+
740+ function getPathFromUrl(url) {
741+ return url.toString().replace("file://", "")
742+ }
743+
744+ function importDocument(sourcePath, destPath) {
745+ DocumentViewer.copy(sourcePath, destPath)
746+ importedDocsModel.append({ path: destPath })
747+ }
748+
749+ function finalizeImport() {
750+ activeTransfer.finalize()
751+ }
752+
753+ function handleNotifications() {
754+ // Check if there's any rejected document in the last transfer.
755+ // If so, show an error dialog.
756+ if (contentHubProxy.rejectedDocuments.count > 0) {
757+ var rejectedDialog = PopupUtils.open(
758+ Qt.resolvedUrl("common/RejectedImportDialog.qml"),
759+ mainView,
760+ {
761+ parent: mainView,
762+ model: contentHubProxy.rejectedDocuments
763+ })
764+ rejectedDialog.closed.connect(openDocument)
765+ } else {
766+ // Open the document, or show a pick dialog if more than one have been imported.
767+ __openDocument()
768+ }
769+ }
770+ }
771+}
772
773=== modified file 'src/app/qml/common/PickImportedDialog.qml'
774--- src/app/qml/common/PickImportedDialog.qml 2015-04-10 17:00:59 +0000
775+++ src/app/qml/common/PickImportedDialog.qml 2015-09-19 17:52:01 +0000
776@@ -32,13 +32,13 @@
777 // We don't use a Flickable, since it already lives in the Dialog itself.
778 Repeater {
779 id: repeater
780- delegate: ListItem.Standard {
781- text: Utils.getNameOfFile(modelData)
782+ ListItem.Standard {
783+ text: Utils.getNameOfFile(model.path)
784 __foregroundColor: Theme.palette.selected.backgroundText
785
786 onClicked: {
787 PopupUtils.close(multipleImportDialog);
788- mainView.openDocument(modelData);
789+ mainView.openDocument(model.path);
790 }
791 }
792 }
793
794=== modified file 'src/app/qml/common/RejectedImportDialog.qml'
795--- src/app/qml/common/RejectedImportDialog.qml 2015-04-12 15:34:47 +0000
796+++ src/app/qml/common/RejectedImportDialog.qml 2015-09-19 17:52:01 +0000
797@@ -25,13 +25,13 @@
798
799 signal closed
800
801- title: i18n.tr("File not supported", "Files not supported", model.length)
802+ title: i18n.tr("File not supported", "Files not supported", repeater.count)
803 text: i18n.tr("Following document has not been imported:",
804- "Following documents have not been imported:", model.length)
805+ "Following documents have not been imported:", repeater.count)
806
807 Repeater {
808 id: repeater
809- delegate: Label { text: modelData }
810+ Label { text: model.path }
811 }
812
813 Button {
814
815=== removed file 'src/app/qml/common/Toast.qml'
816--- src/app/qml/common/Toast.qml 2015-04-07 22:03:03 +0000
817+++ src/app/qml/common/Toast.qml 1970-01-01 00:00:00 +0000
818@@ -1,82 +0,0 @@
819-/*
820- This file is part of quick-memo
821- Copyright (C) 2014, 2015 Stefano Verzegnassi
822-
823- This program is free software: you can redistribute it and/or modify
824- it under the terms of the GNU General Public License 3 as published by
825- the Free Software Foundation.
826-
827- This program is distributed in the hope that it will be useful,
828- but WITHOUT ANY WARRANTY; without even the implied warranty of
829- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
830- GNU General Public License for more details.
831-
832- You should have received a copy of the GNU General Public License
833- along with this program. If not, see http://www.gnu.org/licenses/.
834-*/
835-
836-import QtQuick 2.0
837-import Ubuntu.Components 1.1
838-
839-Rectangle {
840- id: rootItem
841-
842- property alias text: label.text
843-
844- width: parent.width
845- height: units.gu(8)
846-
847- color: "#131313"
848- opacity: 0.85
849- layer.enabled: true
850-
851- anchors {
852- horizontalCenter: parent.horizontalCenter
853- bottom: parent.bottom; bottomMargin: - height
854- }
855-
856- Label {
857- id: label
858- anchors.centerIn: parent
859-
860- font.weight: Font.DemiBold
861- color: "white"
862- }
863-
864- MouseArea {
865- anchors.fill: parent
866-
867- onClicked: {
868- showAnimation.stop()
869- destroyAnimation.restart()
870- }
871- }
872-
873- Rectangle {
874- anchors {
875- bottom: parent.bottom
876- left: parent.left
877- right: parent.right
878- }
879-
880- height: units.dp(2)
881- color: UbuntuColors.orange
882- }
883-
884- SequentialAnimation {
885- id: showAnimation
886- running: true
887-
888- NumberAnimation { target: rootItem; property: "anchors.bottomMargin"; to: 0; duration: 300 }
889- PauseAnimation { duration: 2000 }
890- ScriptAction { script: destroyAnimation.restart() }
891- }
892-
893- SequentialAnimation {
894- id: destroyAnimation
895-
896- NumberAnimation { target: rootItem; property: "opacity"; to: 0; duration: 500 }
897- ScriptAction { script: rootItem.destroy() }
898- }
899-}
900-
901
902=== removed file 'src/app/qml/common/ToastWithAction.qml'
903--- src/app/qml/common/ToastWithAction.qml 2015-07-14 15:43:11 +0000
904+++ src/app/qml/common/ToastWithAction.qml 1970-01-01 00:00:00 +0000
905@@ -1,117 +0,0 @@
906-/*
907- Copyright (C) 2014, 2015 Stefano Verzegnassi
908-
909- This program is free software: you can redistribute it and/or modify
910- it under the terms of the GNU General Public License 3 as published by
911- the Free Software Foundation.
912-
913- This program is distributed in the hope that it will be useful,
914- but WITHOUT ANY WARRANTY; without even the implied warranty of
915- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
916- GNU General Public License for more details.
917-
918- You should have received a copy of the GNU General Public License
919- along with this program. If not, see http://www.gnu.org/licenses/.
920-*/
921-
922-import QtQuick 2.0
923-import Ubuntu.Components 1.1
924-import QtQuick.Layouts 1.1
925-
926-Rectangle {
927- id: rootItem
928-
929- property alias text: label.text
930- readonly property alias action: action
931-
932- width: parent.width
933- height: units.gu(8)
934-
935- color: "#131313"
936- opacity: 0.85
937- layer.enabled: true
938-
939- anchors {
940- horizontalCenter: parent.horizontalCenter
941- bottom: parent.bottom; bottomMargin: - height
942- }
943-
944- MouseArea {
945- anchors.fill: parent
946-
947- onClicked: {
948- showAnimation.stop()
949- destroyAnimation.restart()
950- }
951- }
952-
953- RowLayout {
954- anchors {
955- fill: parent
956- margins: units.gu(2)
957- }
958-
959- Label {
960- id: label
961- Layout.fillWidth: true
962-
963- font.weight: Font.DemiBold
964- color: "white"
965- }
966-
967- AbstractButton {
968- Layout.preferredWidth: actionLabel.paintedWidth
969- Layout.fillHeight: true
970-
971- onClicked: {
972- action.triggered("[Toast] Action %1 clicked!".arg(action.text))
973- }
974-
975- Label {
976- id: actionLabel
977- text: action.text
978-
979- font.capitalization: Font.AllUppercase
980- font.weight: Font.DemiBold
981- color: UbuntuColors.orange
982-
983- anchors.centerIn: parent
984- }
985- }
986- }
987-
988- Rectangle {
989- anchors {
990- bottom: parent.bottom
991- left: parent.left
992- right: parent.right
993- }
994-
995- height: units.dp(2)
996- color: UbuntuColors.orange
997- }
998-
999- Action {
1000- id: action
1001-
1002- text: i18n.tr("Dismiss")
1003- onTriggered: destroyAnimation.restart()
1004- }
1005-
1006- SequentialAnimation {
1007- id: showAnimation
1008- running: true
1009-
1010- NumberAnimation { target: rootItem; property: "anchors.bottomMargin"; to: 0; duration: 300 }
1011- PauseAnimation { duration: 2000 }
1012- ScriptAction { script: destroyAnimation.restart() }
1013- }
1014-
1015- SequentialAnimation {
1016- id: destroyAnimation
1017-
1018- NumberAnimation { target: rootItem; property: "opacity"; to: 0; duration: 500 }
1019- ScriptAction { script: rootItem.destroy() }
1020- }
1021-}
1022-
1023
1024=== modified file 'src/app/qml/documentPage/DocumentGridView.qml'
1025--- src/app/qml/documentPage/DocumentGridView.qml 2015-06-22 17:04:27 +0000
1026+++ src/app/qml/documentPage/DocumentGridView.qml 2015-09-19 17:52:01 +0000
1027@@ -37,6 +37,16 @@
1028 cellWidth: (mainView.width > units.gu(50)) ? units.gu(24)
1029 : (mainView.width - units.gu(2)) * 0.5
1030
1031+ // We allow multiple selection both in selection and pick mode.
1032+ multipleSelection: {
1033+ // No active transfer, then we're in selection mode.
1034+ if (!contentHubProxy.activeTransfer)
1035+ return true
1036+
1037+ // We have an active transfer, get the value from the content hub proxy
1038+ return contentHubProxy.multipleSelectionType
1039+ }
1040+
1041 listDelegate: DocumentGridDelegate {
1042 id: delegate
1043 width: cellWidth
1044@@ -80,5 +90,5 @@
1045 }
1046 }
1047
1048- Component.onCompleted: { if (DOC_VIEWER.pickModeEnabled) documentGridView.startSelection(); }
1049+ Component.onCompleted: { if (mainView.pickMode) documentGridView.startSelection(); }
1050 }
1051
1052=== modified file 'src/app/qml/documentPage/DocumentListView.qml'
1053--- src/app/qml/documentPage/DocumentListView.qml 2015-06-22 17:04:27 +0000
1054+++ src/app/qml/documentPage/DocumentListView.qml 2015-09-19 17:52:01 +0000
1055@@ -48,6 +48,16 @@
1056 }
1057 }
1058
1059+ // We allow multiple selection both in selection and pick mode.
1060+ multipleSelection: {
1061+ // No active transfer, then we're in selection mode.
1062+ if (!contentHubProxy.activeTransfer)
1063+ return true
1064+
1065+ // We have an active transfer, get the value from the content hub proxy
1066+ return contentHubProxy.multipleSelectionType
1067+ }
1068+
1069 listDelegate: DocumentListDelegate {
1070 id: delegate
1071
1072@@ -185,5 +195,5 @@
1073 }
1074 }
1075
1076- Component.onCompleted: { if (DOC_VIEWER.pickModeEnabled) documentListView.startSelection(); }
1077+ Component.onCompleted: { if (mainView.pickMode) documentListView.startSelection(); }
1078 }
1079
1080=== modified file 'src/app/qml/documentPage/DocumentPage.qml'
1081--- src/app/qml/documentPage/DocumentPage.qml 2015-06-22 16:39:07 +0000
1082+++ src/app/qml/documentPage/DocumentPage.qml 2015-09-19 17:52:01 +0000
1083@@ -77,10 +77,10 @@
1084 ]
1085
1086 Connections {
1087- target: DOC_VIEWER
1088+ target: mainView
1089
1090- onPickModeEnabledChanged: {
1091- if (DOC_VIEWER.pickModeEnabled) {
1092+ onPickModeChanged: {
1093+ if (mainView.pickMode) {
1094 viewLoader.item.startSelection()
1095 } else {
1096 viewLoader.item.cancelSelection()
1097
1098=== modified file 'src/app/qml/documentPage/DocumentPagePickModeHeader.qml'
1099--- src/app/qml/documentPage/DocumentPagePickModeHeader.qml 2015-03-03 15:41:11 +0000
1100+++ src/app/qml/documentPage/DocumentPagePickModeHeader.qml 2015-09-19 17:52:01 +0000
1101@@ -16,6 +16,7 @@
1102
1103 import QtQuick 2.3
1104 import Ubuntu.Components 1.1
1105+import Ubuntu.Content 1.1
1106
1107 PageHeadState {
1108 id: rootItem
1109@@ -27,7 +28,12 @@
1110 text: i18n.tr("Cancel")
1111 objectName: "cancelButton"
1112 iconName: "close"
1113- onTriggered: DOC_VIEWER.contentPickingCanceled()
1114+ onTriggered: {
1115+ if (!contentHubProxy.activeTransfer)
1116+ return;
1117+
1118+ contentHubProxy.activeTransfer.state = ContentTransfer.Aborted;
1119+ }
1120 }
1121
1122 actions: [
1123@@ -45,17 +51,18 @@
1124 enabled: viewLoader.item.selectedItems.count > 0
1125 iconName: "ok"
1126 onTriggered: {
1127- if (!enabled)
1128+ if (!enabled || !contentHubProxy.activeTransfer)
1129 return;
1130
1131 var urlList = []
1132 var items = documentPage.view.item.selectedItems;
1133
1134 for (var i=0; i < items.count; i++) {
1135- urlList.push(items.get(i).model.path);
1136+ urlList.push("file://" + items.get(i).model.path);
1137 }
1138
1139- DOC_VIEWER.returnPickedContent(urlList);
1140+ contentHubProxy.activeTransfer.items = urlList
1141+ contentHubProxy.activeTransfer.state = ContentTransfer.Charged
1142 }
1143 }
1144 ]
1145
1146=== modified file 'src/app/qml/ubuntu-docviewer-app.qml'
1147--- src/app/qml/ubuntu-docviewer-app.qml 2015-06-22 16:45:36 +0000
1148+++ src/app/qml/ubuntu-docviewer-app.qml 2015-09-19 17:52:01 +0000
1149@@ -28,7 +28,8 @@
1150 id: mainView
1151 objectName: "mainView"
1152
1153- property bool pickMode: DOC_VIEWER.pickModeEnabled
1154+ // TODO: Connect with arguments
1155+ property bool pickMode: false
1156 readonly property bool isLandscape: Screen.orientation == Qt.LandscapeOrientation ||
1157 Screen.orientation == Qt.InvertedLandscapeOrientation
1158
1159@@ -66,26 +67,12 @@
1160 mainView, { parent: mainView });
1161 }
1162
1163- function showNotification(args) {
1164- var component = Qt.createComponent("common/Toast.qml")
1165- var toast = component.createObject(mainView, args);
1166-
1167- return toast;
1168- }
1169-
1170- function showNotificationWithAction(args) {
1171- var component = Qt.createComponent("common/ToastWithAction.qml")
1172- var toast = component.createObject(mainView, args);
1173-
1174- return toast;
1175- }
1176-
1177 function setFullScreen(fullScreen) {
1178 DOC_VIEWER.fullScreen = fullScreen;
1179 }
1180
1181 function toggleFullScreen() {
1182- DOC_VIEWER.fullScreen = !APP.fullScreen;
1183+ DOC_VIEWER.fullScreen = !DOC_VIEWER.fullScreen;
1184 }
1185
1186 function setHeaderVisibility(visible, toggleFullscreen) {
1187@@ -108,6 +95,19 @@
1188 setHeaderVisibility(!header.visible);
1189 }
1190
1191+ function setPickMode(pickMode) {
1192+ mainView.pickMode = pickMode
1193+ }
1194+
1195+ function switchToBrowseMode() {
1196+ setPickMode(false)
1197+ }
1198+
1199+ function switchToPickMode() {
1200+ setPickMode(true)
1201+ }
1202+
1203+
1204 // On screen rotation, force updating of header/U8 indicators panel visibility
1205 onIsLandscapeChanged: setHeaderVisibility(true);
1206
1207@@ -183,6 +183,16 @@
1208 property bool reverseOrder: false
1209 }
1210
1211+ // Content Hub support
1212+ property alias contentHubProxy: contentHubLoader.item
1213+ Loader {
1214+ id: contentHubLoader
1215+
1216+ asynchronous: true
1217+ source: Qt.resolvedUrl("common/ContentHubProxy.qml")
1218+ }
1219+
1220+ // Uri Handler support
1221 Connections {
1222 target: UriHandler
1223 onOpened: {
1224@@ -198,91 +208,13 @@
1225 onDocumentFileChanged: {
1226 openDocument(DOC_VIEWER.documentFile);
1227 }
1228-
1229- onPickModeEnabledChanged: {
1230- mainView.pickMode = DOC_VIEWER.pickModeEnabled
1231-
1232- if (mainView.pickMode) {
1233- // If a document is loaded, pop() its page.
1234- while (pageStack.depth > 1) {
1235- pageStack.pop()
1236- }
1237- }
1238- }
1239 }
1240
1241- Connections {
1242- target: PICKER_HUB
1243-
1244- onDocumentImported: {
1245- // Create two arrays: one for rejected documents, and the other
1246- // for imported documents.
1247- var importedDocuments = [];
1248- var rejectedDocuments = [];
1249- var entry;
1250-
1251- // Fill the arrays.
1252- for (var i=0; i<documents.length; i++) {
1253- entry = documents[i];
1254-
1255- if (entry.rejected) {
1256- rejectedDocuments.push(entry.fileName);
1257- break;
1258- }
1259-
1260- importedDocuments.push(entry.fileName);
1261- }
1262-
1263- // Prepare import notification
1264- var showImportNotification = function() {
1265- if (importedDocuments.length > 0) {
1266- var importDialog = showNotificationWithAction({
1267- "text": i18n.tr("Document successfully imported!",
1268- "Documents successfully imported!",
1269- importedDocuments.length),
1270- "action.text": i18n.tr("Open")
1271- })
1272-
1273- if (importedDocuments.length > 1) {
1274- // If it has been imported more than a document, show
1275- // a file picker when user taps the "open" action.
1276- importDialog.action.triggered.connect(function() {
1277- PopupUtils.open(
1278- Qt.resolvedUrl("common/PickImportedDialog.qml"),
1279- mainView,
1280- {
1281- parent: mainView,
1282- model: importedDocuments
1283- }
1284- );
1285- });
1286- } else {
1287- // It has been imported just a document, open it when
1288- // user taps the action button.
1289- importDialog.action.triggered.connect(function() {
1290- openDocument(importedDocuments[0]);
1291- });
1292- }
1293- }
1294- }
1295-
1296- // Check if there's any rejected document in the last transfer.
1297- // If so, show an error dialog.
1298- if (rejectedDocuments.length > 0) {
1299- var rejectedDialog = PopupUtils.open(
1300- Qt.resolvedUrl("common/RejectedImportDialog.qml"),
1301- mainView,
1302- {
1303- parent: mainView,
1304- model: rejectedDocuments
1305- }
1306- );
1307-
1308- // Show import notification after the dialog has been closed.
1309- rejectedDialog.closed.connect(showImportNotification)
1310- } else {
1311- // No dialog has been shown. Show the notification.
1312- showImportNotification.call();
1313+ onPickModeChanged: {
1314+ if (mainView.pickMode) {
1315+ // If a document is loaded, pop() its page.
1316+ while (pageStack.depth > 1) {
1317+ pageStack.pop()
1318 }
1319 }
1320 }
1321
1322=== modified file 'src/plugin/file-qml-plugin/CMakeLists.txt'
1323--- src/plugin/file-qml-plugin/CMakeLists.txt 2015-09-09 17:25:56 +0000
1324+++ src/plugin/file-qml-plugin/CMakeLists.txt 2015-09-19 17:52:01 +0000
1325@@ -7,6 +7,7 @@
1326 documentmodel.cpp
1327 fswatcher.cpp
1328 docviewerfile.cpp
1329+ docviewerutils.cpp
1330 )
1331
1332 add_library(fileqmlplugin MODULE
1333
1334=== modified file 'src/plugin/file-qml-plugin/backend.cpp'
1335--- src/plugin/file-qml-plugin/backend.cpp 2015-04-29 15:23:32 +0000
1336+++ src/plugin/file-qml-plugin/backend.cpp 2015-09-19 17:52:01 +0000
1337@@ -21,6 +21,16 @@
1338 #include "backend.h"
1339 #include "documentmodel.h"
1340 #include "docviewerfile.h"
1341+#include "docviewerutils.h"
1342+
1343+static QObject *registerDocviewerUtils (QQmlEngine *engine, QJSEngine *scriptEngine)
1344+{
1345+ Q_UNUSED(engine)
1346+ Q_UNUSED(scriptEngine)
1347+
1348+ DocviewerUtils *ch = new DocviewerUtils();
1349+ return ch;
1350+}
1351
1352 void BackendPlugin::registerTypes(const char *uri)
1353 {
1354@@ -30,6 +40,8 @@
1355
1356 qmlRegisterType<DocumentModel>(uri, 1, 0, "DocumentsModel");
1357 qmlRegisterType<DocviewerFile>(uri, 1, 0, "File");
1358+
1359+ qmlRegisterSingletonType<DocviewerUtils>(uri, 1, 0, "DocumentViewer", registerDocviewerUtils);
1360 }
1361
1362 void BackendPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
1363
1364=== modified file 'src/plugin/file-qml-plugin/documentmodel.cpp'
1365--- src/plugin/file-qml-plugin/documentmodel.cpp 2015-09-09 17:25:56 +0000
1366+++ src/plugin/file-qml-plugin/documentmodel.cpp 2015-09-19 17:52:01 +0000
1367@@ -17,6 +17,7 @@
1368
1369 #include "documentmodel.h"
1370 #include "fswatcher.h"
1371+#include "docviewerutils.h"
1372
1373 #include <QStandardPaths>
1374 #include <QDir>
1375@@ -114,19 +115,7 @@
1376
1377 bool DocumentModel::isFileSupported(const QString &path)
1378 {
1379- QMimeDatabase db;
1380- QString mimetype = db.mimeTypeForFile(path).name();
1381-
1382- return (mimetype.startsWith("text/")
1383- || mimetype == "application/pdf"
1384- || mimetype.startsWith("application/vnd.oasis.opendocument")
1385- || mimetype == "application/msword")
1386- || mimetype == "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
1387- || mimetype == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
1388- || mimetype == "application/vnd.openxmlformats-officedocument.presentationml.presentation"
1389- || mimetype == "application/msword"
1390- || mimetype == "application/vnd.ms-excel"
1391- || mimetype == "application/vnd.ms-powerpoint";
1392+ return DocviewerUtils::isFileSupported(path);
1393 }
1394
1395 QHash<int, QByteArray> DocumentModel::roleNames() const
1396
1397=== added file 'src/plugin/file-qml-plugin/docviewerutils.cpp'
1398--- src/plugin/file-qml-plugin/docviewerutils.cpp 1970-01-01 00:00:00 +0000
1399+++ src/plugin/file-qml-plugin/docviewerutils.cpp 2015-09-19 17:52:01 +0000
1400@@ -0,0 +1,121 @@
1401+/*
1402+ Copyright (C) 2015 Canonical, Ltd.
1403+
1404+ This program is free software: you can redistribute it and/or modify
1405+ it under the terms of the GNU General Public License 3 as published by
1406+ the Free Software Foundation.
1407+
1408+ This program is distributed in the hope that it will be useful,
1409+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1410+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1411+ GNU General Public License for more details.
1412+
1413+ You should have received a copy of the GNU General Public License
1414+ along with this program. If not, see http://www.gnu.org/licenses/.
1415+*/
1416+
1417+#include "docviewerutils.h"
1418+
1419+#include <QFileInfo>
1420+#include <QDir>
1421+#include <QMimeDatabase>
1422+#include <QStandardPaths>
1423+
1424+bool DocviewerUtils::exists(const QString &path)
1425+{
1426+ QFileInfo fi(path);
1427+
1428+ if (fi.isFile())
1429+ return fi.exists();
1430+
1431+ // else
1432+ return QDir(path).exists();
1433+}
1434+
1435+bool DocviewerUtils::copy(const QString &source, const QString &destination)
1436+{
1437+ return QFile::copy(source, destination);
1438+}
1439+
1440+bool DocviewerUtils::isFileSupported(const QString &path)
1441+{
1442+ QMimeDatabase mdb;
1443+ const QString mimetype = mdb.mimeTypeForFile(path).name();
1444+
1445+ return mimetype.startsWith("text/")
1446+ || mimetype == "application/pdf"
1447+ || mimetype.startsWith("application/vnd.oasis.opendocument")
1448+ || mimetype == "application/msword"
1449+ || mimetype == "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
1450+ || mimetype == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
1451+ || mimetype == "application/vnd.openxmlformats-officedocument.presentationml.presentation"
1452+ || mimetype == "application/vnd.ms-excel"
1453+ || mimetype == "application/vnd.ms-powerpoint";
1454+}
1455+
1456+QString DocviewerUtils::getXdgDocumentsLocation()
1457+{
1458+ return QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
1459+}
1460+
1461+QString DocviewerUtils::buildDestinationPath(const QString &destinationDir, const QString &sourcePath)
1462+{
1463+ QFileInfo fi(sourcePath);
1464+
1465+ /*
1466+ We don't support formats that use a double extension
1467+ (e.g. tar.gz), so we can safely use completeBaseName() and
1468+ suffix() functions, in order to properly detect the name of
1469+ the document even when there's a dot in the middle of the name.
1470+ */
1471+ QString suffix = fi.suffix();
1472+ QString filenameWithoutSuffix = fi.completeBaseName();
1473+
1474+ QMimeDatabase mdb;
1475+ QMimeType mt = mdb.mimeTypeForFile(sourcePath);
1476+
1477+ // If the filename doesn't have an extension add one from the
1478+ // detected mimetype
1479+ if (suffix.isEmpty())
1480+ suffix = mt.preferredSuffix();
1481+
1482+ QString dir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + QDir::separator();
1483+ QString destination = QString("%1.%2").arg(dir + filenameWithoutSuffix, suffix);
1484+
1485+ // If there's already a file of this name, reformat it to
1486+ // "filename (copy x).png" where x is a number, incremented until we find an
1487+ // available filename.
1488+ if (QFile::exists(destination)) {
1489+ /*
1490+ TRANSLATORS: This string is used for renaming a copied file,
1491+ when a file with the same name already exists in user's
1492+ Documents folder.
1493+
1494+ e.g. "Manual_Aquaris_E4.5_ubuntu_EN.pdf" will become
1495+ "Manual_Aquaris_E4.5_ubuntu_EN (copy 2).pdf"
1496+
1497+ where "2" is given by the argument "%1"
1498+ */
1499+ QString reformattedSuffix = QString(tr("copy %1"));
1500+
1501+ // Check if the file has already a "copy" suffix
1502+ // If so, remove it since we will update it later.
1503+ QRegExp rx(" \\(" + reformattedSuffix.arg(QString("\\d+")) + "\\)");
1504+ int reformattedSuffixPos = filenameWithoutSuffix.lastIndexOf(rx);
1505+
1506+ if (reformattedSuffixPos != -1)
1507+ filenameWithoutSuffix.truncate(reformattedSuffixPos);
1508+
1509+ // Add the right "copy" suffix.
1510+ int append = 1;
1511+ while (QFile::exists(destination)) {
1512+ destination = QString("%1 (%2).%3").arg(
1513+ dir + filenameWithoutSuffix,
1514+ reformattedSuffix.arg(QString::number(append)),
1515+ suffix);
1516+ append++;
1517+ }
1518+ }
1519+
1520+ return destination;
1521+}
1522
1523=== added file 'src/plugin/file-qml-plugin/docviewerutils.h'
1524--- src/plugin/file-qml-plugin/docviewerutils.h 1970-01-01 00:00:00 +0000
1525+++ src/plugin/file-qml-plugin/docviewerutils.h 2015-09-19 17:52:01 +0000
1526@@ -0,0 +1,37 @@
1527+/*
1528+ Copyright (C) 2015 Canonical, Ltd.
1529+
1530+ This program is free software: you can redistribute it and/or modify
1531+ it under the terms of the GNU General Public License 3 as published by
1532+ the Free Software Foundation.
1533+
1534+ This program is distributed in the hope that it will be useful,
1535+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1536+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1537+ GNU General Public License for more details.
1538+
1539+ You should have received a copy of the GNU General Public License
1540+ along with this program. If not, see http://www.gnu.org/licenses/.
1541+*/
1542+
1543+#ifndef DOCVIEWERUTILS_H
1544+#define DOCVIEWERUTILS_H
1545+
1546+#include <QObject>
1547+#include <QThread>
1548+
1549+class DocviewerUtils : public QObject
1550+{
1551+ Q_OBJECT
1552+
1553+public:
1554+ Q_INVOKABLE static bool exists(const QString &path);
1555+ Q_INVOKABLE static bool copy(const QString &source, const QString &destination);
1556+
1557+ Q_INVOKABLE static bool isFileSupported(const QString &path);
1558+ Q_INVOKABLE static QString getXdgDocumentsLocation();
1559+
1560+ Q_INVOKABLE static QString buildDestinationPath(const QString &destinationDir, const QString &sourcePath);
1561+};
1562+
1563+#endif // DOCVIEWERUTILS_H

Subscribers

People subscribed via source and target branches