Merge lp:~ibelieve/ubuntu-filemanager-app/code-refactoring into lp:ubuntu-filemanager-app

Proposed by Michael Spencer
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
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

To post a comment you must log in.

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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory 'src/app/qml/backend'
=== added file 'src/app/qml/backend/FolderModel.qml'
--- src/app/qml/backend/FolderModel.qml 1970-01-01 00:00:00 +0000
+++ src/app/qml/backend/FolderModel.qml 2014-06-16 21:32:33 +0000
@@ -0,0 +1,303 @@
1/*
2 * Copyright (C) 2014 Michael Spencer <sonrisesoftware@gmail.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16import QtQuick 2.0
17import Ubuntu.Components 0.1
18import org.nemomobile.folderlistmodel 1.0
19
20Object {
21 id: model
22
23 property bool loading: folderModel.awaitingResults
24
25 property alias folderModel: folderModel
26
27 /*!
28 * The user-friendly title for the current directory
29 */
30 property string title: folderName(folder)
31
32 /*!
33 * Set to <code>true</code> true to show hidden files begining with a .
34 * in the current directory
35 */
36 property bool showHiddenFiles: false
37
38 // TODO: Can this be replaced by a property binding?
39 onShowHiddenFilesChanged: {
40 folderModel.showHiddenFiles = folderListPage.showHiddenFiles
41 }
42
43 /*!
44 * The sorting mode for the current directory.
45 *
46 * Can be one of: Name or Date
47 */
48 property string sortingMethod: "Name"
49
50 // TODO: Can this be replaced by a property binding?
51 onSortingMethodChanged: {
52 console.log("Sorting by: " + sortingMethod)
53 if (sortingMethod === "Name") {
54 folderModel.sortBy = FolderListModel.SortByName
55 } else if (sortingMethod === "Date") {
56 folderModel.sortBy = FolderListModel.SortByDate
57 } else {
58 // Something fatal happened!
59 console.log("ERROR: Invalid sort type:", sortingMethod)
60 }
61 }
62 /*!
63 * Set to <code>true</code> true to sort A-Z, or <code>false</code>
64 * to sort in reverse, from Z to A.
65 */
66 property bool sortAccending: true
67
68 // TODO: Can this be replaced by a property binding?
69 onSortAccendingChanged: {
70 console.log("Sorting accending: " + sortAccending)
71
72 if (sortAccending) {
73 folderModel.sortOrder = FolderListModel.SortAscending
74 } else {
75 folderModel.sortOrder = FolderListModel.SortDescending
76 }
77 }
78
79 // This stores the location using ~ to represent home
80 property string folder: homeFolder
81 property string homeFolder: "~"
82
83 // This replaces ~ with the actual home folder, since the
84 // plugin doesn't recognize the ~
85 property string path: folder.replace("~", folderModel.homePath())
86 property string homePath: folderModel.homePath()
87
88
89 /*!
90 * Switches directories to the user's home directory
91 */
92 function goHome() {
93 goTo(model.homeFolder)
94 }
95
96 /*!
97 * Switches directories to the specified path. Can use either /home/<user> or ~
98 * to represent the user's home folder
99 */
100 function goTo(location) {
101 // Since the FolderListModel returns paths using the actual
102 // home folder, this replaces with ~ before actually going
103 // to the specified folder
104 while (location !== '/' && location.substring(location.lastIndexOf('/')+1) === "") {
105 location = location.substring(0, location.length - 1)
106 }
107
108 model.folder = location.replace(homePath, "~")
109 refresh()
110 }
111
112 /*!
113 * Opens the specified file in the default app for the file's type
114 */
115 function openFile(filePath) {
116 if (!folderModel.openPath(filePath)) {
117 error(i18n.tr("File operation error"), i18n.tr("Unable to open '%11").arg(filePath))
118 }
119 }
120
121 /*!
122 * Refreshes the folder model
123 */
124 // TODO: Is this needed?
125 function refresh() {
126 folderModel.refresh()
127 }
128
129 /*!
130 * Returns the user-friendly name for the specified path. Can use either
131 * /home/<user> or ~ to represent the user's home folder
132 */
133 function folderName(folder) {
134 folder = folder.replace(homePath, "~")
135
136 if (folder === homeFolder) {
137 return i18n.tr("Home")
138 } else if (folder === "/") {
139 return i18n.tr("File System")
140 } else {
141 return pathName(folder)
142 }
143 }
144
145 /*!
146 * Returns the last element of the specified path, or / for the
147 * root folder.
148 */
149 function pathName(folder) {
150 if (folder === "/") {
151 return "/"
152 } else {
153 return folder.substr(folder.lastIndexOf('/') + 1)
154 }
155 }
156
157 function pathAccessedDate() {
158 console.log("calling method folderModel.curPathAccessedDate()")
159 return folderModel.curPathAccessedDate()
160 }
161
162 function pathModifiedDate() {
163 console.log("calling method folderModel.curPathModifiedDate()")
164 return folderModel.curPathModifiedDate()
165 }
166
167 function pathIsWritable() {
168 console.log("calling method folderModel.curPathIsWritable()")
169 return folderModel.curPathIsWritable()
170 }
171
172 /*!
173 * Returns true if the specified path exists in the file system.
174 */
175 function pathExists(path) {
176 path = path.replace("~", folderModel.homePath())
177
178 if (path === '/')
179 return true
180
181 if(path.charAt(0) === '/') {
182 console.log("Directory: " + path.substring(0, path.lastIndexOf('/')+1))
183 repeaterModel.path = path.substring(0, path.lastIndexOf('/')+1)
184 console.log("Sub dir: " + path.substring(path.lastIndexOf('/')+1))
185 if (path.substring(path.lastIndexOf('/')+1) !== "" && !repeaterModel.cdIntoPath(path.substring(path.lastIndexOf('/')+1))) {
186 return false
187 } else {
188 return true
189 }
190 } else {
191 return false
192 }
193 }
194
195
196 /*!
197 * Returns the icon for the specified file or folder.
198 */
199 // FIXME: hard coded path for icon, assumes Ubuntu desktop icon available.
200 // Nemo mobile has icon provider. Have to figure out what's the proper way
201 // to get "system wide" icons in Ubuntu Touch, or if we have to use
202 // icons packaged into the application. Both folder and individual
203 // files will need an icon.
204 // TODO: Remove isDir parameter and use new model functions
205 function fileIcon(file, isDir) {
206 file = file.replace(folderModel.homePath(), "~")
207 var iconPath = isDir ? "/usr/share/icons/Humanity/places/48/folder.svg"
208 : "/usr/share/icons/Humanity/mimes/48/empty.svg"
209
210 if (file === "~") {
211 iconPath = "../icons/folder-home.svg"
212 } else if (file === i18n.tr("~/Desktop")) {
213 iconPath = "/usr/share/icons/Humanity/places/48/user-desktop.svg"
214 } else if (file === i18n.tr("~/Documents")) {
215 iconPath = "/usr/share/icons/Humanity/places/48/folder-documents.svg"
216 } else if (file === i18n.tr("~/Downloads")) {
217 iconPath = "/usr/share/icons/Humanity/places/48/folder-downloads.svg"
218 } else if (file === i18n.tr("~/Music")) {
219 iconPath = "/usr/share/icons/Humanity/places/48/folder-music.svg"
220 } else if (file === i18n.tr("~/Pictures")) {
221 iconPath = "/usr/share/icons/Humanity/places/48/folder-pictures.svg"
222 } else if (file === i18n.tr("~/Public")) {
223 iconPath = "/usr/share/icons/Humanity/places/48/folder-publicshare.svg"
224 } else if (file === i18n.tr("~/Programs")) {
225 iconPath = "/usr/share/icons/Humanity/places/48/folder-system.svg"
226 } else if (file === i18n.tr("~/Templates")) {
227 iconPath = "/usr/share/icons/Humanity/places/48/folder-templates.svg"
228 } else if (file === i18n.tr("~/Videos")) {
229 iconPath = "/usr/share/icons/Humanity/places/48/folder-videos.svg"
230 } else if (file === "/") {
231 iconPath = "/usr/share/icons/Humanity/devices/48/drive-harddisk.svg"
232 }
233
234 return Qt.resolvedUrl(iconPath)
235 }
236
237 /*!
238 * The places list for the sidebar
239 */
240 property ListModel places: ListModel {
241 ListElement {
242 objectName: "placeHome"
243 path: "~"
244 }
245
246 ListElement {
247 path: "~/Documents"
248 }
249
250 ListElement {
251 path: "~/Downloads"
252 }
253
254 ListElement {
255 path: "~/Music"
256 }
257
258 ListElement {
259 path: "~/Pictures"
260 }
261
262 ListElement {
263 path: "~/Videos"
264 }
265
266 ListElement {
267 objectName: "placeRoot"
268 path: "/"
269 }
270 }
271
272 /*!
273 * The folder model used to represent the currently selected folder
274 */
275 FolderListModel {
276 id: folderModel
277
278 path: model.path
279
280 enableExternalFSWatcher: true
281
282 // Properties to emulate a model entry for use by FileDetailsPopover
283 property bool isDir: true
284 property string fileName: pathName(folderModel.path)
285 property string fileSize: (folderListView.count === 1
286 ? i18n.tr("1 file")
287 : i18n.tr("%1 files").arg(folderListView.count))
288 property bool isReadable: true
289 property bool isExecutable: true
290 }
291
292 /*!
293 * The folder model used for checking to see if a specified path exists
294 */
295 FolderListModel {
296 id: repeaterModel
297 path: model.folder
298
299 onPathChanged: {
300 console.log("Path: " + repeaterModel.path)
301 }
302 }
303}
0304
=== modified file 'src/app/qml/components/FolderIconDelegate.qml'
--- src/app/qml/components/FolderIconDelegate.qml 2014-03-29 09:20:11 +0000
+++ src/app/qml/components/FolderIconDelegate.qml 2014-06-16 21:32:33 +0000
@@ -52,7 +52,7 @@
52 property string text: fileName52 property string text: fileName
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 : "")
5454
55 property var icon: fileIcon(filePath, model.isDir)55 property var icon: folderModel.fileIcon(filePath, model.isDir)
5656
57 Item {57 Item {
58 anchors {58 anchors {
5959
=== modified file 'src/app/qml/components/FolderListDelegate.qml'
--- src/app/qml/components/FolderListDelegate.qml 2014-03-29 09:20:11 +0000
+++ src/app/qml/components/FolderListDelegate.qml 2014-06-16 21:32:33 +0000
@@ -30,7 +30,7 @@
30 subText: Qt.formatDateTime(model.modifiedDate, Qt.DefaultLocaleShortDate) + (!model.isDir ? ", " + fileSize : "")30 subText: Qt.formatDateTime(model.modifiedDate, Qt.DefaultLocaleShortDate) + (!model.isDir ? ", " + fileSize : "")
3131
32 property string path: fileView.path + '/' + model.fileName32 property string path: fileView.path + '/' + model.fileName
33 iconSource: fileIcon(path, model.isDir)33 iconSource: folderModel.fileIcon(path, model.isDir)
3434
35 progression: model.isDir35 progression: model.isDir
36 iconFrame: false36 iconFrame: false
3737
=== added file 'src/app/qml/components/OverlayStandard.qml'
--- src/app/qml/components/OverlayStandard.qml 1970-01-01 00:00:00 +0000
+++ src/app/qml/components/OverlayStandard.qml 2014-06-16 21:32:33 +0000
@@ -0,0 +1,55 @@
1/***************************************************************************
2 * Ubuntu UI Extras - A collection of QML widgets not available *
3 * in the default Ubuntu UI Toolkit *
4 * Copyright (C) 2013 Michael Spencer <sonrisesoftware@gmail.com> *
5 * *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 ***************************************************************************/
19import QtQuick 2.0
20import Ubuntu.Components 1.1
21import Ubuntu.Components.ListItems 1.0
22
23Standard {
24 id: standard
25
26 property alias text: label.text
27 property alias iconSource: image.source
28
29 Image {
30 id: image
31 width: units.gu(3.5)
32 height: width
33
34 anchors {
35 verticalCenter: parent.verticalCenter
36 left: parent.left
37 leftMargin: units.gu(2)
38 }
39 opacity: standard.enabled ? 1 : 0.5
40 }
41
42 //FIXME: Hack because of Suru theme!
43 Label {
44 id: label
45 anchors {
46 verticalCenter: parent.verticalCenter
47 left: parent.left
48 leftMargin: image.source === "" ? units.gu(2) : image.width + units.gu(4)
49 }
50
51 fontSize: "medium"
52 color: standard.selected ? UbuntuColors.orange : "#666"
53 opacity: standard.enabled ? 1 : 0.5
54 }
55}
056
=== modified file 'src/app/qml/components/PathBar.qml'
--- src/app/qml/components/PathBar.qml 2014-06-03 23:27:22 +0000
+++ src/app/qml/components/PathBar.qml 2014-06-16 21:32:33 +0000
@@ -87,7 +87,7 @@
8787
88 Repeater {88 Repeater {
89 id: repeater89 id: repeater
90 model: folder === "/" ? [""] : folder.split("/")90 model: folderModel.folder === "/" ? [""] : folderModel.folder.split("/")
91 delegate: Rectangle {91 delegate: Rectangle {
92 MouseArea {92 MouseArea {
93 id: mouseArea93 id: mouseArea
9494
=== modified file 'src/app/qml/components/PlacesSidebar.qml'
--- src/app/qml/components/PlacesSidebar.qml 2014-06-10 02:34:07 +0000
+++ src/app/qml/components/PlacesSidebar.qml 2014-06-16 21:32:33 +0000
@@ -27,7 +27,7 @@
27 //color: Qt.rgba(0.5,0.5,0.5,0.3)27 //color: Qt.rgba(0.5,0.5,0.5,0.3)
28 width: collapsed ? units.gu(8) : units.gu(22)28 width: collapsed ? units.gu(8) : units.gu(22)
2929
30 property bool collapsed: collapsedSidebar30 property bool collapsed: collapsedSidebar || !allowSidebarExpanded
3131
32 MouseArea {32 MouseArea {
33 anchors.fill: parent33 anchors.fill: parent
@@ -42,40 +42,6 @@
42 UbuntuNumberAnimation {}42 UbuntuNumberAnimation {}
43 }43 }
4444
45 ListModel {
46 id: places
47
48 ListElement {
49 objectName: "placeHome"
50 path: "~"
51 }
52
53 ListElement {
54 path: "~/Documents"
55 }
56
57 ListElement {
58 path: "~/Downloads"
59 }
60
61 ListElement {
62 path: "~/Music"
63 }
64
65 ListElement {
66 path: "~/Pictures"
67 }
68
69 ListElement {
70 path: "~/Videos"
71 }
72
73 ListElement {
74 objectName: "placeRoot"
75 path: "/"
76 }
77 }
78
79 Column {45 Column {
80 anchors {46 anchors {
81 left: parent.left47 left: parent.left
@@ -91,11 +57,11 @@
91 id: placesList57 id: placesList
92 objectName: "placesList"58 objectName: "placesList"
9359
94 model: places60 model: folderModel.places
9561
96 delegate: Standard {62 delegate: Standard {
97 objectName: model.objectName63 objectName: model.objectName
98 text: folderName(path)64 text: folderModel.folderName(path)
9965
100 Image {66 Image {
101 anchors {67 anchors {
@@ -114,16 +80,16 @@
114 }80 }
115 }81 }
11682
117 iconSource: model.icon || fileIcon(model.path, true)83 iconSource: model.icon || folderModel.fileIcon(model.path, true)
11884
119 onClicked: {85 onClicked: {
120 goTo(model.path)86 folderModel.goTo(model.path)
121 }87 }
12288
123 height: units.gu(5)89 height: units.gu(5)
124 showDivider: !collapsed90 showDivider: !collapsed
12591
126 selected: folder === path92 selected: folderModel.folder === path
127 iconFrame: false93 iconFrame: false
128 }94 }
129 }95 }
13096
=== modified file 'src/app/qml/filemanager.qml'
--- src/app/qml/filemanager.qml 2014-04-29 18:05:45 +0000
+++ src/app/qml/filemanager.qml 2014-06-16 21:32:33 +0000
@@ -47,11 +47,6 @@
4747
48 property bool allowSidebarExpanded: width >= units.gu(80)48 property bool allowSidebarExpanded: width >= units.gu(80)
4949
50 onAllowSidebarExpandedChanged: {
51 if (!allowSidebarExpanded)
52 saveSetting("collapsedSidebar", true)
53 }
54
55 property bool showSidebar: width >= units.gu(50)50 property bool showSidebar: width >= units.gu(50)
5651
57 property bool showToolbar: width >= units.gu(80)52 property bool showToolbar: width >= units.gu(80)
@@ -95,27 +90,17 @@
95 Tabs {90 Tabs {
96 id: tabs91 id: tabs
9792
98 Tab {93 Repeater {
99 title: page.title94 model: folderTabs
100 page: FolderListPage {95 delegate: Tab {
101 objectName: "folderPage"96 title: page.title
97 page: FolderListPage {
98 objectName: "folderPage"
10299
103 folder: "~"//modelData100 folder: modelData
101 }
104 }102 }
105 }103 }
106
107 // TODO: Temporarily disabled tabs support since this is broken in the SDK (lp:1295242)
108// Repeater {
109// model: folderTabs
110// delegate: Tab {
111// title: page.title
112// page: FolderListPage {
113// objectName: "folderPage"
114
115// folder: modelData
116// }
117// }
118// }
119 }104 }
120105
121 Component.onCompleted: {106 Component.onCompleted: {
@@ -192,7 +177,7 @@
192 }177 }
193178
194 function getIcon(name) {179 function getIcon(name) {
195 return "/usr/share/icons/ubuntu-mobile/actions/scalable/" + name + ".svg" //Qt.resolvedUrl("icons/" + name + ".png")180 return Qt.resolvedUrl("icons/" + name + ".png")
196 }181 }
197182
198 function error(title, message) {183 function error(title, message) {
199184
=== added file 'src/app/qml/icons/add.png'
200Binary 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 differ185Binary 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
=== added file 'src/app/qml/icons/delete.png'
201Binary 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 differ186Binary 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
=== added file 'src/app/qml/icons/edit-copy.png'
202Binary 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 differ187Binary 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
=== added file 'src/app/qml/icons/edit-cut.png'
203Binary 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 differ188Binary 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
=== added file 'src/app/qml/icons/edit-paste.png'
204Binary 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 differ189Binary 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
=== modified file 'src/app/qml/icons/edit.png'
205Binary 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 differ190Binary 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
=== added file 'src/app/qml/icons/info.png'
206Binary 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 differ191Binary 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
=== modified file 'src/app/qml/icons/location.png'
207Binary 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 differ192Binary 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
=== modified file 'src/app/qml/icons/navigation-menu.png'
208Binary 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 differ193Binary 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
=== modified file 'src/app/qml/icons/properties.png'
209Binary 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 differ194Binary 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
=== added file 'src/app/qml/ui/FileActionsPopover.qml'
--- src/app/qml/ui/FileActionsPopover.qml 1970-01-01 00:00:00 +0000
+++ src/app/qml/ui/FileActionsPopover.qml 2014-06-16 21:32:33 +0000
@@ -0,0 +1,114 @@
1/*
2 * Copyright (C) 2014 Michael Spencer <sonrisesoftware@gmail.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16import QtQuick 2.0
17import Ubuntu.Components 0.1
18import Ubuntu.Components.Popups 0.1
19import Ubuntu.Components.ListItems 0.1 as ListItem
20import "../components"
21
22Popover {
23 id: root
24
25 property var model
26
27 property list<Action> actions: [
28 Action {
29 text: i18n.tr("Cut")
30 iconSource: getIcon("edit-cut")
31 onTriggered: {
32 console.log("Cut on row called for", root.model.fileName, root.model.index)
33 folderModel.folderModel.cutIndex(root.model.index)
34 console.log("CliboardUrlsCounter after copy", folderModel.folderModel.clipboardUrlsCounter)
35 }
36 },
37
38 Action {
39 text: i18n.tr("Copy")
40 iconSource: getIcon("edit-copy")
41
42 onTriggered: {
43 console.log("Copy on row called for", root.model.fileName, root.model.index)
44 folderModel.folderModel.copyIndex(root.model.index)
45 console.log("CliboardUrlsCounter after copy", folderModel.folderModel.clipboardUrlsCounter)
46 }
47 },
48
49 Action {
50 text: i18n.tr("Delete")
51 iconSource: getIcon("delete")
52 onTriggered: {
53 print(text)
54 PopupUtils.open(confirmSingleDeleteDialog, root.caller,
55 { "filePath" : root.model.filePath,
56 "fileName" : root.model.fileName }
57 )
58 }
59 },
60
61 Action {
62 text: i18n.tr("Rename")
63 iconSource: getIcon("edit")
64 onTriggered: {
65 print(text)
66 PopupUtils.open(confirmRenameDialog, root.caller,
67 { "modelRow" : root.model.index,
68 "inputText" : root.model.fileName
69 })
70 }
71 },
72
73 Action {
74 text: i18n.tr("Properties")
75 iconSource: getIcon("info")
76 onTriggered: {
77 print(text)
78 PopupUtils.open(Qt.resolvedUrl("FileDetailsPopover.qml"),
79 value,
80 { "model": root.model
81 }
82 )
83 }
84 }
85 ]
86
87 Column {
88 anchors {
89 left: parent.left
90 right: parent.right
91 }
92
93 Repeater {
94 id: repeater
95 model: actions
96 delegate: OverlayStandard {
97 property Action action: modelData
98
99 visible: action.visible
100 enabled: action.enabled
101 text: action.text
102 iconSource: action.iconSource
103 iconFrame: false
104
105 onClicked: {
106 action.triggered(root.caller)
107 PopupUtils.close(root)
108 }
109
110 showDivider: index < repeater.count - 1
111 }
112 }
113 }
114}
0115
=== modified file 'src/app/qml/ui/FileDetailsPopover.qml'
--- src/app/qml/ui/FileDetailsPopover.qml 2014-02-19 00:00:15 +0000
+++ src/app/qml/ui/FileDetailsPopover.qml 2014-06-16 21:32:33 +0000
@@ -71,13 +71,13 @@
71 anchors.verticalCenter: parent.verticalCenter71 anchors.verticalCenter: parent.verticalCenter
7272
73 // TODO: how to get proper icon?73 // TODO: how to get proper icon?
74 source: fileIcon(root.path, model.isDir)74 source: folderModel.fileIcon(root.path, model.isDir)
75 }75 }
7676
77 Label {77 Label {
78 anchors.verticalCenter: parent.verticalCenter78 anchors.verticalCenter: parent.verticalCenter
7979
80 text: folderName(root.path)80 text: folderModel.folderName(root.path)
81 color: Theme.palette.normal.overlayText81 color: Theme.palette.normal.overlayText
82 font.bold: true82 font.bold: true
83 }83 }
8484
=== modified file 'src/app/qml/ui/FileOperationProgressDialog.qml'
--- src/app/qml/ui/FileOperationProgressDialog.qml 2014-02-19 00:00:15 +0000
+++ src/app/qml/ui/FileOperationProgressDialog.qml 2014-06-16 21:32:33 +0000
@@ -78,7 +78,7 @@
7878
79 // Errors from model79 // Errors from model
80 Connections {80 Connections {
81 target: pageModel81 target: folderModel
82 onError: {82 onError: {
83 PopupUtils.close(root)83 PopupUtils.close(root)
84 }84 }
8585
=== added file 'src/app/qml/ui/FolderActionsPopover.qml'
--- src/app/qml/ui/FolderActionsPopover.qml 1970-01-01 00:00:00 +0000
+++ src/app/qml/ui/FolderActionsPopover.qml 2014-06-16 21:32:33 +0000
@@ -0,0 +1,116 @@
1/*
2 * Copyright (C) 2014 Michael Spencer <sonrisesoftware@gmail.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16import QtQuick 2.0
17import Ubuntu.Components 0.1
18import Ubuntu.Components.Popups 0.1
19import Ubuntu.Components.ListItems 0.1 as ListItem
20import "../components"
21
22Popover {
23 id: root
24
25 property list<Action> actions: [
26 Action {
27 text: i18n.tr("Create New Folder")
28 iconSource: getIcon("add")
29 onTriggered: {
30 print(text)
31
32 PopupUtils.open(createFolderDialog, folderListPage)
33 }
34 },
35
36 // TODO: Disabled until backend supports creating files
37// Action {
38// text: i18n.tr("Create New File")
39// onTriggered: {
40// print(text)
41
42// PopupUtils.open(createFileDialog, root)
43// }
44// },
45
46 Action {
47 text: folderModel.folderModel.clipboardUrlsCounter === 0
48 ? i18n.tr("Paste")
49 : folderModel.folderModel.clipboardUrlsCounter === 1
50 ? i18n.tr("Paste %1 File").arg(folderModel.folderModel.clipboardUrlsCounter)
51 : i18n.tr("Paste %1 Files").arg(folderModel.folderModel.clipboardUrlsCounter)
52 onTriggered: {
53 console.log("Pasting to current folder items of count " + folderModel.folderModel.clipboardUrlsCounter)
54 fileOperationDialog.startOperation(i18n.tr("Paste files"))
55 folderModel.folderModel.paste()
56 }
57 iconSource: getIcon("edit-paste")
58
59 enabled: folderModel.folderModel.clipboardUrlsCounter > 0
60 },
61
62 // TODO: Disabled until support for opening apps is added
63 Action {
64 text: i18n.tr("Open in Terminal")
65 onTriggered: {
66 print(text)
67
68 // Is this the way it will work??
69 Qt.openUrlExternally("app://terminal")
70 }
71
72 visible: showAdvancedFeatures && false
73 },
74
75 Action {
76 text: i18n.tr("Properties")
77 iconSource: getIcon("info")
78 onTriggered: {
79 print(text)
80 PopupUtils.open(Qt.resolvedUrl("FileDetailsPopover.qml"),
81 folderListPage,
82 { "model": folderModel.folderModel
83 }
84 )
85 }
86 }
87 ]
88
89 Column {
90 anchors {
91 left: parent.left
92 right: parent.right
93 }
94
95 Repeater {
96 id: repeater
97 model: actions
98 delegate: OverlayStandard {
99 property Action action: modelData
100
101 visible: action.visible
102 enabled: action.enabled
103 text: action.text
104 iconSource: action.iconSource
105 iconFrame: false
106
107 onClicked: {
108 action.triggered(root.caller)
109 PopupUtils.close(root)
110 }
111
112 showDivider: index < repeater.count - 1
113 }
114 }
115 }
116}
0117
=== modified file 'src/app/qml/ui/FolderListPage.qml'
--- src/app/qml/ui/FolderListPage.qml 2014-04-30 08:54:08 +0000
+++ src/app/qml/ui/FolderListPage.qml 2014-06-16 21:32:33 +0000
@@ -19,339 +19,105 @@
19import Ubuntu.Components 0.119import Ubuntu.Components 0.1
20import Ubuntu.Components.Popups 0.120import Ubuntu.Components.Popups 0.1
21import Ubuntu.Components.ListItems 0.121import Ubuntu.Components.ListItems 0.1
22import org.nemomobile.folderlistmodel 1.0
23import "../components"22import "../components"
23import "../backend"
2424
25Page {25Page {
26 id: folderListPage26 id: folderListPage
2727
28 title: folderName(folder)28 title: folderModel.title
29
30 property alias folder: folderModel.folder
2931
30 property variant fileView: folderListPage32 property variant fileView: folderListPage
3133
32 property bool showHiddenFiles: false
33
34 property bool showingListView: folderListView.visible34 property bool showingListView: folderListView.visible
3535
36 onShowHiddenFilesChanged: {36 FolderModel {
37 pageModel.showHiddenFiles = folderListPage.showHiddenFiles37 id: folderModel
38 }38 }
3939
40 property string sortingMethod: "Name"40 flickable: !sidebar.expanded ? folderListView.visible ? folderListView : folderIconView.flickable : null
4141
42 onSortingMethodChanged: {42 onFlickableChanged: {
43 console.log("Sorting by: " + sortingMethod)43 if (flickable === null) {
44 if (sortingMethod === "Name") {44 folderListView.topMargin = 0
45 pageModel.sortBy = FolderListModel.SortByName45 folderIconView.flickable.topMargin = 0
46 } else if (sortingMethod === "Date") {46 } else {
47 pageModel.sortBy = FolderListModel.SortByDate47 folderListView.topMargin = units.gu(9.5)
48 } else {48 folderIconView.flickable.topMargin = units.gu(9.5)
49 // Something fatal happened!49 }
50 console.log("ERROR: Invalid sort type:", sortingMethod)50 }
51 }51
52 }52 PlacesSidebar {
5353 id: sidebar
54 property bool sortAccending: true54 objectName: "placesSidebar"
5555
56 onSortAccendingChanged: {56// anchors {
57 console.log("Sorting accending: " + sortAccending)57// top: parent.top
5858// bottom: parent.bottom
59 if (sortAccending) {59// bottomMargin: units.gu(-2)
60 pageModel.sortOrder = FolderListModel.SortAscending60// }
61 } else {61
62 pageModel.sortOrder = FolderListModel.SortDescending62 expanded: showSidebar
63 }63 }
64 }64
6565 FolderIconView {
66 // This stores the location using ~ to represent home66 id: folderIconView
67 property string folder67
68 property string homeFolder: "~"68 clip: true
6969
70 // This replaces ~ with the actual home folder, since the70 folderListModel: folderModel.folderModel
71 // plugin doesn't recognize the ~71 anchors {
72 property string path: folder.replace("~", pageModel.homePath())72 top: parent.top
7373 bottom: parent.bottom
74 function goHome() {74 left: sidebar.right
75 goTo(folderListPage.homeFolder)75 right: parent.right
76 }76 }
7777 smallMode: !sidebar.expanded
78 function goTo(location) {78 visible: viewMethod === i18n.tr("Icons")
79 // Since the FolderListModel returns paths using the actual79 }
80 // home folder, this replaces with ~ before actually going80
81 // to the specified folder81 FolderListView {
82 while (location !== '/' && location.substring(location.lastIndexOf('/')+1) === "") {82 id: folderListView
83 location = location.substring(0, location.length - 1)83
84 }84 clip: true
8585
86 folderListPage.folder = location.replace(pageModel.homePath(), "~")86 folderListModel: folderModel.folderModel
87 refresh()87 anchors {
88 }88 top: parent.top
8989 bottom: parent.bottom
90 function refresh() {90 left: sidebar.right
91 pageModel.refresh()91 right: parent.right
92 }92 }
9393 smallMode: !sidebar.expanded
94 function pathAccessedDate() {94 visible: viewMethod === i18n.tr("List")
95 console.log("calling method pageModel.curPathAccessedDate()")95 }
96 return pageModel.curPathAccessedDate()96
97 }97 Item {
9898 id: contents
99 function pathModifiedDate() {99
100 console.log("calling method pageModel.curPathModifiedDate()")100 anchors {
101 return pageModel.curPathModifiedDate()101 top: parent.top
102 }102 bottom: parent.bottom
103103 left: sidebar.right
104 function pathIsWritable() {104 right: parent.right
105 console.log("calling method pageModel.curPathIsWritable()")105 }
106 return pageModel.curPathIsWritable()106
107 }107
108108 Label {
109 // FIXME: hard coded path for icon, assumes Ubuntu desktop icon available.109 text: i18n.tr("No files")
110 // Nemo mobile has icon provider. Have to figure out what's the proper way110 fontSize: "large"
111 // to get "system wide" icons in Ubuntu Touch, or if we have to use111 opacity: 0.5
112 // icons packaged into the application. Both folder and individual112 anchors.centerIn: parent
113 // files will need an icon.113 visible: folderListView.count == 0 && !folderModel.folderModel.awaitingResults
114 // TODO: Remove isDir parameter and use new model functions114 }
115 function fileIcon(file, isDir) {115
116 file = file.replace(pageModel.homePath(), "~")116 ActivityIndicator {
117 var iconPath = isDir ? "/usr/share/icons/Humanity/places/48/folder.svg"117 running: folderModel.folderModel.awaitingResults
118 : "/usr/share/icons/Humanity/mimes/48/empty.svg"118 width: units.gu(8)
119119 height: units.gu(8)
120 if (file === "~") {120 anchors.centerIn: parent
121 iconPath = "../icons/folder-home.svg"
122 } else if (file === i18n.tr("~/Desktop")) {
123 iconPath = "/usr/share/icons/Humanity/places/48/user-desktop.svg"
124 } else if (file === i18n.tr("~/Documents")) {
125 iconPath = "/usr/share/icons/Humanity/places/48/folder-documents.svg"
126 } else if (file === i18n.tr("~/Downloads")) {
127 iconPath = "/usr/share/icons/Humanity/places/48/folder-downloads.svg"
128 } else if (file === i18n.tr("~/Music")) {
129 iconPath = "/usr/share/icons/Humanity/places/48/folder-music.svg"
130 } else if (file === i18n.tr("~/Pictures")) {
131 iconPath = "/usr/share/icons/Humanity/places/48/folder-pictures.svg"
132 } else if (file === i18n.tr("~/Public")) {
133 iconPath = "/usr/share/icons/Humanity/places/48/folder-publicshare.svg"
134 } else if (file === i18n.tr("~/Programs")) {
135 iconPath = "/usr/share/icons/Humanity/places/48/folder-system.svg"
136 } else if (file === i18n.tr("~/Templates")) {
137 iconPath = "/usr/share/icons/Humanity/places/48/folder-templates.svg"
138 } else if (file === i18n.tr("~/Videos")) {
139 iconPath = "/usr/share/icons/Humanity/places/48/folder-videos.svg"
140 } else if (file === "/") {
141 iconPath = "/usr/share/icons/Humanity/devices/48/drive-harddisk.svg"
142 }
143
144 return Qt.resolvedUrl(iconPath)
145 }
146
147 function folderName(folder) {
148 folder = folder.replace(pageModel.homePath(), "~")
149
150 if (folder === folderListPage.homeFolder) {
151 return i18n.tr("Home")
152 } else if (folder === "/") {
153 return i18n.tr("File System")
154 } else {
155 return folder.substr(folder.lastIndexOf('/') + 1)
156 }
157 }
158
159 function pathName(folder) {
160 if (folder === "/") {
161 return "/"
162 } else {
163 return folder.substr(folder.lastIndexOf('/') + 1)
164 }
165 }
166
167 function pathExists(path) {
168 path = path.replace("~", pageModel.homePath())
169
170 if (path === '/')
171 return true
172
173 if(path.charAt(0) === '/') {
174 console.log("Directory: " + path.substring(0, path.lastIndexOf('/')+1))
175 repeaterModel.path = path.substring(0, path.lastIndexOf('/')+1)
176 console.log("Sub dir: " + path.substring(path.lastIndexOf('/')+1))
177 if (path.substring(path.lastIndexOf('/')+1) !== "" && !repeaterModel.cdIntoPath(path.substring(path.lastIndexOf('/')+1))) {
178 return false
179 } else {
180 return true
181 }
182 } else {
183 return false
184 }
185 }
186
187 property bool loading: pageModel.awaitingResults
188
189 FolderListModel {
190 id: pageModel
191
192 path: folderListPage.path
193
194 enableExternalFSWatcher: true
195
196 // Properties to emulate a model entry for use by FileDetailsPopover
197 property bool isDir: true
198 property string fileName: pathName(pageModel.path)
199 property string fileSize: (folderListView.count === 1
200 ? i18n.tr("1 file")
201 : i18n.tr("%1 files").arg(folderListView.count))
202 property bool isReadable: true
203 property bool isExecutable: true
204 }
205
206 FolderListModel {
207 id: repeaterModel
208 path: folderListPage.folder
209
210 onPathChanged: {
211 console.log("Path: " + repeaterModel.path)
212 }
213 }
214
215 Component {
216 id: tabsPopover
217 ActionSelectionPopover {
218 objectName: "tabsPopover"
219
220 property var tab
221
222 grabDismissAreaEvents: true
223
224 actions: ActionList {
225 Action {
226 text: i18n.tr("Open in a new tab")
227 onTriggered: {
228 openTab(folderListPage.folder)
229 }
230 }
231
232 // The current tab can be closed as long as there is at least one tab remaining
233 Action {
234 text: i18n.tr("Close this tab")
235 onTriggered: {
236 closeTab(tab.index)
237 }
238 enabled: tabs.count > 1
239 }
240 }
241 }
242 }
243
244 Component {
245 id: folderActionsPopoverComponent
246 ActionSelectionPopover {
247 id: folderActionsPopover
248 objectName: "folderActionsPopover"
249
250 grabDismissAreaEvents: true
251
252 actions: ActionList {
253 Action {
254 text: i18n.tr("Create New Folder")
255 onTriggered: {
256 print(text)
257
258 PopupUtils.open(createFolderDialog, folderListPage)
259 }
260 }
261
262 // TODO: Disabled until backend supports creating files
263 // Action {
264 // text: i18n.tr("Create New File")
265 // onTriggered: {
266 // print(text)
267
268 // PopupUtils.open(createFileDialog, root)
269 // }
270 // }
271
272 Action {
273 text: pageModel.clipboardUrlsCounter === 0
274 ? i18n.tr("Paste")
275 : pageModel.clipboardUrlsCounter === 1
276 ? i18n.tr("Paste %1 File").arg(pageModel.clipboardUrlsCounter)
277 : i18n.tr("Paste %1 Files").arg(pageModel.clipboardUrlsCounter)
278 onTriggered: {
279 console.log("Pasting to current folder items of count " + pageModel.clipboardUrlsCounter)
280 fileOperationDialog.startOperation(i18n.tr("Paste files"))
281 pageModel.paste()
282 }
283
284 // FIXME: This property is depreciated and doesn't seem to work!
285 //visible: pageModel.clipboardUrlsCounter > 0
286
287 enabled: pageModel.clipboardUrlsCounter > 0
288 }
289
290 // TODO: Disabled until support for opening apps is added
291 Action {
292 text: i18n.tr("Open in Terminal")
293 onTriggered: {
294 print(text)
295
296 // Is this the way it will work??
297 Qt.openUrlExternally("app://terminal")
298 }
299
300 enabled: showAdvancedFeatures && false
301 }
302
303 Action {
304 text: i18n.tr("Properties")
305 onTriggered: {
306 print(text)
307 PopupUtils.open(Qt.resolvedUrl("FileDetailsPopover.qml"),
308 folderListPage,
309 { "model": pageModel
310 }
311 )
312 }
313 }
314 }
315 }
316 }
317
318 Component {
319 id: createFolderDialog
320 ConfirmDialogWithInput {
321 title: i18n.tr("Create folder")
322 text: i18n.tr("Enter name for new folder")
323
324 onAccepted: {
325 console.log("Create folder accepted", inputText)
326 if (inputText !== '') {
327 pageModel.mkdir(inputText)
328 } else {
329 console.log("Empty directory name, ignored")
330 }
331 }
332 }
333 }
334
335 Component {
336 id: createFileDialog
337 ConfirmDialogWithInput {
338 title: i18n.tr("Create file")
339 text: i18n.tr("Enter name for new file")
340
341 onAccepted: {
342 console.log("Create file accepted", inputText)
343 if (inputText !== '') {
344 //FIXME: Actually create a new file!
345 } else {
346 console.log("Empty file name, ignored")
347 }
348 }
349 }
350 }
351
352 function openFile(filePath) {
353 if (!pageModel.openPath(filePath)) {
354 error(i18n.tr("File operation error"), i18n.tr("Unable to open '%11").arg(filePath))
355 }121 }
356 }122 }
357123
@@ -366,16 +132,15 @@
366 objectName: "up"132 objectName: "up"
367 text: "Up"133 text: "Up"
368 iconSource: getIcon("keyboard-caps")134 iconSource: getIcon("keyboard-caps")
369 enabled: folder != "/"135 enabled: folderModel.folder != "/"
370 onTriggered: {136 onTriggered: {
371 goTo(pageModel.parentPath)137 goTo(folderModel.folderModel.parentPath)
372 }138 }
373 }139 }
374140
375 Item {141 Item {
376 id: pathItem142 id: pathItem
377 // TODO: Uncomment after re-enabling tab support (caused by lp:1295242)143 width: folderListPage.width - units.gu(37)
378 width: folderListPage.width - units.gu(31)//folderListPage.width - units.gu(37)
379 height: units.gu(5)144 height: units.gu(5)
380 anchors.verticalCenter: parent.verticalCenter145 anchors.verticalCenter: parent.verticalCenter
381 PathBar {146 PathBar {
@@ -398,7 +163,7 @@
398163
399 onTriggered: {164 onTriggered: {
400 print(text)165 print(text)
401 PopupUtils.open(folderActionsPopoverComponent, actionsButton)166 PopupUtils.open(Qt.resolvedUrl("FolderActionsPopover.qml"), actionsButton)
402 }167 }
403 }168 }
404169
@@ -427,21 +192,20 @@
427 }192 }
428 }193 }
429194
430 // TODO: Uncomment after re-enabling tab support (caused by lp:1295242)195 ToolbarButton {
431// ToolbarButton {196 id: tabsButton
432// id: tabsButton197 objectName: "tabs"
433// objectName: "tabs"198 text: i18n.tr("Tabs")
434// text: i18n.tr("Tabs")199 iconSource: getIcon("browser-tabs")
435// iconSource: getIcon("browser-tabs")200
436201 onTriggered: {
437// onTriggered: {202 print(text)
438// print(text)203
439204 PopupUtils.open(tabsPopover, tabsButton, {
440// PopupUtils.open(tabsPopover, tabsButton, {205 tab: folderListPage.parent
441// tab: folderListPage.parent206 })
442// })207 }
443// }208 }
444// }
445209
446 ToolbarButton {210 ToolbarButton {
447 id: settingsButton211 id: settingsButton
@@ -451,90 +215,6 @@
451 }215 }
452 }216 }
453217
454 flickable: !sidebar.expanded ? folderListView.visible ? folderListView : folderIconView.flickable : null
455
456 onFlickableChanged: {
457 if (flickable === null) {
458 folderListView.topMargin = 0
459 folderIconView.flickable.topMargin = 0
460 } else {
461 folderListView.topMargin = units.gu(9.5)
462 folderIconView.flickable.topMargin = units.gu(9.5)
463 }
464 }
465
466 PlacesSidebar {
467 id: sidebar
468 objectName: "placesSidebar"
469
470// anchors {
471// top: parent.top
472// bottom: parent.bottom
473// bottomMargin: units.gu(-2)
474// }
475
476 expanded: showSidebar
477 }
478
479 FolderIconView {
480 id: folderIconView
481
482 clip: true
483
484 folderListModel: pageModel
485 anchors {
486 top: parent.top
487 bottom: parent.bottom
488 left: sidebar.right
489 right: parent.right
490 }
491 smallMode: !sidebar.expanded
492 visible: viewMethod === i18n.tr("Icons")
493 }
494
495 FolderListView {
496 id: folderListView
497
498 clip: true
499
500 folderListModel: pageModel
501 anchors {
502 top: parent.top
503 bottom: parent.bottom
504 left: sidebar.right
505 right: parent.right
506 }
507 smallMode: !sidebar.expanded
508 visible: viewMethod === i18n.tr("List")
509 }
510
511 Item {
512 id: contents
513
514 anchors {
515 top: parent.top
516 bottom: parent.bottom
517 left: sidebar.right
518 right: parent.right
519 }
520
521
522 Label {
523 text: i18n.tr("No files")
524 fontSize: "large"
525 opacity: 0.5
526 anchors.centerIn: parent
527 visible: folderListView.count == 0 && !pageModel.awaitingResults
528 }
529
530 ActivityIndicator {
531 running: pageModel.awaitingResults
532 width: units.gu(8)
533 height: units.gu(8)
534 anchors.centerIn: parent
535 }
536 }
537
538 Component {218 Component {
539 id: confirmSingleDeleteDialog219 id: confirmSingleDeleteDialog
540 ConfirmDialog {220 ConfirmDialog {
@@ -548,7 +228,53 @@
548228
549 fileOperationDialog.startOperation("Deleting files")229 fileOperationDialog.startOperation("Deleting files")
550 console.log("Doing delete")230 console.log("Doing delete")
551 pageModel.rm(filePath)231 folderModel.folderModel.rm(filePath)
232 }
233 }
234 }
235
236 Component {
237 id: tabsPopover
238 ActionSelectionPopover {
239 objectName: "tabsPopover"
240
241 property var tab
242
243 grabDismissAreaEvents: true
244
245 actions: ActionList {
246 Action {
247 text: i18n.tr("Open in a new tab")
248 onTriggered: {
249 openTab(folderListPage.folder)
250 }
251 }
252
253 // The current tab can be closed as long as there is at least one tab remaining
254 Action {
255 text: i18n.tr("Close this tab")
256 onTriggered: {
257 closeTab(tab.index)
258 }
259 enabled: tabs.count > 1
260 }
261 }
262 }
263 }
264
265 Component {
266 id: createFolderDialog
267 ConfirmDialogWithInput {
268 title: i18n.tr("Create folder")
269 text: i18n.tr("Enter name for new folder")
270
271 onAccepted: {
272 console.log("Create folder accepted", inputText)
273 if (inputText !== '') {
274 folderModel.folderModel.mkdir(inputText)
275 } else {
276 console.log("Empty directory name, ignored")
277 }
552 }278 }
553 }279 }
554 }280 }
@@ -571,7 +297,7 @@
571 console.log("Rename accepted", inputText)297 console.log("Rename accepted", inputText)
572 if (inputText !== '') {298 if (inputText !== '') {
573 console.log("Rename commensed, modelRow/inputText", modelRow, inputText)299 console.log("Rename commensed, modelRow/inputText", modelRow, inputText)
574 if (pageModel.rename(modelRow, inputText) === false) {300 if (folderModel.folderModel.rename(modelRow, inputText) === false) {
575 PopupUtils.open(Qt.resolvedUrl("NotifyDialog.qml"), delegate,301 PopupUtils.open(Qt.resolvedUrl("NotifyDialog.qml"), delegate,
576 {302 {
577 title: i18n.tr("Could not rename"),303 title: i18n.tr("Could not rename"),
@@ -586,84 +312,9 @@
586 }312 }
587 }313 }
588314
589 Component {
590 id: actionSelectionPopoverComponent
591
592 ActionSelectionPopover {
593 id: actionSelectionPopover
594 objectName: "fileActionsPopover"
595
596 grabDismissAreaEvents: true
597
598 property var model
599 actions: ActionList {
600 Action {
601 text: i18n.tr("Cut")
602 // TODO: temporary
603 iconSource: "/usr/share/icons/Humanity/actions/48/edit-cut.svg"
604 onTriggered: {
605 console.log("Cut on row called for", actionSelectionPopover.model.fileName, actionSelectionPopover.model.index)
606 pageModel.cutIndex(actionSelectionPopover.model.index)
607 console.log("CliboardUrlsCounter after copy", pageModel.clipboardUrlsCounter)
608 }
609 }
610
611 Action {
612 text: i18n.tr("Copy")
613 // TODO: temporary.
614 iconSource: "/usr/share/icons/Humanity/actions/48/edit-copy.svg"
615
616 onTriggered: {
617 console.log("Copy on row called for", actionSelectionPopover.model.fileName, actionSelectionPopover.model.index)
618 pageModel.copyIndex(actionSelectionPopover.model.index)
619 console.log("CliboardUrlsCounter after copy", pageModel.clipboardUrlsCounter)
620 }
621 }
622
623 Action {
624 text: i18n.tr("Delete")
625 // TODO: temporary
626 iconSource: "/usr/share/icons/Humanity/actions/48/edit-delete.svg"
627 onTriggered: {
628 print(text)
629 PopupUtils.open(confirmSingleDeleteDialog, actionSelectionPopover.caller,
630 { "filePath" : actionSelectionPopover.model.filePath,
631 "fileName" : actionSelectionPopover.model.fileName }
632 )
633 }
634 }
635
636 Action {
637 text: i18n.tr("Rename")
638 // TODO: temporary
639 iconSource: "/usr/share/icons/Humanity/actions/48/rotate.svg"
640 onTriggered: {
641 print(text)
642 PopupUtils.open(confirmRenameDialog, actionSelectionPopover.caller,
643 { "modelRow" : actionSelectionPopover.model.index,
644 "inputText" : actionSelectionPopover.model.fileName
645 })
646 }
647 }
648
649 Action {
650 text: i18n.tr("Properties")
651 onTriggered: {
652 print(text)
653 PopupUtils.open(Qt.resolvedUrl("FileDetailsPopover.qml"),
654 actionSelectionPopover.caller,
655 { "model": actionSelectionPopover.model
656 }
657 )
658 }
659 }
660 }
661 }
662 }
663
664 // Errors from model315 // Errors from model
665 Connections {316 Connections {
666 target: pageModel317 target: folderModel.folderModel
667 onError: {318 onError: {
668 console.log("FolderListModel Error Title/Description", errorTitle, errorMessage)319 console.log("FolderListModel Error Title/Description", errorTitle, errorMessage)
669 error(i18n.tr("File operation error"), errorTitle + ": " + errorMessage)320 error(i18n.tr("File operation error"), errorTitle + ": " + errorMessage)
@@ -674,19 +325,19 @@
674 id: fileOperationDialog325 id: fileOperationDialog
675326
676 page: folderListPage327 page: folderListPage
677 model: pageModel328 model: folderModel.folderModel
678 }329 }
679330
680 function itemClicked(model) {331 function itemClicked(model) {
681 if (model.isDir) {332 if (model.isDir) {
682 if (model.isReadable && model.isExecutable) {333 if (model.isReadable && model.isExecutable) {
683 console.log("Changing to dir", model.filePath)334 console.log("Changing to dir", model.filePath)
684 goTo(model.filePath)335 folderModel.goTo(model.filePath)
685 } else {336 } else {
686 PopupUtils.open(Qt.resolvedUrl("NotifyDialog.qml"), delegate,337 PopupUtils.open(Qt.resolvedUrl("NotifyDialog.qml"), delegate,
687 {338 {
688 title: i18n.tr("Folder not accessible"),339 title: i18n.tr("Folder not accessible"),
689 // TRANSLATORS: this refers to a folder name340 // TRANSLATORS: this refers to a folder name
690 text: i18n.tr("Can not access %1").arg(model.fileName)341 text: i18n.tr("Can not access %1").arg(model.fileName)
691342
692 })343 })
@@ -694,18 +345,12 @@
694 } else {345 } else {
695 console.log("Non dir clicked")346 console.log("Non dir clicked")
696 openFile(model.fileName)347 openFile(model.fileName)
697// PopupUtils.open(Qt.resolvedUrl("FileActionDialog.qml"), root,
698// {
699// fileName: model.fileName,
700// filePath: model.filePath,
701// folderListModel: root.folderListModel
702// })
703 }348 }
704 }349 }
705350
706 function itemLongPress(delegate, model) {351 function itemLongPress(delegate, model) {
707 console.log("FolderListDelegate onPressAndHold")352 console.log("FolderListDelegate onPressAndHold")
708 PopupUtils.open(actionSelectionPopoverComponent, delegate,353 PopupUtils.open(Qt.resolvedUrl("FileActionsPopover.qml"), delegate,
709 {354 {
710 model: model355 model: model
711 })356 })
712357
=== modified file 'src/app/qml/ui/GoToDialog.qml'
--- src/app/qml/ui/GoToDialog.qml 2014-02-19 00:00:15 +0000
+++ src/app/qml/ui/GoToDialog.qml 2014-06-16 21:32:33 +0000
@@ -37,7 +37,7 @@
3737
38 inputMethodHints: Qt.ImhNoAutoUppercase38 inputMethodHints: Qt.ImhNoAutoUppercase
3939
40 property bool valid: pathExists(text)40 property bool valid: folderModel.pathExists(text)
4141
42 text: fileView.path42 text: fileView.path
4343
@@ -55,7 +55,7 @@
5555
56 onClicked: {56 onClicked: {
57 print("User switched to:", locationField.text)57 print("User switched to:", locationField.text)
58 goTo(locationField.text)58 folderModel.goTo(locationField.text)
59 PopupUtils.close(root)59 PopupUtils.close(root)
60 }60 }
61 }61 }
6262
=== modified file 'src/app/qml/ui/PlacesPopover.qml'
--- src/app/qml/ui/PlacesPopover.qml 2014-06-10 02:34:07 +0000
+++ src/app/qml/ui/PlacesPopover.qml 2014-06-16 21:32:33 +0000
@@ -24,40 +24,6 @@
24 id: root24 id: root
25 objectName: "placesPopover"25 objectName: "placesPopover"
2626
27 ListModel {
28 id: places
29
30 ListElement {
31 objectName: 'placeHome'
32 path: "~"
33 }
34
35 ListElement {
36 path: "~/Documents"
37 }
38
39 ListElement {
40 path: "~/Downloads"
41 }
42
43 ListElement {
44 path: "~/Music"
45 }
46
47 ListElement {
48 path: "~/Pictures"
49 }
50
51 ListElement {
52 path: "~/Videos"
53 }
54
55 ListElement {
56 objectName: "placeRoot"
57 path: "/"
58 }
59 }
60
61 Column {27 Column {
62 anchors {28 anchors {
63 left: parent.left29 left: parent.left
@@ -79,7 +45,7 @@
7945
80 inputMethodHints: Qt.ImhNoAutoUppercase46 inputMethodHints: Qt.ImhNoAutoUppercase
8147
82 property bool valid: pathExists(text)48 property bool valid: folderModel.pathExists(text)
8349
84 text: fileView.path50 text: fileView.path
8551
@@ -103,7 +69,7 @@
10369
104 onClicked: {70 onClicked: {
105 print("User switched to:", locationField.text)71 print("User switched to:", locationField.text)
106 goTo(locationField.text)72 folderModel.goTo(locationField.text)
107 PopupUtils.close(root)73 PopupUtils.close(root)
108 }74 }
109 }75 }
@@ -113,7 +79,7 @@
113 id: placesList79 id: placesList
114 objectName: "placesList"80 objectName: "placesList"
11581
116 model: places82 model: folderModel.places
11783
118 delegate: Standard {84 delegate: Standard {
119 objectName: model.objectName85 objectName: model.objectName
@@ -123,18 +89,18 @@
123 anchors.left: parent.left89 anchors.left: parent.left
124 anchors.leftMargin: units.gu(8)90 anchors.leftMargin: units.gu(8)
125 anchors.verticalCenter: parent.verticalCenter91 anchors.verticalCenter: parent.verticalCenter
126 text: folderName(path)92 text: folderModel.folderName(path)
127 color: selected ? UbuntuColors.orange : Theme.palette.normal.overlayText93 color: selected ? UbuntuColors.orange : Theme.palette.normal.overlayText
128 }94 }
12995
130 iconSource: model.icon || fileIcon(model.path, true)96 iconSource: model.icon || folderModel.fileIcon(model.path, true)
13197
132 onClicked: {98 onClicked: {
133 PopupUtils.close(root)99 PopupUtils.close(root)
134 goTo(model.path)100 goTo(model.path)
135 }101 }
136102
137 selected: folder === path103 selected: folderModel.folder === path
138 iconFrame: false104 iconFrame: false
139 showDivider: index < (placesList.count - 1)105 showDivider: index < (placesList.count - 1)
140 }106 }

Subscribers

People subscribed via source and target branches