Merge lp:~ibelieve/ubuntu-filemanager-app/improved-toolbar into lp:ubuntu-filemanager-app

Proposed by Michael Spencer
Status: Merged
Approved by: Arto Jalkanen
Approved revision: 56
Merged at revision: 38
Proposed branch: lp:~ibelieve/ubuntu-filemanager-app/improved-toolbar
Merge into: lp:ubuntu-filemanager-app
Prerequisite: lp:~ibelieve/ubuntu-filemanager-app/improved-ui
Diff against target: 993 lines (+625/-106)
12 files modified
ConfirmDialog.qml (+13/-0)
ConfirmDialogWithInput.qml (+17/-0)
FileDetailsPopover.qml (+22/-7)
FileOperationProgressDialog.qml (+8/-0)
FolderListDelegate.qml (+3/-6)
FolderListPage.qml (+276/-50)
FolderListView.qml (+26/-22)
PlacesPopover.qml (+137/-0)
SettingsPopover.qml (+75/-0)
tests/autopilot/ubuntu_filemanager_app/emulators/main_window.py (+6/-1)
tests/autopilot/ubuntu_filemanager_app/tests/test_filemanager.py (+35/-6)
ubuntu-filemanager-app.qml (+7/-14)
To merge this branch: bzr merge lp:~ibelieve/ubuntu-filemanager-app/improved-toolbar
Reviewer Review Type Date Requested Status
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Arto Jalkanen Approve
Review via email: mp+171639@code.launchpad.net

Commit message

Redesigned the toolbar and added settings and some new features

Description of the change

This adds the following new features to the toolbar:

* Places (bookmarks) menu & location entry field
* Actions menu
* Settings menu

This also adds the following new settings:

* Show hidden files
* Sort by name/date
* Sort ascending/descending

In addition, this adds a Properties popover for the current folder.

To post a comment you must log in.
44. By Michael Spencer

Fixed paste action and made minor changes in order of actions and naming of dialogs

45. By Michael Spencer

Disabled hiding of paste action (doesn't work)

46. By Michael Spencer

Added settings menu and ability to show hidden files

47. By Michael Spencer

Added UI to sort the list of files

48. By Michael Spencer

Pulled in autopilot test and fixed it to work with the new UI

49. By Michael Spencer

Added test for going home and to the root folder (fixed LP# 1188734)

50. By Michael Spencer

Added UI to go to a location entered by the user

51. By Michael Spencer

Improved location entry UI

52. By Michael Spencer

Added path entry validation

53. By Michael Spencer

Added properties popover for the current folder and also added icons for file system root, home folder, and main folders in home

54. By Michael Spencer

Added more icons for common folders

Revision history for this message
Arto Jalkanen (ajalkane) wrote :

Great changes, thank you!

review: Approve
Revision history for this message
David Planella (dpm) wrote :

Nice work!

A couple of things that I've noticed:

- The toolbar icons are highly pixelated. Nothing that your branch can do about it, as it might be due to bug 1184569. Perhaps it might be worth shipping local copies of .png images until that bug is fixed?
- The properties popup for folders seem to always return "Unknown" for "Created:" and "Modified:"

55. By Michael Spencer

Added local png icons for the toolbar

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

> Nice work!
>
> A couple of things that I've noticed:
>
> - The toolbar icons are highly pixelated. Nothing that your branch can do
> about it, as it might be due to bug 1184569. Perhaps it might be worth
> shipping local copies of .png images until that bug is fixed?

I've added local copies for the 4 icons in the toolbar.

> - The properties popup for folders seem to always return "Unknown" for
> "Created:" and "Modified:"

Clicking on a folder and choosing Properties should work. If you mean clicking Actions and then Properties, that is because it's using new features from the model that Carlos just added, so it won't show up until the plugin gets updated. (Same with the current folder being writable or not).

56. By Michael Spencer

Colored the cancel buttons gray and made the go to location button green

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'ConfirmDialog.qml'
2--- ConfirmDialog.qml 2013-04-17 17:55:41 +0000
3+++ ConfirmDialog.qml 2013-07-03 15:05:30 +0000
4@@ -35,6 +35,19 @@
5
6 Button {
7 text: i18n.tr("Cancel")
8+
9+ gradient: Gradient {
10+ GradientStop {
11+ position: 0
12+ color: "gray"
13+ }
14+
15+ GradientStop {
16+ position: 1
17+ color: "lightgray"
18+ }
19+ }
20+
21 onClicked: {
22 rejected()
23 PopupUtils.close(root)
24
25=== modified file 'ConfirmDialogWithInput.qml'
26--- ConfirmDialogWithInput.qml 2013-04-17 17:55:41 +0000
27+++ ConfirmDialogWithInput.qml 2013-07-03 15:05:30 +0000
28@@ -29,10 +29,14 @@
29 TextField {
30 id: input
31 focus: true
32+ validator: RegExpValidator {
33+ regExp: /.+/
34+ }
35 }
36
37 Button {
38 text: i18n.tr("Ok")
39+ enabled: input.acceptableInput
40 onClicked: {
41 accepted()
42 PopupUtils.close(root)
43@@ -41,6 +45,19 @@
44
45 Button {
46 text: i18n.tr("Cancel")
47+
48+ gradient: Gradient {
49+ GradientStop {
50+ position: 0
51+ color: "gray"
52+ }
53+
54+ GradientStop {
55+ position: 1
56+ color: "lightgray"
57+ }
58+ }
59+
60 onClicked: {
61 rejected()
62 PopupUtils.close(root)
63
64=== modified file 'FileDetailsPopover.qml'
65--- FileDetailsPopover.qml 2013-06-25 23:43:54 +0000
66+++ FileDetailsPopover.qml 2013-07-03 15:05:30 +0000
67@@ -23,10 +23,12 @@
68 id: root
69 property var model
70
71+ property string path: model.path || (fileView.path + '/' + model.fileName)
72+
73 contentHeight: contents.height + 2 * contents.anchors.margins
74
75 function dateTimeFormat(dateTime) {
76- return Qt.formatDateTime(dateTime, Qt.DefaultLocaleShortDate)
77+ return Qt.formatDateTime(dateTime, Qt.DefaultLocaleShortDate) || "Uknown"
78 }
79
80 function permissionsToString(model) {
81@@ -66,22 +68,35 @@
82 Row {
83 spacing: units.gu(1)
84 Image {
85+ anchors.verticalCenter: parent.verticalCenter
86+
87 // TODO: how to get proper icon?
88- source: model.isDir
89- ? "/usr/share/icons/Humanity/places/48/folder.svg"
90- : "/usr/share/icons/Humanity/mimes/48/empty.svg"
91+ source: fileIcon(root.path, model.isDir)
92 }
93+
94 Label {
95- text: model.fileName
96 anchors.verticalCenter: parent.verticalCenter
97+
98+ text: folderName(root.path)
99+ font.bold: true
100 }
101 }
102
103 Grid {
104 columns: 2
105 spacing: units.gu(1)
106- Label {
107- text: i18n.tr("Size:")
108+
109+ Label {
110+ text: i18n.tr("Path:")
111+ }
112+
113+ Label {
114+ text: root.path
115+ }
116+
117+ Label {
118+ text: model.isDir ? i18n.tr("Contents:")
119+ : i18n.tr("Size:")
120 }
121 Label {
122 text: model.fileSize
123
124=== modified file 'FileOperationProgressDialog.qml'
125--- FileOperationProgressDialog.qml 2013-05-16 15:32:16 +0000
126+++ FileOperationProgressDialog.qml 2013-07-03 15:05:30 +0000
127@@ -57,4 +57,12 @@
128 }
129 }
130 }
131+
132+ // Errors from model
133+ Connections {
134+ target: pageModel
135+ onError: {
136+ PopupUtils.close(root)
137+ }
138+ }
139 }
140
141=== modified file 'FolderListDelegate.qml'
142--- FolderListDelegate.qml 2013-06-25 16:22:38 +0000
143+++ FolderListDelegate.qml 2013-07-03 15:05:30 +0000
144@@ -24,11 +24,8 @@
145 objectName: "folder" + index
146 text: model.fileName
147 subText: Qt.formatDateTime(model.modifiedDate, Qt.DefaultLocaleShortDate) + (!model.isDir ? ", " + fileSize : "")
148- // FIXME: hard coded path for icon, assumes Ubuntu desktop icon available.
149- // Nemo mobile has icon provider. Have to figure out what's the proper way
150- // to get "system wide" icons in Ubuntu Touch, or if we have to use
151- // icons packaged into the application. Both folder and individual
152- // files will need an icon.
153- icon: model.isDir ? "/usr/share/icons/Humanity/places/48/folder.svg" : "/usr/share/icons/Humanity/mimes/48/empty.svg"
154+
155+ property string path: fileView.path + '/' + model.fileName
156+ icon: fileIcon(path, model.isDir)
157 progression: model.isDir
158 }
159
160=== modified file 'FolderListPage.qml'
161--- FolderListPage.qml 2013-06-27 14:18:10 +0000
162+++ FolderListPage.qml 2013-07-03 15:05:30 +0000
163@@ -24,17 +24,146 @@
164 id: root
165 anchors.fill: parent
166
167+ title: folderName(folder)
168+
169+ property variant fileView: root
170+
171+ property bool showHiddenFiles: false
172+
173+ onShowHiddenFilesChanged: {
174+ pageModel.showHiddenFiles = root.showHiddenFiles
175+ }
176+
177+ property string sortingMethod: "Name"
178+
179+ onSortingMethodChanged: {
180+ console.log("Sorting by: " + sortingMethod)
181+ if (sortingMethod === "Name") {
182+ pageModel.sortBy = FolderListModel.SortByName
183+ } else if (sortingMethod === "Date") {
184+ pageModel.sortBy = FolderListModel.SortByDate
185+ } else {
186+ // Something fatal happened!
187+ console.log("ERROR: Invalid sort type:", sortingMethod)
188+ }
189+ }
190+
191+ property bool sortAccending: true
192+
193+ onSortAccendingChanged: {
194+ console.log("Sorting accending: " + sortAccending)
195+
196+ if (sortAccending) {
197+ pageModel.sortOrder = FolderListModel.SortAscending
198+ } else {
199+ pageModel.sortOrder = FolderListModel.SortDescending
200+ }
201+ }
202+
203+ // This stores the location using ~ to represent home
204 property string folder
205- title: folderName(pageModel.path)
206- property string homeFolder: pageModel.homePath()
207+ property string homeFolder: "~"
208+
209+ // This replaces ~ with the actual home folder, since the
210+ // plugin doesn't recognize the ~
211+ property string path: folder.replace("~", pageModel.homePath())
212+
213+ function goHome() {
214+ goTo(root.homeFolder)
215+ }
216+
217+ function goTo(location) {
218+ // Since the FolderListModel returns paths using the actual
219+ // home folder, this replaces with ~ before actually going
220+ // to the specified folder
221+ while (location !== '/' && location.substring(location.lastIndexOf('/')+1) === "") {
222+ location = location.substring(0, location.length - 1)
223+ }
224+
225+ root.folder = location.replace(pageModel.homePath(), "~")
226+ refresh()
227+ }
228+
229+ function refresh() {
230+ pageModel.refresh()
231+ }
232+
233+ // FIXME: hard coded path for icon, assumes Ubuntu desktop icon available.
234+ // Nemo mobile has icon provider. Have to figure out what's the proper way
235+ // to get "system wide" icons in Ubuntu Touch, or if we have to use
236+ // icons packaged into the application. Both folder and individual
237+ // files will need an icon.
238+ // TODO: Remove isDir parameter and use new model functions
239+ function fileIcon(file, isDir) {
240+ file = file.replace(pageModel.homePath(), "~")
241+ if (file === "~") {
242+ return "/usr/share/icons/ubuntu-mono-dark/places/48/folder-home.svg"
243+ } else if (file === i18n.tr("~/Desktop")) {
244+ return "/usr/share/icons/Humanity/places/48/user-desktop.svg"
245+ } else if (file === i18n.tr("~/Documents")) {
246+ return "/usr/share/icons/Humanity/places/48/folder-documents.svg"
247+ } else if (file === i18n.tr("~/Downloads")) {
248+ return "/usr/share/icons/Humanity/places/48/folder-downloads.svg"
249+ } else if (file === i18n.tr("~/Music")) {
250+ return "/usr/share/icons/Humanity/places/48/folder-music.svg"
251+ } else if (file === i18n.tr("~/Pictures")) {
252+ return "/usr/share/icons/Humanity/places/48/folder-pictures.svg"
253+ } else if (file === i18n.tr("~/Public")) {
254+ return "/usr/share/icons/Humanity/places/48/folder-publicshare.svg"
255+ } else if (file === i18n.tr("~/Programs")) {
256+ return "/usr/share/icons/Humanity/places/48/folder-system.svg"
257+ } else if (file === i18n.tr("~/Templates")) {
258+ return "/usr/share/icons/Humanity/places/48/folder-templates.svg"
259+ } else if (file === i18n.tr("~/Videos")) {
260+ return "/usr/share/icons/Humanity/places/48/folder-videos.svg"
261+ } else if (file === "/") {
262+ return "/usr/share/icons/Humanity/devices/48/drive-harddisk.svg"
263+ }
264+
265+ if (isDir) {
266+ return "/usr/share/icons/Humanity/places/48/folder.svg"
267+ } else {
268+ return "/usr/share/icons/Humanity/mimes/48/empty.svg"
269+ }
270+ }
271
272 function folderName(folder) {
273- if (folder === pageModel.homePath()) {
274- return "Home"
275+ folder = folder.replace(pageModel.homePath(), "~")
276+
277+ if (folder === root.homeFolder) {
278+ return i18n.tr("Home")
279 } else if (folder === "/") {
280- return folder
281- } else {
282- return folder.substr(folder.lastIndexOf('/') + 1)
283+ return i18n.tr("File System")
284+ } else {
285+ return folder.substr(folder.lastIndexOf('/') + 1)
286+ }
287+ }
288+
289+ function pathName(folder) {
290+ if (folder === "/") {
291+ return "/"
292+ } else {
293+ return folder.substr(folder.lastIndexOf('/') + 1)
294+ }
295+ }
296+
297+ function pathExists(path) {
298+ path = path.replace("~", pageModel.homePath())
299+
300+ if (path === '/')
301+ return true
302+
303+ if(path.charAt(0) === '/') {
304+ console.log("Directory: " + path.substring(0, path.lastIndexOf('/')+1))
305+ repeaterModel.path = path.substring(0, path.lastIndexOf('/')+1)
306+ console.log("Sub dir: " + path.substring(path.lastIndexOf('/')+1))
307+ if (path.substring(path.lastIndexOf('/')+1) !== "" && !repeaterModel.cdIntoPath(path.substring(path.lastIndexOf('/')+1))) {
308+ return false
309+ } else {
310+ return true
311+ }
312+ } else {
313+ return false
314 }
315 }
316
317@@ -42,13 +171,103 @@
318
319 FolderListModel {
320 id: pageModel
321+
322+ path: root.path
323+
324+ // Properties to emulate a model entry for use by FileDetailsPopover
325+ property bool isDir: true
326+ property string fileName: pathName(pageModel.path)
327+ property string fileSize: (folderListView.count === 1
328+ ? i18n.tr("1 file")
329+ : i18n.tr("%1 files").arg(folderListView.count))
330+ property date creationDate: pageModel.pathCreatedDate
331+ property date modifiedDate: pageModel.pathModifiedDate
332+ property bool isWriteable: pageModel.pathIsWriteable
333+ property bool isReadable: true
334+ property bool isExecutable: true
335+ }
336+
337+ FolderListModel {
338+ id: repeaterModel
339 path: root.folder
340+
341+ onPathChanged: {
342+ console.log("Path: " + repeaterModel.path)
343+ }
344+ }
345+
346+ ActionSelectionPopover {
347+ id: folderActionsPopover
348+ objectName: "folderActionsPopover"
349+
350+ actions: ActionList {
351+ Action {
352+ text: i18n.tr("Create New Folder")
353+ onTriggered: {
354+ print(text)
355+
356+ PopupUtils.open(createFolderDialog, root)
357+ }
358+ }
359+
360+ // TODO: Disabled until backend supports creating files
361+// Action {
362+// text: i18n.tr("Create New File")
363+// onTriggered: {
364+// print(text)
365+
366+// PopupUtils.open(createFileDialog, root)
367+// }
368+// }
369+
370+ Action {
371+ text: pageModel.clipboardUrlsCounter === 0
372+ ? i18n.tr("Paste")
373+ : pageModel.clipboardUrlsCounter === 1
374+ ? i18n.tr("Paste %1 File").arg(pageModel.clipboardUrlsCounter)
375+ : i18n.tr("Paste %1 Files").arg(pageModel.clipboardUrlsCounter)
376+ onTriggered: {
377+ console.log("Pasting to current folder items of count " + pageModel.clipboardUrlsCounter)
378+ PopupUtils.open(Qt.resolvedUrl("FileOperationProgressDialog.qml"),
379+ root,
380+ {
381+ title: i18n.tr("Paste files"),
382+ folderListModel: pageModel
383+ }
384+ )
385+
386+
387+ pageModel.paste()
388+ }
389+
390+ // FIXME: This property is depreciated and doesn't seem to work!
391+ //visible: pageModel.clipboardUrlsCounter > 0
392+
393+ enabled: pageModel.clipboardUrlsCounter > 0
394+ }
395+
396+ Action {
397+ text: i18n.tr("Properties")
398+ onTriggered: {
399+ print(text)
400+ PopupUtils.open(Qt.resolvedUrl("FileDetailsPopover.qml"),
401+ root,
402+ { "model": pageModel
403+ }
404+ )
405+ }
406+ }
407+ }
408+
409+ // Without this the popover jumps up at the start of the application. SDK bug?
410+ // Bug report has been made of these https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1152270
411+ visible: false
412 }
413
414 Component {
415 id: createFolderDialog
416 ConfirmDialogWithInput {
417- title: i18n.tr("Create folder?")
418+ title: i18n.tr("Create folder")
419 text: i18n.tr("Enter name for new folder")
420
421 onAccepted: {
422@@ -62,6 +281,25 @@
423 }
424 }
425
426+ Component {
427+ id: createFileDialog
428+ ConfirmDialogWithInput {
429+ title: i18n.tr("Create file")
430+ text: i18n.tr("Enter name for new file")
431+
432+ onAccepted: {
433+ console.log("Create file accepted", inputText)
434+ if (inputText !== '') {
435+ //FIXME: Actually create a new file!
436+ } else {
437+ console.log("Empty file name, ignored")
438+ }
439+ }
440+ }
441+ }
442+
443+
444+
445 tools: ToolbarItems {
446 id: toolbar
447 locked: true
448@@ -69,7 +307,7 @@
449
450 back: ToolbarButton {
451 text: "Up"
452- iconSource: "/usr/share/icons/ubuntu-mobile/actions/scalable/keyboard-caps.svg"
453+ iconSource: "icons/up.png"
454 visible: folder != "/"
455 onTriggered: {
456 goTo(pageModel.parentPath)
457@@ -77,52 +315,40 @@
458 }
459
460 ToolbarButton {
461- text: i18n.tr("Paste" + " (" + pageModel.clipboardUrlsCounter + ")")
462- // TODO: temporary
463- iconSource: "/usr/share/icons/Humanity/actions/48/edit-paste.svg"
464- onTriggered: {
465- console.log("Pasting to current folder items of count " + pageModel.clipboardUrlsCounter)
466- PopupUtils.open(Qt.resolvedUrl("FileOperationProgressDialog.qml"),
467- root,
468- {
469- title: i18n.tr("Paste files"),
470- folderListModel: pageModel
471- }
472- )
473-
474-
475- pageModel.paste()
476- }
477- visible: pageModel.clipboardUrlsCounter > 0
478- }
479-
480- // IMPROVE: would rather have this as more hidden, in a separate menu that has
481- // file manipulation operations
482- ToolbarButton {
483- text: i18n.tr("Create folder")
484- // TODO: temporary
485- iconSource: "/usr/share/icons/ubuntu-mobile/actions/scalable/add.svg"
486- onTriggered: {
487- print(text)
488- PopupUtils.open(createFolderDialog, root)
489- }
490- }
491-
492- ToolbarButton {
493- text: i18n.tr("Home")
494- // TODO: temporary
495- iconSource: "/usr/share/icons/ubuntu-mobile/actions/scalable/go-to.svg"
496- onTriggered: {
497- goHome()
498-
499- //pageModel.path = pageModel.homePath()
500- console.log("Home triggered")
501+ text: i18n.tr("Actions")
502+ iconSource: "icons/edit.png"
503+
504+ onTriggered: {
505+ print(text)
506+ folderActionsPopover.caller = caller
507+ folderActionsPopover.show();
508+ }
509+ }
510+
511+ ToolbarButton {
512+ text: i18n.tr("Settings")
513+ iconSource: "icons/settings.png"
514+
515+ onTriggered: {
516+ print(text)
517+
518+ PopupUtils.open(Qt.resolvedUrl("SettingsPopover.qml"), caller)
519+ }
520+ }
521+
522+ ToolbarButton {
523+ text: i18n.tr("Places")
524+ iconSource: "icons/location.png"
525+ onTriggered: {
526+ print(text)
527+
528+ PopupUtils.open(Qt.resolvedUrl("PlacesPopover.qml"), caller)
529 }
530 }
531 }
532
533 Column {
534- anchors.centerIn: root
535+ anchors.centerIn: parent
536 Label {
537 text: i18n.tr("No files")
538 fontSize: "large"
539
540=== modified file 'FolderListView.qml'
541--- FolderListView.qml 2013-06-27 14:21:42 +0000
542+++ FolderListView.qml 2013-07-03 15:05:30 +0000
543@@ -28,10 +28,11 @@
544 property string folderPath: folderListModel.path
545 model: folderListModel
546
547- header: Caption {
548+ header: Header {
549 objectName: "directoryHeader"
550- text: (root.count == 1 ? i18n.tr("%1 (%2 file)").arg(root.folderPath).arg(root.count) :
551- i18n.tr("%1 (%2 files)").arg(root.folderPath).arg(root.count))
552+ text: (root.count == 1
553+ ? i18n.tr("%1 (1 file)").arg(root.folderPath)
554+ : i18n.tr("%1 (%2 files)").arg(root.folderPath).arg(root.count))
555 }
556
557 Component {
558@@ -71,7 +72,7 @@
559 // the filesystem, but may be a problem in the future.
560 property int modelRow
561
562- title: i18n.tr("Rename?")
563+ title: i18n.tr("Rename")
564 text: i18n.tr("Enter a new name")
565
566 onAccepted: {
567@@ -100,16 +101,16 @@
568 property var model
569 actions: ActionList {
570 Action {
571- text: i18n.tr("Show details")
572+ text: i18n.tr("Cut")
573+ // TODO: temporary
574+ iconSource: "/usr/share/icons/Humanity/actions/48/edit-cut.svg"
575 onTriggered: {
576- print(text)
577- PopupUtils.open(Qt.resolvedUrl("FileDetailsPopover.qml"),
578- actionSelectionPopover.caller,
579- { "model": actionSelectionPopover.model
580- }
581- )
582+ console.log("Cut on row called for", actionSelectionPopover.model.fileName, actionSelectionPopover.model.index)
583+ model.cutIndex(actionSelectionPopover.model.index)
584+ console.log("CliboardUrlsCounter after copy", folderListModel.clipboardUrlsCounter)
585 }
586 }
587+
588 Action {
589 text: i18n.tr("Copy")
590 // TODO: temporary.
591@@ -121,16 +122,7 @@
592 console.log("CliboardUrlsCounter after copy", folderListModel.clipboardUrlsCounter)
593 }
594 }
595- Action {
596- text: i18n.tr("Cut")
597- // TODO: temporary
598- iconSource: "/usr/share/icons/Humanity/actions/48/edit-cut.svg"
599- onTriggered: {
600- console.log("Cut on row called for", actionSelectionPopover.model.fileName, actionSelectionPopover.model.index)
601- model.cutIndex(actionSelectionPopover.model.index)
602- console.log("CliboardUrlsCounter after copy", folderListModel.clipboardUrlsCounter)
603- }
604- }
605+
606 Action {
607 text: i18n.tr("Delete")
608 // TODO: temporary
609@@ -142,7 +134,8 @@
610 "fileName" : actionSelectionPopover.model.fileName }
611 )
612 }
613- }
614+ }
615+
616 Action {
617 text: i18n.tr("Rename")
618 // TODO: temporary
619@@ -156,6 +149,17 @@
620 }
621 }
622
623+ Action {
624+ text: i18n.tr("Properties")
625+ onTriggered: {
626+ print(text)
627+ PopupUtils.open(Qt.resolvedUrl("FileDetailsPopover.qml"),
628+ actionSelectionPopover.caller,
629+ { "model": actionSelectionPopover.model
630+ }
631+ )
632+ }
633+ }
634 }
635 // TODO: problem: clicking outside popup makes the click go through to the
636 // folder listview, so for example you'd change directory while only trying
637
638=== added file 'PlacesPopover.qml'
639--- PlacesPopover.qml 1970-01-01 00:00:00 +0000
640+++ PlacesPopover.qml 2013-07-03 15:05:30 +0000
641@@ -0,0 +1,137 @@
642+/*
643+ * Copyright (C) 2013 Canonical Ltd
644+ *
645+ * This program is free software: you can redistribute it and/or modify
646+ * it under the terms of the GNU General Public License version 3 as
647+ * published by the Free Software Foundation.
648+ *
649+ * This program is distributed in the hope that it will be useful,
650+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
651+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
652+ * GNU General Public License for more details.
653+ *
654+ * You should have received a copy of the GNU General Public License
655+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
656+ *
657+ * Authored by: Michael Spencer <spencers1993@gmail.com>
658+ */
659+import QtQuick 2.0
660+import Ubuntu.Components 0.1
661+import Ubuntu.Components.Popups 0.1
662+import Ubuntu.Components.ListItems 0.1
663+
664+Popover {
665+ id: root
666+ objectName: "placesPopover"
667+
668+ ListModel {
669+ id: places
670+
671+ ListElement {
672+ path: "~"
673+ }
674+
675+ ListElement {
676+ path: "~/Documents"
677+ }
678+
679+ ListElement {
680+ path: "~/Downloads"
681+ }
682+
683+ ListElement {
684+ path: "~/Music"
685+ }
686+
687+ ListElement {
688+ path: "~/Pictures"
689+ }
690+
691+ ListElement {
692+ path: "~/Videos"
693+ }
694+
695+ ListElement {
696+ path: "/"
697+ }
698+ }
699+
700+ Column {
701+ anchors {
702+ left: parent.left
703+ right: parent.right
704+ top: parent.top
705+ }
706+
707+ Repeater {
708+ id: placesList
709+ objectName: "placesList"
710+
711+ model: places
712+
713+ delegate: Standard {
714+ text: folderName(path)
715+ icon: model.icon || fileIcon(model.path, true)
716+
717+ onClicked: {
718+ PopupUtils.close(root)
719+ goTo(model.path)
720+ }
721+ }
722+ }
723+
724+ Empty {
725+
726+ TextField {
727+ id: locationField
728+ anchors {
729+ verticalCenter: parent.verticalCenter
730+ left: parent.left
731+ right: goButton.left
732+ margins: units.gu(1)
733+ }
734+
735+ inputMethodHints: Qt.ImhNoAutoUppercase
736+
737+ property bool valid: pathExists(text)
738+
739+ text: fileView.path
740+
741+ placeholderText: i18n.tr("Location...")
742+
743+ onAccepted: goButton.clicked()
744+ }
745+
746+ Button {
747+ id: goButton
748+ anchors {
749+ top: locationField.top
750+ bottom: locationField.bottom
751+ right: parent.right
752+ rightMargin: units.gu(1)
753+ }
754+
755+ gradient: Gradient {
756+ GradientStop {
757+ position: 0
758+ color: "green"//Qt.rgba(0,0.7,0,1)
759+ }
760+
761+ GradientStop {
762+ position: 1
763+ color: Qt.rgba(0.3,0.7,0.3,1)
764+ }
765+ }
766+
767+ text: i18n.tr("Go")
768+ enabled: locationField.acceptableInput && locationField.valid
769+
770+ onClicked: {
771+ print("User switched to:", locationField.text)
772+ goTo(locationField.text)
773+ PopupUtils.close(root)
774+ }
775+ }
776+ }
777+ }
778+}
779
780=== added file 'SettingsPopover.qml'
781--- SettingsPopover.qml 1970-01-01 00:00:00 +0000
782+++ SettingsPopover.qml 2013-07-03 15:05:30 +0000
783@@ -0,0 +1,75 @@
784+/*
785+ * Copyright (C) 2013 Canonical Ltd
786+ *
787+ * This program is free software: you can redistribute it and/or modify
788+ * it under the terms of the GNU General Public License version 3 as
789+ * published by the Free Software Foundation.
790+ *
791+ * This program is distributed in the hope that it will be useful,
792+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
793+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
794+ * GNU General Public License for more details.
795+ *
796+ * You should have received a copy of the GNU General Public License
797+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
798+ *
799+ * Authored by: Michael Spencer <spencers1993@gmail.com>
800+ */
801+import QtQuick 2.0
802+import Ubuntu.Components 0.1
803+import Ubuntu.Components.Popups 0.1
804+import Ubuntu.Components.ListItems 0.1
805+
806+Popover {
807+ id: root
808+ objectName: "settingsPopover"
809+
810+ Column {
811+ anchors {
812+ left: parent.left
813+ right: parent.right
814+ top: parent.top
815+ }
816+
817+ Standard {
818+ id: showHiddenFileCheckBox
819+ objectName: "showHiddenFileCheckBox"
820+
821+ text: i18n.tr("Show Hidden Files")
822+ control: CheckBox {
823+ anchors.verticalCenter: parent.verticalCenter
824+
825+ checked: fileView.showHiddenFiles
826+ onCheckedChanged: {
827+ fileView.showHiddenFiles = checked
828+ }
829+ }
830+ }
831+
832+ ValueSelector {
833+ text: "Sort By"
834+ selectedIndex: values.indexOf(fileView.sortingMethod)
835+ values: [
836+ "Name",
837+ "Date"
838+ ]
839+
840+ onSelectedIndexChanged: {
841+ fileView.sortingMethod = values[selectedIndex]
842+ }
843+ }
844+
845+ ValueSelector {
846+ text: "Sort Order"
847+ selectedIndex: sortAccending ? 0 : 1
848+ values: [
849+ "Ascending",
850+ "Descending"
851+ ]
852+
853+ onSelectedIndexChanged: {
854+ fileView.sortAccending = (values[selectedIndex] === "Ascending")
855+ }
856+ }
857+ }
858+}
859
860=== added directory 'icons'
861=== added file 'icons/edit.png'
862Binary files icons/edit.png 1970-01-01 00:00:00 +0000 and icons/edit.png 2013-07-03 15:05:30 +0000 differ
863=== added file 'icons/location.png'
864Binary files icons/location.png 1970-01-01 00:00:00 +0000 and icons/location.png 2013-07-03 15:05:30 +0000 differ
865=== added file 'icons/settings.png'
866Binary files icons/settings.png 1970-01-01 00:00:00 +0000 and icons/settings.png 2013-07-03 15:05:30 +0000 differ
867=== added file 'icons/up.png'
868Binary files icons/up.png 1970-01-01 00:00:00 +0000 and icons/up.png 2013-07-03 15:05:30 +0000 differ
869=== modified file 'tests/autopilot/ubuntu_filemanager_app/emulators/main_window.py'
870--- tests/autopilot/ubuntu_filemanager_app/emulators/main_window.py 2013-06-27 14:18:10 +0000
871+++ tests/autopilot/ubuntu_filemanager_app/emulators/main_window.py 2013-07-03 15:05:30 +0000
872@@ -18,7 +18,10 @@
873
874 def get_folder(self, index):
875 """Returns the list view folder with index number."""
876- return self.app.select_many("Subtitled")[index]
877+ return self.app.select_single('FolderListPage').select_many("Subtitled")[index]
878+
879+ def get_folder_count(self):
880+ return len(self.app.select_single('FolderListPage').select_many("Subtitled"))
881
882 def get_action_popover(self):
883 # Returns all instances, but with current one as first index
884@@ -27,3 +30,5 @@
885 def get_current_folder_name(self):
886 return self.app.select_single('FolderListView').folderPath
887
888+ def get_page_title(self):
889+ return self.app.select_single('FolderListPage').title
890
891=== modified file 'tests/autopilot/ubuntu_filemanager_app/tests/test_filemanager.py'
892--- tests/autopilot/ubuntu_filemanager_app/tests/test_filemanager.py 2013-06-27 14:18:10 +0000
893+++ tests/autopilot/ubuntu_filemanager_app/tests/test_filemanager.py 2013-07-03 15:05:30 +0000
894@@ -36,8 +36,17 @@
895 patcher.start()
896 self.addCleanup(patcher.stop)
897
898- def test_toolbar_shows(self):
899- """Dragging from the bottom reveals the hidden toolbar."""
900+ def _get_place(self, name):
901+ """Returns the place/bookmark with index number."""
902+ self.ubuntusdk.click_toolbar_button('Places')
903+ places_popover = self.app.select_single('Popover', objectName='placesPopover')
904+ places = places_popover.select_many('Standard')
905+ for place in places:
906+ if place.text == name:
907+ return place
908+
909+ def test_file_actions_shows(self):
910+ """Checks to make sure that the file actions popover is shown."""
911 self._make_directory_in_home()
912
913 first_folder = self.main_window.get_folder(0)
914@@ -50,10 +59,12 @@
915 path = tempfile.mkdtemp(dir=os.environ['HOME'])
916 # Currently, we need to open again the home folder to show the newly
917 # created one. See bug #1190676.
918- # TODO when the bug is fixed, remove the next line.
919- self.ubuntusdk.click_toolbar_button('Home')
920- while self.app.select_single('FolderListPage').loading:
921- pass
922+ # TODO when the bug is fixed, remove the following lines up to the assert line
923+ home_place = self._get_place("Home")
924+ self.pointing_device.click_object(home_place)
925+
926+ self.assertThat(self.main_window.get_folder_count, Eventually(Equals(1)))
927+
928 return path
929
930 def test_open_directory(self):
931@@ -64,3 +75,21 @@
932 self.assertThat(
933 self.main_window.get_current_folder_name,
934 Eventually(Equals(sub_dir)))
935+
936+ def test_going_home(self):
937+ home_place = self._get_place("Home")
938+ self.pointing_device.click_object(home_place)
939+
940+ self._check_location("Home", os.environ['HOME'])
941+
942+ def test_going_to_root(self):
943+ root_place = self._get_place("File System")
944+ self.pointing_device.click_object(root_place)
945+
946+ self._check_location("File System", "/")
947+
948+ def _check_location(self,title,location):
949+ self.assertThat(self.main_window.get_page_title, Eventually(Equals(title)))
950+
951+ self.assertThat(self.main_window.get_current_folder_name,
952+ Eventually(Equals(location)))
953
954=== modified file 'ubuntu-filemanager-app.qml'
955--- ubuntu-filemanager-app.qml 2013-06-27 14:18:10 +0000
956+++ ubuntu-filemanager-app.qml 2013-07-03 15:05:30 +0000
957@@ -26,29 +26,22 @@
958 */
959
960 MainView {
961+ id: root
962 // objectName for functional testing purposes (autopilot-qt5)
963 objectName: "filemanager"
964 applicationName: "ubuntu-filemanager-app"
965
966 width: units.gu(50)
967 height: units.gu(75)
968-
969+
970+ property alias filemanager: root
971+
972+ property bool wideAspect: width >= units.gu(80)
973+
974 FolderListPage {
975+ id: folderPage
976 objectName: "folderPage"
977- id: folderPage
978
979 folder: homeFolder
980-
981- function goHome() {
982- // FIXME: Get the user's home folder without requiring an instance
983- // of a FolderListModel
984- goTo(homeFolder)
985- }
986-
987- function goTo(location) {
988- // FIXME: Why is this needed? Folder doesn't seem to refresh without it
989- folder = ""
990- folder = location
991- }
992 }
993 }

Subscribers

People subscribed via source and target branches