Merge lp:~ibelieve/ubuntu-filemanager-app/code-refactoring into lp:ubuntu-filemanager-app
- code-refactoring
- Merge into trunk
Status: | Work in progress | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Proposed branch: | lp:~ibelieve/ubuntu-filemanager-app/code-refactoring | ||||||||||||||||
Merge into: | lp:ubuntu-filemanager-app | ||||||||||||||||
Diff against target: |
1747 lines (+777/-627) 14 files modified
src/app/qml/backend/FolderModel.qml (+303/-0) src/app/qml/components/FolderIconDelegate.qml (+1/-1) src/app/qml/components/FolderListDelegate.qml (+1/-1) src/app/qml/components/OverlayStandard.qml (+55/-0) src/app/qml/components/PathBar.qml (+1/-1) src/app/qml/components/PlacesSidebar.qml (+6/-40) src/app/qml/filemanager.qml (+9/-24) src/app/qml/ui/FileActionsPopover.qml (+114/-0) src/app/qml/ui/FileDetailsPopover.qml (+2/-2) src/app/qml/ui/FileOperationProgressDialog.qml (+1/-1) src/app/qml/ui/FolderActionsPopover.qml (+116/-0) src/app/qml/ui/FolderListPage.qml (+160/-515) src/app/qml/ui/GoToDialog.qml (+2/-2) src/app/qml/ui/PlacesPopover.qml (+6/-40) |
||||||||||||||||
To merge this branch: | bzr merge lp:~ibelieve/ubuntu-filemanager-app/code-refactoring | ||||||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu File Manager Developers | Pending | ||
Review via email: mp+223305@code.launchpad.net |
Commit message
Cleaned up the code, reenabled multi-tab support, and fixed a bug
Description of the change
Lots of work on refactoring code, including:
* Moved all of the model code from FolderListPage into a separate FolderModel class
* Moved some of the popovers from FOlderListPage into separate classes
* Moved the places model from PlacesSidbar and PlacesPopover into FolderModel, removing the extra duplicate
Also, fixed some other bugs:
* Renabled multi-tab support, as this was fixed in the SDK
* Expanding the app's window automatically expands the sidebar if it was previously expanded
Unmerged revisions
- 207. By Michael Spencer
-
Sidebar expands automatically when changing the size of the app on the desktop
- 206. By Michael Spencer
-
Re-enabled multi-tab support
- 205. By Michael Spencer
-
More code refactoring
* split some popovers into separate classes
* Use local icons from the Suru theme
* Moved the places list into one location in the FolderModel - 204. By Michael Spencer
-
Initial refactoring of the model code into a separate backend class
Preview Diff
1 | === added directory 'src/app/qml/backend' |
2 | === added file 'src/app/qml/backend/FolderModel.qml' |
3 | --- src/app/qml/backend/FolderModel.qml 1970-01-01 00:00:00 +0000 |
4 | +++ src/app/qml/backend/FolderModel.qml 2014-06-16 21:32:33 +0000 |
5 | @@ -0,0 +1,303 @@ |
6 | +/* |
7 | + * Copyright (C) 2014 Michael Spencer <sonrisesoftware@gmail.com> |
8 | + * |
9 | + * This program is free software: you can redistribute it and/or modify |
10 | + * it under the terms of the GNU General Public License version 3 as |
11 | + * published by the Free Software Foundation. |
12 | + * |
13 | + * This program is distributed in the hope that it will be useful, |
14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | + * GNU General Public License for more details. |
17 | + * |
18 | + * You should have received a copy of the GNU General Public License |
19 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
20 | + */ |
21 | +import QtQuick 2.0 |
22 | +import Ubuntu.Components 0.1 |
23 | +import org.nemomobile.folderlistmodel 1.0 |
24 | + |
25 | +Object { |
26 | + id: model |
27 | + |
28 | + property bool loading: folderModel.awaitingResults |
29 | + |
30 | + property alias folderModel: folderModel |
31 | + |
32 | + /*! |
33 | + * The user-friendly title for the current directory |
34 | + */ |
35 | + property string title: folderName(folder) |
36 | + |
37 | + /*! |
38 | + * Set to <code>true</code> true to show hidden files begining with a . |
39 | + * in the current directory |
40 | + */ |
41 | + property bool showHiddenFiles: false |
42 | + |
43 | + // TODO: Can this be replaced by a property binding? |
44 | + onShowHiddenFilesChanged: { |
45 | + folderModel.showHiddenFiles = folderListPage.showHiddenFiles |
46 | + } |
47 | + |
48 | + /*! |
49 | + * The sorting mode for the current directory. |
50 | + * |
51 | + * Can be one of: Name or Date |
52 | + */ |
53 | + property string sortingMethod: "Name" |
54 | + |
55 | + // TODO: Can this be replaced by a property binding? |
56 | + onSortingMethodChanged: { |
57 | + console.log("Sorting by: " + sortingMethod) |
58 | + if (sortingMethod === "Name") { |
59 | + folderModel.sortBy = FolderListModel.SortByName |
60 | + } else if (sortingMethod === "Date") { |
61 | + folderModel.sortBy = FolderListModel.SortByDate |
62 | + } else { |
63 | + // Something fatal happened! |
64 | + console.log("ERROR: Invalid sort type:", sortingMethod) |
65 | + } |
66 | + } |
67 | + /*! |
68 | + * Set to <code>true</code> true to sort A-Z, or <code>false</code> |
69 | + * to sort in reverse, from Z to A. |
70 | + */ |
71 | + property bool sortAccending: true |
72 | + |
73 | + // TODO: Can this be replaced by a property binding? |
74 | + onSortAccendingChanged: { |
75 | + console.log("Sorting accending: " + sortAccending) |
76 | + |
77 | + if (sortAccending) { |
78 | + folderModel.sortOrder = FolderListModel.SortAscending |
79 | + } else { |
80 | + folderModel.sortOrder = FolderListModel.SortDescending |
81 | + } |
82 | + } |
83 | + |
84 | + // This stores the location using ~ to represent home |
85 | + property string folder: homeFolder |
86 | + property string homeFolder: "~" |
87 | + |
88 | + // This replaces ~ with the actual home folder, since the |
89 | + // plugin doesn't recognize the ~ |
90 | + property string path: folder.replace("~", folderModel.homePath()) |
91 | + property string homePath: folderModel.homePath() |
92 | + |
93 | + |
94 | + /*! |
95 | + * Switches directories to the user's home directory |
96 | + */ |
97 | + function goHome() { |
98 | + goTo(model.homeFolder) |
99 | + } |
100 | + |
101 | + /*! |
102 | + * Switches directories to the specified path. Can use either /home/<user> or ~ |
103 | + * to represent the user's home folder |
104 | + */ |
105 | + function goTo(location) { |
106 | + // Since the FolderListModel returns paths using the actual |
107 | + // home folder, this replaces with ~ before actually going |
108 | + // to the specified folder |
109 | + while (location !== '/' && location.substring(location.lastIndexOf('/')+1) === "") { |
110 | + location = location.substring(0, location.length - 1) |
111 | + } |
112 | + |
113 | + model.folder = location.replace(homePath, "~") |
114 | + refresh() |
115 | + } |
116 | + |
117 | + /*! |
118 | + * Opens the specified file in the default app for the file's type |
119 | + */ |
120 | + function openFile(filePath) { |
121 | + if (!folderModel.openPath(filePath)) { |
122 | + error(i18n.tr("File operation error"), i18n.tr("Unable to open '%11").arg(filePath)) |
123 | + } |
124 | + } |
125 | + |
126 | + /*! |
127 | + * Refreshes the folder model |
128 | + */ |
129 | + // TODO: Is this needed? |
130 | + function refresh() { |
131 | + folderModel.refresh() |
132 | + } |
133 | + |
134 | + /*! |
135 | + * Returns the user-friendly name for the specified path. Can use either |
136 | + * /home/<user> or ~ to represent the user's home folder |
137 | + */ |
138 | + function folderName(folder) { |
139 | + folder = folder.replace(homePath, "~") |
140 | + |
141 | + if (folder === homeFolder) { |
142 | + return i18n.tr("Home") |
143 | + } else if (folder === "/") { |
144 | + return i18n.tr("File System") |
145 | + } else { |
146 | + return pathName(folder) |
147 | + } |
148 | + } |
149 | + |
150 | + /*! |
151 | + * Returns the last element of the specified path, or / for the |
152 | + * root folder. |
153 | + */ |
154 | + function pathName(folder) { |
155 | + if (folder === "/") { |
156 | + return "/" |
157 | + } else { |
158 | + return folder.substr(folder.lastIndexOf('/') + 1) |
159 | + } |
160 | + } |
161 | + |
162 | + function pathAccessedDate() { |
163 | + console.log("calling method folderModel.curPathAccessedDate()") |
164 | + return folderModel.curPathAccessedDate() |
165 | + } |
166 | + |
167 | + function pathModifiedDate() { |
168 | + console.log("calling method folderModel.curPathModifiedDate()") |
169 | + return folderModel.curPathModifiedDate() |
170 | + } |
171 | + |
172 | + function pathIsWritable() { |
173 | + console.log("calling method folderModel.curPathIsWritable()") |
174 | + return folderModel.curPathIsWritable() |
175 | + } |
176 | + |
177 | + /*! |
178 | + * Returns true if the specified path exists in the file system. |
179 | + */ |
180 | + function pathExists(path) { |
181 | + path = path.replace("~", folderModel.homePath()) |
182 | + |
183 | + if (path === '/') |
184 | + return true |
185 | + |
186 | + if(path.charAt(0) === '/') { |
187 | + console.log("Directory: " + path.substring(0, path.lastIndexOf('/')+1)) |
188 | + repeaterModel.path = path.substring(0, path.lastIndexOf('/')+1) |
189 | + console.log("Sub dir: " + path.substring(path.lastIndexOf('/')+1)) |
190 | + if (path.substring(path.lastIndexOf('/')+1) !== "" && !repeaterModel.cdIntoPath(path.substring(path.lastIndexOf('/')+1))) { |
191 | + return false |
192 | + } else { |
193 | + return true |
194 | + } |
195 | + } else { |
196 | + return false |
197 | + } |
198 | + } |
199 | + |
200 | + |
201 | + /*! |
202 | + * Returns the icon for the specified file or folder. |
203 | + */ |
204 | + // FIXME: hard coded path for icon, assumes Ubuntu desktop icon available. |
205 | + // Nemo mobile has icon provider. Have to figure out what's the proper way |
206 | + // to get "system wide" icons in Ubuntu Touch, or if we have to use |
207 | + // icons packaged into the application. Both folder and individual |
208 | + // files will need an icon. |
209 | + // TODO: Remove isDir parameter and use new model functions |
210 | + function fileIcon(file, isDir) { |
211 | + file = file.replace(folderModel.homePath(), "~") |
212 | + var iconPath = isDir ? "/usr/share/icons/Humanity/places/48/folder.svg" |
213 | + : "/usr/share/icons/Humanity/mimes/48/empty.svg" |
214 | + |
215 | + if (file === "~") { |
216 | + iconPath = "../icons/folder-home.svg" |
217 | + } else if (file === i18n.tr("~/Desktop")) { |
218 | + iconPath = "/usr/share/icons/Humanity/places/48/user-desktop.svg" |
219 | + } else if (file === i18n.tr("~/Documents")) { |
220 | + iconPath = "/usr/share/icons/Humanity/places/48/folder-documents.svg" |
221 | + } else if (file === i18n.tr("~/Downloads")) { |
222 | + iconPath = "/usr/share/icons/Humanity/places/48/folder-downloads.svg" |
223 | + } else if (file === i18n.tr("~/Music")) { |
224 | + iconPath = "/usr/share/icons/Humanity/places/48/folder-music.svg" |
225 | + } else if (file === i18n.tr("~/Pictures")) { |
226 | + iconPath = "/usr/share/icons/Humanity/places/48/folder-pictures.svg" |
227 | + } else if (file === i18n.tr("~/Public")) { |
228 | + iconPath = "/usr/share/icons/Humanity/places/48/folder-publicshare.svg" |
229 | + } else if (file === i18n.tr("~/Programs")) { |
230 | + iconPath = "/usr/share/icons/Humanity/places/48/folder-system.svg" |
231 | + } else if (file === i18n.tr("~/Templates")) { |
232 | + iconPath = "/usr/share/icons/Humanity/places/48/folder-templates.svg" |
233 | + } else if (file === i18n.tr("~/Videos")) { |
234 | + iconPath = "/usr/share/icons/Humanity/places/48/folder-videos.svg" |
235 | + } else if (file === "/") { |
236 | + iconPath = "/usr/share/icons/Humanity/devices/48/drive-harddisk.svg" |
237 | + } |
238 | + |
239 | + return Qt.resolvedUrl(iconPath) |
240 | + } |
241 | + |
242 | + /*! |
243 | + * The places list for the sidebar |
244 | + */ |
245 | + property ListModel places: ListModel { |
246 | + ListElement { |
247 | + objectName: "placeHome" |
248 | + path: "~" |
249 | + } |
250 | + |
251 | + ListElement { |
252 | + path: "~/Documents" |
253 | + } |
254 | + |
255 | + ListElement { |
256 | + path: "~/Downloads" |
257 | + } |
258 | + |
259 | + ListElement { |
260 | + path: "~/Music" |
261 | + } |
262 | + |
263 | + ListElement { |
264 | + path: "~/Pictures" |
265 | + } |
266 | + |
267 | + ListElement { |
268 | + path: "~/Videos" |
269 | + } |
270 | + |
271 | + ListElement { |
272 | + objectName: "placeRoot" |
273 | + path: "/" |
274 | + } |
275 | + } |
276 | + |
277 | + /*! |
278 | + * The folder model used to represent the currently selected folder |
279 | + */ |
280 | + FolderListModel { |
281 | + id: folderModel |
282 | + |
283 | + path: model.path |
284 | + |
285 | + enableExternalFSWatcher: true |
286 | + |
287 | + // Properties to emulate a model entry for use by FileDetailsPopover |
288 | + property bool isDir: true |
289 | + property string fileName: pathName(folderModel.path) |
290 | + property string fileSize: (folderListView.count === 1 |
291 | + ? i18n.tr("1 file") |
292 | + : i18n.tr("%1 files").arg(folderListView.count)) |
293 | + property bool isReadable: true |
294 | + property bool isExecutable: true |
295 | + } |
296 | + |
297 | + /*! |
298 | + * The folder model used for checking to see if a specified path exists |
299 | + */ |
300 | + FolderListModel { |
301 | + id: repeaterModel |
302 | + path: model.folder |
303 | + |
304 | + onPathChanged: { |
305 | + console.log("Path: " + repeaterModel.path) |
306 | + } |
307 | + } |
308 | +} |
309 | |
310 | === modified file 'src/app/qml/components/FolderIconDelegate.qml' |
311 | --- src/app/qml/components/FolderIconDelegate.qml 2014-03-29 09:20:11 +0000 |
312 | +++ src/app/qml/components/FolderIconDelegate.qml 2014-06-16 21:32:33 +0000 |
313 | @@ -52,7 +52,7 @@ |
314 | property string text: fileName |
315 | property string subText: Qt.formatDateTime(model.modifiedDate, Qt.DefaultLocaleShortDate) + (!model.isDir ? ", " + fileSize : "") |
316 | |
317 | - property var icon: fileIcon(filePath, model.isDir) |
318 | + property var icon: folderModel.fileIcon(filePath, model.isDir) |
319 | |
320 | Item { |
321 | anchors { |
322 | |
323 | === modified file 'src/app/qml/components/FolderListDelegate.qml' |
324 | --- src/app/qml/components/FolderListDelegate.qml 2014-03-29 09:20:11 +0000 |
325 | +++ src/app/qml/components/FolderListDelegate.qml 2014-06-16 21:32:33 +0000 |
326 | @@ -30,7 +30,7 @@ |
327 | subText: Qt.formatDateTime(model.modifiedDate, Qt.DefaultLocaleShortDate) + (!model.isDir ? ", " + fileSize : "") |
328 | |
329 | property string path: fileView.path + '/' + model.fileName |
330 | - iconSource: fileIcon(path, model.isDir) |
331 | + iconSource: folderModel.fileIcon(path, model.isDir) |
332 | |
333 | progression: model.isDir |
334 | iconFrame: false |
335 | |
336 | === added file 'src/app/qml/components/OverlayStandard.qml' |
337 | --- src/app/qml/components/OverlayStandard.qml 1970-01-01 00:00:00 +0000 |
338 | +++ src/app/qml/components/OverlayStandard.qml 2014-06-16 21:32:33 +0000 |
339 | @@ -0,0 +1,55 @@ |
340 | +/*************************************************************************** |
341 | + * Ubuntu UI Extras - A collection of QML widgets not available * |
342 | + * in the default Ubuntu UI Toolkit * |
343 | + * Copyright (C) 2013 Michael Spencer <sonrisesoftware@gmail.com> * |
344 | + * * |
345 | + * This program is free software: you can redistribute it and/or modify * |
346 | + * it under the terms of the GNU General Public License as published by * |
347 | + * the Free Software Foundation, either version 2 of the License, or * |
348 | + * (at your option) any later version. * |
349 | + * * |
350 | + * This program is distributed in the hope that it will be useful, * |
351 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
352 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
353 | + * GNU General Public License for more details. * |
354 | + * * |
355 | + * You should have received a copy of the GNU General Public License * |
356 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. * |
357 | + ***************************************************************************/ |
358 | +import QtQuick 2.0 |
359 | +import Ubuntu.Components 1.1 |
360 | +import Ubuntu.Components.ListItems 1.0 |
361 | + |
362 | +Standard { |
363 | + id: standard |
364 | + |
365 | + property alias text: label.text |
366 | + property alias iconSource: image.source |
367 | + |
368 | + Image { |
369 | + id: image |
370 | + width: units.gu(3.5) |
371 | + height: width |
372 | + |
373 | + anchors { |
374 | + verticalCenter: parent.verticalCenter |
375 | + left: parent.left |
376 | + leftMargin: units.gu(2) |
377 | + } |
378 | + opacity: standard.enabled ? 1 : 0.5 |
379 | + } |
380 | + |
381 | + //FIXME: Hack because of Suru theme! |
382 | + Label { |
383 | + id: label |
384 | + anchors { |
385 | + verticalCenter: parent.verticalCenter |
386 | + left: parent.left |
387 | + leftMargin: image.source === "" ? units.gu(2) : image.width + units.gu(4) |
388 | + } |
389 | + |
390 | + fontSize: "medium" |
391 | + color: standard.selected ? UbuntuColors.orange : "#666" |
392 | + opacity: standard.enabled ? 1 : 0.5 |
393 | + } |
394 | +} |
395 | |
396 | === modified file 'src/app/qml/components/PathBar.qml' |
397 | --- src/app/qml/components/PathBar.qml 2014-06-03 23:27:22 +0000 |
398 | +++ src/app/qml/components/PathBar.qml 2014-06-16 21:32:33 +0000 |
399 | @@ -87,7 +87,7 @@ |
400 | |
401 | Repeater { |
402 | id: repeater |
403 | - model: folder === "/" ? [""] : folder.split("/") |
404 | + model: folderModel.folder === "/" ? [""] : folderModel.folder.split("/") |
405 | delegate: Rectangle { |
406 | MouseArea { |
407 | id: mouseArea |
408 | |
409 | === modified file 'src/app/qml/components/PlacesSidebar.qml' |
410 | --- src/app/qml/components/PlacesSidebar.qml 2014-06-10 02:34:07 +0000 |
411 | +++ src/app/qml/components/PlacesSidebar.qml 2014-06-16 21:32:33 +0000 |
412 | @@ -27,7 +27,7 @@ |
413 | //color: Qt.rgba(0.5,0.5,0.5,0.3) |
414 | width: collapsed ? units.gu(8) : units.gu(22) |
415 | |
416 | - property bool collapsed: collapsedSidebar |
417 | + property bool collapsed: collapsedSidebar || !allowSidebarExpanded |
418 | |
419 | MouseArea { |
420 | anchors.fill: parent |
421 | @@ -42,40 +42,6 @@ |
422 | UbuntuNumberAnimation {} |
423 | } |
424 | |
425 | - ListModel { |
426 | - id: places |
427 | - |
428 | - ListElement { |
429 | - objectName: "placeHome" |
430 | - path: "~" |
431 | - } |
432 | - |
433 | - ListElement { |
434 | - path: "~/Documents" |
435 | - } |
436 | - |
437 | - ListElement { |
438 | - path: "~/Downloads" |
439 | - } |
440 | - |
441 | - ListElement { |
442 | - path: "~/Music" |
443 | - } |
444 | - |
445 | - ListElement { |
446 | - path: "~/Pictures" |
447 | - } |
448 | - |
449 | - ListElement { |
450 | - path: "~/Videos" |
451 | - } |
452 | - |
453 | - ListElement { |
454 | - objectName: "placeRoot" |
455 | - path: "/" |
456 | - } |
457 | - } |
458 | - |
459 | Column { |
460 | anchors { |
461 | left: parent.left |
462 | @@ -91,11 +57,11 @@ |
463 | id: placesList |
464 | objectName: "placesList" |
465 | |
466 | - model: places |
467 | + model: folderModel.places |
468 | |
469 | delegate: Standard { |
470 | objectName: model.objectName |
471 | - text: folderName(path) |
472 | + text: folderModel.folderName(path) |
473 | |
474 | Image { |
475 | anchors { |
476 | @@ -114,16 +80,16 @@ |
477 | } |
478 | } |
479 | |
480 | - iconSource: model.icon || fileIcon(model.path, true) |
481 | + iconSource: model.icon || folderModel.fileIcon(model.path, true) |
482 | |
483 | onClicked: { |
484 | - goTo(model.path) |
485 | + folderModel.goTo(model.path) |
486 | } |
487 | |
488 | height: units.gu(5) |
489 | showDivider: !collapsed |
490 | |
491 | - selected: folder === path |
492 | + selected: folderModel.folder === path |
493 | iconFrame: false |
494 | } |
495 | } |
496 | |
497 | === modified file 'src/app/qml/filemanager.qml' |
498 | --- src/app/qml/filemanager.qml 2014-04-29 18:05:45 +0000 |
499 | +++ src/app/qml/filemanager.qml 2014-06-16 21:32:33 +0000 |
500 | @@ -47,11 +47,6 @@ |
501 | |
502 | property bool allowSidebarExpanded: width >= units.gu(80) |
503 | |
504 | - onAllowSidebarExpandedChanged: { |
505 | - if (!allowSidebarExpanded) |
506 | - saveSetting("collapsedSidebar", true) |
507 | - } |
508 | - |
509 | property bool showSidebar: width >= units.gu(50) |
510 | |
511 | property bool showToolbar: width >= units.gu(80) |
512 | @@ -95,27 +90,17 @@ |
513 | Tabs { |
514 | id: tabs |
515 | |
516 | - Tab { |
517 | - title: page.title |
518 | - page: FolderListPage { |
519 | - objectName: "folderPage" |
520 | + Repeater { |
521 | + model: folderTabs |
522 | + delegate: Tab { |
523 | + title: page.title |
524 | + page: FolderListPage { |
525 | + objectName: "folderPage" |
526 | |
527 | - folder: "~"//modelData |
528 | + folder: modelData |
529 | + } |
530 | } |
531 | } |
532 | - |
533 | - // TODO: Temporarily disabled tabs support since this is broken in the SDK (lp:1295242) |
534 | -// Repeater { |
535 | -// model: folderTabs |
536 | -// delegate: Tab { |
537 | -// title: page.title |
538 | -// page: FolderListPage { |
539 | -// objectName: "folderPage" |
540 | - |
541 | -// folder: modelData |
542 | -// } |
543 | -// } |
544 | -// } |
545 | } |
546 | |
547 | Component.onCompleted: { |
548 | @@ -192,7 +177,7 @@ |
549 | } |
550 | |
551 | function getIcon(name) { |
552 | - return "/usr/share/icons/ubuntu-mobile/actions/scalable/" + name + ".svg" //Qt.resolvedUrl("icons/" + name + ".png") |
553 | + return Qt.resolvedUrl("icons/" + name + ".png") |
554 | } |
555 | |
556 | function error(title, message) { |
557 | |
558 | === added file 'src/app/qml/icons/add.png' |
559 | Binary files src/app/qml/icons/add.png 1970-01-01 00:00:00 +0000 and src/app/qml/icons/add.png 2014-06-16 21:32:33 +0000 differ |
560 | === added file 'src/app/qml/icons/delete.png' |
561 | Binary files src/app/qml/icons/delete.png 1970-01-01 00:00:00 +0000 and src/app/qml/icons/delete.png 2014-06-16 21:32:33 +0000 differ |
562 | === added file 'src/app/qml/icons/edit-copy.png' |
563 | Binary files src/app/qml/icons/edit-copy.png 1970-01-01 00:00:00 +0000 and src/app/qml/icons/edit-copy.png 2014-06-16 21:32:33 +0000 differ |
564 | === added file 'src/app/qml/icons/edit-cut.png' |
565 | Binary files src/app/qml/icons/edit-cut.png 1970-01-01 00:00:00 +0000 and src/app/qml/icons/edit-cut.png 2014-06-16 21:32:33 +0000 differ |
566 | === added file 'src/app/qml/icons/edit-paste.png' |
567 | Binary files src/app/qml/icons/edit-paste.png 1970-01-01 00:00:00 +0000 and src/app/qml/icons/edit-paste.png 2014-06-16 21:32:33 +0000 differ |
568 | === modified file 'src/app/qml/icons/edit.png' |
569 | Binary files src/app/qml/icons/edit.png 2013-09-17 16:47:57 +0000 and src/app/qml/icons/edit.png 2014-06-16 21:32:33 +0000 differ |
570 | === added file 'src/app/qml/icons/info.png' |
571 | Binary files src/app/qml/icons/info.png 1970-01-01 00:00:00 +0000 and src/app/qml/icons/info.png 2014-06-16 21:32:33 +0000 differ |
572 | === modified file 'src/app/qml/icons/location.png' |
573 | Binary files src/app/qml/icons/location.png 2013-09-17 16:47:57 +0000 and src/app/qml/icons/location.png 2014-06-16 21:32:33 +0000 differ |
574 | === modified file 'src/app/qml/icons/navigation-menu.png' |
575 | Binary files src/app/qml/icons/navigation-menu.png 2013-11-28 01:55:21 +0000 and src/app/qml/icons/navigation-menu.png 2014-06-16 21:32:33 +0000 differ |
576 | === modified file 'src/app/qml/icons/properties.png' |
577 | Binary files src/app/qml/icons/properties.png 2013-12-04 19:05:26 +0000 and src/app/qml/icons/properties.png 2014-06-16 21:32:33 +0000 differ |
578 | === added file 'src/app/qml/ui/FileActionsPopover.qml' |
579 | --- src/app/qml/ui/FileActionsPopover.qml 1970-01-01 00:00:00 +0000 |
580 | +++ src/app/qml/ui/FileActionsPopover.qml 2014-06-16 21:32:33 +0000 |
581 | @@ -0,0 +1,114 @@ |
582 | +/* |
583 | + * Copyright (C) 2014 Michael Spencer <sonrisesoftware@gmail.com> |
584 | + * |
585 | + * This program is free software: you can redistribute it and/or modify |
586 | + * it under the terms of the GNU General Public License version 3 as |
587 | + * published by the Free Software Foundation. |
588 | + * |
589 | + * This program is distributed in the hope that it will be useful, |
590 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
591 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
592 | + * GNU General Public License for more details. |
593 | + * |
594 | + * You should have received a copy of the GNU General Public License |
595 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
596 | + */ |
597 | +import QtQuick 2.0 |
598 | +import Ubuntu.Components 0.1 |
599 | +import Ubuntu.Components.Popups 0.1 |
600 | +import Ubuntu.Components.ListItems 0.1 as ListItem |
601 | +import "../components" |
602 | + |
603 | +Popover { |
604 | + id: root |
605 | + |
606 | + property var model |
607 | + |
608 | + property list<Action> actions: [ |
609 | + Action { |
610 | + text: i18n.tr("Cut") |
611 | + iconSource: getIcon("edit-cut") |
612 | + onTriggered: { |
613 | + console.log("Cut on row called for", root.model.fileName, root.model.index) |
614 | + folderModel.folderModel.cutIndex(root.model.index) |
615 | + console.log("CliboardUrlsCounter after copy", folderModel.folderModel.clipboardUrlsCounter) |
616 | + } |
617 | + }, |
618 | + |
619 | + Action { |
620 | + text: i18n.tr("Copy") |
621 | + iconSource: getIcon("edit-copy") |
622 | + |
623 | + onTriggered: { |
624 | + console.log("Copy on row called for", root.model.fileName, root.model.index) |
625 | + folderModel.folderModel.copyIndex(root.model.index) |
626 | + console.log("CliboardUrlsCounter after copy", folderModel.folderModel.clipboardUrlsCounter) |
627 | + } |
628 | + }, |
629 | + |
630 | + Action { |
631 | + text: i18n.tr("Delete") |
632 | + iconSource: getIcon("delete") |
633 | + onTriggered: { |
634 | + print(text) |
635 | + PopupUtils.open(confirmSingleDeleteDialog, root.caller, |
636 | + { "filePath" : root.model.filePath, |
637 | + "fileName" : root.model.fileName } |
638 | + ) |
639 | + } |
640 | + }, |
641 | + |
642 | + Action { |
643 | + text: i18n.tr("Rename") |
644 | + iconSource: getIcon("edit") |
645 | + onTriggered: { |
646 | + print(text) |
647 | + PopupUtils.open(confirmRenameDialog, root.caller, |
648 | + { "modelRow" : root.model.index, |
649 | + "inputText" : root.model.fileName |
650 | + }) |
651 | + } |
652 | + }, |
653 | + |
654 | + Action { |
655 | + text: i18n.tr("Properties") |
656 | + iconSource: getIcon("info") |
657 | + onTriggered: { |
658 | + print(text) |
659 | + PopupUtils.open(Qt.resolvedUrl("FileDetailsPopover.qml"), |
660 | + value, |
661 | + { "model": root.model |
662 | + } |
663 | + ) |
664 | + } |
665 | + } |
666 | + ] |
667 | + |
668 | + Column { |
669 | + anchors { |
670 | + left: parent.left |
671 | + right: parent.right |
672 | + } |
673 | + |
674 | + Repeater { |
675 | + id: repeater |
676 | + model: actions |
677 | + delegate: OverlayStandard { |
678 | + property Action action: modelData |
679 | + |
680 | + visible: action.visible |
681 | + enabled: action.enabled |
682 | + text: action.text |
683 | + iconSource: action.iconSource |
684 | + iconFrame: false |
685 | + |
686 | + onClicked: { |
687 | + action.triggered(root.caller) |
688 | + PopupUtils.close(root) |
689 | + } |
690 | + |
691 | + showDivider: index < repeater.count - 1 |
692 | + } |
693 | + } |
694 | + } |
695 | +} |
696 | |
697 | === modified file 'src/app/qml/ui/FileDetailsPopover.qml' |
698 | --- src/app/qml/ui/FileDetailsPopover.qml 2014-02-19 00:00:15 +0000 |
699 | +++ src/app/qml/ui/FileDetailsPopover.qml 2014-06-16 21:32:33 +0000 |
700 | @@ -71,13 +71,13 @@ |
701 | anchors.verticalCenter: parent.verticalCenter |
702 | |
703 | // TODO: how to get proper icon? |
704 | - source: fileIcon(root.path, model.isDir) |
705 | + source: folderModel.fileIcon(root.path, model.isDir) |
706 | } |
707 | |
708 | Label { |
709 | anchors.verticalCenter: parent.verticalCenter |
710 | |
711 | - text: folderName(root.path) |
712 | + text: folderModel.folderName(root.path) |
713 | color: Theme.palette.normal.overlayText |
714 | font.bold: true |
715 | } |
716 | |
717 | === modified file 'src/app/qml/ui/FileOperationProgressDialog.qml' |
718 | --- src/app/qml/ui/FileOperationProgressDialog.qml 2014-02-19 00:00:15 +0000 |
719 | +++ src/app/qml/ui/FileOperationProgressDialog.qml 2014-06-16 21:32:33 +0000 |
720 | @@ -78,7 +78,7 @@ |
721 | |
722 | // Errors from model |
723 | Connections { |
724 | - target: pageModel |
725 | + target: folderModel |
726 | onError: { |
727 | PopupUtils.close(root) |
728 | } |
729 | |
730 | === added file 'src/app/qml/ui/FolderActionsPopover.qml' |
731 | --- src/app/qml/ui/FolderActionsPopover.qml 1970-01-01 00:00:00 +0000 |
732 | +++ src/app/qml/ui/FolderActionsPopover.qml 2014-06-16 21:32:33 +0000 |
733 | @@ -0,0 +1,116 @@ |
734 | +/* |
735 | + * Copyright (C) 2014 Michael Spencer <sonrisesoftware@gmail.com> |
736 | + * |
737 | + * This program is free software: you can redistribute it and/or modify |
738 | + * it under the terms of the GNU General Public License version 3 as |
739 | + * published by the Free Software Foundation. |
740 | + * |
741 | + * This program is distributed in the hope that it will be useful, |
742 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
743 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
744 | + * GNU General Public License for more details. |
745 | + * |
746 | + * You should have received a copy of the GNU General Public License |
747 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
748 | + */ |
749 | +import QtQuick 2.0 |
750 | +import Ubuntu.Components 0.1 |
751 | +import Ubuntu.Components.Popups 0.1 |
752 | +import Ubuntu.Components.ListItems 0.1 as ListItem |
753 | +import "../components" |
754 | + |
755 | +Popover { |
756 | + id: root |
757 | + |
758 | + property list<Action> actions: [ |
759 | + Action { |
760 | + text: i18n.tr("Create New Folder") |
761 | + iconSource: getIcon("add") |
762 | + onTriggered: { |
763 | + print(text) |
764 | + |
765 | + PopupUtils.open(createFolderDialog, folderListPage) |
766 | + } |
767 | + }, |
768 | + |
769 | + // TODO: Disabled until backend supports creating files |
770 | +// Action { |
771 | +// text: i18n.tr("Create New File") |
772 | +// onTriggered: { |
773 | +// print(text) |
774 | + |
775 | +// PopupUtils.open(createFileDialog, root) |
776 | +// } |
777 | +// }, |
778 | + |
779 | + Action { |
780 | + text: folderModel.folderModel.clipboardUrlsCounter === 0 |
781 | + ? i18n.tr("Paste") |
782 | + : folderModel.folderModel.clipboardUrlsCounter === 1 |
783 | + ? i18n.tr("Paste %1 File").arg(folderModel.folderModel.clipboardUrlsCounter) |
784 | + : i18n.tr("Paste %1 Files").arg(folderModel.folderModel.clipboardUrlsCounter) |
785 | + onTriggered: { |
786 | + console.log("Pasting to current folder items of count " + folderModel.folderModel.clipboardUrlsCounter) |
787 | + fileOperationDialog.startOperation(i18n.tr("Paste files")) |
788 | + folderModel.folderModel.paste() |
789 | + } |
790 | + iconSource: getIcon("edit-paste") |
791 | + |
792 | + enabled: folderModel.folderModel.clipboardUrlsCounter > 0 |
793 | + }, |
794 | + |
795 | + // TODO: Disabled until support for opening apps is added |
796 | + Action { |
797 | + text: i18n.tr("Open in Terminal") |
798 | + onTriggered: { |
799 | + print(text) |
800 | + |
801 | + // Is this the way it will work?? |
802 | + Qt.openUrlExternally("app://terminal") |
803 | + } |
804 | + |
805 | + visible: showAdvancedFeatures && false |
806 | + }, |
807 | + |
808 | + Action { |
809 | + text: i18n.tr("Properties") |
810 | + iconSource: getIcon("info") |
811 | + onTriggered: { |
812 | + print(text) |
813 | + PopupUtils.open(Qt.resolvedUrl("FileDetailsPopover.qml"), |
814 | + folderListPage, |
815 | + { "model": folderModel.folderModel |
816 | + } |
817 | + ) |
818 | + } |
819 | + } |
820 | + ] |
821 | + |
822 | + Column { |
823 | + anchors { |
824 | + left: parent.left |
825 | + right: parent.right |
826 | + } |
827 | + |
828 | + Repeater { |
829 | + id: repeater |
830 | + model: actions |
831 | + delegate: OverlayStandard { |
832 | + property Action action: modelData |
833 | + |
834 | + visible: action.visible |
835 | + enabled: action.enabled |
836 | + text: action.text |
837 | + iconSource: action.iconSource |
838 | + iconFrame: false |
839 | + |
840 | + onClicked: { |
841 | + action.triggered(root.caller) |
842 | + PopupUtils.close(root) |
843 | + } |
844 | + |
845 | + showDivider: index < repeater.count - 1 |
846 | + } |
847 | + } |
848 | + } |
849 | +} |
850 | |
851 | === modified file 'src/app/qml/ui/FolderListPage.qml' |
852 | --- src/app/qml/ui/FolderListPage.qml 2014-04-30 08:54:08 +0000 |
853 | +++ src/app/qml/ui/FolderListPage.qml 2014-06-16 21:32:33 +0000 |
854 | @@ -19,339 +19,105 @@ |
855 | import Ubuntu.Components 0.1 |
856 | import Ubuntu.Components.Popups 0.1 |
857 | import Ubuntu.Components.ListItems 0.1 |
858 | -import org.nemomobile.folderlistmodel 1.0 |
859 | import "../components" |
860 | +import "../backend" |
861 | |
862 | Page { |
863 | id: folderListPage |
864 | |
865 | - title: folderName(folder) |
866 | + title: folderModel.title |
867 | + |
868 | + property alias folder: folderModel.folder |
869 | |
870 | property variant fileView: folderListPage |
871 | |
872 | - property bool showHiddenFiles: false |
873 | - |
874 | property bool showingListView: folderListView.visible |
875 | |
876 | - onShowHiddenFilesChanged: { |
877 | - pageModel.showHiddenFiles = folderListPage.showHiddenFiles |
878 | - } |
879 | - |
880 | - property string sortingMethod: "Name" |
881 | - |
882 | - onSortingMethodChanged: { |
883 | - console.log("Sorting by: " + sortingMethod) |
884 | - if (sortingMethod === "Name") { |
885 | - pageModel.sortBy = FolderListModel.SortByName |
886 | - } else if (sortingMethod === "Date") { |
887 | - pageModel.sortBy = FolderListModel.SortByDate |
888 | - } else { |
889 | - // Something fatal happened! |
890 | - console.log("ERROR: Invalid sort type:", sortingMethod) |
891 | - } |
892 | - } |
893 | - |
894 | - property bool sortAccending: true |
895 | - |
896 | - onSortAccendingChanged: { |
897 | - console.log("Sorting accending: " + sortAccending) |
898 | - |
899 | - if (sortAccending) { |
900 | - pageModel.sortOrder = FolderListModel.SortAscending |
901 | - } else { |
902 | - pageModel.sortOrder = FolderListModel.SortDescending |
903 | - } |
904 | - } |
905 | - |
906 | - // This stores the location using ~ to represent home |
907 | - property string folder |
908 | - property string homeFolder: "~" |
909 | - |
910 | - // This replaces ~ with the actual home folder, since the |
911 | - // plugin doesn't recognize the ~ |
912 | - property string path: folder.replace("~", pageModel.homePath()) |
913 | - |
914 | - function goHome() { |
915 | - goTo(folderListPage.homeFolder) |
916 | - } |
917 | - |
918 | - function goTo(location) { |
919 | - // Since the FolderListModel returns paths using the actual |
920 | - // home folder, this replaces with ~ before actually going |
921 | - // to the specified folder |
922 | - while (location !== '/' && location.substring(location.lastIndexOf('/')+1) === "") { |
923 | - location = location.substring(0, location.length - 1) |
924 | - } |
925 | - |
926 | - folderListPage.folder = location.replace(pageModel.homePath(), "~") |
927 | - refresh() |
928 | - } |
929 | - |
930 | - function refresh() { |
931 | - pageModel.refresh() |
932 | - } |
933 | - |
934 | - function pathAccessedDate() { |
935 | - console.log("calling method pageModel.curPathAccessedDate()") |
936 | - return pageModel.curPathAccessedDate() |
937 | - } |
938 | - |
939 | - function pathModifiedDate() { |
940 | - console.log("calling method pageModel.curPathModifiedDate()") |
941 | - return pageModel.curPathModifiedDate() |
942 | - } |
943 | - |
944 | - function pathIsWritable() { |
945 | - console.log("calling method pageModel.curPathIsWritable()") |
946 | - return pageModel.curPathIsWritable() |
947 | - } |
948 | - |
949 | - // FIXME: hard coded path for icon, assumes Ubuntu desktop icon available. |
950 | - // Nemo mobile has icon provider. Have to figure out what's the proper way |
951 | - // to get "system wide" icons in Ubuntu Touch, or if we have to use |
952 | - // icons packaged into the application. Both folder and individual |
953 | - // files will need an icon. |
954 | - // TODO: Remove isDir parameter and use new model functions |
955 | - function fileIcon(file, isDir) { |
956 | - file = file.replace(pageModel.homePath(), "~") |
957 | - var iconPath = isDir ? "/usr/share/icons/Humanity/places/48/folder.svg" |
958 | - : "/usr/share/icons/Humanity/mimes/48/empty.svg" |
959 | - |
960 | - if (file === "~") { |
961 | - iconPath = "../icons/folder-home.svg" |
962 | - } else if (file === i18n.tr("~/Desktop")) { |
963 | - iconPath = "/usr/share/icons/Humanity/places/48/user-desktop.svg" |
964 | - } else if (file === i18n.tr("~/Documents")) { |
965 | - iconPath = "/usr/share/icons/Humanity/places/48/folder-documents.svg" |
966 | - } else if (file === i18n.tr("~/Downloads")) { |
967 | - iconPath = "/usr/share/icons/Humanity/places/48/folder-downloads.svg" |
968 | - } else if (file === i18n.tr("~/Music")) { |
969 | - iconPath = "/usr/share/icons/Humanity/places/48/folder-music.svg" |
970 | - } else if (file === i18n.tr("~/Pictures")) { |
971 | - iconPath = "/usr/share/icons/Humanity/places/48/folder-pictures.svg" |
972 | - } else if (file === i18n.tr("~/Public")) { |
973 | - iconPath = "/usr/share/icons/Humanity/places/48/folder-publicshare.svg" |
974 | - } else if (file === i18n.tr("~/Programs")) { |
975 | - iconPath = "/usr/share/icons/Humanity/places/48/folder-system.svg" |
976 | - } else if (file === i18n.tr("~/Templates")) { |
977 | - iconPath = "/usr/share/icons/Humanity/places/48/folder-templates.svg" |
978 | - } else if (file === i18n.tr("~/Videos")) { |
979 | - iconPath = "/usr/share/icons/Humanity/places/48/folder-videos.svg" |
980 | - } else if (file === "/") { |
981 | - iconPath = "/usr/share/icons/Humanity/devices/48/drive-harddisk.svg" |
982 | - } |
983 | - |
984 | - return Qt.resolvedUrl(iconPath) |
985 | - } |
986 | - |
987 | - function folderName(folder) { |
988 | - folder = folder.replace(pageModel.homePath(), "~") |
989 | - |
990 | - if (folder === folderListPage.homeFolder) { |
991 | - return i18n.tr("Home") |
992 | - } else if (folder === "/") { |
993 | - return i18n.tr("File System") |
994 | - } else { |
995 | - return folder.substr(folder.lastIndexOf('/') + 1) |
996 | - } |
997 | - } |
998 | - |
999 | - function pathName(folder) { |
1000 | - if (folder === "/") { |
1001 | - return "/" |
1002 | - } else { |
1003 | - return folder.substr(folder.lastIndexOf('/') + 1) |
1004 | - } |
1005 | - } |
1006 | - |
1007 | - function pathExists(path) { |
1008 | - path = path.replace("~", pageModel.homePath()) |
1009 | - |
1010 | - if (path === '/') |
1011 | - return true |
1012 | - |
1013 | - if(path.charAt(0) === '/') { |
1014 | - console.log("Directory: " + path.substring(0, path.lastIndexOf('/')+1)) |
1015 | - repeaterModel.path = path.substring(0, path.lastIndexOf('/')+1) |
1016 | - console.log("Sub dir: " + path.substring(path.lastIndexOf('/')+1)) |
1017 | - if (path.substring(path.lastIndexOf('/')+1) !== "" && !repeaterModel.cdIntoPath(path.substring(path.lastIndexOf('/')+1))) { |
1018 | - return false |
1019 | - } else { |
1020 | - return true |
1021 | - } |
1022 | - } else { |
1023 | - return false |
1024 | - } |
1025 | - } |
1026 | - |
1027 | - property bool loading: pageModel.awaitingResults |
1028 | - |
1029 | - FolderListModel { |
1030 | - id: pageModel |
1031 | - |
1032 | - path: folderListPage.path |
1033 | - |
1034 | - enableExternalFSWatcher: true |
1035 | - |
1036 | - // Properties to emulate a model entry for use by FileDetailsPopover |
1037 | - property bool isDir: true |
1038 | - property string fileName: pathName(pageModel.path) |
1039 | - property string fileSize: (folderListView.count === 1 |
1040 | - ? i18n.tr("1 file") |
1041 | - : i18n.tr("%1 files").arg(folderListView.count)) |
1042 | - property bool isReadable: true |
1043 | - property bool isExecutable: true |
1044 | - } |
1045 | - |
1046 | - FolderListModel { |
1047 | - id: repeaterModel |
1048 | - path: folderListPage.folder |
1049 | - |
1050 | - onPathChanged: { |
1051 | - console.log("Path: " + repeaterModel.path) |
1052 | - } |
1053 | - } |
1054 | - |
1055 | - Component { |
1056 | - id: tabsPopover |
1057 | - ActionSelectionPopover { |
1058 | - objectName: "tabsPopover" |
1059 | - |
1060 | - property var tab |
1061 | - |
1062 | - grabDismissAreaEvents: true |
1063 | - |
1064 | - actions: ActionList { |
1065 | - Action { |
1066 | - text: i18n.tr("Open in a new tab") |
1067 | - onTriggered: { |
1068 | - openTab(folderListPage.folder) |
1069 | - } |
1070 | - } |
1071 | - |
1072 | - // The current tab can be closed as long as there is at least one tab remaining |
1073 | - Action { |
1074 | - text: i18n.tr("Close this tab") |
1075 | - onTriggered: { |
1076 | - closeTab(tab.index) |
1077 | - } |
1078 | - enabled: tabs.count > 1 |
1079 | - } |
1080 | - } |
1081 | - } |
1082 | - } |
1083 | - |
1084 | - Component { |
1085 | - id: folderActionsPopoverComponent |
1086 | - ActionSelectionPopover { |
1087 | - id: folderActionsPopover |
1088 | - objectName: "folderActionsPopover" |
1089 | - |
1090 | - grabDismissAreaEvents: true |
1091 | - |
1092 | - actions: ActionList { |
1093 | - Action { |
1094 | - text: i18n.tr("Create New Folder") |
1095 | - onTriggered: { |
1096 | - print(text) |
1097 | - |
1098 | - PopupUtils.open(createFolderDialog, folderListPage) |
1099 | - } |
1100 | - } |
1101 | - |
1102 | - // TODO: Disabled until backend supports creating files |
1103 | - // Action { |
1104 | - // text: i18n.tr("Create New File") |
1105 | - // onTriggered: { |
1106 | - // print(text) |
1107 | - |
1108 | - // PopupUtils.open(createFileDialog, root) |
1109 | - // } |
1110 | - // } |
1111 | - |
1112 | - Action { |
1113 | - text: pageModel.clipboardUrlsCounter === 0 |
1114 | - ? i18n.tr("Paste") |
1115 | - : pageModel.clipboardUrlsCounter === 1 |
1116 | - ? i18n.tr("Paste %1 File").arg(pageModel.clipboardUrlsCounter) |
1117 | - : i18n.tr("Paste %1 Files").arg(pageModel.clipboardUrlsCounter) |
1118 | - onTriggered: { |
1119 | - console.log("Pasting to current folder items of count " + pageModel.clipboardUrlsCounter) |
1120 | - fileOperationDialog.startOperation(i18n.tr("Paste files")) |
1121 | - pageModel.paste() |
1122 | - } |
1123 | - |
1124 | - // FIXME: This property is depreciated and doesn't seem to work! |
1125 | - //visible: pageModel.clipboardUrlsCounter > 0 |
1126 | - |
1127 | - enabled: pageModel.clipboardUrlsCounter > 0 |
1128 | - } |
1129 | - |
1130 | - // TODO: Disabled until support for opening apps is added |
1131 | - Action { |
1132 | - text: i18n.tr("Open in Terminal") |
1133 | - onTriggered: { |
1134 | - print(text) |
1135 | - |
1136 | - // Is this the way it will work?? |
1137 | - Qt.openUrlExternally("app://terminal") |
1138 | - } |
1139 | - |
1140 | - enabled: showAdvancedFeatures && false |
1141 | - } |
1142 | - |
1143 | - Action { |
1144 | - text: i18n.tr("Properties") |
1145 | - onTriggered: { |
1146 | - print(text) |
1147 | - PopupUtils.open(Qt.resolvedUrl("FileDetailsPopover.qml"), |
1148 | - folderListPage, |
1149 | - { "model": pageModel |
1150 | - } |
1151 | - ) |
1152 | - } |
1153 | - } |
1154 | - } |
1155 | - } |
1156 | - } |
1157 | - |
1158 | - Component { |
1159 | - id: createFolderDialog |
1160 | - ConfirmDialogWithInput { |
1161 | - title: i18n.tr("Create folder") |
1162 | - text: i18n.tr("Enter name for new folder") |
1163 | - |
1164 | - onAccepted: { |
1165 | - console.log("Create folder accepted", inputText) |
1166 | - if (inputText !== '') { |
1167 | - pageModel.mkdir(inputText) |
1168 | - } else { |
1169 | - console.log("Empty directory name, ignored") |
1170 | - } |
1171 | - } |
1172 | - } |
1173 | - } |
1174 | - |
1175 | - Component { |
1176 | - id: createFileDialog |
1177 | - ConfirmDialogWithInput { |
1178 | - title: i18n.tr("Create file") |
1179 | - text: i18n.tr("Enter name for new file") |
1180 | - |
1181 | - onAccepted: { |
1182 | - console.log("Create file accepted", inputText) |
1183 | - if (inputText !== '') { |
1184 | - //FIXME: Actually create a new file! |
1185 | - } else { |
1186 | - console.log("Empty file name, ignored") |
1187 | - } |
1188 | - } |
1189 | - } |
1190 | - } |
1191 | - |
1192 | - function openFile(filePath) { |
1193 | - if (!pageModel.openPath(filePath)) { |
1194 | - error(i18n.tr("File operation error"), i18n.tr("Unable to open '%11").arg(filePath)) |
1195 | + FolderModel { |
1196 | + id: folderModel |
1197 | + } |
1198 | + |
1199 | + flickable: !sidebar.expanded ? folderListView.visible ? folderListView : folderIconView.flickable : null |
1200 | + |
1201 | + onFlickableChanged: { |
1202 | + if (flickable === null) { |
1203 | + folderListView.topMargin = 0 |
1204 | + folderIconView.flickable.topMargin = 0 |
1205 | + } else { |
1206 | + folderListView.topMargin = units.gu(9.5) |
1207 | + folderIconView.flickable.topMargin = units.gu(9.5) |
1208 | + } |
1209 | + } |
1210 | + |
1211 | + PlacesSidebar { |
1212 | + id: sidebar |
1213 | + objectName: "placesSidebar" |
1214 | + |
1215 | +// anchors { |
1216 | +// top: parent.top |
1217 | +// bottom: parent.bottom |
1218 | +// bottomMargin: units.gu(-2) |
1219 | +// } |
1220 | + |
1221 | + expanded: showSidebar |
1222 | + } |
1223 | + |
1224 | + FolderIconView { |
1225 | + id: folderIconView |
1226 | + |
1227 | + clip: true |
1228 | + |
1229 | + folderListModel: folderModel.folderModel |
1230 | + anchors { |
1231 | + top: parent.top |
1232 | + bottom: parent.bottom |
1233 | + left: sidebar.right |
1234 | + right: parent.right |
1235 | + } |
1236 | + smallMode: !sidebar.expanded |
1237 | + visible: viewMethod === i18n.tr("Icons") |
1238 | + } |
1239 | + |
1240 | + FolderListView { |
1241 | + id: folderListView |
1242 | + |
1243 | + clip: true |
1244 | + |
1245 | + folderListModel: folderModel.folderModel |
1246 | + anchors { |
1247 | + top: parent.top |
1248 | + bottom: parent.bottom |
1249 | + left: sidebar.right |
1250 | + right: parent.right |
1251 | + } |
1252 | + smallMode: !sidebar.expanded |
1253 | + visible: viewMethod === i18n.tr("List") |
1254 | + } |
1255 | + |
1256 | + Item { |
1257 | + id: contents |
1258 | + |
1259 | + anchors { |
1260 | + top: parent.top |
1261 | + bottom: parent.bottom |
1262 | + left: sidebar.right |
1263 | + right: parent.right |
1264 | + } |
1265 | + |
1266 | + |
1267 | + Label { |
1268 | + text: i18n.tr("No files") |
1269 | + fontSize: "large" |
1270 | + opacity: 0.5 |
1271 | + anchors.centerIn: parent |
1272 | + visible: folderListView.count == 0 && !folderModel.folderModel.awaitingResults |
1273 | + } |
1274 | + |
1275 | + ActivityIndicator { |
1276 | + running: folderModel.folderModel.awaitingResults |
1277 | + width: units.gu(8) |
1278 | + height: units.gu(8) |
1279 | + anchors.centerIn: parent |
1280 | } |
1281 | } |
1282 | |
1283 | @@ -366,16 +132,15 @@ |
1284 | objectName: "up" |
1285 | text: "Up" |
1286 | iconSource: getIcon("keyboard-caps") |
1287 | - enabled: folder != "/" |
1288 | + enabled: folderModel.folder != "/" |
1289 | onTriggered: { |
1290 | - goTo(pageModel.parentPath) |
1291 | + goTo(folderModel.folderModel.parentPath) |
1292 | } |
1293 | } |
1294 | |
1295 | Item { |
1296 | id: pathItem |
1297 | - // TODO: Uncomment after re-enabling tab support (caused by lp:1295242) |
1298 | - width: folderListPage.width - units.gu(31)//folderListPage.width - units.gu(37) |
1299 | + width: folderListPage.width - units.gu(37) |
1300 | height: units.gu(5) |
1301 | anchors.verticalCenter: parent.verticalCenter |
1302 | PathBar { |
1303 | @@ -398,7 +163,7 @@ |
1304 | |
1305 | onTriggered: { |
1306 | print(text) |
1307 | - PopupUtils.open(folderActionsPopoverComponent, actionsButton) |
1308 | + PopupUtils.open(Qt.resolvedUrl("FolderActionsPopover.qml"), actionsButton) |
1309 | } |
1310 | } |
1311 | |
1312 | @@ -427,21 +192,20 @@ |
1313 | } |
1314 | } |
1315 | |
1316 | - // TODO: Uncomment after re-enabling tab support (caused by lp:1295242) |
1317 | -// ToolbarButton { |
1318 | -// id: tabsButton |
1319 | -// objectName: "tabs" |
1320 | -// text: i18n.tr("Tabs") |
1321 | -// iconSource: getIcon("browser-tabs") |
1322 | - |
1323 | -// onTriggered: { |
1324 | -// print(text) |
1325 | - |
1326 | -// PopupUtils.open(tabsPopover, tabsButton, { |
1327 | -// tab: folderListPage.parent |
1328 | -// }) |
1329 | -// } |
1330 | -// } |
1331 | + ToolbarButton { |
1332 | + id: tabsButton |
1333 | + objectName: "tabs" |
1334 | + text: i18n.tr("Tabs") |
1335 | + iconSource: getIcon("browser-tabs") |
1336 | + |
1337 | + onTriggered: { |
1338 | + print(text) |
1339 | + |
1340 | + PopupUtils.open(tabsPopover, tabsButton, { |
1341 | + tab: folderListPage.parent |
1342 | + }) |
1343 | + } |
1344 | + } |
1345 | |
1346 | ToolbarButton { |
1347 | id: settingsButton |
1348 | @@ -451,90 +215,6 @@ |
1349 | } |
1350 | } |
1351 | |
1352 | - flickable: !sidebar.expanded ? folderListView.visible ? folderListView : folderIconView.flickable : null |
1353 | - |
1354 | - onFlickableChanged: { |
1355 | - if (flickable === null) { |
1356 | - folderListView.topMargin = 0 |
1357 | - folderIconView.flickable.topMargin = 0 |
1358 | - } else { |
1359 | - folderListView.topMargin = units.gu(9.5) |
1360 | - folderIconView.flickable.topMargin = units.gu(9.5) |
1361 | - } |
1362 | - } |
1363 | - |
1364 | - PlacesSidebar { |
1365 | - id: sidebar |
1366 | - objectName: "placesSidebar" |
1367 | - |
1368 | -// anchors { |
1369 | -// top: parent.top |
1370 | -// bottom: parent.bottom |
1371 | -// bottomMargin: units.gu(-2) |
1372 | -// } |
1373 | - |
1374 | - expanded: showSidebar |
1375 | - } |
1376 | - |
1377 | - FolderIconView { |
1378 | - id: folderIconView |
1379 | - |
1380 | - clip: true |
1381 | - |
1382 | - folderListModel: pageModel |
1383 | - anchors { |
1384 | - top: parent.top |
1385 | - bottom: parent.bottom |
1386 | - left: sidebar.right |
1387 | - right: parent.right |
1388 | - } |
1389 | - smallMode: !sidebar.expanded |
1390 | - visible: viewMethod === i18n.tr("Icons") |
1391 | - } |
1392 | - |
1393 | - FolderListView { |
1394 | - id: folderListView |
1395 | - |
1396 | - clip: true |
1397 | - |
1398 | - folderListModel: pageModel |
1399 | - anchors { |
1400 | - top: parent.top |
1401 | - bottom: parent.bottom |
1402 | - left: sidebar.right |
1403 | - right: parent.right |
1404 | - } |
1405 | - smallMode: !sidebar.expanded |
1406 | - visible: viewMethod === i18n.tr("List") |
1407 | - } |
1408 | - |
1409 | - Item { |
1410 | - id: contents |
1411 | - |
1412 | - anchors { |
1413 | - top: parent.top |
1414 | - bottom: parent.bottom |
1415 | - left: sidebar.right |
1416 | - right: parent.right |
1417 | - } |
1418 | - |
1419 | - |
1420 | - Label { |
1421 | - text: i18n.tr("No files") |
1422 | - fontSize: "large" |
1423 | - opacity: 0.5 |
1424 | - anchors.centerIn: parent |
1425 | - visible: folderListView.count == 0 && !pageModel.awaitingResults |
1426 | - } |
1427 | - |
1428 | - ActivityIndicator { |
1429 | - running: pageModel.awaitingResults |
1430 | - width: units.gu(8) |
1431 | - height: units.gu(8) |
1432 | - anchors.centerIn: parent |
1433 | - } |
1434 | - } |
1435 | - |
1436 | Component { |
1437 | id: confirmSingleDeleteDialog |
1438 | ConfirmDialog { |
1439 | @@ -548,7 +228,53 @@ |
1440 | |
1441 | fileOperationDialog.startOperation("Deleting files") |
1442 | console.log("Doing delete") |
1443 | - pageModel.rm(filePath) |
1444 | + folderModel.folderModel.rm(filePath) |
1445 | + } |
1446 | + } |
1447 | + } |
1448 | + |
1449 | + Component { |
1450 | + id: tabsPopover |
1451 | + ActionSelectionPopover { |
1452 | + objectName: "tabsPopover" |
1453 | + |
1454 | + property var tab |
1455 | + |
1456 | + grabDismissAreaEvents: true |
1457 | + |
1458 | + actions: ActionList { |
1459 | + Action { |
1460 | + text: i18n.tr("Open in a new tab") |
1461 | + onTriggered: { |
1462 | + openTab(folderListPage.folder) |
1463 | + } |
1464 | + } |
1465 | + |
1466 | + // The current tab can be closed as long as there is at least one tab remaining |
1467 | + Action { |
1468 | + text: i18n.tr("Close this tab") |
1469 | + onTriggered: { |
1470 | + closeTab(tab.index) |
1471 | + } |
1472 | + enabled: tabs.count > 1 |
1473 | + } |
1474 | + } |
1475 | + } |
1476 | + } |
1477 | + |
1478 | + Component { |
1479 | + id: createFolderDialog |
1480 | + ConfirmDialogWithInput { |
1481 | + title: i18n.tr("Create folder") |
1482 | + text: i18n.tr("Enter name for new folder") |
1483 | + |
1484 | + onAccepted: { |
1485 | + console.log("Create folder accepted", inputText) |
1486 | + if (inputText !== '') { |
1487 | + folderModel.folderModel.mkdir(inputText) |
1488 | + } else { |
1489 | + console.log("Empty directory name, ignored") |
1490 | + } |
1491 | } |
1492 | } |
1493 | } |
1494 | @@ -571,7 +297,7 @@ |
1495 | console.log("Rename accepted", inputText) |
1496 | if (inputText !== '') { |
1497 | console.log("Rename commensed, modelRow/inputText", modelRow, inputText) |
1498 | - if (pageModel.rename(modelRow, inputText) === false) { |
1499 | + if (folderModel.folderModel.rename(modelRow, inputText) === false) { |
1500 | PopupUtils.open(Qt.resolvedUrl("NotifyDialog.qml"), delegate, |
1501 | { |
1502 | title: i18n.tr("Could not rename"), |
1503 | @@ -586,84 +312,9 @@ |
1504 | } |
1505 | } |
1506 | |
1507 | - Component { |
1508 | - id: actionSelectionPopoverComponent |
1509 | - |
1510 | - ActionSelectionPopover { |
1511 | - id: actionSelectionPopover |
1512 | - objectName: "fileActionsPopover" |
1513 | - |
1514 | - grabDismissAreaEvents: true |
1515 | - |
1516 | - property var model |
1517 | - actions: ActionList { |
1518 | - Action { |
1519 | - text: i18n.tr("Cut") |
1520 | - // TODO: temporary |
1521 | - iconSource: "/usr/share/icons/Humanity/actions/48/edit-cut.svg" |
1522 | - onTriggered: { |
1523 | - console.log("Cut on row called for", actionSelectionPopover.model.fileName, actionSelectionPopover.model.index) |
1524 | - pageModel.cutIndex(actionSelectionPopover.model.index) |
1525 | - console.log("CliboardUrlsCounter after copy", pageModel.clipboardUrlsCounter) |
1526 | - } |
1527 | - } |
1528 | - |
1529 | - Action { |
1530 | - text: i18n.tr("Copy") |
1531 | - // TODO: temporary. |
1532 | - iconSource: "/usr/share/icons/Humanity/actions/48/edit-copy.svg" |
1533 | - |
1534 | - onTriggered: { |
1535 | - console.log("Copy on row called for", actionSelectionPopover.model.fileName, actionSelectionPopover.model.index) |
1536 | - pageModel.copyIndex(actionSelectionPopover.model.index) |
1537 | - console.log("CliboardUrlsCounter after copy", pageModel.clipboardUrlsCounter) |
1538 | - } |
1539 | - } |
1540 | - |
1541 | - Action { |
1542 | - text: i18n.tr("Delete") |
1543 | - // TODO: temporary |
1544 | - iconSource: "/usr/share/icons/Humanity/actions/48/edit-delete.svg" |
1545 | - onTriggered: { |
1546 | - print(text) |
1547 | - PopupUtils.open(confirmSingleDeleteDialog, actionSelectionPopover.caller, |
1548 | - { "filePath" : actionSelectionPopover.model.filePath, |
1549 | - "fileName" : actionSelectionPopover.model.fileName } |
1550 | - ) |
1551 | - } |
1552 | - } |
1553 | - |
1554 | - Action { |
1555 | - text: i18n.tr("Rename") |
1556 | - // TODO: temporary |
1557 | - iconSource: "/usr/share/icons/Humanity/actions/48/rotate.svg" |
1558 | - onTriggered: { |
1559 | - print(text) |
1560 | - PopupUtils.open(confirmRenameDialog, actionSelectionPopover.caller, |
1561 | - { "modelRow" : actionSelectionPopover.model.index, |
1562 | - "inputText" : actionSelectionPopover.model.fileName |
1563 | - }) |
1564 | - } |
1565 | - } |
1566 | - |
1567 | - Action { |
1568 | - text: i18n.tr("Properties") |
1569 | - onTriggered: { |
1570 | - print(text) |
1571 | - PopupUtils.open(Qt.resolvedUrl("FileDetailsPopover.qml"), |
1572 | - actionSelectionPopover.caller, |
1573 | - { "model": actionSelectionPopover.model |
1574 | - } |
1575 | - ) |
1576 | - } |
1577 | - } |
1578 | - } |
1579 | - } |
1580 | - } |
1581 | - |
1582 | // Errors from model |
1583 | Connections { |
1584 | - target: pageModel |
1585 | + target: folderModel.folderModel |
1586 | onError: { |
1587 | console.log("FolderListModel Error Title/Description", errorTitle, errorMessage) |
1588 | error(i18n.tr("File operation error"), errorTitle + ": " + errorMessage) |
1589 | @@ -674,19 +325,19 @@ |
1590 | id: fileOperationDialog |
1591 | |
1592 | page: folderListPage |
1593 | - model: pageModel |
1594 | + model: folderModel.folderModel |
1595 | } |
1596 | |
1597 | function itemClicked(model) { |
1598 | if (model.isDir) { |
1599 | if (model.isReadable && model.isExecutable) { |
1600 | console.log("Changing to dir", model.filePath) |
1601 | - goTo(model.filePath) |
1602 | + folderModel.goTo(model.filePath) |
1603 | } else { |
1604 | PopupUtils.open(Qt.resolvedUrl("NotifyDialog.qml"), delegate, |
1605 | { |
1606 | title: i18n.tr("Folder not accessible"), |
1607 | - // TRANSLATORS: this refers to a folder name |
1608 | + // TRANSLATORS: this refers to a folder name |
1609 | text: i18n.tr("Can not access %1").arg(model.fileName) |
1610 | |
1611 | }) |
1612 | @@ -694,18 +345,12 @@ |
1613 | } else { |
1614 | console.log("Non dir clicked") |
1615 | openFile(model.fileName) |
1616 | -// PopupUtils.open(Qt.resolvedUrl("FileActionDialog.qml"), root, |
1617 | -// { |
1618 | -// fileName: model.fileName, |
1619 | -// filePath: model.filePath, |
1620 | -// folderListModel: root.folderListModel |
1621 | -// }) |
1622 | } |
1623 | } |
1624 | |
1625 | function itemLongPress(delegate, model) { |
1626 | console.log("FolderListDelegate onPressAndHold") |
1627 | - PopupUtils.open(actionSelectionPopoverComponent, delegate, |
1628 | + PopupUtils.open(Qt.resolvedUrl("FileActionsPopover.qml"), delegate, |
1629 | { |
1630 | model: model |
1631 | }) |
1632 | |
1633 | === modified file 'src/app/qml/ui/GoToDialog.qml' |
1634 | --- src/app/qml/ui/GoToDialog.qml 2014-02-19 00:00:15 +0000 |
1635 | +++ src/app/qml/ui/GoToDialog.qml 2014-06-16 21:32:33 +0000 |
1636 | @@ -37,7 +37,7 @@ |
1637 | |
1638 | inputMethodHints: Qt.ImhNoAutoUppercase |
1639 | |
1640 | - property bool valid: pathExists(text) |
1641 | + property bool valid: folderModel.pathExists(text) |
1642 | |
1643 | text: fileView.path |
1644 | |
1645 | @@ -55,7 +55,7 @@ |
1646 | |
1647 | onClicked: { |
1648 | print("User switched to:", locationField.text) |
1649 | - goTo(locationField.text) |
1650 | + folderModel.goTo(locationField.text) |
1651 | PopupUtils.close(root) |
1652 | } |
1653 | } |
1654 | |
1655 | === modified file 'src/app/qml/ui/PlacesPopover.qml' |
1656 | --- src/app/qml/ui/PlacesPopover.qml 2014-06-10 02:34:07 +0000 |
1657 | +++ src/app/qml/ui/PlacesPopover.qml 2014-06-16 21:32:33 +0000 |
1658 | @@ -24,40 +24,6 @@ |
1659 | id: root |
1660 | objectName: "placesPopover" |
1661 | |
1662 | - ListModel { |
1663 | - id: places |
1664 | - |
1665 | - ListElement { |
1666 | - objectName: 'placeHome' |
1667 | - path: "~" |
1668 | - } |
1669 | - |
1670 | - ListElement { |
1671 | - path: "~/Documents" |
1672 | - } |
1673 | - |
1674 | - ListElement { |
1675 | - path: "~/Downloads" |
1676 | - } |
1677 | - |
1678 | - ListElement { |
1679 | - path: "~/Music" |
1680 | - } |
1681 | - |
1682 | - ListElement { |
1683 | - path: "~/Pictures" |
1684 | - } |
1685 | - |
1686 | - ListElement { |
1687 | - path: "~/Videos" |
1688 | - } |
1689 | - |
1690 | - ListElement { |
1691 | - objectName: "placeRoot" |
1692 | - path: "/" |
1693 | - } |
1694 | - } |
1695 | - |
1696 | Column { |
1697 | anchors { |
1698 | left: parent.left |
1699 | @@ -79,7 +45,7 @@ |
1700 | |
1701 | inputMethodHints: Qt.ImhNoAutoUppercase |
1702 | |
1703 | - property bool valid: pathExists(text) |
1704 | + property bool valid: folderModel.pathExists(text) |
1705 | |
1706 | text: fileView.path |
1707 | |
1708 | @@ -103,7 +69,7 @@ |
1709 | |
1710 | onClicked: { |
1711 | print("User switched to:", locationField.text) |
1712 | - goTo(locationField.text) |
1713 | + folderModel.goTo(locationField.text) |
1714 | PopupUtils.close(root) |
1715 | } |
1716 | } |
1717 | @@ -113,7 +79,7 @@ |
1718 | id: placesList |
1719 | objectName: "placesList" |
1720 | |
1721 | - model: places |
1722 | + model: folderModel.places |
1723 | |
1724 | delegate: Standard { |
1725 | objectName: model.objectName |
1726 | @@ -123,18 +89,18 @@ |
1727 | anchors.left: parent.left |
1728 | anchors.leftMargin: units.gu(8) |
1729 | anchors.verticalCenter: parent.verticalCenter |
1730 | - text: folderName(path) |
1731 | + text: folderModel.folderName(path) |
1732 | color: selected ? UbuntuColors.orange : Theme.palette.normal.overlayText |
1733 | } |
1734 | |
1735 | - iconSource: model.icon || fileIcon(model.path, true) |
1736 | + iconSource: model.icon || folderModel.fileIcon(model.path, true) |
1737 | |
1738 | onClicked: { |
1739 | PopupUtils.close(root) |
1740 | goTo(model.path) |
1741 | } |
1742 | |
1743 | - selected: folder === path |
1744 | + selected: folderModel.folder === path |
1745 | iconFrame: false |
1746 | showDivider: index < (placesList.count - 1) |
1747 | } |