Merge lp:~verzegnassi-stefano/ubuntu-docviewer-app/10-reboot-contenthub-switch-to-qml-apis into lp:ubuntu-docviewer-app
- 10-reboot-contenthub-switch-to-qml-apis
- Merge into lo-viewer
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Roman Shchekin | Approve | ||
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Approve | |
Review via email:
|
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 DocviewerApplic
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.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
- 174. By Stefano Verzegnassi
-
Forgotten bits
- 175. By Stefano Verzegnassi
-
Removed dependency on ContentHub C++ APIs and updated the others
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:174
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:175
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 176. By Stefano Verzegnassi
-
Renamed DocumentViewerS
ingleton as DocviewerUtils
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:176
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Roman Shchekin (mrqtros) wrote : | # |
Left few comments in code. Overall feeling - ok.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Stefano Verzegnassi (verzegnassi-stefano) wrote : | # |
> Should be rewritten as:
> property bool multipleSelection: !activeTransfer || activeTransfer.
> But looks strange anyway. Why do we allow multiple selection when transfer isn't acitve?
Good point.
Also, in DocumentGridVie
multipleSel
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.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
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
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:177
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Roman Shchekin (mrqtros) wrote : | # |
Should I top-approve it?
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Stefano Verzegnassi (verzegnassi-stefano) wrote : | # |
Sure! I forgot it.
Preview Diff
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 |
PASSED: Continuous integration, rev:173 91.189. 93.70:8080/ job/ubuntu- docviewer- app-reboot- ci/27/ 91.189. 93.70:8080/ job/ubuntu- docviewer- app-reboot- vivid-amd64- ci/27
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild: 91.189. 93.70:8080/ job/ubuntu- docviewer- app-reboot- ci/27/rebuild
http://