Merge lp:~ibelieve/ubuntu-filemanager-app/better-desktop-support into lp:ubuntu-filemanager-app

Proposed by Michael Spencer
Status: Merged
Approved by: Michael Spencer
Approved revision: 118
Merged at revision: 132
Proposed branch: lp:~ibelieve/ubuntu-filemanager-app/better-desktop-support
Merge into: lp:ubuntu-filemanager-app
Diff against target: 5148 lines (+2825/-1942)
41 files modified
CMakeLists.txt (+1/-6)
ConfirmDialog.qml (+0/-60)
ConfirmDialogWithInput.qml (+0/-70)
FileActionDialog.qml (+0/-60)
FileDetailsPopover.qml (+0/-140)
FileOperationProgressDialog.qml (+0/-86)
FolderListDelegate.qml (+0/-36)
FolderListPage.qml (+0/-498)
FolderListView.qml (+0/-204)
GoToDialog.qml (+0/-79)
NotifyDialog.qml (+0/-30)
PlacesPopover.qml (+0/-140)
PlacesSidebar.qml (+0/-105)
SettingsPage.qml (+0/-48)
Sidebar.qml (+0/-143)
VerticalDivider.qml (+0/-46)
ViewPopover.qml (+0/-133)
components/AutoSpacedGrid.qml (+102/-0)
components/FolderIconDelegate.qml (+152/-0)
components/FolderIconView.qml (+88/-0)
components/FolderListDelegate.qml (+37/-0)
components/FolderListView.qml (+54/-0)
components/PathBar.qml (+140/-0)
components/PlacesSidebar.qml (+128/-0)
components/Sidebar.qml (+143/-0)
components/SuruSheetStyle.qml (+150/-0)
components/VerticalDivider.qml (+46/-0)
tests/autopilot/ubuntu_filemanager_app/emulators.py (+110/-12)
tests/autopilot/ubuntu_filemanager_app/tests/test_filemanager.py (+4/-17)
ubuntu-filemanager-app.qml (+71/-29)
ui/ConfirmDialog.qml (+60/-0)
ui/ConfirmDialogWithInput.qml (+70/-0)
ui/FileActionDialog.qml (+60/-0)
ui/FileDetailsPopover.qml (+140/-0)
ui/FileOperationProgressDialog.qml (+86/-0)
ui/FolderListPage.qml (+721/-0)
ui/GoToDialog.qml (+84/-0)
ui/NotifyDialog.qml (+30/-0)
ui/PlacesPopover.qml (+140/-0)
ui/SettingsSheet.qml (+53/-0)
ui/ViewPopover.qml (+155/-0)
To merge this branch: bzr merge lp:~ibelieve/ubuntu-filemanager-app/better-desktop-support
Reviewer Review Type Date Requested Status
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Victor Thompson (community) Approve
Ubuntu File Manager Developers Pending
Review via email: mp+198165@code.launchpad.net

Commit message

Added desktop features, including multiple tabs, icon view, and a path bar.

Description of the change

This adds the following features:

 * Multiple tabs
 * Icon view
 * A path bar
 * Collapsible sidebar
 * Keyboard support for going to a location (Ctrl+L), same as Nautilus

To post a comment you must log in.
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
104. By Michael Spencer

Added back wideAspect property

Revision history for this message
Victor Thompson (vthompson) wrote :

Here are a few things that need fixing or may be desirable:
1. The Grid can't be swiped up or down if the user clicks/touches an icon and tried to flick the view up or down.
2. Clicking the Settings icon for the first time doesn't have the intended effect any more. Previously the Component.onComplete function had a push and pop of the Settings page that fixed this.
3. I think a long press on a folder should allow the user to open it up in a new tab.
4. I don't get how the "tabsPopover" actions can be called. How does one produce that pop over?
5. I think it'd be best if the "Path bar" didn't have the large whitespace in between the path and the edit icon. I think the edit icon should align either be to the left of the path or to the immediate right with no whitespace.

review: Needs Fixing
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Spencer (ibelieve) wrote :

Hi Victor,

Sorry I haven't responded to your feedback until now. I finally had some spare time and got my development VM set up again, so I'm back in business!

I'll work on fixing (1), (2), and (5). Here are the answers to your other feedback:

3) Long press is already used on a touch device as the equivalent to a right-click, and doing so opens a popover with options for the current folder.

4) That is accessed by the "Tabs" toolbar button.

105. By Michael Spencer

Various fixes

106. By Michael Spencer

Fixed the pathbar width

107. By Michael Spencer

Animations for the path bar and removed the Unix-style directory header

Revision history for this message
Michael Spencer (ibelieve) wrote :

Okay, (2) and (5) are fixed. As for (1), I'm able to drag while on top of an icon most of the time. Not sure why it doesn't work all the time. I've already set the MouseView to progagate events.

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Victor Thompson (vthompson) wrote :

For (1) it seems like the first click and drag on an icon does not allow you to scroll, but subsequent attempts on the same icon do. I think this is probably good enough and that can be fixed later. A user on the desktop would most likely use a mouse scroll bar--tablet support would need the click and drag on an icon so it isn't *that* important at the moment, IMO. 14.04 would be a good target.

review: Approve
108. By Michael Spencer

Merged in master

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
109. By Michael Spencer

Working on fixing AP tests

110. By Michael Spencer

Merged in master

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
111. By Michael Spencer

More AP test fixes

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
112. By Michael Spencer

Fixed Cmake file

113. By Michael Spencer

Fixed some problems with the list header

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
114. By Michael Spencer

Fixed pep8 errors

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
115. By Michael Spencer

Added files to CMakeList

116. By Michael Spencer

Refactored files into sub-directories

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
117. By Michael Spencer

Fixed a few problems

118. By Michael Spencer

Removed old test

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

I'm top-approving this myself since Victor has already approved it.

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 2014-02-13 02:52:22 +0000
3+++ CMakeLists.txt 2014-02-19 00:47:29 +0000
4@@ -47,12 +47,7 @@
5 file(GLOB SRC_FILES
6 RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
7 *.qml *.js *.png *.js *.json)
8-install(DIRECTORY icons DESTINATION ${DATA_DIR})
9-install(FILES Sidebar.qml GoToDialog.qml ViewPopover.qml NotifyDialog.qml
10- SettingsPage.qml ConfirmDialog.qml PlacesPopover.qml PlacesSidebar.qml
11- FolderListPage.qml FolderListView.qml VerticalDivider.qml
12- FileActionDialog.qml FileDetailsPopover.qml FolderListDelegate.qml
13- ConfirmDialogWithInput.qml FileOperationProgressDialog.qml
14+install(DIRECTORY ui components icons
15 DESTINATION ${DATA_DIR})
16 install(FILES ${MAIN_QML} DESTINATION ${DATA_DIR})
17
18
19=== removed file 'ConfirmDialog.qml'
20--- ConfirmDialog.qml 2013-07-11 22:40:40 +0000
21+++ ConfirmDialog.qml 1970-01-01 00:00:00 +0000
22@@ -1,60 +0,0 @@
23-/*
24- * Copyright (C) 2013 Canonical Ltd
25- *
26- * This program is free software: you can redistribute it and/or modify
27- * it under the terms of the GNU General Public License version 3 as
28- * published by the Free Software Foundation.
29- *
30- * This program is distributed in the hope that it will be useful,
31- * but WITHOUT ANY WARRANTY; without even the implied warranty of
32- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33- * GNU General Public License for more details.
34- *
35- * You should have received a copy of the GNU General Public License
36- * along with this program. If not, see <http://www.gnu.org/licenses/>.
37- *
38- * Authored by: Arto Jalkanen <ajalkane@gmail.com>
39- */
40-import QtQuick 2.0
41-import Ubuntu.Components 0.1
42-import Ubuntu.Components.Popups 0.1
43-
44-Dialog {
45- id: root
46-
47- signal accepted
48- signal rejected
49-
50- Button {
51- id: okButton
52- objectName: "okButton"
53- text: i18n.tr("Ok")
54- onClicked: {
55- accepted()
56- PopupUtils.close(root)
57- }
58- }
59-
60- Button {
61- id: cancelButton
62- objectName: "cancelButton"
63- text: i18n.tr("Cancel")
64-
65- gradient: Gradient {
66- GradientStop {
67- position: 0
68- color: "gray"
69- }
70-
71- GradientStop {
72- position: 1
73- color: "lightgray"
74- }
75- }
76-
77- onClicked: {
78- rejected()
79- PopupUtils.close(root)
80- }
81- }
82-}
83
84=== removed file 'ConfirmDialogWithInput.qml'
85--- ConfirmDialogWithInput.qml 2013-07-04 20:33:07 +0000
86+++ ConfirmDialogWithInput.qml 1970-01-01 00:00:00 +0000
87@@ -1,70 +0,0 @@
88-/*
89- * Copyright (C) 2013 Canonical Ltd
90- *
91- * This program is free software: you can redistribute it and/or modify
92- * it under the terms of the GNU General Public License version 3 as
93- * published by the Free Software Foundation.
94- *
95- * This program is distributed in the hope that it will be useful,
96- * but WITHOUT ANY WARRANTY; without even the implied warranty of
97- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
98- * GNU General Public License for more details.
99- *
100- * You should have received a copy of the GNU General Public License
101- * along with this program. If not, see <http://www.gnu.org/licenses/>.
102- *
103- * Authored by: Arto Jalkanen <ajalkane@gmail.com>
104- */
105-import QtQuick 2.0
106-import Ubuntu.Components 0.1
107-import Ubuntu.Components.Popups 0.1
108-
109-Dialog {
110- id: root
111-
112- property alias inputText: input.text
113- property alias placeholderText: input.placeholderText
114- signal accepted
115- signal rejected
116-
117- TextField {
118- id: input
119- objectName: "inputField"
120- focus: true
121- validator: RegExpValidator {
122- regExp: /.+/
123- }
124- }
125-
126- Button {
127- objectName: "okButton"
128- text: i18n.tr("Ok")
129- enabled: input.acceptableInput
130- onClicked: {
131- accepted()
132- PopupUtils.close(root)
133- }
134- }
135-
136- Button {
137- objectName: "cancelButton"
138- text: i18n.tr("Cancel")
139-
140- gradient: Gradient {
141- GradientStop {
142- position: 0
143- color: "gray"
144- }
145-
146- GradientStop {
147- position: 1
148- color: "lightgray"
149- }
150- }
151-
152- onClicked: {
153- rejected()
154- PopupUtils.close(root)
155- }
156- }
157-}
158
159=== removed file 'FileActionDialog.qml'
160--- FileActionDialog.qml 2013-07-12 01:18:25 +0000
161+++ FileActionDialog.qml 1970-01-01 00:00:00 +0000
162@@ -1,60 +0,0 @@
163-/*
164- * Copyright (C) 2013 Canonical Ltd
165- *
166- * This program is free software: you can redistribute it and/or modify
167- * it under the terms of the GNU General Public License version 3 as
168- * published by the Free Software Foundation.
169- *
170- * This program is distributed in the hope that it will be useful,
171- * but WITHOUT ANY WARRANTY; without even the implied warranty of
172- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
173- * GNU General Public License for more details.
174- *
175- * You should have received a copy of the GNU General Public License
176- * along with this program. If not, see <http://www.gnu.org/licenses/>.
177- *
178- * Authored by: Arto Jalkanen <ajalkane@gmail.com>
179- */
180-import QtQuick 2.0
181-import Ubuntu.Components 0.1
182-import Ubuntu.Components.Popups 0.1
183-import org.nemomobile.folderlistmodel 1.0
184-
185-Dialog {
186- id: root
187-
188- property string fileName
189- property string filePath
190- property FolderListModel folderListModel
191-
192- title: i18n.tr("Choose action")
193- text: i18n.tr("For file: %1").arg(fileName)
194-
195- Button {
196- objectName: "openButton"
197- text: i18n.tr("Open")
198- onClicked: {
199- console.log("Opening file", filePath)
200- folderListModel.openPath(filePath)
201- onClicked: PopupUtils.close(root)
202- }
203- }
204-
205- Button {
206- objectName: "cancelButton"
207- text: i18n.tr("Cancel")
208- onClicked: PopupUtils.close(root)
209-
210- gradient: Gradient {
211- GradientStop {
212- position: 0
213- color: "gray"
214- }
215-
216- GradientStop {
217- position: 1
218- color: "lightgray"
219- }
220- }
221- }
222-}
223
224=== removed file 'FileDetailsPopover.qml'
225--- FileDetailsPopover.qml 2013-09-28 18:48:28 +0000
226+++ FileDetailsPopover.qml 1970-01-01 00:00:00 +0000
227@@ -1,140 +0,0 @@
228-/*
229- * Copyright (C) 2013 Canonical Ltd
230- *
231- * This program is free software: you can redistribute it and/or modify
232- * it under the terms of the GNU General Public License version 3 as
233- * published by the Free Software Foundation.
234- *
235- * This program is distributed in the hope that it will be useful,
236- * but WITHOUT ANY WARRANTY; without even the implied warranty of
237- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
238- * GNU General Public License for more details.
239- *
240- * You should have received a copy of the GNU General Public License
241- * along with this program. If not, see <http://www.gnu.org/licenses/>.
242- *
243- * Authored by: Arto Jalkanen <ajalkane@gmail.com>
244- */
245-import QtQuick 2.0
246-import Ubuntu.Components 0.1
247-import Ubuntu.Components.Popups 0.1
248-
249-Popover {
250- id: root
251- property var model
252-
253- property string path: model.path || (fileView.path + '/' + model.fileName)
254-
255- contentHeight: contents.height + 2 * contents.anchors.margins
256-
257- function dateTimeFormat(dateTime) {
258- return Qt.formatDateTime(dateTime, Qt.DefaultLocaleShortDate) || "Unknown"
259- }
260-
261- function permissionsToString(model) {
262- var permissions = []
263- if (model.isReadable) {
264- permissions.push(i18n.tr("Readable"))
265- }
266- if (pathIsWritable()) {
267- permissions.push(i18n.tr("Writable"))
268- }
269- if (model.isExecutable) {
270- permissions.push(i18n.tr("Executable"))
271- }
272-
273- // Now why does this not work?
274- // return permissions.join(", ")
275- var permStr = ""
276- for (var i = 0; i < permissions.length; ++i) {
277- if (permStr.length > 0) {
278- permStr += ", "
279- }
280- permStr += permissions[i]
281- }
282- return permStr
283- }
284-
285- Column {
286- id: contents
287- spacing: units.gu(1)
288- anchors {
289- margins: units.gu(2)
290- left: parent.left
291- right: parent.right
292- top: parent.top
293- }
294-
295- Row {
296- spacing: units.gu(1)
297- Image {
298- anchors.verticalCenter: parent.verticalCenter
299-
300- // TODO: how to get proper icon?
301- source: fileIcon(root.path, model.isDir)
302- }
303-
304- Label {
305- anchors.verticalCenter: parent.verticalCenter
306-
307- text: folderName(root.path)
308- color: Theme.palette.normal.overlayText
309- font.bold: true
310- }
311- }
312-
313- Grid {
314- columns: 2
315- spacing: units.gu(1)
316-
317- Label {
318- text: i18n.tr("Path:")
319- color: Theme.palette.normal.overlayText
320- }
321-
322- Label {
323- objectName: "pathLabel"
324- text: root.path
325- color: Theme.palette.normal.overlayText
326- }
327-
328- Label {
329- text: model.isDir ? i18n.tr("Contents:")
330- : i18n.tr("Size:")
331- color: Theme.palette.normal.overlayText
332- }
333- Label {
334- text: model.fileSize
335- color: Theme.palette.normal.overlayText
336- }
337-
338- Label {
339- text: i18n.tr("Accessed:")
340- color: Theme.palette.normal.overlayText
341- }
342- Label {
343- text: dateTimeFormat(pathAccessedDate())
344- color: Theme.palette.normal.overlayText
345- }
346-
347- Label {
348- text: i18n.tr("Modified:")
349- color: Theme.palette.normal.overlayText
350- }
351- Label {
352- text: dateTimeFormat(pathModifiedDate())
353- color: Theme.palette.normal.overlayText
354- }
355-
356- Label {
357- text: i18n.tr("Permissions:")
358- color: Theme.palette.normal.overlayText
359- }
360- Label {
361- text: permissionsToString(model)
362- color: Theme.palette.normal.overlayText
363- }
364-
365- }
366- }
367-}
368
369=== removed file 'FileOperationProgressDialog.qml'
370--- FileOperationProgressDialog.qml 2013-09-17 16:40:38 +0000
371+++ FileOperationProgressDialog.qml 1970-01-01 00:00:00 +0000
372@@ -1,86 +0,0 @@
373-/*
374- * Copyright (C) 2013 Canonical Ltd
375- *
376- * This program is free software: you can redistribute it and/or modify
377- * it under the terms of the GNU General Public License version 3 as
378- * published by the Free Software Foundation.
379- *
380- * This program is distributed in the hope that it will be useful,
381- * but WITHOUT ANY WARRANTY; without even the implied warranty of
382- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
383- * GNU General Public License for more details.
384- *
385- * You should have received a copy of the GNU General Public License
386- * along with this program. If not, see <http://www.gnu.org/licenses/>.
387- *
388- * Authored by: Arto Jalkanen <ajalkane@gmail.com>
389- */
390-import QtQuick 2.0
391-import Ubuntu.Components 0.1
392-import Ubuntu.Components.Popups 0.1
393-import org.nemomobile.folderlistmodel 1.0
394-
395-Dialog {
396- id: root
397- property FolderListModel model
398- property Page page
399- property string descriptionPrepend: i18n.tr("Operation in progress")
400-
401- title: "File operation"
402- text: descriptionPrepend
403-
404- function startOperation(name) {
405- root.title = name
406- }
407-
408- ProgressBar {
409- id: progress
410- minimumValue: 0.0
411- maximumValue: 100.0
412- value: 0.0
413- }
414-
415- Button {
416- text: i18n.tr("Cancel")
417- onClicked: {
418- console.log("Cancelling file progress action")
419- model.cancelAction()
420- PopupUtils.close(root)
421- }
422- }
423-
424- Connections {
425- target: model
426- onProgress: {
427- // curItem == 0 && percent == 0 means the Action has just been created, check getProgressCounter() before
428- if (curItem == 0 && percent == 0) {
429- console.log("Creating dialog:", model.getProgressCounter())
430- if (model.getProgressCounter() > 20) {
431- // show/activate/make visible the dialog here
432- print("Showing dialog...")
433- PopupUtils.open(root, page)
434- root.show()
435- }
436- }
437-
438- console.log("On progress ", curItem, totalItems, percent)
439-
440- progress.value = percent
441- if (percent == 100 && curItem == totalItems) {
442- console.log("All files processed, closing progress dialog")
443- //PopupUtils.close(root)
444- root.hide()
445- } else {
446- root.text = descriptionPrepend + " (" + curItem + "/" + totalItems + ")"
447- }
448- }
449- }
450-
451- // Errors from model
452- Connections {
453- target: pageModel
454- onError: {
455- PopupUtils.close(root)
456- }
457- }
458-}
459
460=== removed file 'FolderListDelegate.qml'
461--- FolderListDelegate.qml 2014-01-31 19:51:25 +0000
462+++ FolderListDelegate.qml 1970-01-01 00:00:00 +0000
463@@ -1,36 +0,0 @@
464-/*
465- * Copyright (C) 2013 Canonical Ltd
466- *
467- * This program is free software: you can redistribute it and/or modify
468- * it under the terms of the GNU General Public License version 3 as
469- * published by the Free Software Foundation.
470- *
471- * This program is distributed in the hope that it will be useful,
472- * but WITHOUT ANY WARRANTY; without even the implied warranty of
473- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
474- * GNU General Public License for more details.
475- *
476- * You should have received a copy of the GNU General Public License
477- * along with this program. If not, see <http://www.gnu.org/licenses/>.
478- *
479- * Authored by: Arto Jalkanen <ajalkane@gmail.com>
480- */
481-import QtQuick 2.0
482-import Ubuntu.Components 0.1
483-import Ubuntu.Components.ListItems 0.1 as ListItem
484-import org.nemomobile.folderlistmodel 1.0
485-
486-ListItem.Subtitled {
487- objectName: "folder" + index
488-
489- property string fileName: model.fileName
490- property string filePath: path
491-
492- text: model.fileName
493- subText: Qt.formatDateTime(model.modifiedDate, Qt.DefaultLocaleShortDate) + (!model.isDir ? ", " + fileSize : "")
494-
495- property string path: fileView.path + '/' + model.fileName
496- iconSource: fileIcon(path, model.isDir)
497- progression: model.isDir
498- iconFrame: false
499-}
500
501=== removed file 'FolderListPage.qml'
502--- FolderListPage.qml 2013-12-07 18:51:06 +0000
503+++ FolderListPage.qml 1970-01-01 00:00:00 +0000
504@@ -1,498 +0,0 @@
505-/*
506- * Copyright (C) 2013 Canonical Ltd
507- *
508- * This program is free software: you can redistribute it and/or modify
509- * it under the terms of the GNU General Public License version 3 as
510- * published by the Free Software Foundation.
511- *
512- * This program is distributed in the hope that it will be useful,
513- * but WITHOUT ANY WARRANTY; without even the implied warranty of
514- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
515- * GNU General Public License for more details.
516- *
517- * You should have received a copy of the GNU General Public License
518- * along with this program. If not, see <http://www.gnu.org/licenses/>.
519- *
520- * Authored by: Arto Jalkanen <ajalkane@gmail.com>
521- */
522-import QtQuick 2.0
523-import Ubuntu.Components 0.1
524-import Ubuntu.Components.Popups 0.1
525-import Ubuntu.Components.ListItems 0.1
526-import org.nemomobile.folderlistmodel 1.0
527-
528-Page {
529- id: folderListPage
530-
531- title: folderName(folder)
532-
533- property variant fileView: folderListPage
534-
535- property bool showHiddenFiles: false
536-
537- onShowHiddenFilesChanged: {
538- pageModel.showHiddenFiles = folderListPage.showHiddenFiles
539- }
540-
541- property string sortingMethod: "Name"
542-
543- onSortingMethodChanged: {
544- console.log("Sorting by: " + sortingMethod)
545- if (sortingMethod === "Name") {
546- pageModel.sortBy = FolderListModel.SortByName
547- } else if (sortingMethod === "Date") {
548- pageModel.sortBy = FolderListModel.SortByDate
549- } else {
550- // Something fatal happened!
551- console.log("ERROR: Invalid sort type:", sortingMethod)
552- }
553- }
554-
555- property bool sortAccending: true
556-
557- onSortAccendingChanged: {
558- console.log("Sorting accending: " + sortAccending)
559-
560- if (sortAccending) {
561- pageModel.sortOrder = FolderListModel.SortAscending
562- } else {
563- pageModel.sortOrder = FolderListModel.SortDescending
564- }
565- }
566-
567- // This stores the location using ~ to represent home
568- property string folder
569- property string homeFolder: "~"
570-
571- // This replaces ~ with the actual home folder, since the
572- // plugin doesn't recognize the ~
573- property string path: folder.replace("~", pageModel.homePath())
574-
575- function goHome() {
576- goTo(folderListPage.homeFolder)
577- }
578-
579- function goTo(location) {
580- // Since the FolderListModel returns paths using the actual
581- // home folder, this replaces with ~ before actually going
582- // to the specified folder
583- while (location !== '/' && location.substring(location.lastIndexOf('/')+1) === "") {
584- location = location.substring(0, location.length - 1)
585- }
586-
587- folderListPage.folder = location.replace(pageModel.homePath(), "~")
588- refresh()
589- }
590-
591- function refresh() {
592- pageModel.refresh()
593- }
594-
595- function pathAccessedDate() {
596- console.log("calling method pageModel.curPathAccessedDate()")
597- return pageModel.curPathAccessedDate()
598- }
599-
600- function pathModifiedDate() {
601- console.log("calling method pageModel.curPathModifiedDate()")
602- return pageModel.curPathModifiedDate()
603- }
604-
605- function pathIsWritable() {
606- console.log("calling method pageModel.curPathIsWritable()")
607- return pageModel.curPathIsWritable()
608- }
609-
610- // FIXME: hard coded path for icon, assumes Ubuntu desktop icon available.
611- // Nemo mobile has icon provider. Have to figure out what's the proper way
612- // to get "system wide" icons in Ubuntu Touch, or if we have to use
613- // icons packaged into the application. Both folder and individual
614- // files will need an icon.
615- // TODO: Remove isDir parameter and use new model functions
616- function fileIcon(file, isDir) {
617- file = file.replace(pageModel.homePath(), "~")
618- var iconPath = isDir ? "/usr/share/icons/Humanity/places/48/folder.svg"
619- : "/usr/share/icons/Humanity/mimes/48/empty.svg"
620-
621- if (file === "~") {
622- iconPath = "icons/folder-home.svg"
623- } else if (file === i18n.tr("~/Desktop")) {
624- iconPath = "/usr/share/icons/Humanity/places/48/user-desktop.svg"
625- } else if (file === i18n.tr("~/Documents")) {
626- iconPath = "/usr/share/icons/Humanity/places/48/folder-documents.svg"
627- } else if (file === i18n.tr("~/Downloads")) {
628- iconPath = "/usr/share/icons/Humanity/places/48/folder-downloads.svg"
629- } else if (file === i18n.tr("~/Music")) {
630- iconPath = "/usr/share/icons/Humanity/places/48/folder-music.svg"
631- } else if (file === i18n.tr("~/Pictures")) {
632- iconPath = "/usr/share/icons/Humanity/places/48/folder-pictures.svg"
633- } else if (file === i18n.tr("~/Public")) {
634- iconPath = "/usr/share/icons/Humanity/places/48/folder-publicshare.svg"
635- } else if (file === i18n.tr("~/Programs")) {
636- iconPath = "/usr/share/icons/Humanity/places/48/folder-system.svg"
637- } else if (file === i18n.tr("~/Templates")) {
638- iconPath = "/usr/share/icons/Humanity/places/48/folder-templates.svg"
639- } else if (file === i18n.tr("~/Videos")) {
640- iconPath = "/usr/share/icons/Humanity/places/48/folder-videos.svg"
641- } else if (file === "/") {
642- iconPath = "/usr/share/icons/Humanity/devices/48/drive-harddisk.svg"
643- }
644-
645- return Qt.resolvedUrl(iconPath)
646- }
647-
648- function folderName(folder) {
649- folder = folder.replace(pageModel.homePath(), "~")
650-
651- if (folder === folderListPage.homeFolder) {
652- return i18n.tr("Home")
653- } else if (folder === "/") {
654- return i18n.tr("File System")
655- } else {
656- return folder.substr(folder.lastIndexOf('/') + 1)
657- }
658- }
659-
660- function pathName(folder) {
661- if (folder === "/") {
662- return "/"
663- } else {
664- return folder.substr(folder.lastIndexOf('/') + 1)
665- }
666- }
667-
668- function pathExists(path) {
669- path = path.replace("~", pageModel.homePath())
670-
671- if (path === '/')
672- return true
673-
674- if(path.charAt(0) === '/') {
675- console.log("Directory: " + path.substring(0, path.lastIndexOf('/')+1))
676- repeaterModel.path = path.substring(0, path.lastIndexOf('/')+1)
677- console.log("Sub dir: " + path.substring(path.lastIndexOf('/')+1))
678- if (path.substring(path.lastIndexOf('/')+1) !== "" && !repeaterModel.cdIntoPath(path.substring(path.lastIndexOf('/')+1))) {
679- return false
680- } else {
681- return true
682- }
683- } else {
684- return false
685- }
686- }
687-
688- property bool loading: pageModel.awaitingResults
689-
690- FolderListModel {
691- id: pageModel
692-
693- path: folderListPage.path
694-
695- enableExternalFSWatcher: true
696-
697- // Properties to emulate a model entry for use by FileDetailsPopover
698- property bool isDir: true
699- property string fileName: pathName(pageModel.path)
700- property string fileSize: (folderListView.count === 1
701- ? i18n.tr("1 file")
702- : i18n.tr("%1 files").arg(folderListView.count))
703- property bool isReadable: true
704- property bool isExecutable: true
705- }
706-
707- FolderListModel {
708- id: repeaterModel
709- path: folderListPage.folder
710-
711- onPathChanged: {
712- console.log("Path: " + repeaterModel.path)
713- }
714- }
715-
716- Component {
717- id: folderActionsPopoverComponent
718- ActionSelectionPopover {
719- id: folderActionsPopover
720- objectName: "folderActionsPopover"
721-
722- grabDismissAreaEvents: true
723-
724- actions: ActionList {
725- Action {
726- text: i18n.tr("Create New Folder")
727- onTriggered: {
728- print(text)
729-
730- PopupUtils.open(createFolderDialog, folderListPage)
731- }
732- }
733-
734- // TODO: Disabled until backend supports creating files
735- // Action {
736- // text: i18n.tr("Create New File")
737- // onTriggered: {
738- // print(text)
739-
740- // PopupUtils.open(createFileDialog, root)
741- // }
742- // }
743-
744- Action {
745- text: pageModel.clipboardUrlsCounter === 0
746- ? i18n.tr("Paste")
747- : pageModel.clipboardUrlsCounter === 1
748- ? i18n.tr("Paste %1 File").arg(pageModel.clipboardUrlsCounter)
749- : i18n.tr("Paste %1 Files").arg(pageModel.clipboardUrlsCounter)
750- onTriggered: {
751- console.log("Pasting to current folder items of count " + pageModel.clipboardUrlsCounter)
752- fileOperationDialog.startOperation(i18n.tr("Paste files"))
753- pageModel.paste()
754- }
755-
756- // FIXME: This property is depreciated and doesn't seem to work!
757- //visible: pageModel.clipboardUrlsCounter > 0
758-
759- enabled: pageModel.clipboardUrlsCounter > 0
760- }
761-
762- // TODO: Disabled until support for opening apps is added
763- Action {
764- text: i18n.tr("Open in Terminal")
765- onTriggered: {
766- print(text)
767-
768- // Is this the way it will work??
769- Qt.openUrlExternally("app://terminal")
770- }
771-
772- enabled: showAdvancedFeatures && false
773- }
774-
775- Action {
776- text: i18n.tr("Properties")
777- onTriggered: {
778- print(text)
779- PopupUtils.open(Qt.resolvedUrl("FileDetailsPopover.qml"),
780- folderListPage,
781- { "model": pageModel
782- }
783- )
784- }
785- }
786- }
787-
788- delegate: Empty {
789- id: listItem
790- Label {
791- text: listItem.text
792- anchors {
793- verticalCenter: parent.verticalCenter
794- horizontalCenter: parent.horizontalCenter
795- }
796- wrapMode: Text.Wrap
797- color: Theme.palette.normal.overlayText
798- }
799-
800- /*! \internal */
801- onTriggered: folderActionsPopover.hide()
802- visible: listItem.enabled
803- height: visible ? implicitHeight : 0
804- }
805- }
806- }
807-
808- Component {
809- id: createFolderDialog
810- ConfirmDialogWithInput {
811- title: i18n.tr("Create folder")
812- text: i18n.tr("Enter name for new folder")
813-
814- onAccepted: {
815- console.log("Create folder accepted", inputText)
816- if (inputText !== '') {
817- pageModel.mkdir(inputText)
818- } else {
819- console.log("Empty directory name, ignored")
820- }
821- }
822- }
823- }
824-
825- Component {
826- id: createFileDialog
827- ConfirmDialogWithInput {
828- title: i18n.tr("Create file")
829- text: i18n.tr("Enter name for new file")
830-
831- onAccepted: {
832- console.log("Create file accepted", inputText)
833- if (inputText !== '') {
834- //FIXME: Actually create a new file!
835- } else {
836- console.log("Empty file name, ignored")
837- }
838- }
839- }
840- }
841-
842-
843-
844- tools: ToolbarItems {
845- id: toolbar
846- locked: wideAspect
847- opened: wideAspect
848-
849- onLockedChanged: opened = Qt.binding(function() { return wideAspect })
850-
851- back: ToolbarButton {
852- objectName: "up"
853- text: "Up"
854- iconSource: getIcon("up")
855- visible: folder != "/"
856- onTriggered: {
857- goTo(pageModel.parentPath)
858- }
859- }
860-
861- ToolbarButton {
862- id: actionsButton
863- objectName: "actions"
864- text: i18n.tr("Actions")
865- iconSource: getIcon("edit")
866-
867- onTriggered: {
868- print(text)
869- PopupUtils.open(folderActionsPopoverComponent, actionsButton)
870- }
871- }
872-
873- ToolbarButton {
874- text: i18n.tr("View")
875- iconSource: getIcon("properties")
876- id: optionsButton
877-
878- onTriggered: {
879- print(text)
880-
881- PopupUtils.open(Qt.resolvedUrl("ViewPopover.qml"), optionsButton)
882- }
883- }
884-
885- ToolbarButton {
886- id: goToButton
887- visible: wideAspect
888- objectName: "goTo"
889- text: i18n.tr("Go To")
890- iconSource: getIcon("location")
891- onTriggered: {
892- print(text)
893-
894- PopupUtils.open(Qt.resolvedUrl("GoToDialog.qml"), goToButton)
895- }
896- }
897-
898- ToolbarButton {
899- id: placesButton
900- visible: !wideAspect
901- objectName: "places"
902- text: i18n.tr("Places")
903- iconSource: getIcon("location")
904- onTriggered: {
905- print(text)
906-
907- PopupUtils.open(Qt.resolvedUrl("PlacesPopover.qml"), placesButton)
908- }
909- }
910-
911- ToolbarButton {
912- id: settingsButton
913- visible: wideAspect
914- objectName: "settings"
915- action: settingsAction
916- }
917- }
918-
919- flickable: !wideAspect ? folderListView : null
920-
921- onFlickableChanged: {
922- if (wideAspect) {
923- folderListView.topMargin = 0
924- } else {
925- folderListView.topMargin = units.gu(9.5)
926- }
927- }
928-
929- PlacesSidebar {
930- id: sidebar
931- objectName: "placesSidebar"
932-
933-// anchors {
934-// top: parent.top
935-// bottom: parent.bottom
936-// bottomMargin: units.gu(-2)
937-// }
938-
939- expanded: wideAspect
940- }
941-
942- FolderListView {
943- id: folderListView
944-
945- clip: true
946-
947- folderListModel: pageModel
948- anchors {
949- top: parent.top
950- bottom: parent.bottom
951- left: sidebar.right
952- right: parent.right
953- }
954- }
955-
956- Item {
957- id: contents
958-
959- anchors {
960- top: parent.top
961- bottom: parent.bottom
962- left: sidebar.right
963- right: parent.right
964- }
965-
966- Column {
967- anchors.centerIn: parent
968- Label {
969- text: i18n.tr("No files")
970- fontSize: "large"
971- visible: folderListView.count == 0 && !pageModel.awaitingResults
972- }
973- ActivityIndicator {
974- running: pageModel.awaitingResults
975- width: units.gu(8)
976- height: units.gu(8)
977- }
978- }
979- }
980-
981- // Errors from model
982- Connections {
983- target: pageModel
984- onError: {
985- console.log("FolderListModel Error Title/Description", errorTitle, errorMessage)
986- PopupUtils.open(Qt.resolvedUrl("NotifyDialog.qml"), folderListPage,
987- {
988- // Unfortunately title can not handle too long texts. TODO: bug report
989- // title: i18n.tr(errorTitle),
990- title: i18n.tr("File operation error"),
991- text: errorTitle + ": " + errorMessage
992- })
993- }
994- }
995-
996- FileOperationProgressDialog {
997- id: fileOperationDialog
998-
999- page: folderListPage
1000- model: pageModel
1001- }
1002-}
1003
1004=== removed file 'FolderListView.qml'
1005--- FolderListView.qml 2013-09-17 16:40:38 +0000
1006+++ FolderListView.qml 1970-01-01 00:00:00 +0000
1007@@ -1,204 +0,0 @@
1008-/*
1009- * Copyright (C) 2013 Canonical Ltd
1010- *
1011- * This program is free software: you can redistribute it and/or modify
1012- * it under the terms of the GNU General Public License version 3 as
1013- * published by the Free Software Foundation.
1014- *
1015- * This program is distributed in the hope that it will be useful,
1016- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1017- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1018- * GNU General Public License for more details.
1019- *
1020- * You should have received a copy of the GNU General Public License
1021- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1022- *
1023- * Authored by: Arto Jalkanen <ajalkane@gmail.com>
1024- */
1025-import QtQuick 2.0
1026-import Ubuntu.Components 0.1
1027-import Ubuntu.Components.ListItems 0.1
1028-import Ubuntu.Components.Popups 0.1
1029-import org.nemomobile.folderlistmodel 1.0
1030-
1031-ListView {
1032- id: root
1033-
1034- property FolderListModel folderListModel
1035- property string folderPath: folderListModel.path
1036- model: folderListModel
1037-
1038- header: Header {
1039- objectName: "directoryHeader"
1040- text: (root.count == 1
1041- ? i18n.tr("%1 (1 file)").arg(root.folderPath)
1042- : i18n.tr("%1 (%2 files)").arg(root.folderPath).arg(root.count))
1043- }
1044-
1045- Component {
1046- id: confirmSingleDeleteDialog
1047- ConfirmDialog {
1048- property string filePath
1049- property string fileName
1050- title: i18n.tr("Delete")
1051- text: i18n.tr("Are you sure you want to permanently delete '%1'?").arg(fileName)
1052-
1053- onAccepted: {
1054- console.log("Delete accepted for filePath, fileName", filePath, fileName)
1055-
1056- fileOperationDialog.startOperation("Deleting files")
1057- console.log("Doing delete")
1058- folderListModel.rm(filePath)
1059- }
1060- }
1061- }
1062-
1063- Component {
1064- id: confirmRenameDialog
1065- ConfirmDialogWithInput {
1066- // IMPROVE: this does not seem good: the backend excepts row and new name.
1067- // But what if new files are added/deleted in the background while user is
1068- // entering the new name? The indices change and wrong file is renamed.
1069- // Perhaps the backend should take as parameters the "old name" and "new name"?
1070- // This is not currently a problem since the backend does not poll changes in
1071- // the filesystem, but may be a problem in the future.
1072- property int modelRow
1073-
1074- title: i18n.tr("Rename")
1075- text: i18n.tr("Enter a new name")
1076-
1077- onAccepted: {
1078- console.log("Rename accepted", inputText)
1079- if (inputText !== '') {
1080- console.log("Rename commensed, modelRow/inputText", modelRow, inputText)
1081- if (pageModel.rename(modelRow, inputText) === false) {
1082- PopupUtils.open(Qt.resolvedUrl("NotifyDialog.qml"), delegate,
1083- {
1084- title: i18n.tr("Could not rename"),
1085- text: i18n.tr("Insufficient permissions or name already exists?")
1086- })
1087-
1088- }
1089- } else {
1090- console.log("Empty new name given, ignored")
1091- }
1092- }
1093- }
1094- }
1095-
1096- Component {
1097- id: actionSelectionPopoverComponent
1098-
1099- ActionSelectionPopover {
1100- id: actionSelectionPopover
1101- objectName: "fileActionsPopover"
1102-
1103- grabDismissAreaEvents: true
1104-
1105- property var model
1106- actions: ActionList {
1107- Action {
1108- text: i18n.tr("Cut")
1109- // TODO: temporary
1110- iconSource: "/usr/share/icons/Humanity/actions/48/edit-cut.svg"
1111- onTriggered: {
1112- console.log("Cut on row called for", actionSelectionPopover.model.fileName, actionSelectionPopover.model.index)
1113- pageModel.cutIndex(actionSelectionPopover.model.index)
1114- console.log("CliboardUrlsCounter after copy", folderListModel.clipboardUrlsCounter)
1115- }
1116- }
1117-
1118- Action {
1119- text: i18n.tr("Copy")
1120- // TODO: temporary.
1121- iconSource: "/usr/share/icons/Humanity/actions/48/edit-copy.svg"
1122-
1123- onTriggered: {
1124- console.log("Copy on row called for", actionSelectionPopover.model.fileName, actionSelectionPopover.model.index)
1125- pageModel.copyIndex(actionSelectionPopover.model.index)
1126- console.log("CliboardUrlsCounter after copy", folderListModel.clipboardUrlsCounter)
1127- }
1128- }
1129-
1130- Action {
1131- text: i18n.tr("Delete")
1132- // TODO: temporary
1133- iconSource: "/usr/share/icons/Humanity/actions/48/edit-delete.svg"
1134- onTriggered: {
1135- print(text)
1136- PopupUtils.open(confirmSingleDeleteDialog, actionSelectionPopover.caller,
1137- { "filePath" : actionSelectionPopover.model.filePath,
1138- "fileName" : actionSelectionPopover.model.fileName }
1139- )
1140- }
1141- }
1142-
1143- Action {
1144- text: i18n.tr("Rename")
1145- // TODO: temporary
1146- iconSource: "/usr/share/icons/Humanity/actions/48/rotate.svg"
1147- onTriggered: {
1148- print(text)
1149- PopupUtils.open(confirmRenameDialog, actionSelectionPopover.caller,
1150- { "modelRow" : actionSelectionPopover.model.index,
1151- "inputText" : actionSelectionPopover.model.fileName
1152- })
1153- }
1154- }
1155-
1156- Action {
1157- text: i18n.tr("Properties")
1158- onTriggered: {
1159- print(text)
1160- PopupUtils.open(Qt.resolvedUrl("FileDetailsPopover.qml"),
1161- actionSelectionPopover.caller,
1162- { "model": actionSelectionPopover.model
1163- }
1164- )
1165- }
1166- }
1167- }
1168- }
1169- }
1170-
1171- delegate: FolderListDelegate {
1172- id: delegate
1173-
1174- onClicked: {
1175- if (model.isDir) {
1176- if (model.isReadable && model.isExecutable) {
1177- console.log("Changing to dir", model.filePath)
1178- goTo(model.filePath)
1179- } else {
1180- PopupUtils.open(Qt.resolvedUrl("NotifyDialog.qml"), delegate,
1181- {
1182- title: i18n.tr("Folder not accessible"),
1183- text: i18n.tr("Can not access ") + model.fileName
1184-
1185- })
1186- }
1187- } else {
1188- console.log("Non dir clicked")
1189- PopupUtils.open(Qt.resolvedUrl("FileActionDialog.qml"), root,
1190- {
1191- fileName: model.fileName,
1192- filePath: model.filePath,
1193- folderListModel: root.folderListModel
1194- })
1195- }
1196- }
1197-
1198- onPressAndHold: {
1199- console.log("FolderListDelegate onPressAndHold")
1200- PopupUtils.open(actionSelectionPopoverComponent, delegate,
1201- {
1202- model: model
1203- })
1204- }
1205- }
1206-
1207- Scrollbar {
1208- flickableItem: root
1209- align: Qt.AlignTrailing
1210- }
1211-}
1212
1213=== removed file 'GoToDialog.qml'
1214--- GoToDialog.qml 2013-11-25 21:16:38 +0000
1215+++ GoToDialog.qml 1970-01-01 00:00:00 +0000
1216@@ -1,79 +0,0 @@
1217-/*
1218- * Copyright (C) 2013 Canonical Ltd
1219- *
1220- * This program is free software: you can redistribute it and/or modify
1221- * it under the terms of the GNU General Public License version 3 as
1222- * published by the Free Software Foundation.
1223- *
1224- * This program is distributed in the hope that it will be useful,
1225- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1226- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1227- * GNU General Public License for more details.
1228- *
1229- * You should have received a copy of the GNU General Public License
1230- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1231- *
1232- * Authored by: Michael Spencer <sonrisesoftware@gmail.com>
1233- */
1234-import QtQuick 2.0
1235-import Ubuntu.Components 0.1
1236-import Ubuntu.Components.Popups 0.1
1237-
1238-Dialog {
1239- id: root
1240-
1241- title: i18n.tr("Go To Location")
1242-
1243- text: i18n.tr("Enter a location to go to:")
1244-
1245- TextField {
1246- id: locationField
1247- objectName: "inputField"
1248-
1249- inputMethodHints: Qt.ImhNoAutoUppercase
1250-
1251- property bool valid: pathExists(text)
1252-
1253- text: fileView.path
1254-
1255- placeholderText: i18n.tr("Location...")
1256-
1257- onAccepted: goButton.clicked()
1258- }
1259-
1260- Button {
1261- id: goButton
1262- objectName: "okButton"
1263-
1264- text: i18n.tr("Go")
1265- enabled: locationField.acceptableInput && locationField.valid
1266-
1267- onClicked: {
1268- print("User switched to:", locationField.text)
1269- goTo(locationField.text)
1270- PopupUtils.close(root)
1271- }
1272- }
1273-
1274- Button {
1275- id: cancelButton
1276- objectName: "cancelButton"
1277- text: i18n.tr("Cancel")
1278-
1279- gradient: Gradient {
1280- GradientStop {
1281- position: 0
1282- color: "gray"
1283- }
1284-
1285- GradientStop {
1286- position: 1
1287- color: "lightgray"
1288- }
1289- }
1290-
1291- onClicked: {
1292- PopupUtils.close(root)
1293- }
1294- }
1295-}
1296
1297=== removed file 'NotifyDialog.qml'
1298--- NotifyDialog.qml 2013-04-17 17:55:41 +0000
1299+++ NotifyDialog.qml 1970-01-01 00:00:00 +0000
1300@@ -1,30 +0,0 @@
1301-/*
1302- * Copyright (C) 2013 Canonical Ltd
1303- *
1304- * This program is free software: you can redistribute it and/or modify
1305- * it under the terms of the GNU General Public License version 3 as
1306- * published by the Free Software Foundation.
1307- *
1308- * This program is distributed in the hope that it will be useful,
1309- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1310- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1311- * GNU General Public License for more details.
1312- *
1313- * You should have received a copy of the GNU General Public License
1314- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1315- *
1316- * Authored by: Arto Jalkanen <ajalkane@gmail.com>
1317- */
1318-import QtQuick 2.0
1319-import Ubuntu.Components 0.1
1320-import Ubuntu.Components.Popups 0.1
1321-
1322-Dialog {
1323- id: root
1324- Button {
1325- text: i18n.tr("Ok")
1326- onClicked: {
1327- PopupUtils.close(root)
1328- }
1329- }
1330-}
1331
1332=== removed file 'PlacesPopover.qml'
1333--- PlacesPopover.qml 2014-01-31 19:51:25 +0000
1334+++ PlacesPopover.qml 1970-01-01 00:00:00 +0000
1335@@ -1,140 +0,0 @@
1336-/*
1337- * Copyright (C) 2013 Canonical Ltd
1338- *
1339- * This program is free software: you can redistribute it and/or modify
1340- * it under the terms of the GNU General Public License version 3 as
1341- * published by the Free Software Foundation.
1342- *
1343- * This program is distributed in the hope that it will be useful,
1344- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1345- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1346- * GNU General Public License for more details.
1347- *
1348- * You should have received a copy of the GNU General Public License
1349- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1350- *
1351- * Authored by: Michael Spencer <sonrisesoftware@gmail.com>
1352- */
1353-import QtQuick 2.0
1354-import Ubuntu.Components 0.1
1355-import Ubuntu.Components.Popups 0.1
1356-import Ubuntu.Components.ListItems 0.1
1357-
1358-Popover {
1359- id: root
1360- objectName: "placesPopover"
1361-
1362- ListModel {
1363- id: places
1364-
1365- ListElement {
1366- path: "~"
1367- }
1368-
1369- ListElement {
1370- path: "~/Documents"
1371- }
1372-
1373- ListElement {
1374- path: "~/Downloads"
1375- }
1376-
1377- ListElement {
1378- path: "~/Music"
1379- }
1380-
1381- ListElement {
1382- path: "~/Pictures"
1383- }
1384-
1385- ListElement {
1386- path: "~/Videos"
1387- }
1388-
1389- ListElement {
1390- path: "/"
1391- }
1392- }
1393-
1394- Column {
1395- anchors {
1396- left: parent.left
1397- right: parent.right
1398- top: parent.top
1399- }
1400-
1401- Empty {
1402-
1403- TextField {
1404- id: locationField
1405- objectName: "inputField"
1406- anchors {
1407- verticalCenter: parent.verticalCenter
1408- left: parent.left
1409- right: goButton.left
1410- margins: units.gu(1)
1411- }
1412-
1413- inputMethodHints: Qt.ImhNoAutoUppercase
1414-
1415- property bool valid: pathExists(text)
1416-
1417- text: fileView.path
1418-
1419- placeholderText: i18n.tr("Location...")
1420-
1421- onAccepted: goButton.clicked()
1422- }
1423-
1424- Button {
1425- id: goButton
1426- objectName: "okButton"
1427- anchors {
1428- top: locationField.top
1429- bottom: locationField.bottom
1430- right: parent.right
1431- rightMargin: units.gu(1)
1432- }
1433-
1434- text: i18n.tr("Go")
1435- enabled: locationField.acceptableInput && locationField.valid
1436-
1437- onClicked: {
1438- print("User switched to:", locationField.text)
1439- goTo(locationField.text)
1440- PopupUtils.close(root)
1441- }
1442- }
1443- }
1444-
1445- Repeater {
1446- id: placesList
1447- objectName: "placesList"
1448-
1449- model: places
1450-
1451- delegate: Standard {
1452- property string name: folderName(path)
1453-
1454- Label {
1455- anchors.left: parent.left
1456- anchors.leftMargin: units.gu(8)
1457- anchors.verticalCenter: parent.verticalCenter
1458- text: folderName(path)
1459- color: selected ? UbuntuColors.orange : Theme.palette.normal.overlayText
1460- }
1461-
1462- iconSource: model.icon || fileIcon(model.path, true)
1463-
1464- onClicked: {
1465- PopupUtils.close(root)
1466- goTo(model.path)
1467- }
1468-
1469- selected: folder === path
1470- iconFrame: false
1471- showDivider: index < (placesList.count - 1)
1472- }
1473- }
1474- }
1475-}
1476
1477=== removed file 'PlacesSidebar.qml'
1478--- PlacesSidebar.qml 2014-01-31 19:51:25 +0000
1479+++ PlacesSidebar.qml 1970-01-01 00:00:00 +0000
1480@@ -1,105 +0,0 @@
1481-/*
1482- * Copyright (C) 2013 Canonical Ltd
1483- *
1484- * This program is free software: you can redistribute it and/or modify
1485- * it under the terms of the GNU General Public License version 3 as
1486- * published by the Free Software Foundation.
1487- *
1488- * This program is distributed in the hope that it will be useful,
1489- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1490- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1491- * GNU General Public License for more details.
1492- *
1493- * You should have received a copy of the GNU General Public License
1494- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1495- *
1496- * Authored by: Michael Spencer <sonrisesoftware@gmail.com>
1497- */
1498-import QtQuick 2.0
1499-import Ubuntu.Components 0.1
1500-import Ubuntu.Components.ListItems 0.1
1501-import Ubuntu.Components.Popups 0.1
1502-
1503-Sidebar {
1504- id: root
1505-
1506- //color: Qt.rgba(0.5,0.5,0.5,0.3)
1507- width: units.gu(30)
1508-
1509- ListModel {
1510- id: places
1511-
1512- ListElement {
1513- path: "~"
1514- }
1515-
1516- ListElement {
1517- path: "~/Documents"
1518- }
1519-
1520- ListElement {
1521- path: "~/Downloads"
1522- }
1523-
1524- ListElement {
1525- path: "~/Music"
1526- }
1527-
1528- ListElement {
1529- path: "~/Pictures"
1530- }
1531-
1532- ListElement {
1533- path: "~/Videos"
1534- }
1535-
1536- ListElement {
1537- path: "/"
1538- }
1539- }
1540-
1541- Column {
1542- anchors {
1543- left: parent.left
1544- right: parent.right
1545- top: parent.top
1546- }
1547-
1548- Header {
1549-// Label {
1550-// anchors.left: parent.left
1551-// anchors.leftMargin: units.gu(1)
1552-// anchors.verticalCenter: parent.verticalCenter
1553- text: i18n.tr("Places")
1554-// color: Theme.palette.normal.overlayText
1555-// }
1556- }
1557-
1558- Repeater {
1559- id: placesList
1560- objectName: "placesList"
1561-
1562- model: places
1563-
1564- delegate: Standard {
1565-// Label {
1566-// anchors.left: parent.left
1567-// anchors.leftMargin: units.gu(8)
1568-// anchors.verticalCenter: parent.verticalCenter
1569- text: folderName(path)
1570-// color: Theme.palette.normal.overlayText
1571-// }
1572- iconSource: model.icon || fileIcon(model.path, true)
1573-
1574- onClicked: {
1575- goTo(model.path)
1576- }
1577-
1578- height: units.gu(5)
1579-
1580- selected: folder === path
1581- iconFrame: false
1582- }
1583- }
1584- }
1585-}
1586
1587=== removed file 'SettingsPage.qml'
1588--- SettingsPage.qml 2013-08-30 16:05:42 +0000
1589+++ SettingsPage.qml 1970-01-01 00:00:00 +0000
1590@@ -1,48 +0,0 @@
1591-/*
1592- * Copyright (C) 2013 Canonical Ltd
1593- *
1594- * This program is free software: you can redistribute it and/or modify
1595- * it under the terms of the GNU General Public License version 3 as
1596- * published by the Free Software Foundation.
1597- *
1598- * This program is distributed in the hope that it will be useful,
1599- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1600- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1601- * GNU General Public License for more details.
1602- *
1603- * You should have received a copy of the GNU General Public License
1604- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1605- *
1606- * Authored by: Michael Spencer <sonrisesoftware@gmail.com>
1607- */
1608-import QtQuick 2.0
1609-import Ubuntu.Components 0.1
1610-import Ubuntu.Components.ListItems 0.1
1611-import Ubuntu.Components.Popups 0.1
1612-
1613-/*
1614- * The Settings page holds global settings/preferences.
1615- *
1616- * TODO: Make sure this fits with the UI guidelines if
1617- * they are updated to include About/Settings info.
1618- */
1619-Page {
1620- id: root
1621-
1622- title: i18n.tr("Settings")
1623-
1624- Column {
1625- anchors.fill: parent
1626-
1627- Standard {
1628- text: i18n.tr("Show Advanced Features")
1629- control: CheckBox {
1630- id: showAdvancedFeaturesCheckBox
1631- checked: showAdvancedFeatures
1632- onCheckedChanged: {
1633- saveSetting("showAdvancedFeatures", showAdvancedFeaturesCheckBox.checked ? "true" : "false");
1634- }
1635- }
1636- }
1637- }
1638-}
1639
1640=== removed file 'Sidebar.qml'
1641--- Sidebar.qml 2014-02-04 20:47:28 +0000
1642+++ Sidebar.qml 1970-01-01 00:00:00 +0000
1643@@ -1,143 +0,0 @@
1644-/***************************************************************************
1645- * *
1646- * Ubuntu UI Extras - A collection of QML widgets not available *
1647- * in the default Ubuntu UI Toolkit *
1648- * Copyright (C) 2013 Michael Spencer <sonrisesoftware@gmail.com> *
1649- * *
1650- * This program is free software: you can redistribute it and/or modify *
1651- * it under the terms of the GNU General Public License as published by *
1652- * the Free Software Foundation, either version 3 of the License, or *
1653- * (at your option) any later version. *
1654- * *
1655- * This program is distributed in the hope that it will be useful, *
1656- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
1657- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
1658- * GNU General Public License for more details. *
1659- * *
1660- * You should have received a copy of the GNU General Public License *
1661- * along with this program. If not, see <http://www.gnu.org/licenses/>. *
1662- ***************************************************************************/
1663-import QtQuick 2.0
1664-import Ubuntu.Components 0.1
1665-import Ubuntu.Components.ListItems 0.1
1666-
1667-/*!
1668- \qmltype Sidebar
1669- \brief A sidebar component for use in adaptive layouts
1670-
1671- To use, simply add an instance to your code, and anchor other components to it.
1672-
1673- To show or hide, set the expanded property.
1674-
1675- By default, the sidebar has a flickable built in, and whatever contents are added
1676- will be placed in the flickable. When you want this disabled, or want to fill the
1677- entire sidebar, set the autoFill property to false.
1678-
1679- Examples:
1680- \qml
1681- property bool wideAspect: width > units.gu(80)
1682-
1683- Sidebar {
1684- expanded: wideAspect
1685-
1686- // Anchoring is automatic
1687- }
1688- \endqml
1689-*/
1690-Rectangle {
1691- id: root
1692-
1693- color: Qt.rgba(0.2,0.2,0.2,0.4)
1694-
1695- property bool expanded: true
1696-
1697- property string mode: "left" // or "right"
1698- property alias header: headerItem.text
1699-
1700- anchors {
1701- left: mode === "left" ? parent.left : undefined
1702- right: mode === "right" ? parent.right : undefined
1703- top: parent.top
1704- bottom: parent.bottom
1705- }
1706-
1707- VerticalDivider {
1708- mode: root.mode
1709-
1710- anchors {
1711- top: parent.top
1712- bottom: parent.bottom
1713- right: mode === "left" ? parent.right : undefined
1714- left: mode === "right" ? parent.left : undefined
1715- rightMargin: -1
1716- }
1717- }
1718-
1719- width: units.gu(35)
1720-
1721-
1722- anchors.leftMargin: expanded ? 0 : -width
1723- anchors.rightMargin: expanded ? 0 : -width
1724-
1725- Behavior on anchors.leftMargin {
1726- UbuntuNumberAnimation {}
1727- }
1728-
1729- Behavior on anchors.rightMargin {
1730- UbuntuNumberAnimation {}
1731- }
1732-
1733- default property alias contents: contents.data
1734-
1735- Header {
1736- id: headerItem
1737-
1738- visible: text !== ""
1739- }
1740-
1741- property bool autoFlick: true
1742-
1743- Flickable {
1744- id: flickable
1745-
1746- clip: true
1747-
1748- anchors {
1749- top: headerItem.visible ? headerItem.bottom : parent.top
1750- left: parent.left
1751- right: parent.right
1752- bottom: parent.bottom
1753- rightMargin: mode === "left" ? 1 : 0
1754- leftMargin: mode === "right" ? 1 : 0
1755- }
1756-
1757- contentWidth: width
1758- contentHeight: autoFlick ? contents.height : height
1759- interactive: contentHeight > height
1760-
1761- Item {
1762- id: contents
1763-
1764- width: flickable.width
1765- height: autoFlick ? childrenRect.height : flickable.height
1766- }
1767-
1768- function getFlickableChild(item) {
1769- if (item && item.hasOwnProperty("children")) {
1770- for (var i=0; i < item.children.length; i++) {
1771- var child = item.children[i];
1772- if (internal.isVerticalFlickable(child)) {
1773- if (child.anchors.top === page.top || child.anchors.fill === page) {
1774- return item.children[i];
1775- }
1776- }
1777- }
1778- }
1779- return null;
1780- }
1781- }
1782-
1783- Scrollbar {
1784- flickableItem: flickable
1785- }
1786-}
1787
1788=== removed file 'VerticalDivider.qml'
1789--- VerticalDivider.qml 2014-02-04 20:47:28 +0000
1790+++ VerticalDivider.qml 1970-01-01 00:00:00 +0000
1791@@ -1,46 +0,0 @@
1792-/***************************************************************************
1793- * *
1794- * Ubuntu UI Extras - A collection of QML widgets not available *
1795- * in the default Ubuntu UI Toolkit *
1796- * Copyright (C) 2013 Michael Spencer <sonrisesoftware@gmail.com> *
1797- * *
1798- * This program is free software: you can redistribute it and/or modify *
1799- * it under the terms of the GNU General Public License as published by *
1800- * the Free Software Foundation, either version 3 of the License, or *
1801- * (at your option) any later version. *
1802- * *
1803- * This program is distributed in the hope that it will be useful, *
1804- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
1805- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
1806- * GNU General Public License for more details. *
1807- * *
1808- * You should have received a copy of the GNU General Public License *
1809- * along with this program. If not, see <http://www.gnu.org/licenses/>. *
1810- ***************************************************************************/
1811-import QtQuick 2.0
1812-import Ubuntu.Components 0.1
1813-import Ubuntu.Components.ListItems 0.1
1814-import QtQuick 2.0
1815-
1816-Item {
1817- property string mode: "left" // or right
1818-
1819- ThinDivider {
1820- id: divider
1821- rotation: mode === "left" ? 90 : -90
1822-
1823- width: parent.height
1824-
1825- anchors {
1826- left: undefined
1827- right: undefined
1828- centerIn: parent
1829- }
1830- }
1831- width: divider.height
1832-
1833- anchors {
1834- top: parent ? parent.top : undefined
1835- bottom: parent ? parent.bottom : undefined
1836- }
1837-}
1838
1839=== removed file 'ViewPopover.qml'
1840--- ViewPopover.qml 2013-09-07 09:08:11 +0000
1841+++ ViewPopover.qml 1970-01-01 00:00:00 +0000
1842@@ -1,133 +0,0 @@
1843-/*
1844- * Copyright (C) 2013 Canonical Ltd
1845- *
1846- * This program is free software: you can redistribute it and/or modify
1847- * it under the terms of the GNU General Public License version 3 as
1848- * published by the Free Software Foundation.
1849- *
1850- * This program is distributed in the hope that it will be useful,
1851- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1852- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1853- * GNU General Public License for more details.
1854- *
1855- * You should have received a copy of the GNU General Public License
1856- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1857- *
1858- * Authored by: Michael Spencer <sonrisesoftware@gmail.com>
1859- */
1860-import QtQuick 2.0
1861-import Ubuntu.Components 0.1
1862-import Ubuntu.Components.Popups 0.1
1863-import Ubuntu.Components.ListItems 0.1
1864-
1865-Popover {
1866- id: root
1867- objectName: "viewPopover"
1868-
1869- Column {
1870- anchors {
1871- left: parent.left
1872- right: parent.right
1873- top: parent.top
1874- }
1875-
1876- Standard {
1877- id: showHiddenFileCheckBox
1878- objectName: "showHiddenFileCheckBox"
1879-
1880- Label {
1881- text: i18n.tr("Show Hidden Files")
1882- fontSize: "medium"
1883- color: Theme.palette.normal.overlayText
1884- anchors.left: parent.left
1885- anchors.leftMargin: units.gu(2)
1886- anchors.verticalCenter: parent.verticalCenter
1887- }
1888-
1889- control: CheckBox {
1890- anchors.verticalCenter: parent.verticalCenter
1891-
1892- checked: fileView.showHiddenFiles
1893- onCheckedChanged: {
1894- fileView.showHiddenFiles = checked
1895- }
1896- }
1897- }
1898-
1899- ValueSelector {
1900- Label {
1901- text: i18n.tr("Sort By")
1902- fontSize: "medium"
1903- color: Theme.palette.normal.overlayText
1904- anchors.left: parent.left
1905- anchors.leftMargin: units.gu(2)
1906- anchors.top: parent.top
1907- anchors.topMargin: units.gu(1.6)
1908- }
1909-
1910- selectedIndex: values.indexOf(fileView.sortingMethod)
1911- values: [
1912- i18n.tr("Name"),
1913- i18n.tr("Date")
1914- ]
1915-
1916- onSelectedIndexChanged: {
1917- fileView.sortingMethod = values[selectedIndex]
1918- }
1919- }
1920-
1921- ValueSelector {
1922- Label {
1923- text: i18n.tr("Sort Order")
1924- fontSize: "medium"
1925- color: Theme.palette.normal.overlayText
1926- anchors.left: parent.left
1927- anchors.leftMargin: units.gu(2)
1928- anchors.top: parent.top
1929- anchors.topMargin: units.gu(1.7)
1930- }
1931-
1932- selectedIndex: sortAccending ? 0 : 1
1933- values: [
1934- i18n.tr("Ascending"),
1935- i18n.tr("Descending")
1936- ]
1937-
1938- onSelectedIndexChanged: {
1939- fileView.sortAccending = (values[selectedIndex] === i18n.tr("Ascending"))
1940- }
1941- }
1942-
1943- Standard {
1944- visible: showAdvancedFeatures
1945-
1946- Label {
1947- text: i18n.tr("Filter")
1948- fontSize: "medium"
1949- color: Theme.palette.normal.overlayText
1950- anchors.left: parent.left
1951- anchors.leftMargin: units.gu(2)
1952- anchors.verticalCenter: parent.verticalCenter
1953- }
1954-
1955- TextField {
1956- id: filterField
1957- anchors {
1958- verticalCenter: parent.verticalCenter
1959- right: parent.right
1960- margins: units.gu(1)
1961- }
1962-
1963- inputMethodHints: Qt.ImhNoAutoUppercase
1964-
1965- text: pageModel.nameFilters
1966-
1967- onAccepted: goButton.clicked()
1968- onTextChanged: {
1969- if (text !== pageModel.nameFilters)
1970- pageModel.nameFilters = [text]
1971- }
1972- }
1973- }
1974- }
1975-}
1976
1977=== removed file 'avatar@8.png'
1978Binary files avatar@8.png 2013-02-12 16:18:48 +0000 and avatar@8.png 1970-01-01 00:00:00 +0000 differ
1979=== added directory 'components'
1980=== added file 'components/AutoSpacedGrid.qml'
1981--- components/AutoSpacedGrid.qml 1970-01-01 00:00:00 +0000
1982+++ components/AutoSpacedGrid.qml 2014-02-19 00:47:29 +0000
1983@@ -0,0 +1,102 @@
1984+/***************************************************************************
1985+ * Whatsoever ye do in word or deed, do all in the name of the *
1986+ * Lord Jesus, giving thanks to God and the Father by him. *
1987+ * - Colossians 3:17 *
1988+ * *
1989+ * Ubuntu UI Extras - A collection of QML widgets not available *
1990+ * in the default Ubuntu UI Toolkit *
1991+ * Copyright (C) 2013 Michael Spencer <sonrisesoftware@gmail.com> *
1992+ * *
1993+ * This program is free software: you can redistribute it and/or modify *
1994+ * it under the terms of the GNU General Public License as published by *
1995+ * the Free Software Foundation, either version 2 of the License, or *
1996+ * (at your option) any later version. *
1997+ * *
1998+ * This program is distributed in the hope that it will be useful, *
1999+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
2000+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
2001+ * GNU General Public License for more details. *
2002+ * *
2003+ * You should have received a copy of the GNU General Public License *
2004+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
2005+ ***************************************************************************/
2006+import QtQuick 2.0
2007+
2008+Item {
2009+ id: root
2010+
2011+
2012+ property int cellWidth
2013+ property int cellHeight
2014+
2015+ property int xCount
2016+ property int yCount: {
2017+ var count = cellCount/xCount
2018+ if (cellCount % xCount > 0)
2019+ count++
2020+ return count
2021+ }
2022+
2023+ height: yCount * cellHeight + (yCount - 1) * ySpacing + 2 * outerSpacing
2024+
2025+ property int cellCount
2026+
2027+ Component.onCompleted: layout()
2028+
2029+ onWidthChanged: layout()
2030+
2031+ // FIXME: A really uggly hack to get the layout right
2032+ Timer {
2033+ interval: 1
2034+ running: true
2035+ onTriggered: layout()
2036+ }
2037+
2038+ function layout() {
2039+ var count = 1
2040+ var space = calcSpacing(count)
2041+ while (space >= minSpacing) {
2042+ count++
2043+ space = calcSpacing(count)
2044+ }
2045+
2046+ count--
2047+ spacing = calcSpacing(count)
2048+ if (root.cellCount <= count) {
2049+ spacing = minSpacing
2050+ }
2051+
2052+ xCount = count
2053+ }
2054+
2055+ function calcSpacing(count) {
2056+ var spacing = (width - count * cellWidth)/(count)
2057+ print("Spacing for count", count, "is", spacing/8, "gu")
2058+ return spacing
2059+ }
2060+
2061+ property real spacing
2062+ property int minSpacing: units.gu(2)
2063+ property int outerSpacing: 1/2 * spacing
2064+ property real ySpacing: spacing
2065+
2066+ default property alias children: grid.children
2067+
2068+// Rectangle {
2069+// color: "gray"
2070+// anchors.fill: grid
2071+// }
2072+
2073+ Grid {
2074+ id: grid
2075+ anchors {
2076+ fill: parent
2077+ margins: root.outerSpacing
2078+ }
2079+
2080+ columns: xCount
2081+
2082+ columnSpacing: root.spacing
2083+ rowSpacing: root.ySpacing
2084+ }
2085+}
2086
2087=== added file 'components/FolderIconDelegate.qml'
2088--- components/FolderIconDelegate.qml 1970-01-01 00:00:00 +0000
2089+++ components/FolderIconDelegate.qml 2014-02-19 00:47:29 +0000
2090@@ -0,0 +1,152 @@
2091+/*
2092+ * Copyright (C) 2013 Canonical Ltd
2093+ *
2094+ * This program is free software: you can redistribute it and/or modify
2095+ * it under the terms of the GNU General Public License version 3 as
2096+ * published by the Free Software Foundation.
2097+ *
2098+ * This program is distributed in the hope that it will be useful,
2099+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2100+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2101+ * GNU General Public License for more details.
2102+ *
2103+ * You should have received a copy of the GNU General Public License
2104+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2105+ *
2106+ * Authored by: Michael Spencer <sonrisesoftware@gmail.com>
2107+ */
2108+import QtQuick 2.0
2109+import QtGraphicalEffects 1.0
2110+import Ubuntu.Components 0.1
2111+
2112+Item {
2113+ id: delegate
2114+ height: units.gu(11)
2115+ width: units.gu(11)
2116+
2117+ property bool selected
2118+ property alias mouseOver: mouseArea.containsMouse
2119+
2120+ Rectangle {
2121+ anchors.centerIn: parent
2122+ // anchors.verticalCenterOffset: units.gu(0.5)
2123+ height: parent.height// + units.gu(1)
2124+ width: height
2125+
2126+ radius: units.gu(2)
2127+ smooth: true
2128+ antialiasing: true
2129+ opacity: selected ? 0.5 : 0
2130+ color: UbuntuColors.orange
2131+
2132+ Behavior on opacity {
2133+ UbuntuNumberAnimation {}
2134+ }
2135+ }
2136+
2137+ objectName: "folder" + index
2138+
2139+ property string fileName: model.fileName
2140+ property string filePath: fileView.path + '/' + fileName
2141+
2142+ property string text: fileName
2143+ property string subText: Qt.formatDateTime(model.modifiedDate, Qt.DefaultLocaleShortDate) + (!model.isDir ? ", " + fileSize : "")
2144+
2145+ property var icon: fileIcon(filePath, model.isDir)
2146+
2147+ Item {
2148+ anchors {
2149+ left: parent.left
2150+ right: parent.right
2151+ top: parent.top
2152+ bottom: label.top
2153+ topMargin: units.gu(0.5)
2154+ bottomMargin: units.gu(1)
2155+ leftMargin: units.gu(1)
2156+ rightMargin: units.gu(1)
2157+ }
2158+
2159+ Image {
2160+ id: image
2161+ anchors.centerIn: parent
2162+ width: units.gu(6)
2163+ height: width
2164+
2165+ source: delegate.icon
2166+ }
2167+
2168+ BrightnessContrast {
2169+ anchors.fill: image
2170+ brightness: 0.3
2171+ source: image
2172+ opacity: mouseOver ? 1 : 0
2173+
2174+ Behavior on opacity {
2175+ UbuntuNumberAnimation {}
2176+ }
2177+ }
2178+ }
2179+
2180+ property bool expand: mouseOver && label.implicitWidth >= label.width
2181+ z: expand ? 1 : 0
2182+
2183+ Rectangle {
2184+ anchors {
2185+ fill: label
2186+ margins: units.gu(-0.5)
2187+ leftMargin: units.gu(-1)
2188+ rightMargin: units.gu(-1)
2189+ }
2190+ color: "white"
2191+ radius: height/2
2192+ border.color: UbuntuColors.warmGrey
2193+ antialiasing: true
2194+ opacity: expand ? 1 : 0
2195+
2196+ Behavior on opacity {
2197+ UbuntuNumberAnimation {}
2198+ }
2199+ }
2200+
2201+ Label {
2202+ id: label
2203+ anchors {
2204+ horizontalCenter: parent.horizontalCenter
2205+ bottom: parent.bottom
2206+ bottomMargin: units.gu(0.75)
2207+ }
2208+
2209+ width: expand ? implicitWidth : (parent.width - units.gu(0.5))
2210+
2211+ Behavior on width {
2212+ UbuntuNumberAnimation {}
2213+ }
2214+
2215+ horizontalAlignment: Text.AlignHCenter
2216+ elide: Text.ElideMiddle
2217+
2218+ text: delegate.text
2219+ color: expand ? UbuntuColors.coolGrey : Theme.palette.selected.backgroundText
2220+ Behavior on color {
2221+ ColorAnimation { duration: 200 }
2222+ }
2223+ }
2224+
2225+ MouseArea {
2226+ id: mouseArea
2227+ anchors.fill: parent
2228+ hoverEnabled: true
2229+ acceptedButtons: (Qt.LeftButton | Qt.RightButton)
2230+
2231+ onClicked: {
2232+ if (mouse.button === Qt.RightButton)
2233+ pressAndHold(mouse)
2234+ else
2235+ itemClicked(model)
2236+ }
2237+
2238+ propagateComposedEvents: true
2239+
2240+ onPressAndHold: itemLongPress(delegate, model)
2241+ }
2242+}
2243
2244=== added file 'components/FolderIconView.qml'
2245--- components/FolderIconView.qml 1970-01-01 00:00:00 +0000
2246+++ components/FolderIconView.qml 2014-02-19 00:47:29 +0000
2247@@ -0,0 +1,88 @@
2248+/*
2249+ * Copyright (C) 2013 Canonical Ltd
2250+ *
2251+ * This program is free software: you can redistribute it and/or modify
2252+ * it under the terms of the GNU General Public License version 3 as
2253+ * published by the Free Software Foundation.
2254+ *
2255+ * This program is distributed in the hope that it will be useful,
2256+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2257+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2258+ * GNU General Public License for more details.
2259+ *
2260+ * You should have received a copy of the GNU General Public License
2261+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2262+ *
2263+ * Authored by: Michael Spencer <sonrisesoftware@gmail.com>
2264+ */
2265+import QtQuick 2.0
2266+import Ubuntu.Components 0.1
2267+import Ubuntu.Components.Popups 0.1
2268+import Ubuntu.Components.ListItems 0.1 as ListItem
2269+
2270+Item {
2271+ id: root
2272+
2273+ property var folderListModel
2274+ property string folderPath: folderListModel.path
2275+ property int count: repeater.count
2276+ property Flickable flickable: flickable
2277+ property bool smallMode: !wideAspect
2278+
2279+ Flickable {
2280+ id: flickable
2281+ clip: true
2282+ anchors {
2283+ top: parent.top
2284+ left: parent.left
2285+ right: parent.right
2286+ bottom: parent.bottom
2287+ }
2288+
2289+ contentWidth: width
2290+ contentHeight: column.height
2291+
2292+ Column {
2293+ id: column
2294+
2295+ width: flickable.contentWidth
2296+ // This must be visible so Autopilot can see it
2297+ ListItem.Header {
2298+ anchors {
2299+ left: parent.left
2300+ right: parent.right
2301+ }
2302+
2303+ objectName: "iconViewHeader"
2304+ text: (root.count == 1
2305+ ? i18n.tr("%1 (1 file)").arg(root.folderPath)
2306+ : i18n.tr("%1 (%2 files)").arg(root.folderPath).arg(root.count))
2307+ height: smallMode ? units.gu(4) : 0
2308+ clip: true
2309+ }
2310+
2311+ AutoSpacedGrid {
2312+ id: grid
2313+ width: root.width
2314+
2315+ cellCount: repeater.count
2316+ cellWidth: units.gu(11)
2317+ cellHeight: units.gu(11)
2318+ minSpacing: units.gu(2)
2319+ ySpacing: 1/2 * spacing
2320+
2321+ Repeater {
2322+ id: repeater
2323+ model: folderListModel
2324+ delegate: FolderIconDelegate {
2325+
2326+ }
2327+ }
2328+ }
2329+ }
2330+ }
2331+
2332+ Scrollbar {
2333+ flickableItem: flickable
2334+ }
2335+}
2336
2337=== added file 'components/FolderListDelegate.qml'
2338--- components/FolderListDelegate.qml 1970-01-01 00:00:00 +0000
2339+++ components/FolderListDelegate.qml 2014-02-19 00:47:29 +0000
2340@@ -0,0 +1,37 @@
2341+/*
2342+ * Copyright (C) 2013 Canonical Ltd
2343+ *
2344+ * This program is free software: you can redistribute it and/or modify
2345+ * it under the terms of the GNU General Public License version 3 as
2346+ * published by the Free Software Foundation.
2347+ *
2348+ * This program is distributed in the hope that it will be useful,
2349+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2350+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2351+ * GNU General Public License for more details.
2352+ *
2353+ * You should have received a copy of the GNU General Public License
2354+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2355+ *
2356+ * Authored by: Arto Jalkanen <ajalkane@gmail.com>
2357+ */
2358+import QtQuick 2.0
2359+import Ubuntu.Components 0.1
2360+import Ubuntu.Components.ListItems 0.1 as ListItem
2361+import org.nemomobile.folderlistmodel 1.0
2362+
2363+ListItem.Subtitled {
2364+ objectName: "folder" + index
2365+
2366+ property string fileName: model.fileName
2367+ property string filePath: path
2368+
2369+ text: model.fileName
2370+ subText: Qt.formatDateTime(model.modifiedDate, Qt.DefaultLocaleShortDate) + (!model.isDir ? ", " + fileSize : "")
2371+
2372+ property string path: fileView.path + '/' + model.fileName
2373+ iconSource: fileIcon(path, model.isDir)
2374+
2375+ progression: model.isDir
2376+ iconFrame: false
2377+}
2378
2379=== added file 'components/FolderListView.qml'
2380--- components/FolderListView.qml 1970-01-01 00:00:00 +0000
2381+++ components/FolderListView.qml 2014-02-19 00:47:29 +0000
2382@@ -0,0 +1,54 @@
2383+/*
2384+ * Copyright (C) 2013 Canonical Ltd
2385+ *
2386+ * This program is free software: you can redistribute it and/or modify
2387+ * it under the terms of the GNU General Public License version 3 as
2388+ * published by the Free Software Foundation.
2389+ *
2390+ * This program is distributed in the hope that it will be useful,
2391+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2392+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2393+ * GNU General Public License for more details.
2394+ *
2395+ * You should have received a copy of the GNU General Public License
2396+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2397+ *
2398+ * Authored by: Arto Jalkanen <ajalkane@gmail.com>
2399+ */
2400+import QtQuick 2.0
2401+import Ubuntu.Components 0.1
2402+import Ubuntu.Components.ListItems 0.1
2403+import Ubuntu.Components.Popups 0.1
2404+import org.nemomobile.folderlistmodel 1.0
2405+
2406+ListView {
2407+ id: root
2408+
2409+ property FolderListModel folderListModel
2410+ property string folderPath: folderListModel.path
2411+ model: folderListModel
2412+ property bool smallMode: !wideAspect
2413+
2414+ // This must be visible so Autopilot can see it
2415+ header: Header {
2416+ objectName: "listViewSmallHeader"
2417+ text: (root.count == 1
2418+ ? i18n.tr("%1 (1 file)").arg(root.folderPath)
2419+ : i18n.tr("%1 (%2 files)").arg(root.folderPath).arg(root.count))
2420+ height: smallMode ? units.gu(4) : 0
2421+ clip: true
2422+ }
2423+
2424+ delegate: FolderListDelegate {
2425+ id: delegate
2426+
2427+ onClicked: itemClicked(model)
2428+
2429+ onPressAndHold: itemLongPress(delegate, model)
2430+ }
2431+
2432+ Scrollbar {
2433+ flickableItem: root
2434+ align: Qt.AlignTrailing
2435+ }
2436+}
2437
2438=== added file 'components/PathBar.qml'
2439--- components/PathBar.qml 1970-01-01 00:00:00 +0000
2440+++ components/PathBar.qml 2014-02-19 00:47:29 +0000
2441@@ -0,0 +1,140 @@
2442+import QtQuick 2.0
2443+import Ubuntu.Components 0.1
2444+import Ubuntu.Components.Popups 0.1
2445+
2446+Rectangle {
2447+ id: root
2448+ objectName: "pathbar"
2449+ radius: units.gu(0.5)
2450+ border.color: UbuntuColors.warmGrey
2451+
2452+ antialiasing: true
2453+ anchors.verticalCenter: parent.verticalCenter
2454+
2455+ implicitWidth: goToButton.width + row.width
2456+
2457+ Behavior on width {
2458+ UbuntuNumberAnimation {}
2459+ }
2460+
2461+ Rectangle {
2462+ id: goToButton
2463+ objectName: "goToButton"
2464+ anchors {
2465+ top: parent.top
2466+ bottom: parent.bottom
2467+ right: parent.right
2468+ }
2469+
2470+ MouseArea {
2471+ id: mouseArea2
2472+ anchors.fill: parent
2473+ hoverEnabled: true
2474+
2475+ onClicked: {
2476+ PopupUtils.open(Qt.resolvedUrl("../ui/GoToDialog.qml"), goToButton)
2477+ }
2478+ }
2479+
2480+ color: mouseArea2.containsMouse ? Qt.rgba(0.5,0.5,0.5,0.2) : Qt.rgba(0.5,0.5,0.5,0)
2481+
2482+ Behavior on color {
2483+ ColorAnimation { duration: 200 }
2484+ }
2485+
2486+ width: parent.height
2487+
2488+ Image {
2489+ id: editImage
2490+ anchors.centerIn: parent
2491+
2492+ source: getIcon("edit")
2493+ height: units.gu(2)
2494+ width: height
2495+ }
2496+
2497+ Rectangle {
2498+ anchors {
2499+ left: parent.left
2500+ top: parent.top
2501+ bottom: parent.bottom
2502+ rightMargin: units.gu(1)
2503+ }
2504+
2505+ width: 1
2506+ color: UbuntuColors.warmGrey
2507+ }
2508+ }
2509+
2510+ Flickable {
2511+ anchors {
2512+ left: parent.left
2513+ right: goToButton.left
2514+ top: parent.top
2515+ bottom: parent.bottom
2516+ }
2517+
2518+ clip: true
2519+
2520+ flickableDirection: Flickable.HorizontalFlick
2521+ contentWidth: row.width
2522+ contentHeight: parent.height
2523+
2524+ Row {
2525+ id: row
2526+ height: root.height
2527+ width: implicitWidth - 1
2528+
2529+ Repeater {
2530+ id: repeater
2531+ model: folder === "/" ? [""] : folder.split("/")
2532+ delegate: Rectangle {
2533+ MouseArea {
2534+ id: mouseArea
2535+ anchors.fill: parent
2536+ hoverEnabled: true
2537+
2538+ onClicked: {
2539+ var upCount = index
2540+ var path = modelData
2541+ while (upCount > 0) {
2542+ path = repeater.model[--upCount] + "/" + path
2543+ //print(path)
2544+ }
2545+
2546+ if (path === "") path = "/"
2547+
2548+ goTo(path)
2549+ }
2550+ }
2551+
2552+ color: mouseArea.containsMouse ? Qt.rgba(0.5,0.5,0.5,0.2) : Qt.rgba(0.5,0.5,0.5,0)
2553+
2554+ Behavior on color {
2555+ ColorAnimation { duration: 200 }
2556+ }
2557+
2558+ Label {
2559+ id: label
2560+ anchors.centerIn: parent
2561+ text: modelData === "" ? "/" : modelData === "~" ? i18n.tr("Home") : modelData
2562+ color: UbuntuColors.coolGrey
2563+ }
2564+
2565+ height: parent.height
2566+ width: label.width + units.gu(4)
2567+
2568+ Rectangle {
2569+ anchors {
2570+ right: parent.right
2571+ top: parent.top
2572+ bottom: parent.bottom
2573+ }
2574+ width: 1
2575+ color: UbuntuColors.warmGrey
2576+ }
2577+ }
2578+ }
2579+ }
2580+ }
2581+}
2582
2583=== added file 'components/PlacesSidebar.qml'
2584--- components/PlacesSidebar.qml 1970-01-01 00:00:00 +0000
2585+++ components/PlacesSidebar.qml 2014-02-19 00:47:29 +0000
2586@@ -0,0 +1,128 @@
2587+/*
2588+ * Copyright (C) 2013 Canonical Ltd
2589+ *
2590+ * This program is free software: you can redistribute it and/or modify
2591+ * it under the terms of the GNU General Public License version 3 as
2592+ * published by the Free Software Foundation.
2593+ *
2594+ * This program is distributed in the hope that it will be useful,
2595+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2596+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2597+ * GNU General Public License for more details.
2598+ *
2599+ * You should have received a copy of the GNU General Public License
2600+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2601+ *
2602+ * Authored by: Michael Spencer <sonrisesoftware@gmail.com>
2603+ */
2604+import QtQuick 2.0
2605+import QtGraphicalEffects 1.0
2606+import Ubuntu.Components 0.1
2607+import Ubuntu.Components.ListItems 0.1
2608+import Ubuntu.Components.Popups 0.1
2609+
2610+Sidebar {
2611+ id: root
2612+
2613+ //color: Qt.rgba(0.5,0.5,0.5,0.3)
2614+ width: collapsed ? units.gu(8) : units.gu(22)
2615+
2616+ property bool collapsed: collapsedSidebar
2617+
2618+ MouseArea {
2619+ anchors.fill: parent
2620+ onClicked: {
2621+ saveSetting("collapsedSidebar", !collapsedSidebar)
2622+ }
2623+ }
2624+
2625+ property bool tempExpanded: false
2626+
2627+ Behavior on width {
2628+ UbuntuNumberAnimation {}
2629+ }
2630+
2631+ ListModel {
2632+ id: places
2633+
2634+ ListElement {
2635+ path: "~"
2636+ }
2637+
2638+ ListElement {
2639+ path: "~/Documents"
2640+ }
2641+
2642+ ListElement {
2643+ path: "~/Downloads"
2644+ }
2645+
2646+ ListElement {
2647+ path: "~/Music"
2648+ }
2649+
2650+ ListElement {
2651+ path: "~/Pictures"
2652+ }
2653+
2654+ ListElement {
2655+ path: "~/Videos"
2656+ }
2657+
2658+ ListElement {
2659+ path: "/"
2660+ }
2661+ }
2662+
2663+ Column {
2664+ anchors {
2665+ left: parent.left
2666+ right: parent.right
2667+ top: parent.top
2668+ }
2669+
2670+ Header {
2671+ text: i18n.tr("Places")
2672+ }
2673+
2674+ Repeater {
2675+ id: placesList
2676+ objectName: "placesList"
2677+
2678+ model: places
2679+
2680+ delegate: Standard {
2681+ text: folderName(path)
2682+
2683+ Image {
2684+ anchors {
2685+ verticalCenter: parent.verticalCenter
2686+ left: parent.left
2687+ }
2688+
2689+ height: units.gu(1.1)
2690+ width: height
2691+
2692+ source: getIcon("arrow")
2693+ opacity: selected && collapsed ? 1 : 0
2694+
2695+ Behavior on opacity {
2696+ UbuntuNumberAnimation {}
2697+ }
2698+ }
2699+
2700+ iconSource: model.icon || fileIcon(model.path, true)
2701+
2702+ onClicked: {
2703+ goTo(model.path)
2704+ }
2705+
2706+ height: units.gu(5)
2707+ showDivider: !collapsed
2708+
2709+ selected: folder === path
2710+ iconFrame: false
2711+ }
2712+ }
2713+ }
2714+}
2715
2716=== added file 'components/Sidebar.qml'
2717--- components/Sidebar.qml 1970-01-01 00:00:00 +0000
2718+++ components/Sidebar.qml 2014-02-19 00:47:29 +0000
2719@@ -0,0 +1,143 @@
2720+/***************************************************************************
2721+ * *
2722+ * Ubuntu UI Extras - A collection of QML widgets not available *
2723+ * in the default Ubuntu UI Toolkit *
2724+ * Copyright (C) 2013 Michael Spencer <sonrisesoftware@gmail.com> *
2725+ * *
2726+ * This program is free software: you can redistribute it and/or modify *
2727+ * it under the terms of the GNU General Public License as published by *
2728+ * the Free Software Foundation, either version 3 of the License, or *
2729+ * (at your option) any later version. *
2730+ * *
2731+ * This program is distributed in the hope that it will be useful, *
2732+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
2733+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
2734+ * GNU General Public License for more details. *
2735+ * *
2736+ * You should have received a copy of the GNU General Public License *
2737+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
2738+ ***************************************************************************/
2739+import QtQuick 2.0
2740+import Ubuntu.Components 0.1
2741+import Ubuntu.Components.ListItems 0.1
2742+
2743+/*!
2744+ \qmltype Sidebar
2745+ \brief A sidebar component for use in adaptive layouts
2746+
2747+ To use, simply add an instance to your code, and anchor other components to it.
2748+
2749+ To show or hide, set the expanded property.
2750+
2751+ By default, the sidebar has a flickable built in, and whatever contents are added
2752+ will be placed in the flickable. When you want this disabled, or want to fill the
2753+ entire sidebar, set the autoFill property to false.
2754+
2755+ Examples:
2756+ \qml
2757+ property bool wideAspect: width > units.gu(80)
2758+
2759+ Sidebar {
2760+ expanded: wideAspect
2761+
2762+ // Anchoring is automatic
2763+ }
2764+ \endqml
2765+*/
2766+Rectangle {
2767+ id: root
2768+
2769+ color: Qt.rgba(0.2,0.2,0.2,0.4)
2770+
2771+ property bool expanded: true
2772+
2773+ property string mode: "left" // or "right"
2774+ property alias header: headerItem.text
2775+
2776+ anchors {
2777+ left: mode === "left" ? parent.left : undefined
2778+ right: mode === "right" ? parent.right : undefined
2779+ top: parent.top
2780+ bottom: parent.bottom
2781+ }
2782+
2783+ VerticalDivider {
2784+ mode: root.mode
2785+
2786+ anchors {
2787+ top: parent.top
2788+ bottom: parent.bottom
2789+ right: mode === "left" ? parent.right : undefined
2790+ left: mode === "right" ? parent.left : undefined
2791+ rightMargin: -1
2792+ }
2793+ }
2794+
2795+ width: units.gu(35)
2796+
2797+
2798+ anchors.leftMargin: expanded ? 0 : -width
2799+ anchors.rightMargin: expanded ? 0 : -width
2800+
2801+ Behavior on anchors.leftMargin {
2802+ UbuntuNumberAnimation {}
2803+ }
2804+
2805+ Behavior on anchors.rightMargin {
2806+ UbuntuNumberAnimation {}
2807+ }
2808+
2809+ default property alias contents: contents.data
2810+
2811+ Header {
2812+ id: headerItem
2813+
2814+ visible: text !== ""
2815+ }
2816+
2817+ property bool autoFlick: true
2818+
2819+ Flickable {
2820+ id: flickable
2821+
2822+ clip: true
2823+
2824+ anchors {
2825+ top: headerItem.visible ? headerItem.bottom : parent.top
2826+ left: parent.left
2827+ right: parent.right
2828+ bottom: parent.bottom
2829+ rightMargin: mode === "left" ? 1 : 0
2830+ leftMargin: mode === "right" ? 1 : 0
2831+ }
2832+
2833+ contentWidth: width
2834+ contentHeight: autoFlick ? contents.height : height
2835+ interactive: contentHeight > height
2836+
2837+ Item {
2838+ id: contents
2839+
2840+ width: flickable.width
2841+ height: autoFlick ? childrenRect.height : flickable.height
2842+ }
2843+
2844+ function getFlickableChild(item) {
2845+ if (item && item.hasOwnProperty("children")) {
2846+ for (var i=0; i < item.children.length; i++) {
2847+ var child = item.children[i];
2848+ if (internal.isVerticalFlickable(child)) {
2849+ if (child.anchors.top === page.top || child.anchors.fill === page) {
2850+ return item.children[i];
2851+ }
2852+ }
2853+ }
2854+ }
2855+ return null;
2856+ }
2857+ }
2858+
2859+ Scrollbar {
2860+ flickableItem: flickable
2861+ }
2862+}
2863
2864=== added file 'components/SuruSheetStyle.qml'
2865--- components/SuruSheetStyle.qml 1970-01-01 00:00:00 +0000
2866+++ components/SuruSheetStyle.qml 2014-02-19 00:47:29 +0000
2867@@ -0,0 +1,150 @@
2868+/*
2869+ * Copyright 2012 Canonical Ltd.
2870+ *
2871+ * This program is free software; you can redistribute it and/or modify
2872+ * it under the terms of the GNU Lesser General Public License as published by
2873+ * the Free Software Foundation; version 3.
2874+ *
2875+ * This program is distributed in the hope that it will be useful,
2876+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2877+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2878+ * GNU Lesser General Public License for more details.
2879+ *
2880+ * You should have received a copy of the GNU Lesser General Public License
2881+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2882+ */
2883+
2884+import QtQuick 2.0
2885+import Ubuntu.Components 0.1
2886+import Ubuntu.Components.ListItems 0.1 as ListItem
2887+
2888+Item {
2889+ id: visuals
2890+ // styling properties
2891+ property color backgroundColor: Qt.rgba(0.2,0.2,0.2,0.97)
2892+ property color headerColor: Qt.rgba(0,0,0,0.2)
2893+ property real headerHeight: units.gu(8)
2894+ property real buttonContainerWidth: units.gu(14)
2895+
2896+ implicitWidth: MathUtils.clamp(styledItem.contentsWidth, styledItem.minWidth, styledItem.maxWidth)
2897+ implicitHeight: header.height + containerItem.height
2898+
2899+ property alias contentItem: containerItem
2900+
2901+ property bool maximized: styledItem.contentsWidth > styledItem.maxWidth
2902+
2903+ UbuntuShape {
2904+ id: background
2905+ color: backgroundColor
2906+ visible: !maximized
2907+ anchors {
2908+ left: parent.left
2909+ right: parent.right
2910+ top: header.top
2911+ bottom: containerItem.bottom
2912+ }
2913+ }
2914+
2915+ Rectangle {
2916+ color: backgroundColor
2917+ visible: maximized
2918+ anchors {
2919+ left: parent.left
2920+ right: parent.right
2921+ top: header.top
2922+ bottom: containerItem.bottom
2923+ }
2924+ }
2925+
2926+ Item {
2927+ id: header
2928+ height: visuals.headerHeight
2929+ clip: true
2930+
2931+ anchors {
2932+ top: parent.top
2933+ left: parent.left
2934+ right: parent.right
2935+ }
2936+
2937+ UbuntuShape {
2938+ anchors {
2939+ fill: parent
2940+ bottomMargin: -units.gu(2)
2941+ }
2942+
2943+ visible: !maximized
2944+ color: visuals.headerColor
2945+ }
2946+
2947+ Rectangle {
2948+ anchors {
2949+ fill: parent
2950+ }
2951+
2952+ visible: maximized
2953+ color: visuals.headerColor
2954+ }
2955+
2956+ Label {
2957+ id: headerText
2958+ anchors {
2959+ verticalCenter: parent.verticalCenter
2960+ left: leftButtonContainer.right
2961+ right: rightButtonContainer.left
2962+ }
2963+ width: headerText.implicitWidth + units.gu(4)
2964+ elide: Text.ElideRight
2965+ horizontalAlignment: Text.AlignHCenter
2966+ text: styledItem.title
2967+ fontSize: "large"
2968+ }
2969+
2970+ Item {
2971+ id: leftButtonContainer
2972+ anchors {
2973+ left: parent.left
2974+ top: parent.top
2975+ bottom: parent.bottom
2976+ }
2977+ width: visuals.buttonContainerWidth
2978+ Component.onCompleted: header.updateButton(styledItem.leftButton, leftButtonContainer)
2979+ }
2980+
2981+ Item {
2982+ id: rightButtonContainer
2983+ anchors {
2984+ right: parent.right
2985+ top: parent.top
2986+ bottom: parent.bottom
2987+ }
2988+ width: visuals.buttonContainerWidth
2989+ Component.onCompleted: header.updateButton(styledItem.rightButton, rightButtonContainer)
2990+ }
2991+
2992+ function updateButton(button, container) {
2993+ if (!button) return;
2994+ button.parent = container;
2995+ button.anchors.left = container.left;
2996+ button.anchors.right = container.right;
2997+ button.anchors.verticalCenter = container.verticalCenter;
2998+ button.anchors.margins = units.gu(1);
2999+ }
3000+
3001+ Connections {
3002+ target: styledItem
3003+ onLeftButtonChanged: header.updateButton(styledItem.leftButton, leftButtonContainer)
3004+ onRightButtonChanged: header.updateButton(styledItem.rightButton, rightButtonContainer)
3005+ }
3006+ }
3007+
3008+ Item {
3009+ id: containerItem
3010+ height: false ? styledItem.maxHeight - header.height : MathUtils.clamp(styledItem.contentsHeight, styledItem.minHeight - header.height, styledItem.maxHeight - header.height)
3011+ anchors {
3012+ top: header.bottom
3013+ left: parent.left
3014+ right: parent.right
3015+ }
3016+ }
3017+}
3018
3019=== added file 'components/VerticalDivider.qml'
3020--- components/VerticalDivider.qml 1970-01-01 00:00:00 +0000
3021+++ components/VerticalDivider.qml 2014-02-19 00:47:29 +0000
3022@@ -0,0 +1,46 @@
3023+/***************************************************************************
3024+ * *
3025+ * Ubuntu UI Extras - A collection of QML widgets not available *
3026+ * in the default Ubuntu UI Toolkit *
3027+ * Copyright (C) 2013 Michael Spencer <sonrisesoftware@gmail.com> *
3028+ * *
3029+ * This program is free software: you can redistribute it and/or modify *
3030+ * it under the terms of the GNU General Public License as published by *
3031+ * the Free Software Foundation, either version 3 of the License, or *
3032+ * (at your option) any later version. *
3033+ * *
3034+ * This program is distributed in the hope that it will be useful, *
3035+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
3036+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
3037+ * GNU General Public License for more details. *
3038+ * *
3039+ * You should have received a copy of the GNU General Public License *
3040+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
3041+ ***************************************************************************/
3042+import QtQuick 2.0
3043+import Ubuntu.Components 0.1
3044+import Ubuntu.Components.ListItems 0.1
3045+import QtQuick 2.0
3046+
3047+Item {
3048+ property string mode: "left" // or right
3049+
3050+ ThinDivider {
3051+ id: divider
3052+ rotation: mode === "left" ? 90 : -90
3053+
3054+ width: parent.height
3055+
3056+ anchors {
3057+ left: undefined
3058+ right: undefined
3059+ centerIn: parent
3060+ }
3061+ }
3062+ width: divider.height
3063+
3064+ anchors {
3065+ top: parent ? parent.top : undefined
3066+ bottom: parent ? parent.bottom : undefined
3067+ }
3068+}
3069
3070=== added file 'icons/arrow.png'
3071Binary files icons/arrow.png 1970-01-01 00:00:00 +0000 and icons/arrow.png 2014-02-19 00:47:29 +0000 differ
3072=== added file 'icons/browser-tabs.png'
3073Binary files icons/browser-tabs.png 1970-01-01 00:00:00 +0000 and icons/browser-tabs.png 2014-02-19 00:47:29 +0000 differ
3074=== added file 'icons/home.png'
3075Binary files icons/home.png 1970-01-01 00:00:00 +0000 and icons/home.png 2014-02-19 00:47:29 +0000 differ
3076=== renamed file 'icons/up.png' => 'icons/keyboard-caps.png'
3077=== added file 'icons/navigation-menu.png'
3078Binary files icons/navigation-menu.png 1970-01-01 00:00:00 +0000 and icons/navigation-menu.png 2014-02-19 00:47:29 +0000 differ
3079=== modified file 'tests/autopilot/ubuntu_filemanager_app/emulators.py'
3080--- tests/autopilot/ubuntu_filemanager_app/emulators.py 2014-02-13 03:41:36 +0000
3081+++ tests/autopilot/ubuntu_filemanager_app/emulators.py 2014-02-19 00:47:29 +0000
3082@@ -54,7 +54,7 @@
3083
3084 def get_places_popover(self):
3085 """Return the Places popover."""
3086- if not(self.wideAspect):
3087+ if not(self.internal_wideAspect):
3088 # XXX It would be easier if the places popover was an object
3089 # that inherits from Popover, like the
3090 # ActionSelectionPopover does.
3091@@ -105,7 +105,7 @@
3092 return self.wait_select_single(Popover)
3093
3094
3095-class Sidebar(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
3096+class PlacesSidebar(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
3097 """PlacesSidebar Autopilot emulator."""
3098
3099 def get_place(self, text):
3100@@ -122,7 +122,10 @@
3101
3102 def get_number_of_files_from_list(self):
3103 """Return the number of files shown on the folder."""
3104- return len(self.select_many(FolderListDelegate))
3105+ if self.showingListView:
3106+ return len(self.select_many(FolderListDelegate))
3107+ else:
3108+ return len(self.select_many(FolderIconDelegate))
3109
3110 def get_file_by_index(self, index):
3111 """Return the FolderListDelegate emulator of the file or folder.
3112@@ -130,7 +133,10 @@
3113 :parameter index: The index of file or folder.
3114
3115 """
3116- file_ = self.select_many(FolderListDelegate)[index]
3117+ if self.showingListView:
3118+ file_ = self.select_many(FolderListDelegate)[index]
3119+ else:
3120+ file_ = self.select_many(FolderIconDelegate)[index]
3121 file_.list_view = self.select_single(FolderListView)
3122 return file_
3123
3124@@ -141,25 +147,43 @@
3125
3126 """
3127 files = self.select_many(FolderListDelegate)
3128+ if not(self.showingListView):
3129+ files = self.select_many(FolderIconDelegate)
3130 for file_ in files:
3131 if file_.fileName == name:
3132- file_.list_view = self.select_single(FolderListView)
3133+ if self.showingListView:
3134+ file_.list_view = self.select_single(FolderListView)
3135+ else:
3136+ file_.list_view = self.select_single(FolderIconView)
3137 return file_
3138 raise ValueError(
3139 'File with name "{0}" not found.'.format(name))
3140
3141 def get_current_path(self):
3142- return self.select_single(FolderListView).get_current_path()
3143+ if self.showingListView:
3144+ return self.select_single(FolderListView).get_current_path()
3145+ else:
3146+ return self.select_single(FolderIconView).get_current_path()
3147
3148 def get_number_of_files_from_header(self):
3149- return self.select_single(FolderListView).get_number_of_files()
3150+ if self.showingListView:
3151+ return self.select_single(FolderListView).get_number_of_files()
3152+ else:
3153+ return self.select_single(FolderIconView).get_number_of_files()
3154
3155 def get_sidebar(self):
3156- if self.main_view.wideAspect:
3157- return self.select_single(Sidebar)
3158- else:
3159- raise ValueError(
3160- 'Places sidebar is hidden in wide mode.')
3161+ if self.main_view.internal_wideAspect:
3162+ return self.select_single(PlacesSidebar)
3163+ else:
3164+ raise ValueError(
3165+ 'Places sidebar is hidden in small mode.')
3166+
3167+ def get_pathbar(self):
3168+ if self.main_view.internal_wideAspect:
3169+ return self.main_view.get_toolbar().select_single(PathBar)
3170+ else:
3171+ raise ValueError(
3172+ 'Path bar is hidden in small mode.')
3173
3174
3175 class FolderListView(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
3176@@ -188,6 +212,32 @@
3177 return int(number_of_files)
3178
3179
3180+class FolderIconView(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
3181+ """FolderListView Autopilot emulator."""
3182+
3183+ SPLIT_HEADER_REGEX = '(.+) \((\d+) \w+\)$'
3184+ # Regular expression to split the header text. The header text has the form
3185+ # /path/to/dir (# files). So with this expression, we can split the header
3186+ # in two groups, (.+) will match the path and (\d+) the number of files.
3187+
3188+ def get_current_path(self):
3189+ path, _ = self._split_header_text()
3190+ return path
3191+
3192+ def _split_header_text(self):
3193+ header_text = self.select_single(
3194+ 'Header', objectName='iconViewHeader').text
3195+ match = re.match(self.SPLIT_HEADER_REGEX, header_text)
3196+ if match:
3197+ path = match.group(1)
3198+ number_of_files = match.group(2)
3199+ return path, number_of_files
3200+
3201+ def get_number_of_files(self):
3202+ _, number_of_files = self._split_header_text()
3203+ return int(number_of_files)
3204+
3205+
3206 class FolderListDelegate(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
3207 """FolderListPage Autopilot emulator.
3208
3209@@ -229,6 +279,47 @@
3210 # --elopio - 2013-07-25
3211
3212
3213+class FolderIconDelegate(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
3214+ """FolderIconPage Autopilot emulator.
3215+
3216+ This is a file or folder on the FolderListPage.
3217+
3218+ """
3219+
3220+ def __init__(self, *args):
3221+ super(FolderIconDelegate, self).__init__(*args)
3222+ self.pointing_device = toolkit_emulators.get_pointing_device()
3223+
3224+ def open_directory(self):
3225+ """Open the directory."""
3226+ # TODO Check if it is a directory. If not, raise an error.
3227+ # This is not currently possible because Autopilot is overwriting the
3228+ # path attribute. Reported on
3229+ # https://bugs.launchpad.net/autopilot/+bug/1205204
3230+ # --elopio - 2013-07-25
3231+ self.pointing_device.click_object(self)
3232+
3233+ def open_file(self):
3234+ # TODO For this we would need to access the FileActionDialog that's
3235+ # child of the MainView, but that's not currently possible with
3236+ # autopilot. Reported on
3237+ # bug https://bugs.launchpad.net/autopilot/+bug/1195141
3238+ # --elopio - 2013-07-25
3239+ raise NotImplementedError()
3240+
3241+ def open_actions_popover(self):
3242+ """Open the actions popover of the file or folder."""
3243+ self.pointing_device.move_to_object(self)
3244+ self.pointing_device.press()
3245+ time.sleep(1)
3246+ self.pointing_device.release()
3247+ # TODO wait for the popover to be opened. For this we would need to
3248+ # access the MainView, but that's not currently possible with
3249+ # autopilot. Reported on
3250+ # https://bugs.launchpad.net/autopilot/+bug/1195141
3251+ # --elopio - 2013-07-25
3252+
3253+
3254 class FileActionDialog(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
3255 """FileActionDialog Autopilot emulator."""
3256
3257@@ -362,3 +453,10 @@
3258
3259 def get_path(self):
3260 return self.select_single('Label', objectName='pathLabel').text
3261+
3262+
3263+class PathBar(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
3264+
3265+ def go_to_location(self):
3266+ editButton = self.select_single(objectName='goToButton')
3267+ self.pointing_device.click_object(editButton)
3268
3269=== modified file 'tests/autopilot/ubuntu_filemanager_app/tests/test_filemanager.py'
3270--- tests/autopilot/ubuntu_filemanager_app/tests/test_filemanager.py 2014-02-13 03:41:36 +0000
3271+++ tests/autopilot/ubuntu_filemanager_app/tests/test_filemanager.py 2014-02-19 00:47:29 +0000
3272@@ -102,7 +102,7 @@
3273 # https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1205201
3274 # --elopio - 2013-07-25
3275 place = None
3276- if self.main_view.wideAspect:
3277+ if self.main_view.internal_wideAspect:
3278 place = (self.main_view.get_folder_list_page().get_sidebar()
3279 .get_place(text))
3280 else:
3281@@ -117,9 +117,10 @@
3282 #on wide UI display, we get the location dialog
3283 #on phone UI display, we get places popover
3284 device = model()
3285- if self.main_view.wideAspect:
3286+ if self.main_view.internal_wideAspect:
3287 logger.debug("Using goto to goto %s on %s" % (location, device))
3288- toolbar.click_button('goTo')
3289+ (self.main_view.get_folder_list_page().get_pathbar()
3290+ .go_to_location())
3291 goto_location = self.main_view.get_dialog()
3292 else:
3293 logger.debug("Using places to goto %s on %s" % (location, device))
3294@@ -269,20 +270,6 @@
3295 file_ = self._get_file_by_name(file_name)
3296 self.assertThat(file_.fileName, Eventually(Equals(file_name)))
3297
3298- def test_cancel_file_action_dialog(self):
3299- file_name = os.path.basename(self._make_file_in_testhome())
3300-
3301- first_file = self._get_file_by_name(file_name)
3302- self.pointing_device.click_object(first_file)
3303-
3304- dialog = self.main_view.get_file_action_dialog()
3305- dialog.visible.wait_for(True)
3306- dialog.cancel()
3307-
3308- self.assertThat(
3309- self.main_view.file_action_dialog_exists,
3310- Eventually(Equals(False)))
3311-
3312 def test_cancel_rename_directory(self):
3313 dir_path = self._make_directory_in_testhome()
3314 dir_name = os.path.basename(dir_path)
3315
3316=== modified file 'ubuntu-filemanager-app.qml'
3317--- ubuntu-filemanager-app.qml 2014-01-31 19:37:58 +0000
3318+++ ubuntu-filemanager-app.qml 2014-02-19 00:47:29 +0000
3319@@ -22,6 +22,8 @@
3320 import Ubuntu.Unity.Action 1.0 as UnityActions
3321 import U1db 1.0 as U1db
3322
3323+import "ui"
3324+
3325 /*!
3326 \brief MainView with Tabs element.
3327 First Tab has a single Label and
3328@@ -29,7 +31,7 @@
3329 */
3330
3331 MainView {
3332- id: root
3333+ id: mainView
3334 // objectName for functional testing purposes (autopilot-qt5)
3335 objectName: "filemanager"
3336 applicationName: "com.ubuntu.filemanager"
3337@@ -37,11 +39,23 @@
3338 width: units.gu(100)
3339 height: units.gu(75)
3340
3341- property alias filemanager: root
3342+ property alias filemanager: mainView
3343
3344+ property bool internal_wideAspect: width >= units.gu(80)
3345 property bool wideAspect: width >= units.gu(80) && loaded
3346 property bool loaded: false
3347
3348+ property bool allowSidebarExpanded: width >= units.gu(80)
3349+
3350+ onAllowSidebarExpandedChanged: {
3351+ if (!allowSidebarExpanded)
3352+ saveSetting("collapsedSidebar", true)
3353+ }
3354+
3355+ property bool showSidebar: width >= units.gu(50)
3356+
3357+ property bool showToolbar: width >= units.gu(80)
3358+
3359 headerColor: "#464646"
3360 backgroundColor: "#797979"
3361 footerColor: "#808080"
3362@@ -52,25 +66,44 @@
3363 text: i18n.tr("Settings")
3364 description: i18n.tr("Change app settings")
3365 iconSource: getIcon("settings")
3366- onTriggered: pageStack.push(settingsPage)
3367+ onTriggered: showSettings()
3368 }
3369 actions: [settingsAction]
3370
3371 property var pageStack: pageStack
3372
3373+ property var folderTabs: ["~"]
3374+
3375+ function openTab(folder) {
3376+ var list = folderTabs
3377+ list.push(folder)
3378+ folderTabs = list
3379+ }
3380+
3381+ function closeTab(index) {
3382+ var list = folderTabs
3383+ list.splice(index, 1)
3384+ folderTabs = list
3385+ tabs.selectedTabIndex = 0
3386+ }
3387+
3388 PageStack {
3389 id: pageStack
3390
3391+ anchors.bottomMargin: toolbar.tools.opened && toolbar.tools.locked ? -mainView.toolbar.triggerSize : 0
3392+
3393 Tabs {
3394 id: tabs
3395
3396- Tab {
3397- title: page.title
3398- page: FolderListPage {
3399- id: folderPage
3400- objectName: "folderPage"
3401+ Repeater {
3402+ model: folderTabs
3403+ delegate: Tab {
3404+ title: page.title
3405+ page: FolderListPage {
3406+ objectName: "folderPage"
3407
3408- folder: homeFolder
3409+ folder: modelData
3410+ }
3411 }
3412 }
3413 }
3414@@ -83,19 +116,6 @@
3415 }
3416 }
3417
3418- property var showToolbar: wideAspect ? true : undefined
3419-
3420- states: [
3421- State {
3422- when: showToolbar && toolbar.tools.opened && toolbar.tools.locked
3423-
3424- PropertyChanges {
3425- target: pageStack
3426- anchors.bottomMargin: -root.toolbar.triggerSize
3427- }
3428- }
3429- ]
3430-
3431 /* Settings Storage */
3432
3433 U1db.Database {
3434@@ -112,16 +132,17 @@
3435
3436 defaults: {
3437 showAdvancedFeatures: false
3438+ collapsedSidebar: false
3439 }
3440 }
3441
3442- SettingsPage {
3443- id: settingsPage
3444- }
3445-
3446 // Individual settings, used for bindings
3447 property bool showAdvancedFeatures: false
3448
3449+ property var viewMethod
3450+
3451+ property bool collapsedSidebar: false
3452+
3453 function getSetting(name, def) {
3454 var tempContents = {};
3455 tempContents = settings.contents
3456@@ -146,13 +167,34 @@
3457 }
3458 }
3459
3460+ function showSettings() {
3461+ PopupUtils.open(Qt.resolvedUrl("ui/SettingsSheet.qml"), mainView)
3462+ }
3463+
3464 function reloadSettings() {
3465- showAdvancedFeatures = getSetting("showAdvancedFeatures", false)
3466+ //showAdvancedFeatures = getSetting("showAdvancedFeatures", false)
3467+ viewMethod = getSetting("viewMethod", width > units.gu(40) ? i18n.tr("Icons") : i18n.tr("List"))
3468+ collapsedSidebar = getSetting("collapsedSidebar", false)
3469 }
3470
3471- Component.onCompleted: reloadSettings()
3472+ Component.onCompleted: {
3473+ reloadSettings()
3474+ }
3475
3476 function getIcon(name) {
3477- return Qt.resolvedUrl("icons/" + name + ".png")
3478+ return "/usr/share/icons/ubuntu-mobile/actions/scalable/" + name + ".svg" //Qt.resolvedUrl("icons/" + name + ".png")
3479+ }
3480+
3481+ function error(title, message) {
3482+ PopupUtils.open(Qt.resolvedUrl("NotifyDialog.qml"), mainView,
3483+ {
3484+ title: title,
3485+ text: message
3486+ })
3487+ }
3488+
3489+ Keys.onPressed: {
3490+ print("Key pressed!")
3491+ event.accepted = tabs.currentPage.keyPressed(event.key, event.modifiers)
3492 }
3493 }
3494
3495=== added directory 'ui'
3496=== added file 'ui/ConfirmDialog.qml'
3497--- ui/ConfirmDialog.qml 1970-01-01 00:00:00 +0000
3498+++ ui/ConfirmDialog.qml 2014-02-19 00:47:29 +0000
3499@@ -0,0 +1,60 @@
3500+/*
3501+ * Copyright (C) 2013 Canonical Ltd
3502+ *
3503+ * This program is free software: you can redistribute it and/or modify
3504+ * it under the terms of the GNU General Public License version 3 as
3505+ * published by the Free Software Foundation.
3506+ *
3507+ * This program is distributed in the hope that it will be useful,
3508+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3509+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3510+ * GNU General Public License for more details.
3511+ *
3512+ * You should have received a copy of the GNU General Public License
3513+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3514+ *
3515+ * Authored by: Arto Jalkanen <ajalkane@gmail.com>
3516+ */
3517+import QtQuick 2.0
3518+import Ubuntu.Components 0.1
3519+import Ubuntu.Components.Popups 0.1
3520+
3521+Dialog {
3522+ id: root
3523+
3524+ signal accepted
3525+ signal rejected
3526+
3527+ Button {
3528+ id: okButton
3529+ objectName: "okButton"
3530+ text: i18n.tr("Ok")
3531+ onClicked: {
3532+ accepted()
3533+ PopupUtils.close(root)
3534+ }
3535+ }
3536+
3537+ Button {
3538+ id: cancelButton
3539+ objectName: "cancelButton"
3540+ text: i18n.tr("Cancel")
3541+
3542+ gradient: Gradient {
3543+ GradientStop {
3544+ position: 0
3545+ color: "gray"
3546+ }
3547+
3548+ GradientStop {
3549+ position: 1
3550+ color: "lightgray"
3551+ }
3552+ }
3553+
3554+ onClicked: {
3555+ rejected()
3556+ PopupUtils.close(root)
3557+ }
3558+ }
3559+}
3560
3561=== added file 'ui/ConfirmDialogWithInput.qml'
3562--- ui/ConfirmDialogWithInput.qml 1970-01-01 00:00:00 +0000
3563+++ ui/ConfirmDialogWithInput.qml 2014-02-19 00:47:29 +0000
3564@@ -0,0 +1,70 @@
3565+/*
3566+ * Copyright (C) 2013 Canonical Ltd
3567+ *
3568+ * This program is free software: you can redistribute it and/or modify
3569+ * it under the terms of the GNU General Public License version 3 as
3570+ * published by the Free Software Foundation.
3571+ *
3572+ * This program is distributed in the hope that it will be useful,
3573+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3574+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3575+ * GNU General Public License for more details.
3576+ *
3577+ * You should have received a copy of the GNU General Public License
3578+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3579+ *
3580+ * Authored by: Arto Jalkanen <ajalkane@gmail.com>
3581+ */
3582+import QtQuick 2.0
3583+import Ubuntu.Components 0.1
3584+import Ubuntu.Components.Popups 0.1
3585+
3586+Dialog {
3587+ id: root
3588+
3589+ property alias inputText: input.text
3590+ property alias placeholderText: input.placeholderText
3591+ signal accepted
3592+ signal rejected
3593+
3594+ TextField {
3595+ id: input
3596+ objectName: "inputField"
3597+ focus: true
3598+ validator: RegExpValidator {
3599+ regExp: /.+/
3600+ }
3601+ }
3602+
3603+ Button {
3604+ objectName: "okButton"
3605+ text: i18n.tr("Ok")
3606+ enabled: input.acceptableInput
3607+ onClicked: {
3608+ accepted()
3609+ PopupUtils.close(root)
3610+ }
3611+ }
3612+
3613+ Button {
3614+ objectName: "cancelButton"
3615+ text: i18n.tr("Cancel")
3616+
3617+ gradient: Gradient {
3618+ GradientStop {
3619+ position: 0
3620+ color: "gray"
3621+ }
3622+
3623+ GradientStop {
3624+ position: 1
3625+ color: "lightgray"
3626+ }
3627+ }
3628+
3629+ onClicked: {
3630+ rejected()
3631+ PopupUtils.close(root)
3632+ }
3633+ }
3634+}
3635
3636=== added file 'ui/FileActionDialog.qml'
3637--- ui/FileActionDialog.qml 1970-01-01 00:00:00 +0000
3638+++ ui/FileActionDialog.qml 2014-02-19 00:47:29 +0000
3639@@ -0,0 +1,60 @@
3640+/*
3641+ * Copyright (C) 2013 Canonical Ltd
3642+ *
3643+ * This program is free software: you can redistribute it and/or modify
3644+ * it under the terms of the GNU General Public License version 3 as
3645+ * published by the Free Software Foundation.
3646+ *
3647+ * This program is distributed in the hope that it will be useful,
3648+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3649+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3650+ * GNU General Public License for more details.
3651+ *
3652+ * You should have received a copy of the GNU General Public License
3653+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3654+ *
3655+ * Authored by: Arto Jalkanen <ajalkane@gmail.com>
3656+ */
3657+import QtQuick 2.0
3658+import Ubuntu.Components 0.1
3659+import Ubuntu.Components.Popups 0.1
3660+import org.nemomobile.folderlistmodel 1.0
3661+
3662+Dialog {
3663+ id: root
3664+
3665+ property string fileName
3666+ property string filePath
3667+ property FolderListModel folderListModel
3668+
3669+ title: i18n.tr("Choose action")
3670+ text: i18n.tr("For file: %1").arg(fileName)
3671+
3672+ Button {
3673+ objectName: "openButton"
3674+ text: i18n.tr("Open")
3675+ onClicked: {
3676+ console.log("Opening file", filePath)
3677+ openFile(model.filePath)
3678+ onClicked: PopupUtils.close(root)
3679+ }
3680+ }
3681+
3682+ Button {
3683+ objectName: "cancelButton"
3684+ text: i18n.tr("Cancel")
3685+ onClicked: PopupUtils.close(root)
3686+
3687+ gradient: Gradient {
3688+ GradientStop {
3689+ position: 0
3690+ color: "gray"
3691+ }
3692+
3693+ GradientStop {
3694+ position: 1
3695+ color: "lightgray"
3696+ }
3697+ }
3698+ }
3699+}
3700
3701=== added file 'ui/FileDetailsPopover.qml'
3702--- ui/FileDetailsPopover.qml 1970-01-01 00:00:00 +0000
3703+++ ui/FileDetailsPopover.qml 2014-02-19 00:47:29 +0000
3704@@ -0,0 +1,140 @@
3705+/*
3706+ * Copyright (C) 2013 Canonical Ltd
3707+ *
3708+ * This program is free software: you can redistribute it and/or modify
3709+ * it under the terms of the GNU General Public License version 3 as
3710+ * published by the Free Software Foundation.
3711+ *
3712+ * This program is distributed in the hope that it will be useful,
3713+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3714+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3715+ * GNU General Public License for more details.
3716+ *
3717+ * You should have received a copy of the GNU General Public License
3718+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3719+ *
3720+ * Authored by: Arto Jalkanen <ajalkane@gmail.com>
3721+ */
3722+import QtQuick 2.0
3723+import Ubuntu.Components 0.1
3724+import Ubuntu.Components.Popups 0.1
3725+
3726+Popover {
3727+ id: root
3728+ property var model
3729+
3730+ property string path: model.path || (fileView.path + '/' + model.fileName)
3731+
3732+ contentHeight: contents.height + 2 * contents.anchors.margins
3733+
3734+ function dateTimeFormat(dateTime) {
3735+ return Qt.formatDateTime(dateTime, Qt.DefaultLocaleShortDate) || "Unknown"
3736+ }
3737+
3738+ function permissionsToString(model) {
3739+ var permissions = []
3740+ if (model.isReadable) {
3741+ permissions.push(i18n.tr("Readable"))
3742+ }
3743+ if (pathIsWritable()) {
3744+ permissions.push(i18n.tr("Writable"))
3745+ }
3746+ if (model.isExecutable) {
3747+ permissions.push(i18n.tr("Executable"))
3748+ }
3749+
3750+ // Now why does this not work?
3751+ // return permissions.join(", ")
3752+ var permStr = ""
3753+ for (var i = 0; i < permissions.length; ++i) {
3754+ if (permStr.length > 0) {
3755+ permStr += ", "
3756+ }
3757+ permStr += permissions[i]
3758+ }
3759+ return permStr
3760+ }
3761+
3762+ Column {
3763+ id: contents
3764+ spacing: units.gu(1)
3765+ anchors {
3766+ margins: units.gu(2)
3767+ left: parent.left
3768+ right: parent.right
3769+ top: parent.top
3770+ }
3771+
3772+ Row {
3773+ spacing: units.gu(1)
3774+ Image {
3775+ anchors.verticalCenter: parent.verticalCenter
3776+
3777+ // TODO: how to get proper icon?
3778+ source: fileIcon(root.path, model.isDir)
3779+ }
3780+
3781+ Label {
3782+ anchors.verticalCenter: parent.verticalCenter
3783+
3784+ text: folderName(root.path)
3785+ color: Theme.palette.normal.overlayText
3786+ font.bold: true
3787+ }
3788+ }
3789+
3790+ Grid {
3791+ columns: 2
3792+ spacing: units.gu(1)
3793+
3794+ Label {
3795+ text: i18n.tr("Path:")
3796+ color: Theme.palette.normal.overlayText
3797+ }
3798+
3799+ Label {
3800+ objectName: "pathLabel"
3801+ text: root.path
3802+ color: Theme.palette.normal.overlayText
3803+ }
3804+
3805+ Label {
3806+ text: model.isDir ? i18n.tr("Contents:")
3807+ : i18n.tr("Size:")
3808+ color: Theme.palette.normal.overlayText
3809+ }
3810+ Label {
3811+ text: model.fileSize
3812+ color: Theme.palette.normal.overlayText
3813+ }
3814+
3815+ Label {
3816+ text: i18n.tr("Accessed:")
3817+ color: Theme.palette.normal.overlayText
3818+ }
3819+ Label {
3820+ text: dateTimeFormat(pathAccessedDate())
3821+ color: Theme.palette.normal.overlayText
3822+ }
3823+
3824+ Label {
3825+ text: i18n.tr("Modified:")
3826+ color: Theme.palette.normal.overlayText
3827+ }
3828+ Label {
3829+ text: dateTimeFormat(pathModifiedDate())
3830+ color: Theme.palette.normal.overlayText
3831+ }
3832+
3833+ Label {
3834+ text: i18n.tr("Permissions:")
3835+ color: Theme.palette.normal.overlayText
3836+ }
3837+ Label {
3838+ text: permissionsToString(model)
3839+ color: Theme.palette.normal.overlayText
3840+ }
3841+
3842+ }
3843+ }
3844+}
3845
3846=== added file 'ui/FileOperationProgressDialog.qml'
3847--- ui/FileOperationProgressDialog.qml 1970-01-01 00:00:00 +0000
3848+++ ui/FileOperationProgressDialog.qml 2014-02-19 00:47:29 +0000
3849@@ -0,0 +1,86 @@
3850+/*
3851+ * Copyright (C) 2013 Canonical Ltd
3852+ *
3853+ * This program is free software: you can redistribute it and/or modify
3854+ * it under the terms of the GNU General Public License version 3 as
3855+ * published by the Free Software Foundation.
3856+ *
3857+ * This program is distributed in the hope that it will be useful,
3858+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3859+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3860+ * GNU General Public License for more details.
3861+ *
3862+ * You should have received a copy of the GNU General Public License
3863+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3864+ *
3865+ * Authored by: Arto Jalkanen <ajalkane@gmail.com>
3866+ */
3867+import QtQuick 2.0
3868+import Ubuntu.Components 0.1
3869+import Ubuntu.Components.Popups 0.1
3870+import org.nemomobile.folderlistmodel 1.0
3871+
3872+Dialog {
3873+ id: root
3874+ property FolderListModel model
3875+ property Page page
3876+ property string descriptionPrepend: i18n.tr("Operation in progress")
3877+
3878+ title: "File operation"
3879+ text: descriptionPrepend
3880+
3881+ function startOperation(name) {
3882+ root.title = name
3883+ }
3884+
3885+ ProgressBar {
3886+ id: progress
3887+ minimumValue: 0.0
3888+ maximumValue: 100.0
3889+ value: 0.0
3890+ }
3891+
3892+ Button {
3893+ text: i18n.tr("Cancel")
3894+ onClicked: {
3895+ console.log("Cancelling file progress action")
3896+ model.cancelAction()
3897+ PopupUtils.close(root)
3898+ }
3899+ }
3900+
3901+ Connections {
3902+ target: model
3903+ onProgress: {
3904+ // curItem == 0 && percent == 0 means the Action has just been created, check getProgressCounter() before
3905+ if (curItem == 0 && percent == 0) {
3906+ console.log("Creating dialog:", model.getProgressCounter())
3907+ if (model.getProgressCounter() > 20) {
3908+ // show/activate/make visible the dialog here
3909+ print("Showing dialog...")
3910+ PopupUtils.open(root, page)
3911+ root.show()
3912+ }
3913+ }
3914+
3915+ console.log("On progress ", curItem, totalItems, percent)
3916+
3917+ progress.value = percent
3918+ if (percent == 100 && curItem == totalItems) {
3919+ console.log("All files processed, closing progress dialog")
3920+ //PopupUtils.close(root)
3921+ root.hide()
3922+ } else {
3923+ root.text = descriptionPrepend + " (" + curItem + "/" + totalItems + ")"
3924+ }
3925+ }
3926+ }
3927+
3928+ // Errors from model
3929+ Connections {
3930+ target: pageModel
3931+ onError: {
3932+ PopupUtils.close(root)
3933+ }
3934+ }
3935+}
3936
3937=== added file 'ui/FolderListPage.qml'
3938--- ui/FolderListPage.qml 1970-01-01 00:00:00 +0000
3939+++ ui/FolderListPage.qml 2014-02-19 00:47:29 +0000
3940@@ -0,0 +1,721 @@
3941+/*
3942+ * Copyright (C) 2013 Canonical Ltd
3943+ *
3944+ * This program is free software: you can redistribute it and/or modify
3945+ * it under the terms of the GNU General Public License version 3 as
3946+ * published by the Free Software Foundation.
3947+ *
3948+ * This program is distributed in the hope that it will be useful,
3949+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3950+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3951+ * GNU General Public License for more details.
3952+ *
3953+ * You should have received a copy of the GNU General Public License
3954+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3955+ *
3956+ * Authored by: Arto Jalkanen <ajalkane@gmail.com>
3957+ */
3958+import QtQuick 2.0
3959+import Ubuntu.Components 0.1
3960+import Ubuntu.Components.Popups 0.1
3961+import Ubuntu.Components.ListItems 0.1
3962+import org.nemomobile.folderlistmodel 1.0
3963+import "../components"
3964+
3965+Page {
3966+ id: folderListPage
3967+
3968+ title: folderName(folder)
3969+
3970+ property variant fileView: folderListPage
3971+
3972+ property bool showHiddenFiles: false
3973+
3974+ property bool showingListView: folderListView.visible
3975+
3976+ onShowHiddenFilesChanged: {
3977+ pageModel.showHiddenFiles = folderListPage.showHiddenFiles
3978+ }
3979+
3980+ property string sortingMethod: "Name"
3981+
3982+ onSortingMethodChanged: {
3983+ console.log("Sorting by: " + sortingMethod)
3984+ if (sortingMethod === "Name") {
3985+ pageModel.sortBy = FolderListModel.SortByName
3986+ } else if (sortingMethod === "Date") {
3987+ pageModel.sortBy = FolderListModel.SortByDate
3988+ } else {
3989+ // Something fatal happened!
3990+ console.log("ERROR: Invalid sort type:", sortingMethod)
3991+ }
3992+ }
3993+
3994+ property bool sortAccending: true
3995+
3996+ onSortAccendingChanged: {
3997+ console.log("Sorting accending: " + sortAccending)
3998+
3999+ if (sortAccending) {
4000+ pageModel.sortOrder = FolderListModel.SortAscending
4001+ } else {
4002+ pageModel.sortOrder = FolderListModel.SortDescending
4003+ }
4004+ }
4005+
4006+ // This stores the location using ~ to represent home
4007+ property string folder
4008+ property string homeFolder: "~"
4009+
4010+ // This replaces ~ with the actual home folder, since the
4011+ // plugin doesn't recognize the ~
4012+ property string path: folder.replace("~", pageModel.homePath())
4013+
4014+ function goHome() {
4015+ goTo(folderListPage.homeFolder)
4016+ }
4017+
4018+ function goTo(location) {
4019+ // Since the FolderListModel returns paths using the actual
4020+ // home folder, this replaces with ~ before actually going
4021+ // to the specified folder
4022+ while (location !== '/' && location.substring(location.lastIndexOf('/')+1) === "") {
4023+ location = location.substring(0, location.length - 1)
4024+ }
4025+
4026+ folderListPage.folder = location.replace(pageModel.homePath(), "~")
4027+ refresh()
4028+ }
4029+
4030+ function refresh() {
4031+ pageModel.refresh()
4032+ }
4033+
4034+ function pathAccessedDate() {
4035+ console.log("calling method pageModel.curPathAccessedDate()")
4036+ return pageModel.curPathAccessedDate()
4037+ }
4038+
4039+ function pathModifiedDate() {
4040+ console.log("calling method pageModel.curPathModifiedDate()")
4041+ return pageModel.curPathModifiedDate()
4042+ }
4043+
4044+ function pathIsWritable() {
4045+ console.log("calling method pageModel.curPathIsWritable()")
4046+ return pageModel.curPathIsWritable()
4047+ }
4048+
4049+ // FIXME: hard coded path for icon, assumes Ubuntu desktop icon available.
4050+ // Nemo mobile has icon provider. Have to figure out what's the proper way
4051+ // to get "system wide" icons in Ubuntu Touch, or if we have to use
4052+ // icons packaged into the application. Both folder and individual
4053+ // files will need an icon.
4054+ // TODO: Remove isDir parameter and use new model functions
4055+ function fileIcon(file, isDir) {
4056+ file = file.replace(pageModel.homePath(), "~")
4057+ var iconPath = isDir ? "/usr/share/icons/Humanity/places/48/folder.svg"
4058+ : "/usr/share/icons/Humanity/mimes/48/empty.svg"
4059+
4060+ if (file === "~") {
4061+ iconPath = "../icons/folder-home.svg"
4062+ } else if (file === i18n.tr("~/Desktop")) {
4063+ iconPath = "/usr/share/icons/Humanity/places/48/user-desktop.svg"
4064+ } else if (file === i18n.tr("~/Documents")) {
4065+ iconPath = "/usr/share/icons/Humanity/places/48/folder-documents.svg"
4066+ } else if (file === i18n.tr("~/Downloads")) {
4067+ iconPath = "/usr/share/icons/Humanity/places/48/folder-downloads.svg"
4068+ } else if (file === i18n.tr("~/Music")) {
4069+ iconPath = "/usr/share/icons/Humanity/places/48/folder-music.svg"
4070+ } else if (file === i18n.tr("~/Pictures")) {
4071+ iconPath = "/usr/share/icons/Humanity/places/48/folder-pictures.svg"
4072+ } else if (file === i18n.tr("~/Public")) {
4073+ iconPath = "/usr/share/icons/Humanity/places/48/folder-publicshare.svg"
4074+ } else if (file === i18n.tr("~/Programs")) {
4075+ iconPath = "/usr/share/icons/Humanity/places/48/folder-system.svg"
4076+ } else if (file === i18n.tr("~/Templates")) {
4077+ iconPath = "/usr/share/icons/Humanity/places/48/folder-templates.svg"
4078+ } else if (file === i18n.tr("~/Videos")) {
4079+ iconPath = "/usr/share/icons/Humanity/places/48/folder-videos.svg"
4080+ } else if (file === "/") {
4081+ iconPath = "/usr/share/icons/Humanity/devices/48/drive-harddisk.svg"
4082+ }
4083+
4084+ return Qt.resolvedUrl(iconPath)
4085+ }
4086+
4087+ function folderName(folder) {
4088+ folder = folder.replace(pageModel.homePath(), "~")
4089+
4090+ if (folder === folderListPage.homeFolder) {
4091+ return i18n.tr("Home")
4092+ } else if (folder === "/") {
4093+ return i18n.tr("File System")
4094+ } else {
4095+ return folder.substr(folder.lastIndexOf('/') + 1)
4096+ }
4097+ }
4098+
4099+ function pathName(folder) {
4100+ if (folder === "/") {
4101+ return "/"
4102+ } else {
4103+ return folder.substr(folder.lastIndexOf('/') + 1)
4104+ }
4105+ }
4106+
4107+ function pathExists(path) {
4108+ path = path.replace("~", pageModel.homePath())
4109+
4110+ if (path === '/')
4111+ return true
4112+
4113+ if(path.charAt(0) === '/') {
4114+ console.log("Directory: " + path.substring(0, path.lastIndexOf('/')+1))
4115+ repeaterModel.path = path.substring(0, path.lastIndexOf('/')+1)
4116+ console.log("Sub dir: " + path.substring(path.lastIndexOf('/')+1))
4117+ if (path.substring(path.lastIndexOf('/')+1) !== "" && !repeaterModel.cdIntoPath(path.substring(path.lastIndexOf('/')+1))) {
4118+ return false
4119+ } else {
4120+ return true
4121+ }
4122+ } else {
4123+ return false
4124+ }
4125+ }
4126+
4127+ property bool loading: pageModel.awaitingResults
4128+
4129+ FolderListModel {
4130+ id: pageModel
4131+
4132+ path: folderListPage.path
4133+
4134+ enableExternalFSWatcher: true
4135+
4136+ // Properties to emulate a model entry for use by FileDetailsPopover
4137+ property bool isDir: true
4138+ property string fileName: pathName(pageModel.path)
4139+ property string fileSize: (folderListView.count === 1
4140+ ? i18n.tr("1 file")
4141+ : i18n.tr("%1 files").arg(folderListView.count))
4142+ property bool isReadable: true
4143+ property bool isExecutable: true
4144+ }
4145+
4146+ FolderListModel {
4147+ id: repeaterModel
4148+ path: folderListPage.folder
4149+
4150+ onPathChanged: {
4151+ console.log("Path: " + repeaterModel.path)
4152+ }
4153+ }
4154+
4155+ Component {
4156+ id: tabsPopover
4157+ ActionSelectionPopover {
4158+ objectName: "tabsPopover"
4159+
4160+ property var tab
4161+
4162+ grabDismissAreaEvents: true
4163+
4164+ actions: ActionList {
4165+ Action {
4166+ text: i18n.tr("Open in a new tab")
4167+ onTriggered: {
4168+ openTab(folderListPage.folder)
4169+ }
4170+ }
4171+
4172+ // The current tab can be closed as long as there is at least one tab remaining
4173+ Action {
4174+ text: i18n.tr("Close this tab")
4175+ onTriggered: {
4176+ closeTab(tab.index)
4177+ }
4178+ enabled: tabs.count > 1
4179+ }
4180+ }
4181+ }
4182+ }
4183+
4184+ Component {
4185+ id: folderActionsPopoverComponent
4186+ ActionSelectionPopover {
4187+ id: folderActionsPopover
4188+ objectName: "folderActionsPopover"
4189+
4190+ grabDismissAreaEvents: true
4191+
4192+ actions: ActionList {
4193+ Action {
4194+ text: i18n.tr("Create New Folder")
4195+ onTriggered: {
4196+ print(text)
4197+
4198+ PopupUtils.open(createFolderDialog, folderListPage)
4199+ }
4200+ }
4201+
4202+ // TODO: Disabled until backend supports creating files
4203+ // Action {
4204+ // text: i18n.tr("Create New File")
4205+ // onTriggered: {
4206+ // print(text)
4207+
4208+ // PopupUtils.open(createFileDialog, root)
4209+ // }
4210+ // }
4211+
4212+ Action {
4213+ text: pageModel.clipboardUrlsCounter === 0
4214+ ? i18n.tr("Paste")
4215+ : pageModel.clipboardUrlsCounter === 1
4216+ ? i18n.tr("Paste %1 File").arg(pageModel.clipboardUrlsCounter)
4217+ : i18n.tr("Paste %1 Files").arg(pageModel.clipboardUrlsCounter)
4218+ onTriggered: {
4219+ console.log("Pasting to current folder items of count " + pageModel.clipboardUrlsCounter)
4220+ fileOperationDialog.startOperation(i18n.tr("Paste files"))
4221+ pageModel.paste()
4222+ }
4223+
4224+ // FIXME: This property is depreciated and doesn't seem to work!
4225+ //visible: pageModel.clipboardUrlsCounter > 0
4226+
4227+ enabled: pageModel.clipboardUrlsCounter > 0
4228+ }
4229+
4230+ // TODO: Disabled until support for opening apps is added
4231+ Action {
4232+ text: i18n.tr("Open in Terminal")
4233+ onTriggered: {
4234+ print(text)
4235+
4236+ // Is this the way it will work??
4237+ Qt.openUrlExternally("app://terminal")
4238+ }
4239+
4240+ enabled: showAdvancedFeatures && false
4241+ }
4242+
4243+ Action {
4244+ text: i18n.tr("Properties")
4245+ onTriggered: {
4246+ print(text)
4247+ PopupUtils.open(Qt.resolvedUrl("FileDetailsPopover.qml"),
4248+ folderListPage,
4249+ { "model": pageModel
4250+ }
4251+ )
4252+ }
4253+ }
4254+ }
4255+ }
4256+ }
4257+
4258+ Component {
4259+ id: createFolderDialog
4260+ ConfirmDialogWithInput {
4261+ title: i18n.tr("Create folder")
4262+ text: i18n.tr("Enter name for new folder")
4263+
4264+ onAccepted: {
4265+ console.log("Create folder accepted", inputText)
4266+ if (inputText !== '') {
4267+ pageModel.mkdir(inputText)
4268+ } else {
4269+ console.log("Empty directory name, ignored")
4270+ }
4271+ }
4272+ }
4273+ }
4274+
4275+ Component {
4276+ id: createFileDialog
4277+ ConfirmDialogWithInput {
4278+ title: i18n.tr("Create file")
4279+ text: i18n.tr("Enter name for new file")
4280+
4281+ onAccepted: {
4282+ console.log("Create file accepted", inputText)
4283+ if (inputText !== '') {
4284+ //FIXME: Actually create a new file!
4285+ } else {
4286+ console.log("Empty file name, ignored")
4287+ }
4288+ }
4289+ }
4290+ }
4291+
4292+ function openFile(filePath) {
4293+ if (!pageModel.openPath(filePath)) {
4294+ error(i18n.tr("File operation error"), i18n.tr("Unable to open '%11").arg(filePath))
4295+ }
4296+ }
4297+
4298+ tools: ToolbarItems {
4299+ id: toolbar
4300+ locked: showToolbar
4301+ opened: showToolbar
4302+
4303+ onLockedChanged: opened = locked
4304+
4305+ back: ToolbarButton {
4306+ objectName: "up"
4307+ text: "Up"
4308+ iconSource: getIcon("keyboard-caps")
4309+ enabled: folder != "/"
4310+ onTriggered: {
4311+ goTo(pageModel.parentPath)
4312+ }
4313+ }
4314+
4315+ Item {
4316+ id: pathItem
4317+ width: folderListPage.width - units.gu(37)
4318+ height: units.gu(5)
4319+ anchors.verticalCenter: parent.verticalCenter
4320+ PathBar {
4321+ height: units.gu(5)
4322+ width: Math.min(pathItem.width, implicitWidth)
4323+ visible: sidebar.expanded
4324+ }
4325+ }
4326+
4327+ Item {
4328+ width: units.gu(1)
4329+ height: parent.height
4330+ }
4331+
4332+ ToolbarButton {
4333+ id: actionsButton
4334+ objectName: "actions"
4335+ text: i18n.tr("Actions")
4336+ iconSource: getIcon("navigation-menu")
4337+
4338+ onTriggered: {
4339+ print(text)
4340+ PopupUtils.open(folderActionsPopoverComponent, actionsButton)
4341+ }
4342+ }
4343+
4344+ ToolbarButton {
4345+ text: i18n.tr("View")
4346+ iconSource: getIcon("properties")
4347+ id: optionsButton
4348+
4349+ onTriggered: {
4350+ print(text)
4351+
4352+ PopupUtils.open(Qt.resolvedUrl("ViewPopover.qml"), optionsButton)
4353+ }
4354+ }
4355+
4356+ ToolbarButton {
4357+ id: placesButton
4358+ visible: !sidebar.expanded
4359+ objectName: "places"
4360+ text: i18n.tr("Places")
4361+ iconSource: getIcon("location")
4362+ onTriggered: {
4363+ print(text)
4364+
4365+ PopupUtils.open(Qt.resolvedUrl("PlacesPopover.qml"), placesButton)
4366+ }
4367+ }
4368+
4369+ ToolbarButton {
4370+ id: tabsButton
4371+ objectName: "tabs"
4372+ text: i18n.tr("Tabs")
4373+ iconSource: getIcon("browser-tabs")
4374+
4375+ onTriggered: {
4376+ print(text)
4377+
4378+ PopupUtils.open(tabsPopover, tabsButton, {
4379+ tab: folderListPage.parent
4380+ })
4381+ }
4382+ }
4383+
4384+ ToolbarButton {
4385+ id: settingsButton
4386+ visible: sidebar.expanded
4387+ objectName: "settings"
4388+ action: settingsAction
4389+ }
4390+ }
4391+
4392+ flickable: !sidebar.expanded ? folderListView.visible ? folderListView : folderIconView.flickable : null
4393+
4394+ onFlickableChanged: {
4395+ if (flickable === null) {
4396+ folderListView.topMargin = 0
4397+ folderIconView.flickable.topMargin = 0
4398+ } else {
4399+ folderListView.topMargin = units.gu(9.5)
4400+ folderIconView.flickable.topMargin = units.gu(9.5)
4401+ }
4402+ }
4403+
4404+ PlacesSidebar {
4405+ id: sidebar
4406+ objectName: "placesSidebar"
4407+
4408+// anchors {
4409+// top: parent.top
4410+// bottom: parent.bottom
4411+// bottomMargin: units.gu(-2)
4412+// }
4413+
4414+ expanded: showSidebar
4415+ }
4416+
4417+ FolderIconView {
4418+ id: folderIconView
4419+
4420+ clip: true
4421+
4422+ folderListModel: pageModel
4423+ anchors {
4424+ top: parent.top
4425+ bottom: parent.bottom
4426+ left: sidebar.right
4427+ right: parent.right
4428+ }
4429+ smallMode: !sidebar.expanded
4430+ visible: viewMethod === i18n.tr("Icons")
4431+ }
4432+
4433+ FolderListView {
4434+ id: folderListView
4435+
4436+ clip: true
4437+
4438+ folderListModel: pageModel
4439+ anchors {
4440+ top: parent.top
4441+ bottom: parent.bottom
4442+ left: sidebar.right
4443+ right: parent.right
4444+ }
4445+ smallMode: !sidebar.expanded
4446+ visible: viewMethod === i18n.tr("List")
4447+ }
4448+
4449+ Item {
4450+ id: contents
4451+
4452+ anchors {
4453+ top: parent.top
4454+ bottom: parent.bottom
4455+ left: sidebar.right
4456+ right: parent.right
4457+ }
4458+
4459+
4460+ Label {
4461+ text: i18n.tr("No files")
4462+ fontSize: "large"
4463+ opacity: 0.5
4464+ anchors.centerIn: parent
4465+ visible: folderListView.count == 0 && !pageModel.awaitingResults
4466+ }
4467+
4468+ ActivityIndicator {
4469+ running: pageModel.awaitingResults
4470+ width: units.gu(8)
4471+ height: units.gu(8)
4472+ anchors.centerIn: parent
4473+ }
4474+ }
4475+
4476+ Component {
4477+ id: confirmSingleDeleteDialog
4478+ ConfirmDialog {
4479+ property string filePath
4480+ property string fileName
4481+ title: i18n.tr("Delete")
4482+ text: i18n.tr("Are you sure you want to permanently delete '%1'?").arg(fileName)
4483+
4484+ onAccepted: {
4485+ console.log("Delete accepted for filePath, fileName", filePath, fileName)
4486+
4487+ fileOperationDialog.startOperation("Deleting files")
4488+ console.log("Doing delete")
4489+ pageModel.rm(filePath)
4490+ }
4491+ }
4492+ }
4493+
4494+ Component {
4495+ id: confirmRenameDialog
4496+ ConfirmDialogWithInput {
4497+ // IMPROVE: this does not seem good: the backend excepts row and new name.
4498+ // But what if new files are added/deleted in the background while user is
4499+ // entering the new name? The indices change and wrong file is renamed.
4500+ // Perhaps the backend should take as parameters the "old name" and "new name"?
4501+ // This is not currently a problem since the backend does not poll changes in
4502+ // the filesystem, but may be a problem in the future.
4503+ property int modelRow
4504+
4505+ title: i18n.tr("Rename")
4506+ text: i18n.tr("Enter a new name")
4507+
4508+ onAccepted: {
4509+ console.log("Rename accepted", inputText)
4510+ if (inputText !== '') {
4511+ console.log("Rename commensed, modelRow/inputText", modelRow, inputText)
4512+ if (pageModel.rename(modelRow, inputText) === false) {
4513+ PopupUtils.open(Qt.resolvedUrl("NotifyDialog.qml"), delegate,
4514+ {
4515+ title: i18n.tr("Could not rename"),
4516+ text: i18n.tr("Insufficient permissions or name already exists?")
4517+ })
4518+
4519+ }
4520+ } else {
4521+ console.log("Empty new name given, ignored")
4522+ }
4523+ }
4524+ }
4525+ }
4526+
4527+ Component {
4528+ id: actionSelectionPopoverComponent
4529+
4530+ ActionSelectionPopover {
4531+ id: actionSelectionPopover
4532+ objectName: "fileActionsPopover"
4533+
4534+ grabDismissAreaEvents: true
4535+
4536+ property var model
4537+ actions: ActionList {
4538+ Action {
4539+ text: i18n.tr("Cut")
4540+ // TODO: temporary
4541+ iconSource: "/usr/share/icons/Humanity/actions/48/edit-cut.svg"
4542+ onTriggered: {
4543+ console.log("Cut on row called for", actionSelectionPopover.model.fileName, actionSelectionPopover.model.index)
4544+ pageModel.cutIndex(actionSelectionPopover.model.index)
4545+ console.log("CliboardUrlsCounter after copy", pageModel.clipboardUrlsCounter)
4546+ }
4547+ }
4548+
4549+ Action {
4550+ text: i18n.tr("Copy")
4551+ // TODO: temporary.
4552+ iconSource: "/usr/share/icons/Humanity/actions/48/edit-copy.svg"
4553+
4554+ onTriggered: {
4555+ console.log("Copy on row called for", actionSelectionPopover.model.fileName, actionSelectionPopover.model.index)
4556+ pageModel.copyIndex(actionSelectionPopover.model.index)
4557+ console.log("CliboardUrlsCounter after copy", pageModel.clipboardUrlsCounter)
4558+ }
4559+ }
4560+
4561+ Action {
4562+ text: i18n.tr("Delete")
4563+ // TODO: temporary
4564+ iconSource: "/usr/share/icons/Humanity/actions/48/edit-delete.svg"
4565+ onTriggered: {
4566+ print(text)
4567+ PopupUtils.open(confirmSingleDeleteDialog, actionSelectionPopover.caller,
4568+ { "filePath" : actionSelectionPopover.model.filePath,
4569+ "fileName" : actionSelectionPopover.model.fileName }
4570+ )
4571+ }
4572+ }
4573+
4574+ Action {
4575+ text: i18n.tr("Rename")
4576+ // TODO: temporary
4577+ iconSource: "/usr/share/icons/Humanity/actions/48/rotate.svg"
4578+ onTriggered: {
4579+ print(text)
4580+ PopupUtils.open(confirmRenameDialog, actionSelectionPopover.caller,
4581+ { "modelRow" : actionSelectionPopover.model.index,
4582+ "inputText" : actionSelectionPopover.model.fileName
4583+ })
4584+ }
4585+ }
4586+
4587+ Action {
4588+ text: i18n.tr("Properties")
4589+ onTriggered: {
4590+ print(text)
4591+ PopupUtils.open(Qt.resolvedUrl("FileDetailsPopover.qml"),
4592+ actionSelectionPopover.caller,
4593+ { "model": actionSelectionPopover.model
4594+ }
4595+ )
4596+ }
4597+ }
4598+ }
4599+ }
4600+ }
4601+
4602+ // Errors from model
4603+ Connections {
4604+ target: pageModel
4605+ onError: {
4606+ console.log("FolderListModel Error Title/Description", errorTitle, errorMessage)
4607+ error(i18n.tr("File operation error"), errorTitle + ": " + errorMessage)
4608+ }
4609+ }
4610+
4611+ FileOperationProgressDialog {
4612+ id: fileOperationDialog
4613+
4614+ page: folderListPage
4615+ model: pageModel
4616+ }
4617+
4618+ function itemClicked(model) {
4619+ if (model.isDir) {
4620+ if (model.isReadable && model.isExecutable) {
4621+ console.log("Changing to dir", model.filePath)
4622+ goTo(model.filePath)
4623+ } else {
4624+ PopupUtils.open(Qt.resolvedUrl("NotifyDialog.qml"), delegate,
4625+ {
4626+ title: i18n.tr("Folder not accessible"),
4627+ text: i18n.tr("Can not access ") + model.fileName
4628+
4629+ })
4630+ }
4631+ } else {
4632+ console.log("Non dir clicked")
4633+ openFile(model.fileName)
4634+// PopupUtils.open(Qt.resolvedUrl("FileActionDialog.qml"), root,
4635+// {
4636+// fileName: model.fileName,
4637+// filePath: model.filePath,
4638+// folderListModel: root.folderListModel
4639+// })
4640+ }
4641+ }
4642+
4643+ function itemLongPress(delegate, model) {
4644+ console.log("FolderListDelegate onPressAndHold")
4645+ PopupUtils.open(actionSelectionPopoverComponent, delegate,
4646+ {
4647+ model: model
4648+ })
4649+ }
4650+
4651+ function keyPressed(key, modifiers) {
4652+ if (key === Qt.Key_L && modifiers & Qt.ControlModifier) {
4653+ PopupUtils.open(Qt.resolvedUrl("GoToDialog.qml"), goToButton)
4654+ return true;
4655+ }
4656+
4657+ return false;
4658+ }
4659+
4660+ Component.onCompleted: forceActiveFocus()
4661+}
4662
4663=== added file 'ui/GoToDialog.qml'
4664--- ui/GoToDialog.qml 1970-01-01 00:00:00 +0000
4665+++ ui/GoToDialog.qml 2014-02-19 00:47:29 +0000
4666@@ -0,0 +1,84 @@
4667+/*
4668+ * Copyright (C) 2013 Canonical Ltd
4669+ *
4670+ * This program is free software: you can redistribute it and/or modify
4671+ * it under the terms of the GNU General Public License version 3 as
4672+ * published by the Free Software Foundation.
4673+ *
4674+ * This program is distributed in the hope that it will be useful,
4675+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4676+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4677+ * GNU General Public License for more details.
4678+ *
4679+ * You should have received a copy of the GNU General Public License
4680+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4681+ *
4682+ * Authored by: Michael Spencer <sonrisesoftware@gmail.com>
4683+ */
4684+import QtQuick 2.0
4685+import Ubuntu.Components 0.1
4686+import Ubuntu.Components.Popups 0.1
4687+
4688+Dialog {
4689+ id: root
4690+
4691+ title: i18n.tr("Go To Location")
4692+
4693+ text: i18n.tr("Enter a location to go to:")
4694+
4695+ Component.onCompleted: {
4696+ locationField.forceActiveFocus()
4697+ locationField.cursorPosition = locationField.text.length
4698+ }
4699+
4700+ TextField {
4701+ id: locationField
4702+ objectName: "inputField"
4703+
4704+ inputMethodHints: Qt.ImhNoAutoUppercase
4705+
4706+ property bool valid: pathExists(text)
4707+
4708+ text: fileView.path
4709+
4710+ placeholderText: i18n.tr("Location...")
4711+
4712+ onAccepted: goButton.clicked()
4713+ }
4714+
4715+ Button {
4716+ id: goButton
4717+ objectName: "okButton"
4718+
4719+ text: i18n.tr("Go")
4720+ enabled: locationField.acceptableInput && locationField.valid
4721+
4722+ onClicked: {
4723+ print("User switched to:", locationField.text)
4724+ goTo(locationField.text)
4725+ PopupUtils.close(root)
4726+ }
4727+ }
4728+
4729+ Button {
4730+ id: cancelButton
4731+ objectName: "cancelButton"
4732+ text: i18n.tr("Cancel")
4733+
4734+ gradient: Gradient {
4735+ GradientStop {
4736+ position: 0
4737+ color: "gray"
4738+ }
4739+
4740+ GradientStop {
4741+ position: 1
4742+ color: "lightgray"
4743+ }
4744+ }
4745+
4746+ onClicked: {
4747+ PopupUtils.close(root)
4748+ }
4749+ }
4750+}
4751
4752=== added file 'ui/NotifyDialog.qml'
4753--- ui/NotifyDialog.qml 1970-01-01 00:00:00 +0000
4754+++ ui/NotifyDialog.qml 2014-02-19 00:47:29 +0000
4755@@ -0,0 +1,30 @@
4756+/*
4757+ * Copyright (C) 2013 Canonical Ltd
4758+ *
4759+ * This program is free software: you can redistribute it and/or modify
4760+ * it under the terms of the GNU General Public License version 3 as
4761+ * published by the Free Software Foundation.
4762+ *
4763+ * This program is distributed in the hope that it will be useful,
4764+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4765+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4766+ * GNU General Public License for more details.
4767+ *
4768+ * You should have received a copy of the GNU General Public License
4769+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4770+ *
4771+ * Authored by: Arto Jalkanen <ajalkane@gmail.com>
4772+ */
4773+import QtQuick 2.0
4774+import Ubuntu.Components 0.1
4775+import Ubuntu.Components.Popups 0.1
4776+
4777+Dialog {
4778+ id: root
4779+ Button {
4780+ text: i18n.tr("Ok")
4781+ onClicked: {
4782+ PopupUtils.close(root)
4783+ }
4784+ }
4785+}
4786
4787=== added file 'ui/PlacesPopover.qml'
4788--- ui/PlacesPopover.qml 1970-01-01 00:00:00 +0000
4789+++ ui/PlacesPopover.qml 2014-02-19 00:47:29 +0000
4790@@ -0,0 +1,140 @@
4791+/*
4792+ * Copyright (C) 2013 Canonical Ltd
4793+ *
4794+ * This program is free software: you can redistribute it and/or modify
4795+ * it under the terms of the GNU General Public License version 3 as
4796+ * published by the Free Software Foundation.
4797+ *
4798+ * This program is distributed in the hope that it will be useful,
4799+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4800+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4801+ * GNU General Public License for more details.
4802+ *
4803+ * You should have received a copy of the GNU General Public License
4804+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4805+ *
4806+ * Authored by: Michael Spencer <sonrisesoftware@gmail.com>
4807+ */
4808+import QtQuick 2.0
4809+import Ubuntu.Components 0.1
4810+import Ubuntu.Components.Popups 0.1
4811+import Ubuntu.Components.ListItems 0.1
4812+
4813+Popover {
4814+ id: root
4815+ objectName: "placesPopover"
4816+
4817+ ListModel {
4818+ id: places
4819+
4820+ ListElement {
4821+ path: "~"
4822+ }
4823+
4824+ ListElement {
4825+ path: "~/Documents"
4826+ }
4827+
4828+ ListElement {
4829+ path: "~/Downloads"
4830+ }
4831+
4832+ ListElement {
4833+ path: "~/Music"
4834+ }
4835+
4836+ ListElement {
4837+ path: "~/Pictures"
4838+ }
4839+
4840+ ListElement {
4841+ path: "~/Videos"
4842+ }
4843+
4844+ ListElement {
4845+ path: "/"
4846+ }
4847+ }
4848+
4849+ Column {
4850+ anchors {
4851+ left: parent.left
4852+ right: parent.right
4853+ top: parent.top
4854+ }
4855+
4856+ Empty {
4857+
4858+ TextField {
4859+ id: locationField
4860+ objectName: "inputField"
4861+ anchors {
4862+ verticalCenter: parent.verticalCenter
4863+ left: parent.left
4864+ right: goButton.left
4865+ margins: units.gu(1)
4866+ }
4867+
4868+ inputMethodHints: Qt.ImhNoAutoUppercase
4869+
4870+ property bool valid: pathExists(text)
4871+
4872+ text: fileView.path
4873+
4874+ placeholderText: i18n.tr("Location...")
4875+
4876+ onAccepted: goButton.clicked()
4877+ }
4878+
4879+ Button {
4880+ id: goButton
4881+ objectName: "okButton"
4882+ anchors {
4883+ top: locationField.top
4884+ bottom: locationField.bottom
4885+ right: parent.right
4886+ rightMargin: units.gu(1)
4887+ }
4888+
4889+ text: i18n.tr("Go")
4890+ enabled: locationField.acceptableInput && locationField.valid
4891+
4892+ onClicked: {
4893+ print("User switched to:", locationField.text)
4894+ goTo(locationField.text)
4895+ PopupUtils.close(root)
4896+ }
4897+ }
4898+ }
4899+
4900+ Repeater {
4901+ id: placesList
4902+ objectName: "placesList"
4903+
4904+ model: places
4905+
4906+ delegate: Standard {
4907+ property string name: folderName(path)
4908+
4909+ Label {
4910+ anchors.left: parent.left
4911+ anchors.leftMargin: units.gu(8)
4912+ anchors.verticalCenter: parent.verticalCenter
4913+ text: folderName(path)
4914+ color: selected ? UbuntuColors.orange : Theme.palette.normal.overlayText
4915+ }
4916+
4917+ iconSource: model.icon || fileIcon(model.path, true)
4918+
4919+ onClicked: {
4920+ PopupUtils.close(root)
4921+ goTo(model.path)
4922+ }
4923+
4924+ selected: folder === path
4925+ iconFrame: false
4926+ showDivider: index < (placesList.count - 1)
4927+ }
4928+ }
4929+ }
4930+}
4931
4932=== added file 'ui/SettingsSheet.qml'
4933--- ui/SettingsSheet.qml 1970-01-01 00:00:00 +0000
4934+++ ui/SettingsSheet.qml 2014-02-19 00:47:29 +0000
4935@@ -0,0 +1,53 @@
4936+/*
4937+ * Copyright (C) 2013 Canonical Ltd
4938+ *
4939+ * This program is free software: you can redistribute it and/or modify
4940+ * it under the terms of the GNU General Public License version 3 as
4941+ * published by the Free Software Foundation.
4942+ *
4943+ * This program is distributed in the hope that it will be useful,
4944+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4945+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4946+ * GNU General Public License for more details.
4947+ *
4948+ * You should have received a copy of the GNU General Public License
4949+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4950+ *
4951+ * Authored by: Michael Spencer <sonrisesoftware@gmail.com>
4952+ */
4953+import QtQuick 2.0
4954+import Ubuntu.Components 0.1
4955+import Ubuntu.Components.ListItems 0.1
4956+import Ubuntu.Components.Popups 0.1
4957+
4958+/*
4959+ * The Settings page holds global settings/preferences.
4960+ *
4961+ * TODO: Make sure this fits with the UI guidelines if
4962+ * they are updated to include About/Settings info.
4963+ */
4964+DefaultSheet {
4965+ id: sheet
4966+ title: i18n.tr("Settings")
4967+
4968+ Component.onCompleted: {
4969+ sheet.__leftButton.text = i18n.tr("Close")
4970+ sheet.__foreground.style = Theme.createStyleComponent(Qt.resolvedUrl("../components/SuruSheetStyle.qml"), sheet)
4971+ }
4972+
4973+ Column {
4974+ anchors.fill: parent
4975+ anchors.margins: units.gu(-1)
4976+
4977+ Standard {
4978+ text: i18n.tr("Show Advanced Features")
4979+ control: CheckBox {
4980+ id: showAdvancedFeaturesCheckBox
4981+ checked: showAdvancedFeatures
4982+ onCheckedChanged: {
4983+ saveSetting("showAdvancedFeatures", showAdvancedFeaturesCheckBox.checked ? "true" : "false");
4984+ }
4985+ }
4986+ }
4987+ }
4988+}
4989
4990=== added file 'ui/ViewPopover.qml'
4991--- ui/ViewPopover.qml 1970-01-01 00:00:00 +0000
4992+++ ui/ViewPopover.qml 2014-02-19 00:47:29 +0000
4993@@ -0,0 +1,155 @@
4994+/*
4995+ * Copyright (C) 2013 Canonical Ltd
4996+ *
4997+ * This program is free software: you can redistribute it and/or modify
4998+ * it under the terms of the GNU General Public License version 3 as
4999+ * published by the Free Software Foundation.
5000+ *
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches