diff --git a/examples/quick/localstorage/localstorage/Header.qml b/examples/quick/localstorage/localstorage/Header.qml index d1dedaec3f..3328a88559 100644 --- a/examples/quick/localstorage/localstorage/Header.qml +++ b/examples/quick/localstorage/localstorage/Header.qml @@ -1,4 +1,3 @@ - /**************************************************************************** ** ** Copyright (C) 2021 The Qt Company Ltd. @@ -60,7 +59,8 @@ Item { height: Screen.height / 7 required property ListView listView - required property Text statusText + signal statusMessage(string msg) + enabled: false function insertrec() { var rowid = parseInt(JS.dbInsert(dateInput.text, descInput.text, distInput.text), 10) @@ -125,19 +125,19 @@ Item { anchors.fill: parent Label { - text: "Date" + text: qsTr("Date") font.pixelSize: 22 rightPadding: 10 } Label { - text: "Description" + text: qsTr("Description") font.pixelSize: 22 rightPadding: 10 } Label { - text: "Distance" + text: qsTr("Distance") font.pixelSize: 22 } @@ -146,14 +146,29 @@ Item { font.pixelSize: 22 activeFocusOnPress: true activeFocusOnTab: true - validator: RegularExpressionValidator { - regularExpression: /[0-9/,:.]+/ + + ToolTip { + parent: dateInput + x: parent.width + 3 + y: (parent.height - height) / 2 + text: qsTr("Date format = 'YYYY-MM-DD'") + visible: parent.enabled && parent.hovered + delay: 1000 } - onEditingFinished: { - if (dateInput.text == "") { - root.statusText.text = "Please fill in the date" - dateInput.forceActiveFocus() - } + + validator: RegularExpressionValidator { + regularExpression: /\d{4}[,.:/-]\d\d?[,.:/-]\d\d?/ + } + + onFocusChanged: ()=> { + if (!dateInput.focus && !acceptableInput && root.enabled) + root.statusMessage(qsTr("Please fill in the date")); + } + + onEditingFinished: ()=> { + let regex = /(\d+)[,.:/-](\d+)[,.:/-](\d+)/ + if (dateInput.text.match(regex)) + dateInput.text = dateInput.text.replace(regex, '$1-$2-$3') } } @@ -162,13 +177,11 @@ Item { font.pixelSize: 22 activeFocusOnPress: true activeFocusOnTab: true - onEditingFinished: { - if (descInput.text.length < 8) { - root.statusText.text = "Enter a description of minimum 8 characters" - descInput.forceActiveFocus() - } else { - root.statusText.text = "" - } + property string oldString + onFocusChanged: ()=> { if (focus) oldString = descInput.text; } + onEditingFinished: ()=> { + if (descInput.text.length < 8 && descInput.text != descInput.oldString && root.enabled) + root.statusMessage(qsTr("Enter a description of minimum 8 characters")) } } @@ -180,11 +193,11 @@ Item { validator: RegularExpressionValidator { regularExpression: /\d{1,3}/ } - onEditingFinished: { - if (distInput.text == "") { - root.statusText.text = "Please fill in the distance" - distInput.forceActiveFocus() - } + property string oldString + onFocusChanged: ()=> { if (focus) oldString = distInput.text; } + onEditingFinished: ()=> { + if (distInput.text == "" && distInput.text != distInput.oldString && root.enabled) + root.statusMessage(qsTr("Please fill in the distance")) } } } diff --git a/examples/quick/localstorage/localstorage/MyDelegate.qml b/examples/quick/localstorage/localstorage/MyDelegate.qml index 6fbb9544be..b715882ab4 100644 --- a/examples/quick/localstorage/localstorage/MyDelegate.qml +++ b/examples/quick/localstorage/localstorage/MyDelegate.qml @@ -57,8 +57,8 @@ import "Database.js" as JS Item { id: delegate - width: parent.width - height: rDate.implicitHeight + width: ListView.view.width + implicitHeight: rDate.implicitHeight * 1.5 required property int index required property int distance @@ -72,34 +72,43 @@ Item { anchors.fill: parent opacity: 0.8 color: delegate.index % 2 ? "lightgrey" : "grey" + border.width: 2 + border.color: Qt.lighter(color) + radius: 5 MouseArea { anchors.fill: parent onClicked: delegate.clicked() } - GridLayout { - anchors.fill:parent - columns: 3 + + RowLayout { + anchors.fill: parent Label { id: rDate + Layout.preferredWidth: 42 + Layout.alignment: Qt.AlignCenter + horizontalAlignment: Text.AlignHCenter text: delegate.date font.pixelSize: 22 - Layout.preferredWidth: parent.width / 4 color: "black" } + Label { - id: rDesc + Layout.preferredWidth: 42 + Layout.alignment: Qt.AlignCenter + horizontalAlignment: Text.AlignHCenter text: delegate.trip_desc - Layout.fillWidth: true font.pixelSize: 22 color: "black" } + Label { - id: rDistance + Layout.preferredWidth: 42 + Layout.alignment: Qt.AlignCenter + horizontalAlignment: Text.AlignHCenter text: delegate.distance font.pixelSize: 22 - Layout.alignment: Qt.AlignRight color: "black" } } diff --git a/examples/quick/localstorage/localstorage/localstorage.qml b/examples/quick/localstorage/localstorage/localstorage.qml index 5915b67367..15710fc55c 100644 --- a/examples/quick/localstorage/localstorage/localstorage.qml +++ b/examples/quick/localstorage/localstorage/localstorage.qml @@ -69,16 +69,18 @@ Window { ColumnLayout { anchors.fill: parent + anchors.margins: 10 Header { id: input Layout.fillWidth: true listView: listView - statusText: statustext + enabled: window.creatingNewEntry || window.editingEntry } + RowLayout { Button { - text: "New" + text: qsTr("New") onClicked: { input.initrec_new() window.creatingNewEntry = true @@ -88,7 +90,7 @@ Window { Button { id: saveButton enabled: (window.creatingNewEntry || window.editingEntry) && listView.currentIndex != -1 - text: "Save" + text: qsTr("Save") onClicked: { var insertedRow = false; if (listView.model.get(listView.currentIndex).id < 1) { @@ -99,7 +101,7 @@ Window { insertedRow = true } else { // Failed to insert a row; display an error message. - statustext.text = "Failed to insert row" + statustext.displayWarning(qsTr("Failed to insert row")) } } else { // edit mode @@ -120,7 +122,7 @@ Window { } Button { id: editButton - text: "Edit" + text: qsTr("Edit") enabled: !window.creatingNewEntry && !window.editingEntry && listView.currentIndex != -1 onClicked: { input.editrec(listView.model.get(listView.currentIndex).date, @@ -133,7 +135,7 @@ Window { } Button { id: deleteButton - text: "Delete" + text: qsTr("Delete") enabled: !window.creatingNewEntry && listView.currentIndex != -1 onClicked: { JS.dbDeleteRow(listView.model.get(listView.currentIndex).id) @@ -147,7 +149,7 @@ Window { } Button { id: cancelButton - text: "Cancel" + text: qsTr("Cancel") enabled: (window.creatingNewEntry || window.editingEntry) && listView.currentIndex != -1 onClicked: { if (listView.model.get(listView.currentIndex).id === 0) { @@ -162,10 +164,19 @@ Window { } } Button { - text: "Exit" + text: qsTr("Exit") onClicked: Qt.quit() } } + Item { + Layout.fillWidth: true + height: 5 + } + Label { + Layout.alignment: Qt.AlignCenter + text: qsTr("Saved activities") + font.pointSize: 15 + } Component { id: highlightBar Rectangle { @@ -180,7 +191,8 @@ Window { Layout.fillHeight: true model: MyModel {} delegate: MyDelegate { - onClicked: listView.currentIndex = index + width: listView.width + onClicked: ()=> listView.currentIndex = index } // Don't allow changing the currentIndex while the user is creating/editing values. enabled: !window.creatingNewEntry && !window.editingEntry @@ -188,20 +200,70 @@ Window { highlight: highlightBar highlightFollowsCurrentItem: true focus: true + clip: true header: Component { - Text { - text: "Saved activities" + RowLayout { + property var headerTitles: [qsTr("Date"), qsTr("Description"), qsTr("Distance")] + width: ListView.view.width + Repeater { + model: headerTitles + delegate: Label { + id: headerTitleDelegate + Layout.fillWidth: true + Layout.fillHeight: true + Layout.preferredWidth: 1 + text: modelData + font.pointSize: 15 + font.bold: true + font.underline: true + padding: 12 + horizontalAlignment: Label.AlignHCenter + } + } } } } Label { id: statustext color: "red" - Layout.fillWidth: true font.bold: true font.pointSize: 20 + opacity: 0.0 + visible: opacity !== 0 // properly cull item if effectively invisible + Layout.alignment: Layout.Center + function displayWarning(text) { + statustext.text = text + statusAnim.restart() + } + + Connections { + target: input + function onStatusMessage(msg) { statustext.displayWarning(msg); } + } + + SequentialAnimation { + id: statusAnim + + OpacityAnimator { + target: statustext + from: 0.0 + to: 1.0 + duration: 50 + } + + PauseAnimation { + duration: 2000 + } + + OpacityAnimator { + target: statustext + from: 1.0 + to: 0.0 + duration: 50 + } + } } } }