Merge lp:~ajalkane/ubuntu-filemanager-app/toolbar-to-header-modifications into lp:ubuntu-filemanager-app

Proposed by Arto Jalkanen
Status: Superseded
Proposed branch: lp:~ajalkane/ubuntu-filemanager-app/toolbar-to-header-modifications
Merge into: lp:ubuntu-filemanager-app
Diff against target: 2036 lines (+1150/-499)
13 files modified
po/com.ubuntu.filemanager.pot (+86/-91)
src/app/qml/components/PathBar.qml (+0/-185)
src/app/qml/components/PathHistoryRow.qml (+250/-0)
src/app/qml/filemanager.qml (+14/-2)
src/app/qml/ui/FolderListPage.qml (+172/-207)
src/app/qml/ui/PlacesPage.qml (+117/-0)
src/app/qml/ui/SettingsSheet.qml (+1/-1)
src/app/qml/upstream/FakeHeader.qml (+37/-0)
src/app/qml/upstream/PageWithBottomEdge.qml (+450/-0)
src/plugin/folderlistmodel/clipboard.cpp (+13/-12)
src/plugin/folderlistmodel/clipboard.h (+1/-1)
src/plugin/folderlistmodel/dirmodel.cpp (+4/-0)
src/plugin/folderlistmodel/dirmodel.h (+5/-0)
To merge this branch: bzr merge lp:~ajalkane/ubuntu-filemanager-app/toolbar-to-header-modifications
Reviewer Review Type Date Requested Status
Ubuntu File Manager Developers Pending
Review via email: mp+239152@code.launchpad.net

This proposal has been superseded by a proposal from 2014-10-21.

Commit message

Some small and larger changes:

 - Places added as bottom edge pullover
 - Removed it from menu
 - Changed path history separator from ">" into "/" to avoid confusion
 - Refactored path history into separate component
 - Single click on current folder goes up (was double click)
 - Added Paste to top menu if there's something in clipboard
 - Added clear clipboard if something in clipboard
 - Some small code changes

Note: the places bottom edge pullover is buggy, theme is wrong. Will need fixing yet.

Description of the change

Some small and larger changes:

 - Places added as bottom edge pullover
 - Removed it from menu
 - Changed path history separator from ">" into "/" to avoid confusion
 - Refactored path history into separate component
 - Single click on current folder goes up (was double click)
 - Added Paste to top menu if there's something in clipboard
 - Added clear clipboard if something in clipboard
 - Some small code changes

Note: the places bottom edge pullover is buggy, theme is wrong. Will need fixing yet.

To post a comment you must log in.
322. By Arto Jalkanen

Reposition path to where we are.

323. By Arto Jalkanen

"Good enough" colors for theme.

324. By Arto Jalkanen

"Good enough" colors and merged from trunk

325. By Arto Jalkanen

File selector / Unlock full access buttons fixed to allow room for bottom edge page. Removed Unlock full access from menu. Some fixes.

326. By Arto Jalkanen

Merged from trunk. Reordered top header actions so that the most useful ones are first.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'po/com.ubuntu.filemanager.pot'
2--- po/com.ubuntu.filemanager.pot 2014-10-06 12:27:18 +0000
3+++ po/com.ubuntu.filemanager.pot 2014-10-21 21:27:55 +0000
4@@ -8,7 +8,7 @@
5 msgstr ""
6 "Project-Id-Version: \n"
7 "Report-Msgid-Bugs-To: \n"
8-"POT-Creation-Date: 2014-09-29 15:28+0200\n"
9+"POT-Creation-Date: 2014-10-21 17:19-0400\n"
10 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
11 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12 "Language-Team: LANGUAGE <LL@li.org>\n"
13@@ -30,25 +30,31 @@
14 msgid "%1 (%2 files)"
15 msgstr ""
16
17+#: ../src/app/qml/components/PathHistoryRow.qml:108
18+#: ../src/app/qml/ui/FolderListPage.qml:634
19+msgid "Device"
20+msgstr ""
21+
22 #: ../src/app/qml/components/PlacesSidebar.qml:54
23-#: ../src/app/qml/ui/FolderListPage.qml:306
24+#: ../src/app/qml/ui/PlacesPage.qml:28
25 msgid "Places"
26 msgstr ""
27
28-#: ../src/app/qml/filemanager.qml:89 ../src/app/qml/ui/SettingsSheet.qml:31
29+#: ../src/app/qml/filemanager.qml:90 ../src/app/qml/ui/FolderListPage.qml:79
30+#: ../src/app/qml/ui/SettingsSheet.qml:31
31 msgid "Settings"
32 msgstr ""
33
34-#: ../src/app/qml/filemanager.qml:90
35+#: ../src/app/qml/filemanager.qml:91
36 msgid "Change app settings"
37 msgstr ""
38
39-#: ../src/app/qml/filemanager.qml:252 ../src/app/qml/ui/FolderListPage.qml:432
40+#: ../src/app/qml/filemanager.qml:264 ../src/app/qml/ui/FolderListPage.qml:365
41 #: ../src/app/qml/ui/ViewPopover.qml:70
42 msgid "Icons"
43 msgstr ""
44
45-#: ../src/app/qml/filemanager.qml:252 ../src/app/qml/ui/FolderListPage.qml:449
46+#: ../src/app/qml/filemanager.qml:264 ../src/app/qml/ui/FolderListPage.qml:382
47 #: ../src/app/qml/ui/ViewPopover.qml:71
48 msgid "List"
49 msgstr ""
50@@ -77,7 +83,7 @@
51 #: ../src/app/qml/ui/ConfirmDialogWithInput.qml:57
52 #: ../src/app/qml/ui/FileActionDialog.qml:45
53 #: ../src/app/qml/ui/FileOperationProgressDialog.qml:44
54-#: ../src/app/qml/ui/FolderListPage.qml:386
55+#: ../src/app/qml/ui/FolderListPage.qml:319
56 #: ../src/app/qml/ui/GoToDialog.qml:66
57 msgid "Cancel"
58 msgstr ""
59@@ -139,168 +145,155 @@
60 msgid "File operation"
61 msgstr ""
62
63-#: ../src/app/qml/ui/FolderListPage.qml:94
64+#: ../src/app/qml/ui/FolderListPage.qml:49
65+#, qt-format
66+msgid "Paste %1 File"
67+msgid_plural "Paste %1 Files"
68+msgstr[0] ""
69+msgstr[1] ""
70+
71+#: ../src/app/qml/ui/FolderListPage.qml:53
72+msgid "Paste files"
73+msgstr ""
74+
75+#: ../src/app/qml/ui/FolderListPage.qml:60
76+msgid "Clear clipboard"
77+msgstr ""
78+
79+#: ../src/app/qml/ui/FolderListPage.qml:70
80+#: ../src/app/qml/ui/FolderListPage.qml:101
81+#: ../src/app/qml/ui/FolderListPage.qml:525
82+msgid "Properties"
83+msgstr ""
84+
85+#: ../src/app/qml/ui/FolderListPage.qml:86
86+msgid "Go To"
87+msgstr ""
88+
89+#: ../src/app/qml/ui/FolderListPage.qml:92
90+msgid "New Folder"
91+msgstr ""
92+
93+#: ../src/app/qml/ui/FolderListPage.qml:108
94+#: ../src/app/qml/ui/FolderListPage.qml:327
95+msgid "Unlock full access"
96+msgstr ""
97+
98+#: ../src/app/qml/ui/FolderListPage.qml:123
99+#: ../src/app/qml/ui/FolderListPage.qml:341
100+msgid "Authentication failed"
101+msgstr ""
102+
103+#: ../src/app/qml/ui/FolderListPage.qml:195
104 #, qt-format
105 msgid "%1 file"
106 msgid_plural "%1 files"
107 msgstr[0] ""
108 msgstr[1] ""
109
110-#: ../src/app/qml/ui/FolderListPage.qml:119
111+#: ../src/app/qml/ui/FolderListPage.qml:220
112 msgid "Open in a new tab"
113 msgstr ""
114
115-#: ../src/app/qml/ui/FolderListPage.qml:127
116+#: ../src/app/qml/ui/FolderListPage.qml:228
117 msgid "Close this tab"
118 msgstr ""
119
120-#: ../src/app/qml/ui/FolderListPage.qml:147
121-msgid "Create New Folder"
122-msgstr ""
123-
124-#: ../src/app/qml/ui/FolderListPage.qml:167
125-msgid "Paste"
126-msgstr ""
127-
128-#: ../src/app/qml/ui/FolderListPage.qml:168
129-#, qt-format
130-msgid "Paste %1 File"
131-msgid_plural "Paste %1 Files"
132-msgstr[0] ""
133-msgstr[1] ""
134-
135-#: ../src/app/qml/ui/FolderListPage.qml:171
136-msgid "Paste files"
137-msgstr ""
138-
139-#: ../src/app/qml/ui/FolderListPage.qml:183
140-msgid "Open in Terminal"
141-msgstr ""
142-
143-#: ../src/app/qml/ui/FolderListPage.qml:195
144-#: ../src/app/qml/ui/FolderListPage.qml:591
145-msgid "Properties"
146-msgstr ""
147-
148-#: ../src/app/qml/ui/FolderListPage.qml:212
149+#: ../src/app/qml/ui/FolderListPage.qml:241
150 msgid "Create folder"
151 msgstr ""
152
153-#: ../src/app/qml/ui/FolderListPage.qml:213
154+#: ../src/app/qml/ui/FolderListPage.qml:242
155 msgid "Enter name for new folder"
156 msgstr ""
157
158-#: ../src/app/qml/ui/FolderListPage.qml:229
159+#: ../src/app/qml/ui/FolderListPage.qml:258
160 msgid "Create file"
161 msgstr ""
162
163-#: ../src/app/qml/ui/FolderListPage.qml:230
164+#: ../src/app/qml/ui/FolderListPage.qml:259
165 msgid "Enter name for new file"
166 msgstr ""
167
168-#: ../src/app/qml/ui/FolderListPage.qml:252
169-msgid "Up"
170-msgstr ""
171-
172-#: ../src/app/qml/ui/FolderListPage.qml:281
173-msgid "Actions"
174-msgstr ""
175-
176-#: ../src/app/qml/ui/FolderListPage.qml:291
177-msgid "View"
178-msgstr ""
179-
180-#: ../src/app/qml/ui/FolderListPage.qml:371
181+#: ../src/app/qml/ui/FolderListPage.qml:304
182 msgid "Select"
183 msgstr ""
184
185-#: ../src/app/qml/ui/FolderListPage.qml:394
186-msgid "Unlock full access"
187-msgstr ""
188-
189-#: ../src/app/qml/ui/FolderListPage.qml:408
190-msgid "Authentication failed"
191-msgstr ""
192-
193-#: ../src/app/qml/ui/FolderListPage.qml:464
194+#: ../src/app/qml/ui/FolderListPage.qml:397
195 msgid "No files"
196 msgstr ""
197
198-#: ../src/app/qml/ui/FolderListPage.qml:484
199-#: ../src/app/qml/ui/FolderListPage.qml:565
200+#: ../src/app/qml/ui/FolderListPage.qml:417
201+#: ../src/app/qml/ui/FolderListPage.qml:499
202 msgid "Delete"
203 msgstr ""
204
205-#: ../src/app/qml/ui/FolderListPage.qml:485
206+#: ../src/app/qml/ui/FolderListPage.qml:418
207 #, qt-format
208 msgid "Are you sure you want to permanently delete '%1'?"
209 msgstr ""
210
211-#: ../src/app/qml/ui/FolderListPage.qml:508
212-#: ../src/app/qml/ui/FolderListPage.qml:578
213+#: ../src/app/qml/ui/FolderListPage.qml:441
214+#: ../src/app/qml/ui/FolderListPage.qml:512
215 msgid "Rename"
216 msgstr ""
217
218-#: ../src/app/qml/ui/FolderListPage.qml:509
219+#: ../src/app/qml/ui/FolderListPage.qml:442
220 msgid "Enter a new name"
221 msgstr ""
222
223-#: ../src/app/qml/ui/FolderListPage.qml:518
224+#: ../src/app/qml/ui/FolderListPage.qml:451
225 msgid "Could not rename"
226 msgstr ""
227
228-#: ../src/app/qml/ui/FolderListPage.qml:519
229+#: ../src/app/qml/ui/FolderListPage.qml:452
230 msgid "Insufficient permissions or name already exists?"
231 msgstr ""
232
233-#: ../src/app/qml/ui/FolderListPage.qml:542
234+#: ../src/app/qml/ui/FolderListPage.qml:476
235 msgid "Cut"
236 msgstr ""
237
238-#: ../src/app/qml/ui/FolderListPage.qml:553
239+#: ../src/app/qml/ui/FolderListPage.qml:487
240 msgid "Copy"
241 msgstr ""
242
243-#: ../src/app/qml/ui/FolderListPage.qml:610
244-#: ../src/app/qml/ui/FolderListPage.qml:733
245+#: ../src/app/qml/ui/FolderListPage.qml:545
246+#: ../src/app/qml/ui/FolderListPage.qml:696
247 msgid "File operation error"
248 msgstr ""
249
250-#: ../src/app/qml/ui/FolderListPage.qml:659
251+#: ../src/app/qml/ui/FolderListPage.qml:605
252 msgid "~/Desktop"
253 msgstr ""
254
255-#: ../src/app/qml/ui/FolderListPage.qml:669
256+#: ../src/app/qml/ui/FolderListPage.qml:615
257 msgid "~/Public"
258 msgstr ""
259
260-#: ../src/app/qml/ui/FolderListPage.qml:671
261+#: ../src/app/qml/ui/FolderListPage.qml:617
262 msgid "~/Programs"
263 msgstr ""
264
265-#: ../src/app/qml/ui/FolderListPage.qml:673
266+#: ../src/app/qml/ui/FolderListPage.qml:619
267 msgid "~/Templates"
268 msgstr ""
269
270-#: ../src/app/qml/ui/FolderListPage.qml:686
271+#: ../src/app/qml/ui/FolderListPage.qml:632
272 msgid "Home"
273 msgstr ""
274
275-#: ../src/app/qml/ui/FolderListPage.qml:688
276-msgid "Device"
277-msgstr ""
278-
279-#: ../src/app/qml/ui/FolderListPage.qml:733
280+#: ../src/app/qml/ui/FolderListPage.qml:696
281 #, qt-format
282 msgid "Unable to open '%1'"
283 msgstr ""
284
285-#: ../src/app/qml/ui/FolderListPage.qml:745
286+#: ../src/app/qml/ui/FolderListPage.qml:708
287 msgid "Folder not accessible"
288 msgstr ""
289
290 #. TRANSLATORS: this refers to a folder name
291-#: ../src/app/qml/ui/FolderListPage.qml:747
292+#: ../src/app/qml/ui/FolderListPage.qml:710
293 #, qt-format
294 msgid "Can not access %1"
295 msgstr ""
296@@ -313,11 +306,13 @@
297 msgid "Enter a location to go to:"
298 msgstr ""
299
300-#: ../src/app/qml/ui/GoToDialog.qml:44 ../src/app/qml/ui/PlacesPopover.qml:53
301+#: ../src/app/qml/ui/GoToDialog.qml:44 ../src/app/qml/ui/PlacesPage.qml:59
302+#: ../src/app/qml/ui/PlacesPopover.qml:53
303 msgid "Location..."
304 msgstr ""
305
306-#: ../src/app/qml/ui/GoToDialog.qml:53 ../src/app/qml/ui/PlacesPopover.qml:68
307+#: ../src/app/qml/ui/GoToDialog.qml:53 ../src/app/qml/ui/PlacesPage.qml:74
308+#: ../src/app/qml/ui/PlacesPopover.qml:68
309 msgid "Go"
310 msgstr ""
311
312@@ -377,7 +372,7 @@
313 msgid "Error creating new folder"
314 msgstr ""
315
316-#: ../src/plugin/folderlistmodel/dirmodel.cpp:1264
317+#: ../src/plugin/folderlistmodel/dirmodel.cpp:1268
318 msgid "items"
319 msgstr ""
320
321
322=== removed file 'src/app/qml/components/PathBar.qml'
323--- src/app/qml/components/PathBar.qml 2014-09-20 10:49:51 +0000
324+++ src/app/qml/components/PathBar.qml 1970-01-01 00:00:00 +0000
325@@ -1,185 +0,0 @@
326-import QtQuick 2.3
327-import Ubuntu.Components 1.1
328-import Ubuntu.Components.Popups 1.0
329-import com.ubuntu.PlacesModel 0.1
330-
331-Rectangle {
332- id: root
333- objectName: "pathbar"
334- radius: units.gu(0.5)
335- border.color: UbuntuColors.warmGrey
336-
337- antialiasing: true
338- anchors.verticalCenter: parent.verticalCenter
339-
340- implicitWidth: goToButton.width + row.width
341-
342- function rootDisplayName(path) {
343- // Returns the human-readable name for the root of a filesystem location
344- // for display purposes
345- // Supported roots are /home/$USER and /
346-
347- var pathDisplayName
348-
349- if ((path.substring(0, userplaces.locationHome.length) === userplaces.locationHome) &&
350- ((path.substring(userplaces.locationHome.length, userplaces.locationHome.length + 1) === '/') ||
351- (path.length === userplaces.locationHome.length))) {
352- // Replace /home/$USER by its human readable name (generally "Home")
353- pathDisplayName = path.replace(userplaces.locationHome, folderDisplayName(userplaces.locationHome))
354- } else {
355- // Replace any other path than /home/$USER with the human readable of the root
356- // file system (generally "Device")
357- pathDisplayName = folderDisplayName("/").concat(path.replace(/^\/$/, ""))
358- }
359-
360- return pathDisplayName
361- }
362-
363- function rootAbsName(path) {
364- // Returns the absolute path name given a human-readable path
365- // Does the opposite of the rootDisplayName function
366-
367- var pathAbsName
368- var rootAbsName
369- var pathComponents = path.split("/")
370-
371- // Get the absolute path of the root
372- if (pathComponents[0] === folderDisplayName(userplaces.locationHome)) {
373- rootAbsName = userplaces.locationHome
374- } else {
375- rootAbsName = "/"
376- }
377-
378- // Drop the human-readable part of the path components
379- pathComponents.shift()
380- // Join the root absolute path name with the rest of the path components,
381- // avoiding "/" duplicates
382- pathAbsName = rootAbsName.concat("/", pathComponents.join("/")).replace(/^\/\//, "/")
383-
384- return pathAbsName
385- }
386-
387- Behavior on width {
388- UbuntuNumberAnimation {}
389- }
390-
391- Rectangle {
392- id: goToButton
393- objectName: "goToButton"
394- anchors {
395- top: parent.top
396- bottom: parent.bottom
397- right: parent.right
398- }
399-
400- MouseArea {
401- id: mouseArea2
402- anchors.fill: parent
403- hoverEnabled: true
404-
405- onClicked: {
406- PopupUtils.open(Qt.resolvedUrl("../ui/GoToDialog.qml"), goToButton)
407- }
408- }
409-
410- color: mouseArea2.containsMouse ? Qt.rgba(0.5,0.5,0.5,0.2) : Qt.rgba(0.5,0.5,0.5,0)
411-
412- Behavior on color {
413- ColorAnimation { duration: 200 }
414- }
415-
416- width: parent.height
417-
418- Image {
419- id: editImage
420- anchors.centerIn: parent
421-
422- source: getIcon("edit")
423- height: units.gu(2)
424- width: height
425- }
426-
427- Rectangle {
428- anchors {
429- left: parent.left
430- top: parent.top
431- bottom: parent.bottom
432- rightMargin: units.gu(1)
433- }
434-
435- width: 1
436- color: UbuntuColors.warmGrey
437- }
438- }
439-
440- Flickable {
441- anchors {
442- left: parent.left
443- right: goToButton.left
444- top: parent.top
445- bottom: parent.bottom
446- }
447-
448- clip: true
449-
450- flickableDirection: Flickable.HorizontalFlick
451- contentWidth: row.width
452- contentHeight: parent.height
453-
454- Row {
455- id: row
456- height: root.height
457- width: implicitWidth - 1
458-
459- Repeater {
460- id: repeater
461- // This refers to a parent FolderListPage.folder
462- model: rootDisplayName(folder).split("/")
463- delegate: Rectangle {
464- MouseArea {
465- id: mouseArea
466- anchors.fill: parent
467- hoverEnabled: true
468-
469- onClicked: {
470- var upCount = index
471- var path = modelData
472-
473- while (upCount > 0) {
474- path = repeater.model[--upCount] + "/" + path
475- }
476-
477- goTo(rootAbsName(path))
478- }
479- }
480-
481- color: mouseArea.containsMouse ? Qt.rgba(0.5,0.5,0.5,0.2) : Qt.rgba(0.5,0.5,0.5,0)
482-
483- Behavior on color {
484- ColorAnimation { duration: 200 }
485- }
486-
487- Label {
488- id: label
489- anchors.centerIn: parent
490- text: modelData === "" ? "/" : modelData
491- color: UbuntuColors.coolGrey
492- }
493-
494- height: row.height
495- width: label.width + units.gu(4)
496-
497- Rectangle {
498- anchors {
499- right: parent.right
500- top: parent.top
501- bottom: parent.bottom
502- }
503- width: 1
504- color: UbuntuColors.warmGrey
505- }
506- }
507- }
508- }
509- }
510-}
511
512=== added file 'src/app/qml/components/PathHistoryRow.qml'
513--- src/app/qml/components/PathHistoryRow.qml 1970-01-01 00:00:00 +0000
514+++ src/app/qml/components/PathHistoryRow.qml 2014-10-21 21:27:55 +0000
515@@ -0,0 +1,250 @@
516+/*
517+ * Copyright (C) 2013 Canonical Ltd
518+ *
519+ * This program is free software: you can redistribute it and/or modify
520+ * it under the terms of the GNU General Public License version 3 as
521+ * published by the Free Software Foundation.
522+ *
523+ * This program is distributed in the hope that it will be useful,
524+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
525+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
526+ * GNU General Public License for more details.
527+ *
528+ * You should have received a copy of the GNU General Public License
529+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
530+ *
531+ * Authored by: Akiva
532+ */
533+import QtQuick 2.3
534+import Ubuntu.Components 1.1
535+import Ubuntu.Components.ListItems 1.0
536+
537+/* Full path of your current folder and recent history, that you can jump to by clicking its members */
538+Flickable {
539+ id: flickable
540+
541+ /* Convenience properties ; used a large amount of times to warrant a variable */
542+ property int iconWidth: units.gu(2.5)
543+ property string textSize: "large"
544+ property string separatorText: " /"
545+ /* contentWidth equals this to allow it to hide Device and Home */
546+ contentWidth: {
547+ repeater.model > 0 ?
548+ memoryRepeater.model > 0 ?
549+ width + row.width - memoryRepeater.itemAt(memoryRepeater.model-1).width + memoryRow.width
550+ : width + row.width - repeater.itemAt(repeater.model-1).width
551+ : width + memoryRow.width - memoryRepeater.itemAt(memoryRepeater.model-1).width
552+ }
553+ height: units.gu(7)
554+ anchors {
555+ left: back.right
556+ right: parent.right
557+ rightMargin: units.gu(1)
558+ }
559+ clip: true
560+ boundsBehavior: Flickable.StopAtBounds
561+
562+ Behavior on contentX { SmoothedAnimation { duration: 555 }}
563+
564+ /* This prevents the contentWidth from causing sudden flicks */
565+ Behavior on contentWidth { SmoothedAnimation { duration: 500 }}
566+
567+ // onContentWidthChanged: console.log(contentWidth)
568+ /* Flickable Contents */
569+ Row {
570+ id: row
571+ spacing: 0 // Safety; having any spacing will throw off the contentX calculations.
572+
573+ /* Adjust contentX according to the current folder */
574+ onWidthChanged: {
575+ console.log("---------------------------------------------")
576+ console.log(width)
577+ /* Set contentX to Home */
578+ if (folder === userplaces.locationHome) {
579+ flickable.contentX = repeater.itemAt(1).x
580+ // console.log("folder === userplaces.locationHome")
581+ }
582+ /* Set contentX to 0 */
583+ else if (repeater.model < 2) {
584+ flickable.contentX = 0
585+ // console.log("repeater.model < 2")
586+ }
587+ /* For children of Home */
588+ else if (pathRaw(folder,1) === userplaces.locationHome) {
589+ /* Set contentX to First Child*/
590+ flickable.contentX = repeater.itemAt(2).x
591+ // console.log("pathRaw(folder,1) === userplaces.locationHome")
592+
593+ /* Set contentX to End */
594+ if (flickable.width < width - repeater.itemAt(2).x - flickable.iconWidth) {
595+ flickable.contentX
596+ = repeater.itemAt(repeater.model-1).x
597+ + repeater.itemAt(repeater.model-1).width
598+ - flickable.width
599+ - flickable.iconWidth
600+ console.log("+ row.width > flickable.contentWidth")
601+ }
602+ }
603+ /* Set contentX to End */
604+ else if ( flickable.width < width - flickable.iconWidth) {
605+ flickable.contentX
606+ = repeater.itemAt(repeater.model-1).x
607+ + repeater.itemAt(repeater.model-1).width
608+ - flickable.width
609+ - flickable.iconWidth
610+ console.log("flickable.width < width")
611+ }
612+ }
613+
614+ /* Root Folder displayed as "Device" */
615+ Rectangle {
616+ id: device
617+ width: deviceLabel.contentWidth + flickable.iconWidth
618+ height: units.gu(7)
619+ color: "transparent"
620+
621+ Label {
622+ id: deviceLabel
623+ text: i18n.tr("Device")
624+ fontSize: flickable.textSize
625+ anchors.verticalCenter: parent.verticalCenter
626+ color: folder === "/" ? "white" : UbuntuColors.warmGrey
627+ clip: true
628+ /* Maximum Width = Flickable Width */
629+ width: if (contentWidth > flickable.width) { flickable.width }
630+ }
631+
632+ MouseArea {
633+ anchors.fill: parent
634+ onClicked: {
635+ goTo("/")
636+ }
637+ }
638+ }
639+
640+ /* Current Directory and its parents */
641+ Repeater {
642+ id: repeater
643+
644+ model: pathModel(folder)
645+ property int memoryModel: memoryModel ? memoryModel : pathModel(userplaces.locationHome)
646+ property string memoryPath: memoryPath ? memoryPath : userplaces.locationHome
647+
648+ /* Memory Management */
649+ onModelChanged: {
650+ /* Extend Memory */
651+ if (model > memoryModel && memoryPath === pathRaw(folder, memoryModel-1)) {
652+ memoryModel = model
653+ memoryPath = folder
654+ // console.log("/* Extend Memory */")
655+ // console.log("model > memoryModel && memoryPath === pathRaw(folder, memoryModel-1")
656+ }
657+ /* Reset Memory to Current */
658+ else if (folder !== pathRaw(memoryPath,model-1) && model > 0) {
659+ memoryModel = pathModel(folder)
660+ memoryPath = folder
661+ // console.log("/* Reset Memory to Current */")
662+ // console.log("folder !== pathRaw(memoryPath,model")
663+ }
664+ // console.log("Repeat Model = " + repeater.model)
665+ // console.log("Current Path = " + folder)
666+ // console.log("Memory Model = " + memoryModel)
667+ // console.log("Memory Path = " + memoryPath)
668+ }
669+
670+ delegate: Rectangle {
671+ visible: folder !== "/" // This is to avoid issues with naming the root folder, "Device"
672+ width: label.width + pathSeparator.width
673+ height: units.gu(7)
674+ color: "transparent"
675+
676+ Label {
677+ id: label
678+ text: pathText(folder,index)
679+ fontSize: flickable.textSize
680+ anchors.verticalCenter: parent.verticalCenter
681+ color: repeater.model === index + 1 ? "white" : UbuntuColors.warmGrey
682+ clip: true
683+
684+ /* Maximum Width = Flickable Width */
685+ width: if (contentWidth > flickable.width) { flickable.width } else { contentWidth }
686+ }
687+
688+ Label {
689+ id: pathSeparator
690+ text: separatorText
691+ fontSize: flickable.textSize
692+ width: flickable.iconWidth
693+ anchors.verticalCenter: parent.verticalCenter
694+ anchors.right: label.left
695+ color: "white"
696+ // clip: true
697+ }
698+
699+ MouseArea {
700+ anchors.fill: parent
701+ onClicked: {
702+ // When clicking on an already selected item, go up one level. Otherwise go to
703+ // the clicked item. This behaviour is to make it easy to go up in the folder
704+ // hierarchy now that the "back" button goes back in history and not up the directory
705+ // hierarchy
706+ if (repeater.model === index + 1) {
707+ goUp()
708+ } else {
709+ goTo(pathRaw(folder, index))
710+ }
711+ }
712+ }
713+ }
714+ }
715+ }
716+
717+ /* Memory of Previously visited folders */
718+ Row {
719+ id: memoryRow
720+ anchors.left: row.right // Not placed in the other row, to help avoid making contentX calculations more complicated.
721+
722+ /* Previously visited folders */
723+ Repeater {
724+ id: memoryRepeater
725+ model: repeater.memoryModel - repeater.model
726+
727+ delegate: Rectangle {
728+ width: memoryLabel.width + memoryPathSeparator.width
729+ height: units.gu(7)
730+ color: "transparent"
731+
732+ Label {
733+ id: memoryLabel
734+ text: repeater.model > 0 ? pathText(repeater.memoryPath,repeater.memoryModel-memoryRepeater.model+index)
735+ : pathText(repeater.memoryPath,index)
736+ fontSize: flickable.textSize
737+ anchors.verticalCenter: parent.verticalCenter
738+ color: UbuntuColors.warmGrey
739+ clip: true
740+
741+ /* Maximum Width = Flickable Width */
742+ width: if (contentWidth > flickable.width) { flickable.width } else { contentWidth }
743+ }
744+
745+ Label {
746+ id: memoryPathSeparator
747+ text: separatorText
748+ fontSize: flickable.textSize
749+ width: flickable.iconWidth
750+ anchors.verticalCenter: parent.verticalCenter
751+ anchors.right: memoryLabel.left
752+ color: "white"
753+ // clip: true
754+ }
755+
756+ MouseArea {
757+ anchors.fill: parent
758+ onClicked: {
759+ goTo(pathRaw(repeater.memoryPath, repeater.memoryModel-memoryRepeater.model+index))
760+ }
761+ }
762+ }
763+ }
764+ }
765+}
766
767=== modified file 'src/app/qml/filemanager.qml'
768--- src/app/qml/filemanager.qml 2014-10-10 22:03:01 +0000
769+++ src/app/qml/filemanager.qml 2014-10-21 21:27:55 +0000
770@@ -38,6 +38,7 @@
771 // objectName for functional testing purposes (autopilot-qt5)
772 objectName: "filemanager"
773 applicationName: "com.ubuntu.filemanager"
774+ useDeprecatedToolbar: false
775
776 width: units.gu(100)
777 height: units.gu(75)
778@@ -156,8 +157,6 @@
779 PageStack {
780 id: pageStack
781
782- anchors.bottomMargin: toolbar.tools.opened && toolbar.tools.locked ? -mainView.toolbar.triggerSize : 0
783-
784 Tabs {
785 id: tabs
786
787@@ -169,6 +168,19 @@
788 folder: userplaces.locationHome //modelData
789 }
790 }
791+ Tab {
792+ title: "page.title"
793+ page: Page {
794+ objectName: "settingsPage"
795+ }
796+ }
797+ Tab {
798+ title: "page.title"
799+ page: SettingsSheet {
800+ id: settingsPage
801+ }
802+ }
803+
804
805 // TODO: Temporarily disabled tabs support since this is broken in the SDK (lp:1295242)
806 // Repeater {
807
808=== modified file 'src/app/qml/ui/FolderListPage.qml'
809--- src/app/qml/ui/FolderListPage.qml 2014-10-06 12:27:18 +0000
810+++ src/app/qml/ui/FolderListPage.qml 2014-10-21 21:27:55 +0000
811@@ -22,10 +22,113 @@
812 import org.nemomobile.folderlistmodel 1.0
813 import com.ubuntu.PlacesModel 0.1
814 import "../components"
815+import "../upstream"
816
817-Page {
818+PageWithBottomEdge {
819 id: folderListPage
820- title: folderDisplayName(folder)
821+ title: basename(folder)
822+ bottomEdgeTitle: "Places"
823+ bottomEdgeEnabled: !sidebar.expanded
824+ bottomEdgePageSource: Qt.resolvedUrl("PlacesPage.qml")
825+
826+ head.contents: PathHistoryRow {}
827+
828+ /* Go to last folder visited */
829+ head.backAction: Action {
830+ id: back
831+ iconName: "back"
832+ onTriggered: {
833+ goBack()
834+ }
835+ }
836+
837+ head.actions: [
838+ Action {
839+ id: pasteButton
840+ iconName: "edit-paste"
841+ text: i18n.tr("Paste %1 File", "Paste %1 Files", pageModel.clipboardUrlsCounter).arg(pageModel.clipboardUrlsCounter)
842+ visible: pageModel.clipboardUrlsCounter > 0
843+ onTriggered: {
844+ console.log("Pasting to current folder items of count " + pageModel.clipboardUrlsCounter)
845+ fileOperationDialog.startOperation(i18n.tr("Paste files"))
846+ pageModel.paste()
847+ }
848+ },
849+ Action {
850+ id: clearClipboardButton
851+ iconName: "edit-clear"
852+ text: i18n.tr("Clear clipboard")
853+ visible: pageModel.clipboardUrlsCounter > 0
854+ onTriggered: {
855+ console.log("Clearing clipboard")
856+ pageModel.clearClipboard()
857+ }
858+ },
859+ Action {
860+ id: optionsButton
861+ iconName: "view-list-symbolic"
862+ text: i18n.tr("Properties")
863+ onTriggered: {
864+ PopupUtils.open(Qt.resolvedUrl("ViewPopover.qml"), parent)
865+ }
866+ },
867+ Action {
868+ id: settingsButton
869+ iconName: "settings"
870+ objectName: "settings"
871+ text: i18n.tr("Settings")
872+ visible: sidebar.expanded
873+ onTriggered: pageStack.push(settingsPage);
874+ },
875+ Action {
876+ id: gotoButton
877+ iconName: "find"
878+ text: i18n.tr("Go To")
879+ onTriggered: PopupUtils.open(Qt.resolvedUrl("GoToDialog.qml"), parent)
880+ },
881+ Action {
882+ id: createNewFolder
883+ iconName: "add"
884+ text: i18n.tr("New Folder")
885+ onTriggered: {
886+ print(text)
887+ PopupUtils.open(createFolderDialog, folderListPage)
888+ }
889+ },
890+ Action {
891+ id: viewProperties
892+ iconName: "info"
893+ text: i18n.tr("Properties")
894+ onTriggered: {
895+ print(text)
896+ PopupUtils.open(Qt.resolvedUrl("FileDetailsPopover.qml"), folderListPage,{ "model": pageModel})
897+ }
898+ },
899+ Action {
900+ text: i18n.tr("Unlock full access")
901+ //visible: pageModel.onlyMTPPaths
902+ iconName: "lock"
903+ onTriggered: {
904+ console.log("Full access clicked")
905+ var authDialog = PopupUtils.open(Qt.resolvedUrl("AuthenticationDialog.qml"),
906+ folderListPage)
907+
908+ authDialog.passwordEntered.connect(function(password) {
909+ if (pamAuthentication.validatePasswordToken(password)) {
910+ console.log("Authenticated for full access")
911+ pageModel.onlyMTPPaths = false
912+ } else {
913+ PopupUtils.open(Qt.resolvedUrl("NotifyDialog.qml"), folderListPage,
914+ {
915+ title: i18n.tr("Authentication failed")
916+ })
917+
918+ console.log("Could not authenticate")
919+ }
920+ })
921+ }
922+ }
923+ ]
924 flickable: !sidebar.expanded ?
925 (folderListView.visible ? folderListView : folderIconView.flickable) : null
926
927@@ -78,8 +181,6 @@
928 }
929 }
930
931-
932-
933 PlacesModel { id: userplaces }
934
935 FolderListModel {
936@@ -135,78 +236,6 @@
937 }
938
939 Component {
940- id: folderActionsPopoverComponent
941- ActionSelectionPopover {
942- id: folderActionsPopover
943- objectName: "folderActionsPopover"
944-
945- grabDismissAreaEvents: true
946-
947- actions: ActionList {
948- Action {
949- text: i18n.tr("Create New Folder")
950- onTriggered: {
951- print(text)
952-
953- PopupUtils.open(createFolderDialog, folderListPage)
954- }
955- }
956-
957- // TODO: Disabled until backend supports creating files
958- // Action {
959- // text: i18n.tr("Create New File")
960- // onTriggered: {
961- // print(text)
962-
963- // PopupUtils.open(createFileDialog, root)
964- // }
965- // }
966-
967- Action {
968- text: pageModel.clipboardUrlsCounter === 0 ?
969- i18n.tr("Paste") :
970- i18n.tr("Paste %1 File", "Paste %1 Files", pageModel.clipboardUrlsCounter).arg(pageModel.clipboardUrlsCounter)
971- onTriggered: {
972- console.log("Pasting to current folder items of count " + pageModel.clipboardUrlsCounter)
973- fileOperationDialog.startOperation(i18n.tr("Paste files"))
974- pageModel.paste()
975- }
976-
977- // FIXME: This property is depreciated and doesn't seem to work!
978- //visible: pageModel.clipboardUrlsCounter > 0
979-
980- enabled: pageModel.clipboardUrlsCounter > 0
981- }
982-
983- // TODO: Disabled until support for opening apps is added
984- Action {
985- text: i18n.tr("Open in Terminal")
986- onTriggered: {
987- print(text)
988-
989- // Is this the way it will work??
990- Qt.openUrlExternally("app://terminal")
991- }
992-
993- enabled: showAdvancedFeatures && false
994- }
995-
996- Action {
997- text: i18n.tr("Properties")
998- onTriggered: {
999- print(text)
1000- PopupUtils.open(Qt.resolvedUrl("FileDetailsPopover.qml"),
1001- folderListPage,
1002- { "model": pageModel
1003- }
1004- )
1005- }
1006- }
1007- }
1008- }
1009- }
1010-
1011- Component {
1012 id: createFolderDialog
1013 ConfirmDialogWithInput {
1014 title: i18n.tr("Create folder")
1015@@ -240,111 +269,15 @@
1016 }
1017 }
1018
1019- tools: ToolbarItems {
1020- id: toolbar
1021- locked: showToolbar
1022- opened: showToolbar
1023-
1024- onLockedChanged: opened = locked
1025-
1026- back: ToolbarButton {
1027- objectName: "up"
1028- text: i18n.tr("Up")
1029- iconSource: getIcon("keyboard-caps")
1030- enabled: folder != "/"
1031- onTriggered: {
1032- goTo(pageModel.parentPath)
1033- }
1034- }
1035-
1036- Item {
1037- id: pathItem
1038- // TODO: Uncomment after re-enabling tab support (caused by lp:1295242)
1039- width: folderListPage.width - units.gu(31)//folderListPage.width - units.gu(37)
1040- height: units.gu(5)
1041- anchors.verticalCenter: parent.verticalCenter
1042- PathBar {
1043- height: units.gu(5)
1044- width: Math.min(pathItem.width, implicitWidth)
1045- visible: sidebar.expanded
1046- }
1047- }
1048-
1049- Item {
1050- width: units.gu(1)
1051- height: parent.height
1052- }
1053-
1054- ToolbarButton {
1055- id: actionsButton
1056- objectName: "actions"
1057- text: i18n.tr("Actions")
1058- iconSource: getIcon("navigation-menu")
1059-
1060- onTriggered: {
1061- print(text)
1062- PopupUtils.open(folderActionsPopoverComponent, actionsButton)
1063- }
1064- }
1065-
1066- ToolbarButton {
1067- text: i18n.tr("View")
1068- iconSource: getIcon("properties")
1069- id: optionsButton
1070-
1071- onTriggered: {
1072- print(text)
1073-
1074- PopupUtils.open(Qt.resolvedUrl("ViewPopover.qml"), optionsButton)
1075- }
1076- }
1077-
1078- ToolbarButton {
1079- id: placesButton
1080- visible: !sidebar.expanded
1081- objectName: "places"
1082- text: i18n.tr("Places")
1083- iconSource: getIcon("location")
1084- onTriggered: {
1085- print(text)
1086-
1087- PopupUtils.open(Qt.resolvedUrl("PlacesPopover.qml"), placesButton)
1088- }
1089- }
1090-
1091- // TODO: Uncomment after re-enabling tab support (caused by lp:1295242)
1092-// ToolbarButton {
1093-// id: tabsButton
1094-// objectName: "tabs"
1095-// text: i18n.tr("Tabs")
1096-// iconSource: getIcon("browser-tabs")
1097-
1098-// onTriggered: {
1099-// print(text)
1100-
1101-// PopupUtils.open(tabsPopover, tabsButton, {
1102-// tab: folderListPage.parent
1103-// })
1104-// }
1105-// }
1106-
1107- ToolbarButton {
1108- id: settingsButton
1109- visible: sidebar.expanded
1110- objectName: "settings"
1111- action: settingsAction
1112- }
1113- }
1114-
1115 PlacesSidebar {
1116 id: sidebar
1117 objectName: "placesSidebar"
1118
1119-// anchors {
1120-// top: parent.top
1121-// bottom: parent.bottom
1122-// bottomMargin: units.gu(-2)
1123-// }
1124+ // anchors {
1125+ // top: parent.top
1126+ // bottom: parent.bottom
1127+ // bottomMargin: units.gu(-2)
1128+ // }
1129
1130 expanded: showSidebar
1131 }
1132@@ -372,23 +305,23 @@
1133 enabled: selectionManager.counter > 0
1134 visible: fileSelectorMode
1135 onClicked: {
1136- var selectedAbsPaths = selectionManager.selectedAbsFilePaths();
1137- // For now support only selection in filesystem
1138- var selectedAbsUrls = selectedAbsPaths.map(function(item) {
1139- return "file://" + item;
1140- });
1141- console.log("FileSelector OK clicked, selected items: " + selectedAbsUrls)
1142+ var selectedAbsPaths = selectionManager.selectedAbsFilePaths();
1143+ // For now support only selection in filesystem
1144+ var selectedAbsUrls = selectedAbsPaths.map(function(item) {
1145+ return "file://" + item;
1146+ });
1147+ console.log("FileSelector OK clicked, selected items: " + selectedAbsUrls)
1148
1149- acceptFileSelector(selectedAbsUrls)
1150- }
1151+ acceptFileSelector(selectedAbsUrls)
1152+ }
1153 }
1154 Button {
1155- text: i18n.tr("Cancel")
1156- visible: fileSelectorMode
1157- onClicked: {
1158- console.log("FileSelector cancelled")
1159- cancelFileSelector()
1160- }
1161+ text: i18n.tr("Cancel")
1162+ visible: fileSelectorMode
1163+ onClicked: {
1164+ console.log("FileSelector cancelled")
1165+ cancelFileSelector()
1166+ }
1167 }
1168 Button {
1169 text: i18n.tr("Unlock full access")
1170@@ -396,7 +329,7 @@
1171 onClicked: {
1172 console.log("Full access clicked")
1173 var authDialog = PopupUtils.open(Qt.resolvedUrl("AuthenticationDialog.qml"),
1174- folderListPage)
1175+ folderListPage)
1176
1177 authDialog.passwordEntered.connect(function(password) {
1178 if (pamAuthentication.validatePasswordToken(password)) {
1179@@ -517,7 +450,8 @@
1180 {
1181 title: i18n.tr("Could not rename"),
1182 text: i18n.tr("Insufficient permissions or name already exists?")
1183- })
1184+ }
1185+ )
1186
1187 }
1188 } else {
1189@@ -569,7 +503,7 @@
1190 print(text)
1191 PopupUtils.open(confirmSingleDeleteDialog, actionSelectionPopover.caller,
1192 { "filePath" : actionSelectionPopover.model.filePath,
1193- "fileName" : actionSelectionPopover.model.fileName }
1194+ "fileName" : actionSelectionPopover.model.fileName }
1195 )
1196 }
1197 }
1198@@ -582,19 +516,20 @@
1199 print(text)
1200 PopupUtils.open(confirmRenameDialog, actionSelectionPopover.caller,
1201 { "modelRow" : actionSelectionPopover.model.index,
1202- "inputText" : actionSelectionPopover.model.fileName
1203+ "inputText" : actionSelectionPopover.model.fileName
1204 })
1205 }
1206 }
1207
1208 Action {
1209 text: i18n.tr("Properties")
1210+
1211 onTriggered: {
1212 print(text)
1213 PopupUtils.open(Qt.resolvedUrl("FileDetailsPopover.qml"),
1214 actionSelectionPopover.caller,
1215- { "model": actionSelectionPopover.model
1216- }
1217+ { "model": actionSelectionPopover.model
1218+ }
1219 )
1220 }
1221 }
1222@@ -625,6 +560,17 @@
1223 refresh()
1224 }
1225
1226+ /* Go to last folder visited */
1227+ function goBack() {
1228+ pageModel.goBack()
1229+ folder = pageModel.path
1230+ }
1231+
1232+ /* Go up one directory */
1233+ function goUp() {
1234+ goTo(pageModel.parentPath)
1235+ }
1236+
1237 function refresh() {
1238 pageModel.refresh()
1239 }
1240@@ -691,6 +637,22 @@
1241 }
1242 }
1243
1244+ /* Return depth of current path */
1245+ function pathModel(path){
1246+ if (path === "/") { return 0 } // Otherwise it will return 1
1247+ return path.split("/").length - 1
1248+ }
1249+
1250+ /* Return folder name by its depth in current path */
1251+ function pathText(path,index) {
1252+ return basename(path.split('/').slice(0,index+2).join("/"))
1253+ }
1254+
1255+ /* Return folder path by its depth in current path */
1256+ function pathRaw(path,index) {
1257+ return path.split('/').slice(0,index+2).join("/")
1258+ }
1259+
1260 function pathName(folder) {
1261 if (folder === "/") {
1262 return "/"
1263@@ -704,6 +666,7 @@
1264 // E.g. basename('/home/phablet/Música') returns 'Música'
1265
1266 // Remove the last trailing '/' if there is one
1267+
1268 folder.replace(/\/$/, "")
1269 return folder.substr(folder.lastIndexOf('/') + 1)
1270 }
1271@@ -743,10 +706,10 @@
1272 PopupUtils.open(Qt.resolvedUrl("NotifyDialog.qml"), delegate,
1273 {
1274 title: i18n.tr("Folder not accessible"),
1275- // TRANSLATORS: this refers to a folder name
1276- text: i18n.tr("Can not access %1").arg(model.fileName)
1277+ // TRANSLATORS: this refers to a folder name
1278+ text: i18n.tr("Can not access %1").arg(model.fileName)
1279
1280- })
1281+ })
1282 }
1283 } else {
1284 console.log("Non dir clicked")
1285@@ -757,12 +720,12 @@
1286 } else {
1287 openFile(model.fileName)
1288 }
1289-// PopupUtils.open(Qt.resolvedUrl("FileActionDialog.qml"), root,
1290-// {
1291-// fileName: model.fileName,
1292-// filePath: model.filePath,
1293-// folderListModel: root.folderListModel
1294-// })
1295+ // PopupUtils.open(Qt.resolvedUrl("FileActionDialog.qml"), root,
1296+ // {
1297+ // fileName: model.fileName,
1298+ // filePath: model.filePath,
1299+ // folderListModel: root.folderListModel
1300+ // })
1301 }
1302 }
1303
1304@@ -783,5 +746,7 @@
1305 return false;
1306 }
1307
1308- Component.onCompleted: forceActiveFocus()
1309+ Component.onCompleted: {
1310+ forceActiveFocus()
1311+ }
1312 }
1313
1314=== added file 'src/app/qml/ui/PlacesPage.qml'
1315--- src/app/qml/ui/PlacesPage.qml 1970-01-01 00:00:00 +0000
1316+++ src/app/qml/ui/PlacesPage.qml 2014-10-21 21:27:55 +0000
1317@@ -0,0 +1,117 @@
1318+/*
1319+ * Copyright (C) 2014 Canonical Ltd
1320+ *
1321+ * This program is free software: you can redistribute it and/or modify
1322+ * it under the terms of the GNU General Public License version 3 as
1323+ * published by the Free Software Foundation.
1324+ *
1325+ * This program is distributed in the hope that it will be useful,
1326+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1327+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1328+ * GNU General Public License for more details.
1329+ *
1330+ * You should have received a copy of the GNU General Public License
1331+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1332+ *
1333+ * Authored by: Arto Jalkanen <ajalkane@gmail.com>
1334+ */
1335+import QtQuick 2.3
1336+import Ubuntu.Components 1.1
1337+import Ubuntu.Components.Popups 1.0
1338+import Ubuntu.Components.ListItems 1.0
1339+import org.nemomobile.folderlistmodel 1.0
1340+import com.ubuntu.PlacesModel 0.1
1341+
1342+Page {
1343+ id: root
1344+
1345+ title: i18n.tr("Places")
1346+ objectName: 'PlacesPage'
1347+
1348+ Flickable {
1349+ anchors.fill: parent
1350+
1351+ Column {
1352+ anchors {
1353+ left: parent.left
1354+ right: parent.right
1355+ top: parent.top
1356+ }
1357+
1358+ Empty {
1359+
1360+ TextField {
1361+ id: locationField
1362+ objectName: "inputField"
1363+ anchors {
1364+ verticalCenter: parent.verticalCenter
1365+ left: parent.left
1366+ right: goButton.left
1367+ margins: units.gu(1)
1368+ }
1369+
1370+ inputMethodHints: Qt.ImhNoAutoUppercase
1371+
1372+ property bool valid: pathExists(text)
1373+
1374+ text: fileView.folder
1375+
1376+ placeholderText: i18n.tr("Location...")
1377+
1378+ onAccepted: goButton.clicked()
1379+ }
1380+
1381+ Button {
1382+ id: goButton
1383+ objectName: "okButton"
1384+ anchors {
1385+ top: locationField.top
1386+ bottom: locationField.bottom
1387+ right: parent.right
1388+ rightMargin: units.gu(1)
1389+ }
1390+
1391+ text: i18n.tr("Go")
1392+ enabled: locationField.acceptableInput && locationField.valid
1393+
1394+ onClicked: {
1395+ print("User switched to:", locationField.text)
1396+ goTo(locationField.text)
1397+ pageStack.pop()
1398+ }
1399+ }
1400+ }
1401+
1402+ Repeater {
1403+ id: placesList
1404+ objectName: "placesList"
1405+
1406+ model: PlacesModel {}
1407+
1408+ delegate: Standard {
1409+ objectName: "place" + folderDisplayName(path).replace(/ /g,'')
1410+ property string name: folderDisplayName(path)
1411+
1412+ Label {
1413+ anchors.left: parent.left
1414+ anchors.leftMargin: units.gu(8)
1415+ anchors.verticalCenter: parent.verticalCenter
1416+ text: folderDisplayName(path)
1417+ }
1418+
1419+ iconSource: model.icon || fileIcon(model.path, true)
1420+
1421+ onClicked: {
1422+ goTo(model.path)
1423+ pageStack.pop()
1424+ }
1425+
1426+ selected: folder === path
1427+ iconFrame: false
1428+ showDivider: index < (placesList.count - 1)
1429+ }
1430+ }
1431+ }
1432+ }
1433+
1434+}
1435
1436=== modified file 'src/app/qml/ui/SettingsSheet.qml'
1437--- src/app/qml/ui/SettingsSheet.qml 2014-09-20 10:49:51 +0000
1438+++ src/app/qml/ui/SettingsSheet.qml 2014-10-21 21:27:55 +0000
1439@@ -26,7 +26,7 @@
1440 * TODO: Make sure this fits with the UI guidelines if
1441 * they are updated to include About/Settings info.
1442 */
1443-DefaultSheet {
1444+Page {
1445 id: sheet
1446 title: i18n.tr("Settings")
1447
1448
1449=== added directory 'src/app/qml/upstream'
1450=== added file 'src/app/qml/upstream/FakeHeader.qml'
1451--- src/app/qml/upstream/FakeHeader.qml 1970-01-01 00:00:00 +0000
1452+++ src/app/qml/upstream/FakeHeader.qml 2014-10-21 21:27:55 +0000
1453@@ -0,0 +1,37 @@
1454+/*
1455+ * Copyright (C) 2014 Canonical Ltd
1456+ *
1457+ * Ubuntu Clock App is free software: you can redistribute it and/or modify
1458+ * it under the terms of the GNU General Public License version 3 as
1459+ * published by the Free Software Foundation.
1460+ *
1461+ * Ubuntu Clock App is distributed in the hope that it will be useful,
1462+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1463+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1464+ * GNU General Public License for more details.
1465+ *
1466+ * You should have received a copy of the GNU General Public License
1467+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1468+ */
1469+
1470+import QtQuick 2.3
1471+import Ubuntu.Components 1.1
1472+
1473+Column {
1474+ id: fakeHeader
1475+
1476+ height: units.gu(9)
1477+
1478+ Rectangle {
1479+ height: units.gu(7)
1480+ width: parent.width
1481+ color: Theme.palette.normal.background
1482+ }
1483+
1484+ Rectangle {
1485+ color: "#C9C9C9"
1486+ height: units.gu(2)
1487+ anchors.left: parent.left
1488+ anchors.right: parent.right
1489+ }
1490+}
1491
1492=== added file 'src/app/qml/upstream/PageWithBottomEdge.qml'
1493--- src/app/qml/upstream/PageWithBottomEdge.qml 1970-01-01 00:00:00 +0000
1494+++ src/app/qml/upstream/PageWithBottomEdge.qml 2014-10-21 21:27:55 +0000
1495@@ -0,0 +1,450 @@
1496+/*
1497+ * Copyright (C) 2014 Canonical, Ltd.
1498+ *
1499+ * This program is free software; you can redistribute it and/or modify
1500+ * it under the terms of the GNU General Public License as published by
1501+ * the Free Software Foundation; version 3.
1502+ *
1503+ * This program is distributed in the hope that it will be useful,
1504+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1505+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1506+ * GNU General Public License for more details.
1507+ *
1508+ * You should have received a copy of the GNU General Public License
1509+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1510+ */
1511+
1512+/*
1513+ Example:
1514+
1515+ MainView {
1516+ objectName: "mainView"
1517+
1518+ applicationName: "com.ubuntu.developer.boiko.bottomedge"
1519+
1520+ width: units.gu(100)
1521+ height: units.gu(75)
1522+
1523+ Component {
1524+ id: pageComponent
1525+
1526+ PageWithBottomEdge {
1527+ id: mainPage
1528+ title: i18n.tr("Main Page")
1529+
1530+ Rectangle {
1531+ anchors.fill: parent
1532+ color: "white"
1533+ }
1534+
1535+ bottomEdgePageComponent: Page {
1536+ title: "Contents"
1537+ anchors.fill: parent
1538+ //anchors.topMargin: contentsPage.flickable.contentY
1539+
1540+ ListView {
1541+ anchors.fill: parent
1542+ model: 50
1543+ delegate: ListItems.Standard {
1544+ text: "One Content Item: " + index
1545+ }
1546+ }
1547+ }
1548+ bottomEdgeTitle: i18n.tr("Bottom edge action")
1549+ }
1550+ }
1551+
1552+ PageStack {
1553+ id: stack
1554+ Component.onCompleted: stack.push(pageComponent)
1555+ }
1556+ }
1557+
1558+*/
1559+
1560+import QtQuick 2.2
1561+import Ubuntu.Components 1.1
1562+
1563+Page {
1564+ id: page
1565+
1566+ property alias bottomEdgePageComponent: edgeLoader.sourceComponent
1567+ property alias bottomEdgePageSource: edgeLoader.source
1568+ property alias bottomEdgeTitle: tipLabel.text
1569+ property bool bottomEdgeEnabled: true
1570+ property int bottomEdgeExpandThreshold: page.height * 0.2
1571+ property int bottomEdgeExposedArea: bottomEdge.state !== "expanded" ? (page.height - bottomEdge.y - bottomEdge.tipHeight) : _areaWhenExpanded
1572+ property bool reloadBottomEdgePage: true
1573+
1574+ readonly property alias bottomEdgePage: edgeLoader.item
1575+ readonly property bool isReady: ((bottomEdge.y === fakeHeader.height) && bottomEdgePageLoaded && edgeLoader.item.active)
1576+ readonly property bool isCollapsed: (bottomEdge.y === page.height)
1577+ readonly property bool bottomEdgePageLoaded: (edgeLoader.status == Loader.Ready)
1578+
1579+ property bool _showEdgePageWhenReady: false
1580+ property int _areaWhenExpanded: 0
1581+
1582+ signal bottomEdgeReleased()
1583+ signal bottomEdgeDismissed()
1584+
1585+ function showBottomEdgePage(source, properties)
1586+ {
1587+ edgeLoader.setSource(source, properties)
1588+ _showEdgePageWhenReady = true
1589+ }
1590+
1591+ function setBottomEdgePage(source, properties)
1592+ {
1593+ edgeLoader.setSource(source, properties)
1594+ }
1595+
1596+ function _pushPage()
1597+ {
1598+ if (edgeLoader.status === Loader.Ready) {
1599+ edgeLoader.item.active = true
1600+ page.pageStack.push(edgeLoader.item)
1601+ if (edgeLoader.item.flickable) {
1602+ edgeLoader.item.flickable.contentY = -page.header.height
1603+ edgeLoader.item.flickable.returnToBounds()
1604+ }
1605+ if (edgeLoader.item.ready)
1606+ edgeLoader.item.ready()
1607+ }
1608+ }
1609+
1610+
1611+ Component.onCompleted: {
1612+ // avoid a binding on the expanded height value
1613+ var expandedHeight = height;
1614+ _areaWhenExpanded = expandedHeight;
1615+ }
1616+
1617+ onActiveChanged: {
1618+ if (active) {
1619+ bottomEdge.state = "collapsed"
1620+ }
1621+ }
1622+
1623+ onBottomEdgePageLoadedChanged: {
1624+ if (_showEdgePageWhenReady && bottomEdgePageLoaded) {
1625+ bottomEdge.state = "expanded"
1626+ _showEdgePageWhenReady = false
1627+ }
1628+ }
1629+
1630+ Rectangle {
1631+ id: bgVisual
1632+
1633+ color: "black"
1634+ anchors.fill: page
1635+ opacity: 0.7 * ((page.height - bottomEdge.y) / page.height)
1636+ z: 1
1637+ }
1638+
1639+ UbuntuShape {
1640+ id: tip
1641+ objectName: "bottomEdgeTip"
1642+
1643+ property bool hiden: (activeFocus === false) ||
1644+ ((bottomEdge.y - units.gu(1)) < tip.y)
1645+
1646+ property bool isAnimating: true
1647+
1648+ enabled: mouseArea.enabled
1649+ visible: page.bottomEdgeEnabled
1650+ anchors {
1651+ bottom: parent.bottom
1652+ horizontalCenter: bottomEdge.horizontalCenter
1653+ bottomMargin: hiden ? - height + units.gu(1) : -units.gu(1)
1654+ Behavior on bottomMargin {
1655+ SequentialAnimation {
1656+ // wait some msecs in case of the focus change again, to avoid flickering
1657+ PauseAnimation {
1658+ duration: 300
1659+ }
1660+ UbuntuNumberAnimation {
1661+ duration: UbuntuAnimation.SnapDuration
1662+ }
1663+ ScriptAction {
1664+ script: tip.isAnimating = false
1665+ }
1666+ }
1667+ }
1668+ }
1669+
1670+ z: 1
1671+ width: tipLabel.paintedWidth + units.gu(6)
1672+ height: bottomEdge.tipHeight + units.gu(1)
1673+ color: Theme.palette.normal.overlay
1674+ Label {
1675+ id: tipLabel
1676+
1677+ anchors {
1678+ top: parent.top
1679+ left: parent.left
1680+ right: parent.right
1681+ }
1682+ height: bottomEdge.tipHeight
1683+ verticalAlignment: Text.AlignVCenter
1684+ horizontalAlignment: Text.AlignHCenter
1685+ opacity: tip.hiden ? 0.0 : 1.0
1686+ Behavior on opacity {
1687+ UbuntuNumberAnimation {
1688+ duration: UbuntuAnimation.SnapDuration
1689+ }
1690+ }
1691+ }
1692+ }
1693+
1694+ Rectangle {
1695+ id: shadow
1696+
1697+ anchors {
1698+ left: parent.left
1699+ right: parent.right
1700+ bottom: parent.bottom
1701+ }
1702+ height: units.gu(1)
1703+ z: 1
1704+ opacity: 0.0
1705+ gradient: Gradient {
1706+ GradientStop { position: 0.0; color: "transparent" }
1707+ GradientStop { position: 1.0; color: Qt.rgba(0, 0, 0, 0.2) }
1708+ }
1709+ }
1710+
1711+ MouseArea {
1712+ id: mouseArea
1713+
1714+ property real previousY: -1
1715+ property string dragDirection: "None"
1716+
1717+ preventStealing: true
1718+ drag {
1719+ axis: Drag.YAxis
1720+ target: bottomEdge
1721+ minimumY: bottomEdge.pageStartY
1722+ maximumY: page.height
1723+ }
1724+ enabled: edgeLoader.status == Loader.Ready
1725+ visible: page.bottomEdgeEnabled
1726+
1727+ anchors {
1728+ left: parent.left
1729+ right: parent.right
1730+ bottom: parent.bottom
1731+ }
1732+ height: bottomEdge.tipHeight
1733+ z: 1
1734+
1735+ onReleased: {
1736+ page.bottomEdgeReleased()
1737+ if ((dragDirection === "BottomToTop") &&
1738+ bottomEdge.y < (page.height - bottomEdgeExpandThreshold - bottomEdge.tipHeight)) {
1739+ bottomEdge.state = "expanded"
1740+ } else {
1741+ bottomEdge.state = "collapsed"
1742+ }
1743+ previousY = -1
1744+ dragDirection = "None"
1745+ }
1746+
1747+ onPressed: {
1748+ previousY = mouse.y
1749+ tip.forceActiveFocus()
1750+ }
1751+
1752+ onMouseYChanged: {
1753+ var yOffset = previousY - mouseY
1754+ // skip if was a small move
1755+ if (Math.abs(yOffset) <= units.gu(2)) {
1756+ return
1757+ }
1758+ previousY = mouseY
1759+ dragDirection = yOffset > 0 ? "BottomToTop" : "TopToBottom"
1760+ }
1761+ }
1762+
1763+ FakeHeader {
1764+ id: fakeHeader
1765+ visible: bottomEdgeEnabled
1766+
1767+ anchors {
1768+ left: parent.left
1769+ right: parent.right
1770+ }
1771+ y: -fakeHeader.height + (fakeHeader.height * (page.height - bottomEdge.y)) / (page.height - fakeHeader.height)
1772+ z: bgVisual.z + 1
1773+
1774+ Behavior on y {
1775+ UbuntuNumberAnimation {
1776+ duration: UbuntuAnimation.SnapDuration
1777+ }
1778+ }
1779+ }
1780+
1781+ Rectangle {
1782+ id: bottomEdge
1783+ objectName: "bottomEdge"
1784+
1785+ readonly property int tipHeight: units.gu(3)
1786+ readonly property int pageStartY: fakeHeader.height
1787+
1788+ z: 1
1789+ color: Theme.palette.normal.background
1790+ clip: true
1791+ anchors {
1792+ left: parent.left
1793+ right: parent.right
1794+ }
1795+ height: page.height
1796+ y: height
1797+
1798+ visible: !page.isCollapsed
1799+ state: "collapsed"
1800+ states: [
1801+ State {
1802+ name: "collapsed"
1803+ PropertyChanges {
1804+ target: bottomEdge
1805+ y: bottomEdge.height
1806+ }
1807+ PropertyChanges {
1808+ target: fakeHeader
1809+ y: -fakeHeader.height
1810+ }
1811+ },
1812+ State {
1813+ name: "expanded"
1814+ PropertyChanges {
1815+ target: bottomEdge
1816+ y: bottomEdge.pageStartY
1817+ }
1818+ PropertyChanges {
1819+ target: fakeHeader
1820+ y: 0
1821+ }
1822+ },
1823+ State {
1824+ name: "floating"
1825+ when: mouseArea.drag.active
1826+ PropertyChanges {
1827+ target: shadow
1828+ opacity: 1.0
1829+ }
1830+ }
1831+ ]
1832+
1833+ transitions: [
1834+ Transition {
1835+ to: "expanded"
1836+ SequentialAnimation {
1837+ alwaysRunToEnd: true
1838+ ParallelAnimation {
1839+ SmoothedAnimation {
1840+ target: bottomEdge
1841+ property: "y"
1842+ duration: UbuntuAnimation.FastDuration
1843+ easing.type: Easing.Linear
1844+ }
1845+ SmoothedAnimation {
1846+ target: fakeHeader
1847+ property: "y"
1848+ duration: UbuntuAnimation.FastDuration
1849+ easing.type: Easing.Linear
1850+ }
1851+ }
1852+ SmoothedAnimation {
1853+ target: edgeLoader
1854+ property: "anchors.topMargin"
1855+ to: - units.gu(4)
1856+ duration: UbuntuAnimation.FastDuration
1857+ easing.type: Easing.Linear
1858+ }
1859+ SmoothedAnimation {
1860+ target: edgeLoader
1861+ property: "anchors.topMargin"
1862+ to: 0
1863+ duration: UbuntuAnimation.FastDuration
1864+ easing: UbuntuAnimation.StandardEasing
1865+ }
1866+ ScriptAction {
1867+ script: page._pushPage()
1868+ }
1869+ }
1870+ },
1871+ Transition {
1872+ from: "expanded"
1873+ to: "collapsed"
1874+ SequentialAnimation {
1875+ alwaysRunToEnd: true
1876+
1877+ ScriptAction {
1878+ script: {
1879+ Qt.inputMethod.hide()
1880+ edgeLoader.item.parent = edgeLoader
1881+ edgeLoader.item.anchors.fill = edgeLoader
1882+ edgeLoader.item.active = false
1883+ }
1884+ }
1885+ ParallelAnimation {
1886+ SmoothedAnimation {
1887+ target: bottomEdge
1888+ property: "y"
1889+ duration: UbuntuAnimation.SlowDuration
1890+ }
1891+ SmoothedAnimation {
1892+ target: fakeHeader
1893+ property: "y"
1894+ duration: UbuntuAnimation.SlowDuration
1895+ }
1896+ }
1897+ ScriptAction {
1898+ script: {
1899+ // destroy current bottom page
1900+ if (page.reloadBottomEdgePage) {
1901+ edgeLoader.active = false
1902+ } else {
1903+ tip.forceActiveFocus()
1904+ }
1905+
1906+ // notify
1907+ page.bottomEdgeDismissed()
1908+
1909+ edgeLoader.active = true
1910+ }
1911+ }
1912+ }
1913+ },
1914+ Transition {
1915+ from: "floating"
1916+ to: "collapsed"
1917+ UbuntuNumberAnimation {
1918+ target: bottomEdge
1919+ property: "opacity"
1920+ }
1921+ }
1922+ ]
1923+
1924+ Loader {
1925+ id: edgeLoader
1926+
1927+ asynchronous: true
1928+ anchors.fill: parent
1929+ //WORKAROUND: The SDK move the page contents down to allocate space for the header we need to avoid that during the page dragging
1930+ Binding {
1931+ target: edgeLoader.status === Loader.Ready ? edgeLoader : null
1932+ property: "anchors.topMargin"
1933+ value: edgeLoader.item && edgeLoader.item.flickable ? edgeLoader.item.flickable.contentY : 0
1934+ when: !page.isReady
1935+ }
1936+
1937+ onLoaded: {
1938+ tip.forceActiveFocus()
1939+ if (page.isReady && edgeLoader.item.active !== true) {
1940+ page._pushPage()
1941+ }
1942+ }
1943+ }
1944+ }
1945+}
1946
1947=== modified file 'src/plugin/folderlistmodel/clipboard.cpp'
1948--- src/plugin/folderlistmodel/clipboard.cpp 2014-01-29 16:31:04 +0000
1949+++ src/plugin/folderlistmodel/clipboard.cpp 2014-10-21 21:27:55 +0000
1950@@ -236,7 +236,6 @@
1951
1952 bool DirModelMimeData::fillClipboard(const QStringList& files, const QString &path, ClipboardOperation operation)
1953 {
1954- bool ret = false;
1955 int index = m_formats.indexOf(KDE_CUT_MIME_TYPE);
1956 if (index != -1 && operation != ClipboardCut)
1957 {
1958@@ -259,17 +258,10 @@
1959 m_urls.append(item);
1960 m_gnomeData += QLatin1Char('\n') + item.toEncoded() ;
1961 }
1962- if (m_urls.count() > 0)
1963- {
1964- setData(GNOME_COPIED_MIME_TYPE, m_gnomeData);
1965- setUrls(m_urls);
1966- ret = true;
1967- }
1968- else
1969- {
1970- // emit error( QObject::tr("Item does not exist"), item);
1971- }
1972- return ret;
1973+ setData(GNOME_COPIED_MIME_TYPE, m_gnomeData);
1974+ setUrls(m_urls);
1975+
1976+ return true;
1977 }
1978
1979 //===============================================================================================
1980@@ -493,3 +485,12 @@
1981 }
1982 return items;
1983 }
1984+
1985+/*!
1986+ * \brief Clears clipboard entries
1987+ */
1988+void Clipboard::clear()
1989+{
1990+ qDebug() << Q_FUNC_INFO << "Clearing clipboard";
1991+ storeOnClipboard(QStringList(), ClipboardCopy, "");
1992+}
1993
1994=== modified file 'src/plugin/folderlistmodel/clipboard.h'
1995--- src/plugin/folderlistmodel/clipboard.h 2014-01-29 16:31:04 +0000
1996+++ src/plugin/folderlistmodel/clipboard.h 2014-10-21 21:27:55 +0000
1997@@ -66,7 +66,7 @@
1998 public slots:
1999 void cut(const QStringList& names, const QString &path);
2000 void copy(const QStringList& names, const QString &path);
2001-
2002+ void clear();
2003
2004 signals:
2005 void clipboardChanged();
2006
2007=== modified file 'src/plugin/folderlistmodel/dirmodel.cpp'
2008--- src/plugin/folderlistmodel/dirmodel.cpp 2014-09-09 11:34:15 +0000
2009+++ src/plugin/folderlistmodel/dirmodel.cpp 2014-10-21 21:27:55 +0000
2010@@ -866,6 +866,10 @@
2011 }
2012 }
2013
2014+void DirModel::clearClipboard()
2015+{
2016+ mClipboard->clear();
2017+}
2018
2019 bool DirModel::cdIntoIndex(int row)
2020 {
2021
2022=== modified file 'src/plugin/folderlistmodel/dirmodel.h'
2023--- src/plugin/folderlistmodel/dirmodel.h 2014-09-09 11:11:35 +0000
2024+++ src/plugin/folderlistmodel/dirmodel.h 2014-10-21 21:27:55 +0000
2025@@ -371,6 +371,11 @@
2026 */
2027 void paste();
2028
2029+ /*!
2030+ * \brief clears clipboard entries
2031+ */
2032+ void clearClipboard();
2033+
2034 /*!
2035 * \brief cancelAction() any copy/cut/remove can be cancelled
2036 */

Subscribers

People subscribed via source and target branches