mirror of
https://github.com/Rockbox/rockbox.git
synced 2026-01-22 01:30:35 -05:00
Only for themes, fonts and voice files, includes rgnano implementation to test (can be in its own commit if needed, with the required manual updates and changes to install rockbox itself with rbutil). Change-Id: I2481e6a3224912a298cf4c86011226e466490e08
396 lines
14 KiB
C++
396 lines
14 KiB
C++
/***************************************************************************
|
|
* __________ __ ___.
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
* \/ \/ \/ \/ \/
|
|
*
|
|
* Copyright (C) 2007 by Dominik Riebeling
|
|
*
|
|
* All files in this archive are subject to the GNU General Public License.
|
|
* See the file COPYING in the source tree root for full license agreement.
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include <QDialog>
|
|
#include <QMessageBox>
|
|
#include <QTextCodec>
|
|
|
|
#include "ui_themesinstallfrm.h"
|
|
#include "themesinstallwindow.h"
|
|
#include "zipinstaller.h"
|
|
#include "progressloggergui.h"
|
|
#include "utils.h"
|
|
#include "rbsettings.h"
|
|
#include "playerbuildinfo.h"
|
|
#include "rockboxinfo.h"
|
|
#include "version.h"
|
|
#include "Logger.h"
|
|
|
|
ThemesInstallWindow::ThemesInstallWindow(QWidget *parent) : QDialog(parent)
|
|
{
|
|
ui.setupUi(this);
|
|
ui.listThemes->setAlternatingRowColors(true);
|
|
ui.listThemes->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
|
ui.listThemes->setSortingEnabled(true);
|
|
ui.themePreview->clear();
|
|
ui.themePreview->setText(tr("no theme selected"));
|
|
ui.labelSize->setText(tr("no selection"));
|
|
ui.listThemes->setLayoutDirection(Qt::LeftToRight);
|
|
ui.themeDescription->setLayoutDirection(Qt::LeftToRight);
|
|
|
|
connect(ui.buttonCancel, &QAbstractButton::clicked, this, &QWidget::close);
|
|
connect(ui.buttonOk, &QAbstractButton::clicked, this, &ThemesInstallWindow::buttonOk);
|
|
connect(ui.listThemes, &QListWidget::currentItemChanged,
|
|
this, &ThemesInstallWindow::updateDetails);
|
|
connect(ui.listThemes, &QListWidget::itemSelectionChanged, this, &ThemesInstallWindow::updateSize);
|
|
connect(&igetter, &HttpGet::done, this, &ThemesInstallWindow::updateImage);
|
|
|
|
if(!RbSettings::value(RbSettings::CacheDisabled).toBool())
|
|
igetter.setCache(true);
|
|
else
|
|
{
|
|
if(infocachedir.isEmpty())
|
|
{
|
|
infocachedir = QDir::tempPath() + "rbutil-themeinfo";
|
|
QDir d = QDir::temp();
|
|
d.mkdir("rbutil-themeinfo");
|
|
}
|
|
igetter.setCache(infocachedir);
|
|
}
|
|
|
|
logger = nullptr;
|
|
}
|
|
|
|
ThemesInstallWindow::~ThemesInstallWindow()
|
|
{
|
|
if(!infocachedir.isEmpty())
|
|
Utils::recursiveRmdir(infocachedir);
|
|
}
|
|
|
|
|
|
void ThemesInstallWindow::downloadInfo()
|
|
{
|
|
// try to get the current build information
|
|
getter = new HttpGet(this);
|
|
RockboxInfo installInfo
|
|
= RockboxInfo(RbSettings::value(RbSettings::Mountpoint).toString());
|
|
|
|
themesInfo.open();
|
|
LOG_INFO() << "downloading info to" << themesInfo.fileName();
|
|
themesInfo.close();
|
|
|
|
QString infoUrl = PlayerBuildInfo::instance()->value(PlayerBuildInfo::ThemesInfoUrl).toString();
|
|
if (PlayerBuildInfo::instance()->value(PlayerBuildInfo::ThemeName).toString() != "") {
|
|
infoUrl.replace("%TARGET%",
|
|
PlayerBuildInfo::instance()->value(PlayerBuildInfo::ThemeName).toString());
|
|
} else {
|
|
infoUrl.replace("%TARGET%",
|
|
RbSettings::value(RbSettings::CurrentPlatform).toString().split(".").at(0));
|
|
}
|
|
infoUrl.replace("%REVISION%", installInfo.revision());
|
|
infoUrl.replace("%RELEASE%", installInfo.release());
|
|
infoUrl.replace("%RBUTILVER%", VERSION);
|
|
QUrl url = QUrl(infoUrl);
|
|
LOG_INFO() << "Info URL:" << url;
|
|
getter->setFile(&themesInfo);
|
|
|
|
connect(getter, &HttpGet::done, this, &ThemesInstallWindow::downloadDone);
|
|
connect(logger, &ProgressLoggerGui::aborted, getter, &HttpGet::abort);
|
|
getter->getFile(url);
|
|
}
|
|
|
|
|
|
void ThemesInstallWindow::downloadDone(QNetworkReply::NetworkError error)
|
|
{
|
|
LOG_INFO() << "Download done, error:" << error;
|
|
|
|
disconnect(logger, &ProgressLoggerGui::aborted, getter, &HttpGet::abort);
|
|
disconnect(logger, &ProgressLoggerGui::aborted, this, &QWidget::close);
|
|
themesInfo.open();
|
|
|
|
QSettings iniDetails(themesInfo.fileName(), QSettings::IniFormat, this);
|
|
#if QT_VERSION < 0x060000
|
|
iniDetails.setIniCodec(QTextCodec::codecForName("UTF-8"));
|
|
#endif
|
|
QStringList tl = iniDetails.childGroups();
|
|
LOG_INFO() << "Theme site result:"
|
|
<< iniDetails.value("error/code").toString()
|
|
<< iniDetails.value("error/description").toString()
|
|
<< iniDetails.value("error/query").toString();
|
|
|
|
if(error != QNetworkReply::NoError) {
|
|
logger->addItem(tr("Network error: %1.\n"
|
|
"Please check your network and proxy settings.")
|
|
.arg(getter->errorString()), LOGERROR);
|
|
getter->abort();
|
|
logger->setFinished();
|
|
disconnect(getter, &HttpGet::done, this, &ThemesInstallWindow::downloadDone);
|
|
connect(logger, &ProgressLoggerGui::closed, this, &QWidget::close);
|
|
return;
|
|
}
|
|
// handle possible error codes
|
|
if(iniDetails.value("error/code").toInt() != 0 || !iniDetails.contains("error/code")) {
|
|
LOG_ERROR() << "Theme site returned an error:"
|
|
<< iniDetails.value("error/code");
|
|
logger->addItem(tr("the following error occured:\n%1")
|
|
.arg(iniDetails.value("error/description", "unknown error").toString()), LOGERROR);
|
|
logger->setFinished();
|
|
connect(logger, &ProgressLoggerGui::closed, this, &QWidget::close);
|
|
return;
|
|
}
|
|
logger->addItem(tr("done."), LOGOK);
|
|
logger->setFinished();
|
|
logger->close();
|
|
|
|
// setup list
|
|
for(int i = 0; i < tl.size(); i++) {
|
|
iniDetails.beginGroup(tl.at(i));
|
|
// skip all themes without name field set (i.e. error section)
|
|
if(iniDetails.value("name").toString().isEmpty()) {
|
|
iniDetails.endGroup();
|
|
continue;
|
|
}
|
|
LOG_INFO() << "adding to list:" << tl.at(i);
|
|
// convert to unicode and replace HTML-specific entities
|
|
QByteArray raw = iniDetails.value("name").toByteArray();
|
|
QTextCodec* codec = QTextCodec::codecForHtml(raw);
|
|
QString name = codec->toUnicode(raw);
|
|
name.replace(""", "\"").replace("&", "&");
|
|
name.replace("<", "<").replace(">", ">");
|
|
QListWidgetItem *w = new QListWidgetItem;
|
|
w->setData(Qt::DisplayRole, name.trimmed());
|
|
w->setData(Qt::UserRole, tl.at(i));
|
|
ui.listThemes->addItem(w);
|
|
|
|
iniDetails.endGroup();
|
|
}
|
|
// check if there's a themes "MOTD" available
|
|
if(iniDetails.contains("status/msg")) {
|
|
// check if there's a localized msg available
|
|
QString lang = RbSettings::value(RbSettings::Language).toString().split("_").at(0);
|
|
QString msg;
|
|
if(iniDetails.contains("status/msg." + lang))
|
|
msg = iniDetails.value("status/msg." + lang).toString();
|
|
else
|
|
msg = iniDetails.value("status/msg").toString();
|
|
LOG_INFO() << "MOTD" << msg;
|
|
if(!msg.isEmpty())
|
|
QMessageBox::information(this, tr("Information"), msg);
|
|
}
|
|
}
|
|
|
|
|
|
void ThemesInstallWindow::updateSize(void)
|
|
{
|
|
long size = 0;
|
|
// sum up size for all selected themes
|
|
QSettings iniDetails(themesInfo.fileName(), QSettings::IniFormat, this);
|
|
#if QT_VERSION < 0x060000
|
|
iniDetails.setIniCodec(QTextCodec::codecForName("UTF-8"));
|
|
#endif
|
|
int items = ui.listThemes->selectedItems().size();
|
|
for(int i = 0; i < items; i++) {
|
|
iniDetails.beginGroup(ui.listThemes->selectedItems()
|
|
.at(i)->data(Qt::UserRole).toString());
|
|
size += iniDetails.value("size").toInt();
|
|
iniDetails.endGroup();
|
|
}
|
|
ui.labelSize->setText(tr("Download size %L1 kiB (%n item(s))", "", items)
|
|
.arg((size + 512) / 1024));
|
|
}
|
|
|
|
|
|
void ThemesInstallWindow::updateDetails(QListWidgetItem* cur, QListWidgetItem* prev)
|
|
{
|
|
if(cur == prev)
|
|
return;
|
|
|
|
QSettings iniDetails(themesInfo.fileName(), QSettings::IniFormat, this);
|
|
#if QT_VERSION < 0x060000
|
|
iniDetails.setIniCodec(QTextCodec::codecForName("UTF-8"));
|
|
#endif
|
|
|
|
QCoreApplication::processEvents();
|
|
ui.themeDescription->setText(tr("fetching details for %1")
|
|
.arg(cur->data(Qt::DisplayRole).toString()));
|
|
ui.themePreview->clear();
|
|
ui.themePreview->setText(tr("fetching preview ..."));
|
|
imgData.clear();
|
|
|
|
iniDetails.beginGroup(cur->data(Qt::UserRole).toString());
|
|
|
|
QUrl img, txt;
|
|
txt = QUrl(QString(PlayerBuildInfo::instance()->value(PlayerBuildInfo::ThemesUrl).toString() + "/"
|
|
+ iniDetails.value("descriptionfile").toString()));
|
|
img = QUrl(QString(PlayerBuildInfo::instance()->value(PlayerBuildInfo::ThemesUrl).toString() + "/"
|
|
+ iniDetails.value("image").toString()));
|
|
|
|
QString text;
|
|
QTextCodec* codec = QTextCodec::codecForName("UTF-8");
|
|
text = tr("<b>Author:</b> %1<hr/>").arg(codec->toUnicode(iniDetails
|
|
.value("author", tr("unknown")).toByteArray()));
|
|
text += tr("<b>Version:</b> %1<hr/>").arg(codec->toUnicode(iniDetails
|
|
.value("version", tr("unknown")).toByteArray()));
|
|
text += tr("<b>Description:</b> %1<hr/>").arg(codec->toUnicode(iniDetails
|
|
.value("about", tr("no description")).toByteArray()));
|
|
|
|
text.replace("\n", "<br/>");
|
|
ui.themeDescription->setHtml(text);
|
|
iniDetails.endGroup();
|
|
igetter.abort();
|
|
igetter.getFile(img);
|
|
}
|
|
|
|
|
|
void ThemesInstallWindow::updateImage(QNetworkReply::NetworkError error)
|
|
{
|
|
LOG_INFO() << "Updating image:"<< !error;
|
|
|
|
if(error != QNetworkReply::NoError) {
|
|
ui.themePreview->clear();
|
|
ui.themePreview->setText(tr("Retrieving theme preview failed.\n"
|
|
"HTTP response code: %1").arg(igetter.httpResponse()));
|
|
return;
|
|
}
|
|
else {
|
|
QPixmap p;
|
|
imgData = igetter.readAll();
|
|
if(imgData.isNull()) return;
|
|
p.loadFromData(imgData);
|
|
if(p.isNull()) {
|
|
ui.themePreview->clear();
|
|
ui.themePreview->setText(tr("no theme preview"));
|
|
}
|
|
else
|
|
ui.themePreview->setPixmap(p);
|
|
}
|
|
}
|
|
|
|
|
|
void ThemesInstallWindow::resizeEvent(QResizeEvent* e)
|
|
{
|
|
(void)e;
|
|
QPixmap p, q;
|
|
QSize img;
|
|
img.setHeight(ui.themePreview->height());
|
|
img.setWidth(ui.themePreview->width());
|
|
|
|
p.loadFromData(imgData);
|
|
if(p.isNull()) return;
|
|
q = p.scaled(img, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
|
ui.themePreview->setScaledContents(false);
|
|
ui.themePreview->setPixmap(p);
|
|
}
|
|
|
|
|
|
|
|
void ThemesInstallWindow::show()
|
|
{
|
|
QDialog::show();
|
|
ui.buttonOk->setText(tr("Select"));
|
|
|
|
if(!logger)
|
|
logger = new ProgressLoggerGui(this);
|
|
|
|
if(ui.listThemes->count() == 0) {
|
|
logger->show();
|
|
logger->addItem(tr("getting themes information ..."), LOGINFO);
|
|
|
|
connect(logger, &ProgressLoggerGui::aborted, this, &QWidget::close);
|
|
|
|
downloadInfo();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void ThemesInstallWindow::abort()
|
|
{
|
|
igetter.abort();
|
|
logger->setFinished();
|
|
close();
|
|
}
|
|
|
|
|
|
void ThemesInstallWindow::buttonOk(void)
|
|
{
|
|
emit selected(ui.listThemes->selectedItems().size());
|
|
close();
|
|
}
|
|
|
|
|
|
void ThemesInstallWindow::install()
|
|
{
|
|
if(ui.listThemes->selectedItems().size() == 0) {
|
|
logger->addItem(tr("No themes selected, skipping"), LOGINFO);
|
|
return;
|
|
}
|
|
QStringList themes;
|
|
QStringList names;
|
|
QStringList version;
|
|
QString zip;
|
|
QSettings iniDetails(themesInfo.fileName(), QSettings::IniFormat, this);
|
|
for(int i = 0; i < ui.listThemes->selectedItems().size(); i++) {
|
|
iniDetails.beginGroup(ui.listThemes->selectedItems().at(i)->data(Qt::UserRole).toString());
|
|
zip = PlayerBuildInfo::instance()->value(PlayerBuildInfo::ThemesUrl).toString()
|
|
+ "/" + iniDetails.value("archive").toString();
|
|
themes.append(zip);
|
|
names.append("Theme: " +
|
|
ui.listThemes->selectedItems().at(i)->data(Qt::DisplayRole).toString());
|
|
// if no version info is available use installation (current) date
|
|
version.append(iniDetails.value("version",
|
|
QDate().currentDate().toString("yyyyMMdd")).toString());
|
|
iniDetails.endGroup();
|
|
}
|
|
LOG_INFO() << "installing:" << themes;
|
|
|
|
if(logger == nullptr)
|
|
logger = new ProgressLoggerGui(this);
|
|
logger->show();
|
|
QString mountPoint = RbSettings::value(RbSettings::Mountpoint).toString();
|
|
QString m_suffix = RbSettings::value(RbSettings::Suffix).toString();
|
|
LOG_INFO() << "mountpoint:" << mountPoint;
|
|
// show dialog with error if mount point is wrong
|
|
if(!QFileInfo(mountPoint).isDir()) {
|
|
logger->addItem(tr("Mount point is wrong!"),LOGERROR);
|
|
logger->setFinished();
|
|
return;
|
|
}
|
|
|
|
installer = new ZipInstaller(this);
|
|
installer->setUrl(themes);
|
|
installer->setLogSection(names);
|
|
installer->setLogVersion(version);
|
|
|
|
if (!m_suffix.isEmpty()) {
|
|
QString fullpath = mountPoint + m_suffix;
|
|
installer->setMountPoint(fullpath);
|
|
} else {
|
|
installer->setMountPoint(mountPoint);
|
|
}
|
|
|
|
if(!RbSettings::value(RbSettings::CacheDisabled).toBool())
|
|
installer->setCache(true);
|
|
|
|
connect(installer, &ZipInstaller::logItem, logger, &ProgressLoggerGui::addItem);
|
|
connect(installer, &ZipInstaller::logProgress, logger, &ProgressLoggerGui::setProgress);
|
|
connect(installer, &ZipInstaller::done, this, &ThemesInstallWindow::finished);
|
|
connect(logger, &ProgressLoggerGui::aborted, installer, &ZipInstaller::abort);
|
|
installer->install();
|
|
}
|
|
|
|
|
|
void ThemesInstallWindow::changeEvent(QEvent *e)
|
|
{
|
|
if(e->type() == QEvent::LanguageChange) {
|
|
ui.retranslateUi(this);
|
|
} else {
|
|
QWidget::changeEvent(e);
|
|
}
|
|
}
|
|
|