2018-05-20 01:54:08 +02:00
|
|
|
import QtQuick 2.4
|
|
|
|
import QtQuick.Layouts 1.2
|
|
|
|
import QtQml.Models 2.2
|
2018-09-02 19:09:16 +02:00
|
|
|
import QtQuick.Controls 2.4 as Controls
|
2018-06-12 21:32:44 +02:00
|
|
|
import org.kde.kirigami 2.5 as Kirigami
|
2018-05-20 01:54:08 +02:00
|
|
|
|
|
|
|
Kirigami.ScrollablePage {
|
|
|
|
id: page
|
2018-06-14 23:19:28 +02:00
|
|
|
property var main: undefined
|
2018-06-12 21:32:44 +02:00
|
|
|
property alias entryModel: delegateModel.model
|
2018-05-20 01:54:08 +02:00
|
|
|
property alias rootIndex: delegateModel.rootIndex
|
|
|
|
|
|
|
|
Layout.fillWidth: true
|
2018-09-16 21:37:30 +02:00
|
|
|
title: {
|
|
|
|
var currentEntryName = entryModel.data(rootIndex)
|
|
|
|
return currentEntryName ? currentEntryName : ""
|
|
|
|
}
|
2018-05-20 01:54:08 +02:00
|
|
|
actions {
|
|
|
|
main: Kirigami.Action {
|
|
|
|
iconName: "list-add"
|
|
|
|
text: qsTr("Add account")
|
2018-09-16 21:37:30 +02:00
|
|
|
visible: !nativeInterface.hasEntryFilter
|
|
|
|
enabled: !nativeInterface.hasEntryFilter
|
2018-06-11 23:21:15 +02:00
|
|
|
onTriggered: insertEntry("Account")
|
2018-09-10 20:43:58 +02:00
|
|
|
shortcut: "Ctrl+A"
|
2018-05-20 01:54:08 +02:00
|
|
|
}
|
|
|
|
left: Kirigami.Action {
|
|
|
|
iconName: "edit-paste"
|
|
|
|
text: qsTr("Paste account")
|
2018-09-16 21:37:30 +02:00
|
|
|
visible: !nativeInterface.hasEntryFilter
|
|
|
|
enabled: nativeInterface.canPaste && !nativeInterface.hasEntryFilter
|
2018-06-12 22:20:43 +02:00
|
|
|
onTriggered: {
|
|
|
|
var pastedEntries = nativeInterface.pasteEntries(rootIndex)
|
|
|
|
if (pastedEntries.length < 1) {
|
|
|
|
showPassiveNotification(
|
|
|
|
qsTr("Unable to paste the entries here"))
|
|
|
|
return
|
|
|
|
}
|
2018-06-14 23:46:18 +02:00
|
|
|
showPassiveNotification(
|
|
|
|
qsTr("Pasted ") + pastedEntries.join(", "))
|
2018-06-12 22:20:43 +02:00
|
|
|
}
|
2018-09-10 20:43:58 +02:00
|
|
|
shortcut: StandardKey.Paste
|
2018-05-20 01:54:08 +02:00
|
|
|
}
|
|
|
|
right: Kirigami.Action {
|
|
|
|
iconName: "folder-add"
|
|
|
|
text: qsTr("Add category")
|
2018-09-16 21:37:30 +02:00
|
|
|
visible: !nativeInterface.hasEntryFilter
|
|
|
|
enabled: !nativeInterface.hasEntryFilter
|
2018-06-11 23:21:15 +02:00
|
|
|
onTriggered: insertEntry("Node")
|
2018-09-10 20:43:58 +02:00
|
|
|
shortcut: "Ctrl+Shift+A"
|
2018-05-20 01:54:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
background: Rectangle {
|
|
|
|
color: Kirigami.Theme.backgroundColor
|
|
|
|
}
|
|
|
|
|
2018-06-12 22:02:37 +02:00
|
|
|
// dialog to confirm deletion of an entry
|
2018-06-10 22:39:33 +02:00
|
|
|
BasicDialog {
|
|
|
|
id: confirmDeletionDialog
|
2018-06-11 23:21:15 +02:00
|
|
|
|
2018-06-10 22:39:33 +02:00
|
|
|
property string entryDesc: "?"
|
|
|
|
property int entryIndex: -1
|
2018-06-11 23:21:15 +02:00
|
|
|
|
2018-06-10 22:39:33 +02:00
|
|
|
standardButtons: Controls.Dialog.Ok | Controls.Dialog.Cancel
|
|
|
|
title: qsTr("Delete %1?").arg(entryDesc)
|
2018-06-12 21:32:44 +02:00
|
|
|
onAccepted: entryModel.removeRows(this.entryIndex, 1, rootIndex)
|
2018-06-10 22:39:33 +02:00
|
|
|
|
2018-11-22 22:00:31 +01:00
|
|
|
ColumnLayout {
|
|
|
|
Controls.Label {
|
|
|
|
text: " "
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-10 22:39:33 +02:00
|
|
|
function confirmDeletion(entryName, entryIndex) {
|
2018-11-22 22:09:54 +01:00
|
|
|
// skip if undo is supported
|
|
|
|
if (nativeInterface.undoStack) {
|
|
|
|
entryModel.removeRows(entryIndex, 1, rootIndex)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-06-12 21:32:44 +02:00
|
|
|
var isNode = entryModel.isNode(entryModel.index(entryIndex, 0,
|
|
|
|
rootIndex))
|
2018-06-10 22:39:33 +02:00
|
|
|
var entryType = isNode ? qsTr("category ") : qsTr("account ")
|
|
|
|
|
|
|
|
this.entryIndex = entryIndex
|
|
|
|
this.entryDesc = entryType + entryName
|
|
|
|
this.open()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-12 22:02:37 +02:00
|
|
|
// dialog to rename an entry
|
2018-06-10 22:39:33 +02:00
|
|
|
BasicDialog {
|
|
|
|
id: renameDialog
|
|
|
|
property string entryDesc: "?"
|
|
|
|
property int entryIndex: -1
|
|
|
|
property alias newEntryName: entryNameTextField.text
|
2018-06-11 23:21:15 +02:00
|
|
|
property bool entryNew: false
|
|
|
|
|
2018-06-10 22:39:33 +02:00
|
|
|
standardButtons: newEntryName.length
|
|
|
|
> 0 ? Controls.Dialog.Ok | Controls.Dialog.Cancel : Controls.Dialog.Cancel
|
2018-06-11 23:21:15 +02:00
|
|
|
title: (entryNew ? qsTr("Name for new ") : qsTr("Rename ")) + entryDesc
|
|
|
|
onAccepted: {
|
2018-06-12 21:32:44 +02:00
|
|
|
entryModel.setData(entryModel.index(this.entryIndex, 0, rootIndex),
|
|
|
|
newEntryName)
|
2018-06-11 23:21:15 +02:00
|
|
|
}
|
|
|
|
onRejected: {
|
|
|
|
if (this.entryNew) {
|
2018-06-12 21:32:44 +02:00
|
|
|
entryModel.removeRows(this.entryIndex, 1, rootIndex)
|
2018-06-11 23:21:15 +02:00
|
|
|
}
|
|
|
|
}
|
2018-06-10 22:39:33 +02:00
|
|
|
|
|
|
|
ColumnLayout {
|
|
|
|
Controls.TextField {
|
|
|
|
id: entryNameTextField
|
|
|
|
Layout.preferredWidth: renameDialog.availableWidth
|
|
|
|
placeholderText: qsTr("enter new name here")
|
2018-09-10 20:43:58 +02:00
|
|
|
Keys.onPressed: renameDialog.acceptOnReturn(event)
|
2018-06-10 22:39:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function renameEntry(entryName, entryIndex) {
|
2018-06-12 21:32:44 +02:00
|
|
|
var isNode = entryModel.isNode(entryModel.index(entryIndex, 0,
|
|
|
|
rootIndex))
|
2018-06-10 22:39:33 +02:00
|
|
|
var entryType = isNode ? qsTr("category ") : qsTr("account ")
|
|
|
|
|
|
|
|
this.entryIndex = entryIndex
|
2018-06-11 23:21:15 +02:00
|
|
|
this.entryNew = entryName === null
|
|
|
|
if (this.entryNew) {
|
|
|
|
this.entryDesc = entryType
|
|
|
|
this.newEntryName = ""
|
|
|
|
} else {
|
|
|
|
this.entryDesc = entryType + entryName
|
|
|
|
this.newEntryName = entryName
|
|
|
|
}
|
2018-09-10 19:53:54 +02:00
|
|
|
entryNameTextField.forceActiveFocus()
|
2018-06-10 22:39:33 +02:00
|
|
|
this.open()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-12 22:02:37 +02:00
|
|
|
// component representing an entry
|
2018-06-12 21:32:44 +02:00
|
|
|
Component {
|
|
|
|
id: listDelegateComponent
|
|
|
|
|
|
|
|
Kirigami.SwipeListItem {
|
|
|
|
id: listItem
|
|
|
|
contentItem: RowLayout {
|
|
|
|
Kirigami.ListItemDragHandle {
|
|
|
|
listItem: listItem
|
|
|
|
listView: entriesListView
|
2018-09-16 21:37:30 +02:00
|
|
|
enabled: !nativeInterface.hasEntryFilter
|
2018-09-02 19:04:28 +02:00
|
|
|
// FIXME: not sure why newIndex + 1 is required to be able to move a row at the end
|
|
|
|
onMoveRequested: entryModel.moveRows(
|
|
|
|
rootIndex, oldIndex, 1, rootIndex,
|
|
|
|
oldIndex < newIndex ? newIndex + 1 : newIndex)
|
2018-06-12 21:32:44 +02:00
|
|
|
}
|
2018-09-02 19:09:16 +02:00
|
|
|
Item {
|
2018-06-12 21:32:44 +02:00
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.fillHeight: true
|
2018-09-02 19:09:16 +02:00
|
|
|
RowLayout {
|
|
|
|
anchors.fill: parent
|
|
|
|
Kirigami.Icon {
|
|
|
|
width: Kirigami.Units.iconSizes.smallMedium
|
|
|
|
height: Kirigami.Units.iconSizes.smallMedium
|
|
|
|
Layout.fillHeight: true
|
|
|
|
source: delegateModel.isNode(
|
|
|
|
index) ? "folder-symbolic" : "story-editor"
|
|
|
|
}
|
|
|
|
Controls.Label {
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.fillHeight: true
|
|
|
|
text: model.name
|
|
|
|
}
|
|
|
|
}
|
2018-06-12 21:32:44 +02:00
|
|
|
MouseArea {
|
|
|
|
anchors.fill: parent
|
2018-09-02 19:09:16 +02:00
|
|
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
|
|
onClicked: {
|
|
|
|
if (mouse.button === Qt.RightButton) {
|
|
|
|
entryContextMenu.popup()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
delegateModel.handleEntryClicked(index, model.name)
|
|
|
|
}
|
|
|
|
onPressAndHold: entryContextMenu.popup()
|
|
|
|
}
|
|
|
|
Controls.Menu {
|
|
|
|
id: entryContextMenu
|
|
|
|
Controls.MenuItem {
|
|
|
|
icon.name: "edit-cut"
|
|
|
|
text: qsTr("Cut")
|
2018-09-16 21:37:30 +02:00
|
|
|
enabled: !nativeInterface.hasEntryFilter
|
2018-09-02 19:09:16 +02:00
|
|
|
onTriggered: {
|
|
|
|
nativeInterface.cutEntry(
|
|
|
|
entryModel.index(index, 0,
|
|
|
|
rootIndex))
|
|
|
|
showPassiveNotification(text + " " + model.name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Controls.MenuItem {
|
|
|
|
icon.name: "edit-delete"
|
|
|
|
text: qsTr("Delete")
|
2018-09-16 21:37:30 +02:00
|
|
|
enabled: !nativeInterface.hasEntryFilter
|
2018-09-02 19:09:16 +02:00
|
|
|
onTriggered: confirmDeletionDialog.confirmDeletion(
|
|
|
|
model.name, index)
|
|
|
|
}
|
|
|
|
Controls.MenuItem {
|
|
|
|
icon.name: "edit-rename"
|
|
|
|
text: qsTr("Rename")
|
2018-09-16 21:37:30 +02:00
|
|
|
enabled: !nativeInterface.hasEntryFilter
|
2018-09-02 19:09:16 +02:00
|
|
|
onTriggered: renameDialog.renameEntry(model.name,
|
|
|
|
index)
|
|
|
|
}
|
2018-06-12 21:32:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
actions: [
|
|
|
|
Kirigami.Action {
|
|
|
|
iconName: "edit-cut"
|
|
|
|
text: qsTr("Cut")
|
2018-09-16 21:37:30 +02:00
|
|
|
enabled: !nativeInterface.hasEntryFilter
|
2018-06-12 21:32:44 +02:00
|
|
|
onTriggered: {
|
|
|
|
nativeInterface.cutEntry(entryModel.index(index, 0,
|
|
|
|
rootIndex))
|
2018-06-12 22:02:37 +02:00
|
|
|
showPassiveNotification(text + " " + model.name)
|
2018-06-12 21:32:44 +02:00
|
|
|
}
|
2018-09-10 20:43:58 +02:00
|
|
|
shortcut: StandardKey.Cut
|
2018-06-12 21:32:44 +02:00
|
|
|
},
|
|
|
|
Kirigami.Action {
|
|
|
|
iconName: "edit-delete"
|
|
|
|
text: qsTr("Delete")
|
2018-09-16 21:37:30 +02:00
|
|
|
enabled: !nativeInterface.hasEntryFilter
|
2018-06-12 22:02:37 +02:00
|
|
|
onTriggered: confirmDeletionDialog.confirmDeletion(
|
|
|
|
model.name, index)
|
2018-09-10 20:43:58 +02:00
|
|
|
shortcut: StandardKey.Delete
|
2018-06-12 21:32:44 +02:00
|
|
|
},
|
|
|
|
Kirigami.Action {
|
|
|
|
iconName: "edit-rename"
|
|
|
|
text: qsTr("Rename")
|
2018-09-16 21:37:30 +02:00
|
|
|
enabled: !nativeInterface.hasEntryFilter
|
2018-06-12 22:02:37 +02:00
|
|
|
onTriggered: renameDialog.renameEntry(model.name, index)
|
2018-09-10 20:43:58 +02:00
|
|
|
shortcut: "F2"
|
2018-06-12 21:32:44 +02:00
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-20 01:54:08 +02:00
|
|
|
// list view to display one hierarchy level of entry model
|
|
|
|
ListView {
|
2018-06-12 21:32:44 +02:00
|
|
|
id: entriesListView
|
2018-06-12 22:02:37 +02:00
|
|
|
anchors.fill: parent
|
2018-06-14 23:46:18 +02:00
|
|
|
moveDisplaced: Transition {
|
|
|
|
YAnimator {
|
|
|
|
duration: Kirigami.Units.longDuration
|
|
|
|
easing.type: Easing.InOutQuad
|
|
|
|
}
|
|
|
|
}
|
2018-05-20 01:54:08 +02:00
|
|
|
model: DelegateModel {
|
|
|
|
id: delegateModel
|
|
|
|
|
2018-06-14 23:46:18 +02:00
|
|
|
delegate: Kirigami.DelegateRecycler {
|
|
|
|
width: parent ? parent.width : implicitWidth
|
|
|
|
sourceComponent: listDelegateComponent
|
|
|
|
}
|
|
|
|
|
2018-05-20 01:54:08 +02:00
|
|
|
function isNode(rowNumber) {
|
2018-06-12 21:32:44 +02:00
|
|
|
return entryModel.isNode(entryModel.index(rowNumber, 0,
|
|
|
|
rootIndex))
|
2018-05-20 01:54:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function handleEntryClicked(rowNumber, entryName) {
|
2018-06-12 21:32:44 +02:00
|
|
|
var modelIndex = entryModel.index(rowNumber, 0, rootIndex)
|
|
|
|
if (entryModel.isNode(modelIndex)) {
|
|
|
|
root.pushStackEntry(entryModel, modelIndex)
|
2018-05-20 01:54:08 +02:00
|
|
|
} else {
|
|
|
|
nativeInterface.currentAccountIndex = modelIndex
|
2018-09-09 01:49:32 +02:00
|
|
|
root.pushAccountEdit()
|
2018-05-20 01:54:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-06-11 23:21:15 +02:00
|
|
|
|
|
|
|
function insertEntry(entryType) {
|
2018-06-12 21:32:44 +02:00
|
|
|
var newIndex = entryModel.rowCount(rootIndex)
|
|
|
|
entryModel["setInsertTypeTo" + entryType]()
|
|
|
|
entryModel.insertRows(newIndex, 1, rootIndex)
|
2018-06-11 23:21:15 +02:00
|
|
|
renameDialog.renameEntry(null, newIndex)
|
|
|
|
}
|
2018-05-20 01:54:08 +02:00
|
|
|
}
|