Warning, /education/gcompris/src/core/DownloadDialog.qml is written in an unsupported language. File is not indexed.
0001 /* GCompris - DownloadDialog.qml
0002 *
0003 * SPDX-FileCopyrightText: 2014 Holger Kaelberer <holger.k@elberer.de>
0004 *
0005 * Authors:
0006 * Holger Kaelberer <holger.k@elberer.de>
0007 *
0008 * SPDX-License-Identifier: GPL-3.0-or-later
0009 */
0010 import QtQuick 2.12
0011 import GCompris 1.0
0012 import QtQuick.Layouts 1.12
0013 import QtQuick.Controls 2.12
0014 import "qrc:/gcompris/src/core/core.js" as Core
0015
0016 /**
0017 * A QML component visualizing download progress.
0018 * @ingroup infrastructure
0019 *
0020 * A GCDialog style dialog providing visual feedback for download progress.
0021 * Uses DownloadManager for download control.
0022 *
0023 * Can be conveniently instantiated dynamically using showDownloadDialog
0024 * from core.js.
0025 *
0026 * @inherit QtQuick.Item
0027 * @sa DownloadManager, showDownloadDialog
0028 */
0029 Item {
0030 id: downloadDialog
0031 opacity: 0
0032
0033 anchors {
0034 fill: parent
0035 }
0036
0037 /**
0038 * type:Item
0039 * Parent object for the dialog in the qml hierarchy.
0040 */
0041 property Item main
0042
0043 /**
0044 * type:bool
0045 * Whether to close the dialog automatically when download has finished.
0046 * Default is false.
0047 */
0048 property bool autohide: false;
0049
0050 /**
0051 * type:bool
0052 * Whether to report download success in a Dialog.
0053 * Default is true.
0054 */
0055 property bool reportSuccess: true;
0056
0057 /**
0058 * type:bool
0059 * Whether to report download errors in a Dialog.
0060 * Default is true.
0061 */
0062 property bool reportError: true;
0063
0064 /**
0065 * type:bool
0066 * Whether a message has been displayed
0067 * we don't want to display several dialogs
0068 */
0069 property bool messageDisplayed: false;
0070
0071 /**
0072 * type:GCDialog
0073 * The dialog displaying the result message
0074 */
0075 property var messageDialog: undefined;
0076
0077 /**
0078 * type:bool
0079 * Whether the dialog has been created dynamically. If set to true, the
0080 * component takes care of destroying itself after finished.
0081 * Default is false.
0082 *
0083 * @sa Core.destroyDialog
0084 */
0085 property bool dynamic: false
0086
0087 /**
0088 * type:bool
0089 * Whether the 'Background' button should be visible.
0090 * Default is true.
0091 */
0092 property alias backgroundButtonVisible: backgroundButton.visible
0093
0094 /**
0095 * type:bool
0096 * Whether the 'Abort' button should be visible.
0097 * Default is true.
0098 */
0099 property alias abortButtonVisible: abortButton.visible
0100
0101 /**
0102 * type:bool
0103 * Fixed font size used in this dialog. Note, fixed font-sizes should be
0104 * used in dialog components, to make sure they stay within bounds when
0105 * user increases font size.
0106 * Default is 14.
0107 */
0108 property int fixedFontSize: 14
0109
0110 /// @cond INTERNAL_DOCS
0111
0112 // start and stop trigs the animation FIXME: need to document?
0113 signal start
0114 signal stop
0115
0116 // emitted at stop animation end
0117 signal close
0118
0119 signal finished
0120
0121 focus: true
0122
0123 //We need a timer to properly get focus on this dialog and its children dialogs
0124 Timer {
0125 id: getFocusTimer
0126 interval: 250
0127 onTriggered: {
0128 if(!messageDisplayed) {
0129 downloadDialog.forceActiveFocus();
0130 downloadDialog.parent.Keys.enabled = false;
0131 } else {
0132 messageDialog.forceActiveFocus();
0133 downloadDialog.parent.Keys.enabled = false;
0134 }
0135 }
0136 }
0137
0138 onVisibleChanged: {
0139 if(visible) {
0140 getFocusTimer.restart();
0141 }
0142 }
0143 onStart: {
0144 opacity = 1;
0145 getFocusTimer.restart();
0146 }
0147 onStop: {
0148 opacity = 0;
0149 parent.Keys.enabled = true;
0150 parent.forceActiveFocus();
0151 }
0152 onClose: {
0153 destroy();
0154 parent.Keys.enabled = true;
0155 parent.forceActiveFocus();
0156 }
0157
0158 Behavior on opacity { NumberAnimation { duration: 200 } }
0159 onOpacityChanged: opacity === 0 ? close() : null
0160
0161 function shutdown()
0162 {
0163 if (downloadDialog.dynamic)
0164 Core.destroyDialog(downloadDialog);
0165 else
0166 downloadDialog.close();
0167 }
0168
0169 /// @endcond
0170
0171 Rectangle {
0172 anchors.fill: parent
0173 opacity: 0.8
0174 color: "grey"
0175
0176 MouseArea {
0177 // Empty mouseArea to prevent clicking "behind" the Dialog
0178 anchors.fill: parent
0179 enabled: downloadDialog.opacity != 0
0180 }
0181 }
0182
0183 Item {
0184 id: instruction
0185 anchors {
0186 horizontalCenter: parent.horizontalCenter
0187 top: parent.top
0188 topMargin: parent.height * 0.1
0189 }
0190 width: parent.width * 0.8
0191
0192 GCText {
0193 id: instructionTxt
0194 fontSize: mediumSize
0195 color: "black"
0196 horizontalAlignment: Text.AlignHCenter
0197 width: parent.width
0198 wrapMode: TextEdit.WordWrap
0199 z: 2
0200 height: 60 * ApplicationInfo.ratio
0201 text: qsTr("Downloading...")
0202 }
0203
0204 Rectangle {
0205 anchors.fill: instructionTxt
0206 z: 1
0207 opacity: 0.9
0208 radius: 10
0209 border.width: 2
0210 border.color: "white"
0211 gradient: Gradient {
0212 GradientStop { position: 0.0; color: "#fff" }
0213 GradientStop { position: 0.9; color: "#fff" }
0214 GradientStop { position: 1.0; color: "#ddd" }
0215 }
0216 }
0217
0218 ProgressBar {
0219 id: downloadDialogProgress
0220 width: parent.width
0221 anchors {
0222 horizontalCenter: parent.horizontalCenter
0223 top: instructionTxt.bottom
0224 topMargin: 10
0225 }
0226 visible: true
0227 Layout.alignment: Qt.AlignHCenter
0228 Layout.rowSpan: 1
0229 Layout.fillWidth: true
0230 from: 0
0231 to: 100
0232 value: 0
0233 }
0234
0235 Rectangle {
0236 id: buttonSelector
0237 width: 0
0238 height: 0
0239 color: "#803ACAFF"
0240 scale: 1.1
0241 }
0242
0243 GCButton {
0244 id: backgroundButton
0245 width: parent.width
0246 height: 60 * ApplicationInfo.ratio
0247 anchors {
0248 horizontalCenter: parent.horizontalCenter
0249 top: downloadDialogProgress.bottom
0250 topMargin: 10
0251 }
0252 //: Run this task in background
0253 text: qsTr("Background")
0254 fixedFontSize: downloadDialog.fixedFontSize
0255 theme: "highContrast"
0256 visible: true
0257 property bool selected: false;
0258 onClicked: downloadDialog.shutdown();
0259 }
0260
0261 GCButton {
0262 id: abortButton
0263 width: parent.width
0264 height: 60 * ApplicationInfo.ratio
0265 anchors {
0266 horizontalCenter: parent.horizontalCenter
0267 top: backgroundButton.bottom
0268 topMargin: 10
0269 }
0270 text: qsTr("Abort")
0271 fixedFontSize: downloadDialog.fixedFontSize
0272 theme: "highContrast"
0273
0274 visible: true
0275 property bool selected: false;
0276 onClicked: {
0277 if (DownloadManager.downloadIsRunning())
0278 DownloadManager.abortDownloads();
0279 downloadDialog.finished();
0280 downloadDialog.shutdown();
0281 }
0282 }
0283
0284 states: [
0285 State {
0286 name: "button1Selected"
0287 when: backgroundButton.selected
0288 PropertyChanges {
0289 target: buttonSelector
0290 anchors.fill: backgroundButton
0291 }
0292 },
0293 State {
0294 name: "button2Selected"
0295 when: abortButton.selected
0296 PropertyChanges {
0297 target: buttonSelector
0298 anchors.fill: abortButton
0299 }
0300 }
0301 ]
0302 }
0303
0304 Keys.onEscapePressed: {
0305 if(backgroundButtonVisible)
0306 backgroundButton.clicked();
0307 else if(abortButtonVisible)
0308 abortButton.clicked();
0309 }
0310
0311 Keys.onPressed: {
0312 if(event.key === Qt.Key_Up || event.key === Qt.Key_Left) {
0313 if(abortButton.visible && !backgroundButton.selected && !abortButton.selected) {
0314 abortButton.selected = true;
0315 } else if(backgroundButton.visible) {
0316 abortButton.selected = !abortButton.selected;
0317 backgroundButton.selected = !backgroundButton.selected;
0318 } else if(abortButton.visible) {
0319 button1.selected = true;
0320 }
0321 }
0322 if(event.key === Qt.Key_Down || event.key === Qt.Key_Right) {
0323 if(backgroundButton.visible && !backgroundButton.selected && !abortButton.selected) {
0324 backgroundButton.selected = true;
0325 } else if(backgroundButton.visible) {
0326 backgroundButton.selected = !backgroundButton.selected;
0327 abortButton.selected = !abortButton.selected;
0328 } else if(abortButton.visible) {
0329 abortButton.selected = true;
0330 }
0331 }
0332 if(event.key === Qt.Key_Enter || event.key === Qt.Key_Return || event.key === Qt.Key_Space) {
0333 if(backgroundButton.selected) {
0334 backgroundButton.clicked();
0335 } else if(abortButton.selected) {
0336 abortButton.clicked();
0337 } else if(backgroundButtonVisible) {
0338 backgroundButton.clicked();
0339 } else if(abortButtonVisible) {
0340 abortButton.clicked();
0341 }
0342 }
0343 }
0344
0345 Keys.onReleased: {
0346 if(event.key === Qt.Key_Back) {
0347 if(backgroundButtonVisible)
0348 backgroundButton.clicked();
0349 else if(abortButtonVisible)
0350 abortButton.clicked();
0351 event.accepted = true;
0352 }
0353 }
0354
0355 Connections {
0356 target: DownloadManager
0357
0358 onError: {
0359 //console.warn("DownloadDialog: DM reports error: " + code + ": " + msg);
0360 downloadDialog.finished();
0361 if (downloadDialog.reportError
0362 && code != 5 && !messageDisplayed) { // no error: OperationCanceledError
0363 // show error message
0364 messageDisplayed = true;
0365 messageDialog = Core.showMessageDialog(downloadDialog.parent,
0366 qsTr("Download error (code: %1): %2").arg(code).arg(msg),
0367 "", null,
0368 "", null,
0369 function() {
0370 downloadDialog.shutdown();
0371 }
0372 );
0373 getFocusTimer.restart();
0374 }
0375 }
0376
0377 onDownloadProgress: downloadDialogProgress.value = 100 * bytesReceived / bytesTotal;
0378
0379 onDownloadStarted: {
0380 //console.log("dialog: DM reports started: " + resource);
0381 downloadDialogProgress.value = 0;
0382 }
0383
0384 onAllDownloadsFinished: {
0385 //console.log("dialog: DM all reports finished");
0386 downloadDialog.finished();
0387 if (downloadDialog.reportSuccess
0388 && code != 1 && !messageDisplayed) // note: errors will be reported by the onError handler
0389 {
0390 // report success
0391 messageDisplayed = true;
0392 var infText = "";
0393 if (code == 0) { // Success
0394 infText = qsTr("Your download finished successfully. The data files are now available.")
0395 + '\n'
0396 + qsTr("Restart any currently active activity.");
0397 } else if (code == 2) // NoChange
0398 infText = qsTr("Your local data files are up-to-date.")
0399
0400 messageDialog = Core.showMessageDialog(downloadDialog.parent,
0401 infText,
0402 "", null,
0403 "", null,
0404 function() {
0405 downloadDialog.shutdown();
0406 }
0407 );
0408 getFocusTimer.restart();
0409 } else if (downloadDialog.autohide)
0410 downloadDialog.shutdown();
0411 }
0412
0413 onDownloadFinished: {
0414 //console.log("dialog: DM reports finished: " + code);
0415 }
0416 }
0417
0418 }