ubuntu-touch-coreapps-reviewers team mailing list archive
-
ubuntu-touch-coreapps-reviewers team
-
Mailing list archive
-
Message #00239
Re: [Merge] lp:~verzegnassi-stefano/ubuntu-docviewer-app/document-hub2 into lp:ubuntu-docviewer-app
Review: Needs Fixing code
I read the first 5000 lines of diff, and I left some comments.
Later I'll finish the diff, and then I'll test the app. Maybe I'll do another code review because it's huge
Diff comments:
> === modified file 'CMakeLists.txt'
> --- CMakeLists.txt 2015-01-29 16:35:28 +0000
> +++ CMakeLists.txt 2015-02-27 15:45:56 +0000
> @@ -23,7 +23,7 @@
>
> set(APP_NAME ubuntu-docviewer-app)
> set(DESKTOP_FILE "${PROJECT_NAME}.desktop")
> -#set(URLS_FILE "${PROJECT_NAME}_${APP_NAME}.url-dispatcher")
> +set(URLS_FILE "${PROJECT_NAME}.url-dispatcher")
> set(LP_PROJECT ubuntu-docviewer-app)
> set(ICON_FILE docviewer@xxxxxx)
> set(AUTOPILOT_DIR ubuntu_docviewer_app)
> @@ -67,7 +67,7 @@
> set(DESKTOP_DIR ${DATA_DIR})
> set(URLS_DIR ${DATA_DIR})
> configure_file(manifest.json.in ${CMAKE_CURRENT_BINARY_DIR}/manifest.json)
> - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/manifest.json docviewer.apparmor docviewer-content.json
> + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/manifest.json docviewer.apparmor docviewer-content.json ${URLS_FILE}
> DESTINATION ${CMAKE_INSTALL_PREFIX})
> # Make the click files visible in Qt Creator
> file(GLOB CLICK_FILES
>
> === modified file 'com.ubuntu.docviewer.desktop.in.in'
> --- com.ubuntu.docviewer.desktop.in.in 2014-09-24 05:06:10 +0000
> +++ com.ubuntu.docviewer.desktop.in.in 2015-02-27 15:45:56 +0000
> @@ -6,6 +6,8 @@
> Icon=@ICON@
> _Name=Document Viewer
> _Keywords=documents;viewer;pdf;reader;
> -MimeType=text/plain;image/png;image/jpeg;image/svg+xml;application/pdf
> +MimeType=text/plain;application/pdf
> X-Ubuntu-Touch=true
> X-Ubuntu-StageHint=SideStage
> +X-Ubuntu-Splash-Show-Header=true
> +_X-Ubuntu-Splash-Title=Document Viewer
>
> === added file 'com.ubuntu.docviewer.url-dispatcher'
> --- com.ubuntu.docviewer.url-dispatcher 1970-01-01 00:00:00 +0000
> +++ com.ubuntu.docviewer.url-dispatcher 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,5 @@
> +[
> + {
> + "protocol": "document"
> + }
> +]
>
> === modified file 'debian/changelog'
> --- debian/changelog 2015-02-04 19:30:22 +0000
> +++ debian/changelog 2015-02-27 15:45:56 +0000
> @@ -1,14 +1,24 @@
> +ubuntu-docviewer-app (0.3.0) utopic; urgency=medium
> +
> + * Improved content-hub support
> + * Added uri handler support
> + * Use the Unity 8 splash screen
> + * In-app browser for files stored in XDG Documents folder
> + * Support for images has been dropped
> +
> + -- Stefano Verzegnassi <verzegnassi.stefano@xxxxxxxxx> Mon, 23 Feb 2015 13:41:47 +0100
> +
> ubuntu-docviewer-app (0.2.1) utopic; urgency=medium
>
> * Added Table of Content in the PDF viewer
>
> - -- Stefano <verzegnassi.stefano@xxxxxxxxx> Wed, 04 Feb 2015 20:26:58 +0100
> + -- Stefano Verzegnassi <verzegnassi.stefano@xxxxxxxxx> Wed, 04 Feb 2015 20:26:58 +0100
>
> ubuntu-docviewer-app (0.2.0) utopic; urgency=medium
>
> * Enabled zoom in the PDF viewer
>
> - -- Stefano <verzegnassi.stefano@xxxxxxxxx> Wed, 04 Feb 2015 14:37:54 +0100
> + -- Stefano Verzegnassi <verzegnassi.stefano@xxxxxxxxx> Wed, 04 Feb 2015 14:37:54 +0100
>
> ubuntu-docviewer-app (0.1.2) UNRELEASED; urgency=medium
>
>
> === modified file 'debian/control'
> --- debian/control 2015-02-04 16:08:33 +0000
> +++ debian/control 2015-02-27 15:45:56 +0000
> @@ -4,6 +4,7 @@
> Build-Depends: cmake,
> debhelper (>= 9),
> intltool,
> + libcontent-hub-dev (>= 0.0+13.10.20130930.1),
> libpoppler-qt5-dev,
> pep8,
> pkg-config,
> @@ -27,7 +28,6 @@
> Architecture: any
> Depends: qtdeclarative5-qtquick2-plugin,
> qtdeclarative5-ubuntu-ui-toolkit-plugin,
> - qtdeclarative5-ubuntu-content1,
> ${misc:Depends}
> Description: Document Viewer application
> Core Document Viewer application
>
> === modified file 'docviewer-content.json'
> --- docviewer-content.json 2014-10-31 16:25:17 +0000
> +++ docviewer-content.json 2015-02-27 15:45:56 +0000
> @@ -1,7 +1,8 @@
> {
> "destination": [
> - "pictures",
> - "documents",
> - "unknown"
> + "documents"
> + ],
> + "source": [
> + "documents"
> ]
> }
>
> === modified file 'docviewer.apparmor'
> --- docviewer.apparmor 2014-10-31 16:25:17 +0000
> +++ docviewer.apparmor 2015-02-27 15:45:56 +0000
> @@ -1,6 +1,14 @@
> {
> "policy_groups": [
> - "content_exchange"
> + "content_exchange_source",
> + "content_exchange",
> + "debug"
> + ],
> + "read_path": [
> + "@{HOME}/Documents/"
> + ],
> + "write_path": [
> + "@{HOME}/Documents/"
> ],
> "policy_version": 1.2
> }
>
> === modified file 'manifest.json.in'
> --- manifest.json.in 2015-02-04 19:30:22 +0000
> +++ manifest.json.in 2015-02-27 15:45:56 +0000
> @@ -9,10 +9,11 @@
> "docviewer": {
> "apparmor": "docviewer.apparmor",
> "desktop": "com.ubuntu.docviewer.desktop",
> - "content-hub": "docviewer-content.json"
> + "content-hub": "docviewer-content.json",
> + "urls": "@URLS_FILE@"
> }
> },
> - "version": "0.2.1.@BZR_REVNO@",
> + "version": "0.3.@BZR_REVNO@",
> "maintainer": "Ubuntu App Cats <ubuntu-touch-coreapps@xxxxxxxxxxxxxxxxxxx>",
> "x-source": {
> "vcs-bzr": "@BZR_SOURCE@",
>
> === modified file 'po/com.ubuntu.docviewer.pot'
> --- po/com.ubuntu.docviewer.pot 2015-02-05 19:30:53 +0000
> +++ po/com.ubuntu.docviewer.pot 2015-02-27 15:45:56 +0000
> @@ -8,7 +8,7 @@
> msgstr ""
> "Project-Id-Version: \n"
> "Report-Msgid-Bugs-To: \n"
> -"POT-Creation-Date: 2015-02-05 20:29+0100\n"
> +"POT-Creation-Date: 2015-02-27 16:44+0100\n"
> "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
> "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
> "Language-Team: LANGUAGE <LL@xxxxxx>\n"
> @@ -17,136 +17,190 @@
> "Content-Type: text/plain; charset=CHARSET\n"
> "Content-Transfer-Encoding: 8bit\n"
>
> -#: ../src/app/qml/ContentHubPicker.qml:23
> -msgid "Open with..."
> -msgstr ""
> -
> -#: ../src/app/qml/ContentHubPicker.qml:27
> -msgid "Documents"
> -msgstr ""
> -
> -#: ../src/app/qml/ContentHubPicker.qml:27
> -msgid "Pictures"
> -msgstr ""
> -
> -#: ../src/app/qml/ContentHubPicker.qml:27
> -msgid "Other"
> -msgstr ""
> -
> -#: ../src/app/qml/ContentHubPicker.qml:30
> -#: ../src/app/qml/ImageViewDefaultHeader.qml:53
> -#: ../src/app/qml/PdfViewDefaultHeader.qml:61
> -#: ../src/app/qml/TextViewDefaultHeader.qml:61
> -msgid "Back"
> -msgstr ""
> -
> -#: ../src/app/qml/DetailsPage.qml:27
> -#: ../src/app/qml/ImageViewDefaultHeader.qml:69
> -#: ../src/app/qml/PdfViewDefaultHeader.qml:91
> -#: ../src/app/qml/TextViewDefaultHeader.qml:77
> +#: ../src/app/qml/common/DetailsPage.qml:27
> +#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:91
> +#: ../src/app/qml/textView/TextViewDefaultHeader.qml:77
> msgid "Details"
> msgstr ""
>
> -#: ../src/app/qml/DetailsPage.qml:33
> +#: ../src/app/qml/common/DetailsPage.qml:33
> msgid "Location"
> msgstr ""
>
> -#: ../src/app/qml/DetailsPage.qml:37
> +#: ../src/app/qml/common/DetailsPage.qml:37
> msgid "Size"
> msgstr ""
>
> -#: ../src/app/qml/DetailsPage.qml:42
> +#: ../src/app/qml/common/DetailsPage.qml:42
> msgid "Created"
> msgstr ""
>
> -#: ../src/app/qml/DetailsPage.qml:47
> +#: ../src/app/qml/common/DetailsPage.qml:47
> msgid "Last modified"
> msgstr ""
>
> -#: ../src/app/qml/DetailsPage.qml:54
> +#: ../src/app/qml/common/DetailsPage.qml:54
> msgid "MIME type"
> msgstr ""
>
> -#: ../src/app/qml/ErrorDialog.qml:23
> +#: ../src/app/qml/common/ErrorDialog.qml:23
> msgid "Error"
> msgstr ""
>
> -#: ../src/app/qml/ErrorDialog.qml:24
> +#: ../src/app/qml/common/ErrorDialog.qml:24
> msgid "File does not exist"
> msgstr ""
>
> -#: ../src/app/qml/ErrorDialog.qml:27
> -#: ../src/app/qml/ImageViewDefaultHeader.qml:53
> -#: ../src/app/qml/PdfViewDefaultHeader.qml:61
> -#: ../src/app/qml/TextViewDefaultHeader.qml:61
> +#: ../src/app/qml/common/ErrorDialog.qml:27
> +#: ../src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml:33
> +#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:61
> +#: ../src/app/qml/textView/TextViewDefaultHeader.qml:61
> msgid "Close"
> msgstr ""
>
> -#: ../src/app/qml/PdfContentsPage.qml:24 ../src/app/qml/PdfView.qml:33
> +#: ../src/app/qml/common/UnknownTypeDialog.qml:26
> +msgid "Unknown file type"
> +msgstr ""
> +
> +#: ../src/app/qml/common/UnknownTypeDialog.qml:27
> +msgid ""
> +"Sorry but we can't find a way to display this file. Do you want to open it "
> +"as a plain text?"
> +msgstr ""
> +
> +#: ../src/app/qml/common/UnknownTypeDialog.qml:29
> +msgid "Yes"
> +msgstr ""
> +
> +#: ../src/app/qml/common/UnknownTypeDialog.qml:38
> +msgid "No"
> +msgstr ""
> +
> +#: ../src/app/qml/documentPage/DeleteFileDialog.qml:27
> +msgid "Delete file"
> +msgstr ""
> +
> +#: ../src/app/qml/documentPage/DeleteFileDialog.qml:28
> +#, qt-format
> +msgid "Delete %1 files"
> +msgstr ""
> +
> +#: ../src/app/qml/documentPage/DeleteFileDialog.qml:29
> +msgid "Are you sure you want to permanently delete this file?"
> +msgstr ""
> +
> +#: ../src/app/qml/documentPage/DeleteFileDialog.qml:30
> +msgid "Are you sure you want to permanently delete these files?"
> +msgstr ""
> +
> +#: ../src/app/qml/documentPage/DeleteFileDialog.qml:33
> +#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:29
> +#: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:52
> +msgid "Cancel"
> +msgstr ""
> +
> +#: ../src/app/qml/documentPage/DeleteFileDialog.qml:38
> +#: ../src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml:83
> +msgid "Delete"
> +msgstr ""
> +
> +#: ../src/app/qml/documentPage/DocumentEmptyState.qml:24
> +msgid "No document found"
> +msgstr ""
> +
> +#: ../src/app/qml/documentPage/DocumentEmptyState.qml:28
> +msgid ""
> +"Connect your device to any computer and simply drag files to the Documents "
> +"folder."
> +msgstr ""
> +
> +#: ../src/app/qml/documentPage/DocumentGridDelegate.qml:33
> +msgid "Today, "
> +msgstr ""
> +
> +#: ../src/app/qml/documentPage/DocumentGridDelegate.qml:36
> +msgid "Yesterday, "
> +msgstr ""
> +
> +#: ../src/app/qml/documentPage/DocumentListView.qml:135
> +msgid "Today"
> +msgstr ""
> +
> +#: ../src/app/qml/documentPage/DocumentListView.qml:138
> +msgid "Yesterday"
> +msgstr ""
> +
> +#: ../src/app/qml/documentPage/DocumentListView.qml:141
> +msgid "Earlier this week"
> +msgstr ""
> +
> +#: ../src/app/qml/documentPage/DocumentListView.qml:144
> +msgid "Earlier this month"
> +msgstr ""
> +
> +#: ../src/app/qml/documentPage/DocumentListView.qml:147
> +msgid "Even more earlier..."
> +msgstr ""
> +
> +#: ../src/app/qml/documentPage/DocumentPage.qml:25
> +#: /home/stefano/Progetti/doc-viewer/build-document-hub2-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:1
> +msgid "Document Viewer"
> +msgstr ""
> +
> +#: ../src/app/qml/documentPage/DocumentPageDefaultHeader.qml:30
> +#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:37
> +msgid "Switch to single column list"
> +msgstr ""
> +
> +#: ../src/app/qml/documentPage/DocumentPageDefaultHeader.qml:30
> +#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:37
> +msgid "Switch to grid"
> +msgstr ""
> +
> +#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:45
> +msgid "Pick"
> +msgstr ""
> +
> +#: ../src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml:53
> +msgid "Select None"
> +msgstr ""
> +
> +#: ../src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml:55
> +msgid "Select All"
> +msgstr ""
> +
> +#: ../src/app/qml/pdfView/PdfContentsPage.qml:24
> +#: ../src/app/qml/pdfView/PdfView.qml:34
> msgid "Contents"
> msgstr ""
>
> -#: ../src/app/qml/PdfView.qml:31
> +#: ../src/app/qml/pdfView/PdfView.qml:32
> #, qt-format
> msgid "Page %1 of %2"
> msgstr ""
>
> -#: ../src/app/qml/PdfViewGotoDialog.qml:25
> +#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:61
> +#: ../src/app/qml/textView/TextViewDefaultHeader.qml:61
> +msgid "Back"
> +msgstr ""
> +
> +#: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:25
> msgid "Go to page"
> msgstr ""
>
> -#: ../src/app/qml/PdfViewGotoDialog.qml:26
> +#: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:26
> #, qt-format
> msgid "Choose a page between 1 and %1"
> msgstr ""
>
> -#: ../src/app/qml/PdfViewGotoDialog.qml:44
> +#: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:44
> msgid "GO!"
> msgstr ""
>
> -#: ../src/app/qml/PdfViewGotoDialog.qml:52
> -msgid "Cancel"
> -msgstr ""
> -
> -#: ../src/app/qml/TextView.qml:39
> +#: ../src/app/qml/textView/TextView.qml:39
> msgid "Loading..."
> msgstr ""
>
> -#: ../src/app/qml/UnknownTypeDialog.qml:26
> -msgid "Unknown file type"
> -msgstr ""
> -
> -#: ../src/app/qml/UnknownTypeDialog.qml:27
> -msgid ""
> -"Sorry but we can't find a way to display this file. Do you want to open it "
> -"as a plain text?"
> -msgstr ""
> -
> -#: ../src/app/qml/UnknownTypeDialog.qml:29
> -msgid "Yes"
> -msgstr ""
> -
> -#: ../src/app/qml/UnknownTypeDialog.qml:38
> -msgid "No"
> -msgstr ""
> -
> -#: ../src/app/qml/WelcomePage.qml:23
> -#: /home/stefano/Progetti/doc-viewer/build-ubuntu-docviewer-app-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:1
> -msgid "Document Viewer"
> -msgstr ""
> -
> -#: ../src/app/qml/WelcomePage.qml:27
> -msgid "No opened documents"
> -msgstr ""
> -
> -#: ../src/app/qml/WelcomePage.qml:28
> -msgid "Tap the + icon to open a document"
> -msgstr ""
> -
> -#: ../src/app/qml/WelcomePage.qml:37
> -msgid "Open a file..."
> -msgstr ""
> -
> -#: /home/stefano/Progetti/doc-viewer/build-ubuntu-docviewer-app-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:2
> +#: /home/stefano/Progetti/doc-viewer/build-document-hub2-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:2
> msgid "documents;viewer;pdf;reader;"
> msgstr ""
>
> === modified file 'src/app/CMakeLists.txt'
> --- src/app/CMakeLists.txt 2014-10-21 13:23:11 +0000
> +++ src/app/CMakeLists.txt 2015-02-27 15:45:56 +0000
> @@ -1,13 +1,25 @@
> file(GLOB_RECURSE QML_SRCS *.qml *.js)
> +file(GLOB_RECURSE IMAGE_FILES *.qml *.js)
> +
> +pkg_check_modules(CONTENTHUB REQUIRED libcontent-hub)
>
> set(docviewer_SRCS
> main.cpp
> + content-communicator.cpp
> + command-line-parser.cpp
> + docviewer-application.cpp
> + urlhandler.cpp
> + quick/documentmodel.cpp
> ${QML_SRCS}
> )
>
> add_executable(ubuntu-docviewer-app ${docviewer_SRCS})
>
> -qt5_use_modules(ubuntu-docviewer-app Gui Qml Quick)
> +qt5_use_modules(ubuntu-docviewer-app Widgets Gui Qml Quick DBus)
> +
> +target_link_libraries( ubuntu-docviewer-app
> + ${CONTENTHUB_LIBRARIES}
> +)
>
> if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
> add_custom_target(docviewer-qmlfiles ALL
> @@ -16,7 +28,16 @@
> )
> endif(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
>
> +if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
> +add_custom_target(docviewer-imagefiles ALL
> + COMMAND cp -r ${CMAKE_CURRENT_SOURCE_DIR}/graphics ${CMAKE_CURRENT_BINARY_DIR}
> + DEPENDS ${IMAGE_FILES}
> +)
> +endif(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
> +
> install(DIRECTORY qml DESTINATION ${DATA_DIR})
> +install(DIRECTORY graphics DESTINATION ${DATA_DIR})
> +
> if(CLICK_MODE)
> install(TARGETS ubuntu-docviewer-app DESTINATION ${BIN_DIR})
> else()
>
> === added file 'src/app/command-line-parser.cpp'
> --- src/app/command-line-parser.cpp 1970-01-01 00:00:00 +0000
> +++ src/app/command-line-parser.cpp 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,105 @@
> +/*
> + * Copyright (C) 2013 Canonical, Ltd.
> + *
> + * Authors:
> + * Nicolas d'Offay <nicolas.doffay@xxxxxxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#include "command-line-parser.h"
> +
> +#include "urlhandler.h"
> +
> +#include <QDebug>
> +#include <QDir>
> +#include <QStandardPaths>
> +#include <QTextStream>
> +#include <QUrl>
> +
> +CommandLineParser::CommandLineParser()
> + : m_pickMode(false),
> + m_testability(false),
> + m_documentFile("")
> +{
> + m_urlHandler = new UrlHandler();
> +}
> +
> +/*!
> + * @brief CommandLineParser::processArguments parsers our input commandline args and sets attributes accordingly.
> + * @param QStringList of commandline args to parse and set attributes.
> + * @return false if invalid parameter is input or -h/--help is called.
> + */
> +bool CommandLineParser::processArguments(const QStringList& args)
> +{
> + bool valid_args = true;
> +
> + for (int i = 1; i < args.count(); ++i)
> + {
> + if (args[i] == "--help" || args[i] == "-h") {
> + usage();
> + return false;
> + }
> + else if (args[i] == "--pick-mode") {
> + m_pickMode = true;
> + }
> + else if (args[i] == "--testability") {
> + m_testability = true;
> + }
> + else {
> + if (args[i].startsWith("--desktop_file_hint")) {
> + // ignore this command line switch, hybris uses it to get application info
> + }
> + else if (!args.at(i).isEmpty()) {
> + QFileInfo fi(args.at(i));
> +
> + if (fi.exists()) {
> + m_documentFile = fi.absoluteFilePath();
> + }
> + else if (m_urlHandler->processUri(args.at(i))) {
> + m_documentFile = m_urlHandler->documentFile();
> + }
> + }
> + else {
> + valid_args = !invalidArg(args[i]);
> + }
> + }
> + }
> +
> + return valid_args;
> +}
> +
> +/*!
> + * @brief CommandLineParser::usage() prints out our form factors.
> + */
> +void CommandLineParser::usage()
> +{
> + QTextStream out(stdout);
> + out << "Usage: ubuntu-docviewer-app [options] [file_path]" << endl;
> + out << "Options:" << endl;
> + out << " --pick-mode\t\tEnable mode to pick photos" << endl;
> + out << " file_path\t\tOpens ubuntu-docviewer-app displaying the selected file" << endl;
> +}
> +
> +/*!
> + * @brief CommandLineParser::invalidArg() if an invalid argument is contained in our QStringList.
> + * @return returns true.
> + */
> +bool CommandLineParser::invalidArg(QString arg)
> +{
> + QTextStream(stderr) << "Invalid argument '" << arg << "'" << endl;
> + usage();
> +
> + return true;
> +}
>
> === added file 'src/app/command-line-parser.h'
> --- src/app/command-line-parser.h 1970-01-01 00:00:00 +0000
> +++ src/app/command-line-parser.h 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,56 @@
> +/*
> + * Copyright (C) 2013 Canonical, Ltd.
> + *
> + * Authors:
> + * Nicolas d'Offay <nicolas.doffay@xxxxxxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#ifndef COMMANDLINEPARSER_H
> +#define COMMANDLINEPARSER_H
> +
> +#include <QHash>
> +#include <QSize>
> +#include <QString>
> +
> +class UrlHandler;
> +
> +/*!
> + * @brief The CommandLineParser is used to parse our commandline inputs and set
> + * parameters accordingly.
> + */
> +class CommandLineParser
> +{
> +public:
> + CommandLineParser();
> +
> + bool processArguments(const QStringList& args);
> +
> + bool pickModeEnabled() const { return m_pickMode; }
> + bool testability() const { return m_testability; }
> + const QString &documentFile() const { return m_documentFile; }
> +
> +private:
> + bool invalidArg(QString arg);
> + void usage();
> +
> + UrlHandler *m_urlHandler;
> +
> + bool m_pickMode;
> + bool m_testability;
> + QString m_documentFile;
> +};
> +
> +#endif // COMMANDLINEPARSER_H
>
> === added file 'src/app/content-communicator.cpp'
> --- src/app/content-communicator.cpp 1970-01-01 00:00:00 +0000
> +++ src/app/content-communicator.cpp 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,188 @@
> +/*
> + * Copyright (C) 2013 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#include "content-communicator.h"
> +
> +#include <QApplication>
> +#include <QStandardPaths>
> +#include <QMimeDatabase>
> +#include <QDebug>
> +#include <QFileInfo>
> +
> +#include <com/ubuntu/content/hub.h>
> +#include <com/ubuntu/content/item.h>
> +#include <com/ubuntu/content/transfer.h>
> +
> +
> +using namespace com::ubuntu::content;
> +
> +/*!
> + * \brief ContentCommunicator::ContentCommunicator
> + * \param parent
> + */
> +ContentCommunicator::ContentCommunicator(QObject *parent)
> + : ImportExportHandler(parent),
> + m_transfer(nullptr)
> +{
> +}
> +
> +/*!
> + * \brief ContentCommunicator::registerWithHub Register the handlers provided
> + * by ContentCommunicator with the content hub
> + */
> +void ContentCommunicator::registerWithHub()
> +{
> + Hub *hub = Hub::Client::instance();
> + hub->register_import_export_handler(this);
> +}
> +
> +/*!
> + * \brief \reimp
> + */
> +void ContentCommunicator::handle_import(content::Transfer *transfer)
> +{
> + // FIXME: If a file is imported from $HOME/Documents, a new copy of the file is created.
> + // Sadly, we can't check for the source of the file, since we just get the path
> + // of the cache copy.
> + // FIXME: If there already a file called "filename.1.ext", the imported file won't be renamed as "filename.2.ext", but "filename.1.1.ext".
> + // (This issue is in gallery-app too.)
> +
> + QVector<Item> transferedItems = transfer->collect();
> + foreach (const Item &hubItem, transferedItems) {
> + QFileInfo fi(hubItem.url().toLocalFile());
> + QString filename = fi.fileName();
> + QString dir;
> + QMimeDatabase mdb;
> + QMimeType mt = mdb.mimeTypeForFile(hubItem.url().toLocalFile());
> + QString suffix = fi.completeSuffix();
> + QString filenameWithoutSuffix = filename.left(filename.size() - suffix.size());
Please use QFileInfo::baseName()
http://doc.qt.io/qt-5/qfileinfo.html#baseName
> + if(suffix.isEmpty()) {
> + // If the filename doesn't have an extension add one from the
> + // detected mimetype
> + if(!mt.preferredSuffix().isEmpty()) {
> + suffix = mt.preferredSuffix();
> + filenameWithoutSuffix += ".";
This changes the name of the file without consinstency.
Suppose we already have in our directory a file named file.txt.
If we want to import a file named file.txt we will have file1.txt.
On the other hand, if we want to import a file named file, without suffix, but with txt mimetype, we will have file.1.txt
I suggest to always add the . to filenameWithoutSuffix, so do something like
QString filenameWithoutSuffix = fi.baseName() + '.';
This because we can have file with a date as name, and the dot separate the date from the suffix that comes from the number of the files with the same name
E.g.
20150302.txt becomes 20150302.1.txt
> + }
> + }
> + dir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + QDir::separator();
> +
> + QString destination = QString("%1%2").arg(dir + filenameWithoutSuffix, suffix);
> + // If we already have a file of this name reformat to "filename.x.png"
> + // (where x is a number, incremented until we find an available filename)
> + if(QFile::exists(destination)) {
> + int append = 1;
> + do {
> + destination = QString("%1%2.%3").arg(dir + filenameWithoutSuffix, QString::number(append), suffix);
> + append++;
> + } while(QFile::exists(destination));
> + }
> + QFile::copy(hubItem.url().toLocalFile(), destination);
> + }
> +
Please remove a newline
> +
> + // Allow content-hub to clean up temporary files in .cache/ once we've
> + // moved them
> + transfer->finalize();
> +
> + emit documentImported();
> +}
> +
> +/*!
> + * \brief \reimp
> + */
> +void ContentCommunicator::handle_export(content::Transfer *transfer)
> +{
> + if (m_transfer != nullptr) {
> + qWarning() << "docviewer-app does only one content export at a time";
> + transfer->abort();
> + return;
> + }
> +
> + m_transfer = transfer;
> + emit documentRequested();
> + emit selectionTypeChanged();
> + emit singleContentPickModeChanged();
> +}
> +
> +/*!
> + * \brief \reimp
> + */
> +void ContentCommunicator::handle_share(content::Transfer *)
> +{
> + qDebug() << Q_FUNC_INFO << "docviewer does not share content";
> +}
> +
> +/*!
> + * \brief ContentCommunicator::cancelTransfer aborts the current transfer
> + */
> +void ContentCommunicator::cancelTransfer()
> +{
> + if (!m_transfer) {
> + qWarning() << "No ongoing transfer to cancel";
> + return;
> + }
> +
> + m_transfer->abort();
> + m_transfer = nullptr;
> +}
> +
> +/*!
> + * \brief ContentCommunicator::returnPhoto returns the given photos
This is returnDocuments, not returnPhoto :-)
> + * via content hub to the requester
> + * \param urls
> + */
> +void ContentCommunicator::returnDocuments(const QVector<QUrl> &urls)
> +{
> + if (!m_transfer) {
> + qWarning() << "No ongoing transfer to return a document";
> + return;
> + }
> +
> + QVector<Item> items;
> + items.reserve(urls.size());
> + foreach (const QUrl &url, urls) {
> + items.append(Item(url));
> + }
> +
> + m_transfer->charge(items);
> + m_transfer = nullptr;
> +}
> +
> +/*!
> + * \brief ContentCommunicator::selectionType return if the transfer requests
> + * one single item only, or multiple
> + * \return
> + */
> +ContentCommunicator::SelectionType ContentCommunicator::selectionType() const
> +{
> + if (!m_transfer)
> + return SingleSelect;
> +
> + return static_cast<SelectionType>(m_transfer->selectionType());
> +}
> +
> +/*!
> + * \brief ContentCommunicator::singleContentPickMode
> + * \return
> + */
> +bool ContentCommunicator::singleContentPickMode() const
> +{
> + if (!m_transfer)
> + return true;
> +
> + return m_transfer->selectionType() == Transfer::SelectionType::single;
Shouldn't be Transfer::SelectionType::SingleSelect?
> +}
>
> === added file 'src/app/content-communicator.h'
> --- src/app/content-communicator.h 1970-01-01 00:00:00 +0000
> +++ src/app/content-communicator.h 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,69 @@
> +/*
> + * Copyright (C) 2013 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#ifndef CONTENTCOMMUNICATOR_H
> +#define CONTENTCOMMUNICATOR_H
> +
> +#include <com/ubuntu/content/import_export_handler.h>
> +#include <com/ubuntu/content/transfer.h>
> +
> +#include <QUrl>
> +#include <QVector>
> +
> +using namespace com::ubuntu;
> +
> +/*!
> + * Class to handle the communication with the content manager
> + */
> +class ContentCommunicator : public content::ImportExportHandler
> +{
> + Q_OBJECT
> + Q_PROPERTY(bool singleContentPickMode READ singleContentPickMode NOTIFY singleContentPickModeChanged)
> + Q_PROPERTY(SelectionType selectionType READ selectionType NOTIFY selectionTypeChanged)
> + Q_ENUMS(SelectionType)
> +
> +public:
> + enum SelectionType {
> + SingleSelect = content::Transfer::single,
> + MultiSelect = content::Transfer::multiple
> + };
> +
> + ContentCommunicator(QObject *parent = nullptr);
> +
> + virtual void handle_import(content::Transfer*);
> + virtual void handle_export(content::Transfer *transfer);
> + virtual void handle_share(content::Transfer*);
> +
> + void cancelTransfer();
> + void returnDocuments(const QVector<QUrl> &urls);
> +
> + SelectionType selectionType() const;
> + bool singleContentPickMode() const;
> +
> + void registerWithHub();
> +
> +signals:
> + void documentRequested();
> + void documentImported();
> + void selectionTypeChanged();
> + void singleContentPickModeChanged();
> +
> +private:
> + content::Transfer *m_transfer;
> +};
> +
> +#endif // CONTENTCOMMUNICATOR_H
>
> === added file 'src/app/docviewer-application.cpp'
> --- src/app/docviewer-application.cpp 1970-01-01 00:00:00 +0000
> +++ src/app/docviewer-application.cpp 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,298 @@
> +/*
> + * Copyright (C) 2012 Canonical Ltd
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 3 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authors:
> + * Charles Lindsay <chaz@xxxxxxxxx>
> + */
> +
> +#include "docviewer-application.h"
> +#include "content-communicator.h"
> +#include "command-line-parser.h"
> +#include "urlhandler.h"
> +#include "quick/documentmodel.h"
> +
> +#include <QQuickItem>
> +#include <QStandardPaths>
> +#include <QQuickView>
> +#include <QtQml/QtQml>
> +#include <QString>
> +#include <QUrl>
> +#include <QtGui/QGuiApplication>
> +
> +/*!
> + * \brief DocViewerApplication::DocViewerApplication
> + * \param argc
> + * \param argv
> + */
> +DocViewerApplication::DocViewerApplication(int& argc, char** argv)
> + : QApplication(argc, argv),
> + m_view(new QQuickView()),
> + m_contentCommunicator(new ContentCommunicator(this)),
> + m_pickModeEnabled(false),
> + m_defaultUiMode(BrowseContentMode),
> + m_documentFile(""),
> + m_documentLoaded(false)
> +{
> + //
> +}
> +
> +bool DocViewerApplication::init()
> +{
> + m_cmdLineParser = new CommandLineParser();
> + bool ok = m_cmdLineParser->processArguments(arguments());
> + if (!ok)
> + return false;
Why do you instantiate a new var?
Just do if (!m_cmdLineParser->processArguments(arguments())) return false;
> +
> + if (qgetenv("QT_LOAD_TESTABILITY") == "1" || m_cmdLineParser->testability()) {
> + QLibrary testLib(QLatin1String("qttestability"));
> + if (testLib.load()) {
> + typedef void (*TasInitialize)(void);
> + TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init");
> + if (initFunction) {
> + initFunction();
> + } else {
> + qCritical("Library qttestability resolve failed!");
> + }
> + } else {
> + qCritical("Library qttestability load failed!");
> + }
> + }
> +
> + m_urlHandler = new UrlHandler();
> +
> + registerQML();
> +
> + if (m_cmdLineParser->pickModeEnabled())
> + setDefaultUiMode(DocViewerApplication::PickContentMode);
> +
> + QObject::connect(m_contentCommunicator, SIGNAL(documentRequested()),
> + this, SLOT(switchToPickMode()));
> +
> + QObject::connect(m_contentCommunicator, SIGNAL(documentImported()),
> + this, SLOT(switchToBrowseMode()));
> +
> + return true;
> +}
> +
> +/*!
> + * \brief DocViewerApplication::~DocViewerApplication
> + */
> +DocViewerApplication::~DocViewerApplication()
> +{
> + delete m_view;
> + delete m_cmdLineParser;
> +}
> +
> +/*!
> + * \brief DocViewerApplication::exec
> + * \return
> + */
> +int DocViewerApplication::exec()
> +{
> + createView();
> +
> + return QApplication::exec();
> +}
> +
> +/*!
> + * \brief DocViewerApplication::registerQML
> + */
> +void DocViewerApplication::registerQML()
> +{
> + // Set up import paths
> + QStringList importPathList = m_view->engine()->importPathList();
> + // Prepend the location of the plugin in the build dir,
> + // so that Qt Creator finds it there, thus overriding the one installed
> + // in the sistem if there is one
> + importPathList.prepend(QCoreApplication::applicationDirPath() + "/../plugin/");
> + m_view->engine()->setImportPathList(importPathList);
> +
> + qmlRegisterType<SortFilterDocumentModel>("DocumentViewer", 1, 0, "DocumentsModel");
> +}
> +
> +/*!
> + * \brief DocViewerApplication::getDocumentFile
> + * Returns the document file passed as a parameter
> + */
> +const QString& DocViewerApplication::getDocumentFile() const
> +{
> + return m_documentFile;
> +}
> +
> +/*!
> + * \brief DocViewerApplication::createView
> + * Create the master QDeclarativeView that all the pages will operate within
> + */
> +void DocViewerApplication::createView()
> +{
> + m_view->setTitle("Document Viewer");
I think this should be a translable string:
m_view->setTitle(tr("Document Viewer"));
> +
> + // Set ourselves up to expose functionality to run external commands from QML...
> + m_view->engine()->rootContext()->setContextProperty("DOC_VIEWER", this);
> + m_view->engine()->rootContext()->setContextProperty("PICKER_HUB", m_contentCommunicator);
> +
> + QObject::connect(m_view->engine(), SIGNAL(quit()), this, SLOT(quit()));
> +
> + QString qmlfile;
> + const QString filePath = QLatin1String("qml/ubuntu-docviewer-app.qml");
> + QStringList paths = QStandardPaths::standardLocations(QStandardPaths::DataLocation);
> + paths.prepend(QDir::currentPath());
> + paths.prepend(QCoreApplication::applicationDirPath());
> + Q_FOREACH (const QString &path, paths) {
> + QString myPath = path + QLatin1Char('/') + filePath;
> +
> + if (QFile::exists(myPath)) {
> + qmlfile = myPath;
> + break;
> + } else {
> + myPath.replace(QCoreApplication::applicationName(), "ubuntu-docviewer-app");
> +
> + if (QFile::exists(myPath)) {
> + qmlfile = myPath;
> + break;
> + }
> + }
> + }
> + // sanity check
> + if (qmlfile.isEmpty()) {
> + qFatal("File: %s does not exist at any of the standard paths!", qPrintable(filePath));
> + }
> +
> + registerHub();
> + m_view->setSource(QUrl::fromLocalFile(qmlfile));
> + setDocumentFile(m_cmdLineParser->documentFile());
> +
> + m_view->setResizeMode(QQuickView::SizeRootObjectToView);
> + m_view->show();
> +}
> +
> +/*!
> + * \brief DocViewerApplication::setDefaultUiMode set the default UI mode. This might
> + * get overridden during the lifetime
> + * \param mode
> + */
> +void DocViewerApplication::setDefaultUiMode(DocViewerApplication::UiMode mode)
> +{
> + m_defaultUiMode = mode;
> + setUiMode(mode);
> +}
> +
> +/*!
> + * \brief DocViewerApplication::setUiMode set's the current UI mode
> + * \param mode
> + */
> +void DocViewerApplication::setUiMode(DocViewerApplication::UiMode mode)
> +{
> + bool enablePickMode = (mode == PickContentMode);
> +
> + if (enablePickMode != m_pickModeEnabled) {
> + m_pickModeEnabled = enablePickMode;
> + Q_EMIT pickModeEnabledChanged();
> + }
> +}
> +
> +/*!
> + * \brief DocViewerApplication::pickModeEnabled returns true if the current UI
> + * mode should be for picking acontent
> + * \return
> + */
> +bool DocViewerApplication::pickModeEnabled() const
> +{
> + return m_pickModeEnabled;
> +}
> +
> +/*!
> + * \brief DocViewerApplication::switchToPickMode
> + */
> +void DocViewerApplication::switchToPickMode()
> +{
> + setUiMode(PickContentMode);
> +}
> +
> +/*!
> + * \brief DocViewerApplication::switchToBrowseMode
> + */
> +void DocViewerApplication::switchToBrowseMode()
> +{
> + Q_EMIT browseModeRequested();
> +}
> +
> +void DocViewerApplication::setDocumentFile(const QString &documentFile)
> +{
> + if(!documentFile.isEmpty()) {
> + if (m_documentFile != documentFile) {
> + m_documentFile = "file://" + documentFile;
> + Q_EMIT documentFileChanged();;
> + }
> + }
> +}
> +
> +/*!
> + * \brief DocViewerApplication::returnPickedContent passes the selcted items to the
> + * content manager
> + * \param variant
> + */
> +void DocViewerApplication::returnPickedContent(QList<QString> paths)
> +{
> + QVector<QUrl> selectedMedias;
> + selectedMedias.reserve(paths.size());
> + foreach (const QString path, paths) {
> + // We handle paths without "file://" prefix, so we need to add it when exporting to content-hub.
> + selectedMedias.append(QUrl("file://" + path));
> + }
> + m_contentCommunicator->returnDocuments(selectedMedias);
> +
> + if (m_defaultUiMode == BrowseContentMode) {
> + setUiMode(BrowseContentMode);
> + } else {
> + // give the app and content-hub some time to finish taks (run the event loop)
> + QTimer::singleShot(10, this, SLOT(quit()));
> + }
> +}
> +
> +/*!
> + * \brief DocViewerApplication::contentPickingCanceled tell the content manager, that
> + * the picking was canceled
> + */
> +void DocViewerApplication::contentPickingCanceled()
> +{
> + m_contentCommunicator->cancelTransfer();
> +
> + if (m_defaultUiMode == BrowseContentMode) {
> + setUiMode(BrowseContentMode);
> + } else {
> + // give the app and content-hub some time to finish taks (run the event loop)
> + QTimer::singleShot(10, this, SLOT(quit()));
> + }
> +}
> +
> +void DocViewerApplication::registerHub()
> +{
> + m_contentCommunicator->registerWithHub();
> +}
> +
> +void DocViewerApplication::parseUri(const QString &arg)
> +{
> + if (m_urlHandler->processUri(arg)) {
> + setDocumentFile(m_urlHandler->documentFile());
> + }
> +}
> +
> +void DocViewerApplication::releaseResources()
> +{
> + if (m_view) {
> + m_view->releaseResources();
> + }
> +}
>
> === added file 'src/app/docviewer-application.h'
> --- src/app/docviewer-application.h 1970-01-01 00:00:00 +0000
> +++ src/app/docviewer-application.h 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,92 @@
> +/*
> + * Copyright (C) 2012 Canonical Ltd
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 3 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authors:
> + * Charles Lindsay <chaz@xxxxxxxxx>
> + */
> +
> +#ifndef DOCVIEWERAPPLICATION_H
> +#define DOCVIEWERAPPLICATION_H
> +
> +#include <QApplication>
> +#include <QElapsedTimer>
> +#include <QFileInfo>
> +#include <QTimer>
> +
> +class CommandLineParser;
> +class UrlHandler;
> +class ContentCommunicator;
> +
> +class QQuickView;
> +
> +/*!
> + * \brief The DocViewerApplication class
> + */
> +class DocViewerApplication : public QApplication
> +{
> + Q_OBJECT
> + Q_PROPERTY(bool pickModeEnabled READ pickModeEnabled NOTIFY pickModeEnabledChanged)
> + Q_PROPERTY(QString documentFile READ getDocumentFile WRITE setDocumentFile NOTIFY documentFileChanged)
> +
> +public:
> + enum UiMode{
> + BrowseContentMode,
> + PickContentMode
> + };
> +
> + explicit DocViewerApplication(int& argc, char** argv);
> + virtual ~DocViewerApplication();
> +
> + bool init();
> + int exec();
> +
> + void setDefaultUiMode(UiMode mode);
> + UiMode defaultUiMode() const;
> + void setUiMode(UiMode mode);
> + bool pickModeEnabled() const;
> + const QString &getDocumentFile() const;
> +
> + Q_INVOKABLE void returnPickedContent(QList<QString> paths);
> + Q_INVOKABLE void contentPickingCanceled();
> + Q_INVOKABLE void parseUri(const QString &arg);
> + Q_INVOKABLE void releaseResources();
> +
> +signals:
> + void pickModeEnabledChanged();
> + void documentFileChanged();
> + void browseModeRequested();
> +
> +private slots:
> + void switchToPickMode();
> + void switchToBrowseMode();
> + void setDocumentFile(const QString &documentFile);
> +
> +private:
> + void registerHub();
> + void registerQML();
> + void createView();
> +
> + QQuickView *m_view;
> + CommandLineParser* m_cmdLineParser;
> + UrlHandler *m_urlHandler;
> + ContentCommunicator *m_contentCommunicator;
> +
> + bool m_pickModeEnabled;
> + UiMode m_defaultUiMode;
> + QString m_documentFile;
> + bool m_documentLoaded;
> +};
> +
> +#endif // DOCVIEWERAPPLICATION_H
>
> === added directory 'src/app/graphics'
> === added file 'src/app/graphics/select-none.svg'
> --- src/app/graphics/select-none.svg 1970-01-01 00:00:00 +0000
> +++ src/app/graphics/select-none.svg 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,153 @@
> +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
> +<!-- Created with Inkscape (http://www.inkscape.org/) -->
> +
> +<svg
> + xmlns:dc="http://purl.org/dc/elements/1.1/"
> + xmlns:cc="http://creativecommons.org/ns#"
> + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
> + xmlns:svg="http://www.w3.org/2000/svg"
> + xmlns="http://www.w3.org/2000/svg"
> + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
> + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
> + width="90"
> + height="90"
> + id="svg4874"
> + version="1.1"
> + inkscape:version="0.48+devel r"
> + viewBox="0 0 90 90.000001"
> + sodipodi:docname="select-none.svg">
> + <defs
> + id="defs4876" />
> + <sodipodi:namedview
> + id="base"
> + pagecolor="#ffffff"
> + bordercolor="#666666"
> + borderopacity="1.0"
> + inkscape:pageopacity="0.0"
> + inkscape:pageshadow="2"
> + inkscape:zoom="12.434498"
> + inkscape:cx="10.237647"
> + inkscape:cy="53.078139"
> + inkscape:document-units="px"
> + inkscape:current-layer="g1311"
> + showgrid="true"
> + showborder="true"
> + fit-margin-top="0"
> + fit-margin-left="0"
> + fit-margin-right="0"
> + fit-margin-bottom="0"
> + inkscape:snap-bbox="true"
> + inkscape:bbox-paths="true"
> + inkscape:bbox-nodes="true"
> + inkscape:snap-bbox-edge-midpoints="true"
> + inkscape:snap-bbox-midpoints="true"
> + inkscape:object-paths="true"
> + inkscape:snap-intersection-paths="true"
> + inkscape:object-nodes="true"
> + inkscape:snap-smooth-nodes="true"
> + inkscape:snap-midpoints="true"
> + inkscape:snap-object-midpoints="true"
> + inkscape:snap-center="true"
> + showguides="true"
> + inkscape:guide-bbox="true">
> + <inkscape:grid
> + type="xygrid"
> + id="grid5451"
> + empspacing="6" />
> + <sodipodi:guide
> + orientation="1,0"
> + position="6,77"
> + id="guide4063" />
> + <sodipodi:guide
> + orientation="1,0"
> + position="3,78"
> + id="guide4065" />
> + <sodipodi:guide
> + orientation="0,1"
> + position="55,84"
> + id="guide4067" />
> + <sodipodi:guide
> + orientation="0,1"
> + position="53,87"
> + id="guide4069" />
> + <sodipodi:guide
> + orientation="0,1"
> + position="20,3"
> + id="guide4071" />
> + <sodipodi:guide
> + orientation="0,1"
> + position="20,6"
> + id="guide4073" />
> + <sodipodi:guide
> + orientation="1,0"
> + position="87,7"
> + id="guide4075" />
> + <sodipodi:guide
> + orientation="1,0"
> + position="84,7"
> + id="guide4077" />
> + <sodipodi:guide
> + orientation="0,1"
> + position="58,81"
> + id="guide4074" />
> + <sodipodi:guide
> + orientation="1,0"
> + position="9,74"
> + id="guide4076" />
> + <sodipodi:guide
> + orientation="0,1"
> + position="21,9"
> + id="guide4078" />
> + <sodipodi:guide
> + orientation="1,0"
> + position="81,4"
> + id="guide4080" />
> + </sodipodi:namedview>
> + <metadata
> + id="metadata4879">
> + <rdf:RDF>
> + <cc:Work
> + rdf:about="">
> + <dc:format>image/svg+xml</dc:format>
> + <dc:type
> + rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
> + <dc:title></dc:title>
> + </cc:Work>
> + </rdf:RDF>
> + </metadata>
> + <g
> + inkscape:label="Layer 1"
> + inkscape:groupmode="layer"
> + id="layer1"
> + transform="translate(67.857146,-84.50504)">
> + <g
> + transform="matrix(0,-1,-1,0,373.50506,516.50504)"
> + id="g4845"
> + style="display:inline">
> + <g
> + transform="matrix(0,-1,-1,0,567.36222,615.36221)"
> + id="g1311"
> + inkscape:export-filename="envelope02.png"
> + inkscape:export-xdpi="90"
> + inkscape:export-ydpi="90">
> + <g
> + id="g1313"
> + transform="matrix(1.875,0,0,1.875,-366,-1657.8169)">
> + <rect
> + transform="translate(0,804.3622)"
> + y="152"
> + x="288"
> + height="48"
> + width="48"
> + id="rect1315"
> + style="opacity:0.21171169;fill:none;stroke:none" />
> + </g>
> + <path
> + style="font-size:15px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#808080;fill-opacity:1;stroke:none;display:inline;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
> + d="M 21 6 C 11 6 6 5.9998033 6 17.626953 L 6 72.373047 C 6 84.000207 11 84 21 84 L 69 84 C 79 84 84 84.000207 84 72.373047 L 84 17.626953 C 84 5.9998033 79 6 69 6 L 21 6 z M 22.867188 12 L 67.132812 12 C 75.065512 12 78 11.999356 78 20.191406 L 78 69.808594 C 78 78.000644 75.065512 78 67.132812 78 L 22.867188 78 C 14.934488 78 12 78.000644 12 69.808594 L 12 20.191406 C 12 11.999356 14.934488 12 22.867188 12 z "
> + transform="translate(174,135.36222)"
> + id="path4098" />
> + </g>
> + </g>
> + </g>
> +</svg>
>
> === added file 'src/app/graphics/select.svg'
> --- src/app/graphics/select.svg 1970-01-01 00:00:00 +0000
> +++ src/app/graphics/select.svg 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,158 @@
> +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
> +<!-- Created with Inkscape (http://www.inkscape.org/) -->
> +
> +<svg
> + xmlns:dc="http://purl.org/dc/elements/1.1/"
> + xmlns:cc="http://creativecommons.org/ns#"
> + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
> + xmlns:svg="http://www.w3.org/2000/svg"
> + xmlns="http://www.w3.org/2000/svg"
> + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
> + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
> + width="90"
> + height="90"
> + id="svg4874"
> + version="1.1"
> + inkscape:version="0.48+devel r12833"
> + viewBox="0 0 90 90.000001"
> + sodipodi:docname="select.svg">
> + <defs
> + id="defs4876" />
> + <sodipodi:namedview
> + id="base"
> + pagecolor="#ffffff"
> + bordercolor="#666666"
> + borderopacity="1.0"
> + inkscape:pageopacity="0.0"
> + inkscape:pageshadow="2"
> + inkscape:zoom="12.434498"
> + inkscape:cx="30.343002"
> + inkscape:cy="53.600878"
> + inkscape:document-units="px"
> + inkscape:current-layer="g1311"
> + showgrid="true"
> + showborder="true"
> + fit-margin-top="0"
> + fit-margin-left="0"
> + fit-margin-right="0"
> + fit-margin-bottom="0"
> + inkscape:snap-bbox="true"
> + inkscape:bbox-paths="true"
> + inkscape:bbox-nodes="true"
> + inkscape:snap-bbox-edge-midpoints="true"
> + inkscape:snap-bbox-midpoints="true"
> + inkscape:object-paths="true"
> + inkscape:snap-intersection-paths="true"
> + inkscape:object-nodes="true"
> + inkscape:snap-smooth-nodes="true"
> + inkscape:snap-midpoints="true"
> + inkscape:snap-object-midpoints="true"
> + inkscape:snap-center="true"
> + showguides="true"
> + inkscape:guide-bbox="true">
> + <inkscape:grid
> + type="xygrid"
> + id="grid5451"
> + empspacing="6" />
> + <sodipodi:guide
> + orientation="1,0"
> + position="6,77"
> + id="guide4063" />
> + <sodipodi:guide
> + orientation="1,0"
> + position="3,78"
> + id="guide4065" />
> + <sodipodi:guide
> + orientation="0,1"
> + position="55,84"
> + id="guide4067" />
> + <sodipodi:guide
> + orientation="0,1"
> + position="53,87"
> + id="guide4069" />
> + <sodipodi:guide
> + orientation="0,1"
> + position="20,3"
> + id="guide4071" />
> + <sodipodi:guide
> + orientation="0,1"
> + position="20,6"
> + id="guide4073" />
> + <sodipodi:guide
> + orientation="1,0"
> + position="87,7"
> + id="guide4075" />
> + <sodipodi:guide
> + orientation="1,0"
> + position="84,7"
> + id="guide4077" />
> + <sodipodi:guide
> + orientation="0,1"
> + position="58,81"
> + id="guide4074" />
> + <sodipodi:guide
> + orientation="1,0"
> + position="9,74"
> + id="guide4076" />
> + <sodipodi:guide
> + orientation="0,1"
> + position="21,9"
> + id="guide4078" />
> + <sodipodi:guide
> + orientation="1,0"
> + position="81,4"
> + id="guide4080" />
> + </sodipodi:namedview>
> + <metadata
> + id="metadata4879">
> + <rdf:RDF>
> + <cc:Work
> + rdf:about="">
> + <dc:format>image/svg+xml</dc:format>
> + <dc:type
> + rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
> + <dc:title></dc:title>
> + </cc:Work>
> + </rdf:RDF>
> + </metadata>
> + <g
> + inkscape:label="Layer 1"
> + inkscape:groupmode="layer"
> + id="layer1"
> + transform="translate(67.857146,-84.50504)">
> + <g
> + transform="matrix(0,-1,-1,0,373.50506,516.50504)"
> + id="g4845"
> + style="display:inline">
> + <g
> + transform="matrix(0,-1,-1,0,567.36222,615.36221)"
> + id="g1311"
> + inkscape:export-filename="envelope02.png"
> + inkscape:export-xdpi="90"
> + inkscape:export-ydpi="90">
> + <g
> + id="g1313"
> + transform="matrix(1.875,0,0,1.875,-366,-1657.8169)">
> + <rect
> + transform="translate(0,804.3622)"
> + y="152"
> + x="288"
> + height="48"
> + width="48"
> + id="rect1315"
> + style="opacity:0.21171169;fill:none;stroke:none" />
> + </g>
> + <path
> + style="font-size:15px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#808080;fill-opacity:1;stroke:none;display:inline;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
> + d="M 21 6 C 11 6 6 5.9998033 6 17.626953 L 6 72.373047 C 6 84.000207 11 84 21 84 L 69 84 C 79 84 84 84.000207 84 72.373047 L 84 17.626953 C 84 5.9998033 79 6 69 6 L 21 6 z M 22.867188 12 L 67.132812 12 C 75.065512 12 78 11.999356 78 20.191406 L 78 69.808594 C 78 78.000644 75.065512 78 67.132812 78 L 22.867188 78 C 14.934488 78 12 78.000644 12 69.808594 L 12 20.191406 C 12 11.999356 14.934488 12 22.867188 12 z "
> + transform="translate(174,135.36222)"
> + id="path4098" />
> + <path
> + style="font-size:15px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#808080;fill-opacity:1;stroke:none;font-family:Ubuntu;-inkscape-font-specification:Ubuntu"
> + d="m 242.00422,161.6591 -0.375,0.32812 -26.94727,23.60352 -15.79687,-13.55079 -4.77539,5.4004 20.57617,21.64843 31.30078,-32.9375 -3.98242,-4.49218 z"
> + id="path4041-9"
> + inkscape:connector-curvature="0" />
> + </g>
> + </g>
> + </g>
> +</svg>
>
> === modified file 'src/app/main.cpp'
> --- src/app/main.cpp 2015-01-30 18:52:42 +0000
> +++ src/app/main.cpp 2015-02-27 15:45:56 +0000
> @@ -1,5 +1,5 @@
> /*
> - * Copyright: 2013 - 2015 Canonical, Ltd
> + * Copyright: 2015 Canonical Ltd.
> *
> * This file is part of docviewer
> *
> @@ -14,111 +14,23 @@
> * GNU General Public License for more details.
> *
> * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - *
> - * Authors: Michael Zanetti <michael.zanetti@xxxxxxxxxxxxx>
> - * Riccardo Padovani <rpadovani@xxxxxxxxxx>
> - * David Planella <david.planella@xxxxxxxxxx>
> - * Stefano Verzegnassi <stefano92.100@xxxxxxxxx>
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> */
>
> // Uncomment if you need to use QML analyzer
> // #define QT_QML_DEBUG
>
> -#include <QtGui/QGuiApplication>
> -#include <QtQuick/QQuickView>
> -#include <QtQml/QtQml>
> -#include <QLibrary>
> -#include <QDir>
> -
> +#include "docviewer-application.h"
> #include <QDebug>
>
> int main(int argc, char *argv[])
> {
> - QGuiApplication a(argc, argv);
> - QQuickView view;
> - view.setResizeMode(QQuickView::SizeRootObjectToView);
> -
> - view.setPersistentOpenGLContext(false);
> - view.setPersistentSceneGraph(false);
> - view.engine()->rootContext()->setContextProperty("QQuickView", &view);
> -
> - // Set up import paths
> - QStringList importPathList = view.engine()->importPathList();
> - // Prepend the location of the plugin in the build dir,
> - // so that Qt Creator finds it there, thus overriding the one installed
> - // in the sistem if there is one
> - importPathList.prepend(QCoreApplication::applicationDirPath() + "/../plugin/");
> -
> - QStringList args = a.arguments();
> - if (args.contains("-h") || args.contains("--help")) {
> - qDebug() << "usage: " + args.at(0) + " [-h|--help] <path>";
> - qDebug() << " -h|--help Print this help.";
> - qDebug() << " <path> Path of the document to load.";
> + QCoreApplication::setApplicationName("com.ubuntu.docviewer");
> + QCoreApplication::setOrganizationDomain("com.ubuntu.docviewer");
More than setOrganizationDomain, you have to use setOrganizationName, that is used to name the folder in .local/share
> +
> + DocViewerApplication app(argc, argv);
> + if (!app.init())
> return 0;
> - }
> -
> - // Check if the path of the document has been specified.
> - QString docPath;
> - for (int i = 1; i < args.count(); i++) {
> - if (args.at(i) != "-h" && args.at(i) != "--h") {
> - docPath = args.at(i);
> - }
> - }
> - view.engine()->rootContext()->setContextProperty("documentPath", docPath);
> -
> - if (args.contains(QLatin1String("-testability")) || getenv("QT_LOAD_TESTABILITY")) {
> - QLibrary testLib(QLatin1String("qttestability"));
> - if (testLib.load()) {
> - typedef void (*TasInitialize)(void);
> - TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init");
> - if (initFunction) {
> - initFunction();
> - } else {
> - qCritical("Library qttestability resolve failed!");
> - }
> - } else {
> - qCritical("Library qttestability load failed!");
> - }
> - }
> -
> - view.engine()->setImportPathList(importPathList);
> -
> - QString qmlfile;
> - const QString filePath = QLatin1String("qml/ubuntu-docviewer-app.qml");
> - QStringList paths = QStandardPaths::standardLocations(QStandardPaths::DataLocation);
> - paths.prepend(QDir::currentPath());
> - paths.prepend(QCoreApplication::applicationDirPath());
> - Q_FOREACH (const QString &path, paths) {
> - QString myPath = path + QLatin1Char('/') + filePath;
> - if (QFile::exists(myPath)) {
> - qmlfile = myPath;
> - break;
> - }
> - }
> - // sanity check
> - if (qmlfile.isEmpty()) {
> - qFatal("File: %s does not exist at any of the standard paths!", qPrintable(filePath));
> - }
> -
> - // Make sure our cache dir exists. It'll be used all over in this app.
> - // We need to set the applicationName for that.
> - // It'll be overwritten again when qml loads but we need it already now.
> - // So if you want to change it, make sure to find all the places where it is set, not just here :D
> - QCoreApplication::setApplicationName("com.ubuntu.docviewer");
> -
> - QDir cacheDir(QStandardPaths::standardLocations(QStandardPaths::CacheLocation).first());
> - if (!cacheDir.exists()) {
> - qDebug() << "creating cacheDir:" << cacheDir.absolutePath();
> - cacheDir.mkpath(cacheDir.absolutePath());
> - }
> -
> - // Expose quit() signal to QML
> - QObject::connect(view.engine(), SIGNAL(quit()), &a, SLOT(quit()));
> -
> - qDebug() << "using main qml file from:" << qmlfile;
> - view.setSource(QUrl::fromLocalFile(qmlfile));
> - view.show();
> -
> - return a.exec();
> +
> + app.exec();
> }
>
> === removed file 'src/app/qml/ContentHubPicker.qml'
> --- src/app/qml/ContentHubPicker.qml 2015-01-29 16:24:50 +0000
> +++ src/app/qml/ContentHubPicker.qml 1970-01-01 00:00:00 +0000
> @@ -1,71 +0,0 @@
> -/*
> - * Copyright (C) 2014-2015 Canonical, Ltd.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; version 3.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -import QtQuick 2.0
> -import Ubuntu.Components 1.1
> -import Ubuntu.Content 1.1
> -
> -Page {
> - id: picker
> - title: i18n.tr("Open with...")
> -
> - property var activeTransfer
> -
> - head.sections.model: [i18n.tr("Documents"), i18n.tr("Pictures"), i18n.tr("Other")]
> - head.backAction: Action {
> - iconName: "back"
> - text: i18n.tr("Back")
> - onTriggered: pageStack.pop()
> - }
> -
> - ContentPeerPicker {
> - // Do not show ContentPeerPicker header, since we need head.sections.
> - showTitle: false
> -
> - contentType: {
> - switch (picker.head.sections.selectedIndex) {
> - case 0:
> - return ContentType.Documents
> - case 1:
> - return ContentType.Pictures
> - case 2:
> - return ContentType.Unknown
> - }
> - }
> - handler: ContentHandler.Source
> -
> - onPeerSelected: picker.activeTransfer = peer.request();
> - }
> -
> - ContentTransferHint {
> - id: transferHint
> - anchors.fill: parent
> - activeTransfer: picker.activeTransfer
> - }
> -
> - Connections {
> - target: picker.activeTransfer ? picker.activeTransfer : null
> - onStateChanged: {
> - if (picker.activeTransfer.state === ContentTransfer.Charged) {
> - // Close ContentHubPicker page.
> - pageStack.pop();
> -
> - file.path = picker.activeTransfer.items[0].url.toString().replace("file://", "")
> - console.log("[CONTENT-HUB] Content imported!")
> - }
> - }
> - }
> -}
>
> === removed file 'src/app/qml/ContentHubProxy.qml'
> --- src/app/qml/ContentHubProxy.qml 2014-11-04 18:54:38 +0000
> +++ src/app/qml/ContentHubProxy.qml 1970-01-01 00:00:00 +0000
> @@ -1,38 +0,0 @@
> -/*
> - * Copyright (C) 2012-2014 Canonical, Ltd.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; version 3.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -import QtQuick 2.3
> -import Ubuntu.Content 1.1 as ContentHub
> -
> -QtObject {
> - property QtObject pageStack: null
> - property list<QtObject> objects: [
> - Connections {
> - target: ContentHub.ContentHub
> -
> - onImportRequested: {
> - if (transfer.state === ContentHub.ContentTransfer.Charged) {
> - // We have no signals to know if an import was requested before Component.completed signal
> - // is emitted. So clear the stack when this occurs.
> - pageStack.clear()
> -
> - console.log("[CONTENT-HUB] Incoming Import Request")
> - file.path = transfer.items[0].url.toString().replace("file://", "");
> - }
> - }
> - }
> - ]
> -}
>
> === removed file 'src/app/qml/DetailsPage.qml'
> --- src/app/qml/DetailsPage.qml 2015-01-29 16:24:50 +0000
> +++ src/app/qml/DetailsPage.qml 1970-01-01 00:00:00 +0000
> @@ -1,58 +0,0 @@
> -/*
> - * Copyright (C) 2013-2014 Canonical, Ltd.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; version 3.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -import QtQuick 2.3
> -import Ubuntu.Components 1.1
> -import Ubuntu.Components.ListItems 1.0 as ListItem
> -
> -import "utils.js" as Utils
> -
> -Page {
> - id: detailsPage
> - objectName: "detailsPage"
> -
> - title: i18n.tr("Details")
> -
> - Column {
> - width: parent.width
> -
> - ListItem.Subtitled {
> - text: i18n.tr("Location")
> - subText: file.path
> - }
> - ListItem.Subtitled {
> - text: i18n.tr("Size")
> - subText: Utils.printSize(file.size)
> - }
> -
> - ListItem.Subtitled {
> - text: i18n.tr("Created")
> - subText: file.creationTime.toLocaleString(Qt.locale())
> - }
> -
> - ListItem.Subtitled {
> - text: i18n.tr("Last modified")
> - subText: file.lastModified.toLocaleString(Qt.locale())
> - }
> -
> - ListItem.Subtitled {
> - id: mimetypeItem
> - objectName: "mimetypeItem"
> - text: i18n.tr("MIME type")
> - subText: file.mimetype
> - }
> - }
> -}
>
> === removed file 'src/app/qml/EmptyState.qml'
> --- src/app/qml/EmptyState.qml 2015-01-16 16:46:46 +0000
> +++ src/app/qml/EmptyState.qml 1970-01-01 00:00:00 +0000
> @@ -1,59 +0,0 @@
> -/*
> - * Copyright (C) 2014 Canonical Ltd
> - *
> - * This file is part of Ubuntu Clock App
> - *
> - * Ubuntu Clock App is free software: you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License version 3 as
> - * published by the Free Software Foundation.
> - *
> - * Ubuntu Clock App is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -import QtQuick 2.3
> -import Ubuntu.Components 1.1
> -
> -/*
> - Component which displays an empty state (approved by design). It offers an
> - icon, title and subtitle to describe the empty state.
> -*/
> -
> -Item {
> - id: emptyState
> -
> - // Public APIs
> - property alias iconName: emptyIcon.name
> - property alias title: emptyLabel.text
> - property alias subTitle: emptySublabel.text
> -
> - height: childrenRect.height
> -
> - Icon {
> - id: emptyIcon
> - anchors.horizontalCenter: parent.horizontalCenter
> - height: units.gu(10)
> - width: height
> - color: "#BBBBBB"
> - }
> -
> - Label {
> - id: emptyLabel
> - anchors.top: emptyIcon.bottom
> - anchors.topMargin: units.gu(5)
> - anchors.horizontalCenter: parent.horizontalCenter
> - fontSize: "large"
> - font.bold: true
> - }
> -
> - Label {
> - id: emptySublabel
> - anchors.top: emptyLabel.bottom
> - anchors.horizontalCenter: parent.horizontalCenter
> - }
> -}
>
> === removed file 'src/app/qml/ErrorDialog.qml'
> --- src/app/qml/ErrorDialog.qml 2015-01-29 19:14:08 +0000
> +++ src/app/qml/ErrorDialog.qml 1970-01-01 00:00:00 +0000
> @@ -1,32 +0,0 @@
> -/*
> - * Copyright (C) 2014-2015 Canonical, Ltd.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; version 3.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -import QtQuick 2.3
> -import Ubuntu.Components 1.1
> -import Ubuntu.Components.Popups 1.0
> -
> -Dialog {
> - id: errorDialog
> - title: i18n.tr("Error")
> - text: i18n.tr("File does not exist")
> -
> - Button {
> - text: i18n.tr("Close")
> - color: UbuntuColors.red
> -
> - onClicked: Qt.quit();
> - }
> -}
>
> === removed file 'src/app/qml/ImageView.qml'
> --- src/app/qml/ImageView.qml 2015-02-03 21:11:52 +0000
> +++ src/app/qml/ImageView.qml 1970-01-01 00:00:00 +0000
> @@ -1,48 +0,0 @@
> -/*
> - * Copyright (C) 2013-2015 Canonical, Ltd.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; version 3.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -import QtQuick 2.3
> -import Ubuntu.Components 1.1
> -
> -import "utils.js" as Utils
> -
> -Page {
> - id: imagePage
> - title: Utils.getNameOfFile(file.path);
> -
> - Rectangle {
> - anchors.fill: parent
> - color: "#221E1C" // SuruDark.Palette.Normal.Background
> - }
> -
> - ZoomableImage {
> - id: zoomableImage
> - anchors.fill: parent
> -
> - zoomable: true
> - source: file.path
> - }
> -
> - // *** HEADER ***
> - state: "default"
> - states: [
> - ImageViewDefaultHeader {
> - name: "default"
> - targetPage: imagePage
> - activityRunning: zoomableImage.imageStatus == Image.Loading
> - }
> - ]
> -}
>
> === removed file 'src/app/qml/ImageViewDefaultHeader.qml'
> --- src/app/qml/ImageViewDefaultHeader.qml 2015-02-03 21:11:52 +0000
> +++ src/app/qml/ImageViewDefaultHeader.qml 1970-01-01 00:00:00 +0000
> @@ -1,74 +0,0 @@
> -/*
> - * Copyright (C) 2014-2015 Canonical, Ltd.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; version 3.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -import QtQuick 2.3
> -import Ubuntu.Components 1.1
> -import QtQuick.Layouts 1.1
> -import Ubuntu.Components.Popups 1.0
> -
> -PageHeadState {
> - id: rootItem
> -
> - property Page targetPage
> - property alias activityRunning: activity.running
> -
> - head: targetPage.head
> -
> - contents: RowLayout {
> - anchors.fill: parent
> - spacing: units.gu(1)
> -
> - ActivityIndicator { id: activity }
> -
> - Column {
> - id: layout
> - Layout.fillWidth: true
> -
> - Label {
> - width: parent.width
> - //horizontalAlignment: Text.AlignHCenter
> - elide: Text.ElideMiddle
> -
> - font.weight: Font.DemiBold
> - text: targetPage.title
> - }
> - }
> - }
> -
> - backAction: Action {
> - iconName: "back"
> - text: (pageStack.depth > 1) ? i18n.tr("Back") : i18n.tr("Close")
> - onTriggered: {
> - if (pageStack.depth > 1) {
> - // Go back to Welcome page
> - pageStack.pop();
> - } else {
> - // File has been imported through Content Hub (or was not chosen through WelcomePage)
> - // Close the application and show our source app (e.g. ubuntu-filemanager-app, if used to open a document)
> - Qt.quit()
> - }
> - }
> - }
> -
> - actions: [
> - Action {
> - objectName: "detailsAction"
> - text: i18n.tr("Details")
> - iconName: "info"
> - onTriggered: pageStack.push(Qt.resolvedUrl("DetailsPage.qml"))
> - }
> - ]
> -}
>
> === removed file 'src/app/qml/PageWithBottomEdge.qml'
> --- src/app/qml/PageWithBottomEdge.qml 2015-02-04 19:19:21 +0000
> +++ src/app/qml/PageWithBottomEdge.qml 1970-01-01 00:00:00 +0000
> @@ -1,407 +0,0 @@
> -/*
> - * Copyright (C) 2014 Canonical, Ltd.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; version 3.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -/*
> - Example:
> -
> - MainView {
> - objectName: "mainView"
> -
> - applicationName: "com.ubuntu.developer.boiko.bottomedge"
> -
> - width: units.gu(100)
> - height: units.gu(75)
> -
> - Component {
> - id: pageComponent
> -
> - PageWithBottomEdge {
> - id: mainPage
> - title: i18n.tr("Main Page")
> -
> - Rectangle {
> - anchors.fill: parent
> - color: "white"
> - }
> -
> - bottomEdgePageComponent: Page {
> - title: "Contents"
> - anchors.fill: parent
> - //anchors.topMargin: contentsPage.flickable.contentY
> -
> - ListView {
> - anchors.fill: parent
> - model: 50
> - delegate: ListItems.Standard {
> - text: "One Content Item: " + index
> - }
> - }
> - }
> - bottomEdgeTitle: i18n.tr("Bottom edge action")
> - }
> - }
> -
> - PageStack {
> - id: stack
> - Component.onCompleted: stack.push(pageComponent)
> - }
> - }
> -
> -*/
> -
> -import QtQuick 2.2
> -import Ubuntu.Components 1.1
> -
> -Page {
> - id: page
> -
> - property alias bottomEdgePageComponent: edgeLoader.sourceComponent
> - property alias bottomEdgePageSource: edgeLoader.source
> - property alias bottomEdgeTitle: tipLabel.text
> - property bool bottomEdgeEnabled: true
> - property int bottomEdgeExpandThreshold: page.height * 0.2
> - property int bottomEdgeExposedArea: bottomEdge.state !== "expanded" ? (page.height - bottomEdge.y - bottomEdge.tipHeight) : _areaWhenExpanded
> - property bool reloadBottomEdgePage: true
> -
> - readonly property alias bottomEdgePage: edgeLoader.item
> - readonly property bool isReady: ((bottomEdge.y === 0) && bottomEdgePageLoaded && edgeLoader.item.active)
> - readonly property bool isCollapsed: (bottomEdge.y === page.height)
> - readonly property bool bottomEdgePageLoaded: (edgeLoader.status == Loader.Ready)
> -
> - property bool _showEdgePageWhenReady: false
> - property int _areaWhenExpanded: 0
> -
> - signal bottomEdgeReleased()
> - signal bottomEdgeDismissed()
> -
> -
> - function showBottomEdgePage(source, properties)
> - {
> - edgeLoader.setSource(source, properties)
> - _showEdgePageWhenReady = true
> - }
> -
> - function setBottomEdgePage(source, properties)
> - {
> - edgeLoader.setSource(source, properties)
> - }
> -
> - function _pushPage()
> - {
> - if (edgeLoader.status === Loader.Ready) {
> - edgeLoader.item.active = true
> - page.pageStack.push(edgeLoader.item)
> - if (edgeLoader.item.flickable) {
> - edgeLoader.item.flickable.contentY = -page.header.height
> - edgeLoader.item.flickable.returnToBounds()
> - }
> - if (edgeLoader.item.ready)
> - edgeLoader.item.ready()
> - }
> - }
> -
> -
> - Component.onCompleted: {
> - // avoid a binding on the expanded height value
> - var expandedHeight = height;
> - _areaWhenExpanded = expandedHeight;
> - }
> -
> - onActiveChanged: {
> - if (active) {
> - bottomEdge.state = "collapsed"
> - }
> - }
> -
> - onBottomEdgePageLoadedChanged: {
> - if (_showEdgePageWhenReady && bottomEdgePageLoaded) {
> - bottomEdge.state = "expanded"
> - _showEdgePageWhenReady = false
> - }
> - }
> -
> - Rectangle {
> - id: bgVisual
> -
> - color: "black"
> - anchors.fill: page
> - opacity: 0.7 * ((page.height - bottomEdge.y) / page.height)
> - z: 1
> - }
> -
> - UbuntuShape {
> - id: tip
> - objectName: "bottomEdgeTip"
> -
> - property bool hidden: (activeFocus === false) || ((bottomEdge.y - units.gu(1)) < tip.y)
> -
> - enabled: mouseArea.enabled
> - visible: page.bottomEdgeEnabled
> - anchors {
> - bottom: parent.bottom
> - horizontalCenter: bottomEdge.horizontalCenter
> - bottomMargin: hidden ? - height + units.gu(1) : -units.gu(1)
> - Behavior on bottomMargin {
> - SequentialAnimation {
> - // wait some msecs in case of the focus change again, to avoid flickering
> - PauseAnimation {
> - duration: 300
> - }
> - UbuntuNumberAnimation {
> - duration: UbuntuAnimation.SnapDuration
> - }
> - }
> - }
> - }
> -
> - z: 1
> - width: tipLabel.paintedWidth + units.gu(6)
> - height: bottomEdge.tipHeight + units.gu(1)
> - color: Theme.palette.normal.overlay
> - Label {
> - id: tipLabel
> -
> - anchors {
> - top: parent.top
> - left: parent.left
> - right: parent.right
> - }
> - height: bottomEdge.tipHeight
> - verticalAlignment: Text.AlignVCenter
> - horizontalAlignment: Text.AlignHCenter
> - opacity: tip.hidden ? 0.0 : 1.0
> - Behavior on opacity {
> - UbuntuNumberAnimation {
> - duration: UbuntuAnimation.SnapDuration
> - }
> - }
> - }
> - }
> -
> - Rectangle {
> - id: shadow
> -
> - anchors {
> - left: parent.left
> - right: parent.right
> - bottom: parent.bottom
> - }
> - height: units.gu(1)
> - z: 1
> - opacity: 0.0
> - gradient: Gradient {
> - GradientStop { position: 0.0; color: "transparent" }
> - GradientStop { position: 1.0; color: Qt.rgba(0, 0, 0, 0.2) }
> - }
> - }
> -
> - MouseArea {
> - id: mouseArea
> -
> - property real previousY: -1
> - property string dragDirection: "None"
> -
> - preventStealing: true
> - drag {
> - axis: Drag.YAxis
> - target: bottomEdge
> - minimumY: bottomEdge.pageStartY
> - maximumY: page.height
> - }
> - enabled: edgeLoader.status == Loader.Ready
> - visible: page.bottomEdgeEnabled
> -
> - anchors {
> - left: parent.left
> - right: parent.right
> - bottom: parent.bottom
> -
> - }
> - height: bottomEdge.tipHeight
> - z: 1
> -
> - onReleased: {
> - page.bottomEdgeReleased()
> - if ((dragDirection === "BottomToTop") &&
> - bottomEdge.y < (page.height - bottomEdgeExpandThreshold - bottomEdge.tipHeight)) {
> - bottomEdge.state = "expanded"
> - } else {
> - bottomEdge.state = "collapsed"
> - }
> - previousY = -1
> - dragDirection = "None"
> - }
> -
> - onPressed: {
> - previousY = mouse.y
> - tip.forceActiveFocus()
> - }
> -
> - onMouseYChanged: {
> - var yOffset = previousY - mouseY
> - // skip if was a small move
> - if (Math.abs(yOffset) <= units.gu(2)) {
> - return
> - }
> - previousY = mouseY
> - dragDirection = yOffset > 0 ? "BottomToTop" : "TopToBottom"
> - }
> - }
> -
> - Rectangle {
> - id: bottomEdge
> - objectName: "bottomEdge"
> -
> - readonly property int tipHeight: units.gu(3)
> - readonly property int pageStartY: 0
> -
> - z: 1
> - color: Theme.palette.normal.background
> - clip: true
> - anchors {
> - left: parent.left
> - right: parent.right
> - }
> - height: page.height
> - y: height
> - visible: !page.isCollapsed
> - state: "collapsed"
> - states: [
> - State {
> - name: "collapsed"
> - PropertyChanges {
> - target: bottomEdge
> - y: bottomEdge.height
> - }
> - },
> - State {
> - name: "expanded"
> - PropertyChanges {
> - target: bottomEdge
> - y: bottomEdge.pageStartY
> - }
> - },
> - State {
> - name: "floating"
> - when: mouseArea.drag.active
> - PropertyChanges {
> - target: shadow
> - opacity: 1.0
> - }
> - }
> - ]
> -
> - transitions: [
> - Transition {
> - to: "expanded"
> - SequentialAnimation {
> - alwaysRunToEnd: true
> -
> - SmoothedAnimation {
> - target: bottomEdge
> - property: "y"
> - duration: UbuntuAnimation.FastDuration
> - easing.type: Easing.Linear
> - }
> - SmoothedAnimation {
> - target: edgeLoader
> - property: "anchors.topMargin"
> - to: - units.gu(4)
> - duration: UbuntuAnimation.FastDuration
> - easing.type: Easing.Linear
> - }
> - SmoothedAnimation {
> - target: edgeLoader
> - property: "anchors.topMargin"
> - to: 0
> - duration: UbuntuAnimation.FastDuration
> - easing: UbuntuAnimation.StandardEasing
> - }
> - ScriptAction {
> - script: page._pushPage()
> - }
> - }
> - },
> - Transition {
> - from: "expanded"
> - to: "collapsed"
> - SequentialAnimation {
> - alwaysRunToEnd: true
> -
> - ScriptAction {
> - script: {
> - Qt.inputMethod.hide()
> - edgeLoader.item.parent = edgeLoader
> - edgeLoader.item.anchors.fill = edgeLoader
> - edgeLoader.item.active = false
> - }
> - }
> - SmoothedAnimation {
> - target: bottomEdge
> - property: "y"
> - duration: UbuntuAnimation.SlowDuration
> - }
> - ScriptAction {
> - script: {
> - // destroy current bottom page
> - if (page.reloadBottomEdgePage) {
> - edgeLoader.active = false
> - // tip will receive focus on page active true
> - } else {
> - tip.forceActiveFocus()
> - }
> -
> - // notify
> - page.bottomEdgeDismissed()
> -
> - edgeLoader.active = true
> - }
> - }
> - }
> - },
> - Transition {
> - from: "floating"
> - to: "collapsed"
> - SmoothedAnimation {
> - target: bottomEdge
> - property: "y"
> - duration: UbuntuAnimation.FastDuration
> - }
> - }
> - ]
> -
> - Loader {
> - id: edgeLoader
> -
> - asynchronous: true
> - anchors.fill: parent
> - //WORKAROUND: The SDK move the page contents down to allocate space for the header we need to avoid that during the page dragging
> - Binding {
> - target: edgeLoader.status === Loader.Ready ? edgeLoader : null
> - property: "anchors.topMargin"
> - value: edgeLoader.item && edgeLoader.item.flickable ? edgeLoader.item.flickable.contentY : 0
> - when: !page.isReady
> - }
> -
> - onLoaded: {
> - tip.forceActiveFocus()
> - if (page.isReady && edgeLoader.item.active !== true) {
> - page._pushPage()
> - }
> - }
> - }
> - }
> -}
>
> === removed file 'src/app/qml/PdfContentsPage.qml'
> --- src/app/qml/PdfContentsPage.qml 2015-02-05 16:40:16 +0000
> +++ src/app/qml/PdfContentsPage.qml 1970-01-01 00:00:00 +0000
> @@ -1,60 +0,0 @@
> -/*
> - * Copyright (C) 2014, 2015
> - * Stefano Verzegnassi <verzegnassi.stefano@xxxxxxxxx>
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; version 3.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -import QtQuick 2.0
> -import Ubuntu.Components 1.1
> -import QtQuick.Layouts 1.1
> -import Ubuntu.Components.ListItems 1.0 as ListItem
> -
> -Page {
> - title: i18n.tr("Contents")
> -
> - ListView {
> - anchors.fill: parent
> -
> - model: poppler.tocModel
> -
> - delegate: ListItem.Base {
> - showDivider: model.level == 0
> -
> - onClicked: {
> - pdfView.positionAtIndex(model.pageIndex);
> - pageStack.pop();
> - }
> -
> - RowLayout {
> - anchors.fill: parent
> - anchors.leftMargin: units.gu(2) * model.level
> -
> - spacing: units.gu(1)
> -
> - Label {
> - Layout.fillWidth: true
> -
> - text: (typeof model.title === "undefined") ? "" : model.title;
> - elide: Text.ElideRight
> - Component.onCompleted: { if (model.level === 0); font.weight = Font.DemiBold; }
> - }
> -
> - Label {
> - text: (typeof model.pageIndex === "undefined") ? "" : model.pageIndex + 1;
> - Component.onCompleted: { if (model.level === 0); font.weight = Font.DemiBold; }
> - }
> - }
> - }
> - }
> -}
>
> === removed file 'src/app/qml/PdfView.qml'
> --- src/app/qml/PdfView.qml 2015-02-09 12:00:58 +0000
> +++ src/app/qml/PdfView.qml 1970-01-01 00:00:00 +0000
> @@ -1,107 +0,0 @@
> -/*
> - * Copyright (C) 2013-2014 Canonical, Ltd.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; version 3.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -import QtQuick 2.3
> -import Ubuntu.Components 1.1
> -import com.ubuntu.popplerqmlplugin 1.0 as PDF
> -
> -import "utils.js" as Utils
> -
> -PageWithBottomEdge {
> - id: pdfPage
> - title: Utils.getNameOfFile(file.path);
> -
> - // Disable header auto-hide.
> - // TODO: Show/hide header if a user taps the page
> - flickable: null
> -
> - property string currentPage: i18n.tr("Page %1 of %2").arg(pdfView.currentPageIndex + 1).arg(pdfView.count)
> -
> - bottomEdgeTitle: i18n.tr("Contents")
> - bottomEdgePageComponent: PdfContentsPage {}
> - bottomEdgeEnabled: poppler.tocModel.count > 0
> -
> - PDF.VerticalView {
> - id: pdfView
> - objectName: "pdfView"
> - anchors.fill: parent
> - spacing: units.gu(2)
> -
> - clip: true
> - boundsBehavior: Flickable.StopAtBounds
> - flickDeceleration: 1500 * units.gridUnit / 8
> - maximumFlickVelocity: 2500 * units.gridUnit / 8
> -
> - contentWidth: parent.width * _zoomHelper.scale
> - cacheBuffer: height * poppler.providersNumber * _zoomHelper.scale * 0.5
> - interactive: !pinchy.pinch.active
> -
> - model: poppler
> - delegate: PdfViewDelegate {
> - Component.onDestruction: QQuickView.releaseResources()
> - }
> -
> - // FIXME: On zooming, keep the same content position.
> - PinchArea {
> - id: pinchy
> - anchors.fill: parent
> -
> - pinch {
> - target: _zoomHelper
> - minimumScale: 1.0
> - maximumScale: 2.5
> - }
> -
> - onPinchFinished: {
> - pdfView.returnToBounds();
> -
> - // This is a bit expensive, so it's safer to put it here.
> - // It won't be called on desktop (where PinchArea is not used),
> - // but it's not a problem at the moment (our target is phone).
> - QQuickView.releaseResources();
> - }
> - }
> -
> - Item { id: _zoomHelper }
> - }
> -
> - Scrollbar { flickableItem: pdfView }
> - Scrollbar { flickableItem: pdfView; align: Qt.AlignBottom }
> -
> - PDF.Document {
> - id: poppler
> -
> - property bool isLoading: true
> -
> - Component.onCompleted: path = file.path
> - onPagesLoaded: {
> - isLoading = false;
> -
> - var title = getDocumentInfo("Title")
> - if (title !== "")
> - pdfPage.title = title
> - }
> - }
> -
> -
> - // *** HEADER ***
> - state: "default"
> - states: PdfViewDefaultHeader {
> - name: "default"
> - targetPage: pdfPage
> - activityRunning: pdfView.currentPageItem.status == Image.Loading || poppler.isLoading
> - }
> -}
>
> === removed file 'src/app/qml/PdfViewDefaultHeader.qml'
> --- src/app/qml/PdfViewDefaultHeader.qml 2015-02-03 21:11:52 +0000
> +++ src/app/qml/PdfViewDefaultHeader.qml 1970-01-01 00:00:00 +0000
> @@ -1,96 +0,0 @@
> -/*
> - * Copyright (C) 2014-2015 Canonical, Ltd.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; version 3.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -import QtQuick 2.3
> -import Ubuntu.Components 1.1
> -import QtQuick.Layouts 1.1
> -import Ubuntu.Components.Popups 1.0
> -
> -PageHeadState {
> - id: rootItem
> -
> - property Page targetPage
> - property alias activityRunning: activity.running
> -
> - head: targetPage.head
> -
> - contents: RowLayout {
> - anchors.fill: parent
> - spacing: units.gu(1)
> -
> - ActivityIndicator { id: activity }
> -
> - Column {
> - id: layout
> - Layout.fillWidth: true
> -
> - Label {
> - width: parent.width
> - //horizontalAlignment: Text.AlignHCenter
> - elide: Text.ElideMiddle
> -
> - font.weight: Font.DemiBold
> - text: targetPage.title
> - }
> - Label {
> - width: parent.width
> - //horizontalAlignment: Text.AlignHCenter
> - elide: Text.ElideMiddle
> -
> - fontSize: "small"
> - text: targetPage.currentPage
> - }
> - }
> - }
> -
> - backAction: Action {
> - iconName: "back"
> - text: (pageStack.depth > 1) ? i18n.tr("Back") : i18n.tr("Close")
> - onTriggered: {
> - if (pageStack.depth > 1) {
> - // Go back to Welcome page
> - pageStack.pop();
> - } else {
> - // File has been imported through Content Hub (or was not chosen through WelcomePage)
> - // Close the application and show our source app (e.g. ubuntu-filemanager-app, if used to open a document)
> - Qt.quit()
> - }
> - }
> - }
> -
> - actions: [
> - Action {
> - iconName: "search"
> - // onTriggered: pageMain.state = "search"
> - //Disable it until we provide search in Poppler plugin.
> - enabled: false
> - },
> -
> - Action {
> - objectName:"gotopage"
> - iconName: "browser-tabs"
> - text: "Go to page..."
> - onTriggered: PopupUtils.open(Qt.resolvedUrl("PdfViewGotoDialog.qml"), targetPage)
> - },
> -
> - Action {
> - objectName: "detailsAction"
> - text: i18n.tr("Details")
> - iconName: "info"
> - onTriggered: pageStack.push(Qt.resolvedUrl("DetailsPage.qml"))
> - }
> - ]
> -}
>
> === removed file 'src/app/qml/PdfViewDelegate.qml'
> --- src/app/qml/PdfViewDelegate.qml 2015-02-03 21:05:26 +0000
> +++ src/app/qml/PdfViewDelegate.qml 1970-01-01 00:00:00 +0000
> @@ -1,95 +0,0 @@
> -/*
> - * Copyright (C) 2013-2015 Canonical, Ltd.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; version 3.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -import QtQuick 2.3
> -import Ubuntu.Components 1.1
> -
> -Rectangle {
> - id: pdfPage
> -
> - property int index: model.index
> - property bool _previewFetched: false
> -
> - property alias status: pageImg.status
> -
> - width: parent.width
> - height: width * (model.height / model.width)
> - color: "#E6E6E6"
> -
> - // Preview page rendering. Used as placeholder while zooming the page.
> - // We generate the low resolution preview from the texture of the PDF page,
> - // so that we can keep page rendering as fast as possible.
> - ShaderEffectSource {
> - id: previewImg
> - anchors.fill: parent
> -
> - // We cannot change its opacity or visibility, otherwise the texture will be refreshed,
> - // even if live is false.
> - live: false
> - textureSize: Qt.size(256, 256 * (model.height / model.width))
> - }
> -
> - Image {
> - id: pageImg
> - anchors.fill: parent
> -
> - source: "image://poppler" + (index % poppler.providersNumber) + "/page/" + index;
> - sourceSize.width: pdfPage.width
> -
> - onStatusChanged: {
> - // This is supposed to run the first time PdfViewDelegate gets the page rendering.
> - if (!_previewFetched) {
> - if (status == Image.Ready) {
> - previewImg.sourceItem = pageImg
> - // Re-assign sourceItem property, so the texture is not updated when Image status changes.
> - previewImg.sourceItem = pdfPage
> - }
> - }
> - }
> -
> - // Request a new page rendering. The order, which pages are requested with, depends on the distance from the currentPage
> - Timer {
> - id: _zoomTimer
> - interval: {
> - var diff = Math.abs(pdfView.currentPageIndex - model.index)
> - var prov = poppler.providersNumber * 0.5
> -
> - if (diff < prov)
> - return 0
> - else
> - return (diff - prov) * 10
> - }
> -
> - onTriggered: {
> - pageImg.sourceSize.width = pdfPage.width;
> - }
> - }
> - }
> -
> - // Page rendering depends on the width of PdfViewDelegate.
> - // Because of this, we have multiple callings to ImageProvider while zooming.
> - // Just avoid it.
> - Connections {
> - target: pinchy
> -
> - onPinchStarted: _zoomTimer.stop();
> - onPinchUpdated: {
> - // This ensures that page image is not reloaded when the maximumScale or minimumScale has already been reached.
> - if ( !(_zoomHelper.scale >= 2.5 && pinch.scale > 1.0) && !(_zoomHelper.scale <= 1.0 && pinch.scale < 1.0) )
> - pageImg.sourceSize.width = 0;
> - }
> - onPinchFinished: _zoomTimer.restart();
> - }
> -}
>
> === removed file 'src/app/qml/PdfViewGotoDialog.qml'
> --- src/app/qml/PdfViewGotoDialog.qml 2015-01-30 19:37:00 +0000
> +++ src/app/qml/PdfViewGotoDialog.qml 1970-01-01 00:00:00 +0000
> @@ -1,60 +0,0 @@
> -/*
> - * Copyright (C) 2014-2015 Canonical, Ltd.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; version 3.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -import QtQuick 2.3
> -import Ubuntu.Components 1.1
> -import Ubuntu.Components.Popups 1.0
> -
> -Dialog {
> - id: goToPageDialog
> - objectName:"PdfViewGotoDialog"
> -
> - title: i18n.tr("Go to page")
> - text: i18n.tr("Choose a page between 1 and %1").arg(pdfView.count)
> -
> - TextField {
> - id: goToPageTextField
> - objectName:"goToPageTextField"
> -
> - width: parent.width
> -
> - hasClearButton: true
> - inputMethodHints: Qt.ImhFormattedNumbersOnly
> - validator: IntValidator{ bottom: 1; top: pdfView.count }
> -
> - Keys.onReturnPressed: goToPage()
> - Component.onCompleted: forceActiveFocus()
> - }
> -
> - Button {
> - objectName:"GOButton"
> - text: i18n.tr("GO!")
> - color: UbuntuColors.orange
> -
> - enabled: goToPageTextField.acceptableInput
> - onClicked: goToPage()
> - }
> -
> - Button {
> - text: i18n.tr("Cancel")
> - onClicked: PopupUtils.close(goToPageDialog)
> - }
> -
> - function goToPage() {
> - pdfView.positionAtIndex((goToPageTextField.text - 1))
> - PopupUtils.close(goToPageDialog)
> - }
> -}
>
> === removed file 'src/app/qml/TextView.qml'
> --- src/app/qml/TextView.qml 2015-01-30 19:44:52 +0000
> +++ src/app/qml/TextView.qml 1970-01-01 00:00:00 +0000
> @@ -1,70 +0,0 @@
> -/*
> - * Copyright (C) 2013-2015 Canonical, Ltd.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; version 3.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -import QtQuick 2.3
> -import Ubuntu.Components 1.1
> -import Ubuntu.Components.Themes.Ambiance 0.1
> -
> -import "utils.js" as Utils
> -
> -Page {
> - id: textPage
> - title: Utils.getNameOfFile(file.path);
> -
> - TextArea {
> - id: textAreaMain
> - objectName: "textAreaMain"
> -
> - property bool isLoading: true
> -
> - anchors.fill: parent
> -
> - // FIXME: If set to true, some of the keyboard hooks are disabled
> - // And it's not possible to move the cursor with arrow keys.
> - readOnly: true
> -
> - text: i18n.tr("Loading...")
> - font.family: "UbuntuMono"
> -
> - Component.onCompleted: {
> - var xhr = new XMLHttpRequest;
> -
> - xhr.open("GET", file.path);
> - xhr.onreadystatechange = function() {
> - if (xhr.readyState === XMLHttpRequest.DONE) {
> - textAreaMain.text = xhr.responseText;
> - textAreaMain.isLoading = false
> - }
> - };
> -
> - xhr.send();
> - }
> -
> - style: TextAreaStyle {
> - background: Rectangle { color: "white" }
> - }
> - }
> -
> - // *** HEADER ***
> - state: "default"
> - states: [
> - TextViewDefaultHeader {
> - name: "default"
> - targetPage: textPage
> - activityRunning: textAreaMain.isLoading
> - }
> - ]
> -}
>
> === removed file 'src/app/qml/TextViewDefaultHeader.qml'
> --- src/app/qml/TextViewDefaultHeader.qml 2015-02-03 21:11:52 +0000
> +++ src/app/qml/TextViewDefaultHeader.qml 1970-01-01 00:00:00 +0000
> @@ -1,82 +0,0 @@
> -/*
> - * Copyright (C) 2014-2015 Canonical, Ltd.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; version 3.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -import QtQuick 2.3
> -import Ubuntu.Components 1.1
> -import QtQuick.Layouts 1.1
> -import Ubuntu.Components.Popups 1.0
> -
> -PageHeadState {
> - id: rootItem
> -
> - property Page targetPage
> - property alias activityRunning: activity.running
> -
> - head: targetPage.head
> -
> - contents: RowLayout {
> - anchors.fill: parent
> - spacing: units.gu(1)
> -
> - ActivityIndicator { id: activity }
> -
> - Column {
> - id: layout
> - Layout.fillWidth: true
> -
> - Label {
> - width: parent.width
> - //horizontalAlignment: Text.AlignHCenter
> - elide: Text.ElideMiddle
> -
> - font.weight: Font.DemiBold
> - text: targetPage.title
> - }
> - Label {
> - width: parent.width
> - //horizontalAlignment: Text.AlignHCenter
> - elide: Text.ElideMiddle
> -
> - fontSize: "small"
> - text: file.description
> - }
> - }
> - }
> -
> - backAction: Action {
> - iconName: "back"
> - text: (pageStack.depth > 1) ? i18n.tr("Back") : i18n.tr("Close")
> - onTriggered: {
> - if (pageStack.depth > 1) {
> - // Go back to Welcome page
> - pageStack.pop();
> - } else {
> - // File has been imported through Content Hub (or was not chosen through WelcomePage)
> - // Close the application and show our source app (e.g. ubuntu-filemanager-app, if used to open a document)
> - Qt.quit()
> - }
> - }
> - }
> -
> - actions: [
> - Action {
> - objectName: "detailsAction"
> - text: i18n.tr("Details")
> - iconName: "info"
> - onTriggered: pageStack.push(Qt.resolvedUrl("DetailsPage.qml"))
> - }
> - ]
> -}
>
> === removed file 'src/app/qml/UnknownTypeDialog.qml'
> --- src/app/qml/UnknownTypeDialog.qml 2015-01-29 18:09:26 +0000
> +++ src/app/qml/UnknownTypeDialog.qml 1970-01-01 00:00:00 +0000
> @@ -1,43 +0,0 @@
> -/*
> - * Copyright (C) 2013-2015 Canonical, Ltd.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; version 3.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -import QtQuick 2.3
> -import Ubuntu.Components 1.1
> -import Ubuntu.Components.Popups 1.0
> -
> -import "loadComponent.js" as LoadComponent
> -
> -Dialog {
> - id: unknownDialog
> - objectName: "unknownDialog"
> - title: i18n.tr("Unknown file type")
> - text: i18n.tr("Sorry but we can't find a way to display this file. Do you want to open it as a plain text?")
> - Button {
> - text: i18n.tr("Yes")
> - color: UbuntuColors.green
> -
> - onClicked: {
> - LoadComponent.load("text/plain");
> - PopupUtils.close(unknownDialog)
> - }
> - }
> - Button {
> - text: i18n.tr("No")
> - color: UbuntuColors.red
> - onClicked: PopupUtils.close(unknownDialog)
> - }
> -}
> -
>
> === removed file 'src/app/qml/WelcomePage.qml'
> --- src/app/qml/WelcomePage.qml 2015-01-29 16:24:50 +0000
> +++ src/app/qml/WelcomePage.qml 1970-01-01 00:00:00 +0000
> @@ -1,42 +0,0 @@
> -/*
> - * Copyright (C) 2015 Canonical, Ltd.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; version 3.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -import QtQuick 2.0
> -import Ubuntu.Components 1.1
> -
> -Page {
> - id: welcomePage
> -
> - title: i18n.tr("Document Viewer")
> - head.actions: [ openAction ]
> -
> - EmptyState {
> - title: i18n.tr("No opened documents")
> - subTitle: i18n.tr("Tap the + icon to open a document")
> -
> - iconName: "edit-copy"
> -
> - anchors.centerIn: parent
> - }
> -
> - Action {
> - id: openAction
> - text: i18n.tr("Open a file...")
> - iconName: "add"
> -
> - onTriggered: pageStack.push(Qt.resolvedUrl("ContentHubPicker.qml"))
> - }
> -}
>
> === removed file 'src/app/qml/ZoomableImage.qml'
> --- src/app/qml/ZoomableImage.qml 2014-11-08 10:59:51 +0000
> +++ src/app/qml/ZoomableImage.qml 1970-01-01 00:00:00 +0000
> @@ -1,155 +0,0 @@
> -/*
> - * Copyright (C) 2014 Canonical, Ltd.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; version 3.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -import QtQuick 2.0
> -import Ubuntu.Components 0.1
> -
> -/*! \brief Zoomable for image.
> -
> - This widget shows image contained in source,
> - can be zoomable accordingly with zoomable.
> - */
> -
> -Item {
> - id: root
> - property alias source: imageRenderer.source
> - property var zoomable: false
> - property alias imageStatus: imageRenderer.status
> - property alias asynchronous: imageRenderer.asynchronous
> -
> - Flickable {
> - id: flickable
> - objectName: "flickable"
> - clip: true // FIXME maybe we can remove this, or just not clip in few cases
> - contentHeight: imageContainer.height
> - contentWidth: imageContainer.width
> -
> - onHeightChanged: image.resetScale()
> - onWidthChanged: image.resetScale()
> - anchors.fill: parent
> -
> - Item {
> - id: imageContainer
> - objectName: "imageContainer"
> - width: Math.max(image.width * image.scale, flickable.width)
> - height: Math.max(image.height * image.scale, flickable.height)
> -
> - Item {
> - id: image
> - objectName: "image"
> - property alias imageStatus: imageRenderer.status
> - property var prevScale
> - anchors.centerIn: parent
> -
> - signal imageReloaded
> -
> - Image {
> - id: imageRenderer
> - objectName: "imageRenderer"
> - smooth: !flickable.movingVertically
> - anchors.fill: parent
> - fillMode: Image.PreserveAspectFit
> -
> - readonly property int sourceSizeMultiplier: 3
> -
> - sourceSize.width: root.width * sourceSizeMultiplier <= root.height * sourceSizeMultiplier ? root.width * sourceSizeMultiplier : 0
> - sourceSize.height: root.height * sourceSizeMultiplier <= root.width * sourceSizeMultiplier ? root.height * sourceSizeMultiplier : 0
> -
> - onStatusChanged: {
> - if (status === Image.Ready) {
> - image.imageReloaded();
> - }
> - }
> - }
> -
> - onImageReloaded: {
> - image.height = imageRenderer.implicitHeight
> - image.width = imageRenderer.implicitWidth
> - image.resetScale();
> - }
> -
> - function resetScale() {
> - image.scale = Math.min(flickable.width / image.width, flickable.height / image.height);
> - pinchArea.minScale = image.scale;
> - prevScale = Math.min(image.scale, 1);
> - }
> -
> - onScaleChanged: {
> - var currentWidth = width * scale
> - var currentHeight = height * scale
> - var scaleRatio = scale / prevScale
> - if (currentWidth > flickable.width) {
> - var xpos = flickable.width / 2 + flickable.contentX;
> - var xoff = xpos * scaleRatio;
> - flickable.contentX = xoff - flickable.width / 2;
> - }
> - if (currentHeight > flickable.height) {
> - var ypos = flickable.height / 2 + flickable.contentY;
> - var yoff = ypos * scaleRatio;
> - flickable.contentY = yoff - flickable.height / 2;
> - }
> - prevScale = scale;
> - }
> - }
> - }
> -
> - PinchArea {
> - id: pinchArea
> - objectName: "pinchArea"
> - property real minScale: 1.0
> - anchors.fill: parent
> - enabled: zoomable ? zoomable : false
> -
> - pinch.target: image
> - pinch.minimumScale: minScale
> - pinch.maximumScale: 10
> -
> - onPinchFinished: flickable.returnToBounds()
> - }
> -
> - MouseArea {
> - id: mouseArea
> - objectName: "mouseArea"
> -
> - anchors.fill: parent
> - enabled: zoomable ? zoomable : false
> -
> - onWheel: {
> - var startScale = image.scale;
> - if (wheel.angleDelta.y > 0) {
> - image.scale = startScale + 0.1;
> - } else if (wheel.angleDelta.y < 0) {
> - if (image.scale > 0.1 && image.scale > pinchArea.minScale) {
> - image.scale = startScale - 0.1;
> - }
> - }
> - wheel.accepted = true;
> - }
> -
> - onPressed: {
> - mouse.accepted = false;
> - }
> -
> - onReleased: {
> - mouse.accepted = false;
> - }
> -
> - onClicked: {
> - mouse.accepted = false;
> - }
> - }
> - }
> -}
>
> === added directory 'src/app/qml/common'
> === added file 'src/app/qml/common/DetailsPage.qml'
> --- src/app/qml/common/DetailsPage.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/common/DetailsPage.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,58 @@
> +/*
> + * Copyright (C) 2013-2014 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.3
> +import Ubuntu.Components 1.1
> +import Ubuntu.Components.ListItems 1.0 as ListItem
> +
> +import "utils.js" as Utils
> +
> +Page {
> + id: detailsPage
> + objectName: "detailsPage"
> +
> + title: i18n.tr("Details")
> +
> + Column {
> + width: parent.width
> +
> + ListItem.Subtitled {
> + text: i18n.tr("Location")
> + subText: file.path
> + }
> + ListItem.Subtitled {
> + text: i18n.tr("Size")
> + subText: Utils.printSize(file.size)
> + }
> +
> + ListItem.Subtitled {
> + text: i18n.tr("Created")
> + subText: file.creationTime.toLocaleString(Qt.locale())
> + }
> +
> + ListItem.Subtitled {
> + text: i18n.tr("Last modified")
> + subText: file.lastModified.toLocaleString(Qt.locale())
> + }
> +
> + ListItem.Subtitled {
> + id: mimetypeItem
> + objectName: "mimetypeItem"
> + text: i18n.tr("MIME type")
> + subText: file.mimetype
> + }
> + }
> +}
>
> === added file 'src/app/qml/common/ErrorDialog.qml'
> --- src/app/qml/common/ErrorDialog.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/common/ErrorDialog.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,31 @@
> +/*
> + * Copyright (C) 2014-2015 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.3
> +import Ubuntu.Components 1.1
> +import Ubuntu.Components.Popups 1.0
> +
> +Dialog {
> + id: errorDialog
> + title: i18n.tr("Error")
> + text: i18n.tr("File does not exist")
I think you should make this file more generic, adding a text property (maybe with actual text as default value) and a 'type' property, so app could use this dialog for every error, just passing the right error message and the right type, and changing the visible buttons basing on type
> +
> + Button {
> + text: i18n.tr("Close")
> + color: UbuntuColors.red
> + onClicked: PopupUtils.close(errorDialog)
> + }
> +}
>
> === added file 'src/app/qml/common/UnknownTypeDialog.qml'
> --- src/app/qml/common/UnknownTypeDialog.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/common/UnknownTypeDialog.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,43 @@
> +/*
> + * Copyright (C) 2013-2015 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.3
> +import Ubuntu.Components 1.1
> +import Ubuntu.Components.Popups 1.0
> +
> +import "loadComponent.js" as LoadComponent
> +
> +Dialog {
> + id: unknownDialog
> + objectName: "unknownDialog"
> + title: i18n.tr("Unknown file type")
> + text: i18n.tr("Sorry but we can't find a way to display this file. Do you want to open it as a plain text?")
> + Button {
> + text: i18n.tr("Yes")
> + color: UbuntuColors.green
> +
> + onClicked: {
> + LoadComponent.load("text/plain");
> + PopupUtils.close(unknownDialog)
> + }
> + }
> + Button {
> + text: i18n.tr("No")
> + color: UbuntuColors.red
> + onClicked: PopupUtils.close(unknownDialog)
> + }
> +}
> +
>
> === added file 'src/app/qml/common/loadComponent.js'
> --- src/app/qml/common/loadComponent.js 1970-01-01 00:00:00 +0000
> +++ src/app/qml/common/loadComponent.js 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,38 @@
> +/*
> + * Copyright (C) 2013-2015 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +function load(mimetype) {
> + var qmlToLoad = "";
> +
> + // Open all text files in text editor
> + // With that fix it is possible to open LICENSE file
> + // which was recognised as text/x-pascal
> + if (mimetype.substring(0, 5) === "text/")
> + qmlToLoad = Qt.resolvedUrl("../textView/TextView.qml");
> +
> + // Check if PDF document
> + if (mimetype === "application/pdf")
> + qmlToLoad = Qt.resolvedUrl("../pdfView/PdfView.qml");
> +
> + if (qmlToLoad != "") {
> + pageStack.push(qmlToLoad);
> + } else {
> + console.debug("Unknown MIME type: "+ mimetype);
> + runUnknownTypeDialog();
> + }
> +
> + return mimetype;
> +}
>
> === added file 'src/app/qml/common/utils.js'
> --- src/app/qml/common/utils.js 1970-01-01 00:00:00 +0000
> +++ src/app/qml/common/utils.js 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,34 @@
> +/*
> + * Copyright (C) 2013-2015 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +.pragma library
> +
> +function printSize(size) {
> + if (size >= 1073741824)
> + return (size / 1073741824).toFixed(2) + " GiB";
> +
> + if (size >= 1048576)
> + return (size / 1048576).toFixed(2) + " MiB";
> +
> + if (size >= 1024)
> + return parseInt(size / 1024) + " KiB";
> +
> + return size + " byte";
Shouldn't has to be translable?
We have also Arabic/Chinese support, and I'm pretty sure they have different characters
> +};
> +
> +function getNameOfFile(path) {
> + return path.toString().substring(path.lastIndexOf('/') + 1);
> +}
Choose if you want to have ';' after a function (as printSize function) or not.
I suggest to remove it
>
> === added directory 'src/app/qml/documentPage'
> === added file 'src/app/qml/documentPage/DeleteFileDialog.qml'
> --- src/app/qml/documentPage/DeleteFileDialog.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/documentPage/DeleteFileDialog.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,59 @@
> +/*
> + Copyright (C) 2013-2015 Stefano Verzegnassi
> +
> + This program is free software: you can redistribute it and/or modify
> + it under the terms of the GNU General Public License 3 as published by
> + the Free Software Foundation, either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see http://www.gnu.org/licenses/.
> +*/
> +
> +import QtQuick 2.0
> +import Ubuntu.Components 1.1
> +import Ubuntu.Components.Popups 1.0
> +
> +Dialog {
> + id: deleteFileDialog
> +
> + property string path
> +
> + title: path ? i18n.tr("Delete file") :
> + i18n.tr("Delete %1 files").arg(documentPage.view.item.selectedItems.count)
> + text: path ? i18n.tr("Are you sure you want to permanently delete this file?") :
> + i18n.tr("Are you sure you want to permanently delete these files?")
> +
> + Button {
> + text: i18n.tr("Cancel")
> + onClicked: PopupUtils.close(deleteFileDialog)
> + }
> +
> + Button {
> + text: i18n.tr("Delete")
> + color: UbuntuColors.red
> +
> + onClicked: {
> + if (deleteFileDialog.path) {
> + folderModel.rm(path)
> + } else {
> + var items = documentPage.view.item.selectedItems;
> +
> + for (var i=0; i < items.count; i++) {
> + console.log("Removing:", items.get(i).model.path);
> + folderModel.rm(items.get(i).model.path);
> + }
> +
> + viewLoader.item.endSelection();
This shouldn't be out of the if/else?
You have to endSelection also if user selected only 1 file IMO
> + }
> +
> + PopupUtils.close(deleteFileDialog)
> + }
> + }
> +}
> +
>
> === added file 'src/app/qml/documentPage/DocumentEmptyState.qml'
> --- src/app/qml/documentPage/DocumentEmptyState.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/documentPage/DocumentEmptyState.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,34 @@
> +/*
> + Copyright (C) 2015 Stefano Verzegnassi
> +
> + This program is free software: you can redistribute it and/or modify
> + it under the terms of the GNU General Public License 3 as published by
> + the Free Software Foundation.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see http://www.gnu.org/licenses/.
> +*/
> +
> +import QtQuick 2.0
> +import "../upstreamComponents"
Why?
> +
> +Item {
> + anchors.fill: parent
> +
> + EmptyState {
> + title: i18n.tr("No document found")
> +
> + // TODO: Add "or insert removable media with documents." to subTitle when
> + // the support for SD card will be implemented.
> + subTitle: i18n.tr("Connect your device to any computer and simply drag files to the Documents folder.")
> + iconName: "edit-copy"
> +
> + anchors.centerIn: parent
> + width: parent.width
> + }
> +}
>
> === added file 'src/app/qml/documentPage/DocumentGridDelegate.qml'
> --- src/app/qml/documentPage/DocumentGridDelegate.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/documentPage/DocumentGridDelegate.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,179 @@
> +/*
> + Copyright (C) 2015 Stefano Verzegnassi
> +
> + This program is free software: you can redistribute it and/or modify
> + it under the terms of the GNU General Public License 3 as published by
> + the Free Software Foundation.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see http://www.gnu.org/licenses/.
> +*/
> +
> +import QtQuick 2.0
> +import Ubuntu.Components 1.1
> +import QtQuick.Layouts 1.1
> +
> +import "../common/utils.js" as Utils
> +
> +AbstractButton {
> + id: root
> + property bool selected: false
> + property bool selectionMode: false
> +
> + function formattedDateTime() {
> + var date = new Date(model.date)
> + var diff = model.dateDiff
> +
> + if (diff < 1)
> + return i18n.tr("Today, ") + Qt.formatDateTime(date, "hh:mm")
You should make translable also "hh:mm", and add a comment for translators to explain what it rapresents, maybe in other languages they use different time format
> +
> + if (diff < 2)
> + return i18n.tr("Yesterday, ") + Qt.formatDateTime(date, "hh:mm")
Same as above
> +
> + if (diff < 7)
> + return Qt.formatDateTime(date, "dddd, hh:mm")
Same as above
> +
> + return Qt.formatDateTime(date, "dd-MM-yyyy hh:mm")
Same as above
> + }
> +
> + Rectangle {
> + anchors { fill: parent; margins: units.gu(0.5) }
> +
> + color: Qt.lighter(UbuntuColors.lightGrey)
> + clip: true
> +
> + Loader {
> + id: selectionIcon
> +
> + anchors {
> + right: parent.right
> + top: parent.top
> + }
> +
> + z: 10
> +
> + width: (status === Loader.Ready) ? item.implicitWidth : 0
> + visible: (status === Loader.Ready) && (item.width === item.implicitWidth)
> + Behavior on opacity {
> + NumberAnimation {
> + duration: UbuntuAnimation.SnapDuration
> + }
> + }
> + }
> +
> + // Document mimetype icon
> + Icon {
> + anchors.centerIn: parent
> + anchors.verticalCenterOffset: - units.gu(2)
> +
> + width: units.gu(8); height: width
> +
> + // At the moment the suru icon theme doesn't have much icons.
> + // Just some note for the future:
> + // TODO: Add icons for Office/ODF documents
> + // TODO: Whenever there will be icons for source code files, add them.
> + name: {
> + if (model.mimetype.substring(0, 5) === "text/")
> + return "text-x-generic-symbolic"
> +
> + if (model.mimetype.substring(0, 5) === "image")
> + return "image-x-generic-symbolic"
> +
> + if (model.mimetype === "application/pdf")
> + return "application-pdf-symbolic"
> +
> + return "package-x-generic-symbolic"
> + }
> + }
> +
> + // Cover
> + /* Image {
> + anchors.fill: parent
> +
> + source: {
> + if (model.cover !== "" && typeof model.cover !== "undefined")
> + return model.cover
> +
> + if (model.mimetype.toString().indexOf("image") !== -1)
> + return model.path
> +
> + return ""
> + }
> +
> + sourceSize.width: width
> + fillMode: Image.PreserveAspectCrop
> + }*/
> +
> + // Document info overlay
> + Rectangle {
> + id: overlay
> +
> + anchors {
> + left: parent.left
> + right: parent.right
> + bottom: parent.bottom
> + }
> +
> + height: units.gu(6)
> +
> + color: UbuntuColors.darkGrey
> + opacity: 0.75
> + }
> +
> + // Document info
> + Column {
> + anchors { fill: overlay; margins: units.gu(0.5) }
> +
> + RowLayout {
Why you use a Row with only one element inside?
> + width: parent.width
Please use anchors, if possible, because they have better performances than width/height when the window is resized
> + spacing: units.gu(1)
> +
> + Label {
> + text: model.name
> + color: "white"
> +
> + elide: Text.ElideRight
> + font.weight: Font.DemiBold
> + fontSize: "small"
> +
> + Layout.fillWidth: true
> + }
> + }
> +
> + RowLayout {
> + width: parent.width
> +
> + Label {
> + text: formattedDateTime()
> + color: "white"
> + fontSize: "small"
> +
> + Layout.fillWidth: true
> + }
> +
> + Label {
> + text: Utils.printSize(model.size)
> + color: "white"
> + fontSize: "small"
> + }
> + }
> + } // Document info end
> +
> + states: [
> + State {
> + name: "select"
> + when: selectionMode || selected
> + PropertyChanges {
> + target: selectionIcon
> + source: Qt.resolvedUrl("../upstreamComponents/ListItemWithActionsCheckBox.qml")
> + anchors.margins: units.gu(1)
> + }
> + }
> + ]
> + }
> +}
>
> === added file 'src/app/qml/documentPage/DocumentGridView.qml'
> --- src/app/qml/documentPage/DocumentGridView.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/documentPage/DocumentGridView.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,76 @@
> +/*
> + Copyright (C) 2015 Stefano Verzegnassi
> +
> + This program is free software: you can redistribute it and/or modify
> + it under the terms of the GNU General Public License 3 as published by
> + the Free Software Foundation.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see http://www.gnu.org/licenses/.
> +*/
> +
> +import QtQuick 2.0
> +import Ubuntu.Components 1.1
> +
> +import "../upstreamComponents"
> +
> +MultipleSelectionGridView {
> + id: documentGridView
> +
> + // We use mainView.width to calculate the size and the spacing of elements.
> + // That's because this GridView always fills (and always will) the whole size of MainView.
> + // By this way, we can avoid binding loops, keeping the code pretty simple.
> + anchors {
> + fill: parent
> + margins: units.gu(0.5)
> + leftMargin: (mainView.width % cellWidth) * 0.5
> + rightMargin: (mainView.width % cellWidth) * 0.5
> + }
> + clip: true
> +
> + cellHeight: cellWidth
> + cellWidth: (mainView.width > units.gu(50)) ? units.gu(24)
> + : (mainView.width - units.gu(2)) * 0.5
> +
> + listDelegate: DocumentGridDelegate {
> + id: delegate
> + width: cellWidth
> + height: cellHeight
> +
> + selectionMode: documentGridView.isInSelectionMode
> + selected: documentGridView.isSelected(delegate)
> +
> + onClicked: {
> + if(documentGridView.isInSelectionMode) {
> + if(!documentGridView.selectItem(delegate)) {
> + documentGridView.deselectItem(delegate)
> + }
> + return
> + }
> + else {
> + file.path = model.path
> + }
> + }
> +
> + onPressAndHold: {
> + if (!documentGridView.isInSelectionMode) {
> + documentGridView.startSelection()
> + documentGridView.selectItem(delegate)
> + }
> + }
> + }
> +
> + listModel: folderModel
> +
> + Scrollbar {
> + flickableItem: documentGridView
> + parent: documentGridView.parent
> + }
> +
> + Component.onCompleted: { if (DOC_VIEWER.pickModeEnabled) documentGridView.startSelection(); }
> +}
>
> === added file 'src/app/qml/documentPage/DocumentListDelegate.qml'
> --- src/app/qml/documentPage/DocumentListDelegate.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/documentPage/DocumentListDelegate.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,105 @@
> +/*
> + Copyright (C) 2015 Stefano Verzegnassi
> +
> + This program is free software: you can redistribute it and/or modify
> + it under the terms of the GNU General Public License 3 as published by
> + the Free Software Foundation.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see http://www.gnu.org/licenses/.
> +*/
> +
> +import QtQuick 2.0
> +import Ubuntu.Components 1.1
> +import QtQuick.Layouts 1.1
> +
> +import "../common/utils.js" as Utils
> +import "../upstreamComponents"
> +
> +ListItemWithActions {
> + function formattedDateTime() {
> + var date = new Date(model.date)
> + var diff = model.dateDiff
> +
> + if (diff < 2)
> + return Qt.formatDateTime(date, "hh:mm")
> +
> + if (diff < 7)
> + return Qt.formatDateTime(date, "dddd, hh:mm")
> +
> + return Qt.formatDateTime(date, "dd-MM-yyyy hh:mm")
> + }
> +
> + width: parent.width
Use anchors please
> + height: units.gu(8)
> +
> +
Remove newline
> + locked: documentPage.state == "pickMode"
> +
> + // TODO: NEEDS-DESIGN: Enable left action. Still need to find an equivalent for GridDelegate.
> + /* leftSideAction: Action {
> + iconName: "delete"
> + text: i18n.tr("Delete")
> + onTriggered: {
> + PopupUtils.open(Qt.resolvedUrl("DeleteFileDialog.qml"),
> + documentPage, { path: model.filePath })
> + }
> + }*/
> +
> + contents: RowLayout {
> + anchors.fill: parent
> + spacing: units.gu(2)
> +
> + Icon {
> + width: height
> + height: units.gu(5)
> +
> + // At the moment the suru icon theme doesn't have much icons.
> + name: {
> + if (model.mimetype.substring(0, 5) === "text/")
> + return "text-x-generic-symbolic"
> +
> + if (model.mimetype.substring(0, 5) === "image")
> + return "image-x-generic-symbolic"
> +
> + if (model.mimetype === "application/pdf")
> + return "application-pdf-symbolic"
> +
> + return "package-x-generic-symbolic"
> + }
> + }
> +
> + Column {
> + Layout.fillWidth: true
> +
> + Label {
> + text: model.name
> + wrapMode: Text.Wrap
> + width: parent.width
> +
> + color: UbuntuColors.midAubergine
> + }
> +
> + RowLayout {
> + width: parent.width
> +
> + Label {
> + text: formattedDateTime()
> + fontSize: "small"
> +
> + Layout.fillWidth: true
> + }
> +
> + Label {
> + text: Utils.printSize(model.size)
> + fontSize: "small"
> + }
> + }
> + }
> + }
> +}
>
> === added file 'src/app/qml/documentPage/DocumentListView.qml'
> --- src/app/qml/documentPage/DocumentListView.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/documentPage/DocumentListView.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,157 @@
> +/*
> + Copyright (C) 2015 Stefano Verzegnassi
> +
> + This program is free software: you can redistribute it and/or modify
> + it under the terms of the GNU General Public License 3 as published by
> + the Free Software Foundation.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see http://www.gnu.org/licenses/.
> +*/
> +
> +import QtQuick 2.0
> +import Ubuntu.Components 1.1
> +import Ubuntu.Components.ListItems 1.0 as ListItem
> +
> +import "../upstreamComponents"
> +
> +MultipleSelectionListView {
> + id: documentListView
> +
> + anchors { fill: parent; margins: units.gu(0.5) }
> + clip: true
> +
> + property var _currentSwipedItem: null
> +
> + function _updateSwipeState(item)
> + {
> + if (item.swipping) {
> + return
> + }
> +
> + if (item.swipeState !== "Normal") {
> + if (documentListView._currentSwipedItem !== item) {
> + if (documentListView._currentSwipedItem) {
> + documentListView._currentSwipedItem.resetSwipe()
> + }
> + documentListView._currentSwipedItem = item
> + }
> + } else if (item.swipeState !== "Normal"
> + && documentListView._currentSwipedItem === item) {
> + documentListView._currentSwipedItem = null
> + }
> + }
> +
> + listDelegate: DocumentListDelegate {
> + id: delegate
> +
> + property var removalAnimation
> +
> + function remove() {
> + removalAnimation.start()
> + }
> +
> + selectionMode: documentListView.isInSelectionMode
> + selected: documentListView.isSelected(delegate)
> +
> + onSwippingChanged: {
> + _updateSwipeState(delegate)
> + }
> +
> + onSwipeStateChanged: {
> + _updateSwipeState(delegate)
> + }
> +
> + ListView.onRemove: ScriptAction {
> + script: {
> + if (_currentSwipedItem
> + === delegate) {
> + _currentSwipedItem = null
> + }
> + }
> + }
> +
> + removalAnimation: SequentialAnimation {
> + alwaysRunToEnd: true
> +
> + PropertyAction {
> + target: delegate
> + property: "ListView.delayRemove"
> + value: true
> + }
> +
> + UbuntuNumberAnimation {
> + target: delegate
> + property: "height"
> + to: 0
> + }
> +
> + PropertyAction {
> + target: delegate
> + property: "ListView.delayRemove"
> + value: false
> + }
> +
> + ScriptAction {
> + script: {
> + var filePath = d.folderModel.get(index, "filePath")
> + Storage.rm(filePath)
> + }
> + }
> + }
> +
> + onItemClicked: {
> + if(documentListView.isInSelectionMode) {
> + if(!documentListView.selectItem(delegate)) {
> + documentListView.deselectItem(delegate)
> + }
> + return
> + }
> +
> + else {
> + file.path = model.path
> + }
> + }
> +
> + onItemPressAndHold: {
> + if (!documentListView.isInSelectionMode) {
> + documentListView.startSelection()
> + documentListView.selectItem(delegate)
> + }
> + }
> + }
> +
> + listModel: folderModel
> +
> + section.property: "dateDiff"
> + section.delegate: ListItem.Header {
> + text: {
> + if (section == 0)
> + return i18n.tr("Today")
> +
> + if (section == 1)
> + return i18n.tr("Yesterday")
> +
> + if (section == 2)
> + return i18n.tr("Earlier this week")
> +
> + if (section == 3)
> + return i18n.tr("Earlier this month")
> +
> + if (section > 3)
You don't need this if, just return
> + return i18n.tr("Even more earlier...")
> + }
> + }
> +
> + Scrollbar {
> + flickableItem: documentListView
> + parent: documentListView.parent
> + }
> +
> + Component.onCompleted: { if (DOC_VIEWER.pickModeEnabled) documentListView.startSelection(); }
> +}
>
> === added file 'src/app/qml/documentPage/DocumentPage.qml'
> --- src/app/qml/documentPage/DocumentPage.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/documentPage/DocumentPage.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,76 @@
> +/*
> + * Copyright (C) 2015 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.0
> +import Ubuntu.Components 1.1
> +import Ubuntu.Components.Popups 1.0
> +import Qt.labs.settings 1.0
> +
> +Page {
> + id: documentPage
> +
> + title: i18n.tr("Document Viewer")
> + flickable: null
> +
> + property bool useGridView: false
> +
> + Settings {
> + property alias useGridView: documentPage.useGridView
> + }
> +
> + property alias view: viewLoader
> + Loader {
> + id: viewLoader
> + anchors.fill: parent
> +
> + source: (folderModel.count === 0) ? Qt.resolvedUrl("./DocumentEmptyState.qml")
> + : useGridView ? Qt.resolvedUrl("./DocumentGridView.qml")
> + : Qt.resolvedUrl("./DocumentListView.qml")
> + }
> +
> + // *** HEADER ***
> + states: [
> + DocumentPageDefaultHeader {
> + name: "default"
> + targetPage: documentPage
> + when: !mainView.pickMode && !viewLoader.item.isInSelectionMode
> + },
> +
> + DocumentPagePickModeHeader {
> + name: "pickMode"
> + targetPage: documentPage
> + when: mainView.pickMode
> + },
> +
> + DocumentPageSelectionModeHeader {
> + name: "selection"
> + targetPage: documentPage
> + when: !mainView.pickMode && viewLoader.item.isInSelectionMode
> + }
> + ]
> +
> + Connections {
> + target: DOC_VIEWER
> +
> + onPickModeEnabledChanged: {
> + if (DOC_VIEWER.pickModeEnabled) {
> + viewLoader.item.startSelection()
> + } else {
> + viewLoader.item.cancelSelection()
> + }
> + }
> + }
> +}
>
> === added file 'src/app/qml/documentPage/DocumentPageDefaultHeader.qml'
> --- src/app/qml/documentPage/DocumentPageDefaultHeader.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/documentPage/DocumentPageDefaultHeader.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,36 @@
> +/*
> + * Copyright (C) 2014-2015 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.3
> +import Ubuntu.Components 1.1
> +import QtQuick.Layouts 1.1
> +import Ubuntu.Components.Popups 1.0
Why?
> +
> +PageHeadState {
> + id: rootItem
> +
> + property Page targetPage
> + head: targetPage.head
> +
> + actions: Action {
> + id: switchView
> + text: targetPage.useGridView ? i18n.tr("Switch to single column list") : i18n.tr("Switch to grid")
> + iconName: targetPage.useGridView ? "view-list-symbolic" : "view-grid-symbolic"
> + onTriggered: targetPage.useGridView = !targetPage.useGridView
> +
> + visible: folderModel.count !== 0
> + }
> +}
>
> === added file 'src/app/qml/documentPage/DocumentPagePickModeHeader.qml'
> --- src/app/qml/documentPage/DocumentPagePickModeHeader.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/documentPage/DocumentPagePickModeHeader.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,65 @@
> +/*
> + * Copyright (C) 2014-2015 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.3
> +import Ubuntu.Components 1.1
> +import QtQuick.Layouts 1.1
> +import Ubuntu.Components.Popups 1.0
> +
> +PageHeadState {
> + id: rootItem
> +
> + property Page targetPage
> + head: targetPage.head
> +
> + backAction: Action {
> + text: i18n.tr("Cancel")
> + objectName: "cancelButton"
> + iconName: "close"
> + onTriggered: DOC_VIEWER.contentPickingCanceled()
> + }
> +
> + actions: [
> + Action {
> + text: targetPage.useGridView ? i18n.tr("Switch to single column list") : i18n.tr("Switch to grid")
> + iconName: targetPage.useGridView ? "view-list-symbolic" : "view-grid-symbolic"
> + onTriggered: targetPage.useGridView = !targetPage.useGridView
> +
> + visible: folderModel.count !== 0
> + },
> +
> + Action {
> + text: i18n.tr("Pick")
> + objectName: "pickButton"
> + enabled: viewLoader.item.selectedItems.count > 0
I think you should add visible: enabled
> + iconName: "ok"
> + onTriggered: {
> + if (!enabled)
> + return;
> +
> + var urlList = []
> + var items = documentPage.view.item.selectedItems;
> +
> + for (var i=0; i < items.count; i++) {
> + urlList.push(items.get(i).model.path);
> + }
> +
> + DOC_VIEWER.returnPickedContent(urlList);
> + }
> + }
> + ]
> +}
> +
>
> === added file 'src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml'
> --- src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,96 @@
> +/*
> + * Copyright (C) 2014-2015 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.3
> +import Ubuntu.Components 1.1
> +import QtQuick.Layouts 1.1
> +import Ubuntu.Components.Popups 1.0
> +
> +import "../upstreamComponents"
> +
> +PageHeadState {
> + id: rootItem
> +
> + property Page targetPage
> +
> + head: targetPage.head
> +
> + backAction: Action {
> + iconName: "close"
> + text: i18n.tr("Close")
> + onTriggered: {
> + viewLoader.item.cancelSelection()
> + }
> + }
> +
> + contents: Loader {
> + id: selectionStateLoader
> + active: documentPage.state === "selection"
> + sourceComponent: Item {
> + HeaderButton {
> + id: selectButton
> +
> + anchors {
> + right: deleteButton.left
> + rightMargin: units.gu(1)
> + }
> +
> + text: {
> + if(viewLoader.item.selectedItems.count === viewLoader.item.count) {
> + return i18n.tr("Select None")
> + } else {
> + return i18n.tr("Select All")
> + }
> + }
> +
> + iconSource: {
> + if(viewLoader.item.selectedItems.count === viewLoader.item.count) {
> + return Qt.resolvedUrl("../../graphics/select-none.svg")
> + } else {
> + return Qt.resolvedUrl("../../graphics/select.svg")
> + }
> + }
> +
> + onTriggered: {
> + if(viewLoader.item.selectedItems.count === viewLoader.item.count) {
> + viewLoader.item.clearSelection()
> + } else {
> + viewLoader.item.selectAll()
> + }
> + }
> + }
> +
> + HeaderButton {
> + id: deleteButton
> +
> + anchors.right: parent.right
> + anchors.rightMargin: units.gu(2)
> +
> + iconName: "delete"
> + text: i18n.tr("Delete")
> + enabled: viewLoader.item.selectedItems.count !== 0
> +
> + onTriggered: {
> + PopupUtils.open(Qt.resolvedUrl("DeleteFileDialog.qml"), documentPage)
> + }
> + }
> + }
> +
> + height: parent ? parent.height : undefined
Maybe 0 is better than undefined here?
> + anchors.right: parent ? parent.right: undefined
> + }
> +
> +}
>
> === removed file 'src/app/qml/loadComponent.js'
> --- src/app/qml/loadComponent.js 2015-01-29 18:45:21 +0000
> +++ src/app/qml/loadComponent.js 1970-01-01 00:00:00 +0000
> @@ -1,45 +0,0 @@
> -/*
> - * Copyright (C) 2013-2015 Canonical, Ltd.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; version 3.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -function load(mimetype) {
> - var qmlToLoad = "";
> -
> - // Open all text files in text editor
> - // With that fix it is possible to open LICENSE file
> - // which was recognised as text/x-pascal
> - if (mimetype.substring(0, 5) === "text/")
> - qmlToLoad = "TextView";
> -
> - // Check if image
> - if (mimetype === "image/jpeg" || mimetype === "image/png" ||
> - mimetype === "image/gif" || mimetype === "image/tiff" ||
> - mimetype === "image/x-icon" || mimetype === "image/x-ms-bmp" ||
> - mimetype === "image/svg+xml")
> - qmlToLoad = "ImageView";
> -
> - // Check if PDF document
> - if (mimetype === "application/pdf")
> - qmlToLoad = "PdfView";
> -
> - if (qmlToLoad != "") {
> - pageStack.push(Qt.resolvedUrl(qmlToLoad + ".qml"));
> - } else {
> - console.debug("Unknown MIME type: "+ mimetype);
> - runUnknownTypeDialog();
> - }
> -
> - return mimetype;
> -}
>
> === added directory 'src/app/qml/pdfView'
> === added file 'src/app/qml/pdfView/PdfContentsPage.qml'
> --- src/app/qml/pdfView/PdfContentsPage.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/pdfView/PdfContentsPage.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,60 @@
> +/*
> + * Copyright (C) 2014, 2015
> + * Stefano Verzegnassi <verzegnassi.stefano@xxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.0
> +import Ubuntu.Components 1.1
> +import QtQuick.Layouts 1.1
> +import Ubuntu.Components.ListItems 1.0 as ListItem
> +
> +Page {
> + title: i18n.tr("Contents")
> +
> + ListView {
> + anchors.fill: parent
> +
> + model: poppler.tocModel
> +
> + delegate: ListItem.Base {
> + showDivider: model.level == 0
> +
> + onClicked: {
> + pdfView.positionAtIndex(model.pageIndex);
> + pageStack.pop();
> + }
> +
> + RowLayout {
> + anchors.fill: parent
> + anchors.leftMargin: units.gu(2) * model.level
> +
> + spacing: units.gu(1)
> +
> + Label {
> + Layout.fillWidth: true
> +
> + text: (typeof model.title === "undefined") ? "" : model.title;
> + elide: Text.ElideRight
> + Component.onCompleted: { if (model.level === 0); font.weight = Font.DemiBold; }
> + }
> +
> + Label {
> + text: (typeof model.pageIndex === "undefined") ? "" : model.pageIndex + 1;
> + Component.onCompleted: { if (model.level === 0); font.weight = Font.DemiBold; }
> + }
> + }
> + }
> + }
> +}
>
> === added file 'src/app/qml/pdfView/PdfView.qml'
> --- src/app/qml/pdfView/PdfView.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/pdfView/PdfView.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,107 @@
> +/*
> + * Copyright (C) 2013-2014 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.3
> +import Ubuntu.Components 1.1
> +import com.ubuntu.popplerqmlplugin 1.0 as PDF
> +
> +import "../common/utils.js" as Utils
> +import "../upstreamComponents"
> +
> +PageWithBottomEdge {
> + id: pdfPage
> + title: Utils.getNameOfFile(file.path);
> +
> + // Disable header auto-hide.
> + // TODO: Show/hide header if a user taps the page
> + flickable: null
> +
> + property string currentPage: i18n.tr("Page %1 of %2").arg(pdfView.currentPageIndex + 1).arg(pdfView.count)
Maybe adding a comment for translators here?
> +
> + bottomEdgeTitle: i18n.tr("Contents")
> + bottomEdgePageComponent: PdfContentsPage {}
> + bottomEdgeEnabled: poppler.tocModel.count > 0
> +
> + PDF.VerticalView {
> + id: pdfView
> + objectName: "pdfView"
> + anchors.fill: parent
> + spacing: units.gu(2)
> +
> + clip: true
> + boundsBehavior: Flickable.StopAtBounds
> + flickDeceleration: 1500 * units.gridUnit / 8
> + maximumFlickVelocity: 2500 * units.gridUnit / 8
> +
> + contentWidth: parent.width * _zoomHelper.scale
> + cacheBuffer: height * poppler.providersNumber * _zoomHelper.scale * 0.5
> + interactive: !pinchy.pinch.active
> +
> + model: poppler
> + delegate: PdfViewDelegate {
> + Component.onDestruction: DOC_VIEWER.releaseResources()
> + }
> +
> + // FIXME: On zooming, keep the same content position.
> + PinchArea {
> + id: pinchy
> + anchors.fill: parent
> +
> + pinch {
> + target: _zoomHelper
> + minimumScale: 1.0
> + maximumScale: 2.5
> + }
> +
> + onPinchFinished: {
> + pdfView.returnToBounds();
> +
> + // This is a bit expensive, so it's safer to put it here.
> + // It won't be called on desktop (where PinchArea is not used),
> + // but it's not a problem at the moment (our target is phone).
> + DOC_VIEWER.releaseResources();
> + }
> + }
> +
> + Item { id: _zoomHelper }
> + }
> +
> + Scrollbar { flickableItem: pdfView }
> + Scrollbar { flickableItem: pdfView; align: Qt.AlignBottom }
> +
> + PDF.Document {
> + id: poppler
> +
> + property bool isLoading: true
> +
> + Component.onCompleted: path = file.path
> + onPagesLoaded: {
> + isLoading = false;
> +
> + var title = getDocumentInfo("Title")
> + if (title !== "")
> + pdfPage.title = title
> + }
> + }
> +
> + // *** HEADER ***
> + state: "default"
> + states: PdfViewDefaultHeader {
> + name: "default"
> + targetPage: pdfPage
> + activityRunning: pdfView.currentPageItem.status == Image.Loading || poppler.isLoading
> + }
> +}
>
> === added file 'src/app/qml/pdfView/PdfViewDefaultHeader.qml'
> --- src/app/qml/pdfView/PdfViewDefaultHeader.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/pdfView/PdfViewDefaultHeader.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,96 @@
> +/*
> + * Copyright (C) 2014-2015 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.3
> +import Ubuntu.Components 1.1
> +import QtQuick.Layouts 1.1
> +import Ubuntu.Components.Popups 1.0
> +
> +PageHeadState {
> + id: rootItem
> +
> + property Page targetPage
> + property alias activityRunning: activity.running
> +
> + head: targetPage.head
> +
> + contents: RowLayout {
> + anchors.fill: parent
> + spacing: units.gu(1)
> +
> + ActivityIndicator { id: activity }
> +
> + Column {
> + id: layout
> + Layout.fillWidth: true
> +
> + Label {
> + width: parent.width
> + //horizontalAlignment: Text.AlignHCenter
> + elide: Text.ElideMiddle
> +
> + font.weight: Font.DemiBold
> + text: targetPage.title
> + }
> + Label {
> + width: parent.width
> + //horizontalAlignment: Text.AlignHCenter
> + elide: Text.ElideMiddle
> +
> + fontSize: "small"
> + text: targetPage.currentPage
> + }
> + }
> + }
> +
> + backAction: Action {
> + iconName: "back"
> + text: (pageStack.depth > 1) ? i18n.tr("Back") : i18n.tr("Close")
> + onTriggered: {
> + if (pageStack.depth > 1) {
> + // Go back to Welcome page
> + pageStack.pop();
> + } else {
> + // File has been imported through Content Hub (or was not chosen through WelcomePage)
> + // Close the application and show our source app (e.g. ubuntu-filemanager-app, if used to open a document)
> + Qt.quit()
> + }
> + }
> + }
> +
> + actions: [
> + Action {
> + iconName: "search"
> + // onTriggered: pageMain.state = "search"
> + //Disable it until we provide search in Poppler plugin.
> + enabled: false
> + },
> +
> + Action {
> + objectName:"gotopage"
> + iconName: "browser-tabs"
> + text: "Go to page..."
> + onTriggered: PopupUtils.open(Qt.resolvedUrl("PdfViewGotoDialog.qml"), targetPage)
> + },
> +
> + Action {
> + objectName: "detailsAction"
> + text: i18n.tr("Details")
> + iconName: "info"
> + onTriggered: pageStack.push(Qt.resolvedUrl("../common/DetailsPage.qml"))
> + }
> + ]
> +}
>
> === added file 'src/app/qml/pdfView/PdfViewDelegate.qml'
> --- src/app/qml/pdfView/PdfViewDelegate.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/pdfView/PdfViewDelegate.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,95 @@
> +/*
> + * Copyright (C) 2013-2015 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +import QtQuick 2.3
> +import Ubuntu.Components 1.1
> +
> +Rectangle {
> + id: pdfPage
> +
> + property int index: model.index
> + property bool _previewFetched: false
> +
> + property alias status: pageImg.status
> +
> + width: parent.width
> + height: width * (model.height / model.width)
> + color: "#E6E6E6"
> +
> + // Preview page rendering. Used as placeholder while zooming the page.
> + // We generate the low resolution preview from the texture of the PDF page,
> + // so that we can keep page rendering as fast as possible.
> + ShaderEffectSource {
> + id: previewImg
> + anchors.fill: parent
> +
> + // We cannot change its opacity or visibility, otherwise the texture will be refreshed,
> + // even if live is false.
> + live: false
> + textureSize: Qt.size(256, 256 * (model.height / model.width))
> + }
> +
> + Image {
> + id: pageImg
> + anchors.fill: parent
> +
> + source: "image://poppler" + (index % poppler.providersNumber) + "/page/" + index;
> + sourceSize.width: pdfPage.width
> +
> + onStatusChanged: {
> + // This is supposed to run the first time PdfViewDelegate gets the page rendering.
> + if (!_previewFetched) {
> + if (status == Image.Ready) {
> + previewImg.sourceItem = pageImg
> + // Re-assign sourceItem property, so the texture is not updated when Image status changes.
> + previewImg.sourceItem = pdfPage
> + }
> + }
> + }
> +
> + // Request a new page rendering. The order, which pages are requested with, depends on the distance from the currentPage
> + Timer {
> + id: _zoomTimer
> + interval: {
> + var diff = Math.abs(pdfView.currentPageIndex - model.index)
> + var prov = poppler.providersNumber * 0.5
> +
> + if (diff < prov)
> + return 0
> + else
> + return (diff - prov) * 10
> + }
> +
> + onTriggered: {
> + pageImg.sourceSize.width = pdfPage.width;
> + }
> + }
> + }
> +
> + // Page rendering depends on the width of PdfViewDelegate.
> + // Because of this, we have multiple callings to ImageProvider while zooming.
> + // Just avoid it.
> + Connections {
> + target: pinchy
> +
> + onPinchStarted: _zoomTimer.stop();
> + onPinchUpdated: {
> + // This ensures that page image is not reloaded when the maximumScale or minimumScale has already been reached.
> + if ( !(_zoomHelper.scale >= 2.5 && pinch.scale > 1.0) && !(_zoomHelper.scale <= 1.0 && pinch.scale < 1.0) )
> + pageImg.sourceSize.width = 0;
> + }
> + onPinchFinished: _zoomTimer.restart();
> + }
> +}
>
> === added file 'src/app/qml/pdfView/PdfViewGotoDialog.qml'
> --- src/app/qml/pdfView/PdfViewGotoDialog.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/pdfView/PdfViewGotoDialog.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,60 @@
> +/*
> + * Copyright (C) 2014-2015 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.3
> +import Ubuntu.Components 1.1
> +import Ubuntu.Components.Popups 1.0
> +
> +Dialog {
> + id: goToPageDialog
> + objectName:"PdfViewGotoDialog"
> +
> + title: i18n.tr("Go to page")
> + text: i18n.tr("Choose a page between 1 and %1").arg(pdfView.count)
> +
> + TextField {
> + id: goToPageTextField
> + objectName:"goToPageTextField"
> +
> + width: parent.width
> +
> + hasClearButton: true
> + inputMethodHints: Qt.ImhFormattedNumbersOnly
> + validator: IntValidator{ bottom: 1; top: pdfView.count }
> +
> + Keys.onReturnPressed: goToPage()
> + Component.onCompleted: forceActiveFocus()
> + }
> +
> + Button {
> + objectName:"GOButton"
> + text: i18n.tr("GO!")
> + color: UbuntuColors.orange
> +
> + enabled: goToPageTextField.acceptableInput
> + onClicked: goToPage()
> + }
> +
> + Button {
> + text: i18n.tr("Cancel")
> + onClicked: PopupUtils.close(goToPageDialog)
> + }
> +
> + function goToPage() {
> + pdfView.positionAtIndex((goToPageTextField.text - 1))
> + PopupUtils.close(goToPageDialog)
> + }
> +}
>
> === added directory 'src/app/qml/textView'
> === added file 'src/app/qml/textView/TextView.qml'
> --- src/app/qml/textView/TextView.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/textView/TextView.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,70 @@
> +/*
> + * Copyright (C) 2013-2015 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.3
> +import Ubuntu.Components 1.1
> +import Ubuntu.Components.Themes.Ambiance 0.1
> +
> +import "../common/utils.js" as Utils
> +
> +Page {
> + id: textPage
> + title: Utils.getNameOfFile(file.path);
> +
> + TextArea {
> + id: textAreaMain
> + objectName: "textAreaMain"
> +
> + property bool isLoading: true
> +
> + anchors.fill: parent
> +
> + // FIXME: If set to true, some of the keyboard hooks are disabled
> + // And it's not possible to move the cursor with arrow keys.
> + readOnly: true
> +
> + text: i18n.tr("Loading...")
> + font.family: "UbuntuMono"
> +
> + Component.onCompleted: {
> + var xhr = new XMLHttpRequest;
> +
> + xhr.open("GET", file.path);
> + xhr.onreadystatechange = function() {
> + if (xhr.readyState === XMLHttpRequest.DONE) {
> + textAreaMain.text = xhr.responseText;
> + textAreaMain.isLoading = false
> + }
> + };
> +
> + xhr.send();
> + }
> +
> + style: TextAreaStyle {
> + background: Rectangle { color: "white" }
> + }
> + }
> +
> + // *** HEADER ***
> + state: "default"
> + states: [
> + TextViewDefaultHeader {
> + name: "default"
> + targetPage: textPage
> + activityRunning: textAreaMain.isLoading
> + }
> + ]
> +}
>
> === added file 'src/app/qml/textView/TextViewDefaultHeader.qml'
> --- src/app/qml/textView/TextViewDefaultHeader.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/textView/TextViewDefaultHeader.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,82 @@
> +/*
> + * Copyright (C) 2014-2015 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.3
> +import Ubuntu.Components 1.1
> +import QtQuick.Layouts 1.1
> +import Ubuntu.Components.Popups 1.0
> +
> +PageHeadState {
> + id: rootItem
> +
> + property Page targetPage
> + property alias activityRunning: activity.running
> +
> + head: targetPage.head
> +
> + contents: RowLayout {
> + anchors.fill: parent
> + spacing: units.gu(1)
> +
> + ActivityIndicator { id: activity }
> +
> + Column {
> + id: layout
> + Layout.fillWidth: true
> +
> + Label {
> + width: parent.width
> + //horizontalAlignment: Text.AlignHCenter
> + elide: Text.ElideMiddle
> +
> + font.weight: Font.DemiBold
> + text: targetPage.title
> + }
> + Label {
> + width: parent.width
> + //horizontalAlignment: Text.AlignHCenter
> + elide: Text.ElideMiddle
> +
> + fontSize: "small"
> + text: file.description
> + }
> + }
> + }
> +
> + backAction: Action {
> + iconName: "back"
> + text: (pageStack.depth > 1) ? i18n.tr("Back") : i18n.tr("Close")
> + onTriggered: {
> + if (pageStack.depth > 1) {
> + // Go back to Welcome page
> + pageStack.pop();
> + } else {
> + // File has been imported through Content Hub (or was not chosen through WelcomePage)
> + // Close the application and show our source app (e.g. ubuntu-filemanager-app, if used to open a document)
> + Qt.quit()
> + }
> + }
> + }
> +
> + actions: [
> + Action {
> + objectName: "detailsAction"
> + text: i18n.tr("Details")
> + iconName: "info"
> + onTriggered: pageStack.push(Qt.resolvedUrl("../common/DetailsPage.qml"))
> + }
> + ]
> +}
>
> === modified file 'src/app/qml/ubuntu-docviewer-app.qml'
> --- src/app/qml/ubuntu-docviewer-app.qml 2015-01-29 19:14:08 +0000
> +++ src/app/qml/ubuntu-docviewer-app.qml 2015-02-27 15:45:56 +0000
> @@ -18,8 +18,9 @@
> import Ubuntu.Components 1.1
> import Ubuntu.Components.Popups 1.0
> import com.ubuntu.fileqmlplugin 1.0
> +import DocumentViewer 1.0
>
> -import "loadComponent.js" as LoadComponent
> +import "common/loadComponent.js" as LoadComponent
>
> MainView {
> id: mainView
> @@ -27,49 +28,74 @@
>
> applicationName: "com.ubuntu.docviewer"
> useDeprecatedToolbar: false
> -
> +
> + property bool pickMode: DOC_VIEWER.pickModeEnabled
> +
> width: units.gu(50)
> height: units.gu(75)
>
> + function openDocument(path) {
> + if (path !== "") {
> + console.log("Path of the document:", path)
> +
> + // If a document is already shown, pop() its page.
> + while (pageStack.depth > 1)
> + pageStack.pop();
> +
> + path = path.replace("file://", "")
> + .replace("document://", "");
> +
> + file.path = path;
> + }
> + }
> +
> + function runUnknownTypeDialog() {
> + PopupUtils.open(Qt.resolvedUrl("common/UnknownTypeDialog.qml"), mainView, { parent: mainView });
> + }
> +
> + Component.onCompleted: {
> + pageStack.push(Qt.resolvedUrl("documentPage/DocumentPage.qml"));
> +
> + // Open the document, if one has been specified.
> + openDocument(DOC_VIEWER.documentFile);
> + }
> +
> File {
> id: file
> objectName: "file"
>
> onMimetypeChanged: LoadComponent.load(mimetype)
> - onErrorChanged: { if (error == -1); PopupUtils.open(Qt.resolvedUrl("ErrorDialog.qml"), mainView, { parent: mainView }) }
> - }
> -
> - Component.onCompleted: {
> - // Check if a value has been specified for "documentPath" argument.
> - // The value for the argument is parsed in main.cpp.
> -
> - if (documentPath) {
> - // If so, send the path to the File plugin and load the document.
> - console.log("Path argument is:", documentPath);
> - file.path = documentPath;
> - } else {
> - // Otherwise, push a welcome screen in the stack.
> - pageStack.push(Qt.resolvedUrl("WelcomePage.qml"));
> - }
> - }
> -
> - // Content Importer
> - // Used when user asks to open a document from ContentHub.
> - Loader {
> - id: contentHubLoader
> -
> - asynchronous: true
> - source: Qt.resolvedUrl("ContentHubProxy.qml")
> - onStatusChanged: {
> - if (status === Loader.Ready) {
> - item.pageStack = pageStack
> - }
> - }
> - }
> -
> - function runUnknownTypeDialog() {
> - PopupUtils.open(Qt.resolvedUrl("UnknownTypeDialog.qml"), mainView, { parent: mainView });
> - }
> -
> + onErrorChanged: { if (error == -1); PopupUtils.open(Qt.resolvedUrl("common/ErrorDialog.qml"), mainView, { parent: mainView }) }
> + }
> +
> + DocumentsModel { id: folderModel }
> PageStack { id: pageStack }
> +
> + Connections {
> + target: UriHandler
> + onOpened: {
> + for (var i = 0; i < uris.length; ++i) {
> + DOC_VIEWER.parseUri(uris[i])
> + }
> + }
> + }
> +
> + Connections {
> + target: DOC_VIEWER
> +
> + onDocumentFileChanged: {
> + openDocument(DOC_VIEWER.documentFile);
> + }
> +
> + onPickModeEnabledChanged: {
> + mainView.pickMode = DOC_VIEWER.pickModeEnabled
> +
> + if (mainView.pickMode) {
> + // If a document is loaded, pop() its page.
> + while (pageStack.depth > 1) {
> + pageStack.pop()
> + }
> + }
> + }
> + }
> }
>
> === added directory 'src/app/qml/upstreamComponents'
> === added file 'src/app/qml/upstreamComponents/EmptyState.qml'
> --- src/app/qml/upstreamComponents/EmptyState.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/upstreamComponents/EmptyState.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,62 @@
> +/*
> + * Copyright (C) 2014 Canonical Ltd
> + *
> + * This file is part of Ubuntu Clock App
> + *
> + * Ubuntu Clock App is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 3 as
> + * published by the Free Software Foundation.
> + *
> + * Ubuntu Clock App is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.3
> +import Ubuntu.Components 1.1
> +
> +/*
> + Component which displays an empty state (approved by design). It offers an
> + icon, title and subtitle to describe the empty state.
> +*/
> +
> +Item {
> + id: emptyState
> +
> + // Public APIs
> + property alias iconName: emptyIcon.name
> + property alias title: emptyLabel.text
> + property alias subTitle: emptySublabel.text
> +
> + height: childrenRect.height
> +
> + Icon {
> + id: emptyIcon
> + anchors.horizontalCenter: parent.horizontalCenter
> + height: units.gu(10)
> + width: height
> + color: "#BBBBBB"
> + }
> +
> + Label {
> + id: emptyLabel
> + anchors.top: emptyIcon.bottom
> + anchors.topMargin: units.gu(5)
> + anchors.horizontalCenter: parent.horizontalCenter
> + fontSize: "large"
> + font.bold: true
> + }
> +
> + Label {
> + id: emptySublabel
> + anchors.top: emptyLabel.bottom
> +
> + width: parent.width
> + wrapMode: Text.Wrap
> + horizontalAlignment: Text.AlignHCenter
> + }
> +}
>
> === added file 'src/app/qml/upstreamComponents/HeaderButton.qml'
> --- src/app/qml/upstreamComponents/HeaderButton.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/upstreamComponents/HeaderButton.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,65 @@
> +/*
> + * Copyright (C) 2014 Canonical Ltd
> + *
> + * This file is part of Ubuntu Clock App
> + *
> + * Ubuntu Clock App is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 3 as
> + * published by the Free Software Foundation.
> + *
> + * Ubuntu Clock App is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.3
> +import Ubuntu.Components 1.1
> +
> +AbstractButton {
> + id: headerButton
> +
> + property alias iconSource: _icon.source
> + property alias iconName: _icon.name
> + property alias text: _label.text
> +
> + width: units.gu(6)
> + height: parent ? parent.height : undefined
> +
> + Rectangle {
> + anchors.fill: parent
> + visible: headerButton.pressed
> + color: Theme.palette.selected.background
> + }
> +
> + Column {
> + id: buttonHolder
> +
> + width: _label.width
> + height: childrenRect.height
> +
> + spacing: units.gu(0.2)
> + anchors.centerIn: parent
> + anchors.verticalCenterOffset: units.gu(0.3)
> +
> + Icon {
> + id: _icon
> + color: UbuntuColors.darkGrey
> + width: units.gu(2.5)
> + height: width
> + opacity: headerButton.enabled ? 1.0 : 0.3
> + anchors.horizontalCenter: parent.horizontalCenter
> + }
> +
> + Label {
> + id: _label
> + color: UbuntuColors.darkGrey
> + fontSize: "xx-small"
> + opacity: headerButton.enabled ? 1.0 : 0.3
> + anchors.horizontalCenter: _icon.horizontalCenter
> + }
> + }
> +}
>
> === added file 'src/app/qml/upstreamComponents/ListItemWithActions.qml'
> --- src/app/qml/upstreamComponents/ListItemWithActions.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/upstreamComponents/ListItemWithActions.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,453 @@
> +/*
> + * Copyright (C) 2012-2014 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.3
> +import Ubuntu.Components 1.1
> +
> +Item {
> + id: root
> +
> + property Action leftSideAction: null
> + property list<Action> rightSideActions
> + property double defaultHeight: units.gu(8)
> + property bool locked: false
> + property Action activeAction: null
> + property var activeItem: null
> + property bool triggerActionOnMouseRelease: false
> + property color color: Theme.palette.normal.background
> + property color selectedColor: "#E6E6E6"
> + property bool selected: false
> + property bool selectionMode: false
> + property alias internalAnchors: mainContents.anchors
> + default property alias contents: mainContents.children
> +
> + readonly property double actionWidth: units.gu(4)
> + readonly property double leftActionWidth: units.gu(10)
> + readonly property double actionThreshold: actionWidth * 0.4
> + readonly property double threshold: 0.4
> + readonly property string swipeState: main.x == 0 ? "Normal" : main.x > 0 ? "LeftToRight" : "RightToLeft"
> + readonly property alias swipping: mainItemMoving.running
> + readonly property bool _showActions: mouseArea.pressed || swipeState != "Normal" || swipping
> +
> + /* internal */
> + property var _visibleRightSideActions: filterVisibleActions(rightSideActions)
> +
> + signal itemClicked(var mouse)
> + signal itemPressAndHold(var mouse)
> +
> + function returnToBoundsRTL(direction)
> + {
> + var actionFullWidth = actionWidth + units.gu(2)
> +
> + // go back to normal state if swipping reverse
> + if (direction === "LTR") {
> + updatePosition(0)
> + return
> + } else if (!triggerActionOnMouseRelease) {
> + updatePosition(-rightActionsView.width + units.gu(2))
> + return
> + }
> +
> + var xOffset = Math.abs(main.x)
> + var index = Math.min(Math.floor(xOffset / actionFullWidth), _visibleRightSideActions.length)
> + var newX = 0
> + if (index === _visibleRightSideActions.length) {
> + newX = -(rightActionsView.width - units.gu(2))
> + } else if (index >= 1) {
> + newX = -(actionFullWidth * index)
> + }
> + updatePosition(newX)
> + }
> +
> + function returnToBoundsLTR(direction)
> + {
> + var finalX = leftActionWidth
> + if ((direction === "RTL") || (main.x <= (finalX * root.threshold)))
> + finalX = 0
> + updatePosition(finalX)
> + }
> +
> + function returnToBounds(direction)
> + {
> + if (main.x < 0) {
> + returnToBoundsRTL(direction)
> + } else if (main.x > 0) {
> + returnToBoundsLTR(direction)
> + } else {
> + updatePosition(0)
> + }
> + }
> +
> + function contains(item, point, marginX)
> + {
> + var itemStartX = item.x - marginX
> + var itemEndX = item.x + item.width + marginX
> + return (point.x >= itemStartX) && (point.x <= itemEndX) &&
> + (point.y >= item.y) && (point.y <= (item.y + item.height));
> + }
> +
> + function getActionAt(point)
> + {
> + if (contains(leftActionView, point, 0)) {
> + return leftSideAction
> + } else if (contains(rightActionsView, point, 0)) {
> + var newPoint = root.mapToItem(rightActionsView, point.x, point.y)
> + for (var i = 0; i < rightActionsRepeater.count; i++) {
> + var child = rightActionsRepeater.itemAt(i)
> + if (contains(child, newPoint, units.gu(1))) {
> + return i
> + }
> + }
> + }
> + return -1
> + }
> +
> + function updateActiveAction()
> + {
> + if (triggerActionOnMouseRelease &&
> + (main.x <= -(root.actionWidth + units.gu(2))) &&
> + (main.x > -(rightActionsView.width - units.gu(2)))) {
> + var actionFullWidth = actionWidth + units.gu(2)
> + var xOffset = Math.abs(main.x)
> + var index = Math.min(Math.floor(xOffset / actionFullWidth), _visibleRightSideActions.length)
> + index = index - 1
> + if (index > -1) {
> + root.activeItem = rightActionsRepeater.itemAt(index)
> + root.activeAction = root._visibleRightSideActions[index]
> + }
> + } else {
> + root.activeAction = null
> + }
> + }
> +
> + function resetSwipe()
> + {
> + updatePosition(0)
> + }
> +
> + function filterVisibleActions(actions)
> + {
> + var visibleActions = []
> + for(var i = 0; i < actions.length; i++) {
> + var action = actions[i]
> + if (action.visible) {
> + visibleActions.push(action)
> + }
> + }
> + return visibleActions
> + }
> +
> + function updatePosition(pos)
> + {
> + if (!root.triggerActionOnMouseRelease && (pos !== 0)) {
> + mouseArea.state = pos > 0 ? "RightToLeft" : "LeftToRight"
> + } else {
> + mouseArea.state = ""
> + }
> + main.x = pos
> + }
> +
> + states: [
> + State {
> + name: "select"
> + when: selectionMode || selected
> + PropertyChanges {
> + target: selectionIcon
> + source: Qt.resolvedUrl("ListItemWithActionsCheckBox.qml")
> + anchors.leftMargin: units.gu(2)
> + }
> + PropertyChanges {
> + target: root
> + locked: true
> + }
> + PropertyChanges {
> + target: main
> + x: 0
> + }
> + }
> + ]
> +
> + height: defaultHeight
> + clip: height !== defaultHeight
> +
> + Rectangle {
> + id: leftActionView
> +
> + anchors {
> + top: parent.top
> + bottom: parent.bottom
> + right: main.left
> + }
> + width: root.leftActionWidth + actionThreshold
> + visible: leftSideAction
> + color: UbuntuColors.red
> +
> + Icon {
> + anchors {
> + centerIn: parent
> + horizontalCenterOffset: actionThreshold / 2
> + }
> + name: leftSideAction && _showActions ? leftSideAction.iconName : ""
> + color: Theme.palette.selected.field
> + height: units.gu(3)
> + width: units.gu(3)
> + }
> + }
> +
> + Rectangle {
> + id: rightActionsView
> +
> + anchors {
> + top: main.top
> + left: main.right
> + bottom: main.bottom
> + }
> + visible: _visibleRightSideActions.length > 0
> + width: rightActionsRepeater.count > 0 ? rightActionsRepeater.count * (root.actionWidth + units.gu(2)) + root.actionThreshold + units.gu(2) : 0
> + color: "white"
> + Row {
> + anchors{
> + top: parent.top
> + left: parent.left
> + leftMargin: units.gu(2)
> + right: parent.right
> + rightMargin: units.gu(2)
> + bottom: parent.bottom
> + }
> + spacing: units.gu(2)
> + Repeater {
> + id: rightActionsRepeater
> +
> + model: _showActions ? _visibleRightSideActions : []
> + Item {
> + property alias image: img
> +
> + height: rightActionsView.height
> + width: root.actionWidth
> +
> + Icon {
> + id: img
> +
> + anchors.centerIn: parent
> + width: units.gu(3)
> + height: units.gu(3)
> + name: modelData.iconName
> + color: root.activeAction === modelData ? UbuntuColors.lightAubergine : UbuntuColors.lightGrey
> + }
> + }
> + }
> + }
> + }
> +
> +
> + Rectangle {
> + id: main
> + objectName: "mainItem"
> +
> + anchors {
> + top: parent.top
> + bottom: parent.bottom
> + }
> +
> + width: parent.width
> + color: root.selected ? root.selectedColor : root.color
> +
> + Loader {
> + id: selectionIcon
> +
> + anchors {
> + left: main.left
> + verticalCenter: main.verticalCenter
> + }
> + width: (status === Loader.Ready) ? item.implicitWidth : 0
> + visible: (status === Loader.Ready) && (item.width === item.implicitWidth)
> + Behavior on width {
> + NumberAnimation {
> + duration: UbuntuAnimation.SnapDuration
> + }
> + }
> + }
> +
> +
> + Item {
> + id: mainContents
> +
> + anchors {
> + left: selectionIcon.right
> + leftMargin: units.gu(2)
> + top: parent.top
> + topMargin: units.gu(1)
> + right: parent.right
> + rightMargin: units.gu(2)
> + bottom: parent.bottom
> + bottomMargin: units.gu(1)
> + }
> + }
> +
> + Behavior on x {
> + UbuntuNumberAnimation {
> + id: mainItemMoving
> +
> + easing.type: Easing.OutElastic
> + duration: UbuntuAnimation.SlowDuration
> + }
> + }
> + Behavior on color {
> + ColorAnimation {}
> + }
> + }
> +
> + SequentialAnimation {
> + id: triggerAction
> +
> + property var currentItem: root.activeItem ? root.activeItem.image : null
> +
> + running: false
> + ParallelAnimation {
> + UbuntuNumberAnimation {
> + target: triggerAction.currentItem
> + property: "opacity"
> + from: 1.0
> + to: 0.0
> + duration: UbuntuAnimation.SlowDuration
> + easing {type: Easing.InOutBack; }
> + }
> + UbuntuNumberAnimation {
> + target: triggerAction.currentItem
> + properties: "width, height"
> + from: units.gu(3)
> + to: root.actionWidth
> + duration: UbuntuAnimation.SlowDuration
> + easing {type: Easing.InOutBack; }
> + }
> + }
> + PropertyAction {
> + target: triggerAction.currentItem
> + properties: "width, height"
> + value: units.gu(3)
> + }
> + PropertyAction {
> + target: triggerAction.currentItem
> + properties: "opacity"
> + value: 1.0
> + }
> + ScriptAction {
> + script: {
> + root.activeAction.triggered(root)
> + mouseArea.state = ""
> + }
> + }
> + PauseAnimation {
> + duration: 500
> + }
> + UbuntuNumberAnimation {
> + target: main
> + property: "x"
> + to: 0
> +
> + }
> + }
> +
> + MouseArea {
> + id: mouseArea
> +
> + property bool locked: root.locked || ((root.leftSideAction === null) && (root._visibleRightSideActions.count === 0))
> + property bool manual: false
> + property string direction: "None"
> + property real lastX: -1
> +
> + anchors.fill: parent
> + drag {
> + target: locked ? null : main
> + axis: Drag.XAxis
> + minimumX: rightActionsView.visible ? -(rightActionsView.width) : 0
> + maximumX: leftActionView.visible ? leftActionView.width : 0
> + threshold: root.actionThreshold
> + }
> +
> + states: [
> + State {
> + name: "LeftToRight"
> + PropertyChanges {
> + target: mouseArea
> + drag.maximumX: 0
> + }
> + },
> + State {
> + name: "RightToLeft"
> + PropertyChanges {
> + target: mouseArea
> + drag.minimumX: 0
> + }
> + }
> + ]
> +
> + onMouseXChanged: {
> + var offset = (lastX - mouseX)
> + if (Math.abs(offset) <= root.actionThreshold) {
> + return
> + }
> + lastX = mouseX
> + direction = offset > 0 ? "RTL" : "LTR";
> + }
> +
> + onPressed: {
> + lastX = mouse.x
> + }
> +
> + onReleased: {
> + if (root.triggerActionOnMouseRelease && root.activeAction) {
> + triggerAction.start()
> + } else {
> + root.returnToBounds(direction)
> + root.activeAction = null
> + }
> + lastX = -1
> + direction = "None"
> + }
> + onClicked: {
> + if (main.x === 0) {
> + root.itemClicked(mouse)
> + } else if (main.x > 0) {
> + var action = getActionAt(Qt.point(mouse.x, mouse.y))
> + if (action && action !== -1) {
> + action.triggered(root)
> + }
> + } else {
> + var actionIndex = getActionAt(Qt.point(mouse.x, mouse.y))
> + if (actionIndex !== -1) {
> + root.activeItem = rightActionsRepeater.itemAt(actionIndex)
> + root.activeAction = root._visibleRightSideActions[actionIndex]
> + triggerAction.start()
> + return
> + }
> + }
> + root.resetSwipe()
> + }
> +
> + onPositionChanged: {
> + if (mouseArea.pressed) {
> + updateActiveAction()
> + }
> + }
> + onPressAndHold: {
> + if (main.x === 0) {
> + root.itemPressAndHold(mouse)
> + }
> + }
> + z: -1
> + }
> +}
>
> === added file 'src/app/qml/upstreamComponents/ListItemWithActionsCheckBox.qml'
> --- src/app/qml/upstreamComponents/ListItemWithActionsCheckBox.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/upstreamComponents/ListItemWithActionsCheckBox.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,25 @@
> +/*
> + * Copyright (C) 2012-2014 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.3
> +import Ubuntu.Components 1.1
> +
> +CheckBox {
> + checked: root.selected
> + width: implicitWidth
> + // disable item mouse area to avoid conflicts with parent mouse area
> + __mouseArea.enabled: false
> +}
>
> === added file 'src/app/qml/upstreamComponents/MultipleSelectionGridView.qml'
> --- src/app/qml/upstreamComponents/MultipleSelectionGridView.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/upstreamComponents/MultipleSelectionGridView.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,199 @@
> +/*
> + * Copyright (C) 2013 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.3
> +import Ubuntu.Components 1.1
> +import Ubuntu.Components.Popups 1.0 as Popups
> +
> +/*!
> + \qmltype ContactSimpleListView
> + \inqmlmodule Ubuntu.Contacts 0.1
> + \ingroup ubuntu
> + \brief The MultipleSelectionListView provides a ListView with support to multiple selection
> +
> + The MultipleSelectionListViewprovides a ListView with support to multiple selection which can be used by any
> + application.
> +
> + Example:
> + \qml
> + import Ubuntu.Contacts 0.1
> +
> + MultipleSelectionListView {
> + id: view
> + anchors.fill: paret
> + model: 100
> + delegate: Rectangle {
> + width: parent.width
> + height: 100
> + color: view.selectedItems.indexOf(index) == -1 ? "white" : "blue"
> +
> + MouseArea {
> + anchors.fill: parent
> + onClicked: {
> + if (view.isInSelectionModel) {
> + view.selectItem(index)
> + }
> + }
> + onPressAndHold: view.startSelection()
> + }
> + }
> + onSelectionDone: console.debug("Selected items:" + view.selectedItems)
> + }
> + \endqml
> +*/
> +
> +GridView {
> + id: listView
> +
> + /*!
> + \qmlproperty model selectedItems
> +
> + This property holds the list of selected items
> + */
> + readonly property alias selectedItems: visualModel.selectedItems
> + /*!
> + \qmlproperty bool multipleSelection
> +
> + This property holds if the selection will accept multiple items or single items
> + */
> + property bool multipleSelection: true
> +
> + /*!
> + \qmlproperty model listModel
> +
> + This property holds the model providing data for the list.
> + */
> + property alias listModel: visualModel.model
> + /*!
> + \qmlproperty Component listDelegate
> +
> + The delegate provides a template defining each item instantiated by the view.
> + */
> + property alias listDelegate: visualModel.delegate
> +
> + /*!
> + \qmlproperty bool isInSelectionMode
> +
> + This property holds a list with the index of selected items
> + */
> + readonly property bool isInSelectionMode: state === "selection"
> + /*!
> + This handler is called when the selection mode is finished without be canceled
> + */
> + signal selectionDone(var items)
> + /*!
> + This handler is called when the selection mode is canceled
> + */
> + signal selectionCanceled()
> +
> + /*!
> + Start the selection mode on the list view.
> + */
> + function startSelection()
> + {
> + state = "selection"
> + }
> + /*!
> + Check if the item is selected
> + Returns true if the item was marked as selected or false if the item is unselected
> + */
> + function isSelected(item)
> + {
> + if (item && item.VisualDataModel) {
> + return (item.VisualDataModel.inSelected === true)
> + } else {
> + return false
> + }
> + }
> + /*!
> + Mark the item as selected
> + Returns true if the item was marked as selected or false if the item is already selected
> + */
> + function selectItem(item)
> + {
> + if (item.VisualDataModel.inSelected) {
> + return false
> + } else {
> + if (!multipleSelection) {
> + clearSelection()
> + }
> + item.VisualDataModel.inSelected = true
> + return true
> + }
> + }
> + /*!
> + Remove the index from the selected list
> + */
> + function deselectItem(item)
> + {
> + var result = false
> + if (item.VisualDataModel.inSelected) {
> + item.VisualDataModel.inSelected = false
> + result = true
> + }
> + return result
> + }
> + /*!
> + Finish the selection mode with sucess
> + */
> + function endSelection()
> + {
> + selectionDone(listView.selectedItems)
> + clearSelection()
> + state = ""
> + }
> + /*!
> + Cancel the selection
> + */
> + function cancelSelection()
> + {
> + selectionCanceled()
> + clearSelection()
> + state = ""
> + }
> + /*!
> + Remove any selected item from the selection list
> + */
> + function clearSelection()
> + {
> + if (selectedItems.count > 0) {
> + selectedItems.remove(0, selectedItems.count)
> + }
> + }
> + /*!
> + Select all items in the list
> + */
> + function selectAll()
> + {
> + if (multipleSelection) {
> + visualModel.items.addGroups(0, visualModel.items.count, ["selected"] )
> + }
> + }
> +
> + model: visualModel
> +
> + MultipleSelectionVisualModel {
> + id: visualModel
> + }
> +
> + Component.onCompleted: {
> + // FIXME: workaround for qtubuntu not returning values depending on the grid unit definition
> + // for Flickable.maximumFlickVelocity and Flickable.flickDeceleration
> + var scaleFactor = units.gridUnit / 8;
> + maximumFlickVelocity = maximumFlickVelocity * scaleFactor;
> + flickDeceleration = flickDeceleration * scaleFactor;
> + }
> +}
>
> === added file 'src/app/qml/upstreamComponents/MultipleSelectionListView.qml'
> --- src/app/qml/upstreamComponents/MultipleSelectionListView.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/upstreamComponents/MultipleSelectionListView.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,199 @@
> +/*
> + * Copyright (C) 2013 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.3
> +import Ubuntu.Components 1.1
> +import Ubuntu.Components.Popups 1.0 as Popups
> +
> +/*!
> + \qmltype ContactSimpleListView
> + \inqmlmodule Ubuntu.Contacts 0.1
> + \ingroup ubuntu
> + \brief The MultipleSelectionListView provides a ListView with support to multiple selection
> +
> + The MultipleSelectionListViewprovides a ListView with support to multiple selection which can be used by any
> + application.
> +
> + Example:
> + \qml
> + import Ubuntu.Contacts 0.1
> +
> + MultipleSelectionListView {
> + id: view
> + anchors.fill: paret
> + model: 100
> + delegate: Rectangle {
> + width: parent.width
> + height: 100
> + color: view.selectedItems.indexOf(index) == -1 ? "white" : "blue"
> +
> + MouseArea {
> + anchors.fill: parent
> + onClicked: {
> + if (view.isInSelectionModel) {
> + view.selectItem(index)
> + }
> + }
> + onPressAndHold: view.startSelection()
> + }
> + }
> + onSelectionDone: console.debug("Selected items:" + view.selectedItems)
> + }
> + \endqml
> +*/
> +
> +ListView {
> + id: listView
> +
> + /*!
> + \qmlproperty model selectedItems
> +
> + This property holds the list of selected items
> + */
> + readonly property alias selectedItems: visualModel.selectedItems
> + /*!
> + \qmlproperty bool multipleSelection
> +
> + This property holds if the selection will accept multiple items or single items
> + */
> + property bool multipleSelection: true
> +
> + /*!
> + \qmlproperty model listModel
> +
> + This property holds the model providing data for the list.
> + */
> + property alias listModel: visualModel.model
> + /*!
> + \qmlproperty Component listDelegate
> +
> + The delegate provides a template defining each item instantiated by the view.
> + */
> + property alias listDelegate: visualModel.delegate
> +
> + /*!
> + \qmlproperty bool isInSelectionMode
> +
> + This property holds a list with the index of selected items
> + */
> + readonly property bool isInSelectionMode: state === "selection"
> + /*!
> + This handler is called when the selection mode is finished without be canceled
> + */
> + signal selectionDone(var items)
> + /*!
> + This handler is called when the selection mode is canceled
> + */
> + signal selectionCanceled()
> +
> + /*!
> + Start the selection mode on the list view.
> + */
> + function startSelection()
> + {
> + state = "selection"
> + }
> + /*!
> + Check if the item is selected
> + Returns true if the item was marked as selected or false if the item is unselected
> + */
> + function isSelected(item)
> + {
> + if (item && item.VisualDataModel) {
> + return (item.VisualDataModel.inSelected === true)
> + } else {
> + return false
> + }
> + }
> + /*!
> + Mark the item as selected
> + Returns true if the item was marked as selected or false if the item is already selected
> + */
> + function selectItem(item)
> + {
> + if (item.VisualDataModel.inSelected) {
> + return false
> + } else {
> + if (!multipleSelection) {
> + clearSelection()
> + }
> + item.VisualDataModel.inSelected = true
> + return true
> + }
> + }
> + /*!
> + Remove the index from the selected list
> + */
> + function deselectItem(item)
> + {
> + var result = false
> + if (item.VisualDataModel.inSelected) {
> + item.VisualDataModel.inSelected = false
> + result = true
> + }
> + return result
> + }
> + /*!
> + Finish the selection mode with sucess
> + */
> + function endSelection()
> + {
> + selectionDone(listView.selectedItems)
> + clearSelection()
> + state = ""
> + }
> + /*!
> + Cancel the selection
> + */
> + function cancelSelection()
> + {
> + selectionCanceled()
> + clearSelection()
> + state = ""
> + }
> + /*!
> + Remove any selected item from the selection list
> + */
> + function clearSelection()
> + {
> + if (selectedItems.count > 0) {
> + selectedItems.remove(0, selectedItems.count)
> + }
> + }
> + /*!
> + Select all items in the list
> + */
> + function selectAll()
> + {
> + if (multipleSelection) {
> + visualModel.items.addGroups(0, visualModel.items.count, ["selected"] )
> + }
> + }
> +
> + model: visualModel
> +
> + MultipleSelectionVisualModel {
> + id: visualModel
> + }
> +
> + Component.onCompleted: {
> + // FIXME: workaround for qtubuntu not returning values depending on the grid unit definition
> + // for Flickable.maximumFlickVelocity and Flickable.flickDeceleration
> + var scaleFactor = units.gridUnit / 8;
> + maximumFlickVelocity = maximumFlickVelocity * scaleFactor;
> + flickDeceleration = flickDeceleration * scaleFactor;
> + }
> +}
>
> === added file 'src/app/qml/upstreamComponents/MultipleSelectionVisualModel.qml'
> --- src/app/qml/upstreamComponents/MultipleSelectionVisualModel.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/upstreamComponents/MultipleSelectionVisualModel.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,31 @@
> +/*
> + * Copyright (C) 2012-2013 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.3
> +
> +VisualDataModel {
> + id: contactVisualModel
> +
> + property alias selectedItems: selectedGroup
> +
> + groups: [
> + VisualDataGroup {
> + id: selectedGroup
> +
> + name: "selected"
> + }
> + ]
> +}
>
> === added file 'src/app/qml/upstreamComponents/PageWithBottomEdge.qml'
> --- src/app/qml/upstreamComponents/PageWithBottomEdge.qml 1970-01-01 00:00:00 +0000
> +++ src/app/qml/upstreamComponents/PageWithBottomEdge.qml 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,407 @@
> +/*
> + * Copyright (C) 2014 Canonical, Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +/*
> + Example:
> +
> + MainView {
> + objectName: "mainView"
> +
> + applicationName: "com.ubuntu.developer.boiko.bottomedge"
> +
> + width: units.gu(100)
> + height: units.gu(75)
> +
> + Component {
> + id: pageComponent
> +
> + PageWithBottomEdge {
> + id: mainPage
> + title: i18n.tr("Main Page")
> +
> + Rectangle {
> + anchors.fill: parent
> + color: "white"
> + }
> +
> + bottomEdgePageComponent: Page {
> + title: "Contents"
> + anchors.fill: parent
> + //anchors.topMargin: contentsPage.flickable.contentY
> +
> + ListView {
> + anchors.fill: parent
> + model: 50
> + delegate: ListItems.Standard {
> + text: "One Content Item: " + index
> + }
> + }
> + }
> + bottomEdgeTitle: i18n.tr("Bottom edge action")
> + }
> + }
> +
> + PageStack {
> + id: stack
> + Component.onCompleted: stack.push(pageComponent)
> + }
> + }
> +
> +*/
> +
> +import QtQuick 2.2
> +import Ubuntu.Components 1.1
> +
> +Page {
> + id: page
> +
> + property alias bottomEdgePageComponent: edgeLoader.sourceComponent
> + property alias bottomEdgePageSource: edgeLoader.source
> + property alias bottomEdgeTitle: tipLabel.text
> + property bool bottomEdgeEnabled: true
> + property int bottomEdgeExpandThreshold: page.height * 0.2
> + property int bottomEdgeExposedArea: bottomEdge.state !== "expanded" ? (page.height - bottomEdge.y - bottomEdge.tipHeight) : _areaWhenExpanded
> + property bool reloadBottomEdgePage: true
> +
> + readonly property alias bottomEdgePage: edgeLoader.item
> + readonly property bool isReady: ((bottomEdge.y === 0) && bottomEdgePageLoaded && edgeLoader.item.active)
> + readonly property bool isCollapsed: (bottomEdge.y === page.height)
> + readonly property bool bottomEdgePageLoaded: (edgeLoader.status == Loader.Ready)
> +
> + property bool _showEdgePageWhenReady: false
> + property int _areaWhenExpanded: 0
> +
> + signal bottomEdgeReleased()
> + signal bottomEdgeDismissed()
> +
> +
> + function showBottomEdgePage(source, properties)
> + {
> + edgeLoader.setSource(source, properties)
> + _showEdgePageWhenReady = true
> + }
> +
> + function setBottomEdgePage(source, properties)
> + {
> + edgeLoader.setSource(source, properties)
> + }
> +
> + function _pushPage()
> + {
> + if (edgeLoader.status === Loader.Ready) {
> + edgeLoader.item.active = true
> + page.pageStack.push(edgeLoader.item)
> + if (edgeLoader.item.flickable) {
> + edgeLoader.item.flickable.contentY = -page.header.height
> + edgeLoader.item.flickable.returnToBounds()
> + }
> + if (edgeLoader.item.ready)
> + edgeLoader.item.ready()
> + }
> + }
> +
> +
> + Component.onCompleted: {
> + // avoid a binding on the expanded height value
> + var expandedHeight = height;
> + _areaWhenExpanded = expandedHeight;
> + }
> +
> + onActiveChanged: {
> + if (active) {
> + bottomEdge.state = "collapsed"
> + }
> + }
> +
> + onBottomEdgePageLoadedChanged: {
> + if (_showEdgePageWhenReady && bottomEdgePageLoaded) {
> + bottomEdge.state = "expanded"
> + _showEdgePageWhenReady = false
> + }
> + }
> +
> + Rectangle {
> + id: bgVisual
> +
> + color: "black"
> + anchors.fill: page
> + opacity: 0.7 * ((page.height - bottomEdge.y) / page.height)
> + z: 1
> + }
> +
> + UbuntuShape {
> + id: tip
> + objectName: "bottomEdgeTip"
> +
> + property bool hidden: (activeFocus === false) || ((bottomEdge.y - units.gu(1)) < tip.y)
> +
> + enabled: mouseArea.enabled
> + visible: page.bottomEdgeEnabled
> + anchors {
> + bottom: parent.bottom
> + horizontalCenter: bottomEdge.horizontalCenter
> + bottomMargin: hidden ? - height + units.gu(1) : -units.gu(1)
> + Behavior on bottomMargin {
> + SequentialAnimation {
> + // wait some msecs in case of the focus change again, to avoid flickering
> + PauseAnimation {
> + duration: 300
> + }
> + UbuntuNumberAnimation {
> + duration: UbuntuAnimation.SnapDuration
> + }
> + }
> + }
> + }
> +
> + z: 1
> + width: tipLabel.paintedWidth + units.gu(6)
> + height: bottomEdge.tipHeight + units.gu(1)
> + color: Theme.palette.normal.overlay
> + Label {
> + id: tipLabel
> +
> + anchors {
> + top: parent.top
> + left: parent.left
> + right: parent.right
> + }
> + height: bottomEdge.tipHeight
> + verticalAlignment: Text.AlignVCenter
> + horizontalAlignment: Text.AlignHCenter
> + opacity: tip.hidden ? 0.0 : 1.0
> + Behavior on opacity {
> + UbuntuNumberAnimation {
> + duration: UbuntuAnimation.SnapDuration
> + }
> + }
> + }
> + }
> +
> + Rectangle {
> + id: shadow
> +
> + anchors {
> + left: parent.left
> + right: parent.right
> + bottom: parent.bottom
> + }
> + height: units.gu(1)
> + z: 1
> + opacity: 0.0
> + gradient: Gradient {
> + GradientStop { position: 0.0; color: "transparent" }
> + GradientStop { position: 1.0; color: Qt.rgba(0, 0, 0, 0.2) }
> + }
> + }
> +
> + MouseArea {
> + id: mouseArea
> +
> + property real previousY: -1
> + property string dragDirection: "None"
> +
> + preventStealing: true
> + drag {
> + axis: Drag.YAxis
> + target: bottomEdge
> + minimumY: bottomEdge.pageStartY
> + maximumY: page.height
> + }
> + enabled: edgeLoader.status == Loader.Ready
> + visible: page.bottomEdgeEnabled
> +
> + anchors {
> + left: parent.left
> + right: parent.right
> + bottom: parent.bottom
> +
> + }
> + height: bottomEdge.tipHeight
> + z: 1
> +
> + onReleased: {
> + page.bottomEdgeReleased()
> + if ((dragDirection === "BottomToTop") &&
> + bottomEdge.y < (page.height - bottomEdgeExpandThreshold - bottomEdge.tipHeight)) {
> + bottomEdge.state = "expanded"
> + } else {
> + bottomEdge.state = "collapsed"
> + }
> + previousY = -1
> + dragDirection = "None"
> + }
> +
> + onPressed: {
> + previousY = mouse.y
> + tip.forceActiveFocus()
> + }
> +
> + onMouseYChanged: {
> + var yOffset = previousY - mouseY
> + // skip if was a small move
> + if (Math.abs(yOffset) <= units.gu(2)) {
> + return
> + }
> + previousY = mouseY
> + dragDirection = yOffset > 0 ? "BottomToTop" : "TopToBottom"
> + }
> + }
> +
> + Rectangle {
> + id: bottomEdge
> + objectName: "bottomEdge"
> +
> + readonly property int tipHeight: units.gu(3)
> + readonly property int pageStartY: 0
> +
> + z: 1
> + color: Theme.palette.normal.background
> + clip: true
> + anchors {
> + left: parent.left
> + right: parent.right
> + }
> + height: page.height
> + y: height
> + visible: !page.isCollapsed
> + state: "collapsed"
> + states: [
> + State {
> + name: "collapsed"
> + PropertyChanges {
> + target: bottomEdge
> + y: bottomEdge.height
> + }
> + },
> + State {
> + name: "expanded"
> + PropertyChanges {
> + target: bottomEdge
> + y: bottomEdge.pageStartY
> + }
> + },
> + State {
> + name: "floating"
> + when: mouseArea.drag.active
> + PropertyChanges {
> + target: shadow
> + opacity: 1.0
> + }
> + }
> + ]
> +
> + transitions: [
> + Transition {
> + to: "expanded"
> + SequentialAnimation {
> + alwaysRunToEnd: true
> +
> + SmoothedAnimation {
> + target: bottomEdge
> + property: "y"
> + duration: UbuntuAnimation.FastDuration
> + easing.type: Easing.Linear
> + }
> + SmoothedAnimation {
> + target: edgeLoader
> + property: "anchors.topMargin"
> + to: - units.gu(4)
> + duration: UbuntuAnimation.FastDuration
> + easing.type: Easing.Linear
> + }
> + SmoothedAnimation {
> + target: edgeLoader
> + property: "anchors.topMargin"
> + to: 0
> + duration: UbuntuAnimation.FastDuration
> + easing: UbuntuAnimation.StandardEasing
> + }
> + ScriptAction {
> + script: page._pushPage()
> + }
> + }
> + },
> + Transition {
> + from: "expanded"
> + to: "collapsed"
> + SequentialAnimation {
> + alwaysRunToEnd: true
> +
> + ScriptAction {
> + script: {
> + Qt.inputMethod.hide()
> + edgeLoader.item.parent = edgeLoader
> + edgeLoader.item.anchors.fill = edgeLoader
> + edgeLoader.item.active = false
> + }
> + }
> + SmoothedAnimation {
> + target: bottomEdge
> + property: "y"
> + duration: UbuntuAnimation.SlowDuration
> + }
> + ScriptAction {
> + script: {
> + // destroy current bottom page
> + if (page.reloadBottomEdgePage) {
> + edgeLoader.active = false
> + // tip will receive focus on page active true
> + } else {
> + tip.forceActiveFocus()
> + }
> +
> + // notify
> + page.bottomEdgeDismissed()
> +
> + edgeLoader.active = true
> + }
> + }
> + }
> + },
> + Transition {
> + from: "floating"
> + to: "collapsed"
> + SmoothedAnimation {
> + target: bottomEdge
> + property: "y"
> + duration: UbuntuAnimation.FastDuration
> + }
> + }
> + ]
> +
> + Loader {
> + id: edgeLoader
> +
> + asynchronous: true
> + anchors.fill: parent
> + //WORKAROUND: The SDK move the page contents down to allocate space for the header we need to avoid that during the page dragging
> + Binding {
> + target: edgeLoader.status === Loader.Ready ? edgeLoader : null
> + property: "anchors.topMargin"
> + value: edgeLoader.item && edgeLoader.item.flickable ? edgeLoader.item.flickable.contentY : 0
> + when: !page.isReady
> + }
> +
> + onLoaded: {
> + tip.forceActiveFocus()
> + if (page.isReady && edgeLoader.item.active !== true) {
> + page._pushPage()
> + }
> + }
> + }
> + }
> +}
>
> === removed file 'src/app/qml/utils.js'
> --- src/app/qml/utils.js 2015-01-29 18:45:21 +0000
> +++ src/app/qml/utils.js 1970-01-01 00:00:00 +0000
> @@ -1,34 +0,0 @@
> -/*
> - * Copyright (C) 2013-2015 Canonical, Ltd.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; version 3.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -.pragma library
> -
> -function printSize(size) {
> - if (size >= 1073741824)
> - return (size / 1073741824).toFixed(2) + " GiB";
> -
> - if (size >= 1048576)
> - return (size / 1048576).toFixed(2) + " MiB";
> -
> - if (size >= 1024)
> - return parseInt(size / 1024) + " KiB";
> -
> - return size + " byte";
> -};
> -
> -function getNameOfFile(path) {
> - return path.toString().substring(path.lastIndexOf('/') + 1);
> -}
>
> === added directory 'src/app/quick'
> === added file 'src/app/quick/documentmodel.cpp'
> --- src/app/quick/documentmodel.cpp 1970-01-01 00:00:00 +0000
> +++ src/app/quick/documentmodel.cpp 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,212 @@
> +/*
> + * Copyright (C) 2014, 2015
> + * Stefano Verzegnassi <stefano92.100@xxxxxxxxx>
> + *
> + * This is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 3 of the License.
> + *
> + * This is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see http://www.gnu.org/licenses/.
> + */
> +
> +#include "documentmodel.h"
> +
> +#include <QMimeDatabase>
> +#include <QDateTime>
> +#include <QFileInfo>
> +#include <QDir>
> +#include <QDebug>
> +
> +DocumentModel::DocumentModel(QObject *parent)
> + : QAbstractListModel(parent)
> +{
> + m_docsMonitor = new QFileSystemWatcher;
> +
> + connect(m_docsMonitor, SIGNAL(directoryChanged(QString)), this,
> + SLOT(_q_directoryChanged(QString)));
> +
> + m_docsMonitor->addPath(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
> +
> + Q_FOREACH (const QString dir, m_docsMonitor->directories()) {
> + parseDirectoryContent(dir);
> + }
> +}
> +
> +void DocumentModel::_q_directoryChanged(QString path)
> +{
> + QMutableListIterator<DocumentItem> i(m_docs);
> + int n = 0;
> + int m = 0;
> +
> + while (i.hasNext()) {
> + if (i.next().path.startsWith(path)) {
> + beginRemoveRows(QModelIndex(), n-m, n-m);
> + i.remove();
> + endRemoveRows();
> + m++;
> + }
> + n++;
> + }
> +
> + parseDirectoryContent(path);
> +}
> +
> +void DocumentModel::parseDirectoryContent(QString path)
> +{
> + QDirIterator dir(path, QDir::Files | QDir::NoDotAndDotDot | QDir::Readable,
> + QDirIterator::Subdirectories);
> +
> + while (dir.hasNext()) {
> + dir.next();
> +
> + QDateTime now = QDateTime::currentDateTime();
> + //qDebug() << "Current date is:" << now.toString("dd-MM-yyyy");
> +
> + QMimeDatabase db;
> + QString mimetype = db.mimeTypeForFile(dir.filePath()).name();
> +
> + if (mimetype.startsWith("text/") || mimetype == "application/pdf") {
> + QFileInfo file(dir.filePath());
> + DocumentItem item;
> +
> + QDateTime lastAccess = file.lastRead();
> +
> + item.name = file.fileName();
> + item.path = file.absoluteFilePath();
> + item.mimetype = mimetype;
> + item.date = lastAccess.toMSecsSinceEpoch();
> + item.size = file.size();
> +
> + qint64 dateDiff = lastAccess.daysTo(now);
> + if (dateDiff == 0) {
> + item.dateDiff = 0;
> + }
> + else if (dateDiff == 1) {
> + item.dateDiff = 1;
> + }
> + else if (dateDiff < 7) {
> + item.dateDiff = 2;
> + }
> + else if (dateDiff < 30) {
> + item.dateDiff = 3;
> + }
> + else {
> + item.dateDiff = 4;
> + }
> + //qDebug() << "Item" << item.name << "Date:" << item.date;
> + //qDebug() << "Item" << item.name << "Item date is:" << lastAccess.toString("dd-MM-yyyy") << "diff is" << dateDiff << "DateDiff is:" << item.dateDiff;
> +
> + addDocumentEntry(item);
> + }
> + }
> +}
> +
> +QHash<int, QByteArray> DocumentModel::roleNames() const
> +{
> + QHash<int, QByteArray> roles;
> + roles[PathRole] = "path";
> + roles[NameRole] = "name";
> + roles[MimetypeRole] = "mimetype";
> + roles[DateRole] = "date";
> + roles[DateDiffRole] = "dateDiff";
> + roles[SizeRole] = "size";
> +
> + return roles;
> +}
> +
> +void DocumentModel::addDocumentEntry(DocumentItem item)
> +{
> + beginInsertRows(QModelIndex(), rowCount(), rowCount());
> + m_docs.append(item);
> + endInsertRows();
> +}
> +
> +void DocumentModel::removeDocumentEntry(int index)
> +{
> + beginRemoveRows(QModelIndex(), rowCount(), rowCount());
> + m_docs.removeAt(index);
> + endRemoveRows();
> +}
> +
> +int DocumentModel::rowCount(const QModelIndex & parent) const
> +{
> + Q_UNUSED(parent)
> + return m_docs.count();
> +}
> +
> +QVariant DocumentModel::data(const QModelIndex & index, int role) const
> +{
> + if (index.row() < 0 || index.row() > m_docs.count())
> + return QVariant();
> +
> + const DocumentItem &item = m_docs.at(index.row());
> +
> + switch (role) {
> + case PathRole:
> + return item.path;
> + case NameRole:
> + return item.name;
> + case MimetypeRole:
> + return item.mimetype;
> + case DateRole:
> + return item.date;
> + case DateDiffRole:
> + return item.dateDiff;
> + case SizeRole:
> + return item.size;
> + default:
> + return 0;
> + }
> +}
> +
> +DocumentModel::~DocumentModel()
> +{
> + delete m_docsMonitor;
> +}
> +
> +SortFilterDocumentModel::SortFilterDocumentModel(QObject *parent)
> + : QSortFilterProxyModel(parent)
> +{
> + m_model = new DocumentModel();
> + setSourceModel(m_model);
> + connect(m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SIGNAL(countChanged()));
> + connect(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SIGNAL(countChanged()));
> +
> + setSortRole(DocumentModel::DateRole);
> + setSortCaseSensitivity(Qt::CaseInsensitive);
> + setSortLocaleAware(true);
> +
> + sort(0, Qt::DescendingOrder);
> + setDynamicSortFilter(true);
> +}
> +
> +SortFilterDocumentModel::~SortFilterDocumentModel()
> +{
> + delete m_model;
> +}
> +
> +int SortFilterDocumentModel::rowCount()
> +{
> + return m_model->rowCount();
> +}
> +
> +bool SortFilterDocumentModel::rm(QString path)
> +{
> + bool result = false;
> + QDir dir(path);
> +
> + if (dir.exists()) {
> + result = dir.removeRecursively();
> + } else {
> + QFile fi(path);
> + result = fi.remove();
> + }
> +
> + return result;
> +}
>
> === added file 'src/app/quick/documentmodel.h'
> --- src/app/quick/documentmodel.h 1970-01-01 00:00:00 +0000
> +++ src/app/quick/documentmodel.h 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,89 @@
> +/*
> + Copyright (C) 2014, 2015 Stefano Verzegnassi <stefano92.100@xxxxxxxxx>
> +
> + This is free software: you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation, either version 3 of the License.
> +
> + This is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see http://www.gnu.org/licenses/.
> +*/
> +
> +#ifndef DOCUMENTMODEL_H
> +#define DOCUMENTMODEL_H
> +
> +#include <QAbstractListModel>
> +#include <QSortFilterProxyModel>
> +
> +#include <QStandardPaths>
> +#include <QFileSystemWatcher>
> +#include <QDirIterator>
> +
> +struct DocumentItem {
> + QString name;
> + QString path;
> + QString mimetype;
> + qint64 date;
> + int dateDiff;
> + qint64 size;
> +};
> +
> +class DocumentModel : public QAbstractListModel
> +{
> + Q_OBJECT
> +public:
> + enum Roles {
> + NameRole = Qt::UserRole + 1,
> + PathRole,
> + MimetypeRole,
> + DateRole,
> + DateDiffRole,
> + SizeRole
> + };
> +
> + DocumentModel(QObject *parent = 0);
> + ~DocumentModel();
> +
> + QHash<int, QByteArray> roleNames() const;
> +
> + int rowCount(const QModelIndex & parent = QModelIndex()) const;
> + QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
> +
> + void parseDirectoryContent(QString path);
> +
> +private Q_SLOTS:
> + void _q_directoryChanged(QString path);
> +
> +private:
> + void addDocumentEntry(DocumentItem item);
> + void removeDocumentEntry(int index);
> +
> + QList<DocumentItem> m_docs;
> + QFileSystemWatcher *m_docsMonitor;
> +};
> +
> +class SortFilterDocumentModel : public QSortFilterProxyModel
> +{
> + Q_OBJECT
> + Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
> +
> +public:
> + SortFilterDocumentModel(QObject *parent = 0);
> + ~SortFilterDocumentModel();
> +
> + int rowCount();
> + Q_INVOKABLE bool rm(QString path);
> +
> +Q_SIGNALS:
> + void countChanged();
> +
> +private:
> + DocumentModel *m_model;
> +};
> +
> +#endif // DOCUMENTMODEL_H
>
> === added file 'src/app/urlhandler.cpp'
> --- src/app/urlhandler.cpp 1970-01-01 00:00:00 +0000
> +++ src/app/urlhandler.cpp 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,70 @@
> +/*
> + * Copyright (C) 2014 Canonical, Ltd.
> + *
> + * Authors:
> + * Arthur Mello <arthur.mello@xxxxxxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#include "urlhandler.h"
> +
> +#include <QUrl>
> +#include <QStringList>
> +#include <QFileInfo>
> +#include <QDir>
> +#include <QDebug>
> +
> +UrlHandler::UrlHandler()
> + : m_documentFile("")
> +{
> + m_validSchemes << "document";
> +}
> +
> +/*!
> + * @brief UrlHandler::processUri parsers our input uri and sets attributes accordingly.
> + * @param QString uri to parse and set attributes.
> + * @return false if invalid parameter is input.
> + */
> +bool UrlHandler::processUri(const QString& arg)
> +{
> + QUrl uri(arg);
> +
> + if (!m_validSchemes.contains(uri.scheme())) {
> + return false;
> + }
> +
> + if (uri.scheme() == "document") {
> + uri.setScheme("file");
> + }
> +
> + if (uri.isRelative()) {
> + uri = QUrl::fromLocalFile(QDir::current().absoluteFilePath(arg));
> + }
> +
> + // Check if it's a local file
> + if (uri.isValid() && uri.isLocalFile()) {
> + QFileInfo info(uri.toLocalFile());
> + if (info.exists() && info.isFile()) {
> + m_documentFile = info.absoluteFilePath();
> + return true;
> + } else {
> + qWarning() << "File not found:" << uri << info.exists() << info.isFile();
> + }
> + } else {
> + qWarning() << "Invalid uri:" << uri;
> + }
> +
> + return false;
> +}
>
> === added file 'src/app/urlhandler.h'
> --- src/app/urlhandler.h 1970-01-01 00:00:00 +0000
> +++ src/app/urlhandler.h 2015-02-27 15:45:56 +0000
> @@ -0,0 +1,43 @@
> +/*
> + * Copyright (C) 2014 Canonical, Ltd.
> + *
> + * Authors:
> + * Arthur Mello <arthur.mello@xxxxxxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + *
> + */
> +
> +#ifndef URLHANDLER_H
> +#define URLHANDLER_H
> +
> +#include <QString>
> +#include <QList>
> +
> +/*!
> + * @brief The UrlHandler is used to parse calls of docviewer from the url schema.
> + */
> +class UrlHandler
> +{
> +public:
> + UrlHandler();
> +
> + bool processUri(const QString &arg);
> + const QString &documentFile() { return m_documentFile; }
> +
> +private:
> + QList<QString> m_validSchemes;
> + QString m_documentFile;
> +};
> +
> +#endif // URLHANDLER_H
>
> === removed file 'tests/autopilot/ubuntu_docviewer_app/files/ubuntu-touch.jpg'
> Binary files tests/autopilot/ubuntu_docviewer_app/files/ubuntu-touch.jpg 2013-06-30 15:10:38 +0000 and tests/autopilot/ubuntu_docviewer_app/files/ubuntu-touch.jpg 1970-01-01 00:00:00 +0000 differ
> === modified file 'tests/autopilot/ubuntu_docviewer_app/tests/test_docviewer.py'
> --- tests/autopilot/ubuntu_docviewer_app/tests/test_docviewer.py 2015-02-04 16:08:33 +0000
> +++ tests/autopilot/ubuntu_docviewer_app/tests/test_docviewer.py 2015-02-27 15:45:56 +0000
> @@ -8,7 +8,7 @@
> """Docviewer app autopilot tests."""
>
> from autopilot.matchers import Eventually
> -from testtools.matchers import Equals, Contains, GreaterThan
> +from testtools.matchers import Equals, GreaterThan
>
> from ubuntu_docviewer_app.tests import DocviewerAppTestCase
>
> @@ -34,20 +34,6 @@
> self.assertThat(
> text_area.text, Eventually(Equals('TEST\n')))
>
> - def test_open_image_file(self):
> -
> - self.filepath = 'ubuntu_docviewer_app/files/ubuntu-touch.jpg'
> -
> - self.launch_app()
> -
> - image_item = self.app.main_view.select_single(
> - "QQuickImage", objectName="imageRenderer")
> -
> - self.assertThat(
> - image_item.status, Eventually(Equals(1)))
> - self.assertThat(
> - image_item.source, Contains(self.filepath))
> -
> def test_unknown_file_type(self):
> self.filepath = 'ubuntu_docviewer_app/files/unknown.type'
>
>
--
https://code.launchpad.net/~verzegnassi-stefano/ubuntu-docviewer-app/document-hub2/+merge/251166
Your team Ubuntu Document Viewer Developers is subscribed to branch lp:ubuntu-docviewer-app.