fix(glossary): handle save errors and improve playlist controls
This commit is contained in:
1 parent
3d8f644d8d
commit
309801d059
7 files changed
+204
-33
No files matched your search
+72
-17
@@ -14,10 +14,20 @@ Kirigami.Dialog {
|
||||
required property var translator
|
||||
|
||||
readonly property real removeButtonWidth: Kirigami.Units.iconSizes.smallMedium + Kirigami.Units.smallSpacing * 2
|
||||
readonly property bool hasIncompleteTerms: {
|
||||
for (let i = 0; i < glossaryModel.count; ++i) {
|
||||
const entry = glossaryModel.get(i)
|
||||
if (!entry.source.trim() || !entry.target.trim()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
property string saveError: ""
|
||||
// One inset for the header, content and footer so every edge lines up.
|
||||
readonly property real inset: Kirigami.Units.largeSpacing
|
||||
|
||||
title: KI18n.i18nc("@title:window", "Translation Glossary")
|
||||
title: KI18n.i18nc("@title:window", "Edit Translation Glossary")
|
||||
standardButtons: Kirigami.Dialog.NoButton
|
||||
width: Math.min(parent.width * 0.9, Kirigami.Units.gridUnit * 38)
|
||||
height: Math.min(parent.height - Kirigami.Units.largeSpacing * 2, Kirigami.Units.gridUnit * 30)
|
||||
@@ -53,25 +63,28 @@ Kirigami.Dialog {
|
||||
})
|
||||
}
|
||||
|
||||
function saveGlossary() {
|
||||
const entries = []
|
||||
for (let i = 0; i < glossaryModel.count; ++i) {
|
||||
const entry = glossaryModel.get(i)
|
||||
entries.push({ source: entry.source, target: entry.target })
|
||||
}
|
||||
if (!translator.saveGlossary(entries)) {
|
||||
saveError = translator.glossaryError || KI18n.i18nc("@info", "Could not save the translation glossary. Check that the storage location is writable.")
|
||||
return
|
||||
}
|
||||
saveError = ""
|
||||
root.accept()
|
||||
}
|
||||
|
||||
onOpened: {
|
||||
saveError = ""
|
||||
glossaryModel.clear()
|
||||
for (const entry of translator.glossaryEntries) {
|
||||
glossaryModel.append(entry)
|
||||
}
|
||||
glossaryList.positionViewAtBeginning()
|
||||
}
|
||||
onAccepted: {
|
||||
const entries = []
|
||||
for (let i = 0; i < glossaryModel.count; ++i) {
|
||||
const entry = glossaryModel.get(i)
|
||||
entries.push({
|
||||
source: entry.source,
|
||||
target: entry.target
|
||||
})
|
||||
}
|
||||
translator.saveGlossary(entries)
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: glossaryModel
|
||||
}
|
||||
@@ -94,7 +107,8 @@ Kirigami.Dialog {
|
||||
Button {
|
||||
text: KI18n.i18nc("@action:button", "Save")
|
||||
icon.name: "document-save"
|
||||
onClicked: root.accept()
|
||||
enabled: !root.hasIncompleteTerms
|
||||
onClicked: root.saveGlossary()
|
||||
}
|
||||
|
||||
Button {
|
||||
@@ -112,8 +126,41 @@ Kirigami.Dialog {
|
||||
onTriggered: root.addTerm()
|
||||
}
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
contentItem: ScrollView {
|
||||
id: contentScroll
|
||||
clip: true
|
||||
contentWidth: availableWidth
|
||||
contentHeight: contentColumn.height
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
|
||||
// Fill the dialog normally; only scroll as a whole when the window is too
|
||||
// short for the list's minimum height.
|
||||
ColumnLayout {
|
||||
id: contentColumn
|
||||
width: contentScroll.availableWidth
|
||||
height: Math.max(contentScroll.availableHeight, implicitHeight)
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
|
||||
Kirigami.InlineMessage {
|
||||
Layout.fillWidth: true
|
||||
visible: root.saveError.length > 0
|
||||
type: Kirigami.MessageType.Error
|
||||
text: root.saveError
|
||||
showCloseButton: true
|
||||
actions: Kirigami.Action {
|
||||
text: KI18n.i18nc("@action:button", "Retry")
|
||||
icon.name: "view-refresh"
|
||||
onTriggered: root.saveGlossary()
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.InlineMessage {
|
||||
Layout.fillWidth: true
|
||||
visible: root.hasIncompleteTerms
|
||||
type: Kirigami.MessageType.Warning
|
||||
text: KI18n.i18nc("@info", "Complete both fields for each term, or remove incomplete rows, before saving.")
|
||||
showCloseButton: false
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
@@ -169,6 +216,8 @@ Kirigami.Dialog {
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.minimumHeight: Kirigami.Units.gridUnit * 6
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 6
|
||||
|
||||
ScrollView {
|
||||
id: listScroll
|
||||
@@ -240,6 +289,8 @@ Kirigami.Dialog {
|
||||
Layout.preferredWidth: 1
|
||||
Layout.minimumWidth: 0
|
||||
text: termRow.source
|
||||
// Show the start of long terms, not the end.
|
||||
Component.onCompleted: cursorPosition = 0
|
||||
placeholderText: KI18n.i18nc("@info:placeholder glossary source term", "Original term")
|
||||
Accessible.name: KI18n.i18nc("@label:textbox glossary source term", "Original term")
|
||||
onTextEdited: glossaryModel.setProperty(termRow.index, "source", text)
|
||||
@@ -250,12 +301,14 @@ Kirigami.Dialog {
|
||||
Layout.preferredWidth: 1
|
||||
Layout.minimumWidth: 0
|
||||
text: termRow.target
|
||||
// Show the start of long terms, not the end.
|
||||
Component.onCompleted: cursorPosition = 0
|
||||
placeholderText: KI18n.i18nc("@info:placeholder glossary translated term", "Translation")
|
||||
Accessible.name: KI18n.i18nc("@label:textbox glossary translated term", "Translation")
|
||||
onTextEdited: glossaryModel.setProperty(termRow.index, "target", text)
|
||||
}
|
||||
|
||||
ToolButton {
|
||||
Button {
|
||||
Layout.preferredWidth: root.removeButtonWidth
|
||||
Layout.minimumWidth: root.removeButtonWidth
|
||||
Layout.maximumWidth: root.removeButtonWidth
|
||||
@@ -264,6 +317,7 @@ Kirigami.Dialog {
|
||||
icon.name: "edit-delete"
|
||||
icon.color: Kirigami.Theme.textColor
|
||||
display: AbstractButton.IconOnly
|
||||
Accessible.name: text
|
||||
text: KI18n.i18nc("@action:button remove glossary term", "Remove")
|
||||
ToolTip.text: text
|
||||
ToolTip.visible: hovered
|
||||
@@ -284,4 +338,5 @@ Kirigami.Dialog {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,13 +20,13 @@ Page {
|
||||
property bool fullscreen: false
|
||||
|
||||
readonly property int edge: QtPotatoSettings.playlistPosition === "left" ? Qt.LeftEdge : Qt.RightEdge
|
||||
readonly property int buttonSize: Kirigami.Units.iconSizes.small
|
||||
readonly property int buttonSize: Kirigami.Units.iconSizes.smallMedium
|
||||
property real customWidth: QtPotatoSettings.playlistWidth
|
||||
|
||||
signal addFilesRequested()
|
||||
|
||||
function limitWidth(width: real): real {
|
||||
return Math.min(Math.max(width, 260), mainWindowWidth - 50)
|
||||
return Math.min(Math.max(width, Kirigami.Units.gridUnit * 13), mainWindowWidth - Kirigami.Units.gridUnit * 2.5)
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
@@ -63,7 +63,7 @@ Page {
|
||||
icon.name: "list-add"
|
||||
icon.width: root.buttonSize
|
||||
icon.height: root.buttonSize
|
||||
focusPolicy: Qt.NoFocus
|
||||
focusPolicy: Qt.StrongFocus
|
||||
onClicked: root.addFilesRequested()
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ Page {
|
||||
icon.width: root.buttonSize
|
||||
icon.height: root.buttonSize
|
||||
display: AbstractButton.IconOnly
|
||||
focusPolicy: Qt.NoFocus
|
||||
focusPolicy: Qt.StrongFocus
|
||||
enabled: root.playlist.playingIndex >= 0
|
||||
onClicked: playlistView.positionViewAtIndex(root.playlist.playingIndex, ListView.Center)
|
||||
|
||||
@@ -88,7 +88,7 @@ Page {
|
||||
icon.width: root.buttonSize
|
||||
icon.height: root.buttonSize
|
||||
display: AbstractButton.IconOnly
|
||||
focusPolicy: Qt.NoFocus
|
||||
focusPolicy: Qt.StrongFocus
|
||||
enabled: root.playlist.count > 0
|
||||
onClicked: root.playlist.clear()
|
||||
|
||||
@@ -141,7 +141,7 @@ Page {
|
||||
ResizeHandler {
|
||||
id: resizeHandlerTall
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: 8
|
||||
width: Kirigami.Units.smallSpacing * 2
|
||||
height: parent.height
|
||||
onMoved: delta => root.customWidth = root.limitWidth(root.customWidth + (root.edge === Qt.RightEdge ? -delta : delta))
|
||||
onReleased: {
|
||||
@@ -152,8 +152,8 @@ Page {
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: 5
|
||||
height: 50
|
||||
width: Kirigami.Units.smallSpacing
|
||||
height: Kirigami.Units.gridUnit * 2.5
|
||||
color: resizeHandlerTall.hovered ? Kirigami.Theme.highlightColor : Kirigami.Theme.alternateBackgroundColor
|
||||
radius: Kirigami.Units.cornerRadius
|
||||
border.width: 1
|
||||
|
||||
@@ -22,6 +22,25 @@ Item {
|
||||
|
||||
readonly property bool hovered: hoverHandler.hovered
|
||||
readonly property real fontSize: Kirigami.Theme.defaultFont.pointSize
|
||||
activeFocusOnTab: true
|
||||
|
||||
function activate() {
|
||||
root.playlist.play(root.index)
|
||||
}
|
||||
|
||||
function showContextMenu() {
|
||||
contextMenu.popup()
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: root.activate()
|
||||
Keys.onEnterPressed: root.activate()
|
||||
Keys.onMenuPressed: root.showContextMenu()
|
||||
Keys.onPressed: event => {
|
||||
if (event.key === Qt.Key_F10 && (event.modifiers & Qt.ShiftModifier)) {
|
||||
root.showContextMenu()
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
function labelColor(): color {
|
||||
if (root.isPlaying && !root.hovered) {
|
||||
@@ -39,6 +58,7 @@ Item {
|
||||
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onTapped: root.forceActiveFocus(Qt.MouseFocusReason)
|
||||
onDoubleTapped: root.playlist.play(root.index)
|
||||
}
|
||||
|
||||
@@ -60,6 +80,9 @@ Item {
|
||||
return Qt.alpha(Kirigami.Theme.backgroundColor, root.alpha)
|
||||
}
|
||||
|
||||
border.width: root.activeFocus ? 2 : 0
|
||||
border.color: Kirigami.Theme.focusColor
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
@@ -95,8 +118,8 @@ Item {
|
||||
color: root.labelColor()
|
||||
visible: root.isPlaying
|
||||
Layout.leftMargin: QtPotatoSettings.playlistShowRowNumber ? 0 : Kirigami.Units.largeSpacing
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.small
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.small
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.smallMedium
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.smallMedium
|
||||
}
|
||||
|
||||
LabelWithTooltip {
|
||||
@@ -105,11 +128,26 @@ Item {
|
||||
color: root.labelColor()
|
||||
elide: Text.ElideRight
|
||||
font.pointSize: root.fontSize
|
||||
font.bold: root.isPlaying
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: !QtPotatoSettings.playlistShowRowNumber && !root.isPlaying ? Kirigami.Units.largeSpacing : 0
|
||||
Layout.rightMargin: Kirigami.Units.largeSpacing
|
||||
}
|
||||
|
||||
Button {
|
||||
text: KI18n.i18nc("@action:button remove playlist item", "Remove")
|
||||
icon.name: "list-remove"
|
||||
display: AbstractButton.IconOnly
|
||||
flat: true
|
||||
Accessible.name: text
|
||||
ToolTip.text: text
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.smallMedium + Kirigami.Units.smallSpacing * 2
|
||||
Layout.rightMargin: Kirigami.Units.smallSpacing
|
||||
onClicked: root.playlist.remove(root.index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user