Merge lp:~verzegnassi-stefano/ubuntu-docviewer-app/document-hub2 into lp:ubuntu-docviewer-app/trunk

Proposed by Stefano Verzegnassi on 2015-02-26
Status: Merged
Approved by: Stefano Verzegnassi on 2015-03-03
Approved revision: 93
Merged at revision: 86
Proposed branch: lp:~verzegnassi-stefano/ubuntu-docviewer-app/document-hub2
Merge into: lp:ubuntu-docviewer-app/trunk
Diff against target: 7414 lines (+4916/-1923)
75 files modified
CMakeLists.txt (+2/-2)
com.ubuntu.docviewer.desktop.in.in (+3/-1)
com.ubuntu.docviewer.url-dispatcher (+5/-0)
debian/changelog (+12/-2)
debian/control (+1/-1)
docviewer-content.json (+4/-3)
docviewer.apparmor (+7/-0)
manifest.json.in (+3/-2)
po/com.ubuntu.docviewer.pot (+155/-85)
src/app/CMakeLists.txt (+22/-1)
src/app/command-line-parser.cpp (+105/-0)
src/app/command-line-parser.h (+56/-0)
src/app/content-communicator.cpp (+188/-0)
src/app/content-communicator.h (+69/-0)
src/app/docviewer-application.cpp (+298/-0)
src/app/docviewer-application.h (+92/-0)
src/app/graphics/select-none.svg (+153/-0)
src/app/graphics/select.svg (+158/-0)
src/app/main.cpp (+10/-98)
src/app/qml/ContentHubPicker.qml (+0/-71)
src/app/qml/ContentHubProxy.qml (+0/-38)
src/app/qml/DetailsPage.qml (+0/-58)
src/app/qml/EmptyState.qml (+0/-59)
src/app/qml/ErrorDialog.qml (+0/-32)
src/app/qml/ImageView.qml (+0/-48)
src/app/qml/ImageViewDefaultHeader.qml (+0/-74)
src/app/qml/PageWithBottomEdge.qml (+0/-407)
src/app/qml/PdfContentsPage.qml (+0/-60)
src/app/qml/PdfView.qml (+0/-107)
src/app/qml/PdfViewDefaultHeader.qml (+0/-96)
src/app/qml/PdfViewDelegate.qml (+0/-95)
src/app/qml/PdfViewGotoDialog.qml (+0/-60)
src/app/qml/TextView.qml (+0/-70)
src/app/qml/TextViewDefaultHeader.qml (+0/-82)
src/app/qml/UnknownTypeDialog.qml (+0/-43)
src/app/qml/WelcomePage.qml (+0/-42)
src/app/qml/ZoomableImage.qml (+0/-155)
src/app/qml/common/DetailsPage.qml (+58/-0)
src/app/qml/common/ErrorDialog.qml (+32/-0)
src/app/qml/common/UnknownTypeDialog.qml (+43/-0)
src/app/qml/common/loadComponent.js (+38/-0)
src/app/qml/common/utils.js (+34/-0)
src/app/qml/documentPage/DeleteFileDialog.qml (+58/-0)
src/app/qml/documentPage/DocumentEmptyState.qml (+34/-0)
src/app/qml/documentPage/DocumentGridDelegate.qml (+178/-0)
src/app/qml/documentPage/DocumentGridView.qml (+76/-0)
src/app/qml/documentPage/DocumentListDelegate.qml (+108/-0)
src/app/qml/documentPage/DocumentListView.qml (+156/-0)
src/app/qml/documentPage/DocumentPage.qml (+76/-0)
src/app/qml/documentPage/DocumentPageDefaultHeader.qml (+34/-0)
src/app/qml/documentPage/DocumentPagePickModeHeader.qml (+63/-0)
src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml (+94/-0)
src/app/qml/loadComponent.js (+0/-45)
src/app/qml/pdfView/PdfContentsPage.qml (+60/-0)
src/app/qml/pdfView/PdfView.qml (+109/-0)
src/app/qml/pdfView/PdfViewDefaultHeader.qml (+96/-0)
src/app/qml/pdfView/PdfViewDelegate.qml (+95/-0)
src/app/qml/pdfView/PdfViewGotoDialog.qml (+60/-0)
src/app/qml/textView/TextView.qml (+70/-0)
src/app/qml/textView/TextViewDefaultHeader.qml (+82/-0)
src/app/qml/ubuntu-docviewer-app.qml (+63/-37)
src/app/qml/upstreamComponents/EmptyState.qml (+62/-0)
src/app/qml/upstreamComponents/HeaderButton.qml (+65/-0)
src/app/qml/upstreamComponents/ListItemWithActions.qml (+453/-0)
src/app/qml/upstreamComponents/ListItemWithActionsCheckBox.qml (+25/-0)
src/app/qml/upstreamComponents/MultipleSelectionGridView.qml (+199/-0)
src/app/qml/upstreamComponents/MultipleSelectionListView.qml (+199/-0)
src/app/qml/upstreamComponents/MultipleSelectionVisualModel.qml (+31/-0)
src/app/qml/upstreamComponents/PageWithBottomEdge.qml (+407/-0)
src/app/qml/utils.js (+0/-34)
src/app/quick/documentmodel.cpp (+212/-0)
src/app/quick/documentmodel.h (+89/-0)
src/app/urlhandler.cpp (+70/-0)
src/app/urlhandler.h (+43/-0)
tests/autopilot/ubuntu_docviewer_app/tests/test_docviewer.py (+1/-15)
To merge this branch: bzr merge lp:~verzegnassi-stefano/ubuntu-docviewer-app/document-hub2
Reviewer Review Type Date Requested Status
Alan Pope 🍺🐧🐱 🦄 2015-02-26 Approve on 2015-03-03
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve on 2015-03-03
Riccardo Padovani (community) code Approve on 2015-03-03
Review via email: mp+251166@code.launchpad.net

Commit Message

List of changes:
 - Refactored project structure (too much QML files in the same folder)
 - Added full content-hub support
 - Uri handler support
 - In-app browser
 - Document Viewer has now rw permissions in HOME/Documents
 - Dropped support for Image and Other file type
 - Use new splash screen features

Description of the Change

I'm sorry for the length of the diff: bzr move didn't recognise the folder changes.

In order to help with the review, here's some information:
    * All the C++ classes in src/app and src/app/quick needs a review.
    * Files in src/app/qml/upstreamComponents come from UCS or other core apps. The only "custom" files are MultipleSelectionGridView.qml (derived from MultipleSelectionListView.qml) and EmptyState.qml (allow wrapping of long subText)
    * All the files in src/app/qml/documentPage needs a deep review.
    * Other QML files had just minor changes.

CHANGES:
    - Refactored project structure (too much QML files in the same folder)
    - Added full content-hub support
    - Uri handler support
    - In-app browser
    - Document Viewer has now rw permissions in [HOME]/Documents
    - Dropped support for Image and Other file type
    - Use new splash screen features

MANUAL TESTING:
New features are still not covered by Autopilot tests. Before approving the MP, we need to manually execute some tests:

    - Check if all the documents in HOME/Documents are shown in DocumentPage (NOTE: Only PDFs and file with mimetype=text/* are supported)

    - Import content to the Document Viewer (browser-app and filemanager-app surely work, Dekko should also work)

    - Export content to 3rd party applications (e.g. PdfjsViewer)

    - Remove a document from user's Documents folder (tap-and-hold the list item, so the view switches to the selection mode).
      Two conditions should be satisfied: the document should be deleted from user's Documents folder and the view should not display "undefined" entries).

    - Add some document in the user's Documents folder while the application is running.
      Two conditions should be satisfied: new documents should be listed in the view, and no "undefined" entries are displayed.

    - Importing/exporting tests should be done with both the application running and closed.

    - Check if the DocumentPage correctly switches between the three states of the page: default, selectionMode, pickerMode.

    - Empty state: When Documents folder is empty, an empty state should be shown on the screen.

To post a comment you must log in.

Ok, got the issue.
In docviewer-application.cpp[1] we use the old code used to find out where the main qml file is located (from line 138).
Since in main.cpp[2] we set the ApplicationName (com.ubuntu.docviewer), the app looks for the qml file in the wrong folder:

"/usr/share/com.ubuntu.docviewer/qml/ubuntu-docviewer-app.qml"
instead of
"/usr/share/ubuntu-docviewer-app/qml/ubuntu-docviewer-app.qml"

I will fix it lately this night.

[1]: http://bazaar.launchpad.net/~verzegnassi-stefano/ubuntu-docviewer-app/document-hub2/view/head:/src/app/docviewer-application.cpp
[2]: http://bazaar.launchpad.net/~verzegnassi-stefano/ubuntu-docviewer-app/document-hub2/view/head:/src/app/main.cpp

89. By Stefano Verzegnassi on 2015-02-27

Terribly bad-designed workaround for looking QML files path up in QStandardPaths::DataLocations

Alan Pope 🍺🐧🐱 🦄 (popey) wrote :

Not sure what I did wrong, but I built this with qtc and installed on my device and get this:-

File: qml/ubuntu-docviewer-app.qml does not exist at any of the standard paths!

Tried on vivid flo and rtm (utopic) krillin.

Definitely my fault! The "terribly bad-designed workaround" is really terribly bad-designed...

The folders used in debian packaging are different than the ones of the click package.
Should change the debian rules, so app files are installed in /usr/share/com.ubuntu.docviewer

I'll solve it ASAP!

90. By Stefano Verzegnassi on 2015-02-27

Fixed revision 89

Ok, fixed my stupid mistake :-)
Tested on both desktop (14.10) and hammerhead (rtm)

Alan Pope 🍺🐧🐱 🦄 (popey) wrote :

A few comments.

* Really like that documents just appear when I copy them into ~/Documents. Also like that deleting them removes them from disk. This helps with managing disk space! Nice one!

* If we only look in ~/Documents then it doesn't find files on my SD card which are in /media/phablet/2541-1C26/Documents - and as we no longer have the "+" button in the toolbar, I can't add them to the list using file manager.

* Long press to delete brings buttons in the toolbar which are not right-aligned. There is a gap (I assume where the list/grid toggle button was) in the toolbar. I think the buttons should appear on the right. http://people.canonical.com/~alan/screenshots/device-2015-02-28-155804.png

* Long press to delete is not easily discovered and doesn't match the rest of the platform which uses swipe right to delete (see music / contacts / alarms etc). Can we have long press for multi-select delete _and_ swipe right for single document delete?

> A few comments.
>
> * Really like that documents just appear when I copy them into ~/Documents.
> Also like that deleting them removes them from disk. This helps with managing
> disk space! Nice one!

Glad you like it!

> * If we only look in ~/Documents then it doesn't find files on my SD card
> which are in /media/phablet/2541-1C26/Documents - and as we no longer have the
> "+" button in the toolbar, I can't add them to the list using file manager.

Well, you can open files from the file manager itself: Document Viewer will be shown in the list of the available destinations for the trasfer, and a local copy will be created in ~/Documents.
ATM I prefer not to support external storages, since this MP is already huge for testing, and I still need to find out the best solution for being notified of changes in the list of removable medias.

> * Long press to delete brings buttons in the toolbar which are not right-
> aligned. There is a gap (I assume where the list/grid toggle button was) in
> the toolbar. I think the buttons should appear on the right.
> http://people.canonical.com/~alan/screenshots/device-2015-02-28-155804.png

I saw it some time ago. It seemed to me that it was unpredictable, and doesn't happen any time the headerState switches.
Sure I'll try to fix it.

> * Long press to delete is not easily discovered and doesn't match the rest of
> the platform which uses swipe right to delete (see music / contacts / alarms
> etc). Can we have long press for multi-select delete _and_ swipe right for
> single document delete?

Design reasons. I've already added a comment in the code in order to remember that I have to activate the swipe-to-delete gesture.
Sure we can have it, but I need to find equivalent action for the delegate in the grid view mode.
I'm open to any suggestions. :)

Alan Pope 🍺🐧🐱 🦄 (popey) wrote :

Ok, it's good for me then.

review: Approve
Riccardo Padovani (rpadovani) wrote :

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

review: Needs Fixing (code)
Riccardo Padovani (rpadovani) wrote :

There is a problem with file importing.
You do a check to check if already exists a file with the same name. If there is, then you import the file adding a numb at the end of the name.

if(QFile::exists(destination))

But I think you should add another check: if the new file it's the same you already imported, then don't import it.

I think the best way to achieve this check is to use md5 function.

http://doc.qt.io/qt-5/qml-qtqml-qt.html#md5-method

Riccardo Padovani (rpadovani) wrote :

Last 2403 lines of diff (rev 90).
Unfortunately they aren't here on Launchpad. So I locally merged this branch in the trunk, then I used qdiff, I report here interesting pieces:

src/app/qml/pdfView/PdfViewGotoDialog.qml
+ Button {
+ objectName:"GOButton"
+ text: i18n.tr("GO!")
+ color: UbuntuColors.orange

Orange isn't anymore suggested by design guidelines[0]. I suggest to use green or gray

###
src/app/qml/textView/TextView.qml

Why do you use a TextArea with readOnly: true and not a Label?

###
src/app/quick/documentmodel.cpp

Could you please explain what are you trying to achieve with DocumentModel::_q_directoryChanged?
Seems improvable, but I'm not sure I understand how you want to use it

DocumentModel::parseDirectoryContent
item.dateDiff = 0;
Probably is better to add a ENUM for this

Great work Stefano, congrats!

All issues I pointed out are minor, and the improvement is huge :-)

I'm going to test it

[0]https://design.ubuntu.com/apps/building-blocks/buttons

review: Needs Fixing (code)
Riccardo Padovani (rpadovani) wrote :

Mhh, I tried to launch it on vivid desktop 64bit.

It compiles like a charm, but then the app doesn't start, both via CLI and via QtCreator.
It is stucked on

./src/app/ubuntu-docviewer-app
APP_ID isn't set, the handler can not be registered

I have all packages reported by the README.

What am I doing wrong?

Download full text (4.3 KiB)

Riccardo, there's also the “debug” policy issue that you spotted this morning.
Dunno why it's there, but I shall fix it before the branch is merged.

Sorry if I reply to the inline comments here, but it's for my brain sanity when I will fix them. :-)

> Line 734: QString filenameWithoutSuffix = filename.left(filename.size() - suffix.size());
It comes from gallery-app

> Line 740: filenameWithoutSuffix += ".";
Same as above.

> Line 757:
My fault here.

> Line 806: \brief ContentCommunicator::returnPhoto returns the given photos
Yes, it is. Forgot to change it (I did it the first time, but I lost the code) :P

> Line 849: return m_transfer->selectionType() == Transfer::SelectionType::single;
TBH dunno, it's the same in the upstream code (gallery-app). I need to check.

> Line 983: bool ok = m_cmdLineParser->processArguments(arguments());
Nice question! Why I did it? Need to fix! :-)

> Line 1069: m_view->setTitle("Document Viewer");
Sure! (Even if the string is replaced by QML Page title)

> Line 1706: QcoreApplication::setOrganizationDomain("com.ubuntu.docviewer");
Huh, I think I choose the wrong hint from QtCreator. :P

> Line 3558:
Yes, I agree with you! This dialog is part of the earlier code of the docviewer (before I adopted the project).
I didn't spent much time on it, but surely it's something I'd like to improve!

> Line 3690:
You're right!

> Line 3695:
As I told to Filippo some time ago, I followed the code style guidelines that has been chosen for the Core Apps project.
Probably it's too much orthodox as implementation.

> Line 3753: viewLoader.item.endSelection();
You're right again!

>Line 3783: not sure which line do you mean?
>> If (import "../upstreamComponents”)
The EmptyState item lives in ../upstreamComponents
>> If you mean the Item that contains the EmptyState, it's because of the alignment inside a QML Loader.

> Line 3837, 3840, 3843, 3845:
Again, you're right about translations!

> Line 3936:
Oops, I think there's another label earlier and I forgot to remove the RowLayout.

> Line 3937, 4107:
I will fix it!

> Line 4110:
Haha

> Line 4325:
Yep! Will fix it!

> Line 4442:
No reason!

> Line 4510:
Nope! As in gallery-app, the button is not enabled but still visible, to advice that the content transfer could not be done if no item has been selected.
IMHO it should be shown in any case.

> Line 4625:
Could be. Need to try.

> Line 4782:
IMHO “Page %1 of %2” in a docviewer is pretty unequivocal. Anyway, adding an hint for translators it's surely not a problem!

> There is a problem with file importing.
> You do a check to check if already exists a file with the same name. If there is, then > you import the file adding a numb at the end of the name.
> if(QFile:
> But I think you should add another check: if the new file it's the same you already > > imported, then don't import it.
> I think the best way to achieve this check is to use md5 function.
Again, same issue is in the gallery-app.

>src/app/qml/pdfView/PdfViewGotoDialog.qml
>+ Button {
>+ objectName:
>+ text: i18n.tr("GO!")
>+ color: UbuntuColors.orange
>Orange isn't anymore suggested by design guidelines[0]. I suggest to use green or gray
No problem, I'll change ...

Read more...

Riccardo Padovani (rpadovani) wrote :

> Sorry if I reply to the inline comments here, but it's for my brain sanity
> when I will fix them. :-)

I completely understand :D

> >Line 3783: not sure which line do you mean?
> >> If (import "../upstreamComponents”)
> The EmptyState item lives in ../upstreamComponents

Oh, right, my fault here!

> > Line 4510:
> Nope! As in gallery-app, the button is not enabled but still visible, to
> advice that the content transfer could not be done if no item has been
> selected.
> IMHO it should be shown in any case.

You have a point here, I agree with you

> >src/app/qml/textView/TextView.qml
> >Why do you use a TextArea with readOnly: true and not a Label?
> Copy and paste! Even if the TextArea is read-only, they are still useful.

Aha, right! Didn't think about it, sorry

> > src/app/quick/documentMode.cpp
> > Could you please explain what are you trying to achieve with DocumentModel:
> > Seems improvable, but I'm not sure I understand how you want to use it
> When there's a change in the directory we're watching (e.g. document added or
> removed), we want to update the model according to the changes:
> The code in that slot just removes all the entries from that directory and re-
> parse its content.
> The two ints, n and m, are used to keep a note of the number of removed items,
> so that we can exactly remove the rows from the model (by doing so we avoid to
> have duplicated undefined rows).

Oh, I see, makes sense.
I think could be improvable, but atm works well, so it's ok

> About the ENUM, I will do in a next MP. At the moment it works, but I have no
> resources (most of all, time) for staying in-sync with the tasks I still need
> to do for the docviewer.
> The same observation is also valid for the issues you reported that are
> related to the gallery-app.

I fully understand that, there are simply too much work to do :-)

> For all the rest I will provide a fix hopefully today (max. tomorrow).

Ok, I'll do another quick review after then I'll approve it, thanks!

> Thank you Riccardo for the huge review.

Thanks to you for the amazing work!

91. By Stefano Verzegnassi on 2015-03-03

Remove 'debug' policy from apparmor profile

92. By Stefano Verzegnassi on 2015-03-03

Fixes for the minor issues found in the last review

Just a note for Riccardo, when he will review the latest changes:
 * I've added some comment in the code for the things I didn't fix yet (e.g. issues related to the gallery-app).
 * Please double check translation changes (e.g. i18n.tr("dd MM yyyy, hh:mm"), since I'm not completely sure if I did it right)

Riccardo Padovani (rpadovani) wrote :

Now code looks good to me.

There are some FIXME, but they don't cause any error, they are only minor code refactoring you can do in a second moment.

Since this branch has a lot of improvements, I think is good enough to land, I'm sure you will do other branches for little fixes :-)

As we discussed yesterday, I'm not able to launch it on vivid desktop, but could be a my problem.
Anyway, I wasn't able to review the UI/UX. Code is good, but I leave to popey the top approving :-)

review: Approve (code)

Changing:
    QCoreApplication::setOrganizationDomain("com.ubuntu.docviewer")
to:
    QCoreApplication::setOrganizationName("com.ubuntu.docviewer")

makes the app look for the main QML file in the wrong path, since DataLocation is built as "/usr/share/<APPNAME>", where <APPNAME> (according to Qt docs) "is usually the organization name, the application name, or both, or a unique name generated at packaging."

In this case, it is both[1].

[1] "/usr/local/share/com.ubuntu.docviewer/com.ubuntu.docviewer/qml/ubuntu-docviewer-app.qml"

93. By Stefano Verzegnassi on 2015-03-03

Revert 'setOrganizationName' change

I reverted to 'QCoreApplication::setOrganizationDomain".

Here's the reason of my choice: the code has been on testing for a few weeks, and even if the line was wrong, it used to work with no issue both on desktop and on devices.
Since I have no UT device at the moment - my brand new (a.k.a. "refurbished") hammerhead has been shipped today - I can't properly test if any further change will cause some regression.

Content-hub used to work, as all the rest of the application did.
Because of this, I assume that everything is ok for a release.

I should get my new Nexus 5 in max. 2-3 days: when it will happen, I'll be able to fix this part of the code.

Alan Pope 🍺🐧🐱 🦄 (popey) wrote :

Seems launching a pdf from another application via content hub broke.

* Open browser
* Search for pdf + weather
* Click a random pdf file
* Content hub popup, select docviewer
* Wait for download
* Wait for popup, choose 'Open'
* Docviewer launches, but document list is shown, the document doesn't load.

review: Needs Fixing
Alan Pope 🍺🐧🐱 🦄 (popey) wrote :

I didn't realise this was an intentional design decision based on what the gallery uses.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2015-01-29 16:35:28 +0000
3+++ CMakeLists.txt 2015-03-03 16:49:59 +0000
4@@ -23,7 +23,7 @@
5
6 set(APP_NAME ubuntu-docviewer-app)
7 set(DESKTOP_FILE "${PROJECT_NAME}.desktop")
8-#set(URLS_FILE "${PROJECT_NAME}_${APP_NAME}.url-dispatcher")
9+set(URLS_FILE "${PROJECT_NAME}.url-dispatcher")
10 set(LP_PROJECT ubuntu-docviewer-app)
11 set(ICON_FILE docviewer@30.png)
12 set(AUTOPILOT_DIR ubuntu_docviewer_app)
13@@ -67,7 +67,7 @@
14 set(DESKTOP_DIR ${DATA_DIR})
15 set(URLS_DIR ${DATA_DIR})
16 configure_file(manifest.json.in ${CMAKE_CURRENT_BINARY_DIR}/manifest.json)
17- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/manifest.json docviewer.apparmor docviewer-content.json
18+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/manifest.json docviewer.apparmor docviewer-content.json ${URLS_FILE}
19 DESTINATION ${CMAKE_INSTALL_PREFIX})
20 # Make the click files visible in Qt Creator
21 file(GLOB CLICK_FILES
22
23=== modified file 'com.ubuntu.docviewer.desktop.in.in'
24--- com.ubuntu.docviewer.desktop.in.in 2014-09-24 05:06:10 +0000
25+++ com.ubuntu.docviewer.desktop.in.in 2015-03-03 16:49:59 +0000
26@@ -6,6 +6,8 @@
27 Icon=@ICON@
28 _Name=Document Viewer
29 _Keywords=documents;viewer;pdf;reader;
30-MimeType=text/plain;image/png;image/jpeg;image/svg+xml;application/pdf
31+MimeType=text/plain;application/pdf
32 X-Ubuntu-Touch=true
33 X-Ubuntu-StageHint=SideStage
34+X-Ubuntu-Splash-Show-Header=true
35+_X-Ubuntu-Splash-Title=Document Viewer
36
37=== added file 'com.ubuntu.docviewer.url-dispatcher'
38--- com.ubuntu.docviewer.url-dispatcher 1970-01-01 00:00:00 +0000
39+++ com.ubuntu.docviewer.url-dispatcher 2015-03-03 16:49:59 +0000
40@@ -0,0 +1,5 @@
41+[
42+ {
43+ "protocol": "document"
44+ }
45+]
46
47=== modified file 'debian/changelog'
48--- debian/changelog 2015-02-04 19:30:22 +0000
49+++ debian/changelog 2015-03-03 16:49:59 +0000
50@@ -1,14 +1,24 @@
51+ubuntu-docviewer-app (0.3.0) utopic; urgency=medium
52+
53+ * Improved content-hub support
54+ * Added uri handler support
55+ * Use the Unity 8 splash screen
56+ * In-app browser for files stored in XDG Documents folder
57+ * Support for images has been dropped
58+
59+ -- Stefano Verzegnassi <verzegnassi.stefano@gmail.com> Mon, 23 Feb 2015 13:41:47 +0100
60+
61 ubuntu-docviewer-app (0.2.1) utopic; urgency=medium
62
63 * Added Table of Content in the PDF viewer
64
65- -- Stefano <verzegnassi.stefano@gmail.com> Wed, 04 Feb 2015 20:26:58 +0100
66+ -- Stefano Verzegnassi <verzegnassi.stefano@gmail.com> Wed, 04 Feb 2015 20:26:58 +0100
67
68 ubuntu-docviewer-app (0.2.0) utopic; urgency=medium
69
70 * Enabled zoom in the PDF viewer
71
72- -- Stefano <verzegnassi.stefano@gmail.com> Wed, 04 Feb 2015 14:37:54 +0100
73+ -- Stefano Verzegnassi <verzegnassi.stefano@gmail.com> Wed, 04 Feb 2015 14:37:54 +0100
74
75 ubuntu-docviewer-app (0.1.2) UNRELEASED; urgency=medium
76
77
78=== modified file 'debian/control'
79--- debian/control 2015-02-04 16:08:33 +0000
80+++ debian/control 2015-03-03 16:49:59 +0000
81@@ -4,6 +4,7 @@
82 Build-Depends: cmake,
83 debhelper (>= 9),
84 intltool,
85+ libcontent-hub-dev (>= 0.0+13.10.20130930.1),
86 libpoppler-qt5-dev,
87 pep8,
88 pkg-config,
89@@ -27,7 +28,6 @@
90 Architecture: any
91 Depends: qtdeclarative5-qtquick2-plugin,
92 qtdeclarative5-ubuntu-ui-toolkit-plugin,
93- qtdeclarative5-ubuntu-content1,
94 ${misc:Depends}
95 Description: Document Viewer application
96 Core Document Viewer application
97
98=== modified file 'docviewer-content.json'
99--- docviewer-content.json 2014-10-31 16:25:17 +0000
100+++ docviewer-content.json 2015-03-03 16:49:59 +0000
101@@ -1,7 +1,8 @@
102 {
103 "destination": [
104- "pictures",
105- "documents",
106- "unknown"
107+ "documents"
108+ ],
109+ "source": [
110+ "documents"
111 ]
112 }
113
114=== modified file 'docviewer.apparmor'
115--- docviewer.apparmor 2014-10-31 16:25:17 +0000
116+++ docviewer.apparmor 2015-03-03 16:49:59 +0000
117@@ -1,6 +1,13 @@
118 {
119 "policy_groups": [
120+ "content_exchange_source",
121 "content_exchange"
122 ],
123+ "read_path": [
124+ "@{HOME}/Documents/"
125+ ],
126+ "write_path": [
127+ "@{HOME}/Documents/"
128+ ],
129 "policy_version": 1.2
130 }
131
132=== modified file 'manifest.json.in'
133--- manifest.json.in 2015-02-04 19:30:22 +0000
134+++ manifest.json.in 2015-03-03 16:49:59 +0000
135@@ -9,10 +9,11 @@
136 "docviewer": {
137 "apparmor": "docviewer.apparmor",
138 "desktop": "com.ubuntu.docviewer.desktop",
139- "content-hub": "docviewer-content.json"
140+ "content-hub": "docviewer-content.json",
141+ "urls": "@URLS_FILE@"
142 }
143 },
144- "version": "0.2.1.@BZR_REVNO@",
145+ "version": "0.3.@BZR_REVNO@",
146 "maintainer": "Ubuntu App Cats <ubuntu-touch-coreapps@lists.launchpad.net>",
147 "x-source": {
148 "vcs-bzr": "@BZR_SOURCE@",
149
150=== modified file 'po/com.ubuntu.docviewer.pot'
151--- po/com.ubuntu.docviewer.pot 2015-02-05 19:30:53 +0000
152+++ po/com.ubuntu.docviewer.pot 2015-03-03 16:49:59 +0000
153@@ -8,7 +8,7 @@
154 msgstr ""
155 "Project-Id-Version: \n"
156 "Report-Msgid-Bugs-To: \n"
157-"POT-Creation-Date: 2015-02-05 20:29+0100\n"
158+"POT-Creation-Date: 2015-03-03 17:49+0100\n"
159 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
160 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
161 "Language-Team: LANGUAGE <LL@li.org>\n"
162@@ -17,136 +17,206 @@
163 "Content-Type: text/plain; charset=CHARSET\n"
164 "Content-Transfer-Encoding: 8bit\n"
165
166-#: ../src/app/qml/ContentHubPicker.qml:23
167-msgid "Open with..."
168-msgstr ""
169-
170-#: ../src/app/qml/ContentHubPicker.qml:27
171-msgid "Documents"
172-msgstr ""
173-
174-#: ../src/app/qml/ContentHubPicker.qml:27
175-msgid "Pictures"
176-msgstr ""
177-
178-#: ../src/app/qml/ContentHubPicker.qml:27
179-msgid "Other"
180-msgstr ""
181-
182-#: ../src/app/qml/ContentHubPicker.qml:30
183-#: ../src/app/qml/ImageViewDefaultHeader.qml:53
184-#: ../src/app/qml/PdfViewDefaultHeader.qml:61
185-#: ../src/app/qml/TextViewDefaultHeader.qml:61
186-msgid "Back"
187-msgstr ""
188-
189-#: ../src/app/qml/DetailsPage.qml:27
190-#: ../src/app/qml/ImageViewDefaultHeader.qml:69
191-#: ../src/app/qml/PdfViewDefaultHeader.qml:91
192-#: ../src/app/qml/TextViewDefaultHeader.qml:77
193+#: ../src/app/qml/common/DetailsPage.qml:27
194+#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:91
195+#: ../src/app/qml/textView/TextViewDefaultHeader.qml:77
196 msgid "Details"
197 msgstr ""
198
199-#: ../src/app/qml/DetailsPage.qml:33
200+#: ../src/app/qml/common/DetailsPage.qml:33
201 msgid "Location"
202 msgstr ""
203
204-#: ../src/app/qml/DetailsPage.qml:37
205+#: ../src/app/qml/common/DetailsPage.qml:37
206 msgid "Size"
207 msgstr ""
208
209-#: ../src/app/qml/DetailsPage.qml:42
210+#: ../src/app/qml/common/DetailsPage.qml:42
211 msgid "Created"
212 msgstr ""
213
214-#: ../src/app/qml/DetailsPage.qml:47
215+#: ../src/app/qml/common/DetailsPage.qml:47
216 msgid "Last modified"
217 msgstr ""
218
219-#: ../src/app/qml/DetailsPage.qml:54
220+#: ../src/app/qml/common/DetailsPage.qml:54
221 msgid "MIME type"
222 msgstr ""
223
224-#: ../src/app/qml/ErrorDialog.qml:23
225+#: ../src/app/qml/common/ErrorDialog.qml:24
226 msgid "Error"
227 msgstr ""
228
229-#: ../src/app/qml/ErrorDialog.qml:24
230+#: ../src/app/qml/common/ErrorDialog.qml:25
231 msgid "File does not exist"
232 msgstr ""
233
234-#: ../src/app/qml/ErrorDialog.qml:27
235-#: ../src/app/qml/ImageViewDefaultHeader.qml:53
236-#: ../src/app/qml/PdfViewDefaultHeader.qml:61
237-#: ../src/app/qml/TextViewDefaultHeader.qml:61
238+#: ../src/app/qml/common/ErrorDialog.qml:28
239+#: ../src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml:31
240+#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:61
241+#: ../src/app/qml/textView/TextViewDefaultHeader.qml:61
242 msgid "Close"
243 msgstr ""
244
245-#: ../src/app/qml/PdfContentsPage.qml:24 ../src/app/qml/PdfView.qml:33
246+#: ../src/app/qml/common/UnknownTypeDialog.qml:26
247+msgid "Unknown file type"
248+msgstr ""
249+
250+#: ../src/app/qml/common/UnknownTypeDialog.qml:27
251+msgid ""
252+"Sorry but we can't find a way to display this file. Do you want to open it "
253+"as a plain text?"
254+msgstr ""
255+
256+#: ../src/app/qml/common/UnknownTypeDialog.qml:29
257+msgid "Yes"
258+msgstr ""
259+
260+#: ../src/app/qml/common/UnknownTypeDialog.qml:38
261+msgid "No"
262+msgstr ""
263+
264+#: ../src/app/qml/documentPage/DeleteFileDialog.qml:27
265+msgid "Delete file"
266+msgstr ""
267+
268+#: ../src/app/qml/documentPage/DeleteFileDialog.qml:28
269+#, qt-format
270+msgid "Delete %1 files"
271+msgstr ""
272+
273+#: ../src/app/qml/documentPage/DeleteFileDialog.qml:29
274+msgid "Are you sure you want to permanently delete this file?"
275+msgstr ""
276+
277+#: ../src/app/qml/documentPage/DeleteFileDialog.qml:30
278+msgid "Are you sure you want to permanently delete these files?"
279+msgstr ""
280+
281+#: ../src/app/qml/documentPage/DeleteFileDialog.qml:33
282+#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:27
283+#: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:52
284+msgid "Cancel"
285+msgstr ""
286+
287+#: ../src/app/qml/documentPage/DeleteFileDialog.qml:38
288+#: ../src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml:81
289+msgid "Delete"
290+msgstr ""
291+
292+#: ../src/app/qml/documentPage/DocumentEmptyState.qml:24
293+msgid "No document found"
294+msgstr ""
295+
296+#: ../src/app/qml/documentPage/DocumentEmptyState.qml:28
297+msgid ""
298+"Connect your device to any computer and simply drag files to the Documents "
299+"folder."
300+msgstr ""
301+
302+#: ../src/app/qml/documentPage/DocumentGridDelegate.qml:33
303+msgid "Today, "
304+msgstr ""
305+
306+#: ../src/app/qml/documentPage/DocumentGridDelegate.qml:36
307+msgid "Yesterday, "
308+msgstr ""
309+
310+#. TRANSLATORS: this is a datetime formatting string,
311+#. see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
312+#: ../src/app/qml/documentPage/DocumentGridDelegate.qml:41
313+#: ../src/app/qml/documentPage/DocumentListDelegate.qml:35
314+msgid "dddd, hh:mm"
315+msgstr ""
316+
317+#. TRANSLATORS: this is a datetime formatting string,
318+#. see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
319+#: ../src/app/qml/documentPage/DocumentGridDelegate.qml:45
320+#: ../src/app/qml/documentPage/DocumentListDelegate.qml:39
321+msgid "dd-MM-yyyy hh:mm"
322+msgstr ""
323+
324+#: ../src/app/qml/documentPage/DocumentListView.qml:135
325+msgid "Today"
326+msgstr ""
327+
328+#: ../src/app/qml/documentPage/DocumentListView.qml:138
329+msgid "Yesterday"
330+msgstr ""
331+
332+#: ../src/app/qml/documentPage/DocumentListView.qml:141
333+msgid "Earlier this week"
334+msgstr ""
335+
336+#: ../src/app/qml/documentPage/DocumentListView.qml:144
337+msgid "Earlier this month"
338+msgstr ""
339+
340+#: ../src/app/qml/documentPage/DocumentListView.qml:146
341+msgid "Even more earlier..."
342+msgstr ""
343+
344+#: ../src/app/qml/documentPage/DocumentPage.qml:25
345+#: /home/stefano/Progetti/doc-viewer/build-document-hub2-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:1
346+msgid "Document Viewer"
347+msgstr ""
348+
349+#: ../src/app/qml/documentPage/DocumentPageDefaultHeader.qml:28
350+#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:35
351+msgid "Switch to single column list"
352+msgstr ""
353+
354+#: ../src/app/qml/documentPage/DocumentPageDefaultHeader.qml:28
355+#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:35
356+msgid "Switch to grid"
357+msgstr ""
358+
359+#: ../src/app/qml/documentPage/DocumentPagePickModeHeader.qml:43
360+msgid "Pick"
361+msgstr ""
362+
363+#: ../src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml:51
364+msgid "Select None"
365+msgstr ""
366+
367+#: ../src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml:53
368+msgid "Select All"
369+msgstr ""
370+
371+#: ../src/app/qml/pdfView/PdfContentsPage.qml:24
372+#: ../src/app/qml/pdfView/PdfView.qml:36
373 msgid "Contents"
374 msgstr ""
375
376-#: ../src/app/qml/PdfView.qml:31
377+#. TRANSLATORS: the first argument (%1) refers to the page currently shown on the screen,
378+#. while the second one (%2) refers to the total pages count.
379+#: ../src/app/qml/pdfView/PdfView.qml:34
380 #, qt-format
381 msgid "Page %1 of %2"
382 msgstr ""
383
384-#: ../src/app/qml/PdfViewGotoDialog.qml:25
385+#: ../src/app/qml/pdfView/PdfViewDefaultHeader.qml:61
386+#: ../src/app/qml/textView/TextViewDefaultHeader.qml:61
387+msgid "Back"
388+msgstr ""
389+
390+#: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:25
391 msgid "Go to page"
392 msgstr ""
393
394-#: ../src/app/qml/PdfViewGotoDialog.qml:26
395+#: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:26
396 #, qt-format
397 msgid "Choose a page between 1 and %1"
398 msgstr ""
399
400-#: ../src/app/qml/PdfViewGotoDialog.qml:44
401+#: ../src/app/qml/pdfView/PdfViewGotoDialog.qml:44
402 msgid "GO!"
403 msgstr ""
404
405-#: ../src/app/qml/PdfViewGotoDialog.qml:52
406-msgid "Cancel"
407-msgstr ""
408-
409-#: ../src/app/qml/TextView.qml:39
410+#: ../src/app/qml/textView/TextView.qml:39
411 msgid "Loading..."
412 msgstr ""
413
414-#: ../src/app/qml/UnknownTypeDialog.qml:26
415-msgid "Unknown file type"
416-msgstr ""
417-
418-#: ../src/app/qml/UnknownTypeDialog.qml:27
419-msgid ""
420-"Sorry but we can't find a way to display this file. Do you want to open it "
421-"as a plain text?"
422-msgstr ""
423-
424-#: ../src/app/qml/UnknownTypeDialog.qml:29
425-msgid "Yes"
426-msgstr ""
427-
428-#: ../src/app/qml/UnknownTypeDialog.qml:38
429-msgid "No"
430-msgstr ""
431-
432-#: ../src/app/qml/WelcomePage.qml:23
433-#: /home/stefano/Progetti/doc-viewer/build-ubuntu-docviewer-app-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:1
434-msgid "Document Viewer"
435-msgstr ""
436-
437-#: ../src/app/qml/WelcomePage.qml:27
438-msgid "No opened documents"
439-msgstr ""
440-
441-#: ../src/app/qml/WelcomePage.qml:28
442-msgid "Tap the + icon to open a document"
443-msgstr ""
444-
445-#: ../src/app/qml/WelcomePage.qml:37
446-msgid "Open a file..."
447-msgstr ""
448-
449-#: /home/stefano/Progetti/doc-viewer/build-ubuntu-docviewer-app-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:2
450+#: /home/stefano/Progetti/doc-viewer/build-document-hub2-Desktop-Default/po/com.ubuntu.docviewer.desktop.in.in.h:2
451 msgid "documents;viewer;pdf;reader;"
452 msgstr ""
453
454=== modified file 'src/app/CMakeLists.txt'
455--- src/app/CMakeLists.txt 2014-10-21 13:23:11 +0000
456+++ src/app/CMakeLists.txt 2015-03-03 16:49:59 +0000
457@@ -1,13 +1,25 @@
458 file(GLOB_RECURSE QML_SRCS *.qml *.js)
459+file(GLOB_RECURSE IMAGE_FILES *.qml *.js)
460+
461+pkg_check_modules(CONTENTHUB REQUIRED libcontent-hub)
462
463 set(docviewer_SRCS
464 main.cpp
465+ content-communicator.cpp
466+ command-line-parser.cpp
467+ docviewer-application.cpp
468+ urlhandler.cpp
469+ quick/documentmodel.cpp
470 ${QML_SRCS}
471 )
472
473 add_executable(ubuntu-docviewer-app ${docviewer_SRCS})
474
475-qt5_use_modules(ubuntu-docviewer-app Gui Qml Quick)
476+qt5_use_modules(ubuntu-docviewer-app Widgets Gui Qml Quick DBus)
477+
478+target_link_libraries( ubuntu-docviewer-app
479+ ${CONTENTHUB_LIBRARIES}
480+)
481
482 if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
483 add_custom_target(docviewer-qmlfiles ALL
484@@ -16,7 +28,16 @@
485 )
486 endif(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
487
488+if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
489+add_custom_target(docviewer-imagefiles ALL
490+ COMMAND cp -r ${CMAKE_CURRENT_SOURCE_DIR}/graphics ${CMAKE_CURRENT_BINARY_DIR}
491+ DEPENDS ${IMAGE_FILES}
492+)
493+endif(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
494+
495 install(DIRECTORY qml DESTINATION ${DATA_DIR})
496+install(DIRECTORY graphics DESTINATION ${DATA_DIR})
497+
498 if(CLICK_MODE)
499 install(TARGETS ubuntu-docviewer-app DESTINATION ${BIN_DIR})
500 else()
501
502=== added file 'src/app/command-line-parser.cpp'
503--- src/app/command-line-parser.cpp 1970-01-01 00:00:00 +0000
504+++ src/app/command-line-parser.cpp 2015-03-03 16:49:59 +0000
505@@ -0,0 +1,105 @@
506+/*
507+ * Copyright (C) 2013 Canonical, Ltd.
508+ *
509+ * Authors:
510+ * Nicolas d'Offay <nicolas.doffay@canonical.com>
511+ *
512+ * This program is free software; you can redistribute it and/or modify
513+ * it under the terms of the GNU General Public License as published by
514+ * the Free Software Foundation; version 3.
515+ *
516+ * This program is distributed in the hope that it will be useful,
517+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
518+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
519+ * GNU General Public License for more details.
520+ *
521+ * You should have received a copy of the GNU General Public License
522+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
523+ *
524+ */
525+
526+#include "command-line-parser.h"
527+
528+#include "urlhandler.h"
529+
530+#include <QDebug>
531+#include <QDir>
532+#include <QStandardPaths>
533+#include <QTextStream>
534+#include <QUrl>
535+
536+CommandLineParser::CommandLineParser()
537+ : m_pickMode(false),
538+ m_testability(false),
539+ m_documentFile("")
540+{
541+ m_urlHandler = new UrlHandler();
542+}
543+
544+/*!
545+ * @brief CommandLineParser::processArguments parsers our input commandline args and sets attributes accordingly.
546+ * @param QStringList of commandline args to parse and set attributes.
547+ * @return false if invalid parameter is input or -h/--help is called.
548+ */
549+bool CommandLineParser::processArguments(const QStringList& args)
550+{
551+ bool valid_args = true;
552+
553+ for (int i = 1; i < args.count(); ++i)
554+ {
555+ if (args[i] == "--help" || args[i] == "-h") {
556+ usage();
557+ return false;
558+ }
559+ else if (args[i] == "--pick-mode") {
560+ m_pickMode = true;
561+ }
562+ else if (args[i] == "--testability") {
563+ m_testability = true;
564+ }
565+ else {
566+ if (args[i].startsWith("--desktop_file_hint")) {
567+ // ignore this command line switch, hybris uses it to get application info
568+ }
569+ else if (!args.at(i).isEmpty()) {
570+ QFileInfo fi(args.at(i));
571+
572+ if (fi.exists()) {
573+ m_documentFile = fi.absoluteFilePath();
574+ }
575+ else if (m_urlHandler->processUri(args.at(i))) {
576+ m_documentFile = m_urlHandler->documentFile();
577+ }
578+ }
579+ else {
580+ valid_args = !invalidArg(args[i]);
581+ }
582+ }
583+ }
584+
585+ return valid_args;
586+}
587+
588+/*!
589+ * @brief CommandLineParser::usage() prints out our form factors.
590+ */
591+void CommandLineParser::usage()
592+{
593+ QTextStream out(stdout);
594+ out << "Usage: ubuntu-docviewer-app [options] [file_path]" << endl;
595+ out << "Options:" << endl;
596+ out << " --pick-mode\t\tEnable mode to pick photos" << endl;
597+ out << " file_path\t\tOpens ubuntu-docviewer-app displaying the selected file" << endl;
598+}
599+
600+/*!
601+ * @brief CommandLineParser::invalidArg() if an invalid argument is contained in our QStringList.
602+ * @return returns true.
603+ */
604+bool CommandLineParser::invalidArg(QString arg)
605+{
606+ QTextStream(stderr) << "Invalid argument '" << arg << "'" << endl;
607+ usage();
608+
609+ return true;
610+}
611
612=== added file 'src/app/command-line-parser.h'
613--- src/app/command-line-parser.h 1970-01-01 00:00:00 +0000
614+++ src/app/command-line-parser.h 2015-03-03 16:49:59 +0000
615@@ -0,0 +1,56 @@
616+/*
617+ * Copyright (C) 2013 Canonical, Ltd.
618+ *
619+ * Authors:
620+ * Nicolas d'Offay <nicolas.doffay@canonical.com>
621+ *
622+ * This program is free software; you can redistribute it and/or modify
623+ * it under the terms of the GNU General Public License as published by
624+ * the Free Software Foundation; version 3.
625+ *
626+ * This program is distributed in the hope that it will be useful,
627+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
628+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
629+ * GNU General Public License for more details.
630+ *
631+ * You should have received a copy of the GNU General Public License
632+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
633+ *
634+ */
635+
636+#ifndef COMMANDLINEPARSER_H
637+#define COMMANDLINEPARSER_H
638+
639+#include <QHash>
640+#include <QSize>
641+#include <QString>
642+
643+class UrlHandler;
644+
645+/*!
646+ * @brief The CommandLineParser is used to parse our commandline inputs and set
647+ * parameters accordingly.
648+ */
649+class CommandLineParser
650+{
651+public:
652+ CommandLineParser();
653+
654+ bool processArguments(const QStringList& args);
655+
656+ bool pickModeEnabled() const { return m_pickMode; }
657+ bool testability() const { return m_testability; }
658+ const QString &documentFile() const { return m_documentFile; }
659+
660+private:
661+ bool invalidArg(QString arg);
662+ void usage();
663+
664+ UrlHandler *m_urlHandler;
665+
666+ bool m_pickMode;
667+ bool m_testability;
668+ QString m_documentFile;
669+};
670+
671+#endif // COMMANDLINEPARSER_H
672
673=== added file 'src/app/content-communicator.cpp'
674--- src/app/content-communicator.cpp 1970-01-01 00:00:00 +0000
675+++ src/app/content-communicator.cpp 2015-03-03 16:49:59 +0000
676@@ -0,0 +1,188 @@
677+/*
678+ * Copyright (C) 2013 Canonical, Ltd.
679+ *
680+ * This program is free software; you can redistribute it and/or modify
681+ * it under the terms of the GNU General Public License as published by
682+ * the Free Software Foundation; version 3.
683+ *
684+ * This program is distributed in the hope that it will be useful,
685+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
686+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
687+ * GNU General Public License for more details.
688+ *
689+ * You should have received a copy of the GNU General Public License
690+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
691+ *
692+ */
693+
694+#include "content-communicator.h"
695+
696+#include <QApplication>
697+#include <QStandardPaths>
698+#include <QMimeDatabase>
699+#include <QDebug>
700+#include <QFileInfo>
701+
702+#include <com/ubuntu/content/hub.h>
703+#include <com/ubuntu/content/item.h>
704+#include <com/ubuntu/content/transfer.h>
705+
706+
707+using namespace com::ubuntu::content;
708+
709+/*!
710+ * \brief ContentCommunicator::ContentCommunicator
711+ * \param parent
712+ */
713+ContentCommunicator::ContentCommunicator(QObject *parent)
714+ : ImportExportHandler(parent),
715+ m_transfer(nullptr)
716+{
717+}
718+
719+/*!
720+ * \brief ContentCommunicator::registerWithHub Register the handlers provided
721+ * by ContentCommunicator with the content hub
722+ */
723+void ContentCommunicator::registerWithHub()
724+{
725+ Hub *hub = Hub::Client::instance();
726+ hub->register_import_export_handler(this);
727+}
728+
729+/*!
730+ * \brief \reimp
731+ */
732+void ContentCommunicator::handle_import(content::Transfer *transfer)
733+{
734+ // FIXME: If a file is imported from $HOME/Documents, a new copy of the file is created.
735+ // Could be use md5? http://doc.qt.io/qt-5/qml-qtqml-qt.html#md5-method
736+ // 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".
737+ // (This issue is in gallery-app too.)
738+
739+ QVector<Item> transferedItems = transfer->collect();
740+ foreach (const Item &hubItem, transferedItems) {
741+ QFileInfo fi(hubItem.url().toLocalFile());
742+ QString filename = fi.fileName();
743+ QString dir;
744+ QMimeDatabase mdb;
745+ QMimeType mt = mdb.mimeTypeForFile(hubItem.url().toLocalFile());
746+ QString suffix = fi.completeSuffix();
747+ // FIXME: Should we use fi.baseName()?
748+ QString filenameWithoutSuffix = filename.left(filename.size() - suffix.size());
749+ if(suffix.isEmpty()) {
750+ // If the filename doesn't have an extension add one from the
751+ // detected mimetype
752+ if(!mt.preferredSuffix().isEmpty()) {
753+ suffix = mt.preferredSuffix();
754+ filenameWithoutSuffix += ".";
755+ }
756+ }
757+ dir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + QDir::separator();
758+
759+ QString destination = QString("%1%2").arg(dir + filenameWithoutSuffix, suffix);
760+ // If we already have a file of this name reformat to "filename.x.png"
761+ // (where x is a number, incremented until we find an available filename)
762+ if(QFile::exists(destination)) {
763+ int append = 1;
764+ do {
765+ destination = QString("%1%2.%3").arg(dir + filenameWithoutSuffix, QString::number(append), suffix);
766+ append++;
767+ } while(QFile::exists(destination));
768+ }
769+ QFile::copy(hubItem.url().toLocalFile(), destination);
770+ }
771+
772+ // Allow content-hub to clean up temporary files in .cache/ once we've
773+ // moved them
774+ transfer->finalize();
775+
776+ emit documentImported();
777+}
778+
779+/*!
780+ * \brief \reimp
781+ */
782+void ContentCommunicator::handle_export(content::Transfer *transfer)
783+{
784+ if (m_transfer != nullptr) {
785+ qWarning() << "docviewer-app does only one content export at a time";
786+ transfer->abort();
787+ return;
788+ }
789+
790+ m_transfer = transfer;
791+ emit documentRequested();
792+ emit selectionTypeChanged();
793+ emit singleContentPickModeChanged();
794+}
795+
796+/*!
797+ * \brief \reimp
798+ */
799+void ContentCommunicator::handle_share(content::Transfer *)
800+{
801+ qDebug() << Q_FUNC_INFO << "docviewer does not share content";
802+}
803+
804+/*!
805+ * \brief ContentCommunicator::cancelTransfer aborts the current transfer
806+ */
807+void ContentCommunicator::cancelTransfer()
808+{
809+ if (!m_transfer) {
810+ qWarning() << "No ongoing transfer to cancel";
811+ return;
812+ }
813+
814+ m_transfer->abort();
815+ m_transfer = nullptr;
816+}
817+
818+/*!
819+ * \brief ContentCommunicator::returnSocuments returns the given documents
820+ * via content hub to the requester
821+ * \param urls
822+ */
823+void ContentCommunicator::returnDocuments(const QVector<QUrl> &urls)
824+{
825+ if (!m_transfer) {
826+ qWarning() << "No ongoing transfer to return a document";
827+ return;
828+ }
829+
830+ QVector<Item> items;
831+ items.reserve(urls.size());
832+ foreach (const QUrl &url, urls) {
833+ items.append(Item(url));
834+ }
835+
836+ m_transfer->charge(items);
837+ m_transfer = nullptr;
838+}
839+
840+/*!
841+ * \brief ContentCommunicator::selectionType return if the transfer requests
842+ * one single item only, or multiple
843+ * \return
844+ */
845+ContentCommunicator::SelectionType ContentCommunicator::selectionType() const
846+{
847+ if (!m_transfer)
848+ return SingleSelect;
849+
850+ return static_cast<SelectionType>(m_transfer->selectionType());
851+}
852+
853+/*!
854+ * \brief ContentCommunicator::singleContentPickMode
855+ * \return
856+ */
857+bool ContentCommunicator::singleContentPickMode() const
858+{
859+ if (!m_transfer)
860+ return true;
861+
862+ // FIXME: Shouldn't be Transfer::SelectionType::SingleSelect?
863+ return m_transfer->selectionType() == Transfer::SelectionType::single;
864+}
865
866=== added file 'src/app/content-communicator.h'
867--- src/app/content-communicator.h 1970-01-01 00:00:00 +0000
868+++ src/app/content-communicator.h 2015-03-03 16:49:59 +0000
869@@ -0,0 +1,69 @@
870+/*
871+ * Copyright (C) 2013 Canonical, Ltd.
872+ *
873+ * This program is free software; you can redistribute it and/or modify
874+ * it under the terms of the GNU General Public License as published by
875+ * the Free Software Foundation; version 3.
876+ *
877+ * This program is distributed in the hope that it will be useful,
878+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
879+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
880+ * GNU General Public License for more details.
881+ *
882+ * You should have received a copy of the GNU General Public License
883+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
884+ *
885+ */
886+
887+#ifndef CONTENTCOMMUNICATOR_H
888+#define CONTENTCOMMUNICATOR_H
889+
890+#include <com/ubuntu/content/import_export_handler.h>
891+#include <com/ubuntu/content/transfer.h>
892+
893+#include <QUrl>
894+#include <QVector>
895+
896+using namespace com::ubuntu;
897+
898+/*!
899+ * Class to handle the communication with the content manager
900+ */
901+class ContentCommunicator : public content::ImportExportHandler
902+{
903+ Q_OBJECT
904+ Q_PROPERTY(bool singleContentPickMode READ singleContentPickMode NOTIFY singleContentPickModeChanged)
905+ Q_PROPERTY(SelectionType selectionType READ selectionType NOTIFY selectionTypeChanged)
906+ Q_ENUMS(SelectionType)
907+
908+public:
909+ enum SelectionType {
910+ SingleSelect = content::Transfer::single,
911+ MultiSelect = content::Transfer::multiple
912+ };
913+
914+ ContentCommunicator(QObject *parent = nullptr);
915+
916+ virtual void handle_import(content::Transfer*);
917+ virtual void handle_export(content::Transfer *transfer);
918+ virtual void handle_share(content::Transfer*);
919+
920+ void cancelTransfer();
921+ void returnDocuments(const QVector<QUrl> &urls);
922+
923+ SelectionType selectionType() const;
924+ bool singleContentPickMode() const;
925+
926+ void registerWithHub();
927+
928+signals:
929+ void documentRequested();
930+ void documentImported();
931+ void selectionTypeChanged();
932+ void singleContentPickModeChanged();
933+
934+private:
935+ content::Transfer *m_transfer;
936+};
937+
938+#endif // CONTENTCOMMUNICATOR_H
939
940=== added file 'src/app/docviewer-application.cpp'
941--- src/app/docviewer-application.cpp 1970-01-01 00:00:00 +0000
942+++ src/app/docviewer-application.cpp 2015-03-03 16:49:59 +0000
943@@ -0,0 +1,298 @@
944+/*
945+ * Copyright (C) 2012 Canonical Ltd
946+ *
947+ * This program is free software: you can redistribute it and/or modify
948+ * it under the terms of the GNU General Public License version 3 as
949+ * published by the Free Software Foundation.
950+ *
951+ * This program is distributed in the hope that it will be useful,
952+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
953+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
954+ * GNU General Public License for more details.
955+ *
956+ * You should have received a copy of the GNU General Public License
957+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
958+ *
959+ * Authors:
960+ * Charles Lindsay <chaz@yorba.org>
961+ */
962+
963+#include "docviewer-application.h"
964+#include "content-communicator.h"
965+#include "command-line-parser.h"
966+#include "urlhandler.h"
967+#include "quick/documentmodel.h"
968+
969+#include <QQuickItem>
970+#include <QStandardPaths>
971+#include <QQuickView>
972+#include <QtQml/QtQml>
973+#include <QString>
974+#include <QUrl>
975+#include <QtGui/QGuiApplication>
976+
977+/*!
978+ * \brief DocViewerApplication::DocViewerApplication
979+ * \param argc
980+ * \param argv
981+ */
982+DocViewerApplication::DocViewerApplication(int& argc, char** argv)
983+ : QApplication(argc, argv),
984+ m_view(new QQuickView()),
985+ m_contentCommunicator(new ContentCommunicator(this)),
986+ m_pickModeEnabled(false),
987+ m_defaultUiMode(BrowseContentMode),
988+ m_documentFile(""),
989+ m_documentLoaded(false)
990+{
991+ //
992+}
993+
994+bool DocViewerApplication::init()
995+{
996+ m_cmdLineParser = new CommandLineParser();
997+
998+ if (!m_cmdLineParser->processArguments(arguments()))
999+ return false;
1000+
1001+ if (qgetenv("QT_LOAD_TESTABILITY") == "1" || m_cmdLineParser->testability()) {
1002+ QLibrary testLib(QLatin1String("qttestability"));
1003+ if (testLib.load()) {
1004+ typedef void (*TasInitialize)(void);
1005+ TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init");
1006+ if (initFunction) {
1007+ initFunction();
1008+ } else {
1009+ qCritical("Library qttestability resolve failed!");
1010+ }
1011+ } else {
1012+ qCritical("Library qttestability load failed!");
1013+ }
1014+ }
1015+
1016+ m_urlHandler = new UrlHandler();
1017+
1018+ registerQML();
1019+
1020+ if (m_cmdLineParser->pickModeEnabled())
1021+ setDefaultUiMode(DocViewerApplication::PickContentMode);
1022+
1023+ QObject::connect(m_contentCommunicator, SIGNAL(documentRequested()),
1024+ this, SLOT(switchToPickMode()));
1025+
1026+ QObject::connect(m_contentCommunicator, SIGNAL(documentImported()),
1027+ this, SLOT(switchToBrowseMode()));
1028+
1029+ return true;
1030+}
1031+
1032+/*!
1033+ * \brief DocViewerApplication::~DocViewerApplication
1034+ */
1035+DocViewerApplication::~DocViewerApplication()
1036+{
1037+ delete m_view;
1038+ delete m_cmdLineParser;
1039+}
1040+
1041+/*!
1042+ * \brief DocViewerApplication::exec
1043+ * \return
1044+ */
1045+int DocViewerApplication::exec()
1046+{
1047+ createView();
1048+
1049+ return QApplication::exec();
1050+}
1051+
1052+/*!
1053+ * \brief DocViewerApplication::registerQML
1054+ */
1055+void DocViewerApplication::registerQML()
1056+{
1057+ // Set up import paths
1058+ QStringList importPathList = m_view->engine()->importPathList();
1059+ // Prepend the location of the plugin in the build dir,
1060+ // so that Qt Creator finds it there, thus overriding the one installed
1061+ // in the sistem if there is one
1062+ importPathList.prepend(QCoreApplication::applicationDirPath() + "/../plugin/");
1063+ m_view->engine()->setImportPathList(importPathList);
1064+
1065+ qmlRegisterType<SortFilterDocumentModel>("DocumentViewer", 1, 0, "DocumentsModel");
1066+}
1067+
1068+/*!
1069+ * \brief DocViewerApplication::getDocumentFile
1070+ * Returns the document file passed as a parameter
1071+ */
1072+const QString& DocViewerApplication::getDocumentFile() const
1073+{
1074+ return m_documentFile;
1075+}
1076+
1077+/*!
1078+ * \brief DocViewerApplication::createView
1079+ * Create the master QDeclarativeView that all the pages will operate within
1080+ */
1081+void DocViewerApplication::createView()
1082+{
1083+ m_view->setTitle(tr("Document Viewer"));
1084+
1085+ // Set ourselves up to expose functionality to run external commands from QML...
1086+ m_view->engine()->rootContext()->setContextProperty("DOC_VIEWER", this);
1087+ m_view->engine()->rootContext()->setContextProperty("PICKER_HUB", m_contentCommunicator);
1088+
1089+ QObject::connect(m_view->engine(), SIGNAL(quit()), this, SLOT(quit()));
1090+
1091+ QString qmlfile;
1092+ const QString filePath = QLatin1String("qml/ubuntu-docviewer-app.qml");
1093+ QStringList paths = QStandardPaths::standardLocations(QStandardPaths::DataLocation);
1094+ paths.prepend(QDir::currentPath());
1095+ paths.prepend(QCoreApplication::applicationDirPath());
1096+ Q_FOREACH (const QString &path, paths) {
1097+ QString myPath = path + QLatin1Char('/') + filePath;
1098+
1099+ if (QFile::exists(myPath)) {
1100+ qmlfile = myPath;
1101+ break;
1102+ } else {
1103+ myPath.replace(QCoreApplication::applicationName(), "ubuntu-docviewer-app");
1104+
1105+ if (QFile::exists(myPath)) {
1106+ qmlfile = myPath;
1107+ break;
1108+ }
1109+ }
1110+ }
1111+ // sanity check
1112+ if (qmlfile.isEmpty()) {
1113+ qFatal("File: %s does not exist at any of the standard paths!", qPrintable(filePath));
1114+ }
1115+
1116+ registerHub();
1117+ m_view->setSource(QUrl::fromLocalFile(qmlfile));
1118+ setDocumentFile(m_cmdLineParser->documentFile());
1119+
1120+ m_view->setResizeMode(QQuickView::SizeRootObjectToView);
1121+ m_view->show();
1122+}
1123+
1124+/*!
1125+ * \brief DocViewerApplication::setDefaultUiMode set the default UI mode. This might
1126+ * get overridden during the lifetime
1127+ * \param mode
1128+ */
1129+void DocViewerApplication::setDefaultUiMode(DocViewerApplication::UiMode mode)
1130+{
1131+ m_defaultUiMode = mode;
1132+ setUiMode(mode);
1133+}
1134+
1135+/*!
1136+ * \brief DocViewerApplication::setUiMode set's the current UI mode
1137+ * \param mode
1138+ */
1139+void DocViewerApplication::setUiMode(DocViewerApplication::UiMode mode)
1140+{
1141+ bool enablePickMode = (mode == PickContentMode);
1142+
1143+ if (enablePickMode != m_pickModeEnabled) {
1144+ m_pickModeEnabled = enablePickMode;
1145+ Q_EMIT pickModeEnabledChanged();
1146+ }
1147+}
1148+
1149+/*!
1150+ * \brief DocViewerApplication::pickModeEnabled returns true if the current UI
1151+ * mode should be for picking acontent
1152+ * \return
1153+ */
1154+bool DocViewerApplication::pickModeEnabled() const
1155+{
1156+ return m_pickModeEnabled;
1157+}
1158+
1159+/*!
1160+ * \brief DocViewerApplication::switchToPickMode
1161+ */
1162+void DocViewerApplication::switchToPickMode()
1163+{
1164+ setUiMode(PickContentMode);
1165+}
1166+
1167+/*!
1168+ * \brief DocViewerApplication::switchToBrowseMode
1169+ */
1170+void DocViewerApplication::switchToBrowseMode()
1171+{
1172+ Q_EMIT browseModeRequested();
1173+}
1174+
1175+void DocViewerApplication::setDocumentFile(const QString &documentFile)
1176+{
1177+ if(!documentFile.isEmpty()) {
1178+ if (m_documentFile != documentFile) {
1179+ m_documentFile = "file://" + documentFile;
1180+ Q_EMIT documentFileChanged();;
1181+ }
1182+ }
1183+}
1184+
1185+/*!
1186+ * \brief DocViewerApplication::returnPickedContent passes the selcted items to the
1187+ * content manager
1188+ * \param variant
1189+ */
1190+void DocViewerApplication::returnPickedContent(QList<QString> paths)
1191+{
1192+ QVector<QUrl> selectedMedias;
1193+ selectedMedias.reserve(paths.size());
1194+ foreach (const QString path, paths) {
1195+ // We handle paths without "file://" prefix, so we need to add it when exporting to content-hub.
1196+ selectedMedias.append(QUrl("file://" + path));
1197+ }
1198+ m_contentCommunicator->returnDocuments(selectedMedias);
1199+
1200+ if (m_defaultUiMode == BrowseContentMode) {
1201+ setUiMode(BrowseContentMode);
1202+ } else {
1203+ // give the app and content-hub some time to finish taks (run the event loop)
1204+ QTimer::singleShot(10, this, SLOT(quit()));
1205+ }
1206+}
1207+
1208+/*!
1209+ * \brief DocViewerApplication::contentPickingCanceled tell the content manager, that
1210+ * the picking was canceled
1211+ */
1212+void DocViewerApplication::contentPickingCanceled()
1213+{
1214+ m_contentCommunicator->cancelTransfer();
1215+
1216+ if (m_defaultUiMode == BrowseContentMode) {
1217+ setUiMode(BrowseContentMode);
1218+ } else {
1219+ // give the app and content-hub some time to finish taks (run the event loop)
1220+ QTimer::singleShot(10, this, SLOT(quit()));
1221+ }
1222+}
1223+
1224+void DocViewerApplication::registerHub()
1225+{
1226+ m_contentCommunicator->registerWithHub();
1227+}
1228+
1229+void DocViewerApplication::parseUri(const QString &arg)
1230+{
1231+ if (m_urlHandler->processUri(arg)) {
1232+ setDocumentFile(m_urlHandler->documentFile());
1233+ }
1234+}
1235+
1236+void DocViewerApplication::releaseResources()
1237+{
1238+ if (m_view) {
1239+ m_view->releaseResources();
1240+ }
1241+}
1242
1243=== added file 'src/app/docviewer-application.h'
1244--- src/app/docviewer-application.h 1970-01-01 00:00:00 +0000
1245+++ src/app/docviewer-application.h 2015-03-03 16:49:59 +0000
1246@@ -0,0 +1,92 @@
1247+/*
1248+ * Copyright (C) 2012 Canonical Ltd
1249+ *
1250+ * This program is free software: you can redistribute it and/or modify
1251+ * it under the terms of the GNU General Public License version 3 as
1252+ * published by the Free Software Foundation.
1253+ *
1254+ * This program is distributed in the hope that it will be useful,
1255+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1256+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1257+ * GNU General Public License for more details.
1258+ *
1259+ * You should have received a copy of the GNU General Public License
1260+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1261+ *
1262+ * Authors:
1263+ * Charles Lindsay <chaz@yorba.org>
1264+ */
1265+
1266+#ifndef DOCVIEWERAPPLICATION_H
1267+#define DOCVIEWERAPPLICATION_H
1268+
1269+#include <QApplication>
1270+#include <QElapsedTimer>
1271+#include <QFileInfo>
1272+#include <QTimer>
1273+
1274+class CommandLineParser;
1275+class UrlHandler;
1276+class ContentCommunicator;
1277+
1278+class QQuickView;
1279+
1280+/*!
1281+ * \brief The DocViewerApplication class
1282+ */
1283+class DocViewerApplication : public QApplication
1284+{
1285+ Q_OBJECT
1286+ Q_PROPERTY(bool pickModeEnabled READ pickModeEnabled NOTIFY pickModeEnabledChanged)
1287+ Q_PROPERTY(QString documentFile READ getDocumentFile WRITE setDocumentFile NOTIFY documentFileChanged)
1288+
1289+public:
1290+ enum UiMode{
1291+ BrowseContentMode,
1292+ PickContentMode
1293+ };
1294+
1295+ explicit DocViewerApplication(int& argc, char** argv);
1296+ virtual ~DocViewerApplication();
1297+
1298+ bool init();
1299+ int exec();
1300+
1301+ void setDefaultUiMode(UiMode mode);
1302+ UiMode defaultUiMode() const;
1303+ void setUiMode(UiMode mode);
1304+ bool pickModeEnabled() const;
1305+ const QString &getDocumentFile() const;
1306+
1307+ Q_INVOKABLE void returnPickedContent(QList<QString> paths);
1308+ Q_INVOKABLE void contentPickingCanceled();
1309+ Q_INVOKABLE void parseUri(const QString &arg);
1310+ Q_INVOKABLE void releaseResources();
1311+
1312+signals:
1313+ void pickModeEnabledChanged();
1314+ void documentFileChanged();
1315+ void browseModeRequested();
1316+
1317+private slots:
1318+ void switchToPickMode();
1319+ void switchToBrowseMode();
1320+ void setDocumentFile(const QString &documentFile);
1321+
1322+private:
1323+ void registerHub();
1324+ void registerQML();
1325+ void createView();
1326+
1327+ QQuickView *m_view;
1328+ CommandLineParser* m_cmdLineParser;
1329+ UrlHandler *m_urlHandler;
1330+ ContentCommunicator *m_contentCommunicator;
1331+
1332+ bool m_pickModeEnabled;
1333+ UiMode m_defaultUiMode;
1334+ QString m_documentFile;
1335+ bool m_documentLoaded;
1336+};
1337+
1338+#endif // DOCVIEWERAPPLICATION_H
1339
1340=== added directory 'src/app/graphics'
1341=== added file 'src/app/graphics/select-none.svg'
1342--- src/app/graphics/select-none.svg 1970-01-01 00:00:00 +0000
1343+++ src/app/graphics/select-none.svg 2015-03-03 16:49:59 +0000
1344@@ -0,0 +1,153 @@
1345+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
1346+<!-- Created with Inkscape (http://www.inkscape.org/) -->
1347+
1348+<svg
1349+ xmlns:dc="http://purl.org/dc/elements/1.1/"
1350+ xmlns:cc="http://creativecommons.org/ns#"
1351+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
1352+ xmlns:svg="http://www.w3.org/2000/svg"
1353+ xmlns="http://www.w3.org/2000/svg"
1354+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
1355+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
1356+ width="90"
1357+ height="90"
1358+ id="svg4874"
1359+ version="1.1"
1360+ inkscape:version="0.48+devel r"
1361+ viewBox="0 0 90 90.000001"
1362+ sodipodi:docname="select-none.svg">
1363+ <defs
1364+ id="defs4876" />
1365+ <sodipodi:namedview
1366+ id="base"
1367+ pagecolor="#ffffff"
1368+ bordercolor="#666666"
1369+ borderopacity="1.0"
1370+ inkscape:pageopacity="0.0"
1371+ inkscape:pageshadow="2"
1372+ inkscape:zoom="12.434498"
1373+ inkscape:cx="10.237647"
1374+ inkscape:cy="53.078139"
1375+ inkscape:document-units="px"
1376+ inkscape:current-layer="g1311"
1377+ showgrid="true"
1378+ showborder="true"
1379+ fit-margin-top="0"
1380+ fit-margin-left="0"
1381+ fit-margin-right="0"
1382+ fit-margin-bottom="0"
1383+ inkscape:snap-bbox="true"
1384+ inkscape:bbox-paths="true"
1385+ inkscape:bbox-nodes="true"
1386+ inkscape:snap-bbox-edge-midpoints="true"
1387+ inkscape:snap-bbox-midpoints="true"
1388+ inkscape:object-paths="true"
1389+ inkscape:snap-intersection-paths="true"
1390+ inkscape:object-nodes="true"
1391+ inkscape:snap-smooth-nodes="true"
1392+ inkscape:snap-midpoints="true"
1393+ inkscape:snap-object-midpoints="true"
1394+ inkscape:snap-center="true"
1395+ showguides="true"
1396+ inkscape:guide-bbox="true">
1397+ <inkscape:grid
1398+ type="xygrid"
1399+ id="grid5451"
1400+ empspacing="6" />
1401+ <sodipodi:guide
1402+ orientation="1,0"
1403+ position="6,77"
1404+ id="guide4063" />
1405+ <sodipodi:guide
1406+ orientation="1,0"
1407+ position="3,78"
1408+ id="guide4065" />
1409+ <sodipodi:guide
1410+ orientation="0,1"
1411+ position="55,84"
1412+ id="guide4067" />
1413+ <sodipodi:guide
1414+ orientation="0,1"
1415+ position="53,87"
1416+ id="guide4069" />
1417+ <sodipodi:guide
1418+ orientation="0,1"
1419+ position="20,3"
1420+ id="guide4071" />
1421+ <sodipodi:guide
1422+ orientation="0,1"
1423+ position="20,6"
1424+ id="guide4073" />
1425+ <sodipodi:guide
1426+ orientation="1,0"
1427+ position="87,7"
1428+ id="guide4075" />
1429+ <sodipodi:guide
1430+ orientation="1,0"
1431+ position="84,7"
1432+ id="guide4077" />
1433+ <sodipodi:guide
1434+ orientation="0,1"
1435+ position="58,81"
1436+ id="guide4074" />
1437+ <sodipodi:guide
1438+ orientation="1,0"
1439+ position="9,74"
1440+ id="guide4076" />
1441+ <sodipodi:guide
1442+ orientation="0,1"
1443+ position="21,9"
1444+ id="guide4078" />
1445+ <sodipodi:guide
1446+ orientation="1,0"
1447+ position="81,4"
1448+ id="guide4080" />
1449+ </sodipodi:namedview>
1450+ <metadata
1451+ id="metadata4879">
1452+ <rdf:RDF>
1453+ <cc:Work
1454+ rdf:about="">
1455+ <dc:format>image/svg+xml</dc:format>
1456+ <dc:type
1457+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
1458+ <dc:title></dc:title>
1459+ </cc:Work>
1460+ </rdf:RDF>
1461+ </metadata>
1462+ <g
1463+ inkscape:label="Layer 1"
1464+ inkscape:groupmode="layer"
1465+ id="layer1"
1466+ transform="translate(67.857146,-84.50504)">
1467+ <g
1468+ transform="matrix(0,-1,-1,0,373.50506,516.50504)"
1469+ id="g4845"
1470+ style="display:inline">
1471+ <g
1472+ transform="matrix(0,-1,-1,0,567.36222,615.36221)"
1473+ id="g1311"
1474+ inkscape:export-filename="envelope02.png"
1475+ inkscape:export-xdpi="90"
1476+ inkscape:export-ydpi="90">
1477+ <g
1478+ id="g1313"
1479+ transform="matrix(1.875,0,0,1.875,-366,-1657.8169)">
1480+ <rect
1481+ transform="translate(0,804.3622)"
1482+ y="152"
1483+ x="288"
1484+ height="48"
1485+ width="48"
1486+ id="rect1315"
1487+ style="opacity:0.21171169;fill:none;stroke:none" />
1488+ </g>
1489+ <path
1490+ 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"
1491+ 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 "
1492+ transform="translate(174,135.36222)"
1493+ id="path4098" />
1494+ </g>
1495+ </g>
1496+ </g>
1497+</svg>
1498
1499=== added file 'src/app/graphics/select.svg'
1500--- src/app/graphics/select.svg 1970-01-01 00:00:00 +0000
1501+++ src/app/graphics/select.svg 2015-03-03 16:49:59 +0000
1502@@ -0,0 +1,158 @@
1503+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
1504+<!-- Created with Inkscape (http://www.inkscape.org/) -->
1505+
1506+<svg
1507+ xmlns:dc="http://purl.org/dc/elements/1.1/"
1508+ xmlns:cc="http://creativecommons.org/ns#"
1509+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
1510+ xmlns:svg="http://www.w3.org/2000/svg"
1511+ xmlns="http://www.w3.org/2000/svg"
1512+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
1513+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
1514+ width="90"
1515+ height="90"
1516+ id="svg4874"
1517+ version="1.1"
1518+ inkscape:version="0.48+devel r12833"
1519+ viewBox="0 0 90 90.000001"
1520+ sodipodi:docname="select.svg">
1521+ <defs
1522+ id="defs4876" />
1523+ <sodipodi:namedview
1524+ id="base"
1525+ pagecolor="#ffffff"
1526+ bordercolor="#666666"
1527+ borderopacity="1.0"
1528+ inkscape:pageopacity="0.0"
1529+ inkscape:pageshadow="2"
1530+ inkscape:zoom="12.434498"
1531+ inkscape:cx="30.343002"
1532+ inkscape:cy="53.600878"
1533+ inkscape:document-units="px"
1534+ inkscape:current-layer="g1311"
1535+ showgrid="true"
1536+ showborder="true"
1537+ fit-margin-top="0"
1538+ fit-margin-left="0"
1539+ fit-margin-right="0"
1540+ fit-margin-bottom="0"
1541+ inkscape:snap-bbox="true"
1542+ inkscape:bbox-paths="true"
1543+ inkscape:bbox-nodes="true"
1544+ inkscape:snap-bbox-edge-midpoints="true"
1545+ inkscape:snap-bbox-midpoints="true"
1546+ inkscape:object-paths="true"
1547+ inkscape:snap-intersection-paths="true"
1548+ inkscape:object-nodes="true"
1549+ inkscape:snap-smooth-nodes="true"
1550+ inkscape:snap-midpoints="true"
1551+ inkscape:snap-object-midpoints="true"
1552+ inkscape:snap-center="true"
1553+ showguides="true"
1554+ inkscape:guide-bbox="true">
1555+ <inkscape:grid
1556+ type="xygrid"
1557+ id="grid5451"
1558+ empspacing="6" />
1559+ <sodipodi:guide
1560+ orientation="1,0"
1561+ position="6,77"
1562+ id="guide4063" />
1563+ <sodipodi:guide
1564+ orientation="1,0"
1565+ position="3,78"
1566+ id="guide4065" />
1567+ <sodipodi:guide
1568+ orientation="0,1"
1569+ position="55,84"
1570+ id="guide4067" />
1571+ <sodipodi:guide
1572+ orientation="0,1"
1573+ position="53,87"
1574+ id="guide4069" />
1575+ <sodipodi:guide
1576+ orientation="0,1"
1577+ position="20,3"
1578+ id="guide4071" />
1579+ <sodipodi:guide
1580+ orientation="0,1"
1581+ position="20,6"
1582+ id="guide4073" />
1583+ <sodipodi:guide
1584+ orientation="1,0"
1585+ position="87,7"
1586+ id="guide4075" />
1587+ <sodipodi:guide
1588+ orientation="1,0"
1589+ position="84,7"
1590+ id="guide4077" />
1591+ <sodipodi:guide
1592+ orientation="0,1"
1593+ position="58,81"
1594+ id="guide4074" />
1595+ <sodipodi:guide
1596+ orientation="1,0"
1597+ position="9,74"
1598+ id="guide4076" />
1599+ <sodipodi:guide
1600+ orientation="0,1"
1601+ position="21,9"
1602+ id="guide4078" />
1603+ <sodipodi:guide
1604+ orientation="1,0"
1605+ position="81,4"
1606+ id="guide4080" />
1607+ </sodipodi:namedview>
1608+ <metadata
1609+ id="metadata4879">
1610+ <rdf:RDF>
1611+ <cc:Work
1612+ rdf:about="">
1613+ <dc:format>image/svg+xml</dc:format>
1614+ <dc:type
1615+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
1616+ <dc:title></dc:title>
1617+ </cc:Work>
1618+ </rdf:RDF>
1619+ </metadata>
1620+ <g
1621+ inkscape:label="Layer 1"
1622+ inkscape:groupmode="layer"
1623+ id="layer1"
1624+ transform="translate(67.857146,-84.50504)">
1625+ <g
1626+ transform="matrix(0,-1,-1,0,373.50506,516.50504)"
1627+ id="g4845"
1628+ style="display:inline">
1629+ <g
1630+ transform="matrix(0,-1,-1,0,567.36222,615.36221)"
1631+ id="g1311"
1632+ inkscape:export-filename="envelope02.png"
1633+ inkscape:export-xdpi="90"
1634+ inkscape:export-ydpi="90">
1635+ <g
1636+ id="g1313"
1637+ transform="matrix(1.875,0,0,1.875,-366,-1657.8169)">
1638+ <rect
1639+ transform="translate(0,804.3622)"
1640+ y="152"
1641+ x="288"
1642+ height="48"
1643+ width="48"
1644+ id="rect1315"
1645+ style="opacity:0.21171169;fill:none;stroke:none" />
1646+ </g>
1647+ <path
1648+ 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"
1649+ 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 "
1650+ transform="translate(174,135.36222)"
1651+ id="path4098" />
1652+ <path
1653+ 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"
1654+ 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"
1655+ id="path4041-9"
1656+ inkscape:connector-curvature="0" />
1657+ </g>
1658+ </g>
1659+ </g>
1660+</svg>
1661
1662=== modified file 'src/app/main.cpp'
1663--- src/app/main.cpp 2015-01-30 18:52:42 +0000
1664+++ src/app/main.cpp 2015-03-03 16:49:59 +0000
1665@@ -1,5 +1,5 @@
1666 /*
1667- * Copyright: 2013 - 2015 Canonical, Ltd
1668+ * Copyright: 2015 Canonical Ltd.
1669 *
1670 * This file is part of docviewer
1671 *
1672@@ -14,111 +14,23 @@
1673 * GNU General Public License for more details.
1674 *
1675 * You should have received a copy of the GNU General Public License
1676- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1677- *
1678- * Authors: Michael Zanetti <michael.zanetti@canonical.com>
1679- * Riccardo Padovani <rpadovani@ubuntu.com>
1680- * David Planella <david.planella@ubuntu.com>
1681- * Stefano Verzegnassi <stefano92.100@gmail.com>
1682+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1683 */
1684
1685 // Uncomment if you need to use QML analyzer
1686 // #define QT_QML_DEBUG
1687
1688-#include <QtGui/QGuiApplication>
1689-#include <QtQuick/QQuickView>
1690-#include <QtQml/QtQml>
1691-#include <QLibrary>
1692-#include <QDir>
1693-
1694+#include "docviewer-application.h"
1695 #include <QDebug>
1696
1697 int main(int argc, char *argv[])
1698 {
1699- QGuiApplication a(argc, argv);
1700- QQuickView view;
1701- view.setResizeMode(QQuickView::SizeRootObjectToView);
1702-
1703- view.setPersistentOpenGLContext(false);
1704- view.setPersistentSceneGraph(false);
1705- view.engine()->rootContext()->setContextProperty("QQuickView", &view);
1706-
1707- // Set up import paths
1708- QStringList importPathList = view.engine()->importPathList();
1709- // Prepend the location of the plugin in the build dir,
1710- // so that Qt Creator finds it there, thus overriding the one installed
1711- // in the sistem if there is one
1712- importPathList.prepend(QCoreApplication::applicationDirPath() + "/../plugin/");
1713-
1714- QStringList args = a.arguments();
1715- if (args.contains("-h") || args.contains("--help")) {
1716- qDebug() << "usage: " + args.at(0) + " [-h|--help] <path>";
1717- qDebug() << " -h|--help Print this help.";
1718- qDebug() << " <path> Path of the document to load.";
1719+ QCoreApplication::setApplicationName("com.ubuntu.docviewer");
1720+ QCoreApplication::setOrganizationDomain("com.ubuntu.docviewer");
1721+
1722+ DocViewerApplication app(argc, argv);
1723+ if (!app.init())
1724 return 0;
1725- }
1726-
1727- // Check if the path of the document has been specified.
1728- QString docPath;
1729- for (int i = 1; i < args.count(); i++) {
1730- if (args.at(i) != "-h" && args.at(i) != "--h") {
1731- docPath = args.at(i);
1732- }
1733- }
1734- view.engine()->rootContext()->setContextProperty("documentPath", docPath);
1735-
1736- if (args.contains(QLatin1String("-testability")) || getenv("QT_LOAD_TESTABILITY")) {
1737- QLibrary testLib(QLatin1String("qttestability"));
1738- if (testLib.load()) {
1739- typedef void (*TasInitialize)(void);
1740- TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init");
1741- if (initFunction) {
1742- initFunction();
1743- } else {
1744- qCritical("Library qttestability resolve failed!");
1745- }
1746- } else {
1747- qCritical("Library qttestability load failed!");
1748- }
1749- }
1750-
1751- view.engine()->setImportPathList(importPathList);
1752-
1753- QString qmlfile;
1754- const QString filePath = QLatin1String("qml/ubuntu-docviewer-app.qml");
1755- QStringList paths = QStandardPaths::standardLocations(QStandardPaths::DataLocation);
1756- paths.prepend(QDir::currentPath());
1757- paths.prepend(QCoreApplication::applicationDirPath());
1758- Q_FOREACH (const QString &path, paths) {
1759- QString myPath = path + QLatin1Char('/') + filePath;
1760- if (QFile::exists(myPath)) {
1761- qmlfile = myPath;
1762- break;
1763- }
1764- }
1765- // sanity check
1766- if (qmlfile.isEmpty()) {
1767- qFatal("File: %s does not exist at any of the standard paths!", qPrintable(filePath));
1768- }
1769-
1770- // Make sure our cache dir exists. It'll be used all over in this app.
1771- // We need to set the applicationName for that.
1772- // It'll be overwritten again when qml loads but we need it already now.
1773- // So if you want to change it, make sure to find all the places where it is set, not just here :D
1774- QCoreApplication::setApplicationName("com.ubuntu.docviewer");
1775-
1776- QDir cacheDir(QStandardPaths::standardLocations(QStandardPaths::CacheLocation).first());
1777- if (!cacheDir.exists()) {
1778- qDebug() << "creating cacheDir:" << cacheDir.absolutePath();
1779- cacheDir.mkpath(cacheDir.absolutePath());
1780- }
1781-
1782- // Expose quit() signal to QML
1783- QObject::connect(view.engine(), SIGNAL(quit()), &a, SLOT(quit()));
1784-
1785- qDebug() << "using main qml file from:" << qmlfile;
1786- view.setSource(QUrl::fromLocalFile(qmlfile));
1787- view.show();
1788-
1789- return a.exec();
1790+
1791+ app.exec();
1792 }
1793
1794=== removed file 'src/app/qml/ContentHubPicker.qml'
1795--- src/app/qml/ContentHubPicker.qml 2015-01-29 16:24:50 +0000
1796+++ src/app/qml/ContentHubPicker.qml 1970-01-01 00:00:00 +0000
1797@@ -1,71 +0,0 @@
1798-/*
1799- * Copyright (C) 2014-2015 Canonical, Ltd.
1800- *
1801- * This program is free software; you can redistribute it and/or modify
1802- * it under the terms of the GNU General Public License as published by
1803- * the Free Software Foundation; version 3.
1804- *
1805- * This program is distributed in the hope that it will be useful,
1806- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1807- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1808- * GNU General Public License for more details.
1809- *
1810- * You should have received a copy of the GNU General Public License
1811- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1812- */
1813-
1814-import QtQuick 2.0
1815-import Ubuntu.Components 1.1
1816-import Ubuntu.Content 1.1
1817-
1818-Page {
1819- id: picker
1820- title: i18n.tr("Open with...")
1821-
1822- property var activeTransfer
1823-
1824- head.sections.model: [i18n.tr("Documents"), i18n.tr("Pictures"), i18n.tr("Other")]
1825- head.backAction: Action {
1826- iconName: "back"
1827- text: i18n.tr("Back")
1828- onTriggered: pageStack.pop()
1829- }
1830-
1831- ContentPeerPicker {
1832- // Do not show ContentPeerPicker header, since we need head.sections.
1833- showTitle: false
1834-
1835- contentType: {
1836- switch (picker.head.sections.selectedIndex) {
1837- case 0:
1838- return ContentType.Documents
1839- case 1:
1840- return ContentType.Pictures
1841- case 2:
1842- return ContentType.Unknown
1843- }
1844- }
1845- handler: ContentHandler.Source
1846-
1847- onPeerSelected: picker.activeTransfer = peer.request();
1848- }
1849-
1850- ContentTransferHint {
1851- id: transferHint
1852- anchors.fill: parent
1853- activeTransfer: picker.activeTransfer
1854- }
1855-
1856- Connections {
1857- target: picker.activeTransfer ? picker.activeTransfer : null
1858- onStateChanged: {
1859- if (picker.activeTransfer.state === ContentTransfer.Charged) {
1860- // Close ContentHubPicker page.
1861- pageStack.pop();
1862-
1863- file.path = picker.activeTransfer.items[0].url.toString().replace("file://", "")
1864- console.log("[CONTENT-HUB] Content imported!")
1865- }
1866- }
1867- }
1868-}
1869
1870=== removed file 'src/app/qml/ContentHubProxy.qml'
1871--- src/app/qml/ContentHubProxy.qml 2014-11-04 18:54:38 +0000
1872+++ src/app/qml/ContentHubProxy.qml 1970-01-01 00:00:00 +0000
1873@@ -1,38 +0,0 @@
1874-/*
1875- * Copyright (C) 2012-2014 Canonical, Ltd.
1876- *
1877- * This program is free software; you can redistribute it and/or modify
1878- * it under the terms of the GNU General Public License as published by
1879- * the Free Software Foundation; version 3.
1880- *
1881- * This program is distributed in the hope that it will be useful,
1882- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1883- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1884- * GNU General Public License for more details.
1885- *
1886- * You should have received a copy of the GNU General Public License
1887- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1888- */
1889-
1890-import QtQuick 2.3
1891-import Ubuntu.Content 1.1 as ContentHub
1892-
1893-QtObject {
1894- property QtObject pageStack: null
1895- property list<QtObject> objects: [
1896- Connections {
1897- target: ContentHub.ContentHub
1898-
1899- onImportRequested: {
1900- if (transfer.state === ContentHub.ContentTransfer.Charged) {
1901- // We have no signals to know if an import was requested before Component.completed signal
1902- // is emitted. So clear the stack when this occurs.
1903- pageStack.clear()
1904-
1905- console.log("[CONTENT-HUB] Incoming Import Request")
1906- file.path = transfer.items[0].url.toString().replace("file://", "");
1907- }
1908- }
1909- }
1910- ]
1911-}
1912
1913=== removed file 'src/app/qml/DetailsPage.qml'
1914--- src/app/qml/DetailsPage.qml 2015-01-29 16:24:50 +0000
1915+++ src/app/qml/DetailsPage.qml 1970-01-01 00:00:00 +0000
1916@@ -1,58 +0,0 @@
1917-/*
1918- * Copyright (C) 2013-2014 Canonical, Ltd.
1919- *
1920- * This program is free software; you can redistribute it and/or modify
1921- * it under the terms of the GNU General Public License as published by
1922- * the Free Software Foundation; version 3.
1923- *
1924- * This program is distributed in the hope that it will be useful,
1925- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1926- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1927- * GNU General Public License for more details.
1928- *
1929- * You should have received a copy of the GNU General Public License
1930- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1931- */
1932-
1933-import QtQuick 2.3
1934-import Ubuntu.Components 1.1
1935-import Ubuntu.Components.ListItems 1.0 as ListItem
1936-
1937-import "utils.js" as Utils
1938-
1939-Page {
1940- id: detailsPage
1941- objectName: "detailsPage"
1942-
1943- title: i18n.tr("Details")
1944-
1945- Column {
1946- width: parent.width
1947-
1948- ListItem.Subtitled {
1949- text: i18n.tr("Location")
1950- subText: file.path
1951- }
1952- ListItem.Subtitled {
1953- text: i18n.tr("Size")
1954- subText: Utils.printSize(file.size)
1955- }
1956-
1957- ListItem.Subtitled {
1958- text: i18n.tr("Created")
1959- subText: file.creationTime.toLocaleString(Qt.locale())
1960- }
1961-
1962- ListItem.Subtitled {
1963- text: i18n.tr("Last modified")
1964- subText: file.lastModified.toLocaleString(Qt.locale())
1965- }
1966-
1967- ListItem.Subtitled {
1968- id: mimetypeItem
1969- objectName: "mimetypeItem"
1970- text: i18n.tr("MIME type")
1971- subText: file.mimetype
1972- }
1973- }
1974-}
1975
1976=== removed file 'src/app/qml/EmptyState.qml'
1977--- src/app/qml/EmptyState.qml 2015-01-16 16:46:46 +0000
1978+++ src/app/qml/EmptyState.qml 1970-01-01 00:00:00 +0000
1979@@ -1,59 +0,0 @@
1980-/*
1981- * Copyright (C) 2014 Canonical Ltd
1982- *
1983- * This file is part of Ubuntu Clock App
1984- *
1985- * Ubuntu Clock App is free software: you can redistribute it and/or modify
1986- * it under the terms of the GNU General Public License version 3 as
1987- * published by the Free Software Foundation.
1988- *
1989- * Ubuntu Clock App is distributed in the hope that it will be useful,
1990- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1991- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1992- * GNU General Public License for more details.
1993- *
1994- * You should have received a copy of the GNU General Public License
1995- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1996- */
1997-
1998-import QtQuick 2.3
1999-import Ubuntu.Components 1.1
2000-
2001-/*
2002- Component which displays an empty state (approved by design). It offers an
2003- icon, title and subtitle to describe the empty state.
2004-*/
2005-
2006-Item {
2007- id: emptyState
2008-
2009- // Public APIs
2010- property alias iconName: emptyIcon.name
2011- property alias title: emptyLabel.text
2012- property alias subTitle: emptySublabel.text
2013-
2014- height: childrenRect.height
2015-
2016- Icon {
2017- id: emptyIcon
2018- anchors.horizontalCenter: parent.horizontalCenter
2019- height: units.gu(10)
2020- width: height
2021- color: "#BBBBBB"
2022- }
2023-
2024- Label {
2025- id: emptyLabel
2026- anchors.top: emptyIcon.bottom
2027- anchors.topMargin: units.gu(5)
2028- anchors.horizontalCenter: parent.horizontalCenter
2029- fontSize: "large"
2030- font.bold: true
2031- }
2032-
2033- Label {
2034- id: emptySublabel
2035- anchors.top: emptyLabel.bottom
2036- anchors.horizontalCenter: parent.horizontalCenter
2037- }
2038-}
2039
2040=== removed file 'src/app/qml/ErrorDialog.qml'
2041--- src/app/qml/ErrorDialog.qml 2015-01-29 19:14:08 +0000
2042+++ src/app/qml/ErrorDialog.qml 1970-01-01 00:00:00 +0000
2043@@ -1,32 +0,0 @@
2044-/*
2045- * Copyright (C) 2014-2015 Canonical, Ltd.
2046- *
2047- * This program is free software; you can redistribute it and/or modify
2048- * it under the terms of the GNU General Public License as published by
2049- * the Free Software Foundation; version 3.
2050- *
2051- * This program is distributed in the hope that it will be useful,
2052- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2053- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2054- * GNU General Public License for more details.
2055- *
2056- * You should have received a copy of the GNU General Public License
2057- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2058- */
2059-
2060-import QtQuick 2.3
2061-import Ubuntu.Components 1.1
2062-import Ubuntu.Components.Popups 1.0
2063-
2064-Dialog {
2065- id: errorDialog
2066- title: i18n.tr("Error")
2067- text: i18n.tr("File does not exist")
2068-
2069- Button {
2070- text: i18n.tr("Close")
2071- color: UbuntuColors.red
2072-
2073- onClicked: Qt.quit();
2074- }
2075-}
2076
2077=== removed file 'src/app/qml/ImageView.qml'
2078--- src/app/qml/ImageView.qml 2015-02-03 21:11:52 +0000
2079+++ src/app/qml/ImageView.qml 1970-01-01 00:00:00 +0000
2080@@ -1,48 +0,0 @@
2081-/*
2082- * Copyright (C) 2013-2015 Canonical, Ltd.
2083- *
2084- * This program is free software; you can redistribute it and/or modify
2085- * it under the terms of the GNU General Public License as published by
2086- * the Free Software Foundation; version 3.
2087- *
2088- * This program is distributed in the hope that it will be useful,
2089- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2090- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2091- * GNU General Public License for more details.
2092- *
2093- * You should have received a copy of the GNU General Public License
2094- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2095- */
2096-
2097-import QtQuick 2.3
2098-import Ubuntu.Components 1.1
2099-
2100-import "utils.js" as Utils
2101-
2102-Page {
2103- id: imagePage
2104- title: Utils.getNameOfFile(file.path);
2105-
2106- Rectangle {
2107- anchors.fill: parent
2108- color: "#221E1C" // SuruDark.Palette.Normal.Background
2109- }
2110-
2111- ZoomableImage {
2112- id: zoomableImage
2113- anchors.fill: parent
2114-
2115- zoomable: true
2116- source: file.path
2117- }
2118-
2119- // *** HEADER ***
2120- state: "default"
2121- states: [
2122- ImageViewDefaultHeader {
2123- name: "default"
2124- targetPage: imagePage
2125- activityRunning: zoomableImage.imageStatus == Image.Loading
2126- }
2127- ]
2128-}
2129
2130=== removed file 'src/app/qml/ImageViewDefaultHeader.qml'
2131--- src/app/qml/ImageViewDefaultHeader.qml 2015-02-03 21:11:52 +0000
2132+++ src/app/qml/ImageViewDefaultHeader.qml 1970-01-01 00:00:00 +0000
2133@@ -1,74 +0,0 @@
2134-/*
2135- * Copyright (C) 2014-2015 Canonical, Ltd.
2136- *
2137- * This program is free software; you can redistribute it and/or modify
2138- * it under the terms of the GNU General Public License as published by
2139- * the Free Software Foundation; version 3.
2140- *
2141- * This program is distributed in the hope that it will be useful,
2142- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2143- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2144- * GNU General Public License for more details.
2145- *
2146- * You should have received a copy of the GNU General Public License
2147- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2148- */
2149-
2150-import QtQuick 2.3
2151-import Ubuntu.Components 1.1
2152-import QtQuick.Layouts 1.1
2153-import Ubuntu.Components.Popups 1.0
2154-
2155-PageHeadState {
2156- id: rootItem
2157-
2158- property Page targetPage
2159- property alias activityRunning: activity.running
2160-
2161- head: targetPage.head
2162-
2163- contents: RowLayout {
2164- anchors.fill: parent
2165- spacing: units.gu(1)
2166-
2167- ActivityIndicator { id: activity }
2168-
2169- Column {
2170- id: layout
2171- Layout.fillWidth: true
2172-
2173- Label {
2174- width: parent.width
2175- //horizontalAlignment: Text.AlignHCenter
2176- elide: Text.ElideMiddle
2177-
2178- font.weight: Font.DemiBold
2179- text: targetPage.title
2180- }
2181- }
2182- }
2183-
2184- backAction: Action {
2185- iconName: "back"
2186- text: (pageStack.depth > 1) ? i18n.tr("Back") : i18n.tr("Close")
2187- onTriggered: {
2188- if (pageStack.depth > 1) {
2189- // Go back to Welcome page
2190- pageStack.pop();
2191- } else {
2192- // File has been imported through Content Hub (or was not chosen through WelcomePage)
2193- // Close the application and show our source app (e.g. ubuntu-filemanager-app, if used to open a document)
2194- Qt.quit()
2195- }
2196- }
2197- }
2198-
2199- actions: [
2200- Action {
2201- objectName: "detailsAction"
2202- text: i18n.tr("Details")
2203- iconName: "info"
2204- onTriggered: pageStack.push(Qt.resolvedUrl("DetailsPage.qml"))
2205- }
2206- ]
2207-}
2208
2209=== removed file 'src/app/qml/PageWithBottomEdge.qml'
2210--- src/app/qml/PageWithBottomEdge.qml 2015-02-04 19:19:21 +0000
2211+++ src/app/qml/PageWithBottomEdge.qml 1970-01-01 00:00:00 +0000
2212@@ -1,407 +0,0 @@
2213-/*
2214- * Copyright (C) 2014 Canonical, Ltd.
2215- *
2216- * This program is free software; you can redistribute it and/or modify
2217- * it under the terms of the GNU General Public License as published by
2218- * the Free Software Foundation; version 3.
2219- *
2220- * This program is distributed in the hope that it will be useful,
2221- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2222- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2223- * GNU General Public License for more details.
2224- *
2225- * You should have received a copy of the GNU General Public License
2226- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2227- */
2228-
2229-/*
2230- Example:
2231-
2232- MainView {
2233- objectName: "mainView"
2234-
2235- applicationName: "com.ubuntu.developer.boiko.bottomedge"
2236-
2237- width: units.gu(100)
2238- height: units.gu(75)
2239-
2240- Component {
2241- id: pageComponent
2242-
2243- PageWithBottomEdge {
2244- id: mainPage
2245- title: i18n.tr("Main Page")
2246-
2247- Rectangle {
2248- anchors.fill: parent
2249- color: "white"
2250- }
2251-
2252- bottomEdgePageComponent: Page {
2253- title: "Contents"
2254- anchors.fill: parent
2255- //anchors.topMargin: contentsPage.flickable.contentY
2256-
2257- ListView {
2258- anchors.fill: parent
2259- model: 50
2260- delegate: ListItems.Standard {
2261- text: "One Content Item: " + index
2262- }
2263- }
2264- }
2265- bottomEdgeTitle: i18n.tr("Bottom edge action")
2266- }
2267- }
2268-
2269- PageStack {
2270- id: stack
2271- Component.onCompleted: stack.push(pageComponent)
2272- }
2273- }
2274-
2275-*/
2276-
2277-import QtQuick 2.2
2278-import Ubuntu.Components 1.1
2279-
2280-Page {
2281- id: page
2282-
2283- property alias bottomEdgePageComponent: edgeLoader.sourceComponent
2284- property alias bottomEdgePageSource: edgeLoader.source
2285- property alias bottomEdgeTitle: tipLabel.text
2286- property bool bottomEdgeEnabled: true
2287- property int bottomEdgeExpandThreshold: page.height * 0.2
2288- property int bottomEdgeExposedArea: bottomEdge.state !== "expanded" ? (page.height - bottomEdge.y - bottomEdge.tipHeight) : _areaWhenExpanded
2289- property bool reloadBottomEdgePage: true
2290-
2291- readonly property alias bottomEdgePage: edgeLoader.item
2292- readonly property bool isReady: ((bottomEdge.y === 0) && bottomEdgePageLoaded && edgeLoader.item.active)
2293- readonly property bool isCollapsed: (bottomEdge.y === page.height)
2294- readonly property bool bottomEdgePageLoaded: (edgeLoader.status == Loader.Ready)
2295-
2296- property bool _showEdgePageWhenReady: false
2297- property int _areaWhenExpanded: 0
2298-
2299- signal bottomEdgeReleased()
2300- signal bottomEdgeDismissed()
2301-
2302-
2303- function showBottomEdgePage(source, properties)
2304- {
2305- edgeLoader.setSource(source, properties)
2306- _showEdgePageWhenReady = true
2307- }
2308-
2309- function setBottomEdgePage(source, properties)
2310- {
2311- edgeLoader.setSource(source, properties)
2312- }
2313-
2314- function _pushPage()
2315- {
2316- if (edgeLoader.status === Loader.Ready) {
2317- edgeLoader.item.active = true
2318- page.pageStack.push(edgeLoader.item)
2319- if (edgeLoader.item.flickable) {
2320- edgeLoader.item.flickable.contentY = -page.header.height
2321- edgeLoader.item.flickable.returnToBounds()
2322- }
2323- if (edgeLoader.item.ready)
2324- edgeLoader.item.ready()
2325- }
2326- }
2327-
2328-
2329- Component.onCompleted: {
2330- // avoid a binding on the expanded height value
2331- var expandedHeight = height;
2332- _areaWhenExpanded = expandedHeight;
2333- }
2334-
2335- onActiveChanged: {
2336- if (active) {
2337- bottomEdge.state = "collapsed"
2338- }
2339- }
2340-
2341- onBottomEdgePageLoadedChanged: {
2342- if (_showEdgePageWhenReady && bottomEdgePageLoaded) {
2343- bottomEdge.state = "expanded"
2344- _showEdgePageWhenReady = false
2345- }
2346- }
2347-
2348- Rectangle {
2349- id: bgVisual
2350-
2351- color: "black"
2352- anchors.fill: page
2353- opacity: 0.7 * ((page.height - bottomEdge.y) / page.height)
2354- z: 1
2355- }
2356-
2357- UbuntuShape {
2358- id: tip
2359- objectName: "bottomEdgeTip"
2360-
2361- property bool hidden: (activeFocus === false) || ((bottomEdge.y - units.gu(1)) < tip.y)
2362-
2363- enabled: mouseArea.enabled
2364- visible: page.bottomEdgeEnabled
2365- anchors {
2366- bottom: parent.bottom
2367- horizontalCenter: bottomEdge.horizontalCenter
2368- bottomMargin: hidden ? - height + units.gu(1) : -units.gu(1)
2369- Behavior on bottomMargin {
2370- SequentialAnimation {
2371- // wait some msecs in case of the focus change again, to avoid flickering
2372- PauseAnimation {
2373- duration: 300
2374- }
2375- UbuntuNumberAnimation {
2376- duration: UbuntuAnimation.SnapDuration
2377- }
2378- }
2379- }
2380- }
2381-
2382- z: 1
2383- width: tipLabel.paintedWidth + units.gu(6)
2384- height: bottomEdge.tipHeight + units.gu(1)
2385- color: Theme.palette.normal.overlay
2386- Label {
2387- id: tipLabel
2388-
2389- anchors {
2390- top: parent.top
2391- left: parent.left
2392- right: parent.right
2393- }
2394- height: bottomEdge.tipHeight
2395- verticalAlignment: Text.AlignVCenter
2396- horizontalAlignment: Text.AlignHCenter
2397- opacity: tip.hidden ? 0.0 : 1.0
2398- Behavior on opacity {
2399- UbuntuNumberAnimation {
2400- duration: UbuntuAnimation.SnapDuration
2401- }
2402- }
2403- }
2404- }
2405-
2406- Rectangle {
2407- id: shadow
2408-
2409- anchors {
2410- left: parent.left
2411- right: parent.right
2412- bottom: parent.bottom
2413- }
2414- height: units.gu(1)
2415- z: 1
2416- opacity: 0.0
2417- gradient: Gradient {
2418- GradientStop { position: 0.0; color: "transparent" }
2419- GradientStop { position: 1.0; color: Qt.rgba(0, 0, 0, 0.2) }
2420- }
2421- }
2422-
2423- MouseArea {
2424- id: mouseArea
2425-
2426- property real previousY: -1
2427- property string dragDirection: "None"
2428-
2429- preventStealing: true
2430- drag {
2431- axis: Drag.YAxis
2432- target: bottomEdge
2433- minimumY: bottomEdge.pageStartY
2434- maximumY: page.height
2435- }
2436- enabled: edgeLoader.status == Loader.Ready
2437- visible: page.bottomEdgeEnabled
2438-
2439- anchors {
2440- left: parent.left
2441- right: parent.right
2442- bottom: parent.bottom
2443-
2444- }
2445- height: bottomEdge.tipHeight
2446- z: 1
2447-
2448- onReleased: {
2449- page.bottomEdgeReleased()
2450- if ((dragDirection === "BottomToTop") &&
2451- bottomEdge.y < (page.height - bottomEdgeExpandThreshold - bottomEdge.tipHeight)) {
2452- bottomEdge.state = "expanded"
2453- } else {
2454- bottomEdge.state = "collapsed"
2455- }
2456- previousY = -1
2457- dragDirection = "None"
2458- }
2459-
2460- onPressed: {
2461- previousY = mouse.y
2462- tip.forceActiveFocus()
2463- }
2464-
2465- onMouseYChanged: {
2466- var yOffset = previousY - mouseY
2467- // skip if was a small move
2468- if (Math.abs(yOffset) <= units.gu(2)) {
2469- return
2470- }
2471- previousY = mouseY
2472- dragDirection = yOffset > 0 ? "BottomToTop" : "TopToBottom"
2473- }
2474- }
2475-
2476- Rectangle {
2477- id: bottomEdge
2478- objectName: "bottomEdge"
2479-
2480- readonly property int tipHeight: units.gu(3)
2481- readonly property int pageStartY: 0
2482-
2483- z: 1
2484- color: Theme.palette.normal.background
2485- clip: true
2486- anchors {
2487- left: parent.left
2488- right: parent.right
2489- }
2490- height: page.height
2491- y: height
2492- visible: !page.isCollapsed
2493- state: "collapsed"
2494- states: [
2495- State {
2496- name: "collapsed"
2497- PropertyChanges {
2498- target: bottomEdge
2499- y: bottomEdge.height
2500- }
2501- },
2502- State {
2503- name: "expanded"
2504- PropertyChanges {
2505- target: bottomEdge
2506- y: bottomEdge.pageStartY
2507- }
2508- },
2509- State {
2510- name: "floating"
2511- when: mouseArea.drag.active
2512- PropertyChanges {
2513- target: shadow
2514- opacity: 1.0
2515- }
2516- }
2517- ]
2518-
2519- transitions: [
2520- Transition {
2521- to: "expanded"
2522- SequentialAnimation {
2523- alwaysRunToEnd: true
2524-
2525- SmoothedAnimation {
2526- target: bottomEdge
2527- property: "y"
2528- duration: UbuntuAnimation.FastDuration
2529- easing.type: Easing.Linear
2530- }
2531- SmoothedAnimation {
2532- target: edgeLoader
2533- property: "anchors.topMargin"
2534- to: - units.gu(4)
2535- duration: UbuntuAnimation.FastDuration
2536- easing.type: Easing.Linear
2537- }
2538- SmoothedAnimation {
2539- target: edgeLoader
2540- property: "anchors.topMargin"
2541- to: 0
2542- duration: UbuntuAnimation.FastDuration
2543- easing: UbuntuAnimation.StandardEasing
2544- }
2545- ScriptAction {
2546- script: page._pushPage()
2547- }
2548- }
2549- },
2550- Transition {
2551- from: "expanded"
2552- to: "collapsed"
2553- SequentialAnimation {
2554- alwaysRunToEnd: true
2555-
2556- ScriptAction {
2557- script: {
2558- Qt.inputMethod.hide()
2559- edgeLoader.item.parent = edgeLoader
2560- edgeLoader.item.anchors.fill = edgeLoader
2561- edgeLoader.item.active = false
2562- }
2563- }
2564- SmoothedAnimation {
2565- target: bottomEdge
2566- property: "y"
2567- duration: UbuntuAnimation.SlowDuration
2568- }
2569- ScriptAction {
2570- script: {
2571- // destroy current bottom page
2572- if (page.reloadBottomEdgePage) {
2573- edgeLoader.active = false
2574- // tip will receive focus on page active true
2575- } else {
2576- tip.forceActiveFocus()
2577- }
2578-
2579- // notify
2580- page.bottomEdgeDismissed()
2581-
2582- edgeLoader.active = true
2583- }
2584- }
2585- }
2586- },
2587- Transition {
2588- from: "floating"
2589- to: "collapsed"
2590- SmoothedAnimation {
2591- target: bottomEdge
2592- property: "y"
2593- duration: UbuntuAnimation.FastDuration
2594- }
2595- }
2596- ]
2597-
2598- Loader {
2599- id: edgeLoader
2600-
2601- asynchronous: true
2602- anchors.fill: parent
2603- //WORKAROUND: The SDK move the page contents down to allocate space for the header we need to avoid that during the page dragging
2604- Binding {
2605- target: edgeLoader.status === Loader.Ready ? edgeLoader : null
2606- property: "anchors.topMargin"
2607- value: edgeLoader.item && edgeLoader.item.flickable ? edgeLoader.item.flickable.contentY : 0
2608- when: !page.isReady
2609- }
2610-
2611- onLoaded: {
2612- tip.forceActiveFocus()
2613- if (page.isReady && edgeLoader.item.active !== true) {
2614- page._pushPage()
2615- }
2616- }
2617- }
2618- }
2619-}
2620
2621=== removed file 'src/app/qml/PdfContentsPage.qml'
2622--- src/app/qml/PdfContentsPage.qml 2015-02-05 16:40:16 +0000
2623+++ src/app/qml/PdfContentsPage.qml 1970-01-01 00:00:00 +0000
2624@@ -1,60 +0,0 @@
2625-/*
2626- * Copyright (C) 2014, 2015
2627- * Stefano Verzegnassi <verzegnassi.stefano@gmail.com>
2628- *
2629- * This program is free software; you can redistribute it and/or modify
2630- * it under the terms of the GNU General Public License as published by
2631- * the Free Software Foundation; version 3.
2632- *
2633- * This program is distributed in the hope that it will be useful,
2634- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2635- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2636- * GNU General Public License for more details.
2637- *
2638- * You should have received a copy of the GNU General Public License
2639- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2640- */
2641-
2642-import QtQuick 2.0
2643-import Ubuntu.Components 1.1
2644-import QtQuick.Layouts 1.1
2645-import Ubuntu.Components.ListItems 1.0 as ListItem
2646-
2647-Page {
2648- title: i18n.tr("Contents")
2649-
2650- ListView {
2651- anchors.fill: parent
2652-
2653- model: poppler.tocModel
2654-
2655- delegate: ListItem.Base {
2656- showDivider: model.level == 0
2657-
2658- onClicked: {
2659- pdfView.positionAtIndex(model.pageIndex);
2660- pageStack.pop();
2661- }
2662-
2663- RowLayout {
2664- anchors.fill: parent
2665- anchors.leftMargin: units.gu(2) * model.level
2666-
2667- spacing: units.gu(1)
2668-
2669- Label {
2670- Layout.fillWidth: true
2671-
2672- text: (typeof model.title === "undefined") ? "" : model.title;
2673- elide: Text.ElideRight
2674- Component.onCompleted: { if (model.level === 0); font.weight = Font.DemiBold; }
2675- }
2676-
2677- Label {
2678- text: (typeof model.pageIndex === "undefined") ? "" : model.pageIndex + 1;
2679- Component.onCompleted: { if (model.level === 0); font.weight = Font.DemiBold; }
2680- }
2681- }
2682- }
2683- }
2684-}
2685
2686=== removed file 'src/app/qml/PdfView.qml'
2687--- src/app/qml/PdfView.qml 2015-02-09 12:00:58 +0000
2688+++ src/app/qml/PdfView.qml 1970-01-01 00:00:00 +0000
2689@@ -1,107 +0,0 @@
2690-/*
2691- * Copyright (C) 2013-2014 Canonical, Ltd.
2692- *
2693- * This program is free software; you can redistribute it and/or modify
2694- * it under the terms of the GNU General Public License as published by
2695- * the Free Software Foundation; version 3.
2696- *
2697- * This program is distributed in the hope that it will be useful,
2698- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2699- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2700- * GNU General Public License for more details.
2701- *
2702- * You should have received a copy of the GNU General Public License
2703- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2704- */
2705-
2706-import QtQuick 2.3
2707-import Ubuntu.Components 1.1
2708-import com.ubuntu.popplerqmlplugin 1.0 as PDF
2709-
2710-import "utils.js" as Utils
2711-
2712-PageWithBottomEdge {
2713- id: pdfPage
2714- title: Utils.getNameOfFile(file.path);
2715-
2716- // Disable header auto-hide.
2717- // TODO: Show/hide header if a user taps the page
2718- flickable: null
2719-
2720- property string currentPage: i18n.tr("Page %1 of %2").arg(pdfView.currentPageIndex + 1).arg(pdfView.count)
2721-
2722- bottomEdgeTitle: i18n.tr("Contents")
2723- bottomEdgePageComponent: PdfContentsPage {}
2724- bottomEdgeEnabled: poppler.tocModel.count > 0
2725-
2726- PDF.VerticalView {
2727- id: pdfView
2728- objectName: "pdfView"
2729- anchors.fill: parent
2730- spacing: units.gu(2)
2731-
2732- clip: true
2733- boundsBehavior: Flickable.StopAtBounds
2734- flickDeceleration: 1500 * units.gridUnit / 8
2735- maximumFlickVelocity: 2500 * units.gridUnit / 8
2736-
2737- contentWidth: parent.width * _zoomHelper.scale
2738- cacheBuffer: height * poppler.providersNumber * _zoomHelper.scale * 0.5
2739- interactive: !pinchy.pinch.active
2740-
2741- model: poppler
2742- delegate: PdfViewDelegate {
2743- Component.onDestruction: QQuickView.releaseResources()
2744- }
2745-
2746- // FIXME: On zooming, keep the same content position.
2747- PinchArea {
2748- id: pinchy
2749- anchors.fill: parent
2750-
2751- pinch {
2752- target: _zoomHelper
2753- minimumScale: 1.0
2754- maximumScale: 2.5
2755- }
2756-
2757- onPinchFinished: {
2758- pdfView.returnToBounds();
2759-
2760- // This is a bit expensive, so it's safer to put it here.
2761- // It won't be called on desktop (where PinchArea is not used),
2762- // but it's not a problem at the moment (our target is phone).
2763- QQuickView.releaseResources();
2764- }
2765- }
2766-
2767- Item { id: _zoomHelper }
2768- }
2769-
2770- Scrollbar { flickableItem: pdfView }
2771- Scrollbar { flickableItem: pdfView; align: Qt.AlignBottom }
2772-
2773- PDF.Document {
2774- id: poppler
2775-
2776- property bool isLoading: true
2777-
2778- Component.onCompleted: path = file.path
2779- onPagesLoaded: {
2780- isLoading = false;
2781-
2782- var title = getDocumentInfo("Title")
2783- if (title !== "")
2784- pdfPage.title = title
2785- }
2786- }
2787-
2788-
2789- // *** HEADER ***
2790- state: "default"
2791- states: PdfViewDefaultHeader {
2792- name: "default"
2793- targetPage: pdfPage
2794- activityRunning: pdfView.currentPageItem.status == Image.Loading || poppler.isLoading
2795- }
2796-}
2797
2798=== removed file 'src/app/qml/PdfViewDefaultHeader.qml'
2799--- src/app/qml/PdfViewDefaultHeader.qml 2015-02-03 21:11:52 +0000
2800+++ src/app/qml/PdfViewDefaultHeader.qml 1970-01-01 00:00:00 +0000
2801@@ -1,96 +0,0 @@
2802-/*
2803- * Copyright (C) 2014-2015 Canonical, Ltd.
2804- *
2805- * This program is free software; you can redistribute it and/or modify
2806- * it under the terms of the GNU General Public License as published by
2807- * the Free Software Foundation; version 3.
2808- *
2809- * This program is distributed in the hope that it will be useful,
2810- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2811- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2812- * GNU General Public License for more details.
2813- *
2814- * You should have received a copy of the GNU General Public License
2815- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2816- */
2817-
2818-import QtQuick 2.3
2819-import Ubuntu.Components 1.1
2820-import QtQuick.Layouts 1.1
2821-import Ubuntu.Components.Popups 1.0
2822-
2823-PageHeadState {
2824- id: rootItem
2825-
2826- property Page targetPage
2827- property alias activityRunning: activity.running
2828-
2829- head: targetPage.head
2830-
2831- contents: RowLayout {
2832- anchors.fill: parent
2833- spacing: units.gu(1)
2834-
2835- ActivityIndicator { id: activity }
2836-
2837- Column {
2838- id: layout
2839- Layout.fillWidth: true
2840-
2841- Label {
2842- width: parent.width
2843- //horizontalAlignment: Text.AlignHCenter
2844- elide: Text.ElideMiddle
2845-
2846- font.weight: Font.DemiBold
2847- text: targetPage.title
2848- }
2849- Label {
2850- width: parent.width
2851- //horizontalAlignment: Text.AlignHCenter
2852- elide: Text.ElideMiddle
2853-
2854- fontSize: "small"
2855- text: targetPage.currentPage
2856- }
2857- }
2858- }
2859-
2860- backAction: Action {
2861- iconName: "back"
2862- text: (pageStack.depth > 1) ? i18n.tr("Back") : i18n.tr("Close")
2863- onTriggered: {
2864- if (pageStack.depth > 1) {
2865- // Go back to Welcome page
2866- pageStack.pop();
2867- } else {
2868- // File has been imported through Content Hub (or was not chosen through WelcomePage)
2869- // Close the application and show our source app (e.g. ubuntu-filemanager-app, if used to open a document)
2870- Qt.quit()
2871- }
2872- }
2873- }
2874-
2875- actions: [
2876- Action {
2877- iconName: "search"
2878- // onTriggered: pageMain.state = "search"
2879- //Disable it until we provide search in Poppler plugin.
2880- enabled: false
2881- },
2882-
2883- Action {
2884- objectName:"gotopage"
2885- iconName: "browser-tabs"
2886- text: "Go to page..."
2887- onTriggered: PopupUtils.open(Qt.resolvedUrl("PdfViewGotoDialog.qml"), targetPage)
2888- },
2889-
2890- Action {
2891- objectName: "detailsAction"
2892- text: i18n.tr("Details")
2893- iconName: "info"
2894- onTriggered: pageStack.push(Qt.resolvedUrl("DetailsPage.qml"))
2895- }
2896- ]
2897-}
2898
2899=== removed file 'src/app/qml/PdfViewDelegate.qml'
2900--- src/app/qml/PdfViewDelegate.qml 2015-02-03 21:05:26 +0000
2901+++ src/app/qml/PdfViewDelegate.qml 1970-01-01 00:00:00 +0000
2902@@ -1,95 +0,0 @@
2903-/*
2904- * Copyright (C) 2013-2015 Canonical, Ltd.
2905- *
2906- * This program is free software; you can redistribute it and/or modify
2907- * it under the terms of the GNU General Public License as published by
2908- * the Free Software Foundation; version 3.
2909- *
2910- * This program is distributed in the hope that it will be useful,
2911- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2912- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2913- * GNU General Public License for more details.
2914- *
2915- * You should have received a copy of the GNU General Public License
2916- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2917- */
2918-import QtQuick 2.3
2919-import Ubuntu.Components 1.1
2920-
2921-Rectangle {
2922- id: pdfPage
2923-
2924- property int index: model.index
2925- property bool _previewFetched: false
2926-
2927- property alias status: pageImg.status
2928-
2929- width: parent.width
2930- height: width * (model.height / model.width)
2931- color: "#E6E6E6"
2932-
2933- // Preview page rendering. Used as placeholder while zooming the page.
2934- // We generate the low resolution preview from the texture of the PDF page,
2935- // so that we can keep page rendering as fast as possible.
2936- ShaderEffectSource {
2937- id: previewImg
2938- anchors.fill: parent
2939-
2940- // We cannot change its opacity or visibility, otherwise the texture will be refreshed,
2941- // even if live is false.
2942- live: false
2943- textureSize: Qt.size(256, 256 * (model.height / model.width))
2944- }
2945-
2946- Image {
2947- id: pageImg
2948- anchors.fill: parent
2949-
2950- source: "image://poppler" + (index % poppler.providersNumber) + "/page/" + index;
2951- sourceSize.width: pdfPage.width
2952-
2953- onStatusChanged: {
2954- // This is supposed to run the first time PdfViewDelegate gets the page rendering.
2955- if (!_previewFetched) {
2956- if (status == Image.Ready) {
2957- previewImg.sourceItem = pageImg
2958- // Re-assign sourceItem property, so the texture is not updated when Image status changes.
2959- previewImg.sourceItem = pdfPage
2960- }
2961- }
2962- }
2963-
2964- // Request a new page rendering. The order, which pages are requested with, depends on the distance from the currentPage
2965- Timer {
2966- id: _zoomTimer
2967- interval: {
2968- var diff = Math.abs(pdfView.currentPageIndex - model.index)
2969- var prov = poppler.providersNumber * 0.5
2970-
2971- if (diff < prov)
2972- return 0
2973- else
2974- return (diff - prov) * 10
2975- }
2976-
2977- onTriggered: {
2978- pageImg.sourceSize.width = pdfPage.width;
2979- }
2980- }
2981- }
2982-
2983- // Page rendering depends on the width of PdfViewDelegate.
2984- // Because of this, we have multiple callings to ImageProvider while zooming.
2985- // Just avoid it.
2986- Connections {
2987- target: pinchy
2988-
2989- onPinchStarted: _zoomTimer.stop();
2990- onPinchUpdated: {
2991- // This ensures that page image is not reloaded when the maximumScale or minimumScale has already been reached.
2992- if ( !(_zoomHelper.scale >= 2.5 && pinch.scale > 1.0) && !(_zoomHelper.scale <= 1.0 && pinch.scale < 1.0) )
2993- pageImg.sourceSize.width = 0;
2994- }
2995- onPinchFinished: _zoomTimer.restart();
2996- }
2997-}
2998
2999=== removed file 'src/app/qml/PdfViewGotoDialog.qml'
3000--- src/app/qml/PdfViewGotoDialog.qml 2015-01-30 19:37:00 +0000
3001+++ src/app/qml/PdfViewGotoDialog.qml 1970-01-01 00:00:00 +0000
3002@@ -1,60 +0,0 @@
3003-/*
3004- * Copyright (C) 2014-2015 Canonical, Ltd.
3005- *
3006- * This program is free software; you can redistribute it and/or modify
3007- * it under the terms of the GNU General Public License as published by
3008- * the Free Software Foundation; version 3.
3009- *
3010- * This program is distributed in the hope that it will be useful,
3011- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3012- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3013- * GNU General Public License for more details.
3014- *
3015- * You should have received a copy of the GNU General Public License
3016- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3017- */
3018-
3019-import QtQuick 2.3
3020-import Ubuntu.Components 1.1
3021-import Ubuntu.Components.Popups 1.0
3022-
3023-Dialog {
3024- id: goToPageDialog
3025- objectName:"PdfViewGotoDialog"
3026-
3027- title: i18n.tr("Go to page")
3028- text: i18n.tr("Choose a page between 1 and %1").arg(pdfView.count)
3029-
3030- TextField {
3031- id: goToPageTextField
3032- objectName:"goToPageTextField"
3033-
3034- width: parent.width
3035-
3036- hasClearButton: true
3037- inputMethodHints: Qt.ImhFormattedNumbersOnly
3038- validator: IntValidator{ bottom: 1; top: pdfView.count }
3039-
3040- Keys.onReturnPressed: goToPage()
3041- Component.onCompleted: forceActiveFocus()
3042- }
3043-
3044- Button {
3045- objectName:"GOButton"
3046- text: i18n.tr("GO!")
3047- color: UbuntuColors.orange
3048-
3049- enabled: goToPageTextField.acceptableInput
3050- onClicked: goToPage()
3051- }
3052-
3053- Button {
3054- text: i18n.tr("Cancel")
3055- onClicked: PopupUtils.close(goToPageDialog)
3056- }
3057-
3058- function goToPage() {
3059- pdfView.positionAtIndex((goToPageTextField.text - 1))
3060- PopupUtils.close(goToPageDialog)
3061- }
3062-}
3063
3064=== removed file 'src/app/qml/TextView.qml'
3065--- src/app/qml/TextView.qml 2015-01-30 19:44:52 +0000
3066+++ src/app/qml/TextView.qml 1970-01-01 00:00:00 +0000
3067@@ -1,70 +0,0 @@
3068-/*
3069- * Copyright (C) 2013-2015 Canonical, Ltd.
3070- *
3071- * This program is free software; you can redistribute it and/or modify
3072- * it under the terms of the GNU General Public License as published by
3073- * the Free Software Foundation; version 3.
3074- *
3075- * This program is distributed in the hope that it will be useful,
3076- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3077- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3078- * GNU General Public License for more details.
3079- *
3080- * You should have received a copy of the GNU General Public License
3081- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3082- */
3083-
3084-import QtQuick 2.3
3085-import Ubuntu.Components 1.1
3086-import Ubuntu.Components.Themes.Ambiance 0.1
3087-
3088-import "utils.js" as Utils
3089-
3090-Page {
3091- id: textPage
3092- title: Utils.getNameOfFile(file.path);
3093-
3094- TextArea {
3095- id: textAreaMain
3096- objectName: "textAreaMain"
3097-
3098- property bool isLoading: true
3099-
3100- anchors.fill: parent
3101-
3102- // FIXME: If set to true, some of the keyboard hooks are disabled
3103- // And it's not possible to move the cursor with arrow keys.
3104- readOnly: true
3105-
3106- text: i18n.tr("Loading...")
3107- font.family: "UbuntuMono"
3108-
3109- Component.onCompleted: {
3110- var xhr = new XMLHttpRequest;
3111-
3112- xhr.open("GET", file.path);
3113- xhr.onreadystatechange = function() {
3114- if (xhr.readyState === XMLHttpRequest.DONE) {
3115- textAreaMain.text = xhr.responseText;
3116- textAreaMain.isLoading = false
3117- }
3118- };
3119-
3120- xhr.send();
3121- }
3122-
3123- style: TextAreaStyle {
3124- background: Rectangle { color: "white" }
3125- }
3126- }
3127-
3128- // *** HEADER ***
3129- state: "default"
3130- states: [
3131- TextViewDefaultHeader {
3132- name: "default"
3133- targetPage: textPage
3134- activityRunning: textAreaMain.isLoading
3135- }
3136- ]
3137-}
3138
3139=== removed file 'src/app/qml/TextViewDefaultHeader.qml'
3140--- src/app/qml/TextViewDefaultHeader.qml 2015-02-03 21:11:52 +0000
3141+++ src/app/qml/TextViewDefaultHeader.qml 1970-01-01 00:00:00 +0000
3142@@ -1,82 +0,0 @@
3143-/*
3144- * Copyright (C) 2014-2015 Canonical, Ltd.
3145- *
3146- * This program is free software; you can redistribute it and/or modify
3147- * it under the terms of the GNU General Public License as published by
3148- * the Free Software Foundation; version 3.
3149- *
3150- * This program is distributed in the hope that it will be useful,
3151- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3152- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3153- * GNU General Public License for more details.
3154- *
3155- * You should have received a copy of the GNU General Public License
3156- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3157- */
3158-
3159-import QtQuick 2.3
3160-import Ubuntu.Components 1.1
3161-import QtQuick.Layouts 1.1
3162-import Ubuntu.Components.Popups 1.0
3163-
3164-PageHeadState {
3165- id: rootItem
3166-
3167- property Page targetPage
3168- property alias activityRunning: activity.running
3169-
3170- head: targetPage.head
3171-
3172- contents: RowLayout {
3173- anchors.fill: parent
3174- spacing: units.gu(1)
3175-
3176- ActivityIndicator { id: activity }
3177-
3178- Column {
3179- id: layout
3180- Layout.fillWidth: true
3181-
3182- Label {
3183- width: parent.width
3184- //horizontalAlignment: Text.AlignHCenter
3185- elide: Text.ElideMiddle
3186-
3187- font.weight: Font.DemiBold
3188- text: targetPage.title
3189- }
3190- Label {
3191- width: parent.width
3192- //horizontalAlignment: Text.AlignHCenter
3193- elide: Text.ElideMiddle
3194-
3195- fontSize: "small"
3196- text: file.description
3197- }
3198- }
3199- }
3200-
3201- backAction: Action {
3202- iconName: "back"
3203- text: (pageStack.depth > 1) ? i18n.tr("Back") : i18n.tr("Close")
3204- onTriggered: {
3205- if (pageStack.depth > 1) {
3206- // Go back to Welcome page
3207- pageStack.pop();
3208- } else {
3209- // File has been imported through Content Hub (or was not chosen through WelcomePage)
3210- // Close the application and show our source app (e.g. ubuntu-filemanager-app, if used to open a document)
3211- Qt.quit()
3212- }
3213- }
3214- }
3215-
3216- actions: [
3217- Action {
3218- objectName: "detailsAction"
3219- text: i18n.tr("Details")
3220- iconName: "info"
3221- onTriggered: pageStack.push(Qt.resolvedUrl("DetailsPage.qml"))
3222- }
3223- ]
3224-}
3225
3226=== removed file 'src/app/qml/UnknownTypeDialog.qml'
3227--- src/app/qml/UnknownTypeDialog.qml 2015-01-29 18:09:26 +0000
3228+++ src/app/qml/UnknownTypeDialog.qml 1970-01-01 00:00:00 +0000
3229@@ -1,43 +0,0 @@
3230-/*
3231- * Copyright (C) 2013-2015 Canonical, Ltd.
3232- *
3233- * This program is free software; you can redistribute it and/or modify
3234- * it under the terms of the GNU General Public License as published by
3235- * the Free Software Foundation; version 3.
3236- *
3237- * This program is distributed in the hope that it will be useful,
3238- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3239- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3240- * GNU General Public License for more details.
3241- *
3242- * You should have received a copy of the GNU General Public License
3243- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3244- */
3245-
3246-import QtQuick 2.3
3247-import Ubuntu.Components 1.1
3248-import Ubuntu.Components.Popups 1.0
3249-
3250-import "loadComponent.js" as LoadComponent
3251-
3252-Dialog {
3253- id: unknownDialog
3254- objectName: "unknownDialog"
3255- title: i18n.tr("Unknown file type")
3256- 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?")
3257- Button {
3258- text: i18n.tr("Yes")
3259- color: UbuntuColors.green
3260-
3261- onClicked: {
3262- LoadComponent.load("text/plain");
3263- PopupUtils.close(unknownDialog)
3264- }
3265- }
3266- Button {
3267- text: i18n.tr("No")
3268- color: UbuntuColors.red
3269- onClicked: PopupUtils.close(unknownDialog)
3270- }
3271-}
3272-
3273
3274=== removed file 'src/app/qml/WelcomePage.qml'
3275--- src/app/qml/WelcomePage.qml 2015-01-29 16:24:50 +0000
3276+++ src/app/qml/WelcomePage.qml 1970-01-01 00:00:00 +0000
3277@@ -1,42 +0,0 @@
3278-/*
3279- * Copyright (C) 2015 Canonical, Ltd.
3280- *
3281- * This program is free software; you can redistribute it and/or modify
3282- * it under the terms of the GNU General Public License as published by
3283- * the Free Software Foundation; version 3.
3284- *
3285- * This program is distributed in the hope that it will be useful,
3286- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3287- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3288- * GNU General Public License for more details.
3289- *
3290- * You should have received a copy of the GNU General Public License
3291- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3292- */
3293-
3294-import QtQuick 2.0
3295-import Ubuntu.Components 1.1
3296-
3297-Page {
3298- id: welcomePage
3299-
3300- title: i18n.tr("Document Viewer")
3301- head.actions: [ openAction ]
3302-
3303- EmptyState {
3304- title: i18n.tr("No opened documents")
3305- subTitle: i18n.tr("Tap the + icon to open a document")
3306-
3307- iconName: "edit-copy"
3308-
3309- anchors.centerIn: parent
3310- }
3311-
3312- Action {
3313- id: openAction
3314- text: i18n.tr("Open a file...")
3315- iconName: "add"
3316-
3317- onTriggered: pageStack.push(Qt.resolvedUrl("ContentHubPicker.qml"))
3318- }
3319-}
3320
3321=== removed file 'src/app/qml/ZoomableImage.qml'
3322--- src/app/qml/ZoomableImage.qml 2014-11-08 10:59:51 +0000
3323+++ src/app/qml/ZoomableImage.qml 1970-01-01 00:00:00 +0000
3324@@ -1,155 +0,0 @@
3325-/*
3326- * Copyright (C) 2014 Canonical, Ltd.
3327- *
3328- * This program is free software; you can redistribute it and/or modify
3329- * it under the terms of the GNU General Public License as published by
3330- * the Free Software Foundation; version 3.
3331- *
3332- * This program is distributed in the hope that it will be useful,
3333- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3334- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3335- * GNU General Public License for more details.
3336- *
3337- * You should have received a copy of the GNU General Public License
3338- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3339- */
3340-
3341-import QtQuick 2.0
3342-import Ubuntu.Components 0.1
3343-
3344-/*! \brief Zoomable for image.
3345-
3346- This widget shows image contained in source,
3347- can be zoomable accordingly with zoomable.
3348- */
3349-
3350-Item {
3351- id: root
3352- property alias source: imageRenderer.source
3353- property var zoomable: false
3354- property alias imageStatus: imageRenderer.status
3355- property alias asynchronous: imageRenderer.asynchronous
3356-
3357- Flickable {
3358- id: flickable
3359- objectName: "flickable"
3360- clip: true // FIXME maybe we can remove this, or just not clip in few cases
3361- contentHeight: imageContainer.height
3362- contentWidth: imageContainer.width
3363-
3364- onHeightChanged: image.resetScale()
3365- onWidthChanged: image.resetScale()
3366- anchors.fill: parent
3367-
3368- Item {
3369- id: imageContainer
3370- objectName: "imageContainer"
3371- width: Math.max(image.width * image.scale, flickable.width)
3372- height: Math.max(image.height * image.scale, flickable.height)
3373-
3374- Item {
3375- id: image
3376- objectName: "image"
3377- property alias imageStatus: imageRenderer.status
3378- property var prevScale
3379- anchors.centerIn: parent
3380-
3381- signal imageReloaded
3382-
3383- Image {
3384- id: imageRenderer
3385- objectName: "imageRenderer"
3386- smooth: !flickable.movingVertically
3387- anchors.fill: parent
3388- fillMode: Image.PreserveAspectFit
3389-
3390- readonly property int sourceSizeMultiplier: 3
3391-
3392- sourceSize.width: root.width * sourceSizeMultiplier <= root.height * sourceSizeMultiplier ? root.width * sourceSizeMultiplier : 0
3393- sourceSize.height: root.height * sourceSizeMultiplier <= root.width * sourceSizeMultiplier ? root.height * sourceSizeMultiplier : 0
3394-
3395- onStatusChanged: {
3396- if (status === Image.Ready) {
3397- image.imageReloaded();
3398- }
3399- }
3400- }
3401-
3402- onImageReloaded: {
3403- image.height = imageRenderer.implicitHeight
3404- image.width = imageRenderer.implicitWidth
3405- image.resetScale();
3406- }
3407-
3408- function resetScale() {
3409- image.scale = Math.min(flickable.width / image.width, flickable.height / image.height);
3410- pinchArea.minScale = image.scale;
3411- prevScale = Math.min(image.scale, 1);
3412- }
3413-
3414- onScaleChanged: {
3415- var currentWidth = width * scale
3416- var currentHeight = height * scale
3417- var scaleRatio = scale / prevScale
3418- if (currentWidth > flickable.width) {
3419- var xpos = flickable.width / 2 + flickable.contentX;
3420- var xoff = xpos * scaleRatio;
3421- flickable.contentX = xoff - flickable.width / 2;
3422- }
3423- if (currentHeight > flickable.height) {
3424- var ypos = flickable.height / 2 + flickable.contentY;
3425- var yoff = ypos * scaleRatio;
3426- flickable.contentY = yoff - flickable.height / 2;
3427- }
3428- prevScale = scale;
3429- }
3430- }
3431- }
3432-
3433- PinchArea {
3434- id: pinchArea
3435- objectName: "pinchArea"
3436- property real minScale: 1.0
3437- anchors.fill: parent
3438- enabled: zoomable ? zoomable : false
3439-
3440- pinch.target: image
3441- pinch.minimumScale: minScale
3442- pinch.maximumScale: 10
3443-
3444- onPinchFinished: flickable.returnToBounds()
3445- }
3446-
3447- MouseArea {
3448- id: mouseArea
3449- objectName: "mouseArea"
3450-
3451- anchors.fill: parent
3452- enabled: zoomable ? zoomable : false
3453-
3454- onWheel: {
3455- var startScale = image.scale;
3456- if (wheel.angleDelta.y > 0) {
3457- image.scale = startScale + 0.1;
3458- } else if (wheel.angleDelta.y < 0) {
3459- if (image.scale > 0.1 && image.scale > pinchArea.minScale) {
3460- image.scale = startScale - 0.1;
3461- }
3462- }
3463- wheel.accepted = true;
3464- }
3465-
3466- onPressed: {
3467- mouse.accepted = false;
3468- }
3469-
3470- onReleased: {
3471- mouse.accepted = false;
3472- }
3473-
3474- onClicked: {
3475- mouse.accepted = false;
3476- }
3477- }
3478- }
3479-}
3480
3481=== added directory 'src/app/qml/common'
3482=== added file 'src/app/qml/common/DetailsPage.qml'
3483--- src/app/qml/common/DetailsPage.qml 1970-01-01 00:00:00 +0000
3484+++ src/app/qml/common/DetailsPage.qml 2015-03-03 16:49:59 +0000
3485@@ -0,0 +1,58 @@
3486+/*
3487+ * Copyright (C) 2013-2014 Canonical, Ltd.
3488+ *
3489+ * This program is free software; you can redistribute it and/or modify
3490+ * it under the terms of the GNU General Public License as published by
3491+ * the Free Software Foundation; version 3.
3492+ *
3493+ * This program is distributed in the hope that it will be useful,
3494+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3495+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3496+ * GNU General Public License for more details.
3497+ *
3498+ * You should have received a copy of the GNU General Public License
3499+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3500+ */
3501+
3502+import QtQuick 2.3
3503+import Ubuntu.Components 1.1
3504+import Ubuntu.Components.ListItems 1.0 as ListItem
3505+
3506+import "utils.js" as Utils
3507+
3508+Page {
3509+ id: detailsPage
3510+ objectName: "detailsPage"
3511+
3512+ title: i18n.tr("Details")
3513+
3514+ Column {
3515+ width: parent.width
3516+
3517+ ListItem.Subtitled {
3518+ text: i18n.tr("Location")
3519+ subText: file.path
3520+ }
3521+ ListItem.Subtitled {
3522+ text: i18n.tr("Size")
3523+ subText: Utils.printSize(file.size)
3524+ }
3525+
3526+ ListItem.Subtitled {
3527+ text: i18n.tr("Created")
3528+ subText: file.creationTime.toLocaleString(Qt.locale())
3529+ }
3530+
3531+ ListItem.Subtitled {
3532+ text: i18n.tr("Last modified")
3533+ subText: file.lastModified.toLocaleString(Qt.locale())
3534+ }
3535+
3536+ ListItem.Subtitled {
3537+ id: mimetypeItem
3538+ objectName: "mimetypeItem"
3539+ text: i18n.tr("MIME type")
3540+ subText: file.mimetype
3541+ }
3542+ }
3543+}
3544
3545=== added file 'src/app/qml/common/ErrorDialog.qml'
3546--- src/app/qml/common/ErrorDialog.qml 1970-01-01 00:00:00 +0000
3547+++ src/app/qml/common/ErrorDialog.qml 2015-03-03 16:49:59 +0000
3548@@ -0,0 +1,32 @@
3549+/*
3550+ * Copyright (C) 2014-2015 Canonical, Ltd.
3551+ *
3552+ * This program is free software; you can redistribute it and/or modify
3553+ * it under the terms of the GNU General Public License as published by
3554+ * the Free Software Foundation; version 3.
3555+ *
3556+ * This program is distributed in the hope that it will be useful,
3557+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3558+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3559+ * GNU General Public License for more details.
3560+ *
3561+ * You should have received a copy of the GNU General Public License
3562+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3563+ */
3564+
3565+import QtQuick 2.3
3566+import Ubuntu.Components 1.1
3567+import Ubuntu.Components.Popups 1.0
3568+
3569+// TODO: We may want to make it more generic and useful.
3570+Dialog {
3571+ id: errorDialog
3572+ title: i18n.tr("Error")
3573+ text: i18n.tr("File does not exist")
3574+
3575+ Button {
3576+ text: i18n.tr("Close")
3577+ color: UbuntuColors.red
3578+ onClicked: PopupUtils.close(errorDialog)
3579+ }
3580+}
3581
3582=== added file 'src/app/qml/common/UnknownTypeDialog.qml'
3583--- src/app/qml/common/UnknownTypeDialog.qml 1970-01-01 00:00:00 +0000
3584+++ src/app/qml/common/UnknownTypeDialog.qml 2015-03-03 16:49:59 +0000
3585@@ -0,0 +1,43 @@
3586+/*
3587+ * Copyright (C) 2013-2015 Canonical, Ltd.
3588+ *
3589+ * This program is free software; you can redistribute it and/or modify
3590+ * it under the terms of the GNU General Public License as published by
3591+ * the Free Software Foundation; version 3.
3592+ *
3593+ * This program is distributed in the hope that it will be useful,
3594+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3595+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3596+ * GNU General Public License for more details.
3597+ *
3598+ * You should have received a copy of the GNU General Public License
3599+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3600+ */
3601+
3602+import QtQuick 2.3
3603+import Ubuntu.Components 1.1
3604+import Ubuntu.Components.Popups 1.0
3605+
3606+import "loadComponent.js" as LoadComponent
3607+
3608+Dialog {
3609+ id: unknownDialog
3610+ objectName: "unknownDialog"
3611+ title: i18n.tr("Unknown file type")
3612+ 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?")
3613+ Button {
3614+ text: i18n.tr("Yes")
3615+ color: UbuntuColors.green
3616+
3617+ onClicked: {
3618+ LoadComponent.load("text/plain");
3619+ PopupUtils.close(unknownDialog)
3620+ }
3621+ }
3622+ Button {
3623+ text: i18n.tr("No")
3624+ color: UbuntuColors.red
3625+ onClicked: PopupUtils.close(unknownDialog)
3626+ }
3627+}
3628+
3629
3630=== added file 'src/app/qml/common/loadComponent.js'
3631--- src/app/qml/common/loadComponent.js 1970-01-01 00:00:00 +0000
3632+++ src/app/qml/common/loadComponent.js 2015-03-03 16:49:59 +0000
3633@@ -0,0 +1,38 @@
3634+/*
3635+ * Copyright (C) 2013-2015 Canonical, Ltd.
3636+ *
3637+ * This program is free software; you can redistribute it and/or modify
3638+ * it under the terms of the GNU General Public License as published by
3639+ * the Free Software Foundation; version 3.
3640+ *
3641+ * This program is distributed in the hope that it will be useful,
3642+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3643+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3644+ * GNU General Public License for more details.
3645+ *
3646+ * You should have received a copy of the GNU General Public License
3647+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3648+ */
3649+
3650+function load(mimetype) {
3651+ var qmlToLoad = "";
3652+
3653+ // Open all text files in text editor
3654+ // With that fix it is possible to open LICENSE file
3655+ // which was recognised as text/x-pascal
3656+ if (mimetype.substring(0, 5) === "text/")
3657+ qmlToLoad = Qt.resolvedUrl("../textView/TextView.qml");
3658+
3659+ // Check if PDF document
3660+ if (mimetype === "application/pdf")
3661+ qmlToLoad = Qt.resolvedUrl("../pdfView/PdfView.qml");
3662+
3663+ if (qmlToLoad != "") {
3664+ pageStack.push(qmlToLoad);
3665+ } else {
3666+ console.debug("Unknown MIME type: "+ mimetype);
3667+ runUnknownTypeDialog();
3668+ }
3669+
3670+ return mimetype;
3671+}
3672
3673=== added file 'src/app/qml/common/utils.js'
3674--- src/app/qml/common/utils.js 1970-01-01 00:00:00 +0000
3675+++ src/app/qml/common/utils.js 2015-03-03 16:49:59 +0000
3676@@ -0,0 +1,34 @@
3677+/*
3678+ * Copyright (C) 2013-2015 Canonical, Ltd.
3679+ *
3680+ * This program is free software; you can redistribute it and/or modify
3681+ * it under the terms of the GNU General Public License as published by
3682+ * the Free Software Foundation; version 3.
3683+ *
3684+ * This program is distributed in the hope that it will be useful,
3685+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3686+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3687+ * GNU General Public License for more details.
3688+ *
3689+ * You should have received a copy of the GNU General Public License
3690+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3691+ */
3692+
3693+.pragma library
3694+
3695+function printSize(size) {
3696+ if (size >= 1073741824)
3697+ return (size / 1073741824).toFixed(2) + qsTr(" GiB");
3698+
3699+ if (size >= 1048576)
3700+ return (size / 1048576).toFixed(2) + qsTr(" MiB");
3701+
3702+ if (size >= 1024)
3703+ return parseInt(size / 1024) + qsTr(" KiB");
3704+
3705+ return size + qsTr(" byte");
3706+}
3707+
3708+function getNameOfFile(path) {
3709+ return path.toString().substring(path.lastIndexOf('/') + 1);
3710+}
3711
3712=== added directory 'src/app/qml/documentPage'
3713=== added file 'src/app/qml/documentPage/DeleteFileDialog.qml'
3714--- src/app/qml/documentPage/DeleteFileDialog.qml 1970-01-01 00:00:00 +0000
3715+++ src/app/qml/documentPage/DeleteFileDialog.qml 2015-03-03 16:49:59 +0000
3716@@ -0,0 +1,58 @@
3717+/*
3718+ Copyright (C) 2013-2015 Stefano Verzegnassi
3719+
3720+ This program is free software: you can redistribute it and/or modify
3721+ it under the terms of the GNU General Public License 3 as published by
3722+ the Free Software Foundation, either version 3 of the License, or
3723+ (at your option) any later version.
3724+
3725+ This program is distributed in the hope that it will be useful,
3726+ but WITHOUT ANY WARRANTY; without even the implied warranty of
3727+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3728+ GNU General Public License for more details.
3729+
3730+ You should have received a copy of the GNU General Public License
3731+ along with this program. If not, see http://www.gnu.org/licenses/.
3732+*/
3733+
3734+import QtQuick 2.0
3735+import Ubuntu.Components 1.1
3736+import Ubuntu.Components.Popups 1.0
3737+
3738+Dialog {
3739+ id: deleteFileDialog
3740+
3741+ property string path
3742+
3743+ title: path ? i18n.tr("Delete file") :
3744+ i18n.tr("Delete %1 files").arg(documentPage.view.item.selectedItems.count)
3745+ text: path ? i18n.tr("Are you sure you want to permanently delete this file?") :
3746+ i18n.tr("Are you sure you want to permanently delete these files?")
3747+
3748+ Button {
3749+ text: i18n.tr("Cancel")
3750+ onClicked: PopupUtils.close(deleteFileDialog)
3751+ }
3752+
3753+ Button {
3754+ text: i18n.tr("Delete")
3755+ color: UbuntuColors.red
3756+
3757+ onClicked: {
3758+ if (deleteFileDialog.path) {
3759+ folderModel.rm(path)
3760+ } else {
3761+ var items = documentPage.view.item.selectedItems;
3762+
3763+ for (var i=0; i < items.count; i++) {
3764+ console.log("Removing:", items.get(i).model.path);
3765+ folderModel.rm(items.get(i).model.path);
3766+ }
3767+ }
3768+
3769+ viewLoader.item.endSelection();
3770+ PopupUtils.close(deleteFileDialog)
3771+ }
3772+ }
3773+}
3774+
3775
3776=== added file 'src/app/qml/documentPage/DocumentEmptyState.qml'
3777--- src/app/qml/documentPage/DocumentEmptyState.qml 1970-01-01 00:00:00 +0000
3778+++ src/app/qml/documentPage/DocumentEmptyState.qml 2015-03-03 16:49:59 +0000
3779@@ -0,0 +1,34 @@
3780+/*
3781+ Copyright (C) 2015 Stefano Verzegnassi
3782+
3783+ This program is free software: you can redistribute it and/or modify
3784+ it under the terms of the GNU General Public License 3 as published by
3785+ the Free Software Foundation.
3786+
3787+ This program is distributed in the hope that it will be useful,
3788+ but WITHOUT ANY WARRANTY; without even the implied warranty of
3789+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3790+ GNU General Public License for more details.
3791+
3792+ You should have received a copy of the GNU General Public License
3793+ along with this program. If not, see http://www.gnu.org/licenses/.
3794+*/
3795+
3796+import QtQuick 2.0
3797+import "../upstreamComponents"
3798+
3799+Item {
3800+ anchors.fill: parent
3801+
3802+ EmptyState {
3803+ title: i18n.tr("No document found")
3804+
3805+ // TODO: Add "or insert removable media with documents." to subTitle when
3806+ // the support for SD card will be implemented.
3807+ subTitle: i18n.tr("Connect your device to any computer and simply drag files to the Documents folder.")
3808+ iconName: "edit-copy"
3809+
3810+ anchors.centerIn: parent
3811+ width: parent.width
3812+ }
3813+}
3814
3815=== added file 'src/app/qml/documentPage/DocumentGridDelegate.qml'
3816--- src/app/qml/documentPage/DocumentGridDelegate.qml 1970-01-01 00:00:00 +0000
3817+++ src/app/qml/documentPage/DocumentGridDelegate.qml 2015-03-03 16:49:59 +0000
3818@@ -0,0 +1,178 @@
3819+/*
3820+ Copyright (C) 2015 Stefano Verzegnassi
3821+
3822+ This program is free software: you can redistribute it and/or modify
3823+ it under the terms of the GNU General Public License 3 as published by
3824+ the Free Software Foundation.
3825+
3826+ This program is distributed in the hope that it will be useful,
3827+ but WITHOUT ANY WARRANTY; without even the implied warranty of
3828+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3829+ GNU General Public License for more details.
3830+
3831+ You should have received a copy of the GNU General Public License
3832+ along with this program. If not, see http://www.gnu.org/licenses/.
3833+*/
3834+
3835+import QtQuick 2.0
3836+import Ubuntu.Components 1.1
3837+import QtQuick.Layouts 1.1
3838+
3839+import "../common/utils.js" as Utils
3840+
3841+AbstractButton {
3842+ id: root
3843+ property bool selected: false
3844+ property bool selectionMode: false
3845+
3846+ function formattedDateTime() {
3847+ var date = new Date(model.date)
3848+ var diff = model.dateDiff
3849+
3850+ if (diff < 1)
3851+ return i18n.tr("Today, ") + Qt.formatTime(date, Qt.locale().timeFormat(Locale.ShortFormat))
3852+
3853+ if (diff < 2)
3854+ return i18n.tr("Yesterday, ") + Qt.formatDateTime(date, Qt.locale().timeFormat(Locale.ShortFormat))
3855+
3856+ if (diff < 7)
3857+ // TRANSLATORS: this is a datetime formatting string,
3858+ // see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
3859+ return Qt.formatDateTime(date, i18n.tr("dddd, hh:mm"))
3860+
3861+ // TRANSLATORS: this is a datetime formatting string,
3862+ // see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
3863+ return Qt.formatDateTime(date, i18n.tr("dd-MM-yyyy hh:mm"))
3864+ }
3865+
3866+ Rectangle {
3867+ anchors { fill: parent; margins: units.gu(0.5) }
3868+
3869+ color: Qt.lighter(UbuntuColors.lightGrey)
3870+ clip: true
3871+
3872+ Loader {
3873+ id: selectionIcon
3874+
3875+ anchors {
3876+ right: parent.right
3877+ top: parent.top
3878+ }
3879+
3880+ z: 10
3881+
3882+ width: (status === Loader.Ready) ? item.implicitWidth : 0
3883+ visible: (status === Loader.Ready) && (item.width === item.implicitWidth)
3884+ Behavior on opacity {
3885+ NumberAnimation {
3886+ duration: UbuntuAnimation.SnapDuration
3887+ }
3888+ }
3889+ }
3890+
3891+ // Document mimetype icon
3892+ Icon {
3893+ anchors.centerIn: parent
3894+ anchors.verticalCenterOffset: - units.gu(2)
3895+
3896+ width: units.gu(8); height: width
3897+
3898+ // At the moment the suru icon theme doesn't have much icons.
3899+ // Just some note for the future:
3900+ // TODO: Add icons for Office/ODF documents
3901+ // TODO: Whenever there will be icons for source code files, add them.
3902+ name: {
3903+ if (model.mimetype.substring(0, 5) === "text/")
3904+ return "text-x-generic-symbolic"
3905+
3906+ if (model.mimetype.substring(0, 5) === "image")
3907+ return "image-x-generic-symbolic"
3908+
3909+ if (model.mimetype === "application/pdf")
3910+ return "application-pdf-symbolic"
3911+
3912+ return "package-x-generic-symbolic"
3913+ }
3914+ }
3915+
3916+ // Cover
3917+ /* Image {
3918+ anchors.fill: parent
3919+
3920+ source: {
3921+ if (model.cover !== "" && typeof model.cover !== "undefined")
3922+ return model.cover
3923+
3924+ if (model.mimetype.toString().indexOf("image") !== -1)
3925+ return model.path
3926+
3927+ return ""
3928+ }
3929+
3930+ sourceSize.width: width
3931+ fillMode: Image.PreserveAspectCrop
3932+ }*/
3933+
3934+ // Document info overlay
3935+ Rectangle {
3936+ id: overlay
3937+
3938+ anchors {
3939+ left: parent.left
3940+ right: parent.right
3941+ bottom: parent.bottom
3942+ }
3943+
3944+ height: units.gu(6)
3945+
3946+ color: UbuntuColors.darkGrey
3947+ opacity: 0.75
3948+ }
3949+
3950+ // Document info
3951+ Column {
3952+ anchors { fill: overlay; margins: units.gu(0.5) }
3953+
3954+ Label {
3955+ text: model.name
3956+ color: "white"
3957+
3958+ elide: Text.ElideRight
3959+ font.weight: Font.DemiBold
3960+ fontSize: "small"
3961+
3962+ anchors { left: parent.left; right: parent.right }
3963+ }
3964+
3965+ RowLayout {
3966+ anchors { left: parent.left; right: parent.right }
3967+
3968+ Label {
3969+ text: formattedDateTime()
3970+ color: "white"
3971+ fontSize: "small"
3972+
3973+ Layout.fillWidth: true
3974+ }
3975+
3976+ Label {
3977+ text: Utils.printSize(model.size)
3978+ color: "white"
3979+ fontSize: "small"
3980+ }
3981+ }
3982+ } // Document info end
3983+
3984+ states: [
3985+ State {
3986+ name: "select"
3987+ when: selectionMode || selected
3988+ PropertyChanges {
3989+ target: selectionIcon
3990+ source: Qt.resolvedUrl("../upstreamComponents/ListItemWithActionsCheckBox.qml")
3991+ anchors.margins: units.gu(1)
3992+ }
3993+ }
3994+ ]
3995+ }
3996+}
3997
3998=== added file 'src/app/qml/documentPage/DocumentGridView.qml'
3999--- src/app/qml/documentPage/DocumentGridView.qml 1970-01-01 00:00:00 +0000
4000+++ src/app/qml/documentPage/DocumentGridView.qml 2015-03-03 16:49:59 +0000
4001@@ -0,0 +1,76 @@
4002+/*
4003+ Copyright (C) 2015 Stefano Verzegnassi
4004+
4005+ This program is free software: you can redistribute it and/or modify
4006+ it under the terms of the GNU General Public License 3 as published by
4007+ the Free Software Foundation.
4008+
4009+ This program is distributed in the hope that it will be useful,
4010+ but WITHOUT ANY WARRANTY; without even the implied warranty of
4011+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4012+ GNU General Public License for more details.
4013+
4014+ You should have received a copy of the GNU General Public License
4015+ along with this program. If not, see http://www.gnu.org/licenses/.
4016+*/
4017+
4018+import QtQuick 2.0
4019+import Ubuntu.Components 1.1
4020+
4021+import "../upstreamComponents"
4022+
4023+MultipleSelectionGridView {
4024+ id: documentGridView
4025+
4026+ // We use mainView.width to calculate the size and the spacing of elements.
4027+ // That's because this GridView always fills (and always will) the whole size of MainView.
4028+ // By this way, we can avoid binding loops, keeping the code pretty simple.
4029+ anchors {
4030+ fill: parent
4031+ margins: units.gu(0.5)
4032+ leftMargin: (mainView.width % cellWidth) * 0.5
4033+ rightMargin: (mainView.width % cellWidth) * 0.5
4034+ }
4035+ clip: true
4036+
4037+ cellHeight: cellWidth
4038+ cellWidth: (mainView.width > units.gu(50)) ? units.gu(24)
4039+ : (mainView.width - units.gu(2)) * 0.5
4040+
4041+ listDelegate: DocumentGridDelegate {
4042+ id: delegate
4043+ width: cellWidth
4044+ height: cellHeight
4045+
4046+ selectionMode: documentGridView.isInSelectionMode
4047+ selected: documentGridView.isSelected(delegate)
4048+
4049+ onClicked: {
4050+ if(documentGridView.isInSelectionMode) {
4051+ if(!documentGridView.selectItem(delegate)) {
4052+ documentGridView.deselectItem(delegate)
4053+ }
4054+ return
4055+ }
4056+ else {
4057+ file.path = model.path
4058+ }
4059+ }
4060+
4061+ onPressAndHold: {
4062+ if (!documentGridView.isInSelectionMode) {
4063+ documentGridView.startSelection()
4064+ documentGridView.selectItem(delegate)
4065+ }
4066+ }
4067+ }
4068+
4069+ listModel: folderModel
4070+
4071+ Scrollbar {
4072+ flickableItem: documentGridView
4073+ parent: documentGridView.parent
4074+ }
4075+
4076+ Component.onCompleted: { if (DOC_VIEWER.pickModeEnabled) documentGridView.startSelection(); }
4077+}
4078
4079=== added file 'src/app/qml/documentPage/DocumentListDelegate.qml'
4080--- src/app/qml/documentPage/DocumentListDelegate.qml 1970-01-01 00:00:00 +0000
4081+++ src/app/qml/documentPage/DocumentListDelegate.qml 2015-03-03 16:49:59 +0000
4082@@ -0,0 +1,108 @@
4083+/*
4084+ Copyright (C) 2015 Stefano Verzegnassi
4085+
4086+ This program is free software: you can redistribute it and/or modify
4087+ it under the terms of the GNU General Public License 3 as published by
4088+ the Free Software Foundation.
4089+
4090+ This program is distributed in the hope that it will be useful,
4091+ but WITHOUT ANY WARRANTY; without even the implied warranty of
4092+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4093+ GNU General Public License for more details.
4094+
4095+ You should have received a copy of the GNU General Public License
4096+ along with this program. If not, see http://www.gnu.org/licenses/.
4097+*/
4098+
4099+import QtQuick 2.0
4100+import Ubuntu.Components 1.1
4101+import QtQuick.Layouts 1.1
4102+
4103+import "../common/utils.js" as Utils
4104+import "../upstreamComponents"
4105+
4106+ListItemWithActions {
4107+ function formattedDateTime() {
4108+ var date = new Date(model.date)
4109+ var diff = model.dateDiff
4110+
4111+ if (diff < 2)
4112+ return Qt.formatDateTime(date, Qt.locale().timeFormat(Locale.ShortFormat))
4113+
4114+ if (diff < 7)
4115+ // TRANSLATORS: this is a datetime formatting string,
4116+ // see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
4117+ return Qt.formatDateTime(date, i18n.tr("dddd, hh:mm"))
4118+
4119+ // TRANSLATORS: this is a datetime formatting string,
4120+ // see http://qt-project.org/doc/qt-5/qml-qtqml-date.html#details for valid expressions.
4121+ return Qt.formatDateTime(date, i18n.tr("dd-MM-yyyy hh:mm"))
4122+ }
4123+
4124+ anchors { left: parent.left; right: parent.right }
4125+ height: units.gu(8)
4126+
4127+ locked: documentPage.state == "pickMode"
4128+
4129+ // TODO: NEEDS-DESIGN: Enable left action. Still need to find an equivalent for GridDelegate.
4130+ /* leftSideAction: Action {
4131+ iconName: "delete"
4132+ text: i18n.tr("Delete")
4133+ onTriggered: {
4134+ PopupUtils.open(Qt.resolvedUrl("DeleteFileDialog.qml"),
4135+ documentPage, { path: model.filePath })
4136+ }
4137+ }*/
4138+
4139+ contents: RowLayout {
4140+ anchors.fill: parent
4141+ spacing: units.gu(2)
4142+
4143+ Icon {
4144+ width: height
4145+ height: units.gu(5)
4146+
4147+ // At the moment the suru icon theme doesn't have much icons.
4148+ name: {
4149+ if (model.mimetype.substring(0, 5) === "text/")
4150+ return "text-x-generic-symbolic"
4151+
4152+ if (model.mimetype.substring(0, 5) === "image")
4153+ return "image-x-generic-symbolic"
4154+
4155+ if (model.mimetype === "application/pdf")
4156+ return "application-pdf-symbolic"
4157+
4158+ return "package-x-generic-symbolic"
4159+ }
4160+ }
4161+
4162+ Column {
4163+ Layout.fillWidth: true
4164+
4165+ Label {
4166+ text: model.name
4167+ wrapMode: Text.Wrap
4168+ width: parent.width
4169+
4170+ color: UbuntuColors.midAubergine
4171+ }
4172+
4173+ RowLayout {
4174+ width: parent.width
4175+
4176+ Label {
4177+ text: formattedDateTime()
4178+ fontSize: "small"
4179+
4180+ Layout.fillWidth: true
4181+ }
4182+
4183+ Label {
4184+ text: Utils.printSize(model.size)
4185+ fontSize: "small"
4186+ }
4187+ }
4188+ }
4189+ }
4190+}
4191
4192=== added file 'src/app/qml/documentPage/DocumentListView.qml'
4193--- src/app/qml/documentPage/DocumentListView.qml 1970-01-01 00:00:00 +0000
4194+++ src/app/qml/documentPage/DocumentListView.qml 2015-03-03 16:49:59 +0000
4195@@ -0,0 +1,156 @@
4196+/*
4197+ Copyright (C) 2015 Stefano Verzegnassi
4198+
4199+ This program is free software: you can redistribute it and/or modify
4200+ it under the terms of the GNU General Public License 3 as published by
4201+ the Free Software Foundation.
4202+
4203+ This program is distributed in the hope that it will be useful,
4204+ but WITHOUT ANY WARRANTY; without even the implied warranty of
4205+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4206+ GNU General Public License for more details.
4207+
4208+ You should have received a copy of the GNU General Public License
4209+ along with this program. If not, see http://www.gnu.org/licenses/.
4210+*/
4211+
4212+import QtQuick 2.0
4213+import Ubuntu.Components 1.1
4214+import Ubuntu.Components.ListItems 1.0 as ListItem
4215+
4216+import "../upstreamComponents"
4217+
4218+MultipleSelectionListView {
4219+ id: documentListView
4220+
4221+ anchors { fill: parent; margins: units.gu(0.5) }
4222+ clip: true
4223+
4224+ property var _currentSwipedItem: null
4225+
4226+ function _updateSwipeState(item)
4227+ {
4228+ if (item.swipping) {
4229+ return
4230+ }
4231+
4232+ if (item.swipeState !== "Normal") {
4233+ if (documentListView._currentSwipedItem !== item) {
4234+ if (documentListView._currentSwipedItem) {
4235+ documentListView._currentSwipedItem.resetSwipe()
4236+ }
4237+ documentListView._currentSwipedItem = item
4238+ }
4239+ } else if (item.swipeState !== "Normal"
4240+ && documentListView._currentSwipedItem === item) {
4241+ documentListView._currentSwipedItem = null
4242+ }
4243+ }
4244+
4245+ listDelegate: DocumentListDelegate {
4246+ id: delegate
4247+
4248+ property var removalAnimation
4249+
4250+ function remove() {
4251+ removalAnimation.start()
4252+ }
4253+
4254+ selectionMode: documentListView.isInSelectionMode
4255+ selected: documentListView.isSelected(delegate)
4256+
4257+ onSwippingChanged: {
4258+ _updateSwipeState(delegate)
4259+ }
4260+
4261+ onSwipeStateChanged: {
4262+ _updateSwipeState(delegate)
4263+ }
4264+
4265+ ListView.onRemove: ScriptAction {
4266+ script: {
4267+ if (_currentSwipedItem
4268+ === delegate) {
4269+ _currentSwipedItem = null
4270+ }
4271+ }
4272+ }
4273+
4274+ removalAnimation: SequentialAnimation {
4275+ alwaysRunToEnd: true
4276+
4277+ PropertyAction {
4278+ target: delegate
4279+ property: "ListView.delayRemove"
4280+ value: true
4281+ }
4282+
4283+ UbuntuNumberAnimation {
4284+ target: delegate
4285+ property: "height"
4286+ to: 0
4287+ }
4288+
4289+ PropertyAction {
4290+ target: delegate
4291+ property: "ListView.delayRemove"
4292+ value: false
4293+ }
4294+
4295+ ScriptAction {
4296+ script: {
4297+ var filePath = d.folderModel.get(index, "filePath")
4298+ Storage.rm(filePath)
4299+ }
4300+ }
4301+ }
4302+
4303+ onItemClicked: {
4304+ if(documentListView.isInSelectionMode) {
4305+ if(!documentListView.selectItem(delegate)) {
4306+ documentListView.deselectItem(delegate)
4307+ }
4308+ return
4309+ }
4310+
4311+ else {
4312+ file.path = model.path
4313+ }
4314+ }
4315+
4316+ onItemPressAndHold: {
4317+ if (!documentListView.isInSelectionMode) {
4318+ documentListView.startSelection()
4319+ documentListView.selectItem(delegate)
4320+ }
4321+ }
4322+ }
4323+
4324+ listModel: folderModel
4325+
4326+ section.property: "dateDiff"
4327+ section.delegate: ListItem.Header {
4328+ text: {
4329+ if (section == 0)
4330+ return i18n.tr("Today")
4331+
4332+ if (section == 1)
4333+ return i18n.tr("Yesterday")
4334+
4335+ if (section == 2)
4336+ return i18n.tr("Earlier this week")
4337+
4338+ if (section == 3)
4339+ return i18n.tr("Earlier this month")
4340+
4341+ return i18n.tr("Even more earlier...")
4342+ }
4343+ }
4344+
4345+ Scrollbar {
4346+ flickableItem: documentListView
4347+ parent: documentListView.parent
4348+ }
4349+
4350+ Component.onCompleted: { if (DOC_VIEWER.pickModeEnabled) documentListView.startSelection(); }
4351+}
4352
4353=== added file 'src/app/qml/documentPage/DocumentPage.qml'
4354--- src/app/qml/documentPage/DocumentPage.qml 1970-01-01 00:00:00 +0000
4355+++ src/app/qml/documentPage/DocumentPage.qml 2015-03-03 16:49:59 +0000
4356@@ -0,0 +1,76 @@
4357+/*
4358+ * Copyright (C) 2015 Canonical, Ltd.
4359+ *
4360+ * This program is free software; you can redistribute it and/or modify
4361+ * it under the terms of the GNU General Public License as published by
4362+ * the Free Software Foundation; version 3.
4363+ *
4364+ * This program is distributed in the hope that it will be useful,
4365+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4366+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4367+ * GNU General Public License for more details.
4368+ *
4369+ * You should have received a copy of the GNU General Public License
4370+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4371+ */
4372+
4373+import QtQuick 2.0
4374+import Ubuntu.Components 1.1
4375+import Ubuntu.Components.Popups 1.0
4376+import Qt.labs.settings 1.0
4377+
4378+Page {
4379+ id: documentPage
4380+
4381+ title: i18n.tr("Document Viewer")
4382+ flickable: null
4383+
4384+ property bool useGridView: false
4385+
4386+ Settings {
4387+ property alias useGridView: documentPage.useGridView
4388+ }
4389+
4390+ property alias view: viewLoader
4391+ Loader {
4392+ id: viewLoader
4393+ anchors.fill: parent
4394+
4395+ source: (folderModel.count === 0) ? Qt.resolvedUrl("./DocumentEmptyState.qml")
4396+ : useGridView ? Qt.resolvedUrl("./DocumentGridView.qml")
4397+ : Qt.resolvedUrl("./DocumentListView.qml")
4398+ }
4399+
4400+ // *** HEADER ***
4401+ states: [
4402+ DocumentPageDefaultHeader {
4403+ name: "default"
4404+ targetPage: documentPage
4405+ when: !mainView.pickMode && !viewLoader.item.isInSelectionMode
4406+ },
4407+
4408+ DocumentPagePickModeHeader {
4409+ name: "pickMode"
4410+ targetPage: documentPage
4411+ when: mainView.pickMode
4412+ },
4413+
4414+ DocumentPageSelectionModeHeader {
4415+ name: "selection"
4416+ targetPage: documentPage
4417+ when: !mainView.pickMode && viewLoader.item.isInSelectionMode
4418+ }
4419+ ]
4420+
4421+ Connections {
4422+ target: DOC_VIEWER
4423+
4424+ onPickModeEnabledChanged: {
4425+ if (DOC_VIEWER.pickModeEnabled) {
4426+ viewLoader.item.startSelection()
4427+ } else {
4428+ viewLoader.item.cancelSelection()
4429+ }
4430+ }
4431+ }
4432+}
4433
4434=== added file 'src/app/qml/documentPage/DocumentPageDefaultHeader.qml'
4435--- src/app/qml/documentPage/DocumentPageDefaultHeader.qml 1970-01-01 00:00:00 +0000
4436+++ src/app/qml/documentPage/DocumentPageDefaultHeader.qml 2015-03-03 16:49:59 +0000
4437@@ -0,0 +1,34 @@
4438+/*
4439+ * Copyright (C) 2014-2015 Canonical, Ltd.
4440+ *
4441+ * This program is free software; you can redistribute it and/or modify
4442+ * it under the terms of the GNU General Public License as published by
4443+ * the Free Software Foundation; version 3.
4444+ *
4445+ * This program is distributed in the hope that it will be useful,
4446+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4447+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4448+ * GNU General Public License for more details.
4449+ *
4450+ * You should have received a copy of the GNU General Public License
4451+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4452+ */
4453+
4454+import QtQuick 2.3
4455+import Ubuntu.Components 1.1
4456+
4457+PageHeadState {
4458+ id: rootItem
4459+
4460+ property Page targetPage
4461+ head: targetPage.head
4462+
4463+ actions: Action {
4464+ id: switchView
4465+ text: targetPage.useGridView ? i18n.tr("Switch to single column list") : i18n.tr("Switch to grid")
4466+ iconName: targetPage.useGridView ? "view-list-symbolic" : "view-grid-symbolic"
4467+ onTriggered: targetPage.useGridView = !targetPage.useGridView
4468+
4469+ visible: folderModel.count !== 0
4470+ }
4471+}
4472
4473=== added file 'src/app/qml/documentPage/DocumentPagePickModeHeader.qml'
4474--- src/app/qml/documentPage/DocumentPagePickModeHeader.qml 1970-01-01 00:00:00 +0000
4475+++ src/app/qml/documentPage/DocumentPagePickModeHeader.qml 2015-03-03 16:49:59 +0000
4476@@ -0,0 +1,63 @@
4477+/*
4478+ * Copyright (C) 2014-2015 Canonical, Ltd.
4479+ *
4480+ * This program is free software; you can redistribute it and/or modify
4481+ * it under the terms of the GNU General Public License as published by
4482+ * the Free Software Foundation; version 3.
4483+ *
4484+ * This program is distributed in the hope that it will be useful,
4485+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4486+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4487+ * GNU General Public License for more details.
4488+ *
4489+ * You should have received a copy of the GNU General Public License
4490+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4491+ */
4492+
4493+import QtQuick 2.3
4494+import Ubuntu.Components 1.1
4495+
4496+PageHeadState {
4497+ id: rootItem
4498+
4499+ property Page targetPage
4500+ head: targetPage.head
4501+
4502+ backAction: Action {
4503+ text: i18n.tr("Cancel")
4504+ objectName: "cancelButton"
4505+ iconName: "close"
4506+ onTriggered: DOC_VIEWER.contentPickingCanceled()
4507+ }
4508+
4509+ actions: [
4510+ Action {
4511+ text: targetPage.useGridView ? i18n.tr("Switch to single column list") : i18n.tr("Switch to grid")
4512+ iconName: targetPage.useGridView ? "view-list-symbolic" : "view-grid-symbolic"
4513+ onTriggered: targetPage.useGridView = !targetPage.useGridView
4514+
4515+ visible: folderModel.count !== 0
4516+ },
4517+
4518+ Action {
4519+ text: i18n.tr("Pick")
4520+ objectName: "pickButton"
4521+ enabled: viewLoader.item.selectedItems.count > 0
4522+ iconName: "ok"
4523+ onTriggered: {
4524+ if (!enabled)
4525+ return;
4526+
4527+ var urlList = []
4528+ var items = documentPage.view.item.selectedItems;
4529+
4530+ for (var i=0; i < items.count; i++) {
4531+ urlList.push(items.get(i).model.path);
4532+ }
4533+
4534+ DOC_VIEWER.returnPickedContent(urlList);
4535+ }
4536+ }
4537+ ]
4538+}
4539+
4540
4541=== added file 'src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml'
4542--- src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml 1970-01-01 00:00:00 +0000
4543+++ src/app/qml/documentPage/DocumentPageSelectionModeHeader.qml 2015-03-03 16:49:59 +0000
4544@@ -0,0 +1,94 @@
4545+/*
4546+ * Copyright (C) 2014-2015 Canonical, Ltd.
4547+ *
4548+ * This program is free software; you can redistribute it and/or modify
4549+ * it under the terms of the GNU General Public License as published by
4550+ * the Free Software Foundation; version 3.
4551+ *
4552+ * This program is distributed in the hope that it will be useful,
4553+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4554+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4555+ * GNU General Public License for more details.
4556+ *
4557+ * You should have received a copy of the GNU General Public License
4558+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4559+ */
4560+
4561+import QtQuick 2.3
4562+import Ubuntu.Components 1.1
4563+
4564+import "../upstreamComponents"
4565+
4566+PageHeadState {
4567+ id: rootItem
4568+
4569+ property Page targetPage
4570+
4571+ head: targetPage.head
4572+
4573+ backAction: Action {
4574+ iconName: "close"
4575+ text: i18n.tr("Close")
4576+ onTriggered: {
4577+ viewLoader.item.cancelSelection()
4578+ }
4579+ }
4580+
4581+ contents: Loader {
4582+ id: selectionStateLoader
4583+ active: documentPage.state === "selection"
4584+ sourceComponent: Item {
4585+ HeaderButton {
4586+ id: selectButton
4587+
4588+ anchors {
4589+ right: deleteButton.left
4590+ rightMargin: units.gu(1)
4591+ }
4592+
4593+ text: {
4594+ if(viewLoader.item.selectedItems.count === viewLoader.item.count) {
4595+ return i18n.tr("Select None")
4596+ } else {
4597+ return i18n.tr("Select All")
4598+ }
4599+ }
4600+
4601+ iconSource: {
4602+ if(viewLoader.item.selectedItems.count === viewLoader.item.count) {
4603+ return Qt.resolvedUrl("../../graphics/select-none.svg")
4604+ } else {
4605+ return Qt.resolvedUrl("../../graphics/select.svg")
4606+ }
4607+ }
4608+
4609+ onTriggered: {
4610+ if(viewLoader.item.selectedItems.count === viewLoader.item.count) {
4611+ viewLoader.item.clearSelection()
4612+ } else {
4613+ viewLoader.item.selectAll()
4614+ }
4615+ }
4616+ }
4617+
4618+ HeaderButton {
4619+ id: deleteButton
4620+
4621+ anchors.right: parent.right
4622+ anchors.rightMargin: units.gu(2)
4623+
4624+ iconName: "delete"
4625+ text: i18n.tr("Delete")
4626+ enabled: viewLoader.item.selectedItems.count !== 0
4627+
4628+ onTriggered: {
4629+ PopupUtils.open(Qt.resolvedUrl("DeleteFileDialog.qml"), documentPage)
4630+ }
4631+ }
4632+ }
4633+
4634+ height: parent ? parent.height : undefined
4635+ anchors.right: parent ? parent.right: undefined
4636+ }
4637+
4638+}
4639
4640=== removed file 'src/app/qml/loadComponent.js'
4641--- src/app/qml/loadComponent.js 2015-01-29 18:45:21 +0000
4642+++ src/app/qml/loadComponent.js 1970-01-01 00:00:00 +0000
4643@@ -1,45 +0,0 @@
4644-/*
4645- * Copyright (C) 2013-2015 Canonical, Ltd.
4646- *
4647- * This program is free software; you can redistribute it and/or modify
4648- * it under the terms of the GNU General Public License as published by
4649- * the Free Software Foundation; version 3.
4650- *
4651- * This program is distributed in the hope that it will be useful,
4652- * but WITHOUT ANY WARRANTY; without even the implied warranty of
4653- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4654- * GNU General Public License for more details.
4655- *
4656- * You should have received a copy of the GNU General Public License
4657- * along with this program. If not, see <http://www.gnu.org/licenses/>.
4658- */
4659-
4660-function load(mimetype) {
4661- var qmlToLoad = "";
4662-
4663- // Open all text files in text editor
4664- // With that fix it is possible to open LICENSE file
4665- // which was recognised as text/x-pascal
4666- if (mimetype.substring(0, 5) === "text/")
4667- qmlToLoad = "TextView";
4668-
4669- // Check if image
4670- if (mimetype === "image/jpeg" || mimetype === "image/png" ||
4671- mimetype === "image/gif" || mimetype === "image/tiff" ||
4672- mimetype === "image/x-icon" || mimetype === "image/x-ms-bmp" ||
4673- mimetype === "image/svg+xml")
4674- qmlToLoad = "ImageView";
4675-
4676- // Check if PDF document
4677- if (mimetype === "application/pdf")
4678- qmlToLoad = "PdfView";
4679-
4680- if (qmlToLoad != "") {
4681- pageStack.push(Qt.resolvedUrl(qmlToLoad + ".qml"));
4682- } else {
4683- console.debug("Unknown MIME type: "+ mimetype);
4684- runUnknownTypeDialog();
4685- }
4686-
4687- return mimetype;
4688-}
4689
4690=== added directory 'src/app/qml/pdfView'
4691=== added file 'src/app/qml/pdfView/PdfContentsPage.qml'
4692--- src/app/qml/pdfView/PdfContentsPage.qml 1970-01-01 00:00:00 +0000
4693+++ src/app/qml/pdfView/PdfContentsPage.qml 2015-03-03 16:49:59 +0000
4694@@ -0,0 +1,60 @@
4695+/*
4696+ * Copyright (C) 2014, 2015
4697+ * Stefano Verzegnassi <verzegnassi.stefano@gmail.com>
4698+ *
4699+ * This program is free software; you can redistribute it and/or modify
4700+ * it under the terms of the GNU General Public License as published by
4701+ * the Free Software Foundation; version 3.
4702+ *
4703+ * This program is distributed in the hope that it will be useful,
4704+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4705+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4706+ * GNU General Public License for more details.
4707+ *
4708+ * You should have received a copy of the GNU General Public License
4709+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4710+ */
4711+
4712+import QtQuick 2.0
4713+import Ubuntu.Components 1.1
4714+import QtQuick.Layouts 1.1
4715+import Ubuntu.Components.ListItems 1.0 as ListItem
4716+
4717+Page {
4718+ title: i18n.tr("Contents")
4719+
4720+ ListView {
4721+ anchors.fill: parent
4722+
4723+ model: poppler.tocModel
4724+
4725+ delegate: ListItem.Base {
4726+ showDivider: model.level == 0
4727+
4728+ onClicked: {
4729+ pdfView.positionAtIndex(model.pageIndex);
4730+ pageStack.pop();
4731+ }
4732+
4733+ RowLayout {
4734+ anchors.fill: parent
4735+ anchors.leftMargin: units.gu(2) * model.level
4736+
4737+ spacing: units.gu(1)
4738+
4739+ Label {
4740+ Layout.fillWidth: true
4741+
4742+ text: (typeof model.title === "undefined") ? "" : model.title;
4743+ elide: Text.ElideRight
4744+ Component.onCompleted: { if (model.level === 0); font.weight = Font.DemiBold; }
4745+ }
4746+
4747+ Label {
4748+ text: (typeof model.pageIndex === "undefined") ? "" : model.pageIndex + 1;
4749+ Component.onCompleted: { if (model.level === 0); font.weight = Font.DemiBold; }
4750+ }
4751+ }
4752+ }
4753+ }
4754+}
4755
4756=== added file 'src/app/qml/pdfView/PdfView.qml'
4757--- src/app/qml/pdfView/PdfView.qml 1970-01-01 00:00:00 +0000
4758+++ src/app/qml/pdfView/PdfView.qml 2015-03-03 16:49:59 +0000
4759@@ -0,0 +1,109 @@
4760+/*
4761+ * Copyright (C) 2013-2014 Canonical, Ltd.
4762+ *
4763+ * This program is free software; you can redistribute it and/or modify
4764+ * it under the terms of the GNU General Public License as published by
4765+ * the Free Software Foundation; version 3.
4766+ *
4767+ * This program is distributed in the hope that it will be useful,
4768+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4769+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4770+ * GNU General Public License for more details.
4771+ *
4772+ * You should have received a copy of the GNU General Public License
4773+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4774+ */
4775+
4776+import QtQuick 2.3
4777+import Ubuntu.Components 1.1
4778+import com.ubuntu.popplerqmlplugin 1.0 as PDF
4779+
4780+import "../common/utils.js" as Utils
4781+import "../upstreamComponents"
4782+
4783+PageWithBottomEdge {
4784+ id: pdfPage
4785+ title: Utils.getNameOfFile(file.path);
4786+
4787+ // Disable header auto-hide.
4788+ // TODO: Show/hide header if a user taps the page
4789+ flickable: null
4790+
4791+ // TRANSLATORS: the first argument (%1) refers to the page currently shown on the screen,
4792+ // while the second one (%2) refers to the total pages count.
4793+ property string currentPage: i18n.tr("Page %1 of %2").arg(pdfView.currentPageIndex + 1).arg(pdfView.count)
4794+
4795+ bottomEdgeTitle: i18n.tr("Contents")
4796+ bottomEdgePageComponent: PdfContentsPage {}
4797+ bottomEdgeEnabled: poppler.tocModel.count > 0
4798+
4799+ PDF.VerticalView {
4800+ id: pdfView
4801+ objectName: "pdfView"
4802+ anchors.fill: parent
4803+ spacing: units.gu(2)
4804+
4805+ clip: true
4806+ boundsBehavior: Flickable.StopAtBounds
4807+ flickDeceleration: 1500 * units.gridUnit / 8
4808+ maximumFlickVelocity: 2500 * units.gridUnit / 8
4809+
4810+ contentWidth: parent.width * _zoomHelper.scale
4811+ cacheBuffer: height * poppler.providersNumber * _zoomHelper.scale * 0.5
4812+ interactive: !pinchy.pinch.active
4813+
4814+ model: poppler
4815+ delegate: PdfViewDelegate {
4816+ Component.onDestruction: DOC_VIEWER.releaseResources()
4817+ }
4818+
4819+ // FIXME: On zooming, keep the same content position.
4820+ PinchArea {
4821+ id: pinchy
4822+ anchors.fill: parent
4823+
4824+ pinch {
4825+ target: _zoomHelper
4826+ minimumScale: 1.0
4827+ maximumScale: 2.5
4828+ }
4829+
4830+ onPinchFinished: {
4831+ pdfView.returnToBounds();
4832+
4833+ // This is a bit expensive, so it's safer to put it here.
4834+ // It won't be called on desktop (where PinchArea is not used),
4835+ // but it's not a problem at the moment (our target is phone).
4836+ DOC_VIEWER.releaseResources();
4837+ }
4838+ }
4839+
4840+ Item { id: _zoomHelper }
4841+ }
4842+
4843+ Scrollbar { flickableItem: pdfView }
4844+ Scrollbar { flickableItem: pdfView; align: Qt.AlignBottom }
4845+
4846+ PDF.Document {
4847+ id: poppler
4848+
4849+ property bool isLoading: true
4850+
4851+ Component.onCompleted: path = file.path
4852+ onPagesLoaded: {
4853+ isLoading = false;
4854+
4855+ var title = getDocumentInfo("Title")
4856+ if (title !== "")
4857+ pdfPage.title = title
4858+ }
4859+ }
4860+
4861+ // *** HEADER ***
4862+ state: "default"
4863+ states: PdfViewDefaultHeader {
4864+ name: "default"
4865+ targetPage: pdfPage
4866+ activityRunning: pdfView.currentPageItem.status == Image.Loading || poppler.isLoading
4867+ }
4868+}
4869
4870=== added file 'src/app/qml/pdfView/PdfViewDefaultHeader.qml'
4871--- src/app/qml/pdfView/PdfViewDefaultHeader.qml 1970-01-01 00:00:00 +0000
4872+++ src/app/qml/pdfView/PdfViewDefaultHeader.qml 2015-03-03 16:49:59 +0000
4873@@ -0,0 +1,96 @@
4874+/*
4875+ * Copyright (C) 2014-2015 Canonical, Ltd.
4876+ *
4877+ * This program is free software; you can redistribute it and/or modify
4878+ * it under the terms of the GNU General Public License as published by
4879+ * the Free Software Foundation; version 3.
4880+ *
4881+ * This program is distributed in the hope that it will be useful,
4882+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4883+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4884+ * GNU General Public License for more details.
4885+ *
4886+ * You should have received a copy of the GNU General Public License
4887+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4888+ */
4889+
4890+import QtQuick 2.3
4891+import Ubuntu.Components 1.1
4892+import QtQuick.Layouts 1.1
4893+import Ubuntu.Components.Popups 1.0
4894+
4895+PageHeadState {
4896+ id: rootItem
4897+
4898+ property Page targetPage
4899+ property alias activityRunning: activity.running
4900+
4901+ head: targetPage.head
4902+
4903+ contents: RowLayout {
4904+ anchors.fill: parent
4905+ spacing: units.gu(1)
4906+
4907+ ActivityIndicator { id: activity }
4908+
4909+ Column {
4910+ id: layout
4911+ Layout.fillWidth: true
4912+
4913+ Label {
4914+ width: parent.width
4915+ //horizontalAlignment: Text.AlignHCenter
4916+ elide: Text.ElideMiddle
4917+
4918+ font.weight: Font.DemiBold
4919+ text: targetPage.title
4920+ }
4921+ Label {
4922+ width: parent.width
4923+ //horizontalAlignment: Text.AlignHCenter
4924+ elide: Text.ElideMiddle
4925+
4926+ fontSize: "small"
4927+ text: targetPage.currentPage
4928+ }
4929+ }
4930+ }
4931+
4932+ backAction: Action {
4933+ iconName: "back"
4934+ text: (pageStack.depth > 1) ? i18n.tr("Back") : i18n.tr("Close")
4935+ onTriggered: {
4936+ if (pageStack.depth > 1) {
4937+ // Go back to Welcome page
4938+ pageStack.pop();
4939+ } else {
4940+ // File has been imported through Content Hub (or was not chosen through WelcomePage)
4941+ // Close the application and show our source app (e.g. ubuntu-filemanager-app, if used to open a document)
4942+ Qt.quit()
4943+ }
4944+ }
4945+ }
4946+
4947+ actions: [
4948+ Action {
4949+ iconName: "search"
4950+ // onTriggered: pageMain.state = "search"
4951+ //Disable it until we provide search in Poppler plugin.
4952+ enabled: false
4953+ },
4954+
4955+ Action {
4956+ objectName:"gotopage"
4957+ iconName: "browser-tabs"
4958+ text: "Go to page..."
4959+ onTriggered: PopupUtils.open(Qt.resolvedUrl("PdfViewGotoDialog.qml"), targetPage)
4960+ },
4961+
4962+ Action {
4963+ objectName: "detailsAction"
4964+ text: i18n.tr("Details")
4965+ iconName: "info"
4966+ onTriggered: pageStack.push(Qt.resolvedUrl("../common/DetailsPage.qml"))
4967+ }
4968+ ]
4969+}
4970
4971=== added file 'src/app/qml/pdfView/PdfViewDelegate.qml'
4972--- src/app/qml/pdfView/PdfViewDelegate.qml 1970-01-01 00:00:00 +0000
4973+++ src/app/qml/pdfView/PdfViewDelegate.qml 2015-03-03 16:49:59 +0000
4974@@ -0,0 +1,95 @@
4975+/*
4976+ * Copyright (C) 2013-2015 Canonical, Ltd.
4977+ *
4978+ * This program is free software; you can redistribute it and/or modify
4979+ * it under the terms of the GNU General Public License as published by
4980+ * the Free Software Foundation; version 3.
4981+ *
4982+ * This program is distributed in the hope that it will be useful,
4983+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4984+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4985+ * GNU General Public License for more details.
4986+ *
4987+ * You should have received a copy of the GNU General Public License
4988+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4989+ */
4990+import QtQuick 2.3
4991+import Ubuntu.Components 1.1
4992+
4993+Rectangle {
4994+ id: pdfPage
4995+
4996+ property int index: model.index
4997+ property bool _previewFetched: false
4998+
4999+ property alias status: pageImg.status
5000+
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches