summaryrefslogtreecommitdiff
path: root/utils/rbutilqt/gui
diff options
context:
space:
mode:
Diffstat (limited to 'utils/rbutilqt/gui')
-rw-r--r--utils/rbutilqt/gui/backupdialog.cpp152
-rw-r--r--utils/rbutilqt/gui/backupdialog.h48
-rw-r--r--utils/rbutilqt/gui/backupdialogfrm.ui145
-rw-r--r--utils/rbutilqt/gui/changelog.cpp78
-rw-r--r--utils/rbutilqt/gui/changelog.h40
-rw-r--r--utils/rbutilqt/gui/changelogfrm.ui60
-rw-r--r--utils/rbutilqt/gui/comboboxviewdelegate.cpp56
-rw-r--r--utils/rbutilqt/gui/comboboxviewdelegate.h30
-rw-r--r--utils/rbutilqt/gui/infowidget.cpp112
-rw-r--r--utils/rbutilqt/gui/infowidget.h41
-rw-r--r--utils/rbutilqt/gui/infowidgetfrm.ui43
-rw-r--r--utils/rbutilqt/gui/selectiveinstallwidget.cpp691
-rw-r--r--utils/rbutilqt/gui/selectiveinstallwidget.h74
-rw-r--r--utils/rbutilqt/gui/selectiveinstallwidgetfrm.ui316
14 files changed, 1886 insertions, 0 deletions
diff --git a/utils/rbutilqt/gui/backupdialog.cpp b/utils/rbutilqt/gui/backupdialog.cpp
new file mode 100644
index 0000000000..f12c47b570
--- /dev/null
+++ b/utils/rbutilqt/gui/backupdialog.cpp
@@ -0,0 +1,152 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2012 by Dominik Riebeling
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19#include <QThread>
20#include <QDialog>
21#include <QMessageBox>
22#include <QFileDialog>
23#include "backupdialog.h"
24#include "ui_backupdialogfrm.h"
25#include "rbsettings.h"
26#include "progressloggergui.h"
27#include "ziputil.h"
28#include "rockboxinfo.h"
29#include "Logger.h"
30
31class BackupSizeThread : public QThread
32{
33 public:
34 void run(void);
35 void setPath(QString p) { m_path = p; }
36 qint64 currentSize(void) { return m_currentSize; }
37
38 private:
39 QString m_path;
40 qint64 m_currentSize;
41};
42
43
44void BackupSizeThread::run(void)
45{
46 LOG_INFO() << "Thread started, calculating" << m_path;
47 m_currentSize = 0;
48
49 QDirIterator it(m_path, QDirIterator::Subdirectories);
50 while(it.hasNext()) {
51 m_currentSize += QFileInfo(it.next()).size();
52 }
53 LOG_INFO() << "Thread done, sum:" << m_currentSize;
54}
55
56
57BackupDialog::BackupDialog(QWidget* parent) : QDialog(parent)
58{
59 ui.setupUi(this);
60
61 m_thread = new BackupSizeThread();
62 connect(m_thread, SIGNAL(finished()), this, SLOT(updateSizeInfo()));
63 connect(m_thread, SIGNAL(terminated()), this, SLOT(updateSizeInfo()));
64
65 connect(ui.buttonCancel, SIGNAL(clicked()), this, SLOT(close()));
66 connect(ui.buttonCancel, SIGNAL(clicked()), m_thread, SLOT(quit()));
67 connect(ui.buttonChange, SIGNAL(clicked()), this, SLOT(changeBackupPath()));
68 connect(ui.buttonBackup, SIGNAL(clicked()), this, SLOT(backup()));
69
70 ui.backupSize->setText(tr("Installation size: calculating ..."));
71 m_mountpoint = RbSettings::value(RbSettings::Mountpoint).toString();
72
73 m_backupName = RbSettings::value(RbSettings::BackupPath).toString();
74 if(m_backupName.isEmpty()) {
75 m_backupName = m_mountpoint;
76 }
77 RockboxInfo info(m_mountpoint);
78 m_backupName += "/.backup/rockbox-backup-" + info.version() + ".zip";
79 ui.backupLocation->setText(QDir::toNativeSeparators(m_backupName));
80
81 m_thread->setPath(m_mountpoint + "/.rockbox");
82 m_thread->start();
83}
84
85
86void BackupDialog::changeBackupPath(void)
87{
88 QString backupString = QFileDialog::getSaveFileName(this,
89 tr("Select Backup Filename"), m_backupName, "*.zip");
90 // only update if a filename was entered, ignore if cancelled
91 if(!backupString.isEmpty()) {
92 m_backupName = backupString;
93 ui.backupLocation->setText(QDir::toNativeSeparators(m_backupName));
94 RbSettings::setValue(RbSettings::BackupPath, QFileInfo(m_backupName).absolutePath());
95 }
96}
97
98
99void BackupDialog::updateSizeInfo(void)
100{
101 double size = m_thread->currentSize() / (1024 * 1024);
102 QString unit = "MiB";
103
104 if(size > 1024) {
105 size /= 1024;
106 unit = "GiB";
107 }
108
109 ui.backupSize->setText(tr("Installation size: %L1 %2").arg(size, 0, 'g', 4).arg(unit));
110}
111
112
113void BackupDialog::backup(void)
114{
115 if(QFileInfo(m_backupName).isFile()) {
116 if(QMessageBox::warning(this, tr("File exists"),
117 tr("The selected backup file already exists. Overwrite?"),
118 QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) {
119 return;
120 }
121 }
122 m_logger = new ProgressLoggerGui(this);
123 connect(m_logger, SIGNAL(closed()), this, SLOT(close()));
124 m_logger->show();
125 m_logger->addItem(tr("Starting backup ..."),LOGINFO);
126 QCoreApplication::processEvents();
127
128 // create dir, if it doesnt exist
129 QFileInfo backupFile(m_backupName);
130 if(!QDir(backupFile.path()).exists())
131 {
132 QDir a;
133 a.mkpath(backupFile.path());
134 }
135
136 // create backup
137 ZipUtil zip(this);
138 connect(&zip, SIGNAL(logProgress(int, int)), m_logger, SLOT(setProgress(int, int)));
139 connect(&zip, SIGNAL(logItem(QString, int)), m_logger, SLOT(addItem(QString, int)));
140 zip.open(m_backupName, QuaZip::mdCreate);
141
142 QString mp = m_mountpoint + "/.rockbox";
143 if(zip.appendDirToArchive(mp, m_mountpoint)) {
144 m_logger->addItem(tr("Backup successful."), LOGINFO);
145 }
146 else {
147 m_logger->addItem(tr("Backup failed!"), LOGERROR);
148 }
149 zip.close();
150 m_logger->setFinished();
151}
152
diff --git a/utils/rbutilqt/gui/backupdialog.h b/utils/rbutilqt/gui/backupdialog.h
new file mode 100644
index 0000000000..185166134a
--- /dev/null
+++ b/utils/rbutilqt/gui/backupdialog.h
@@ -0,0 +1,48 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2012 by Dominik Riebeling
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19#ifndef BACKUPDIALOG_H
20#define BACKUPDIALOG_H
21
22#include <QDialog>
23#include "ui_backupdialogfrm.h"
24#include "progressloggergui.h"
25
26class BackupSizeThread;
27
28class BackupDialog : public QDialog
29{
30 Q_OBJECT
31 public:
32 BackupDialog(QWidget* parent = nullptr);
33
34 private slots:
35 void changeBackupPath(void);
36 void updateSizeInfo(void);
37 void backup(void);
38
39 private:
40 Ui::BackupDialog ui;
41 QString m_backupName;
42 QString m_mountpoint;
43 BackupSizeThread *m_thread;
44 ProgressLoggerGui *m_logger;
45};
46
47#endif
48
diff --git a/utils/rbutilqt/gui/backupdialogfrm.ui b/utils/rbutilqt/gui/backupdialogfrm.ui
new file mode 100644
index 0000000000..f843ad3a65
--- /dev/null
+++ b/utils/rbutilqt/gui/backupdialogfrm.ui
@@ -0,0 +1,145 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>BackupDialog</class>
4 <widget class="QDialog" name="BackupDialog">
5 <property name="windowModality">
6 <enum>Qt::WindowModal</enum>
7 </property>
8 <property name="geometry">
9 <rect>
10 <x>0</x>
11 <y>0</y>
12 <width>554</width>
13 <height>448</height>
14 </rect>
15 </property>
16 <property name="windowTitle">
17 <string>Backup</string>
18 </property>
19 <layout class="QGridLayout" name="gridLayout_2">
20 <item row="0" column="0" rowspan="4">
21 <widget class="QLabel" name="label_4">
22 <property name="text">
23 <string/>
24 </property>
25 <property name="pixmap">
26 <pixmap resource="../rbutilqt.qrc">:/icons/wizard.jpg</pixmap>
27 </property>
28 </widget>
29 </item>
30 <item row="0" column="1" colspan="3">
31 <widget class="QLabel" name="label_2">
32 <property name="text">
33 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This dialog will create a backup by archiving the contents of the Rockbox installation on the player into a zip file. This will include installed themes and settings stored below the .rockbox folder on the player.&lt;/p&gt;&lt;p&gt;The backup filename will be created based on the installed version. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
34 </property>
35 <property name="wordWrap">
36 <bool>true</bool>
37 </property>
38 </widget>
39 </item>
40 <item row="1" column="1" colspan="3">
41 <widget class="QGroupBox" name="groupBox">
42 <property name="title">
43 <string>Backup</string>
44 </property>
45 <layout class="QGridLayout" name="gridLayout">
46 <item row="0" column="0">
47 <widget class="QLabel" name="backupSize">
48 <property name="text">
49 <string>Size: unknown</string>
50 </property>
51 </widget>
52 </item>
53 <item row="1" column="0">
54 <widget class="QLabel" name="backupLocation">
55 <property name="text">
56 <string>Backup to: unknown</string>
57 </property>
58 </widget>
59 </item>
60 <item row="1" column="1">
61 <spacer name="horizontalSpacer">
62 <property name="orientation">
63 <enum>Qt::Horizontal</enum>
64 </property>
65 <property name="sizeHint" stdset="0">
66 <size>
67 <width>78</width>
68 <height>20</height>
69 </size>
70 </property>
71 </spacer>
72 </item>
73 <item row="1" column="2">
74 <widget class="QPushButton" name="buttonChange">
75 <property name="text">
76 <string>&amp;Change</string>
77 </property>
78 <property name="icon">
79 <iconset resource="../rbutilqt.qrc">
80 <normaloff>:/icons/edit-find.svg</normaloff>:/icons/edit-find.svg</iconset>
81 </property>
82 </widget>
83 </item>
84 </layout>
85 </widget>
86 </item>
87 <item row="2" column="2" colspan="2">
88 <spacer name="verticalSpacer">
89 <property name="orientation">
90 <enum>Qt::Vertical</enum>
91 </property>
92 <property name="sizeHint" stdset="0">
93 <size>
94 <width>20</width>
95 <height>1</height>
96 </size>
97 </property>
98 </spacer>
99 </item>
100 <item row="3" column="1">
101 <spacer name="horizontalSpacer_2">
102 <property name="orientation">
103 <enum>Qt::Horizontal</enum>
104 </property>
105 <property name="sizeHint" stdset="0">
106 <size>
107 <width>143</width>
108 <height>20</height>
109 </size>
110 </property>
111 </spacer>
112 </item>
113 <item row="3" column="2">
114 <widget class="QPushButton" name="buttonBackup">
115 <property name="text">
116 <string>&amp;Backup</string>
117 </property>
118 <property name="icon">
119 <iconset resource="../rbutilqt.qrc">
120 <normaloff>:/icons/go-next.svg</normaloff>:/icons/go-next.svg</iconset>
121 </property>
122 </widget>
123 </item>
124 <item row="3" column="3">
125 <widget class="QPushButton" name="buttonCancel">
126 <property name="text">
127 <string>&amp;Cancel</string>
128 </property>
129 <property name="icon">
130 <iconset resource="../rbutilqt.qrc">
131 <normaloff>:/icons/process-stop.svg</normaloff>:/icons/process-stop.svg</iconset>
132 </property>
133 </widget>
134 </item>
135 </layout>
136 </widget>
137 <tabstops>
138 <tabstop>buttonBackup</tabstop>
139 <tabstop>buttonCancel</tabstop>
140 </tabstops>
141 <resources>
142 <include location="../rbutilqt.qrc"/>
143 </resources>
144 <connections/>
145</ui>
diff --git a/utils/rbutilqt/gui/changelog.cpp b/utils/rbutilqt/gui/changelog.cpp
new file mode 100644
index 0000000000..79d601e412
--- /dev/null
+++ b/utils/rbutilqt/gui/changelog.cpp
@@ -0,0 +1,78 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2013 by Dominik Riebeling
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19#include "changelog.h"
20#include "rbsettings.h"
21#include "ui_changelogfrm.h"
22
23Changelog::Changelog(QWidget *parent) : QDialog(parent)
24{
25 ui.setupUi(this);
26 ui.browserChangelog->setOpenExternalLinks(true);
27 // FIXME: support translated changelog file (changelog.de.txt etc)
28 ui.browserChangelog->setHtml(parseChangelogFile(":/docs/changelog.txt"));
29 ui.browserChangelog->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
30 ui.checkBoxShowAlways->setChecked(RbSettings::value(RbSettings::ShowChangelog).toBool());
31 connect(ui.buttonOk, SIGNAL(clicked()), this, SLOT(accept()));
32}
33
34
35void Changelog::accept(void)
36{
37 RbSettings::setValue(RbSettings::ShowChangelog, ui.checkBoxShowAlways->isChecked());
38 this->hide();
39 this->deleteLater();
40}
41
42
43QString Changelog::parseChangelogFile(QString filename)
44{
45 QFile changelog(filename);
46 changelog.open(QIODevice::ReadOnly);
47 QTextStream c(&changelog);
48#if QT_VERSION < 0x060000
49 c.setCodec(QTextCodec::codecForName("UTF-8"));
50#else
51 c.setEncoding(QStringConverter::Utf8);
52#endif
53 QString text;
54 while(!c.atEnd()) {
55 QString line = c.readLine();
56 if(line.startsWith("#"))
57 continue;
58 if(line.startsWith("Version")) {
59 text.append(QString("<h4>Rockbox Utility %1</h4>").arg(line.remove("Version")));
60 line = c.readLine();
61 text.append("<ul>");
62 while(line.startsWith("*")) {
63 QString t = line.remove(QRegExp("^\\*"));
64 t.replace(QRegExp("FS#(\\d+)"),
65 "<a href='http://www.rockbox.org/tracker/task/\\1'>FS#\\1</a>");
66 t.replace(QRegExp("G#(\\d+)"),
67 "<a href='http://gerrit.rockbox.org/r/\\1'>G#\\1</a>");
68 text.append(QString("<li>%1</li>").arg(t));
69 line = c.readLine();
70 if(line.startsWith("#"))
71 line = c.readLine();
72 }
73 text.append("</ul>");
74 }
75 }
76 changelog.close();
77 return text;
78}
diff --git a/utils/rbutilqt/gui/changelog.h b/utils/rbutilqt/gui/changelog.h
new file mode 100644
index 0000000000..aca2a6ed32
--- /dev/null
+++ b/utils/rbutilqt/gui/changelog.h
@@ -0,0 +1,40 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2013 by Dominik Riebeling
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19#ifndef CHANGELOG_H
20#define CHANGELOG_H
21
22#include <QDialog>
23#include "ui_changelogfrm.h"
24
25class Changelog : public QDialog
26{
27 Q_OBJECT
28public:
29 Changelog(QWidget *parent = nullptr);
30
31public slots:
32 void accept(void);
33
34private:
35 QString parseChangelogFile(QString filename);
36 Ui::Changelog ui;
37
38};
39
40#endif
diff --git a/utils/rbutilqt/gui/changelogfrm.ui b/utils/rbutilqt/gui/changelogfrm.ui
new file mode 100644
index 0000000000..0a28ee2421
--- /dev/null
+++ b/utils/rbutilqt/gui/changelogfrm.ui
@@ -0,0 +1,60 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>Changelog</class>
4 <widget class="QDialog" name="Changelog">
5 <property name="windowModality">
6 <enum>Qt::WindowModal</enum>
7 </property>
8 <property name="geometry">
9 <rect>
10 <x>0</x>
11 <y>0</y>
12 <width>500</width>
13 <height>400</height>
14 </rect>
15 </property>
16 <property name="windowTitle">
17 <string>Changelog</string>
18 </property>
19 <layout class="QGridLayout" name="gridLayout">
20 <item row="0" column="0" colspan="3">
21 <widget class="QTextBrowser" name="browserChangelog"/>
22 </item>
23 <item row="1" column="1">
24 <spacer name="horizontalSpacer">
25 <property name="orientation">
26 <enum>Qt::Horizontal</enum>
27 </property>
28 <property name="sizeHint" stdset="0">
29 <size>
30 <width>40</width>
31 <height>20</height>
32 </size>
33 </property>
34 </spacer>
35 </item>
36 <item row="1" column="0">
37 <widget class="QCheckBox" name="checkBoxShowAlways">
38 <property name="text">
39 <string>Show on startup</string>
40 </property>
41 </widget>
42 </item>
43 <item row="1" column="2">
44 <widget class="QPushButton" name="buttonOk">
45 <property name="text">
46 <string>&amp;Ok</string>
47 </property>
48 <property name="icon">
49 <iconset resource="../rbutilqt.qrc">
50 <normaloff>:/icons/go-next.svg</normaloff>:/icons/go-next.svg</iconset>
51 </property>
52 </widget>
53 </item>
54 </layout>
55 </widget>
56 <resources>
57 <include location="../rbutilqt.qrc"/>
58 </resources>
59 <connections/>
60</ui>
diff --git a/utils/rbutilqt/gui/comboboxviewdelegate.cpp b/utils/rbutilqt/gui/comboboxviewdelegate.cpp
new file mode 100644
index 0000000000..91489d10c0
--- /dev/null
+++ b/utils/rbutilqt/gui/comboboxviewdelegate.cpp
@@ -0,0 +1,56 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2011 by Dominik Riebeling
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19#include <QStyledItemDelegate>
20#include <QPainter>
21#include <QApplication>
22#include <qdebug.h>
23#include "comboboxviewdelegate.h"
24
25void ComboBoxViewDelegate::paint(QPainter *painter,
26 const QStyleOptionViewItem &option, const QModelIndex &index) const
27{
28 QPen pen;
29 QFont font;
30 pen = painter->pen();
31 font = painter->font();
32
33 painter->save();
34 // paint selection
35 if(option.state & QStyle::State_Selected) {
36 painter->setPen(QPen(Qt::NoPen));
37 painter->setBrush(QApplication::palette().highlight());
38 painter->drawRect(option.rect);
39 painter->restore();
40 painter->save();
41 pen.setColor(QApplication::palette().color(QPalette::HighlightedText));
42 }
43 else {
44 pen.setColor(QApplication::palette().color(QPalette::Text));
45 }
46 // draw data (text)
47 painter->setPen(pen);
48 painter->drawText(option.rect, Qt::AlignLeft, index.data().toString());
49
50 // draw user data right aligned, italic
51 font.setItalic(true);
52 painter->setFont(font);
53 painter->drawText(option.rect, Qt::AlignRight, index.data(Qt::UserRole).toString());
54 painter->restore();
55}
56
diff --git a/utils/rbutilqt/gui/comboboxviewdelegate.h b/utils/rbutilqt/gui/comboboxviewdelegate.h
new file mode 100644
index 0000000000..a0070bb126
--- /dev/null
+++ b/utils/rbutilqt/gui/comboboxviewdelegate.h
@@ -0,0 +1,30 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2011 by Dominik Riebeling
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19#include <QStyledItemDelegate>
20
21class ComboBoxViewDelegate : public QStyledItemDelegate
22{
23 Q_OBJECT
24 public:
25 ComboBoxViewDelegate(QObject* parent = nullptr) : QStyledItemDelegate(parent) { }
26
27 void paint(QPainter *painter, const QStyleOptionViewItem &option,
28 const QModelIndex &index) const;
29};
30
diff --git a/utils/rbutilqt/gui/infowidget.cpp b/utils/rbutilqt/gui/infowidget.cpp
new file mode 100644
index 0000000000..25b0503090
--- /dev/null
+++ b/utils/rbutilqt/gui/infowidget.cpp
@@ -0,0 +1,112 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2012 by Dominik Riebeling
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19#include <QWidget>
20#include <QDebug>
21#include "infowidget.h"
22#include "rbsettings.h"
23#include "Logger.h"
24
25InfoWidget::InfoWidget(QWidget *parent) : QWidget(parent)
26{
27 ui.setupUi(this);
28
29 ui.treeInfo->setAlternatingRowColors(true);
30 ui.treeInfo->setHeaderLabels(QStringList() << tr("File") << tr("Version"));
31 ui.treeInfo->expandAll();
32 ui.treeInfo->setColumnCount(2);
33 ui.treeInfo->setLayoutDirection(Qt::LeftToRight);
34}
35
36
37void InfoWidget::updateInfo(void)
38{
39 LOG_INFO() << "updating server info";
40
41 QString mp = RbSettings::value(RbSettings::Mountpoint).toString();
42 QSettings log(mp + "/.rockbox/rbutil.log", QSettings::IniFormat, this);
43 QStringList groups = log.childGroups();
44 QList<QTreeWidgetItem *> items;
45 QTreeWidgetItem *w, *w2;
46 QString min, max;
47 int olditems = 0;
48
49 // remove old list entries (if any)
50 int l = ui.treeInfo->topLevelItemCount();
51 while(l--) {
52 QTreeWidgetItem *m;
53 m = ui.treeInfo->takeTopLevelItem(l);
54 // delete childs (single level deep, no recursion here)
55 int n = m->childCount();
56 while(n--)
57 delete m->child(n);
58 }
59 // get and populate new items
60 for(int a = 0; a < groups.size(); a++) {
61 log.beginGroup(groups.at(a));
62 QStringList keys = log.allKeys();
63 w = new QTreeWidgetItem;
64 w->setFlags(Qt::ItemIsEnabled);
65 w->setText(0, groups.at(a));
66 items.append(w);
67 // get minimum and maximum version information so we can hilight old files
68 min = max = log.value(keys.at(0)).toString();
69 for(int b = 0; b < keys.size(); b++) {
70 if(log.value(keys.at(b)).toString() > max)
71 max = log.value(keys.at(b)).toString();
72 if(log.value(keys.at(b)).toString() < min)
73 min = log.value(keys.at(b)).toString();
74 }
75
76 for(int b = 0; b < keys.size(); b++) {
77 QString file;
78 file = mp + "/" + keys.at(b);
79 if(QFileInfo(file).isDir())
80 continue;
81 w2 = new QTreeWidgetItem(w, QStringList() << "/"
82 + keys.at(b) << log.value(keys.at(b)).toString());
83 if(log.value(keys.at(b)).toString() != max) {
84 w2->setForeground(0, QBrush(QColor(255, 0, 0)));
85 w2->setForeground(1, QBrush(QColor(255, 0, 0)));
86 olditems++;
87 }
88 items.append(w2);
89 }
90 log.endGroup();
91 if(min != max)
92 w->setData(1, Qt::DisplayRole, QString("%1 / %2").arg(min, max));
93 else
94 w->setData(1, Qt::DisplayRole, max);
95 }
96 ui.treeInfo->insertTopLevelItems(0, items);
97 ui.treeInfo->expandAll();
98 ui.treeInfo->resizeColumnToContents(0);
99 ui.treeInfo->collapseAll();
100}
101
102
103void InfoWidget::changeEvent(QEvent *e)
104{
105 if(e->type() == QEvent::LanguageChange) {
106 ui.retranslateUi(this);
107 ui.treeInfo->setHeaderLabels(QStringList() << tr("File") << tr("Version"));
108 } else {
109 QWidget::changeEvent(e);
110 }
111}
112
diff --git a/utils/rbutilqt/gui/infowidget.h b/utils/rbutilqt/gui/infowidget.h
new file mode 100644
index 0000000000..51eef0a37a
--- /dev/null
+++ b/utils/rbutilqt/gui/infowidget.h
@@ -0,0 +1,41 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2012 by Dominik Riebeling
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19#ifndef INFOWIDGET_H
20#define INFOWIDGET_H
21
22#include <QWidget>
23#include "ui_infowidgetfrm.h"
24
25class InfoWidget : public QWidget
26{
27 Q_OBJECT
28 public:
29 InfoWidget(QWidget *parent = nullptr);
30
31 public slots:
32 void updateInfo(void);
33
34 private:
35 void changeEvent(QEvent *e);
36
37 Ui::InfoWidgetFrm ui;
38};
39
40#endif
41
diff --git a/utils/rbutilqt/gui/infowidgetfrm.ui b/utils/rbutilqt/gui/infowidgetfrm.ui
new file mode 100644
index 0000000000..8c7fdb30f7
--- /dev/null
+++ b/utils/rbutilqt/gui/infowidgetfrm.ui
@@ -0,0 +1,43 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>InfoWidgetFrm</class>
4 <widget class="QWidget" name="InfoWidgetFrm">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>400</width>
10 <height>300</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Info</string>
15 </property>
16 <layout class="QGridLayout" name="gridLayout">
17 <item row="0" column="0">
18 <widget class="QLabel" name="labelInfo">
19 <property name="text">
20 <string>Currently installed packages.&lt;br/&gt;&lt;b&gt;Note:&lt;/b&gt; if you manually installed packages this might not be correct!</string>
21 </property>
22 <property name="textFormat">
23 <enum>Qt::RichText</enum>
24 </property>
25 <property name="wordWrap">
26 <bool>true</bool>
27 </property>
28 </widget>
29 </item>
30 <item row="1" column="0">
31 <widget class="QTreeWidget" name="treeInfo">
32 <column>
33 <property name="text">
34 <string>Package</string>
35 </property>
36 </column>
37 </widget>
38 </item>
39 </layout>
40 </widget>
41 <resources/>
42 <connections/>
43</ui>
diff --git a/utils/rbutilqt/gui/selectiveinstallwidget.cpp b/utils/rbutilqt/gui/selectiveinstallwidget.cpp
new file mode 100644
index 0000000000..9bfe7414a3
--- /dev/null
+++ b/utils/rbutilqt/gui/selectiveinstallwidget.cpp
@@ -0,0 +1,691 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2012 by Dominik Riebeling
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19#include <QWidget>
20#include <QMessageBox>
21#include <QFileDialog>
22#include "selectiveinstallwidget.h"
23#include "ui_selectiveinstallwidgetfrm.h"
24#include "playerbuildinfo.h"
25#include "rbsettings.h"
26#include "rockboxinfo.h"
27#include "progressloggergui.h"
28#include "bootloaderinstallbase.h"
29#include "bootloaderinstallhelper.h"
30#include "themesinstallwindow.h"
31#include "utils.h"
32#include "Logger.h"
33
34SelectiveInstallWidget::SelectiveInstallWidget(QWidget* parent) : QWidget(parent)
35{
36 ui.setupUi(this);
37 ui.rockboxCheckbox->setChecked(RbSettings::value(RbSettings::InstallRockbox).toBool());
38 ui.fontsCheckbox->setChecked(RbSettings::value(RbSettings::InstallFonts).toBool());
39 ui.themesCheckbox->setChecked(RbSettings::value(RbSettings::InstallThemes).toBool());
40 ui.pluginDataCheckbox->setChecked(RbSettings::value(RbSettings::InstallPluginData).toBool());
41 ui.voiceCheckbox->setChecked(RbSettings::value(RbSettings::InstallVoice).toBool());
42 ui.manualCheckbox->setChecked(RbSettings::value(RbSettings::InstallManual).toBool());
43
44 ui.manualCombobox->addItem("PDF", "pdf");
45 ui.manualCombobox->addItem("HTML (zip)", "zip");
46 ui.manualCombobox->addItem("HTML", "html");
47
48 // check if Rockbox is installed by looking after rockbox-info.txt.
49 // If installed uncheck bootloader installation.
50 RockboxInfo info(m_mountpoint);
51 ui.bootloaderCheckbox->setChecked(!info.success());
52
53 m_logger = nullptr;
54 m_zipinstaller = nullptr;
55 m_themesinstaller = nullptr;
56
57 connect(ui.installButton, &QAbstractButton::clicked,
58 this, &SelectiveInstallWidget::startInstall);
59 connect(this, &SelectiveInstallWidget::installSkipped,
60 this, &SelectiveInstallWidget::continueInstall);
61 connect(ui.themesCustomize, &QAbstractButton::clicked,
62 this, &SelectiveInstallWidget::customizeThemes);
63 connect(ui.selectedVersion, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
64 this, &SelectiveInstallWidget::selectedVersionChanged);
65 // update version information. This also handles setting the previously
66 // selected build type and bootloader disabling.
67 updateVersion();
68}
69
70
71void SelectiveInstallWidget::selectedVersionChanged(int index)
72{
73 m_buildtype = static_cast<PlayerBuildInfo::BuildType>(ui.selectedVersion->itemData(index).toInt());
74 bool voice = true;
75 switch(m_buildtype) {
76 case PlayerBuildInfo::TypeRelease:
77 ui.selectedDescription->setText(tr("This is the latest stable "
78 "release available."));
79 voice = true;
80 break;
81 case PlayerBuildInfo::TypeDevel:
82 ui.selectedDescription->setText(tr("The development version is "
83 "updated on every code change."));
84 voice = false;
85 break;
86 case PlayerBuildInfo::TypeCandidate:
87 ui.selectedDescription->setText(tr("This will eventually become the "
88 "next Rockbox version. Install it to help testing."));
89 voice = false;
90 break;
91 case PlayerBuildInfo::TypeDaily:
92 ui.selectedDescription->setText(tr("Daily updated development version."));
93 voice = true;
94 break;
95 }
96 ui.voiceCheckbox->setEnabled(voice);
97 ui.voiceCombobox->setEnabled(voice);
98 ui.voiceLabel->setEnabled(voice);
99 ui.voiceCheckbox->setToolTip(voice ? "" : tr("Not available for the selected version"));
100
101 updateVoiceLangs();
102}
103
104
105void SelectiveInstallWidget::updateVersion(void)
106{
107 // get some configuration values globally
108 m_mountpoint = RbSettings::value(RbSettings::Mountpoint).toString();
109 m_target = RbSettings::value(RbSettings::CurrentPlatform).toString();
110 m_blmethod = PlayerBuildInfo::instance()->value(
111 PlayerBuildInfo::BootloaderMethod, m_target).toString();
112
113 if(m_logger != nullptr) {
114 delete m_logger;
115 m_logger = nullptr;
116 }
117
118 // re-populate all version items
119 QMap<PlayerBuildInfo::BuildType, QString> types;
120 types[PlayerBuildInfo::TypeRelease] = tr("Stable Release (Version %1)");
121 if (PlayerBuildInfo::instance()->value(PlayerBuildInfo::BuildStatus).toInt() != STATUS_RETIRED) {
122 types[PlayerBuildInfo::TypeCandidate] = tr("Release Candidate (Revison %1)");
123 types[PlayerBuildInfo::TypeDaily] = tr("Daily Build (%1)");
124 types[PlayerBuildInfo::TypeDevel] = tr("Development Version (Revison %1)");
125 }
126
127 ui.selectedVersion->clear();
128 for(auto i = types.begin(); i != types.end(); i++) {
129 QString version = PlayerBuildInfo::instance()->value(
130 PlayerBuildInfo::BuildVersion, i.key()).toString();
131 if(!version.isEmpty())
132 ui.selectedVersion->addItem(i.value().arg(version), i.key());
133 }
134
135 // select previously selected version
136 int index = ui.selectedVersion->findData(
137 static_cast<PlayerBuildInfo::BuildType>(RbSettings::value(RbSettings::Build).toInt()));
138 if(index < 0) {
139 index = ui.selectedVersion->findData(PlayerBuildInfo::TypeRelease);
140 if(index < 0) {
141 index = ui.selectedVersion->findData(PlayerBuildInfo::TypeDevel);
142 }
143 }
144 ui.selectedVersion->setCurrentIndex(index);
145 // check if Rockbox is installed. If it is untick the bootloader option, as
146 // well as if the selected player doesn't need a bootloader.
147 if(m_blmethod == "none") {
148 ui.bootloaderCheckbox->setEnabled(false);
149 ui.bootloaderCheckbox->setChecked(false);
150 ui.bootloaderLabel->setEnabled(false);
151 ui.bootloaderLabel->setText(tr("The selected player doesn't need a bootloader."));
152 }
153 else {
154 ui.bootloaderCheckbox->setEnabled(true);
155 ui.bootloaderLabel->setEnabled(true);
156 ui.bootloaderLabel->setText(tr("The bootloader is required for starting "
157 "Rockbox. Installation of the bootloader is only necessary "
158 "on first time installation."));
159 // check if Rockbox is installed by looking after rockbox-info.txt.
160 // If installed uncheck bootloader installation.
161 RockboxInfo info(m_mountpoint);
162 ui.bootloaderCheckbox->setChecked(!info.success());
163 }
164
165 updateVoiceLangs();
166}
167
168void SelectiveInstallWidget::updateVoiceLangs()
169{
170 // populate languages for voice file.
171 QVariant current = ui.voiceCombobox->currentData();
172 QMap<QString, QVariant> langs = PlayerBuildInfo::instance()->value(
173 PlayerBuildInfo::LanguageList).toMap();
174 QStringList voicelangs = PlayerBuildInfo::instance()->value(
175 PlayerBuildInfo::BuildVoiceLangs, m_buildtype).toStringList();
176 ui.voiceCombobox->clear();
177 for(auto it = langs.begin(); it != langs.end(); it++) {
178 if(voicelangs.contains(it.key())) {
179 ui.voiceCombobox->addItem(it.value().toString(), it.key());
180 LOG_INFO() << "available voices: adding" << it.key();
181 }
182
183 }
184 // try to select the previously selected one again (if still present)
185 // TODO: Fall back to system language if not found, or english.
186 int sel = ui.voiceCombobox->findData(current);
187 if(sel >= 0)
188 ui.voiceCombobox->setCurrentIndex(sel);
189
190}
191
192
193void SelectiveInstallWidget::saveSettings(void)
194{
195 LOG_INFO() << "saving current settings";
196
197 RbSettings::setValue(RbSettings::InstallRockbox, ui.rockboxCheckbox->isChecked());
198 RbSettings::setValue(RbSettings::InstallFonts, ui.fontsCheckbox->isChecked());
199 RbSettings::setValue(RbSettings::InstallThemes, ui.themesCheckbox->isChecked());
200 RbSettings::setValue(RbSettings::InstallPluginData, ui.pluginDataCheckbox->isChecked());
201 RbSettings::setValue(RbSettings::InstallVoice, ui.voiceCheckbox->isChecked());
202 RbSettings::setValue(RbSettings::InstallManual, ui.manualCheckbox->isChecked());
203 RbSettings::setValue(RbSettings::VoiceLanguage, ui.voiceCombobox->currentData().toString());
204}
205
206
207void SelectiveInstallWidget::startInstall(void)
208{
209 LOG_INFO() << "starting installation";
210 saveSettings();
211
212 m_installStage = 0;
213 if(m_logger != nullptr) delete m_logger;
214 m_logger = new ProgressLoggerGui(this);
215 QString warning = Utils::checkEnvironment(false);
216 if(!warning.isEmpty())
217 {
218 warning += "<br/>" + tr("Continue with installation?");
219 if(QMessageBox::warning(this, tr("Really continue?"), warning,
220 QMessageBox::Ok | QMessageBox::Abort, QMessageBox::Abort)
221 == QMessageBox::Abort)
222 {
223 emit installSkipped(true);
224 return;
225 }
226 }
227
228 m_logger->show();
229 if(!QFileInfo(m_mountpoint).isDir()) {
230 m_logger->addItem(tr("Mountpoint is wrong"), LOGERROR);
231 m_logger->setFinished();
232 return;
233 }
234 // start installation. No errors until now.
235 continueInstall(false);
236
237}
238
239
240void SelectiveInstallWidget::continueInstall(bool error)
241{
242 LOG_INFO() << "continuing install with stage" << m_installStage;
243 if(error) {
244 LOG_ERROR() << "Last part returned error.";
245 m_logger->setFinished();
246 m_installStage = 9;
247 }
248 m_installStage++;
249 switch(m_installStage) {
250 case 0: LOG_ERROR() << "Something wrong!"; break;
251 case 1: installBootloader(); break;
252 case 2: installRockbox(); break;
253 case 3: installFonts(); break;
254 case 4: installThemes(); break;
255 case 5: installPluginData(); break;
256 case 6: installVoicefile(); break;
257 case 7: installManual(); break;
258 case 8: installBootloaderPost(); break;
259 default: break;
260 }
261
262 if(m_installStage > 8) {
263 LOG_INFO() << "All install stages done.";
264 m_logger->setFinished();
265 if(m_blmethod != "none") {
266 // check if Rockbox is installed by looking after rockbox-info.txt.
267 // If installed uncheck bootloader installation.
268 RockboxInfo info(m_mountpoint);
269 ui.bootloaderCheckbox->setChecked(!info.success());
270 }
271 }
272}
273
274
275void SelectiveInstallWidget::installBootloader(void)
276{
277 if(ui.bootloaderCheckbox->isChecked()) {
278 LOG_INFO() << "installing bootloader";
279
280 QString platform = RbSettings::value(RbSettings::Platform).toString();
281 QString backupDestination = "";
282
283 // create installer
284 BootloaderInstallBase *bl =
285 BootloaderInstallHelper::createBootloaderInstaller(this,
286 PlayerBuildInfo::instance()->value(
287 PlayerBuildInfo::BootloaderMethod).toString());
288 if(bl == nullptr) {
289 m_logger->addItem(tr("No install method known."), LOGERROR);
290 m_logger->setFinished();
291 return;
292 }
293
294 // the bootloader install class does NOT use any GUI stuff.
295 // All messages are passed via signals.
296 connect(bl, SIGNAL(done(bool)), m_logger, SLOT(setFinished()));
297 connect(bl, SIGNAL(done(bool)), this, SLOT(continueInstall(bool)));
298 connect(bl, SIGNAL(logItem(QString, int)), m_logger, SLOT(addItem(QString, int)));
299 connect(bl, SIGNAL(logProgress(int, int)), m_logger, SLOT(setProgress(int, int)));
300 // pass Abort button click signal to current installer
301 connect(m_logger, SIGNAL(aborted()), bl, SLOT(progressAborted()));
302
303 // set bootloader filename. Do this now as installed() needs it.
304 QStringList blfile = PlayerBuildInfo::instance()->value(
305 PlayerBuildInfo::BootloaderFile).toStringList();
306 QStringList blfilepath;
307 for(int a = 0; a < blfile.size(); a++) {
308 blfilepath.append(RbSettings::value(RbSettings::Mountpoint).toString()
309 + blfile.at(a));
310 }
311 bl->setBlFile(blfilepath);
312 QUrl url(PlayerBuildInfo::instance()->value(PlayerBuildInfo::BootloaderUrl).toString()
313 + PlayerBuildInfo::instance()->value(PlayerBuildInfo::BootloaderName).toString());
314 bl->setBlUrl(url);
315 bl->setLogfile(RbSettings::value(RbSettings::Mountpoint).toString()
316 + "/.rockbox/rbutil.log");
317
318 if(bl->installed() == BootloaderInstallBase::BootloaderRockbox) {
319 if(QMessageBox::question(this, tr("Bootloader detected"),
320 tr("Bootloader already installed. Do you want to reinstall the bootloader?"),
321 QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) {
322 // keep m_logger open for auto installs.
323 // don't consider abort as error in auto-mode.
324 m_logger->addItem(tr("Bootloader installation skipped"), LOGINFO);
325 delete bl;
326 emit installSkipped(true);
327 return;
328 }
329 }
330 else if(bl->installed() == BootloaderInstallBase::BootloaderOther
331 && bl->capabilities() & BootloaderInstallBase::Backup)
332 {
333 QString targetFolder = PlayerBuildInfo::instance()->value(
334 PlayerBuildInfo::DisplayName).toString()
335 + " Firmware Backup";
336 // remove invalid character(s)
337 targetFolder.remove(QRegExp("[:/]"));
338 if(QMessageBox::question(this, tr("Create Bootloader backup"),
339 tr("You can create a backup of the original bootloader "
340 "file. Press \"Yes\" to select an output folder on your "
341 "computer to save the file to. The file will get placed "
342 "in a new folder \"%1\" created below the selected folder.\n"
343 "Press \"No\" to skip this step.").arg(targetFolder),
344 QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
345 backupDestination = QFileDialog::getExistingDirectory(this,
346 tr("Browse backup folder"), QDir::homePath());
347 if(!backupDestination.isEmpty())
348 backupDestination += "/" + targetFolder;
349
350 LOG_INFO() << "backing up to" << backupDestination;
351 // backup needs to be done after the m_logger has been set up.
352 }
353 }
354
355 if(bl->capabilities() & BootloaderInstallBase::NeedsOf)
356 {
357 int ret;
358 ret = QMessageBox::information(this, tr("Prerequisites"),
359 bl->ofHint(),QMessageBox::Ok | QMessageBox::Abort);
360 if(ret != QMessageBox::Ok) {
361 // consider aborting an error to close window / abort automatic
362 // installation.
363 m_logger->addItem(tr("Bootloader installation aborted"), LOGINFO);
364 m_logger->setFinished();
365 emit installSkipped(true);
366 return;
367 }
368 // open dialog to browse to of file
369 QString offile;
370 QString filter
371 = PlayerBuildInfo::instance()->value(PlayerBuildInfo::BootloaderFilter).toString();
372 if(!filter.isEmpty()) {
373 filter = tr("Bootloader files (%1)").arg(filter) + ";;";
374 }
375 filter += tr("All files (*)");
376 offile = QFileDialog::getOpenFileName(this,
377 tr("Select firmware file"), QDir::homePath(), filter);
378 if(!QFileInfo(offile).isReadable()) {
379 m_logger->addItem(tr("Error opening firmware file"), LOGERROR);
380 m_logger->setFinished();
381 emit installSkipped(true);
382 return;
383 }
384 if(!bl->setOfFile(offile, blfile)) {
385 m_logger->addItem(tr("Error reading firmware file"), LOGERROR);
386 m_logger->setFinished();
387 emit installSkipped(true);
388 return;
389 }
390 }
391
392 // start install.
393 if(!backupDestination.isEmpty()) {
394 if(!bl->backup(backupDestination)) {
395 if(QMessageBox::warning(this, tr("Backup error"),
396 tr("Could not create backup file. Continue?"),
397 QMessageBox::No | QMessageBox::Yes)
398 == QMessageBox::No) {
399 m_logger->setFinished();
400 return;
401 }
402 }
403 }
404 bl->install();
405
406 }
407 else {
408 LOG_INFO() << "Bootloader install disabled.";
409 emit installSkipped(false);
410 }
411}
412
413void SelectiveInstallWidget::installBootloaderPost()
414{
415 // don't do anything if no bootloader install has been done.
416 if(ui.bootloaderCheckbox->isChecked()) {
417 QString msg = BootloaderInstallHelper::postinstallHints(
418 RbSettings::value(RbSettings::Platform).toString());
419 if(!msg.isEmpty()) {
420 QMessageBox::information(this, tr("Manual steps required"), msg);
421 }
422 }
423 emit installSkipped(false);
424}
425
426
427void SelectiveInstallWidget::installRockbox(void)
428{
429 if(ui.rockboxCheckbox->isChecked()) {
430 LOG_INFO() << "installing Rockbox";
431 QString url;
432
433 RbSettings::setValue(RbSettings::Build, m_buildtype);
434 RbSettings::sync();
435
436 url = PlayerBuildInfo::instance()->value(
437 PlayerBuildInfo::BuildUrl, m_buildtype).toString();
438 //! install build
439 if(m_zipinstaller != nullptr) m_zipinstaller->deleteLater();
440 m_zipinstaller = new ZipInstaller(this);
441 m_zipinstaller->setUrl(url);
442 m_zipinstaller->setLogSection("Rockbox (Base)");
443 if(!RbSettings::value(RbSettings::CacheDisabled).toBool())
444 m_zipinstaller->setCache(true);
445 m_zipinstaller->setLogVersion(PlayerBuildInfo::instance()->value(
446 PlayerBuildInfo::BuildVersion, m_buildtype).toString());
447 m_zipinstaller->setMountPoint(m_mountpoint);
448
449 connect(m_zipinstaller, SIGNAL(done(bool)), this, SLOT(continueInstall(bool)));
450
451 connect(m_zipinstaller, SIGNAL(logItem(QString, int)), m_logger, SLOT(addItem(QString, int)));
452 connect(m_zipinstaller, SIGNAL(logProgress(int, int)), m_logger, SLOT(setProgress(int, int)));
453 connect(m_logger, SIGNAL(aborted()), m_zipinstaller, SLOT(abort()));
454 m_zipinstaller->install();
455
456 }
457 else {
458 LOG_INFO() << "Rockbox install disabled.";
459 emit installSkipped(false);
460 }
461}
462
463
464void SelectiveInstallWidget::installFonts(void)
465{
466 if(ui.fontsCheckbox->isChecked()) {
467 LOG_INFO() << "installing Fonts";
468
469 RockboxInfo installInfo(m_mountpoint);
470 QString fontsurl;
471 QString logversion;
472 QString relversion = installInfo.release();
473 if(!relversion.isEmpty()) {
474 // release is empty for non-release versions (i.e. daily / current)
475 logversion = installInfo.release();
476 }
477 fontsurl = PlayerBuildInfo::instance()->value(
478 PlayerBuildInfo::BuildFontUrl, m_buildtype).toString();
479 fontsurl.replace("%RELVERSION%", relversion);
480
481 // create new zip installer
482 if(m_zipinstaller != nullptr) m_zipinstaller->deleteLater();
483 m_zipinstaller = new ZipInstaller(this);
484 m_zipinstaller->setUrl(fontsurl);
485 m_zipinstaller->setLogSection("Fonts");
486 m_zipinstaller->setLogVersion(logversion);
487 m_zipinstaller->setMountPoint(m_mountpoint);
488 if(!RbSettings::value(RbSettings::CacheDisabled).toBool())
489 m_zipinstaller->setCache(true);
490
491 connect(m_zipinstaller, SIGNAL(done(bool)), this, SLOT(continueInstall(bool)));
492 connect(m_zipinstaller, SIGNAL(logItem(QString, int)), m_logger, SLOT(addItem(QString, int)));
493 connect(m_zipinstaller, SIGNAL(logProgress(int, int)), m_logger, SLOT(setProgress(int, int)));
494 connect(m_logger, SIGNAL(aborted()), m_zipinstaller, SLOT(abort()));
495 m_zipinstaller->install();
496 }
497 else {
498 LOG_INFO() << "Fonts install disabled.";
499 emit installSkipped(false);
500 }
501}
502
503void SelectiveInstallWidget::installVoicefile(void)
504{
505 if(ui.voiceCheckbox->isChecked() && ui.voiceCheckbox->isEnabled()) {
506 LOG_INFO() << "installing Voice file";
507 QString lang = ui.voiceCombobox->currentData().toString();
508
509 RockboxInfo installInfo(m_mountpoint);
510 QString voiceurl;
511 QString logversion;
512 QString relversion = installInfo.release();
513 if(m_buildtype != PlayerBuildInfo::TypeRelease) {
514 // release is empty for non-release versions (i.e. daily / current)
515 logversion = installInfo.release();
516 }
517 voiceurl = PlayerBuildInfo::instance()->value(
518 PlayerBuildInfo::BuildVoiceUrl, m_buildtype).toString();
519 voiceurl.replace("%LANGUAGE%", lang);
520
521 // create new zip installer
522 if(m_zipinstaller != nullptr) m_zipinstaller->deleteLater();
523 m_zipinstaller = new ZipInstaller(this);
524 m_zipinstaller->setUrl(voiceurl);
525 m_zipinstaller->setLogSection("Prerendered Voice (" + lang + ")");
526 m_zipinstaller->setLogVersion(logversion);
527 m_zipinstaller->setMountPoint(m_mountpoint);
528 if(!RbSettings::value(RbSettings::CacheDisabled).toBool())
529 m_zipinstaller->setCache(true);
530
531 connect(m_zipinstaller, SIGNAL(done(bool)), this, SLOT(continueInstall(bool)));
532 connect(m_zipinstaller, SIGNAL(logItem(QString, int)), m_logger, SLOT(addItem(QString, int)));
533 connect(m_zipinstaller, SIGNAL(logProgress(int, int)), m_logger, SLOT(setProgress(int, int)));
534 connect(m_logger, SIGNAL(aborted()), m_zipinstaller, SLOT(abort()));
535 m_zipinstaller->install();
536 }
537 else {
538 LOG_INFO() << "Voice install disabled.";
539 emit installSkipped(false);
540 }
541}
542
543void SelectiveInstallWidget::installManual(void)
544{
545 if(ui.manualCheckbox->isChecked() && ui.manualCheckbox->isEnabled()) {
546 LOG_INFO() << "installing Manual";
547 QString mantype = ui.manualCombobox->currentData().toString();
548
549 RockboxInfo installInfo(m_mountpoint);
550 QString manualurl;
551 QString logversion;
552 QString relversion = installInfo.release();
553 if(m_buildtype != PlayerBuildInfo::TypeRelease) {
554 // release is empty for non-release versions (i.e. daily / current)
555 logversion = installInfo.release();
556 }
557
558 manualurl = PlayerBuildInfo::instance()->value(
559 PlayerBuildInfo::BuildManualUrl, m_buildtype).toString();
560 if(mantype == "pdf")
561 manualurl.replace("%FORMAT%", ".pdf");
562 else
563 manualurl.replace("%FORMAT%", "-html.zip");
564
565 // create new zip installer
566 if(m_zipinstaller != nullptr) m_zipinstaller->deleteLater();
567 m_zipinstaller = new ZipInstaller(this);
568 m_zipinstaller->setUrl(manualurl);
569 m_zipinstaller->setLogSection("Manual (" + mantype + ")");
570 m_zipinstaller->setLogVersion(logversion);
571 m_zipinstaller->setMountPoint(m_mountpoint);
572 if(!RbSettings::value(RbSettings::CacheDisabled).toBool())
573 m_zipinstaller->setCache(true);
574 // if type is html extract it.
575 m_zipinstaller->setUnzip(mantype == "html");
576
577 connect(m_zipinstaller, SIGNAL(done(bool)), this, SLOT(continueInstall(bool)));
578 connect(m_zipinstaller, SIGNAL(logItem(QString, int)), m_logger, SLOT(addItem(QString, int)));
579 connect(m_zipinstaller, SIGNAL(logProgress(int, int)), m_logger, SLOT(setProgress(int, int)));
580 connect(m_logger, SIGNAL(aborted()), m_zipinstaller, SLOT(abort()));
581 m_zipinstaller->install();
582 }
583 else {
584 LOG_INFO() << "Manual install disabled.";
585 emit installSkipped(false);
586 }
587}
588
589void SelectiveInstallWidget::customizeThemes(void)
590{
591 if(m_themesinstaller == nullptr)
592 m_themesinstaller = new ThemesInstallWindow(this);
593
594 m_themesinstaller->setSelectOnly(true);
595 m_themesinstaller->show();
596}
597
598
599void SelectiveInstallWidget::installThemes(void)
600{
601 if(ui.themesCheckbox->isChecked()) {
602 LOG_INFO() << "installing themes";
603 if(m_themesinstaller == nullptr)
604 m_themesinstaller = new ThemesInstallWindow(this);
605
606 connect(m_themesinstaller, SIGNAL(done(bool)), this, SLOT(continueInstall(bool)));
607 m_themesinstaller->setLogger(m_logger);
608 m_themesinstaller->setModal(true);
609 m_themesinstaller->install();
610 }
611 else {
612 LOG_INFO() << "Themes install disabled.";
613 emit installSkipped(false);
614 }
615}
616
617static const struct {
618 const char *name; // display name
619 const char *rockfile; // rock file to look for
620 PlayerBuildInfo::BuildInfo zipurl; // download url
621} PluginDataFiles[] = {
622 { "Doom", "games/doom.rock", PlayerBuildInfo::DoomUrl },
623 { "Duke3D", "games/duke3d.rock", PlayerBuildInfo::Duke3DUrl },
624 { "Quake", "games/quake.rock", PlayerBuildInfo::QuakeUrl },
625 { "Puzzles fonts", "games/sgt-blackbox.rock", PlayerBuildInfo::PuzzFontsUrl },
626 { "Wolf3D", "games/wolf3d.rock", PlayerBuildInfo::Wolf3DUrl },
627 { "XWorld", "games/xworld.rock", PlayerBuildInfo::XWorldUrl },
628 { "MIDI Patchset", "viewers/midi.rock", PlayerBuildInfo::MidiPatchsetUrl },
629};
630
631void SelectiveInstallWidget::installPluginData(void)
632{
633 if(ui.pluginDataCheckbox->isChecked()) {
634 // build a list of zip urls that we need, then install
635 QStringList dataUrls;
636 QStringList dataName;
637
638 for(size_t i = 0; i < sizeof(PluginDataFiles) / sizeof(PluginDataFiles[0]); i++)
639 {
640 // check if installed Rockbox has this plugin.
641 if(QFileInfo(m_mountpoint + "/.rockbox/rocks/" + PluginDataFiles[i].rockfile).exists()) {
642 dataName.append(PluginDataFiles[i].name);
643 // game URLs do not depend on the actual build type, but we need
644 // to pass it (simplifies the API, and will allow to make them
645 // type specific later if needed)
646 dataUrls.append(PlayerBuildInfo::instance()->value(
647 PluginDataFiles[i].zipurl, m_buildtype).toString());
648 }
649 }
650
651 if(dataUrls.size() == 0)
652 {
653 m_logger->addItem(
654 tr("Your installation doesn't require any plugin data files, skipping."),
655 LOGINFO);
656 emit installSkipped(false);
657 return;
658 }
659
660 LOG_INFO() << "installing plugin data files";
661
662 // create new zip installer
663 if(m_zipinstaller != nullptr) m_zipinstaller->deleteLater();
664 m_zipinstaller = new ZipInstaller(this);
665
666 m_zipinstaller->setUrl(dataUrls);
667 m_zipinstaller->setLogSection(dataName);
668 m_zipinstaller->setLogVersion();
669 m_zipinstaller->setMountPoint(m_mountpoint);
670 if(!RbSettings::value(RbSettings::CacheDisabled).toBool())
671 m_zipinstaller->setCache(true);
672 connect(m_zipinstaller, SIGNAL(done(bool)), this, SLOT(continueInstall(bool)));
673 connect(m_zipinstaller, SIGNAL(logItem(QString, int)), m_logger, SLOT(addItem(QString, int)));
674 connect(m_zipinstaller, SIGNAL(logProgress(int, int)), m_logger, SLOT(setProgress(int, int)));
675 connect(m_logger, SIGNAL(aborted()), m_zipinstaller, SLOT(abort()));
676 m_zipinstaller->install();
677 }
678 else {
679 LOG_INFO() << "Gamefile install disabled.";
680 emit installSkipped(false);
681 }
682}
683
684void SelectiveInstallWidget::changeEvent(QEvent *e)
685{
686 if(e->type() == QEvent::LanguageChange) {
687 ui.retranslateUi(this);
688 } else {
689 QWidget::changeEvent(e);
690 }
691}
diff --git a/utils/rbutilqt/gui/selectiveinstallwidget.h b/utils/rbutilqt/gui/selectiveinstallwidget.h
new file mode 100644
index 0000000000..c961a387e0
--- /dev/null
+++ b/utils/rbutilqt/gui/selectiveinstallwidget.h
@@ -0,0 +1,74 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2012 by Dominik Riebeling
10 *
11 * All files in this archive are subject to the GNU General Public License.
12 * See the file COPYING in the source tree root for full license agreement.
13 *
14 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * KIND, either express or implied.
16 *
17 ****************************************************************************/
18
19#ifndef SELECTIVEINSTALLWIDGET_H
20#define SELECTIVEINSTALLWIDGET_H
21
22#include <QWidget>
23#include "ui_selectiveinstallwidgetfrm.h"
24#include "progressloggergui.h"
25#include "zipinstaller.h"
26#include "themesinstallwindow.h"
27#include "playerbuildinfo.h"
28
29class SelectiveInstallWidget : public QWidget
30{
31 Q_OBJECT
32 public:
33 SelectiveInstallWidget(QWidget* parent = nullptr);
34
35 public slots:
36 void updateVersion(void);
37 void saveSettings(void);
38 void startInstall(void);
39
40 private slots:
41 void continueInstall(bool);
42 void customizeThemes(void);
43 void selectedVersionChanged(int);
44 void updateVoiceLangs();
45
46 private:
47 void installBootloader(void);
48 void installRockbox(void);
49 void installFonts(void);
50 void installVoicefile(void);
51 void installManual(void);
52 void installThemes(void);
53 void installPluginData(void);
54 void installBootloaderPost(void);
55
56 signals:
57 void installSkipped(bool);
58
59 private:
60 void changeEvent(QEvent *e);
61
62 Ui::SelectiveInstallWidget ui;
63 QString m_target;
64 QString m_blmethod;
65 QString m_mountpoint;
66 ProgressLoggerGui *m_logger;
67 int m_installStage;
68 ZipInstaller *m_zipinstaller;
69 ThemesInstallWindow *m_themesinstaller;
70 PlayerBuildInfo::BuildType m_buildtype;
71};
72
73#endif
74
diff --git a/utils/rbutilqt/gui/selectiveinstallwidgetfrm.ui b/utils/rbutilqt/gui/selectiveinstallwidgetfrm.ui
new file mode 100644
index 0000000000..f68ff350f3
--- /dev/null
+++ b/utils/rbutilqt/gui/selectiveinstallwidgetfrm.ui
@@ -0,0 +1,316 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>SelectiveInstallWidget</class>
4 <widget class="QWidget" name="SelectiveInstallWidget">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>663</width>
10 <height>440</height>
11 </rect>
12 </property>
13 <property name="sizePolicy">
14 <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
15 <horstretch>0</horstretch>
16 <verstretch>0</verstretch>
17 </sizepolicy>
18 </property>
19 <property name="windowTitle">
20 <string>Selective Installation</string>
21 </property>
22 <layout class="QGridLayout" name="gridLayout_3">
23 <item row="0" column="0">
24 <widget class="QGroupBox" name="versionSelectGroupBox">
25 <property name="title">
26 <string>Rockbox version to install</string>
27 </property>
28 <layout class="QGridLayout" name="gridLayout">
29 <item row="0" column="0">
30 <widget class="QComboBox" name="selectedVersion"/>
31 </item>
32 <item row="0" column="1">
33 <widget class="QLabel" name="selectedDescription">
34 <property name="text">
35 <string>Version information not available yet.</string>
36 </property>
37 <property name="wordWrap">
38 <bool>true</bool>
39 </property>
40 </widget>
41 </item>
42 </layout>
43 </widget>
44 </item>
45 <item row="1" column="0">
46 <widget class="QGroupBox" name="groupBox">
47 <property name="sizePolicy">
48 <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
49 <horstretch>0</horstretch>
50 <verstretch>0</verstretch>
51 </sizepolicy>
52 </property>
53 <property name="title">
54 <string>Rockbox components to install</string>
55 </property>
56 <layout class="QGridLayout" name="gridLayout_2">
57 <item row="0" column="0">
58 <widget class="QCheckBox" name="bootloaderCheckbox">
59 <property name="text">
60 <string>&amp;Bootloader</string>
61 </property>
62 <property name="icon">
63 <iconset resource="../rbutilqt.qrc">
64 <normaloff>:/icons/preferences-system.svg</normaloff>:/icons/preferences-system.svg</iconset>
65 </property>
66 <property name="checked">
67 <bool>true</bool>
68 </property>
69 </widget>
70 </item>
71 <item row="1" column="0">
72 <widget class="QCheckBox" name="rockboxCheckbox">
73 <property name="text">
74 <string>&amp;Rockbox</string>
75 </property>
76 <property name="icon">
77 <iconset resource="../rbutilqt.qrc">
78 <normaloff>:/icons/multimedia-player.svg</normaloff>:/icons/multimedia-player.svg</iconset>
79 </property>
80 <property name="checked">
81 <bool>true</bool>
82 </property>
83 </widget>
84 </item>
85 <item row="3" column="2">
86 <widget class="QLabel" name="themesLabel">
87 <property name="sizePolicy">
88 <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
89 <horstretch>0</horstretch>
90 <verstretch>0</verstretch>
91 </sizepolicy>
92 </property>
93 <property name="text">
94 <string>Themes allow adjusting the user interface of Rockbox. Use &quot;Customize&quot; to select themes.</string>
95 </property>
96 <property name="wordWrap">
97 <bool>true</bool>
98 </property>
99 </widget>
100 </item>
101 <item row="3" column="0">
102 <widget class="QCheckBox" name="themesCheckbox">
103 <property name="text">
104 <string>Themes</string>
105 </property>
106 <property name="icon">
107 <iconset resource="../rbutilqt.qrc">
108 <normaloff>:/icons/preferences-desktop-theme.svg</normaloff>:/icons/preferences-desktop-theme.svg</iconset>
109 </property>
110 </widget>
111 </item>
112 <item row="2" column="0">
113 <widget class="QCheckBox" name="fontsCheckbox">
114 <property name="text">
115 <string>Fonts</string>
116 </property>
117 <property name="icon">
118 <iconset resource="../rbutilqt.qrc">
119 <normaloff>:/icons/preferences-desktop-font.svg</normaloff>:/icons/preferences-desktop-font.svg</iconset>
120 </property>
121 <property name="checked">
122 <bool>true</bool>
123 </property>
124 </widget>
125 </item>
126 <item row="0" column="2">
127 <widget class="QLabel" name="bootloaderLabel">
128 <property name="sizePolicy">
129 <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
130 <horstretch>0</horstretch>
131 <verstretch>0</verstretch>
132 </sizepolicy>
133 </property>
134 <property name="text">
135 <string>The bootloader is required for starting Rockbox. Only necessary for first time install.</string>
136 </property>
137 <property name="wordWrap">
138 <bool>true</bool>
139 </property>
140 </widget>
141 </item>
142 <item row="6" column="2">
143 <widget class="QLabel" name="pluginDataLabe">
144 <property name="sizePolicy">
145 <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
146 <horstretch>0</horstretch>
147 <verstretch>0</verstretch>
148 </sizepolicy>
149 </property>
150 <property name="text">
151 <string>Some plugins require additional data files.</string>
152 </property>
153 <property name="wordWrap">
154 <bool>true</bool>
155 </property>
156 </widget>
157 </item>
158 <item row="3" column="4">
159 <widget class="QPushButton" name="themesCustomize">
160 <property name="text">
161 <string>Customize</string>
162 </property>
163 <property name="icon">
164 <iconset resource="../rbutilqt.qrc">
165 <normaloff>:/icons/preferences-system.svg</normaloff>:/icons/preferences-system.svg</iconset>
166 </property>
167 </widget>
168 </item>
169 <item row="2" column="2">
170 <widget class="QLabel" name="fontsLabel">
171 <property name="sizePolicy">
172 <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
173 <horstretch>0</horstretch>
174 <verstretch>0</verstretch>
175 </sizepolicy>
176 </property>
177 <property name="text">
178 <string>Additional fonts for the User Interface.</string>
179 </property>
180 <property name="wordWrap">
181 <bool>true</bool>
182 </property>
183 </widget>
184 </item>
185 <item row="7" column="2">
186 <widget class="QLabel" name="voiceLabel">
187 <property name="text">
188 <string>Install prerendered voice file.</string>
189 </property>
190 </widget>
191 </item>
192 <item row="6" column="0">
193 <widget class="QCheckBox" name="pluginDataCheckbox">
194 <property name="text">
195 <string>Plugin Data</string>
196 </property>
197 <property name="icon">
198 <iconset resource="../rbutilqt.qrc">
199 <normaloff>:/icons/input-gaming.svg</normaloff>:/icons/input-gaming.svg</iconset>
200 </property>
201 </widget>
202 </item>
203 <item row="1" column="3">
204 <spacer name="horizontalSpacer">
205 <property name="orientation">
206 <enum>Qt::Horizontal</enum>
207 </property>
208 <property name="sizeType">
209 <enum>QSizePolicy::Minimum</enum>
210 </property>
211 <property name="sizeHint" stdset="0">
212 <size>
213 <width>1</width>
214 <height>1</height>
215 </size>
216 </property>
217 </spacer>
218 </item>
219 <item row="8" column="0">
220 <widget class="QCheckBox" name="manualCheckbox">
221 <property name="text">
222 <string>&amp;Manual</string>
223 </property>
224 <property name="icon">
225 <iconset resource="../rbutilqt.qrc">
226 <normaloff>:/icons/edit-find.svg</normaloff>:/icons/edit-find.svg</iconset>
227 </property>
228 </widget>
229 </item>
230 <item row="7" column="0">
231 <widget class="QCheckBox" name="voiceCheckbox">
232 <property name="text">
233 <string>&amp;Voice File</string>
234 </property>
235 <property name="icon">
236 <iconset resource="../rbutilqt.qrc">
237 <normaloff>:/icons/audio-volume-high.svg</normaloff>:/icons/audio-volume-high.svg</iconset>
238 </property>
239 </widget>
240 </item>
241 <item row="7" column="4">
242 <widget class="QComboBox" name="voiceCombobox"/>
243 </item>
244 <item row="1" column="2">
245 <widget class="QLabel" name="rockboxLabel">
246 <property name="sizePolicy">
247 <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
248 <horstretch>0</horstretch>
249 <verstretch>0</verstretch>
250 </sizepolicy>
251 </property>
252 <property name="text">
253 <string>The main Rockbox firmware.</string>
254 </property>
255 <property name="wordWrap">
256 <bool>true</bool>
257 </property>
258 </widget>
259 </item>
260 <item row="8" column="2">
261 <widget class="QLabel" name="manualLabel">
262 <property name="text">
263 <string>Save a copy of the manual on the player.</string>
264 </property>
265 </widget>
266 </item>
267 <item row="8" column="4">
268 <widget class="QComboBox" name="manualCombobox"/>
269 </item>
270 </layout>
271 </widget>
272 </item>
273 <item row="2" column="0">
274 <spacer name="verticalSpacer">
275 <property name="orientation">
276 <enum>Qt::Vertical</enum>
277 </property>
278 <property name="sizeType">
279 <enum>QSizePolicy::Expanding</enum>
280 </property>
281 <property name="sizeHint" stdset="0">
282 <size>
283 <width>20</width>
284 <height>1</height>
285 </size>
286 </property>
287 </spacer>
288 </item>
289 <item row="3" column="0">
290 <widget class="QPushButton" name="installButton">
291 <property name="text">
292 <string>&amp;Install</string>
293 </property>
294 <property name="icon">
295 <iconset resource="../rbutilqt.qrc">
296 <normaloff>:/icons/package-x-generic.svg</normaloff>:/icons/package-x-generic.svg</iconset>
297 </property>
298 </widget>
299 </item>
300 </layout>
301 </widget>
302 <tabstops>
303 <tabstop>selectedVersion</tabstop>
304 <tabstop>bootloaderCheckbox</tabstop>
305 <tabstop>rockboxCheckbox</tabstop>
306 <tabstop>fontsCheckbox</tabstop>
307 <tabstop>themesCheckbox</tabstop>
308 <tabstop>themesCustomize</tabstop>
309 <tabstop>pluginDataCheckbox</tabstop>
310 <tabstop>installButton</tabstop>
311 </tabstops>
312 <resources>
313 <include location="../rbutilqt.qrc"/>
314 </resources>
315 <connections/>
316</ui>