~ubuntu-branches/ubuntu/raring/plasma-mobile/raring-proposed

« back to all changes in this revision

Viewing changes to applications/filebrowser/package/contents/ui/Browser.qml

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2012-07-17 12:04:43 UTC
  • mfrom: (1.1.6)
  • Revision ID: package-import@ubuntu.com-20120717120443-q3ig9u2fnltx67yg
Tags: 2.0+git2012071701-0ubuntu1
* New upstream snapshot
* Remove build-dep on kde-runtime-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *   Copyright 2011 Marco Martin <mart@kde.org>
 
3
 *
 
4
 *   This program is free software; you can redistribute it and/or modify
 
5
 *   it under the terms of the GNU Library General Public License as
 
6
 *   published by the Free Software Foundation; either version 2, or
 
7
 *   (at your option) any later version.
 
8
 *
 
9
 *   This program is distributed in the hope that it will be useful,
 
10
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 *   GNU Library General Public License for more details
 
13
 *
 
14
 *   You should have received a copy of the GNU Library General Public
 
15
 *   License along with this program; if not, write to the
 
16
 *   Free Software Foundation, Inc.,
 
17
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
18
 */
 
19
 
 
20
import QtQuick 1.1
 
21
import org.kde.metadatamodels 0.1 as MetadataModels
 
22
import org.kde.plasma.components 0.1 as PlasmaComponents
 
23
import org.kde.plasma.core 0.1 as PlasmaCore
 
24
import org.kde.plasma.mobilecomponents 0.1 as MobileComponents
 
25
import org.kde.draganddrop 1.0
 
26
import org.kde.qtextracomponents 0.1
 
27
 
 
28
 
 
29
PlasmaComponents.Page {
 
30
    id: resourceBrowser
 
31
    objectName: "resourceBrowser"
 
32
    property string currentUdi
 
33
    anchors {
 
34
        fill: parent
 
35
        topMargin: toolBar.height
 
36
    }
 
37
 
 
38
    PlasmaCore.DataSource {
 
39
        id: hotplugSource
 
40
        engine: "hotplug"
 
41
        connectedSources: sources
 
42
    }
 
43
    PlasmaCore.DataSource {
 
44
        id: devicesSource
 
45
        engine: "soliddevice"
 
46
        connectedSources: hotplugSource.sources
 
47
        onDataChanged: {
 
48
            //access it here due to the async nature of the dataengine
 
49
            if (resultsGrid.model == dirModel) {
 
50
                var udi
 
51
                var path
 
52
 
 
53
                for (var i in devicesSource.connectedSources) {
 
54
                    udi = devicesSource.connectedSources[i]
 
55
                    path = devicesSource.data[udi]["File Path"]
 
56
                    print(udi+dirModel.url.indexOf(udi))
 
57
                    if (dirModel.url.indexOf(path) > 2) {
 
58
                        resourceBrowser.currentUdi = udi
 
59
                        break
 
60
                    }
 
61
                }
 
62
            } else if (resultsGrid.model != dirModel && devicesSource.data[resourceBrowser.currentUdi]["File Path"] != "") {
 
63
                dirModel.url = devicesSource.data[resourceBrowser.currentUdi]["File Path"]
 
64
 
 
65
                fileBrowserRoot.model = dirModel
 
66
            }
 
67
        }
 
68
    }
 
69
 
 
70
    //FIXME: this will have to be removed
 
71
    Timer {
 
72
        interval: 100
 
73
        running: true
 
74
        onTriggered: backConnection.target = application.action("back")
 
75
    }
 
76
    Connections {
 
77
        id: backConnection
 
78
        target: application.action("back")
 
79
        onTriggered: {
 
80
            resourceInstance.uri = ""
 
81
            fileBrowserRoot.goBack()
 
82
        }
 
83
    }
 
84
 
 
85
    tools: Item {
 
86
        width: parent.width
 
87
        height: childrenRect.height
 
88
 
 
89
        PlasmaCore.DataModel {
 
90
            id: devicesModel
 
91
            dataSource: hotplugSource
 
92
        }
 
93
 
 
94
        Row {
 
95
            id: devicesFlow
 
96
            spacing: 4
 
97
            anchors {
 
98
               // bottom: parent.bottom
 
99
               verticalCenter: parent.verticalCenter
 
100
               left: parent.left
 
101
            }
 
102
 
 
103
            property int itemCount: 1
 
104
            property string currentUdi
 
105
 
 
106
            Item {
 
107
                width: theme.largeIconSize
 
108
                height: width
 
109
                PlasmaComponents.ToolButton {
 
110
                    id: upButton
 
111
                    anchors.fill: parent
 
112
                    flat: false
 
113
                    iconSource: "go-up"
 
114
                    visible: currentUdi != "" &&
 
115
                        devicesSource.data[currentUdi] &&
 
116
                        dirModel.url.indexOf(devicesSource.data[currentUdi]["File Path"]) !== -1 &&
 
117
                        "file://" + devicesSource.data[currentUdi]["File Path"] !== dirModel.url
 
118
                    onClicked: dirModel.url = dirModel.url+"/.."
 
119
                }
 
120
            }
 
121
 
 
122
            PlasmaComponents.ToolButton {
 
123
                id: localButton
 
124
                width: theme.mediumIconSize + 10
 
125
                height: width
 
126
                iconSource: "drive-harddisk"
 
127
                checked: fileBrowserRoot.model == metadataModel
 
128
                onClicked: checked = true
 
129
                onCheckedChanged: {
 
130
                    if (checked) {
 
131
                        for (var i = 0; i < devicesFlow.children.length; ++i) {
 
132
                            var child = devicesFlow.children[i]
 
133
                            if (child != localButton && child.checked !== undefined) {
 
134
                                child.checked = false
 
135
                            }
 
136
                        }
 
137
                        for (child in devicesFlow.children) {
 
138
                            if (child != localButton) {
 
139
                                child.checked = false
 
140
                            }
 
141
                        }
 
142
                        fileBrowserRoot.model = metadataModel
 
143
                        //nepomuk db, not filesystem
 
144
                        resourceBrowser.currentUdi = ""
 
145
                    }
 
146
                }
 
147
                DropArea {
 
148
                    enabled: !parent.checked
 
149
                    anchors.fill: parent
 
150
                    onDragEnter: parent.flat = false
 
151
                    onDragLeave: parent.flat = true
 
152
                    onDrop: {
 
153
                        parent.flat = true
 
154
                        application.copy(event.mimeData.urls, "~")
 
155
                    }
 
156
                }
 
157
            }
 
158
 
 
159
 
 
160
            Repeater {
 
161
                id: devicesRepeater
 
162
                model: devicesModel
 
163
 
 
164
                delegate: PlasmaComponents.ToolButton {
 
165
                    id: removableButton
 
166
                    width: theme.mediumIconSize + 10
 
167
                    height: width
 
168
                    visible: devicesSource.data[udi]["Removable"] == true
 
169
                    iconSource: model["icon"]
 
170
                    onClicked: checked = true
 
171
                    onCheckedChanged: {
 
172
                        if (checked) {
 
173
                            for (var i = 0; i < devicesFlow.children.length; ++i) {
 
174
                                var child = devicesFlow.children[i]
 
175
                                if (child != removableButton && child.checked !== undefined) {
 
176
                                    child.checked = false
 
177
                                }
 
178
                            }
 
179
                            resourceBrowser.currentUdi = udi
 
180
 
 
181
                            if (devicesSource.data[udi]["Accessible"]) {
 
182
                                dirModel.url = devicesSource.data[udi]["File Path"]
 
183
 
 
184
                                fileBrowserRoot.model = dirModel
 
185
                            } else {
 
186
                                var service = devicesSource.serviceForSource(udi);
 
187
                                var operation = service.operationDescription("mount");
 
188
                                service.startOperationCall(operation);
 
189
                            }
 
190
                        }
 
191
                    }
 
192
                    DropArea {
 
193
                        enabled: !parent.checked
 
194
                        anchors.fill: parent
 
195
                        onDragEnter: parent.flat = false
 
196
                        onDragLeave: parent.flat = true
 
197
                        onDrop: {
 
198
                            application.copy(event.mimeData.urls, devicesSource.data[udi]["File Path"])
 
199
                            parent.flat = true
 
200
                        }
 
201
                    }
 
202
                }
 
203
            }
 
204
 
 
205
            PlasmaComponents.ToolButton {
 
206
                id: trashButton
 
207
                width: theme.mediumIconSize + 10
 
208
                height: width
 
209
                parent: devicesFlow
 
210
                iconSource: "user-trash"
 
211
                onClicked: checked = true
 
212
                onCheckedChanged: {
 
213
                    if (checked) {
 
214
                        for (var i = 0; i < devicesFlow.children.length; ++i) {
 
215
                            var child = devicesFlow.children[i]
 
216
                            if (child != trashButton && child.checked !== undefined) {
 
217
                                child.checked = false
 
218
                            }
 
219
                        }
 
220
                        resourceBrowser.currentUdi = ""
 
221
 
 
222
                        dirModel.url = "trash:/"
 
223
 
 
224
                        fileBrowserRoot.model = dirModel
 
225
                    }
 
226
                }
 
227
                DropArea {
 
228
                    enabled: !parent.checked
 
229
                    anchors.fill: parent
 
230
                    onDragEnter: parent.flat = false
 
231
                    onDragLeave: parent.flat = true
 
232
                    onDrop: {
 
233
                        parent.flat = true
 
234
                        application.trash(event.mimeData.urls)
 
235
                    }
 
236
                }
 
237
            }
 
238
        }
 
239
 
 
240
        MobileComponents.ViewSearch {
 
241
            id: searchBox
 
242
            anchors.centerIn: parent
 
243
            visible: fileBrowserRoot.model == metadataModel
 
244
 
 
245
            onSearchQueryChanged: {
 
246
                if (searchQuery.length > 3) {
 
247
                    // the "*" are needed for substring match.
 
248
                    metadataModel.extraParameters["nfo:fileName"] = "*" + searchBox.searchQuery + "*"
 
249
                } else {
 
250
                    metadataModel.extraParameters["nfo:fileName"] = ""
 
251
                }
 
252
            }
 
253
            busy: metadataModel.running
 
254
        }
 
255
 
 
256
        Item {
 
257
            width: childrenRect.width
 
258
            height: childrenRect.height
 
259
            clip: true
 
260
            anchors {
 
261
                right: emptyTrashButton.left
 
262
                bottom: parent.bottom
 
263
                bottomMargin: -4
 
264
                rightMargin: 4
 
265
            }
 
266
            PlasmaComponents.ButtonRow {
 
267
                z: 900
 
268
                y: sidebar.open ? 0 : height
 
269
                exclusive: true
 
270
                Behavior on y {
 
271
                    NumberAnimation {
 
272
                        duration: 250
 
273
                        easing.type: Easing.InOutQuad
 
274
                    }
 
275
                }
 
276
                SidebarTab {
 
277
                    id: mainTab
 
278
                    text: i18n("Filters")
 
279
                    onCheckedChanged: {
 
280
                        if (checked) {
 
281
                            while (sidebarStack.depth > 1) {
 
282
                                sidebarStack.pop()
 
283
                            }
 
284
                        }
 
285
                    }
 
286
                }
 
287
                SidebarTab {
 
288
                    text: i18n("Time")
 
289
                    enabled: fileBrowserRoot.model == metadataModel
 
290
                    opacity: enabled ? 1 : 0.6
 
291
                    onCheckedChanged: {
 
292
                        if (checked) {
 
293
                            if (sidebarStack.depth > 1) {
 
294
                                sidebarStack.replace(Qt.createComponent("TimelineSidebar.qml"))
 
295
                            } else {
 
296
                                sidebarStack.push(Qt.createComponent("TimelineSidebar.qml"))
 
297
                            }
 
298
                        }
 
299
                    }
 
300
                }
 
301
                SidebarTab {
 
302
                    text: i18n("Tags")
 
303
                    enabled: fileBrowserRoot.model == metadataModel
 
304
                    opacity: enabled ? 1 : 0.6
 
305
                    onCheckedChanged: {
 
306
                        print(checked)
 
307
                        if (checked) {
 
308
                            if (sidebarStack.depth > 1) {
 
309
                                sidebarStack.replace(Qt.createComponent("TagsBar.qml"))
 
310
                            } else {
 
311
                                sidebarStack.push(Qt.createComponent("TagsBar.qml"))
 
312
                            }
 
313
                        }
 
314
                    }
 
315
                }
 
316
            }
 
317
        }
 
318
 
 
319
        PlasmaComponents.ToolButton {
 
320
            id: emptyTrashButton
 
321
            width: theme.largeIconSize
 
322
            height: width
 
323
            anchors {
 
324
                right: parent.right
 
325
                verticalCenter: parent.verticalCenter
 
326
                rightMargin: y
 
327
            }
 
328
            visible: fileBrowserRoot.model == dirModel && dirModel.url == "trash:/"
 
329
            enabled: dirModel.count > 0
 
330
            iconSource: "trash-empty"
 
331
            onClicked: application.emptyTrash()
 
332
        }
 
333
    }
 
334
 
 
335
    ListModel {
 
336
        id: selectedModel
 
337
        signal modelCleared
 
338
    }
 
339
    Connections {
 
340
        target: metadataModel
 
341
        onModelReset: {
 
342
            selectedModel.clear()
 
343
            selectedModel.modelCleared()
 
344
        }
 
345
    }
 
346
 
 
347
    //BUG: For some reason onCountChanged doesn't get binded directly in ListModel
 
348
    Connections {
 
349
        target: selectedModel
 
350
        onCountChanged: {
 
351
            var newUrls = new Array()
 
352
            for (var i = 0; i < selectedModel.count; ++i) {
 
353
              newUrls[i] = selectedModel.get(i).url
 
354
            }
 
355
            dragArea.mimeData.urls = newUrls
 
356
        }
 
357
    }
 
358
    Connections {
 
359
        target: metadataModel
 
360
        onModelReset: selectedModel.clear()
 
361
    }
 
362
 
 
363
    Image {
 
364
        id: browserFrame
 
365
        z: 100
 
366
        source: "image://appbackgrounds/standard"
 
367
        fillMode: Image.Tile
 
368
        anchors {
 
369
            top: parent.top
 
370
            bottom: parent.bottom
 
371
        }
 
372
        width: parent.width
 
373
        x: 0
 
374
 
 
375
        //This pinch area is for selection
 
376
        PinchArea {
 
377
            id: pinchArea
 
378
            anchors {
 
379
                fill: parent
 
380
                leftMargin: 0
 
381
            }
 
382
            property bool selecting: false
 
383
            property int selectingX
 
384
            property int selectingY
 
385
            pinch.target: parent
 
386
 
 
387
            function resetSelection()
 
388
            {
 
389
                selectedModel.modelCleared()
 
390
                selectedModel.clear()
 
391
                selectionRect.x = -1
 
392
                selectionRect.y = -1
 
393
                selectionRect.width = 0
 
394
                selectionRect.height = 0
 
395
            }
 
396
 
 
397
            onPinchStarted: {
 
398
                //hotspot to start select procedures
 
399
                print("point1: " + pinch.point1.x + " " + pinch.point1.y)
 
400
                print("Selecting")
 
401
                selecting = true
 
402
                selectingX = pinch.point2.x
 
403
                selectingY = pinch.point2.y
 
404
                selectionRect.opacity = 0.4
 
405
            }
 
406
            onPinchUpdated: {
 
407
                //only one point
 
408
                if (pinch.point1.x == pinch.point2.x) {
 
409
                    return
 
410
                }
 
411
                selectionRect.x = Math.min(pinch.point1.x, pinch.point2.x)
 
412
                selectionRect.y = Math.min(pinch.point1.y, pinch.point2.y)
 
413
                selectionRect.width = Math.abs(pinch.point2.x - pinch.point1.x)
 
414
                selectionRect.height = Math.abs(pinch.point2.y - pinch.point1.y)
 
415
                if (selecting) {
 
416
                    print("Selected" + resultsGrid.childAt(pinch.point2.x, pinch.point2.y))
 
417
                    selectingX = pinch.point2.x
 
418
                    selectingY = pinch.point2.y
 
419
                }
 
420
            }
 
421
            onPinchFinished: {
 
422
                selectionRect.opacity = 0
 
423
                selecting = false
 
424
            }
 
425
 
 
426
            Rectangle {
 
427
                id: selectionRect
 
428
                color: theme.highlightColor
 
429
                opacity: 0.4
 
430
                Behavior on opacity {
 
431
                    NumberAnimation {
 
432
                        duration: 250
 
433
                        easing.type: Easing.InOutQuad
 
434
                    }
 
435
                }
 
436
            }
 
437
            DragArea {
 
438
                id: dragArea
 
439
                anchors.fill: parent
 
440
                //startDragDistance: 200
 
441
                enabled: false
 
442
                mimeData {
 
443
                    source: parent
 
444
                }
 
445
                onDrop: enabled = false
 
446
                MouseEventListener {
 
447
                    anchors.fill: parent
 
448
                    onPressed: startY = mouse.y
 
449
                    onPositionChanged: {
 
450
                        if (selectedModel.count > 0 && Math.abs(mouse.y - startY) > 200) {
 
451
                            dragArea.enabled = true
 
452
                        }
 
453
                    }
 
454
 
 
455
                    Connections {
 
456
                        target: fileBrowserRoot.model
 
457
                        onCountChanged: pinchArea.resetSelection()
 
458
                        onModelReset: pinchArea.resetSelection()
 
459
                    }
 
460
                    MobileComponents.IconGrid {
 
461
                        id: resultsGrid
 
462
                        anchors.fill: parent
 
463
 
 
464
                        model: fileBrowserRoot.model
 
465
                        onCurrentPageChanged: pinchArea.resetSelection()
 
466
 
 
467
                        delegate: Item {
 
468
                            id: resourceDelegate
 
469
                            width: resultsGrid.delegateWidth
 
470
                            height: resultsGrid.delegateHeight
 
471
 
 
472
                            PlasmaCore.FrameSvgItem {
 
473
                                id: highlightFrame
 
474
                                imagePath: "widgets/viewitem"
 
475
                                prefix: "selected+hover"
 
476
                                anchors.fill: parent
 
477
 
 
478
                                property bool contains: resourceDelegate.x+resourceDelegate.width > selectionRect.x && resourceDelegate.y+resourceDelegate.height > selectionRect.y && resourceDelegate.x < selectionRect.x+selectionRect.width && resourceDelegate.y < selectionRect.y+selectionRect.height
 
479
                                opacity: 0
 
480
                                /*Behavior on opacity {
 
481
                                    NumberAnimation {duration: 250}
 
482
                                }*/
 
483
                                onContainsChanged: {
 
484
                                    if (contains) {
 
485
                                        selectedModel.append({"url": model.url})
 
486
                                        opacity = 1
 
487
                                    } else {
 
488
                                        for (var i = 0; i < selectedModel.count; ++i) {
 
489
                                            if ((model.url && model.url == selectedModel.get(i).url)) {
 
490
                                                opacity = 0
 
491
                                                selectedModel.remove(i)
 
492
                                                return
 
493
                                            }
 
494
                                        }
 
495
                                    }
 
496
                                }
 
497
                            }
 
498
                            Connections {
 
499
                                target: selectedModel
 
500
                                onModelCleared: highlightFrame.opacity = 0
 
501
                            }
 
502
                            MobileComponents.ResourceDelegate {
 
503
                                className: model["className"] ? model["className"] : ""
 
504
                                genericClassName: (resultsGrid.model == metadataModel) ? (model["genericClassName"] ? model["genericClassName"] : "") : "FileDataObject"
 
505
 
 
506
                                property string label: model.label ? model.label : model.display
 
507
 
 
508
                                width: resultsGrid.delegateWidth
 
509
                                height: resultsGrid.delegateHeight
 
510
                                onPressAndHold: {
 
511
                                    resourceInstance.uri = model["url"] ? model["url"] : model["resourceUri"]
 
512
                                    resourceInstance.title = model["label"]
 
513
                                    if (highlightFrame.opacity == 1) {
 
514
                                        for (var i = 0; i < selectedModel.count; ++i) {
 
515
                                            if ((model.url && model.url == selectedModel.get(i).url)) {
 
516
                                                highlightFrame.opacity = 0
 
517
                                                selectedModel.remove(i)
 
518
                                                return
 
519
                                            }
 
520
                                        }
 
521
                                    } else {
 
522
                                        highlightFrame.opacity = 1
 
523
                                        selectedModel.append({"url": model.url})
 
524
                                    }
 
525
                                }
 
526
                                onClicked: openFile(model["url"], mimeType)
 
527
                            }
 
528
                            Component.onCompleted: {
 
529
                                for (var i = 0; i < selectedModel.count; ++i) {
 
530
                                    if ((model.url && model.url == selectedModel.get(i).url)) {
 
531
                                        highlightFrame.opacity = 1
 
532
                                        return
 
533
                                    }
 
534
                                }
 
535
                            }
 
536
                        }
 
537
                    }
 
538
                }
 
539
            }
 
540
        }
 
541
        Image {
 
542
            source: "image://appbackgrounds/shadow-right"
 
543
            fillMode: Image.TileVertically
 
544
            anchors {
 
545
                left: parent.right
 
546
                top: parent.top
 
547
                bottom: parent.bottom
 
548
                leftMargin: -1
 
549
            }
 
550
        }
 
551
        PlasmaCore.FrameSvgItem {
 
552
            id: handleGraphics
 
553
            imagePath: "dialogs/background"
 
554
            enabledBorders: "LeftBorder|TopBorder|BottomBorder"
 
555
            width: handleIcon.width + margins.left + margins.right + 4
 
556
            height: handleIcon.width * 1.6 + margins.top + margins.bottom + 4
 
557
            anchors {
 
558
                right: parent.right
 
559
                verticalCenter: parent.verticalCenter
 
560
            }
 
561
 
 
562
            //TODO: an icon
 
563
            PlasmaCore.SvgItem {
 
564
                id: handleIcon
 
565
                svg: PlasmaCore.Svg {imagePath: "toolbar-icons/show"}
 
566
                elementId: "show-menu"
 
567
                x: parent.margins.left
 
568
                y: parent.margins.top
 
569
                width: theme.smallMediumIconSize
 
570
                height: width
 
571
                anchors.verticalCenter: parent.verticalCenter
 
572
            }
 
573
        }
 
574
        MouseArea {
 
575
            anchors {
 
576
                top: parent.top
 
577
                bottom: parent.bottom
 
578
                left: handleGraphics.left
 
579
                right: handleGraphics.right
 
580
            }
 
581
            drag {
 
582
                target: browserFrame
 
583
                axis: Drag.XAxis
 
584
                //-50, an overshoot to make it look smooter
 
585
                minimumX: -sidebar.width - 50
 
586
                maximumX: 0
 
587
            }
 
588
            property int startX
 
589
            property bool toggle: true
 
590
            onPressed: {
 
591
                startX = browserFrame.x
 
592
                toggle = true
 
593
            }
 
594
            onPositionChanged: {
 
595
                if (Math.abs(browserFrame.x - startX) > 20) {
 
596
                    toggle = false
 
597
                }
 
598
            }
 
599
            onReleased: {
 
600
                if (toggle) {
 
601
                    sidebar.open = !sidebar.open
 
602
                } else {
 
603
                    sidebar.open = (browserFrame.x < -sidebar.width/2)
 
604
                }
 
605
                sidebarSlideAnimation.to = sidebar.open ? -sidebar.width : 0
 
606
                sidebarSlideAnimation.running = true
 
607
            }
 
608
        }
 
609
        //FIXME: use a state machine
 
610
        SequentialAnimation {
 
611
            id: sidebarSlideAnimation
 
612
            property alias to: actualSlideAnimation.to
 
613
            NumberAnimation {
 
614
                id: actualSlideAnimation
 
615
                target: browserFrame
 
616
                properties: "x"
 
617
                duration: 250
 
618
                easing.type: Easing.InOutQuad
 
619
            }
 
620
            ScriptAction {
 
621
                script: pinchArea.anchors.leftMargin = -browserFrame.x
 
622
            }
 
623
        }
 
624
    }
 
625
 
 
626
    Item {
 
627
        id: sidebar
 
628
 
 
629
        property bool open: false
 
630
 
 
631
        width: parent.width/4
 
632
        x: parent.width - width
 
633
        Behavior on width {
 
634
            NumberAnimation {
 
635
                duration: 250
 
636
                easing.type: Easing.InOutQuad
 
637
            }
 
638
        }
 
639
        anchors {
 
640
            top: parent.top
 
641
            bottom: parent.bottom
 
642
        }
 
643
 
 
644
        Item {
 
645
            anchors.fill: parent
 
646
            clip: true
 
647
            PlasmaComponents.PageStack {
 
648
                id: sidebarStack
 
649
                width: fileBrowserRoot.width/4 - theme.defaultFont.mSize.width * 2
 
650
                initialPage: Qt.createComponent("CategorySidebar.qml")
 
651
                anchors {
 
652
                    left: parent.left
 
653
                    top: parent.top
 
654
                    bottom: parent.bottom
 
655
                    bottomMargin: 0
 
656
                    topMargin: toolBar.height
 
657
                    leftMargin: theme.defaultFont.mSize.width * 2
 
658
                    rightMargin: theme.defaultFont.mSize.width
 
659
                }
 
660
            }
 
661
        }
 
662
    }
 
663
 
 
664
    Image {
 
665
        source: "image://appbackgrounds/shadow-bottom"
 
666
        fillMode: Image.TileHorizontally
 
667
        opacity: 0.8
 
668
        anchors {
 
669
            left: parent.left
 
670
            top: toolBar.bottom
 
671
            right: parent.right
 
672
            topMargin: -2
 
673
        }
 
674
    }
 
675
 
 
676
    ParallelAnimation {
 
677
        id: positionAnim
 
678
        property Item target
 
679
        property int x
 
680
        property int y
 
681
        NumberAnimation {
 
682
            target: positionAnim.target
 
683
            to: positionAnim.y
 
684
            properties: "y"
 
685
 
 
686
            duration: 250
 
687
            easing.type: Easing.InOutQuad
 
688
        }
 
689
        NumberAnimation {
 
690
            target: positionAnim.target
 
691
            to: positionAnim.x
 
692
            properties: "x"
 
693
 
 
694
            duration: 250
 
695
            easing.type: Easing.InOutQuad
 
696
        }
 
697
    }
 
698
}
 
699