2
* Copyright 2011 Marco Martin <mart@kde.org>
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.
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
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.
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
29
PlasmaComponents.Page {
31
objectName: "resourceBrowser"
32
property string currentUdi
35
topMargin: toolBar.height
38
PlasmaCore.DataSource {
41
connectedSources: sources
43
PlasmaCore.DataSource {
46
connectedSources: hotplugSource.sources
48
//access it here due to the async nature of the dataengine
49
if (resultsGrid.model == dirModel) {
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
62
} else if (resultsGrid.model != dirModel && devicesSource.data[resourceBrowser.currentUdi]["File Path"] != "") {
63
dirModel.url = devicesSource.data[resourceBrowser.currentUdi]["File Path"]
65
fileBrowserRoot.model = dirModel
70
//FIXME: this will have to be removed
74
onTriggered: backConnection.target = application.action("back")
78
target: application.action("back")
80
resourceInstance.uri = ""
81
fileBrowserRoot.goBack()
87
height: childrenRect.height
89
PlasmaCore.DataModel {
91
dataSource: hotplugSource
98
// bottom: parent.bottom
99
verticalCenter: parent.verticalCenter
103
property int itemCount: 1
104
property string currentUdi
107
width: theme.largeIconSize
109
PlasmaComponents.ToolButton {
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+"/.."
122
PlasmaComponents.ToolButton {
124
width: theme.mediumIconSize + 10
126
iconSource: "drive-harddisk"
127
checked: fileBrowserRoot.model == metadataModel
128
onClicked: checked = true
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
137
for (child in devicesFlow.children) {
138
if (child != localButton) {
139
child.checked = false
142
fileBrowserRoot.model = metadataModel
143
//nepomuk db, not filesystem
144
resourceBrowser.currentUdi = ""
148
enabled: !parent.checked
150
onDragEnter: parent.flat = false
151
onDragLeave: parent.flat = true
154
application.copy(event.mimeData.urls, "~")
164
delegate: PlasmaComponents.ToolButton {
166
width: theme.mediumIconSize + 10
168
visible: devicesSource.data[udi]["Removable"] == true
169
iconSource: model["icon"]
170
onClicked: checked = true
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
179
resourceBrowser.currentUdi = udi
181
if (devicesSource.data[udi]["Accessible"]) {
182
dirModel.url = devicesSource.data[udi]["File Path"]
184
fileBrowserRoot.model = dirModel
186
var service = devicesSource.serviceForSource(udi);
187
var operation = service.operationDescription("mount");
188
service.startOperationCall(operation);
193
enabled: !parent.checked
195
onDragEnter: parent.flat = false
196
onDragLeave: parent.flat = true
198
application.copy(event.mimeData.urls, devicesSource.data[udi]["File Path"])
205
PlasmaComponents.ToolButton {
207
width: theme.mediumIconSize + 10
210
iconSource: "user-trash"
211
onClicked: checked = true
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
220
resourceBrowser.currentUdi = ""
222
dirModel.url = "trash:/"
224
fileBrowserRoot.model = dirModel
228
enabled: !parent.checked
230
onDragEnter: parent.flat = false
231
onDragLeave: parent.flat = true
234
application.trash(event.mimeData.urls)
240
MobileComponents.ViewSearch {
242
anchors.centerIn: parent
243
visible: fileBrowserRoot.model == metadataModel
245
onSearchQueryChanged: {
246
if (searchQuery.length > 3) {
247
// the "*" are needed for substring match.
248
metadataModel.extraParameters["nfo:fileName"] = "*" + searchBox.searchQuery + "*"
250
metadataModel.extraParameters["nfo:fileName"] = ""
253
busy: metadataModel.running
257
width: childrenRect.width
258
height: childrenRect.height
261
right: emptyTrashButton.left
262
bottom: parent.bottom
266
PlasmaComponents.ButtonRow {
268
y: sidebar.open ? 0 : height
273
easing.type: Easing.InOutQuad
278
text: i18n("Filters")
281
while (sidebarStack.depth > 1) {
289
enabled: fileBrowserRoot.model == metadataModel
290
opacity: enabled ? 1 : 0.6
293
if (sidebarStack.depth > 1) {
294
sidebarStack.replace(Qt.createComponent("TimelineSidebar.qml"))
296
sidebarStack.push(Qt.createComponent("TimelineSidebar.qml"))
303
enabled: fileBrowserRoot.model == metadataModel
304
opacity: enabled ? 1 : 0.6
308
if (sidebarStack.depth > 1) {
309
sidebarStack.replace(Qt.createComponent("TagsBar.qml"))
311
sidebarStack.push(Qt.createComponent("TagsBar.qml"))
319
PlasmaComponents.ToolButton {
321
width: theme.largeIconSize
325
verticalCenter: parent.verticalCenter
328
visible: fileBrowserRoot.model == dirModel && dirModel.url == "trash:/"
329
enabled: dirModel.count > 0
330
iconSource: "trash-empty"
331
onClicked: application.emptyTrash()
340
target: metadataModel
342
selectedModel.clear()
343
selectedModel.modelCleared()
347
//BUG: For some reason onCountChanged doesn't get binded directly in ListModel
349
target: selectedModel
351
var newUrls = new Array()
352
for (var i = 0; i < selectedModel.count; ++i) {
353
newUrls[i] = selectedModel.get(i).url
355
dragArea.mimeData.urls = newUrls
359
target: metadataModel
360
onModelReset: selectedModel.clear()
366
source: "image://appbackgrounds/standard"
370
bottom: parent.bottom
375
//This pinch area is for selection
382
property bool selecting: false
383
property int selectingX
384
property int selectingY
387
function resetSelection()
389
selectedModel.modelCleared()
390
selectedModel.clear()
393
selectionRect.width = 0
394
selectionRect.height = 0
398
//hotspot to start select procedures
399
print("point1: " + pinch.point1.x + " " + pinch.point1.y)
402
selectingX = pinch.point2.x
403
selectingY = pinch.point2.y
404
selectionRect.opacity = 0.4
408
if (pinch.point1.x == pinch.point2.x) {
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)
416
print("Selected" + resultsGrid.childAt(pinch.point2.x, pinch.point2.y))
417
selectingX = pinch.point2.x
418
selectingY = pinch.point2.y
422
selectionRect.opacity = 0
428
color: theme.highlightColor
430
Behavior on opacity {
433
easing.type: Easing.InOutQuad
440
//startDragDistance: 200
445
onDrop: enabled = false
448
onPressed: startY = mouse.y
450
if (selectedModel.count > 0 && Math.abs(mouse.y - startY) > 200) {
451
dragArea.enabled = true
456
target: fileBrowserRoot.model
457
onCountChanged: pinchArea.resetSelection()
458
onModelReset: pinchArea.resetSelection()
460
MobileComponents.IconGrid {
464
model: fileBrowserRoot.model
465
onCurrentPageChanged: pinchArea.resetSelection()
469
width: resultsGrid.delegateWidth
470
height: resultsGrid.delegateHeight
472
PlasmaCore.FrameSvgItem {
474
imagePath: "widgets/viewitem"
475
prefix: "selected+hover"
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
480
/*Behavior on opacity {
481
NumberAnimation {duration: 250}
485
selectedModel.append({"url": model.url})
488
for (var i = 0; i < selectedModel.count; ++i) {
489
if ((model.url && model.url == selectedModel.get(i).url)) {
491
selectedModel.remove(i)
499
target: selectedModel
500
onModelCleared: highlightFrame.opacity = 0
502
MobileComponents.ResourceDelegate {
503
className: model["className"] ? model["className"] : ""
504
genericClassName: (resultsGrid.model == metadataModel) ? (model["genericClassName"] ? model["genericClassName"] : "") : "FileDataObject"
506
property string label: model.label ? model.label : model.display
508
width: resultsGrid.delegateWidth
509
height: resultsGrid.delegateHeight
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)
522
highlightFrame.opacity = 1
523
selectedModel.append({"url": model.url})
526
onClicked: openFile(model["url"], mimeType)
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
542
source: "image://appbackgrounds/shadow-right"
543
fillMode: Image.TileVertically
547
bottom: parent.bottom
551
PlasmaCore.FrameSvgItem {
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
559
verticalCenter: parent.verticalCenter
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
571
anchors.verticalCenter: parent.verticalCenter
577
bottom: parent.bottom
578
left: handleGraphics.left
579
right: handleGraphics.right
584
//-50, an overshoot to make it look smooter
585
minimumX: -sidebar.width - 50
589
property bool toggle: true
591
startX = browserFrame.x
595
if (Math.abs(browserFrame.x - startX) > 20) {
601
sidebar.open = !sidebar.open
603
sidebar.open = (browserFrame.x < -sidebar.width/2)
605
sidebarSlideAnimation.to = sidebar.open ? -sidebar.width : 0
606
sidebarSlideAnimation.running = true
609
//FIXME: use a state machine
610
SequentialAnimation {
611
id: sidebarSlideAnimation
612
property alias to: actualSlideAnimation.to
614
id: actualSlideAnimation
618
easing.type: Easing.InOutQuad
621
script: pinchArea.anchors.leftMargin = -browserFrame.x
629
property bool open: false
631
width: parent.width/4
632
x: parent.width - width
636
easing.type: Easing.InOutQuad
641
bottom: parent.bottom
647
PlasmaComponents.PageStack {
649
width: fileBrowserRoot.width/4 - theme.defaultFont.mSize.width * 2
650
initialPage: Qt.createComponent("CategorySidebar.qml")
654
bottom: parent.bottom
656
topMargin: toolBar.height
657
leftMargin: theme.defaultFont.mSize.width * 2
658
rightMargin: theme.defaultFont.mSize.width
665
source: "image://appbackgrounds/shadow-bottom"
666
fillMode: Image.TileHorizontally
682
target: positionAnim.target
687
easing.type: Easing.InOutQuad
690
target: positionAnim.target
695
easing.type: Easing.InOutQuad