Merge lp:~ibelieve/ubuntu-filemanager-app/improved-toolbar into lp:ubuntu-filemanager-app
- improved-toolbar
- Merge into trunk
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 | ||||
Related bugs: |
|
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/
In addition, this adds a Properties popover for the current folder.
- 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
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
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
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) : | # |
Preview Diff
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' |
862 | Binary 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' |
864 | Binary 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' |
866 | Binary 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' |
868 | Binary 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 | } |
Great changes, thank you!