2020-03-04 16:55:40 +01:00
/ *
* SPDX - License - Identifier: Apache - 2.0
2022-02-03 11:48:21 +01:00
* Copyright ( C ) 2020 Raspberry Pi Ltd
2020-03-04 16:55:40 +01:00
* /
import QtQuick 2.9
import QtQuick . Window 2.2
import QtQuick . Controls 2.2
import QtQuick . Layouts 1.0
import QtQuick . Controls . Material 2.2
2022-02-04 12:32:12 +01:00
import "qmlcomponents"
2020-03-04 16:55:40 +01:00
ApplicationWindow {
2024-10-11 02:24:56 -04:00
// Define the colors
property color beigeColor: "#c4bebb"
property color maroonColor: "#800000"
property color yellowColor: "#fcad01"
property string selectedCFW: "" // This should be set dynamically
property color backgroundColor: beigeColor
property color accentColor: maroonColor
2020-03-04 16:55:40 +01:00
id: window
visible: true
2020-06-01 17:45:41 +02:00
2023-10-10 13:13:44 +01:00
width: imageWriter . isEmbeddedMode ( ) ? - 1 : 680
2023-09-23 19:51:45 +02:00
height: imageWriter . isEmbeddedMode ( ) ? - 1 : 450
2023-10-10 13:13:44 +01:00
minimumWidth: imageWriter . isEmbeddedMode ( ) ? - 1 : 680
2024-10-11 02:24:56 -04:00
minimumHeight: imageWriter . isEmbeddedMode ( ) ? - 1 : 450
2020-03-04 16:55:40 +01:00
2024-10-11 02:24:56 -04:00
title: qsTr ( "Retro Imager v%1" ) . arg ( imageWriter . constantVersion ( ) )
2020-03-04 16:55:40 +01:00
FontLoader { id: roboto ; source: "fonts/Roboto-Regular.ttf" }
FontLoader { id: robotoLight ; source: "fonts/Roboto-Light.ttf" }
FontLoader { id: robotoBold ; source: "fonts/Roboto-Bold.ttf" }
2020-05-23 19:07:03 +02:00
onClosing: {
if ( progressBar . visible ) {
close . accepted = false
2020-06-30 00:42:39 +02:00
quitpopup . openPopup ( )
2020-05-23 19:07:03 +02:00
}
}
2020-05-25 00:36:16 +02:00
Shortcut {
sequence: StandardKey . Quit
context: Qt . ApplicationShortcut
onActivated: {
if ( ! progressBar . visible ) {
Qt . quit ( )
}
}
}
2021-01-17 17:43:17 +01:00
Shortcut {
sequences: [ "Shift+Ctrl+X" , "Shift+Meta+X" ]
context: Qt . ApplicationShortcut
onActivated: {
optionspopup . openPopup ( )
}
}
2020-03-04 16:55:40 +01:00
ColumnLayout {
id: bg
spacing: 0
2020-06-01 17:45:41 +02:00
Rectangle {
2023-10-16 15:06:11 +01:00
id: logoContainer
2024-10-11 02:24:56 -04:00
color: accentColor
2023-10-16 15:06:11 +01:00
implicitHeight: window . height / 4
2020-06-01 17:45:41 +02:00
Image {
id: image
2023-10-10 14:03:20 +01:00
source: "icons/logo_sxs_imager.png"
2023-10-16 15:06:11 +01:00
// Specify the maximum size of the image
width: window . width * 0.45
height: window . height / 3
2024-10-11 02:24:56 -04:00
smooth: true
antialiasing: true
anchors {
left: logoContainer . left
leftMargin: 40
top: logoContainer . top
bottom: logoContainer . bottom
topMargin: window . height / 25
bottomMargin: window . height / 25
}
2020-06-01 17:45:41 +02:00
}
2020-03-04 16:55:40 +01:00
}
Rectangle {
2024-10-11 02:24:56 -04:00
color: backgroundColor
2020-03-04 16:55:40 +01:00
implicitWidth: window . width
2023-10-16 15:06:11 +01:00
implicitHeight: window . height * ( 1 - 1 / 4 )
2020-03-04 16:55:40 +01:00
GridLayout {
id: gridLayout
2023-10-10 13:13:44 +01:00
rowSpacing: 15
2020-03-04 16:55:40 +01:00
anchors.fill: parent
anchors.topMargin: 25
anchors.rightMargin: 50
anchors.leftMargin: 50
2023-10-10 13:13:44 +01:00
rows: 5
columns: 3
columnSpacing: 15
2020-03-04 16:55:40 +01:00
ColumnLayout {
2023-10-03 22:24:49 +01:00
id: columnLayout0
spacing: 0
2023-10-10 13:13:44 +01:00
Layout.row: 0
Layout.column: 0
2023-10-03 22:24:49 +01:00
Layout.fillWidth: true
Text {
id: text0
2024-10-11 02:24:56 -04:00
color: accentColor
text: qsTr ( "Retro Gaming Handheld Device" )
2023-10-03 22:24:49 +01:00
Layout.fillWidth: true
Layout.preferredHeight: 17
Layout.preferredWidth: 100
font.pixelSize: 12
font.family: robotoBold . name
font.bold: true
horizontalAlignment: Text . AlignHCenter
}
ImButton {
id: hwbutton
text: qsTr ( "CHOOSE DEVICE" )
spacing: 0
padding: 0
bottomPadding: 0
topPadding: 0
Layout.minimumHeight: 40
Layout.fillWidth: true
2024-10-11 02:24:56 -04:00
Accessible.ignored: ospopup . visible || dstpopup . visible || hwpopup . visible
Accessible.description: qsTr ( "Select this button to choose your target Retro Gaming Handheld" )
MouseArea {
id: hwbuttonMouseArea
anchors.fill: parent
cursorShape: Qt . PointingHandCursor
hoverEnabled: true
onEntered: {
bgrect . mouseOver = true
}
onExited: {
bgrect . mouseOver = false
}
onClicked: {
2023-10-03 22:24:49 +01:00
hwpopup . open ( )
2023-10-18 12:56:59 +01:00
hwlist . forceActiveFocus ( )
2024-10-11 02:24:56 -04:00
}
}
Rectangle {
id: bgrect
anchors.fill: parent
color: accentColor
visible: mouseOver
property bool mouseOver: false
2023-10-03 22:24:49 +01:00
}
}
}
ColumnLayout {
id: columnLayout1
2020-03-04 16:55:40 +01:00
spacing: 0
2023-10-10 13:13:44 +01:00
Layout.row: 0
Layout.column: 1
2020-03-04 16:55:40 +01:00
Layout.fillWidth: true
Text {
id: text1
2024-10-11 02:24:56 -04:00
color: accentColor
text: qsTr ( "Custom Firmware" )
2020-03-04 16:55:40 +01:00
Layout.fillWidth: true
Layout.preferredHeight: 17
font.pixelSize: 12
font.family: robotoBold . name
font.bold: true
horizontalAlignment: Text . AlignHCenter
}
2022-02-04 12:32:12 +01:00
ImButton {
2020-03-04 16:55:40 +01:00
id: osbutton
2024-10-11 02:24:56 -04:00
text: imageWriter . srcFileName ( ) === "" ? qsTr ( "CHOOSE CFW" ) : imageWriter . srcFileName ( )
2020-03-04 16:55:40 +01:00
spacing: 0
padding: 0
bottomPadding: 0
topPadding: 0
Layout.minimumHeight: 40
Layout.fillWidth: true
2024-10-11 02:24:56 -04:00
Accessible.ignored: ospopup . visible || dstpopup . visible || hwpopup . visible
Accessible.description: qsTr ( "Select this button to change the custom firmware" )
MouseArea {
id: osbuttonMouseArea
anchors.fill: parent
cursorShape: Qt . PointingHandCursor
hoverEnabled: true
onEntered: {
bgrect1 . mouseOver = true
}
onExited: {
bgrect1 . mouseOver = false
}
onClicked: {
2020-06-30 00:42:39 +02:00
ospopup . open ( )
2020-12-01 15:52:33 +01:00
osswipeview . currentItem . forceActiveFocus ( )
2024-10-11 02:24:56 -04:00
}
}
Rectangle {
id: bgrect1
anchors.fill: parent
color: accentColor
visible: mouseOver
property bool mouseOver: false
2020-06-30 00:42:39 +02:00
}
2020-03-04 16:55:40 +01:00
}
}
ColumnLayout {
id: columnLayout2
spacing: 0
2023-10-10 13:13:44 +01:00
Layout.row: 0
Layout.column: 2
2020-03-04 16:55:40 +01:00
Layout.fillWidth: true
Text {
id: text2
2024-10-11 02:24:56 -04:00
color: accentColor
2021-02-08 22:06:39 +01:00
text: qsTr ( "Storage" )
2020-03-04 16:55:40 +01:00
Layout.fillWidth: true
Layout.preferredHeight: 17
font.pixelSize: 12
font.family: robotoBold . name
font.bold: true
horizontalAlignment: Text . AlignHCenter
}
2022-02-04 12:32:12 +01:00
ImButton {
2020-03-04 16:55:40 +01:00
id: dstbutton
2021-02-08 22:06:39 +01:00
text: qsTr ( "CHOOSE STORAGE" )
2023-10-09 14:12:42 +01:00
spacing: 0
padding: 0
bottomPadding: 0
topPadding: 0
2020-03-04 16:55:40 +01:00
Layout.minimumHeight: 40
2023-10-09 14:12:42 +01:00
Layout.preferredWidth: 200
2020-03-04 16:55:40 +01:00
Layout.fillWidth: true
2023-10-10 13:13:44 +01:00
Accessible.ignored: ospopup . visible || dstpopup . visible || hwpopup . visible
2024-10-11 22:26:58 -04:00
Accessible.description: qsTr ( "Select this button to select you storage device" )
MouseArea {
2024-10-11 22:31:37 -04:00
id: dstbuttonMouseArea
2024-10-11 22:26:58 -04:00
anchors.fill: parent
cursorShape: Qt . PointingHandCursor
hoverEnabled: true
onEntered: {
2024-10-11 22:36:01 -04:00
bgrect2 . mouseOver = true
2024-10-11 22:26:58 -04:00
}
onExited: {
2024-10-11 22:36:01 -04:00
bgrect2 . mouseOver = false
2024-10-11 22:26:58 -04:00
}
onClicked: {
2024-10-11 22:56:49 -04:00
imageWriter . startDriveListPolling ( )
dstpopup . open ( )
dstlist . forceActiveFocus ( )
}
2024-10-11 22:26:58 -04:00
}
Rectangle {
2024-10-11 22:36:01 -04:00
id: bgrect2
2024-10-11 22:26:58 -04:00
anchors.fill: parent
color: accentColor
visible: mouseOver
property bool mouseOver: false
}
2023-10-10 10:34:34 +01:00
}
2020-03-04 16:55:40 +01:00
}
ColumnLayout {
2023-10-10 14:03:20 +01:00
id: columnLayoutProgress
2020-03-04 16:55:40 +01:00
spacing: 0
2023-10-10 13:13:44 +01:00
Layout.row: 1
Layout.column: 0
2023-10-10 14:03:20 +01:00
Layout.columnSpan: 2
2020-03-04 16:55:40 +01:00
Text {
id: progressText
font.pointSize: 10
2024-10-11 02:24:56 -04:00
color: accentColor
2020-03-04 16:55:40 +01:00
font.family: robotoBold . name
font.bold: true
visible: false
horizontalAlignment: Text . AlignHCenter
Layout.fillWidth: true
2023-10-10 13:13:44 +01:00
Layout.bottomMargin: 25
2020-03-04 16:55:40 +01:00
}
ProgressBar {
2023-10-10 13:13:44 +01:00
Layout.bottomMargin: 25
2020-03-04 16:55:40 +01:00
id: progressBar
Layout.fillWidth: true
visible: false
2024-10-11 02:24:56 -04:00
Material.background: accentColor
2020-03-04 16:55:40 +01:00
}
2023-10-10 14:03:20 +01:00
}
ColumnLayout {
id: columnLayout3
Layout.row: 1
Layout.column: 2
Layout.alignment: Qt . AlignRight | Qt . AlignVCenter
spacing: 0
2020-03-04 16:55:40 +01:00
2022-02-04 12:32:12 +01:00
ImButton {
2023-10-10 13:13:44 +01:00
Layout.bottomMargin: 25
2023-10-10 14:03:20 +01:00
Layout.minimumHeight: 40
Layout.preferredWidth: 200
2023-10-10 13:13:44 +01:00
padding: 5
2020-03-04 16:55:40 +01:00
id: cancelwritebutton
text: qsTr ( "CANCEL WRITE" )
onClicked: {
enabled = false
progressText . text = qsTr ( "Cancelling..." )
imageWriter . cancelWrite ( )
}
Layout.alignment: Qt . AlignRight
visible: false
}
2022-02-04 12:32:12 +01:00
ImButton {
2023-10-10 13:13:44 +01:00
Layout.bottomMargin: 25
2023-10-10 14:03:20 +01:00
Layout.minimumHeight: 40
Layout.preferredWidth: 200
2023-10-10 13:13:44 +01:00
padding: 5
2020-03-04 16:55:40 +01:00
id: cancelverifybutton
text: qsTr ( "CANCEL VERIFY" )
onClicked: {
enabled = false
progressText . text = qsTr ( "Finalizing..." )
imageWriter . setVerifyEnabled ( false )
}
Layout.alignment: Qt . AlignRight
visible: false
}
2022-01-20 17:23:47 +01:00
2023-10-10 14:03:20 +01:00
ImButton {
id: writebutton
2023-10-11 13:22:32 +01:00
text: qsTr ( "Next" )
2023-10-10 14:03:20 +01:00
Layout.bottomMargin: 25
Layout.minimumHeight: 40
Layout.preferredWidth: 200
Layout.alignment: Qt . AlignRight
Accessible.ignored: ospopup . visible || dstpopup . visible || hwpopup . visible
Accessible.description: qsTr ( "Select this button to start writing the image" )
enabled: false
onClicked: {
if ( ! imageWriter . readyToWrite ( ) ) {
return
}
2023-10-11 13:22:32 +01:00
if ( ! optionspopup . visible && imageWriter . imageSupportsCustomization ( ) ) {
2023-10-10 14:03:20 +01:00
usesavedsettingspopup . openPopup ( )
} else {
confirmwritepopup . askForConfirmation ( )
}
}
}
2020-03-04 16:55:40 +01:00
}
2021-11-22 00:21:30 +01:00
2021-11-23 12:09:03 +01:00
Text {
Layout.columnSpan: 3
2024-10-11 02:24:56 -04:00
color: accentColor
2021-11-23 12:09:03 +01:00
font.pixelSize: 18
font.family: roboto . name
visible: imageWriter . isEmbeddedMode ( ) && imageWriter . customRepo ( )
text: qsTr ( "Using custom repository: %1" ) . arg ( imageWriter . constantOsListUrl ( ) )
}
2024-01-15 00:16:43 +01:00
Text {
id: networkInfo
Layout.columnSpan: 3
2024-10-11 02:24:56 -04:00
color: accentColor
2024-01-15 00:16:43 +01:00
font.pixelSize: 18
font.family: roboto . name
visible: imageWriter . isEmbeddedMode ( )
text: qsTr ( "Network not ready yet" )
}
2021-11-23 12:09:03 +01:00
Text {
Layout.columnSpan: 3
2024-10-11 02:24:56 -04:00
color: accentColor
2021-11-23 12:09:03 +01:00
font.pixelSize: 18
font.family: roboto . name
visible: ! imageWriter . hasMouse ( )
text: qsTr ( "Keyboard navigation: <tab> navigate to next button <space> press button/select item <arrow up/down> go up/down in lists" )
}
2023-09-23 19:51:45 +02:00
Rectangle {
id: langbarRect
2021-11-22 00:21:30 +01:00
Layout.columnSpan: 3
2021-11-27 21:44:32 +01:00
Layout.alignment: Qt . AlignHCenter | Qt . AlignBottom
Layout.bottomMargin: 5
2021-11-22 00:21:30 +01:00
visible: imageWriter . isEmbeddedMode ( )
2023-09-23 19:51:45 +02:00
implicitWidth: langbar . width
implicitHeight: langbar . height
2024-10-11 02:24:56 -04:00
color: backgroundColor
2023-09-23 19:51:45 +02:00
radius: 5
2021-11-22 00:21:30 +01:00
2023-09-23 19:51:45 +02:00
RowLayout {
id: langbar
spacing: 10
2021-11-22 00:21:30 +01:00
2023-09-23 19:51:45 +02:00
Text {
font.pixelSize: 12
font.family: roboto . name
text: qsTr ( "Language: " )
Layout.leftMargin: 30
Layout.topMargin: 10
Layout.bottomMargin: 10
2021-11-22 00:21:30 +01:00
}
2023-09-23 19:51:45 +02:00
ComboBox {
font.pixelSize: 12
font.family: roboto . name
model: imageWriter . getTranslations ( )
Layout.preferredWidth: 200
currentIndex: - 1
Component.onCompleted: {
currentIndex = find ( imageWriter . getCurrentLanguage ( ) )
}
onActivated: {
imageWriter . changeLanguage ( editText )
}
Layout.topMargin: 10
Layout.bottomMargin: 10
2021-11-22 00:21:30 +01:00
}
2023-09-23 19:51:45 +02:00
Text {
font.pixelSize: 12
font.family: roboto . name
text: qsTr ( "Keyboard: " )
Layout.topMargin: 10
Layout.bottomMargin: 10
2021-11-22 00:21:30 +01:00
}
2023-09-23 19:51:45 +02:00
ComboBox {
enabled: imageWriter . isEmbeddedMode ( )
font.pixelSize: 12
font.family: roboto . name
model: imageWriter . getKeymapLayoutList ( )
currentIndex: - 1
Component.onCompleted: {
currentIndex = find ( imageWriter . getCurrentKeyboard ( ) )
}
onActivated: {
imageWriter . changeKeyboard ( editText )
}
Layout.topMargin: 10
Layout.bottomMargin: 10
Layout.rightMargin: 30
2021-11-22 00:21:30 +01:00
}
}
}
/ * L a n g u a g e / k e y b o a r d b a r i s n o r m a l l y o n l y v i s i b l e i n e m b e d d e d m o d e .
To test translations also show it when shift + ctrl + L is pressed . * /
Shortcut {
sequences: [ "Shift+Ctrl+L" , "Shift+Meta+L" ]
context: Qt . ApplicationShortcut
onActivated: {
2023-09-23 19:51:45 +02:00
langbarRect . visible = true
2021-11-22 00:21:30 +01:00
}
}
2020-03-04 16:55:40 +01:00
}
2023-08-13 00:21:31 +01:00
DropArea {
anchors.fill: parent
onEntered: {
if ( drag . active && mimeData . hasUrls ( ) ) {
drag . acceptProposedAction ( )
}
}
onDropped: {
if ( drop . urls && drop . urls . length > 0 ) {
onFileSelected ( drop . urls [ 0 ] . toString ( ) )
}
}
}
2020-03-04 16:55:40 +01:00
}
}
Popup {
2023-10-03 22:24:49 +01:00
id: hwpopup
2020-03-04 16:55:40 +01:00
x: 50
y: 25
width: parent . width - 100
height: parent . height - 50
padding: 0
2024-09-03 14:14:00 +01:00
closePolicy: Popup . CloseOnEscape
2023-10-03 22:24:49 +01:00
property string hwselected: ""
2020-03-04 16:55:40 +01:00
// background of title
Rectangle {
2024-07-17 11:07:54 +01:00
id: hwpopup_title_background
2024-10-11 02:24:56 -04:00
color: backgroundColor
2024-07-17 11:07:54 +01:00
anchors.left: parent . left
2020-03-04 16:55:40 +01:00
anchors.top: parent . top
height: 35
width: parent . width
2024-07-17 11:07:54 +01:00
Text {
text: qsTr ( "Raspberry Pi Device" )
horizontalAlignment: Text . AlignHCenter
2020-03-04 16:55:40 +01:00
anchors.fill: parent
2024-07-17 11:07:54 +01:00
anchors.topMargin: 10
font.family: roboto . name
font.bold: true
2020-03-04 16:55:40 +01:00
}
Text {
2024-07-17 11:07:54 +01:00
text: "X"
Layout.alignment: Qt . AlignRight
horizontalAlignment: Text . AlignRight
2020-03-04 16:55:40 +01:00
verticalAlignment: Text . AlignVCenter
2024-07-17 11:07:54 +01:00
anchors.right: parent . right
anchors.top: parent . top
anchors.rightMargin: 25
anchors.topMargin: 10
2020-03-04 16:55:40 +01:00
font.family: roboto . name
font.bold: true
2024-07-17 11:07:54 +01:00
MouseArea {
anchors.fill: parent
cursorShape: Qt . PointingHandCursor
onClicked: {
hwpopup . close ( )
2023-09-23 19:51:45 +02:00
}
}
}
2023-10-03 22:24:49 +01:00
}
2024-07-17 11:07:54 +01:00
// line under title
Rectangle {
id: hwpopup_title_separator
color: "#afafaf"
width: parent . width
anchors.top: hwpopup_title_background . bottom
height: 1
}
ListView {
id: hwlist
clip: true
model: ListModel {
id: deviceModel
ListElement {
name: qsTr ( "[ All ]" )
tags: "[]"
icon: ""
description: ""
matching_type: "exclusive"
}
}
currentIndex: - 1
delegate: hwdelegate
anchors.top: hwpopup_title_separator . bottom
anchors.left: parent . left
anchors.right: parent . right
anchors.bottom: parent . bottom
boundsBehavior: Flickable . StopAtBounds
ScrollBar.vertical: ScrollBar {
anchors.right: parent . right
width: 10
policy: hwlist . contentHeight > hwlist . height ? ScrollBar.AlwaysOn : ScrollBar . AsNeeded
}
Keys.onSpacePressed: {
if ( currentIndex != - 1 )
selectHWitem ( model . get ( currentIndex ) )
}
Accessible.onPressAction: {
if ( currentIndex != - 1 )
selectHWitem ( model . get ( currentIndex ) )
}
Keys.onEnterPressed: Keys . onSpacePressed ( event )
Keys.onReturnPressed: Keys . onSpacePressed ( event )
}
2023-10-03 22:24:49 +01:00
}
/ *
Popup for OS selection
* /
Popup {
id: ospopup
x: 50
y: 25
width: parent . width - 100
height: parent . height - 50
padding: 0
2024-09-03 14:14:00 +01:00
closePolicy: Popup . CloseOnEscape
2023-10-03 22:24:49 +01:00
property string categorySelected : ""
// background of title
Rectangle {
2024-07-17 11:07:54 +01:00
id: ospopup_title_background
2024-10-11 02:24:56 -04:00
color: backgroundColor
2024-07-17 11:07:54 +01:00
anchors.left: parent . left
2023-10-03 22:24:49 +01:00
anchors.top: parent . top
height: 35
width: parent . width
2024-07-17 11:07:54 +01:00
Text {
2024-10-11 02:24:56 -04:00
text: qsTr ( "Custom Firmware" )
2024-07-17 11:07:54 +01:00
horizontalAlignment: Text . AlignHCenter
2023-10-03 22:24:49 +01:00
anchors.fill: parent
2024-07-17 11:07:54 +01:00
anchors.topMargin: 10
font.family: roboto . name
font.bold: true
2023-10-03 22:24:49 +01:00
}
Text {
2024-07-17 11:07:54 +01:00
text: "X"
Layout.alignment: Qt . AlignRight
horizontalAlignment: Text . AlignRight
2023-10-03 22:24:49 +01:00
verticalAlignment: Text . AlignVCenter
2024-07-17 11:07:54 +01:00
anchors.right: parent . right
anchors.top: parent . top
anchors.rightMargin: 25
anchors.topMargin: 10
2023-10-03 22:24:49 +01:00
font.family: roboto . name
font.bold: true
2023-09-23 19:51:45 +02:00
2024-07-17 11:07:54 +01:00
MouseArea {
anchors.fill: parent
cursorShape: Qt . PointingHandCursor
onClicked: {
ospopup . close ( )
osswipeview . decrementCurrentIndex ( )
2020-03-04 16:55:40 +01:00
}
2020-12-01 15:52:33 +01:00
}
}
}
2024-07-17 11:07:54 +01:00
// line under title
Rectangle {
id: ospopup_title_separator
color: "#afafaf"
width: parent . width
anchors.top: ospopup_title_background . bottom
height: 1
}
SwipeView {
anchors.top: ospopup_title_separator . bottom
anchors.left: parent . left
anchors.right: parent . right
anchors.bottom: parent . bottom
id: osswipeview
interactive: false
clip: true
ListView {
id: oslist
model: osmodel
currentIndex: - 1
delegate: osdelegate
anchors.top: parent . top
anchors.left: parent . left
anchors.bottom: parent . bottom
width: ospopup . width
boundsBehavior: Flickable . StopAtBounds
ScrollBar.vertical: ScrollBar {
anchors.right: parent . right
width: 10
policy: oslist . contentHeight > oslist . height ? ScrollBar.AlwaysOn : ScrollBar . AsNeeded
}
Keys.onSpacePressed: {
if ( currentIndex != - 1 )
selectOSitem ( model . get ( currentIndex ) , true )
}
Accessible.onPressAction: {
if ( currentIndex != - 1 )
selectOSitem ( model . get ( currentIndex ) , true )
}
Keys.onEnterPressed: Keys . onSpacePressed ( event )
Keys.onReturnPressed: Keys . onSpacePressed ( event )
Keys.onRightPressed: {
// Navigate into sublists but don't select an OS entry
if ( currentIndex != - 1 && isOSsublist ( model . get ( currentIndex ) ) )
selectOSitem ( model . get ( currentIndex ) , true )
}
}
}
2020-12-01 15:52:33 +01:00
}
2020-03-04 16:55:40 +01:00
2020-12-01 15:52:33 +01:00
Component {
id: suboslist
ListView {
model: ListModel {
ListElement {
url: ""
icon: "icons/ic_chevron_left_40px.svg"
extract_size: 0
image_download_size: 0
extract_sha256: ""
contains_multiple_files: false
release_date: ""
subitems_url: "internal://back"
2022-01-23 19:30:16 +01:00
subitems_json: ""
2020-12-01 15:52:33 +01:00
name: qsTr ( "Back" )
description: qsTr ( "Go back to main menu" )
tooltip: ""
2021-05-07 13:10:23 +02:00
website: ""
2021-11-18 20:48:24 +01:00
init_format: ""
2020-03-04 16:55:40 +01:00
}
}
2020-12-01 15:52:33 +01:00
currentIndex: - 1
delegate: osdelegate
2024-07-17 11:07:54 +01:00
2020-12-01 15:52:33 +01:00
boundsBehavior: Flickable . StopAtBounds
ScrollBar.vertical: ScrollBar {
width: 10
policy: parent . contentHeight > parent . height ? ScrollBar.AlwaysOn : ScrollBar . AsNeeded
}
Keys.onSpacePressed: {
if ( currentIndex != - 1 )
selectOSitem ( model . get ( currentIndex ) )
}
Accessible.onPressAction: {
if ( currentIndex != - 1 )
selectOSitem ( model . get ( currentIndex ) )
}
2022-02-04 12:32:12 +01:00
Keys.onEnterPressed: Keys . onSpacePressed ( event )
Keys.onReturnPressed: Keys . onSpacePressed ( event )
2023-10-17 15:35:44 +01:00
Keys.onRightPressed: {
// Navigate into sublists but don't select an OS entry
if ( currentIndex != - 1 && isOSsublist ( model . get ( currentIndex ) ) )
selectOSitem ( model . get ( currentIndex ) , true )
}
Keys.onLeftPressed: {
osswipeview . decrementCurrentIndex ( )
ospopup . categorySelected = ""
}
2020-03-04 16:55:40 +01:00
}
}
ListModel {
id: osmodel
Component.onCompleted: {
2020-05-25 00:36:16 +02:00
if ( imageWriter . isOnline ( ) ) {
fetchOSlist ( ) ;
}
2020-03-04 16:55:40 +01:00
}
}
2023-10-03 22:24:49 +01:00
Component {
id: hwdelegate
Item {
width: window . width - 100
height: contentLayout . implicitHeight + 24
Accessible.name: name + ".\n" + description
MouseArea {
id: hwMouseArea
anchors.fill: parent
cursorShape: Qt . PointingHandCursor
hoverEnabled: true
onEntered: {
bgrect . mouseOver = true
}
onExited: {
bgrect . mouseOver = false
}
onClicked: {
selectHWitem ( model )
}
}
Rectangle {
2024-07-17 11:07:54 +01:00
id: bgrect
anchors.fill: parent
2024-10-11 02:24:56 -04:00
color: accentColor
2024-07-17 11:07:54 +01:00
visible: mouseOver && parent . ListView . view . currentIndex !== index
property bool mouseOver: false
2023-10-03 22:24:49 +01:00
}
Rectangle {
2024-07-17 11:07:54 +01:00
id: borderrect
implicitHeight: 1
implicitWidth: parent . width
2024-10-11 02:24:56 -04:00
color: accentColor
2024-07-17 11:07:54 +01:00
y: parent . height
2023-10-03 22:24:49 +01:00
}
RowLayout {
id: contentLayout
anchors {
left: parent . left
top: parent . top
right: parent . right
margins: 12
}
spacing: 12
Image {
2023-10-21 10:34:40 +02:00
source: typeof icon === "undefined" ? "" : icon
2023-10-16 11:47:24 +01:00
Layout.preferredHeight: 64
Layout.preferredWidth: 64
sourceSize.width: 64
sourceSize.height: 64
2023-10-03 22:24:49 +01:00
fillMode: Image . PreserveAspectFit
verticalAlignment: Image . AlignVCenter
Layout.alignment: Qt . AlignVCenter
}
ColumnLayout {
Layout.fillWidth: true
Text {
text: name
elide: Text . ElideRight
font.family: roboto . name
font.bold: true
}
Text {
Layout.fillWidth: true
font.family: roboto . name
wrapMode: Text . WordWrap
2024-10-11 02:24:56 -04:00
color: accentColor
2023-10-03 22:24:49 +01:00
}
}
}
}
}
2020-03-04 16:55:40 +01:00
Component {
id: osdelegate
Item {
width: window . width - 100
2024-10-11 02:24:56 -04:00
height: Math . max ( contentLayout . implicitHeight + 24 , 50 )
2020-06-30 00:42:39 +02:00
Accessible.name: name + ".\n" + description
2020-03-04 16:55:40 +01:00
2022-01-09 13:47:43 +01:00
MouseArea {
id: osMouseArea
anchors.fill: parent
cursorShape: Qt . PointingHandCursor
hoverEnabled: true
onEntered: {
bgrect . mouseOver = true
2024-10-11 22:26:58 -04:00
mouseText . color = accentColor
mouseText2 . color = accentColor
2022-01-09 13:47:43 +01:00
}
onExited: {
bgrect . mouseOver = false
2024-10-11 02:24:56 -04:00
mouseText . color = accentColor
mouseText2 . color = accentColor
2022-01-09 13:47:43 +01:00
}
onClicked: {
selectOSitem ( model )
}
}
2020-03-04 16:55:40 +01:00
Rectangle {
2024-07-17 11:07:54 +01:00
id: bgrect
anchors.fill: parent
2024-10-11 02:24:56 -04:00
color: backgroundColor
2024-07-17 11:07:54 +01:00
visible: mouseOver && parent . ListView . view . currentIndex !== index
property bool mouseOver: false
2020-03-04 16:55:40 +01:00
}
Rectangle {
2024-07-17 11:07:54 +01:00
id: borderrect
implicitHeight: 1
implicitWidth: parent . width
2024-10-11 02:24:56 -04:00
color: accentColor
2024-07-17 11:07:54 +01:00
y: parent . height
2020-03-04 16:55:40 +01:00
}
2022-01-09 13:47:43 +01:00
RowLayout {
id: contentLayout
anchors {
left: parent . left
top: parent . top
right: parent . right
margins: 12
}
spacing: 12
Image {
source: icon == "icons/ic_build_48px.svg" ? "icons/cat_misc_utility_images.png" : icon
Layout.preferredHeight: 40
Layout.preferredWidth: 40
sourceSize.width: 40
sourceSize.height: 40
fillMode: Image . PreserveAspectFit
verticalAlignment: Image . AlignVCenter
Layout.alignment: Qt . AlignVCenter
2020-03-04 16:55:40 +01:00
}
2022-01-09 13:47:43 +01:00
ColumnLayout {
Layout.fillWidth: true
2020-03-04 16:55:40 +01:00
2022-01-09 13:47:43 +01:00
RowLayout {
spacing: 12
Text {
text: name
elide: Text . ElideRight
font.family: roboto . name
font.bold: true
}
Image {
source: "icons/ic_info_16px.png"
Layout.preferredHeight: 16
Layout.preferredWidth: 16
visible: typeof ( website ) == "string" && website
MouseArea {
anchors.fill: parent
onClicked: Qt . openUrlExternally ( website )
2020-03-04 16:55:40 +01:00
}
}
2022-01-09 13:47:43 +01:00
Item {
Layout.fillWidth: true
2020-05-23 12:30:06 +02:00
}
2020-03-04 16:55:40 +01:00
}
2022-01-09 13:47:43 +01:00
Text {
Layout.fillWidth: true
font.family: roboto . name
text: description
wrapMode: Text . WordWrap
2024-10-11 22:26:58 -04:00
color: accentColor
2020-03-04 16:55:40 +01:00
}
2022-01-09 13:47:43 +01:00
Text {
2024-10-11 02:24:56 -04:00
id:mouseText
2022-01-09 13:47:43 +01:00
Layout.fillWidth: true
elide: Text . ElideRight
2024-10-11 02:24:56 -04:00
color: accentColor
2022-01-09 13:47:43 +01:00
font.weight: Font . Light
visible: typeof ( release_date ) == "string" && release_date
text: qsTr ( "Released: %1" ) . arg ( release_date )
}
Text {
2024-10-11 02:24:56 -04:00
id:mouseText2
2022-01-09 13:47:43 +01:00
Layout.fillWidth: true
elide: Text . ElideRight
2024-10-11 02:24:56 -04:00
color: accentColor
2022-01-09 13:47:43 +01:00
font.weight: Font . Light
visible: typeof ( url ) == "string" && url != "" && url != "internal://format"
text: ! url ? "" :
2024-07-17 11:07:54 +01:00
typeof ( extract_sha256 ) != "undefined" && imageWriter . isCached ( url , extract_sha256 )
? qsTr ( "Cached on your computer" )
: url . startsWith ( "file://" )
? qsTr ( "Local file" )
: qsTr ( "Online - %1 GB download" ) . arg ( ( image_download_size / 1073741824 ) . toFixed ( 1 ) )
2022-01-09 13:47:43 +01:00
}
2020-03-04 16:55:40 +01:00
2022-01-09 13:47:43 +01:00
ToolTip {
visible: osMouseArea . containsMouse && typeof ( tooltip ) == "string" && tooltip != ""
delay: 1000
text: typeof ( tooltip ) == "string" ? tooltip : ""
clip: false
2021-05-07 13:10:23 +02:00
}
2020-03-04 16:55:40 +01:00
}
2022-01-09 13:47:43 +01:00
Image {
source: "icons/ic_chevron_right_40px.svg"
2022-01-24 11:09:40 +01:00
visible: ( typeof ( subitems_json ) == "string" && subitems_json != "" ) || ( typeof ( subitems_url ) == "string" && subitems_url != "" && subitems_url != "internal://back" )
2022-01-09 13:47:43 +01:00
Layout.preferredHeight: 40
Layout.preferredWidth: 40
fillMode: Image . PreserveAspectFit
}
2020-03-04 16:55:40 +01:00
}
}
}
/ *
2021-02-26 14:51:09 +01:00
Popup for storage device selection
2020-03-04 16:55:40 +01:00
* /
Popup {
id: dstpopup
x: 50
y: 25
width: parent . width - 100
height: parent . height - 50
padding: 0
2024-09-03 14:14:00 +01:00
closePolicy: Popup . CloseOnEscape
2020-07-02 23:31:20 +02:00
onClosed: imageWriter . stopDriveListPolling ( )
2020-03-04 16:55:40 +01:00
// background of title
Rectangle {
2024-07-17 11:07:54 +01:00
id: dstpopup_title_background
2024-10-11 02:24:56 -04:00
color: backgroundColor
2024-07-17 11:07:54 +01:00
anchors.left: parent . left
2020-03-04 16:55:40 +01:00
anchors.top: parent . top
height: 35
width: parent . width
2024-07-17 11:07:54 +01:00
Text {
text: qsTr ( "Storage" )
horizontalAlignment: Text . AlignHCenter
anchors.fill: parent
anchors.topMargin: 10
font.family: roboto . name
font.bold: true
}
Text {
text: "X"
Layout.alignment: Qt . AlignRight
horizontalAlignment: Text . AlignRight
verticalAlignment: Text . AlignVCenter
anchors.right: parent . right
anchors.top: parent . top
anchors.rightMargin: 25
anchors.topMargin: 10
font.family: roboto . name
font.bold: true
MouseArea {
anchors.fill: parent
cursorShape: Qt . PointingHandCursor
onClicked: {
dstpopup . close ( )
}
}
}
2020-03-04 16:55:40 +01:00
}
// line under title
Rectangle {
2024-07-17 11:07:54 +01:00
id: dstpopup_title_separator
2020-03-04 16:55:40 +01:00
color: "#afafaf"
width: parent . width
2024-07-17 11:07:54 +01:00
anchors.top: dstpopup_title_background . bottom
height: 1
2020-03-04 16:55:40 +01:00
}
2024-07-17 11:07:54 +01:00
ListView {
id: dstlist
model: driveListModel
delegate: dstdelegate
2020-03-04 16:55:40 +01:00
2024-07-17 11:07:54 +01:00
anchors.top: dstpopup_title_separator . bottom
anchors.left: parent . left
2020-03-04 16:55:40 +01:00
anchors.right: parent . right
2024-07-17 11:07:54 +01:00
anchors.bottom: parent . bottom
boundsBehavior: Flickable . StopAtBounds
clip: true
2020-03-04 16:55:40 +01:00
2024-07-17 11:07:54 +01:00
Label {
2020-03-04 16:55:40 +01:00
anchors.fill: parent
2024-07-17 11:07:54 +01:00
horizontalAlignment: Qt . AlignHCenter
verticalAlignment: Qt . AlignVCenter
visible: parent . count == 0
text: qsTr ( "No storage devices found" )
2020-03-04 16:55:40 +01:00
font.bold: true
}
2024-07-17 11:07:54 +01:00
ScrollBar.vertical: ScrollBar {
width: 10
policy: dstlist . contentHeight > dstlist . height ? ScrollBar.AlwaysOn : ScrollBar . AsNeeded
}
2020-06-30 00:42:39 +02:00
2024-07-17 11:07:54 +01:00
Keys.onSpacePressed: {
if ( currentIndex == - 1 )
return
selectDstItem ( currentItem )
}
Accessible.onPressAction: {
if ( currentIndex == - 1 )
return
selectDstItem ( currentItem )
2020-03-04 16:55:40 +01:00
}
2024-07-17 11:07:54 +01:00
Keys.onEnterPressed: Keys . onSpacePressed ( event )
Keys.onReturnPressed: Keys . onSpacePressed ( event )
2020-03-04 16:55:40 +01:00
}
}
Component {
id: dstdelegate
Item {
2024-07-17 11:07:54 +01:00
anchors.left: parent . left
anchors.right: parent . right
Layout.topMargin: 1
height: 61
2020-06-30 00:42:39 +02:00
Accessible.name: {
var txt = description + " - " + ( size / 1000000000 ) . toFixed ( 1 ) + " gigabytes"
if ( mountpoints . length > 0 ) {
txt += qsTr ( "Mounted as %1" ) . arg ( mountpoints . join ( ", " ) )
}
return txt ;
}
property string description: model . description
property string device: model . device
property string size: model . size
2020-03-04 16:55:40 +01:00
Rectangle {
2024-07-17 11:07:54 +01:00
id: dstbgrect
anchors.top: parent . top
anchors.left: parent . left
anchors.right: parent . right
height: 60
2020-06-30 00:42:39 +02:00
2024-10-11 02:24:56 -04:00
color: mouseOver ? accentColor : "#ffffff"
2024-07-17 11:07:54 +01:00
property bool mouseOver: false
2020-03-04 16:55:40 +01:00
2024-07-17 11:07:54 +01:00
RowLayout {
anchors.fill: parent
2020-03-04 16:55:40 +01:00
2024-07-17 11:07:54 +01:00
Item {
width: 25
}
2020-03-04 16:55:40 +01:00
Image {
2024-07-17 11:07:54 +01:00
id: dstitem_image
2020-06-01 17:45:41 +02:00
source: isUsb ? "icons/ic_usb_40px.svg" : isScsi ? "icons/ic_storage_40px.svg" : "icons/ic_sd_storage_40px.svg"
2020-03-04 16:55:40 +01:00
verticalAlignment: Image . AlignVCenter
fillMode: Image . Pad
2024-07-17 11:07:54 +01:00
width: 64
height: 60
2020-03-04 16:55:40 +01:00
}
2024-07-17 11:07:54 +01:00
Item {
width: 25
}
ColumnLayout {
Text {
textFormat: Text . StyledText
verticalAlignment: Text . AlignVCenter
Layout.fillWidth: true
font.family: roboto . name
font.pointSize: 16
color: isReadOnly ? "grey" : "" ;
text: {
var sizeStr = ( size / 1000000000 ) . toFixed ( 1 ) + " " + qsTr ( "GB" ) ;
return description + " - " + sizeStr ;
}
}
Text {
textFormat: Text . StyledText
height: parent . height
verticalAlignment: Text . AlignVCenter
Layout.fillWidth: true
font.family: roboto . name
font.pointSize: 12
color: "grey"
text: {
var txt = qsTr ( "Mounted as %1" ) . arg ( mountpoints . join ( ", " ) ) ;
if ( isReadOnly ) {
txt += " " + qsTr ( "[WRITE PROTECTED]" )
2020-07-03 21:16:49 +02:00
}
2024-07-17 11:07:54 +01:00
return txt ;
2020-03-04 16:55:40 +01:00
}
}
}
}
2024-07-17 11:07:54 +01:00
}
Rectangle {
id: dstborderrect
anchors.top: dstbgrect . bottom
anchors.left: parent . left
anchors.right: parent . right
height: 1
color: "#dcdcdc"
2020-03-04 16:55:40 +01:00
}
MouseArea {
anchors.fill: parent
cursorShape: Qt . PointingHandCursor
hoverEnabled: true
onEntered: {
2020-06-30 00:42:39 +02:00
dstbgrect . mouseOver = true
2020-03-04 16:55:40 +01:00
}
onExited: {
2020-06-30 00:42:39 +02:00
dstbgrect . mouseOver = false
2020-03-04 16:55:40 +01:00
}
onClicked: {
2020-07-03 21:16:49 +02:00
selectDstItem ( model )
2020-03-04 16:55:40 +01:00
}
}
}
}
2020-06-30 00:42:39 +02:00
MsgPopup {
2020-03-04 16:55:40 +01:00
id: msgpopup
2023-10-18 12:56:59 +01:00
onOpened: {
forceActiveFocus ( )
}
2020-06-30 00:42:39 +02:00
}
2020-03-04 16:55:40 +01:00
2020-06-30 00:42:39 +02:00
MsgPopup {
id: quitpopup
continueButton: false
yesButton: true
noButton: true
title: qsTr ( "Are you sure you want to quit?" )
2024-10-11 02:24:56 -04:00
text: qsTr ( "Retro-Imager is still busy.<br>Are you sure you want to quit?" )
2020-06-30 00:42:39 +02:00
onYes: {
Qt . quit ( )
2020-03-04 16:55:40 +01:00
}
2020-06-30 00:42:39 +02:00
}
2020-03-04 16:55:40 +01:00
2020-06-30 00:42:39 +02:00
MsgPopup {
id: confirmwritepopup
continueButton: false
yesButton: true
noButton: true
title: qsTr ( "Warning" )
2023-10-18 12:56:59 +01:00
modal: true
2020-06-30 00:42:39 +02:00
onYes: {
2023-09-23 19:51:45 +02:00
langbarRect . visible = false
2023-10-10 14:03:20 +01:00
writebutton . visible = false
2020-06-30 00:42:39 +02:00
writebutton . enabled = false
cancelwritebutton . enabled = true
cancelwritebutton . visible = true
cancelverifybutton . enabled = true
2020-11-19 18:10:05 +01:00
progressText . text = qsTr ( "Preparing to write..." ) ;
2020-06-30 00:42:39 +02:00
progressText . visible = true
progressBar . visible = true
progressBar . indeterminate = true
2024-10-11 02:24:56 -04:00
progressBar . Material . accent = accentColor
2020-06-30 00:42:39 +02:00
osbutton . enabled = false
dstbutton . enabled = false
2023-10-10 14:03:20 +01:00
hwbutton . enabled = false
2020-06-30 00:42:39 +02:00
imageWriter . setVerifyEnabled ( true )
imageWriter . startWrite ( )
2020-03-04 16:55:40 +01:00
}
2020-06-30 00:42:39 +02:00
function askForConfirmation ( )
{
text = qsTr ( "All existing data on '%1' will be erased.<br>Are you sure you want to continue?" ) . arg ( dstbutton . text )
openPopup ( )
2020-03-04 16:55:40 +01:00
}
2023-10-18 12:56:59 +01:00
onOpened: {
forceActiveFocus ( )
}
2020-03-04 16:55:40 +01:00
}
2020-11-23 19:23:20 +01:00
MsgPopup {
id: updatepopup
continueButton: false
yesButton: true
noButton: true
property url url
title: qsTr ( "Update available" )
text: qsTr ( "There is a newer version of Imager available.<br>Would you like to visit the website to download it?" )
onYes: {
Qt . openUrlExternally ( url )
}
}
2021-01-17 17:43:17 +01:00
OptionsPopup {
2024-07-17 11:07:54 +01:00
minimumWidth: 450
minimumHeight: 400
2021-01-17 17:43:17 +01:00
id: optionspopup
2023-10-17 15:21:49 +01:00
onSaveSettingsSignal: {
imageWriter . setSavedCustomizationSettings ( settings )
usesavedsettingspopup . hasSavedSettings = true
}
2021-01-17 17:43:17 +01:00
}
2021-01-20 13:04:18 +01:00
UseSavedSettingsPopup {
id: usesavedsettingspopup
onYes: {
optionspopup . initialize ( )
optionspopup . applySettings ( )
confirmwritepopup . askForConfirmation ( )
}
onNo: {
2023-11-16 14:59:39 +00:00
imageWriter . setImageCustomization ( "" , "" , "" , "" , "" )
2023-03-24 14:26:43 +01:00
confirmwritepopup . askForConfirmation ( )
}
onNoClearSettings: {
2023-10-17 15:21:49 +01:00
hasSavedSettings = false
optionspopup . clearCustomizationFields ( )
2021-01-20 13:04:18 +01:00
imageWriter . clearSavedCustomizationSettings ( )
confirmwritepopup . askForConfirmation ( )
}
onEditSettings: {
optionspopup . openPopup ( )
}
2023-10-17 10:23:59 +01:00
onCloseSettings: {
optionspopup . close ( )
}
2021-01-20 13:04:18 +01:00
}
2020-03-04 16:55:40 +01:00
/* Slots for signals imagewrite emits */
function onDownloadProgress ( now , total ) {
var newPos
if ( total ) {
newPos = now / ( total + 1 )
} else {
newPos = 0
}
2020-05-23 12:30:06 +02:00
if ( progressBar . value !== newPos ) {
if ( progressText . text === qsTr ( "Cancelling..." ) )
2020-03-04 16:55:40 +01:00
return
progressText . text = qsTr ( "Writing... %1%" ) . arg ( Math . floor ( newPos * 100 ) )
progressBar . indeterminate = false
progressBar . value = newPos
}
}
function onVerifyProgress ( now , total ) {
var newPos
if ( total ) {
newPos = now / total
} else {
newPos = 0
}
2020-05-23 12:30:06 +02:00
if ( progressBar . value !== newPos ) {
2020-03-04 16:55:40 +01:00
if ( cancelwritebutton . visible ) {
cancelwritebutton . visible = false
cancelverifybutton . visible = true
}
2020-05-23 12:30:06 +02:00
if ( progressText . text === qsTr ( "Finalizing..." ) )
2020-03-04 16:55:40 +01:00
return
progressText . text = qsTr ( "Verifying... %1%" ) . arg ( Math . floor ( newPos * 100 ) )
2024-10-11 02:24:56 -04:00
progressBar . Material . accent = accentColor
2020-03-04 16:55:40 +01:00
progressBar . value = newPos
}
}
2020-11-19 18:10:05 +01:00
function onPreparationStatusUpdate ( msg ) {
progressText . text = qsTr ( "Preparing to write... (%1)" ) . arg ( msg )
}
2023-11-09 14:38:34 +00:00
function onOsListPrepared ( ) {
fetchOSlist ( )
}
2020-03-04 16:55:40 +01:00
function resetWriteButton ( ) {
progressText . visible = false
progressBar . visible = false
osbutton . enabled = true
dstbutton . enabled = true
2023-10-10 14:03:20 +01:00
hwbutton . enabled = true
2020-03-04 16:55:40 +01:00
writebutton . visible = true
writebutton . enabled = imageWriter . readyToWrite ( )
cancelwritebutton . visible = false
cancelverifybutton . visible = false
}
function onError ( msg ) {
2020-06-30 00:42:39 +02:00
msgpopup . title = qsTr ( "Error" )
msgpopup . text = msg
msgpopup . openPopup ( )
2020-03-04 16:55:40 +01:00
resetWriteButton ( )
}
function onSuccess ( ) {
2020-06-30 00:42:39 +02:00
msgpopup . title = qsTr ( "Write Successful" )
2020-05-23 14:12:23 +02:00
if ( osbutton . text === qsTr ( "Erase" ) )
2020-06-30 00:42:39 +02:00
msgpopup . text = qsTr ( "<b>%1</b> has been erased<br><br>You can now remove the SD card from the reader" ) . arg ( dstbutton . text )
2022-01-21 17:31:52 +01:00
else if ( imageWriter . isEmbeddedMode ( ) ) {
//msgpopup.text = qsTr("<b>%1</b> has been written to <b>%2</b>").arg(osbutton.text).arg(dstbutton.text)
/* Just reboot to the installed OS */
Qt . quit ( )
}
2020-05-23 14:12:23 +02:00
else
2020-06-30 00:42:39 +02:00
msgpopup . text = qsTr ( "<b>%1</b> has been written to <b>%2</b><br><br>You can now remove the SD card from the reader" ) . arg ( osbutton . text ) . arg ( dstbutton . text )
2021-03-06 11:40:46 +01:00
if ( imageWriter . isEmbeddedMode ( ) ) {
msgpopup . continueButton = false
msgpopup . quitButton = true
}
2020-06-30 00:42:39 +02:00
msgpopup . openPopup ( )
2020-03-04 16:55:40 +01:00
imageWriter . setDst ( "" )
2021-02-26 14:51:09 +01:00
dstbutton . text = qsTr ( "CHOOSE STORAGE" )
2020-03-04 16:55:40 +01:00
resetWriteButton ( )
}
function onFileSelected ( file ) {
imageWriter . setSrc ( file )
osbutton . text = imageWriter . srcFileName ( )
ospopup . close ( )
2023-10-05 11:06:22 +01:00
osswipeview . decrementCurrentIndex ( )
2020-03-04 16:55:40 +01:00
if ( imageWriter . readyToWrite ( ) ) {
writebutton . enabled = true
}
}
function onCancelled ( ) {
resetWriteButton ( )
}
function onFinalizing ( ) {
progressText . text = qsTr ( "Finalizing..." )
}
2020-05-25 00:36:16 +02:00
2024-01-15 00:16:43 +01:00
function onNetworkInfo ( msg ) {
networkInfo . text = msg
}
2022-01-20 17:23:47 +01:00
function shuffle ( arr ) {
for ( var i = 0 ; i < arr . length - 1 ; i ++ ) {
var j = i + Math . floor ( Math . random ( ) * ( arr . length - i ) ) ;
var t = arr [ j ] ;
arr [ j ] = arr [ i ] ;
arr [ i ] = t ;
}
}
function checkForRandom ( list ) {
for ( var i in list ) {
var entry = list [ i ]
if ( "subitems" in entry ) {
checkForRandom ( entry [ "subitems" ] )
if ( "random" in entry && entry [ "random" ] ) {
shuffle ( entry [ "subitems" ] )
}
}
}
}
2023-10-10 11:57:01 +01:00
function filterItems ( list , tags , matchingType )
2023-09-23 19:51:45 +02:00
{
if ( ! tags || ! tags . length )
return
var i = list . length
while ( i -- ) {
var entry = list [ i ]
if ( "devices" in entry && entry [ "devices" ] . length ) {
var foundTag = false
2023-10-10 11:57:01 +01:00
switch ( matchingType ) {
2024-07-17 11:07:54 +01:00
case 0 : /* exact matching */
case 2 : /* exact matching */
for ( var j in tags )
{
if ( entry [ "devices" ] . includes ( tags [ j ] ) )
2023-10-10 11:57:01 +01:00
{
2024-07-17 11:07:54 +01:00
foundTag = true
break
}
}
/* If there's no match, remove this item from the list. */
if ( ! foundTag )
{
list . splice ( i , 1 )
continue
}
break
case 1 : /* Exlusive by prefix matching */
case 3 : /* Inclusive by prefix matching */
for ( var deviceTypePrefix in tags ) {
for ( var deviceSpec in entry [ "devices" ] ) {
if ( deviceSpec . startsWith ( deviceTypePrefix ) ) {
2023-10-10 11:57:01 +01:00
foundTag = true
break
}
}
2024-07-17 11:07:54 +01:00
/ * T e r m i n a t e o u t e r l o o p e a r l y i f w e ' v e a l r e a d y
2023-10-10 11:57:01 +01:00
* decided it ' s a match
* /
2024-07-17 11:07:54 +01:00
if ( foundTag ) {
break
2023-10-10 11:57:01 +01:00
}
2024-07-17 11:07:54 +01:00
}
/* If there's no match, remove this item from the list. */
if ( ! foundTag )
{
list . splice ( i , 1 )
continue
}
break
2023-09-23 19:51:45 +02:00
}
2023-10-10 11:57:01 +01:00
} else {
/* No device list attached? If we're in an exclusive mode that's bad news indeed. */
switch ( matchingType ) {
2024-07-17 11:07:54 +01:00
case 0 :
case 1 :
if ( ! ( "subitems" in entry ) ) {
/* If you're not carrying subitems, you're not going in. */
list . splice ( i , 1 )
}
break
case 2 :
case 3 :
/* Inclusive filtering. We're keeping this one. */
break ;
2023-09-23 19:51:45 +02:00
}
}
if ( "subitems" in entry ) {
2023-10-10 11:57:01 +01:00
filterItems ( entry [ "subitems" ] , tags , hwTagMatchingType )
2023-10-19 11:50:29 +01:00
// If this sub-list has no items then hide it
if ( entry [ "subitems" ] . length == 0 ) {
list . splice ( i , 1 )
}
2023-09-23 19:51:45 +02:00
}
}
}
2020-12-01 15:52:33 +01:00
function oslistFromJson ( o ) {
2023-11-09 14:38:34 +00:00
var oslist_parsed = false
2020-12-01 15:52:33 +01:00
var lang_country = Qt . locale ( ) . name
if ( "os_list_" + lang_country in o ) {
2023-11-09 14:38:34 +00:00
oslist_parsed = o [ "os_list_" + lang_country ]
2020-12-01 15:52:33 +01:00
}
2022-01-23 19:30:16 +01:00
else if ( lang_country . includes ( "_" ) ) {
2020-12-01 15:52:33 +01:00
var lang = lang_country . substr ( 0 , lang_country . indexOf ( "_" ) )
if ( "os_list_" + lang in o ) {
2023-11-09 14:38:34 +00:00
oslist_parsed = o [ "os_list_" + lang ]
2020-12-01 15:52:33 +01:00
}
}
2023-11-09 14:38:34 +00:00
if ( ! oslist_parsed ) {
2022-01-23 19:30:16 +01:00
if ( ! "os_list" in o ) {
onError ( qsTr ( "Error parsing os_list.json" ) )
return false
}
2023-11-09 14:38:34 +00:00
oslist_parsed = o [ "os_list" ]
2020-12-01 15:52:33 +01:00
}
2023-11-09 14:38:34 +00:00
checkForRandom ( oslist_parsed )
2022-01-23 19:30:16 +01:00
/* Flatten subitems to subitems_json */
2023-11-09 14:38:34 +00:00
for ( var i in oslist_parsed ) {
var entry = oslist_parsed [ i ] ;
2022-01-23 19:30:16 +01:00
if ( "subitems" in entry ) {
entry [ "subitems_json" ] = JSON . stringify ( entry [ "subitems" ] )
delete entry [ "subitems" ]
}
2020-12-01 15:52:33 +01:00
}
2023-11-09 14:38:34 +00:00
return oslist_parsed
2020-12-01 15:52:33 +01:00
}
2021-11-23 02:53:50 +01:00
function selectNamedOS ( name , collection )
{
for ( var i = 0 ; i < collection . count ; i ++ ) {
var os = collection . get ( i )
2022-01-23 19:30:16 +01:00
if ( typeof ( os . subitems_json ) == "string" && os . subitems_json != "" ) {
selectNamedOS ( name , os . subitems_json )
2021-11-23 02:53:50 +01:00
}
else if ( typeof ( os . url ) !== "undefined" && name === os . name ) {
selectOSitem ( os , false )
break
}
}
}
2020-05-25 00:36:16 +02:00
function fetchOSlist ( ) {
2023-11-09 14:38:34 +00:00
var oslist_json = imageWriter . getFilteredOSlist ( ) ;
var o = JSON . parse ( oslist_json )
var oslist_parsed = oslistFromJson ( o )
if ( oslist_parsed === false )
return
osmodel . clear ( )
for ( var i in oslist_parsed ) {
osmodel . append ( oslist_parsed [ i ] )
}
2020-11-23 19:23:20 +01:00
2023-11-09 14:38:34 +00:00
if ( "imager" in o ) {
var imager = o [ "imager" ]
2023-09-23 19:51:45 +02:00
2023-11-09 14:38:34 +00:00
if ( "devices" in imager )
{
deviceModel . clear ( )
var devices = imager [ "devices" ]
for ( var j in devices )
2023-09-23 19:51:45 +02:00
{
2023-11-09 14:38:34 +00:00
devices [ j ] [ "tags" ] = JSON . stringify ( devices [ j ] [ "tags" ] )
deviceModel . append ( devices [ j ] )
if ( "default" in devices [ j ] && devices [ j ] [ "default" ] )
2023-09-23 19:51:45 +02:00
{
2023-11-09 14:38:34 +00:00
hwlist . currentIndex = deviceModel . count - 1
2023-09-23 19:51:45 +02:00
}
}
2023-11-09 14:38:34 +00:00
}
2023-09-23 19:51:45 +02:00
2023-11-09 14:38:34 +00:00
if ( imageWriter . getBoolSetting ( "check_version" ) && "latest_version" in imager && "url" in imager ) {
if ( ! imageWriter . isEmbeddedMode ( ) && imageWriter . isVersionNewer ( imager [ "latest_version" ] ) ) {
updatepopup . url = imager [ "url" ]
updatepopup . openPopup ( )
2020-11-23 19:23:20 +01:00
}
2023-11-09 14:38:34 +00:00
}
if ( "default_os" in imager ) {
selectNamedOS ( imager [ "default_os" ] , osmodel )
}
if ( imageWriter . isEmbeddedMode ( ) ) {
if ( "embedded_default_os" in imager ) {
selectNamedOS ( imager [ "embedded_default_os" ] , osmodel )
2021-11-23 02:53:50 +01:00
}
2023-11-09 14:38:34 +00:00
if ( "embedded_default_destination" in imager ) {
imageWriter . startDriveListPolling ( )
setDefaultDest . drive = imager [ "embedded_default_destination" ]
setDefaultDest . start ( )
2021-11-23 02:53:50 +01:00
}
2020-11-23 19:23:20 +01:00
}
2023-11-09 14:38:34 +00:00
}
2020-05-25 00:36:16 +02:00
}
2020-06-30 00:42:39 +02:00
2021-11-23 02:53:50 +01:00
Timer {
/* Verify if default drive is in our list after 100 ms */
id: setDefaultDest
property string drive : ""
interval: 100
onTriggered: {
for ( var i = 0 ; i < driveListModel . rowCount ( ) ; i ++ )
{
/ * F I X M E : t h e r e s h o u l d b e a b e t t e r w a y t o i t e r a t e d r i v e l i s t t h a n
fetch data by numeric role number * /
if ( driveListModel . data ( driveListModel . index ( i , 0 ) , 0x101 ) === drive ) {
selectDstItem ( {
2024-07-17 11:07:54 +01:00
device: drive ,
description: driveListModel . data ( driveListModel . index ( i , 0 ) , 0x102 ) ,
size: driveListModel . data ( driveListModel . index ( i , 0 ) , 0x103 ) ,
readonly: false
} )
2021-11-23 02:53:50 +01:00
break
}
}
}
}
2020-12-01 15:52:33 +01:00
function newSublist ( ) {
if ( osswipeview . currentIndex == ( osswipeview . count - 1 ) )
{
var newlist = suboslist . createObject ( osswipeview )
osswipeview . addItem ( newlist )
}
var m = osswipeview . itemAt ( osswipeview . currentIndex + 1 ) . model
if ( m . count > 1 )
{
m . remove ( 1 , m . count - 1 )
}
return m
}
2023-10-03 22:24:49 +01:00
function selectHWitem ( hwmodel ) {
2023-11-13 11:46:31 +00:00
/* Default is exclusive matching */
var inclusive = false
2023-10-11 13:22:32 +01:00
2023-10-10 11:57:01 +01:00
if ( hwmodel . matching_type ) {
switch ( hwmodel . matching_type ) {
2024-07-17 11:07:54 +01:00
case "exclusive" :
break ;
case "inclusive" :
inclusive = true
break ;
2023-10-10 11:57:01 +01:00
}
}
2023-11-13 11:46:31 +00:00
imageWriter . setHWFilterList ( hwmodel . tags , inclusive )
2023-10-03 22:24:49 +01:00
/* Reload list */
2023-11-09 14:38:34 +00:00
var oslist_json = imageWriter . getFilteredOSlist ( ) ;
var o = JSON . parse ( oslist_json )
var oslist_parsed = oslistFromJson ( o )
if ( oslist_parsed === false )
return
2023-10-03 22:24:49 +01:00
2023-11-09 14:38:34 +00:00
/ * A s w e ' r e f i l t e r i n g t h e O S l i s t , w e n e e d t o e n s u r e w e p r e s e n t a ' R e c o m m e n d e d ' O S .
* To do this , we exploit a convention of how we build the OS list . By convention ,
* the preferred OS for a device is listed at the top level of the list , and is at the
* lowest index . So . .
* /
if ( oslist_parsed . length != 0 ) {
var candidate = oslist_parsed [ 0 ]
2023-10-20 11:42:37 +01:00
2024-07-17 11:05:51 +01:00
if ( "description" in candidate &&
! ( "subitems" in candidate ) &&
! candidate [ "description" ] . includes ( "(Recommended)" )
)
{
2023-11-09 14:38:34 +00:00
candidate [ "description" ] += " (Recommended)"
2023-10-20 11:42:37 +01:00
}
2023-11-09 14:38:34 +00:00
}
2023-10-20 11:42:37 +01:00
2023-11-09 14:38:34 +00:00
osmodel . clear ( )
for ( var i in oslist_parsed ) {
osmodel . append ( oslist_parsed [ i ] )
}
2023-10-03 22:24:49 +01:00
2023-10-19 11:50:29 +01:00
// When the HW device is changed, reset the OS selection otherwise
// you get a weird effect with the selection moving around in the list
// when the user next opens the OS list, and the user could still have
// an OS selected which isn't compatible with this HW device
oslist . currentIndex = - 1
osswipeview . currentIndex = 0
2023-10-21 11:04:09 +02:00
imageWriter . setSrc ( "" )
2024-10-11 02:24:56 -04:00
osbutton . text = qsTr ( "CHOOSE CFW" )
2023-10-19 11:50:29 +01:00
writebutton . enabled = false
2023-10-03 22:24:49 +01:00
hwbutton . text = hwmodel . name
hwpopup . close ( )
}
2023-10-17 15:35:44 +01:00
/// Is the item a sub-list or sub-sub-list in the OS selection model?
function isOSsublist ( d ) {
// Top level category
if ( typeof ( d . subitems_json ) == "string" && d . subitems_json !== "" ) {
return true
}
// Sub-category
if ( typeof ( d . subitems_url ) == "string" && d . subitems_url !== ""
2024-07-17 11:07:54 +01:00
&& d . subitems_url !== "internal://back" )
2023-10-17 15:35:44 +01:00
{
return true
}
return false
}
2020-06-30 00:42:39 +02:00
function selectOSitem ( d , selectFirstSubitem )
{
2022-01-23 19:30:16 +01:00
if ( typeof ( d . subitems_json ) == "string" && d . subitems_json !== "" ) {
2020-12-01 15:52:33 +01:00
var m = newSublist ( )
2022-01-23 19:30:16 +01:00
var subitems = JSON . parse ( d . subitems_json )
2020-12-01 15:52:33 +01:00
2022-01-23 19:30:16 +01:00
for ( var i in subitems )
2020-06-30 00:42:39 +02:00
{
2022-01-23 19:30:16 +01:00
var entry = subitems [ i ] ;
if ( "subitems" in entry ) {
/* Flatten sub-subitems entry */
entry [ "subitems_json" ] = JSON . stringify ( entry [ "subitems" ] )
delete entry [ "subitems" ]
}
m . append ( entry )
2020-06-30 00:42:39 +02:00
}
2020-12-01 15:52:33 +01:00
osswipeview . itemAt ( osswipeview . currentIndex + 1 ) . currentIndex = ( selectFirstSubitem === true ) ? 0 : - 1
osswipeview . incrementCurrentIndex ( )
2020-11-26 22:26:15 +01:00
ospopup . categorySelected = d . name
2020-06-30 00:42:39 +02:00
} else if ( typeof ( d . subitems_url ) == "string" && d . subitems_url !== "" ) {
if ( d . subitems_url === "internal://back" )
{
2020-12-01 15:52:33 +01:00
osswipeview . decrementCurrentIndex ( )
2020-11-26 22:26:15 +01:00
ospopup . categorySelected = ""
2020-06-30 00:42:39 +02:00
}
else
{
2023-11-09 14:38:34 +00:00
console . log ( "Failure: Backend should have pre-flattened the JSON!" ) ;
2020-06-30 00:42:39 +02:00
2020-12-01 15:52:33 +01:00
osswipeview . itemAt ( osswipeview . currentIndex + 1 ) . currentIndex = ( selectFirstSubitem === true ) ? 0 : - 1
osswipeview . incrementCurrentIndex ( )
2020-06-30 00:42:39 +02:00
}
} else if ( d . url === "" ) {
if ( ! imageWriter . isEmbeddedMode ( ) ) {
imageWriter . openFileDialog ( )
}
else {
if ( imageWriter . mountUsbSourceMedia ( ) ) {
2020-12-01 15:52:33 +01:00
var m = newSublist ( )
2020-06-30 00:42:39 +02:00
2023-11-09 14:38:34 +00:00
var usboslist = JSON . parse ( imageWriter . getUsbSourceOSlist ( ) )
for ( var i in usboslist ) {
m . append ( usboslist [ i ] )
2020-06-30 00:42:39 +02:00
}
2020-12-01 15:52:33 +01:00
osswipeview . itemAt ( osswipeview . currentIndex + 1 ) . currentIndex = ( selectFirstSubitem === true ) ? 0 : - 1
osswipeview . incrementCurrentIndex ( )
2020-06-30 00:42:39 +02:00
}
else
{
onError ( qsTr ( "Connect an USB stick containing images first.<br>The images must be located in the root folder of the USB stick." ) )
}
}
} else {
2021-11-18 20:48:24 +01:00
imageWriter . setSrc ( d . url , d . image_download_size , d . extract_size , typeof ( d . extract_sha256 ) != "undefined" ? d.extract_sha256 : "" , typeof ( d . contains_multiple_files ) != "undefined" ? d.contains_multiple_files : false , ospopup . categorySelected , d . name , typeof ( d . init_format ) != "undefined" ? d.init_format : "" )
2020-06-30 00:42:39 +02:00
osbutton . text = d . name
ospopup . close ( )
2023-10-05 11:06:22 +01:00
osswipeview . decrementCurrentIndex ( )
2020-06-30 00:42:39 +02:00
if ( imageWriter . readyToWrite ( ) ) {
writebutton . enabled = true
}
}
}
2020-07-03 21:16:49 +02:00
function selectDstItem ( d ) {
if ( d . isReadOnly ) {
onError ( qsTr ( "SD card is write protected.<br>Push the lock switch on the left side of the card upwards, and try again." ) )
return
}
dstpopup . close ( )
imageWriter . setDst ( d . device , d . size )
dstbutton . text = d . description
if ( imageWriter . readyToWrite ( ) ) {
writebutton . enabled = true
}
}
2020-03-04 16:55:40 +01:00
}