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