Fix a bug where the conditional use of %C (i.e. %?C) caused the album art to draw...
[kugel-rb.git] / rbutil / rbutilqt / rbutilqt.cpp
blobec06955eef7ca31d1f46db0b333ac4be83d34e16
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
9 * Copyright (C) 2007 by Dominik Riebeling
10 * $Id$
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include <QtGui>
22 #include "version.h"
23 #include "rbutilqt.h"
24 #include "ui_rbutilqtfrm.h"
25 #include "ui_aboutbox.h"
26 #include "configure.h"
27 #include "install.h"
28 #include "installtalkwindow.h"
29 #include "createvoicewindow.h"
30 #include "httpget.h"
31 #include "themesinstallwindow.h"
32 #include "uninstallwindow.h"
33 #include "utils.h"
34 #include "rbzip.h"
35 #include "sysinfo.h"
36 #include "system.h"
37 #include "systrace.h"
38 #include "rbsettings.h"
40 #include "progressloggerinterface.h"
42 #include "bootloaderinstallbase.h"
43 #include "bootloaderinstallmi4.h"
44 #include "bootloaderinstallhex.h"
45 #include "bootloaderinstallipod.h"
46 #include "bootloaderinstallsansa.h"
47 #include "bootloaderinstallfile.h"
48 #include "bootloaderinstallchinachip.h"
49 #include "bootloaderinstallams.h"
52 #if defined(Q_OS_LINUX)
53 #include <stdio.h>
54 #endif
55 #if defined(Q_OS_WIN32)
56 #if defined(UNICODE)
57 #define _UNICODE
58 #endif
59 #include <stdio.h>
60 #include <tchar.h>
61 #include <windows.h>
62 #endif
64 RbUtilQt::RbUtilQt(QWidget *parent) : QMainWindow(parent)
66 // startup log
67 qDebug() << "======================================";
68 qDebug() << "[System] Rockbox Utility " VERSION;
69 qDebug() << "[System] Qt version:" << qVersion();
70 qDebug() << "======================================";
72 absolutePath = qApp->applicationDirPath();
74 HttpGet::setGlobalUserAgent("rbutil/"VERSION);
75 // init startup & autodetection
76 ui.setupUi(this);
77 updateSettings();
78 downloadInfo();
80 m_gotInfo = false;
81 m_auto = false;
83 // manual tab
84 ui.radioPdf->setChecked(true);
86 // info tab
87 ui.treeInfo->setAlternatingRowColors(true);
88 ui.treeInfo->setHeaderLabels(QStringList() << tr("File") << tr("Version"));
89 ui.treeInfo->expandAll();
90 ui.treeInfo->setColumnCount(2);
91 // disable quick install until version info is available
92 ui.buttonSmall->setEnabled(false);
93 ui.buttonComplete->setEnabled(false);
95 connect(ui.tabWidget, SIGNAL(currentChanged(int)), this, SLOT(updateTabs(int)));
96 connect(ui.actionAbout_Qt, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
97 connect(ui.action_About, SIGNAL(triggered()), this, SLOT(about()));
98 connect(ui.action_Help, SIGNAL(triggered()), this, SLOT(help()));
99 connect(ui.action_Configure, SIGNAL(triggered()), this, SLOT(configDialog()));
100 connect(ui.buttonChangeDevice, SIGNAL(clicked()), this, SLOT(configDialog()));
101 connect(ui.buttonRockbox, SIGNAL(clicked()), this, SLOT(installBtn()));
102 connect(ui.buttonBootloader, SIGNAL(clicked()), this, SLOT(installBootloaderBtn()));
103 connect(ui.buttonFonts, SIGNAL(clicked()), this, SLOT(installFontsBtn()));
104 connect(ui.buttonGames, SIGNAL(clicked()), this, SLOT(installDoomBtn()));
105 connect(ui.buttonTalk, SIGNAL(clicked()), this, SLOT(createTalkFiles()));
106 connect(ui.buttonCreateVoice, SIGNAL(clicked()), this, SLOT(createVoiceFile()));
107 connect(ui.buttonVoice, SIGNAL(clicked()), this, SLOT(installVoice()));
108 connect(ui.buttonThemes, SIGNAL(clicked()), this, SLOT(installThemes()));
109 connect(ui.buttonRemoveRockbox, SIGNAL(clicked()), this, SLOT(uninstall()));
110 connect(ui.buttonRemoveBootloader, SIGNAL(clicked()), this, SLOT(uninstallBootloader()));
111 connect(ui.buttonDownloadManual, SIGNAL(clicked()), this, SLOT(downloadManual()));
112 connect(ui.buttonSmall, SIGNAL(clicked()), this, SLOT(smallInstall()));
113 connect(ui.buttonComplete, SIGNAL(clicked()), this, SLOT(completeInstall()));
115 // actions accessible from the menu
116 connect(ui.actionComplete_Installation, SIGNAL(triggered()), this, SLOT(completeInstall()));
117 connect(ui.actionSmall_Installation, SIGNAL(triggered()), this, SLOT(smallInstall()));
118 connect(ui.actionInstall_Bootloader, SIGNAL(triggered()), this, SLOT(installBootloaderBtn()));
119 connect(ui.actionInstall_Rockbox, SIGNAL(triggered()), this, SLOT(installBtn()));
120 connect(ui.actionFonts_Package, SIGNAL(triggered()), this, SLOT(installFontsBtn()));
121 connect(ui.actionInstall_Themes, SIGNAL(triggered()), this, SLOT(installThemes()));
122 connect(ui.actionInstall_Game_Files, SIGNAL(triggered()), this, SLOT(installDoomBtn()));
123 connect(ui.actionInstall_Voice_File, SIGNAL(triggered()), this, SLOT(installVoice()));
124 connect(ui.actionCreate_Voice_File, SIGNAL(triggered()), this, SLOT(createVoiceFile()));
125 connect(ui.actionCreate_Talk_Files, SIGNAL(triggered()), this, SLOT(createTalkFiles()));
126 connect(ui.actionRemove_bootloader, SIGNAL(triggered()), this, SLOT(uninstallBootloader()));
127 connect(ui.actionUninstall_Rockbox, SIGNAL(triggered()), this, SLOT(uninstall()));
128 connect(ui.action_System_Info, SIGNAL(triggered()), this, SLOT(sysinfo()));
129 connect(ui.action_Trace, SIGNAL(triggered()), this, SLOT(trace()));
131 #if !defined(STATIC)
132 ui.actionInstall_Rockbox_Utility_on_player->setEnabled(false);
133 #else
134 connect(ui.actionInstall_Rockbox_Utility_on_player, SIGNAL(triggered()), this, SLOT(installPortable()));
135 #endif
140 void RbUtilQt::trace(void)
142 SysTrace wnd(this);
143 wnd.exec();
146 void RbUtilQt::sysinfo(void)
148 Sysinfo info(this);
149 info.exec();
152 void RbUtilQt::updateTabs(int count)
154 switch(count) {
155 case 6:
156 updateInfo();
157 break;
158 default:
159 break;
164 void RbUtilQt::downloadInfo()
166 // make sure the version map is repopulated correctly later.
167 versmap.clear();
168 // try to get the current build information
169 daily = new HttpGet(this);
170 connect(daily, SIGNAL(done(bool)), this, SLOT(downloadDone(bool)));
171 connect(daily, SIGNAL(requestFinished(int, bool)), this, SLOT(downloadDone(int, bool)));
172 connect(qApp, SIGNAL(lastWindowClosed()), daily, SLOT(abort()));
173 if(RbSettings::value(RbSettings::CacheOffline).toBool())
174 daily->setCache(true);
175 else
176 daily->setCache(false);
177 qDebug() << "[RbUtil] downloading build info";
178 daily->setFile(&buildInfo);
179 daily->getFile(QUrl(RbSettings::value(RbSettings::ServerConfUrl).toString()));
183 void RbUtilQt::downloadDone(bool error)
185 if(error) {
186 qDebug() << "[RbUtil] network error:" << daily->error();
187 QMessageBox::critical(this, tr("Network error"),
188 tr("Can't get version information."));
189 return;
191 qDebug() << "[RbUtil] network status:" << daily->error();
193 buildInfo.open();
194 QSettings info(buildInfo.fileName(), QSettings::IniFormat, this);
195 buildInfo.close();
196 versmap.insert("arch_rev", info.value("dailies/rev").toString());
197 versmap.insert("arch_date", info.value("dailies/date").toString());
199 info.beginGroup("release");
200 versmap.insert("rel_rev", info.value(RbSettings::value(RbSettings::CurBuildserverModel).toString()).toString());
201 info.endGroup();
203 if(versmap.value("rel_rev").isEmpty()) {
204 ui.buttonSmall->setEnabled(false);
205 ui.buttonComplete->setEnabled(false);
207 else {
208 ui.buttonSmall->setEnabled(true);
209 ui.buttonComplete->setEnabled(true);
212 bleeding = new HttpGet(this);
213 connect(bleeding, SIGNAL(done(bool)), this, SLOT(downloadBleedingDone(bool)));
214 connect(bleeding, SIGNAL(requestFinished(int, bool)), this, SLOT(downloadDone(int, bool)));
215 connect(qApp, SIGNAL(lastWindowClosed()), daily, SLOT(abort()));
216 if(RbSettings::value(RbSettings::CacheOffline).toBool())
217 bleeding->setCache(true);
218 bleeding->setFile(&bleedingInfo);
219 bleeding->getFile(QUrl(RbSettings::value(RbSettings::BleedingInfo).toString()));
221 if(RbSettings::value(RbSettings::RbutilVersion) != PUREVERSION) {
222 QApplication::processEvents();
223 QMessageBox::information(this, tr("New installation"),
224 tr("This is a new installation of Rockbox Utility, or a new version. "
225 "The configuration dialog will now open to allow you to setup the program, "
226 " or review your settings."));
227 configDialog();
229 else if(chkConfig(false)) {
230 QApplication::processEvents();
231 QMessageBox::critical(this, tr("Configuration error"),
232 tr("Your configuration is invalid. This is most likely due "
233 "to a changed device path. The configuration dialog will "
234 "now open to allow you to correct the problem."));
235 configDialog();
240 void RbUtilQt::downloadBleedingDone(bool error)
242 if(error) {
243 qDebug() << "[RbUtil] network error:" << bleeding->error();
245 else {
246 bleedingInfo.open();
247 QSettings info(bleedingInfo.fileName(), QSettings::IniFormat, this);
248 bleedingInfo.close();
249 versmap.insert("bleed_rev", info.value("bleeding/rev").toString());
250 versmap.insert("bleed_date", info.value("bleeding/timestamp").toString());
251 qDebug() << "[RbUtil] version map:" << versmap;
253 m_gotInfo = true;
258 void RbUtilQt::downloadDone(int id, bool error)
260 QString errorString;
261 errorString = tr("Network error: %1. Please check your network and proxy settings.")
262 .arg(daily->errorString());
263 if(error) {
264 QMessageBox::about(this, "Network Error", errorString);
265 m_networkerror = daily->errorString();
267 qDebug() << "[RbUtil] downloadDone:" << id << "error:" << error;
271 void RbUtilQt::about()
273 QDialog *window = new QDialog(this);
274 Ui::aboutBox about;
275 about.setupUi(window);
276 window->setModal(true);
278 QFile licence(":/docs/gpl-2.0.html");
279 licence.open(QIODevice::ReadOnly);
280 QTextStream c(&licence);
281 QString cline = c.readAll();
282 about.browserLicense->insertHtml(cline);
283 about.browserLicense->moveCursor(QTextCursor::Start, QTextCursor::MoveAnchor);
284 QFile credits(":/docs/CREDITS");
285 credits.open(QIODevice::ReadOnly);
286 QTextStream r(&credits);
287 r.setCodec(QTextCodec::codecForName("UTF-8"));
288 QString rline = r.readAll();
289 about.browserCredits->insertPlainText(rline);
290 about.browserCredits->moveCursor(QTextCursor::Start, QTextCursor::MoveAnchor);
291 QString title = QString("<b>The Rockbox Utility</b><br/>Version %1").arg(FULLVERSION);
292 about.labelTitle->setText(title);
294 window->show();
299 void RbUtilQt::help()
301 QUrl helpurl("http://www.rockbox.org/wiki/RockboxUtility");
302 QDesktopServices::openUrl(helpurl);
306 void RbUtilQt::configDialog()
308 Config *cw = new Config(this);
309 connect(cw, SIGNAL(settingsUpdated()), this, SLOT(updateSettings()));
310 connect(cw, SIGNAL(settingsUpdated()), this, SLOT(downloadInfo()));
311 cw->show();
315 void RbUtilQt::updateSettings()
317 qDebug() << "[RbUtil] updating current settings";
318 updateDevice();
319 updateManual();
320 if(RbSettings::value(RbSettings::ProxyType) == "system") {
321 HttpGet::setGlobalProxy(System::systemProxy());
323 else if(RbSettings::value(RbSettings::ProxyType) == "manual") {
324 HttpGet::setGlobalProxy(RbSettings::value(RbSettings::Proxy).toString());
326 else {
327 HttpGet::setGlobalProxy(QUrl(""));
329 HttpGet::setGlobalCache(RbSettings::value(RbSettings::CachePath).toString());
330 HttpGet::setGlobalDumbCache(RbSettings::value(RbSettings::CacheOffline).toBool());
334 void RbUtilQt::updateDevice()
336 if(RbSettings::value(RbSettings::CurBootloaderMethod) == "none" ) {
337 ui.buttonBootloader->setEnabled(false);
338 ui.buttonRemoveBootloader->setEnabled(false);
339 ui.labelBootloader->setEnabled(false);
340 ui.labelRemoveBootloader->setEnabled(false);
342 else {
343 ui.buttonBootloader->setEnabled(true);
344 ui.labelBootloader->setEnabled(true);
345 if(RbSettings::value(RbSettings::CurBootloaderMethod) == "fwpatcher") {
346 ui.labelRemoveBootloader->setEnabled(false);
347 ui.buttonRemoveBootloader->setEnabled(false);
349 else {
350 ui.labelRemoveBootloader->setEnabled(true);
351 ui.buttonRemoveBootloader->setEnabled(true);
355 // displayed device info
356 QString mountpoint = RbSettings::value(RbSettings::Mountpoint).toString();
357 QString brand = RbSettings::value(RbSettings::CurBrand).toString();
358 QString name = RbSettings::value(RbSettings::CurName).toString();
359 if(name.isEmpty()) name = "&lt;none&gt;";
360 if(mountpoint.isEmpty()) mountpoint = "&lt;invalid&gt;";
361 ui.labelDevice->setText(tr("<b>%1 %2</b> at <b>%3</b>")
362 .arg(brand, name, QDir::toNativeSeparators(mountpoint)));
366 void RbUtilQt::updateManual()
368 if(RbSettings::value(RbSettings::Platform) != "")
370 QString manual= RbSettings::value(RbSettings::CurManual).toString();
372 if(manual == "")
373 manual = "rockbox-" + RbSettings::value(RbSettings::Platform).toString();
374 QString pdfmanual;
375 pdfmanual = RbSettings::value(RbSettings::ManualUrl).toString()
376 + "/" + manual + ".pdf";
377 QString htmlmanual;
378 htmlmanual = RbSettings::value(RbSettings::ManualUrl).toString()
379 + "/" + manual + "/rockbox-build.html";
380 ui.labelPdfManual->setText(tr("<a href='%1'>PDF Manual</a>")
381 .arg(pdfmanual));
382 ui.labelHtmlManual->setText(tr("<a href='%1'>HTML Manual (opens in browser)</a>")
383 .arg(htmlmanual));
385 else {
386 ui.labelPdfManual->setText(tr("Select a device for a link to the correct manual"));
387 ui.labelHtmlManual->setText(tr("<a href='%1'>Manual Overview</a>")
388 .arg("http://www.rockbox.org/manual.shtml"));
393 void RbUtilQt::completeInstall()
395 if(chkConfig(true)) return;
396 if(QMessageBox::question(this, tr("Confirm Installation"),
397 tr("Do you really want to perform a complete installation?\n\n"
398 "This will install Rockbox %1. To install the most recent "
399 "development build available press \"Cancel\" and "
400 "use the \"Installation\" tab.")
401 .arg(versmap.value("rel_rev")),
402 QMessageBox::Ok | QMessageBox::Cancel) != QMessageBox::Ok)
403 return;
404 // create logger
405 logger = new ProgressLoggerGui(this);
406 logger->show();
408 if(smallInstallInner())
409 return;
410 logger->setRunning();
411 // Fonts
412 m_error = false;
413 m_installed = false;
414 if(!installFontsAuto())
415 return;
416 else
418 // wait for installation finished
419 while(!m_installed)
420 QApplication::processEvents();
422 if(m_error) return;
423 logger->setRunning();
425 // Doom
426 if(hasDoom())
428 m_error = false;
429 m_installed = false;
430 if(!installDoomAuto())
431 return;
432 else
434 // wait for installation finished
435 while(!m_installed)
436 QApplication::processEvents();
438 if(m_error) return;
441 // theme
442 // this is a window
443 // it has its own logger window,so close our.
444 logger->close();
445 installThemes();
449 void RbUtilQt::smallInstall()
451 if(chkConfig(true)) return;
452 if(QMessageBox::question(this, tr("Confirm Installation"),
453 tr("Do you really want to perform a minimal installation? "
454 "A minimal installation will contain only the absolutely "
455 "necessary parts to run Rockbox.\n\n"
456 "This will install Rockbox %1. To install the most recent "
457 "development build available press \"Cancel\" and "
458 "use the \"Installation\" tab.")
459 .arg(versmap.value("rel_rev")),
460 QMessageBox::Ok | QMessageBox::Cancel) != QMessageBox::Ok)
461 return;
463 // create logger
464 logger = new ProgressLoggerGui(this);
465 logger->show();
467 smallInstallInner();
470 bool RbUtilQt::smallInstallInner()
472 QString mountpoint = RbSettings::value(RbSettings::Mountpoint).toString();
473 // show dialog with error if mount point is wrong
474 if(!QFileInfo(mountpoint).isDir()) {
475 logger->addItem(tr("Mount point is wrong!"),LOGERROR);
476 logger->setFinished();
477 return true;
479 // Bootloader
480 if(RbSettings::value(RbSettings::CurBootloaderMethod) != "none")
482 m_error = false;
483 m_installed = false;
484 m_auto = true;
485 if(!installBootloaderAuto()) {
486 logger->setFinished();
487 return true;
489 else
491 // wait for boot loader installation finished
492 while(!m_installed)
493 QApplication::processEvents();
495 m_auto = false;
496 if(m_error) return true;
497 logger->setRunning();
500 // Rockbox
501 m_error = false;
502 m_installed = false;
503 if(!installAuto())
504 return true;
505 else
507 // wait for installation finished
508 while(!m_installed)
509 QApplication::processEvents();
512 installBootloaderPost(false);
513 return false;
516 void RbUtilQt::installdone(bool error)
518 qDebug() << "[RbUtil] install done";
519 m_installed = true;
520 m_error = error;
523 void RbUtilQt::installBtn()
525 if(chkConfig(true)) return;
526 install();
529 bool RbUtilQt::installAuto()
531 QString file = RbSettings::value(RbSettings::ReleaseUrl).toString();
532 file.replace("%MODEL%", RbSettings::value(RbSettings::CurBuildserverModel).toString());
533 file.replace("%RELVERSION%", versmap.value("rel_rev"));
534 buildInfo.open();
535 QSettings info(buildInfo.fileName(), QSettings::IniFormat, this);
536 buildInfo.close();
538 // check installed Version and Target
539 QString warning = check(false);
540 if(!warning.isEmpty())
542 if(QMessageBox::warning(this, tr("Really continue?"), warning,
543 QMessageBox::Ok | QMessageBox::Abort, QMessageBox::Abort)
544 == QMessageBox::Abort)
546 logger->addItem(tr("Aborted!"), LOGERROR);
547 logger->setFinished();
548 return false;
552 // check version
553 RockboxInfo rbinfo(RbSettings::value(RbSettings::Mountpoint).toString());
554 if(rbinfo.version() != "")
556 if(QMessageBox::question(this, tr("Installed Rockbox detected"),
557 tr("Rockbox installation detected. Do you want to backup first?"),
558 QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
560 logger->addItem(tr("Starting backup..."),LOGINFO);
561 QString backupName = RbSettings::value(RbSettings::Mountpoint).toString()
562 + "/.backup/rockbox-backup-" + rbinfo.version() + ".zip";
564 //! create dir, if it doesnt exist
565 QFileInfo backupFile(backupName);
566 if(!QDir(backupFile.path()).exists())
568 QDir a;
569 a.mkpath(backupFile.path());
572 //! create backup
573 RbZip backup;
574 connect(&backup,SIGNAL(zipProgress(int,int)),logger, SLOT(setProgress(int,int)));
575 if(backup.createZip(backupName,
576 RbSettings::value(RbSettings::Mountpoint).toString() + "/.rockbox") == Zip::Ok)
578 logger->addItem(tr("Backup successful"),LOGOK);
580 else
582 logger->addItem(tr("Backup failed!"),LOGERROR);
583 logger->setFinished();
584 return false;
589 //! install current build
590 ZipInstaller* installer = new ZipInstaller(this);
591 installer->setUrl(file);
592 installer->setLogSection("Rockbox (Base)");
593 installer->setLogVersion(versmap.value("rel_rev"));
594 if(!RbSettings::value(RbSettings::CacheDisabled).toBool())
595 installer->setCache(true);
596 installer->setMountPoint(RbSettings::value(RbSettings::Mountpoint).toString());
598 connect(installer, SIGNAL(done(bool)), this, SLOT(installdone(bool)));
599 connect(installer, SIGNAL(logItem(QString, int)), logger, SLOT(addItem(QString, int)));
600 connect(installer, SIGNAL(logProgress(int, int)), logger, SLOT(setProgress(int, int)));
601 connect(installer, SIGNAL(done(bool)), logger, SLOT(setFinished()));
602 connect(logger, SIGNAL(aborted()), installer, SLOT(abort()));
603 installer->install();
604 return true;
608 void RbUtilQt::install()
610 Install *installWindow = new Install(this);
612 buildInfo.open();
613 QSettings info(buildInfo.fileName(), QSettings::IniFormat, this);
614 buildInfo.close();
615 installWindow->setVersionStrings(versmap);
617 installWindow->show();
620 bool RbUtilQt::installBootloaderAuto()
622 installBootloader();
623 return !m_error;
626 void RbUtilQt::installBootloaderBtn()
628 if(chkConfig(true)) return;
629 if(QMessageBox::question(this, tr("Confirm Installation"),
630 tr("Do you really want to install the Bootloader?"),
631 QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) return;
633 // create logger
634 logger = new ProgressLoggerGui(this);
635 logger->show();
636 installBootloader();
639 void RbUtilQt::installBootloader()
641 QString platform = RbSettings::value(RbSettings::Platform).toString();
642 QString backupDestination = "";
643 m_error = false;
645 // create installer
646 BootloaderInstallBase *bl;
647 QString type = RbSettings::value(RbSettings::CurBootloaderMethod).toString();
648 if(type == "mi4") {
649 bl = new BootloaderInstallMi4(this);
651 else if(type == "hex") {
652 bl = new BootloaderInstallHex(this);
654 else if(type == "sansa") {
655 bl = new BootloaderInstallSansa(this);
657 else if(type == "ipod") {
658 bl = new BootloaderInstallIpod(this);
660 else if(type == "file") {
661 bl = new BootloaderInstallFile(this);
663 else if(type == "chinachip") {
664 bl = new BootloaderInstallChinaChip(this);
666 else if(type == "ams") {
667 bl = new BootloaderInstallAms(this);
669 else {
670 logger->addItem(tr("No install method known."), LOGERROR);
671 logger->setFinished();
672 return;
675 // set bootloader filename. Do this now as installed() needs it.
676 QStringList blfile = RbSettings::value(RbSettings::CurBootloaderFile).toStringList();
677 QStringList blfilepath;
678 for(int a = 0; a < blfile.size(); a++) {
679 blfilepath.append(RbSettings::value(RbSettings::Mountpoint).toString()
680 + blfile.at(a));
682 bl->setBlFile(blfilepath);
683 QUrl url(RbSettings::value(RbSettings::BootloaderUrl).toString()
684 + RbSettings::value(RbSettings::CurBootloaderName).toString());
685 bl->setBlUrl(url);
686 bl->setLogfile(RbSettings::value(RbSettings::Mountpoint).toString()
687 + "/.rockbox/rbutil.log");
689 if(bl->installed() == BootloaderInstallBase::BootloaderRockbox) {
690 if(QMessageBox::question(this, tr("Bootloader detected"),
691 tr("Bootloader already installed. Do you want to reinstall the bootloader?"),
692 QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) {
693 if(m_auto) {
694 // keep logger open for auto installs.
695 // don't consider abort as error in auto-mode.
696 logger->addItem(tr("Bootloader installation skipped"), LOGINFO);
697 installBootloaderPost(false);
699 else {
700 logger->close();
701 installBootloaderPost(true);
703 return;
706 else if(bl->installed() == BootloaderInstallBase::BootloaderOther
707 && bl->capabilities() & BootloaderInstallBase::Backup)
709 QString targetFolder = RbSettings::value(RbSettings::CurPlatformName).toString()
710 + " Firmware Backup";
711 // remove invalid character(s)
712 targetFolder.remove(QRegExp("[:/]"));
713 if(QMessageBox::question(this, tr("Create Bootloader backup"),
714 tr("You can create a backup of the original bootloader "
715 "file. Press \"Yes\" to select an output folder on your "
716 "computer to save the file to. The file will get placed "
717 "in a new folder \"%1\" created below the selected folder.\n"
718 "Press \"No\" to skip this step.").arg(targetFolder),
719 QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
720 BrowseDirtree tree(this, tr("Browse backup folder"));
721 tree.setDir(QDir::home());
722 tree.exec();
724 backupDestination = tree.getSelected() + "/" + targetFolder;
725 qDebug() << "[RbUtil] backing up to" << backupDestination;
726 // backup needs to be done after the logger has been set up.
730 if(bl->capabilities() & BootloaderInstallBase::NeedsOf)
732 int ret;
733 ret = QMessageBox::information(this, tr("Prerequisites"),
734 bl->ofHint(),QMessageBox::Ok | QMessageBox::Abort);
735 if(ret != QMessageBox::Ok) {
736 // consider aborting an error to close window / abort automatic
737 // installation.
738 m_error = true;
739 logger->addItem(tr("Bootloader installation aborted"), LOGINFO);
740 logger->setFinished();
741 return;
743 // open dialog to browse to of file
744 QString offile;
745 offile = QFileDialog::getOpenFileName(this,
746 tr("Select firmware file"), QDir::homePath());
747 if(!QFileInfo(offile).isReadable()) {
748 logger->addItem(tr("Error opening firmware file"), LOGERROR);
749 logger->setFinished();
750 m_error = true;
751 return;
753 bl->setOfFile(offile);
756 // the bootloader install class does NOT use any GUI stuff.
757 // All messages are passed via signals.
758 connect(bl, SIGNAL(done(bool)), logger, SLOT(setFinished()));
759 connect(bl, SIGNAL(done(bool)), this, SLOT(installBootloaderPost(bool)));
760 connect(bl, SIGNAL(logItem(QString, int)), logger, SLOT(addItem(QString, int)));
761 connect(bl, SIGNAL(logProgress(int, int)), logger, SLOT(setProgress(int, int)));
763 // start install.
764 if(!backupDestination.isEmpty()) {
765 if(!bl->backup(backupDestination)) {
766 if(QMessageBox::warning(this, tr("Backup error"),
767 tr("Could not create backup file. Continue?"),
768 QMessageBox::No | QMessageBox::Yes)
769 == QMessageBox::No) {
770 logger->setFinished();
771 return;
775 bl->install();
778 void RbUtilQt::installBootloaderPost(bool error)
780 qDebug() << "[RbUtil] Bootloader Post-Installation, error state:" << error;
781 // if an error occured don't perform post install steps.
782 if(error) {
783 m_error = true;
784 return;
786 else
787 m_error = false;
789 m_installed = true;
790 // end here if automated install
791 if(m_auto)
792 return;
794 QString msg = BootloaderInstallBase::postinstallHints(
795 RbSettings::value(RbSettings::Platform).toString());
796 if(!msg.isEmpty()) {
797 QMessageBox::information(this, tr("Manual steps required"), msg);
798 logger->close();
803 void RbUtilQt::installFontsBtn()
805 if(chkConfig(true)) return;
806 if(QMessageBox::question(this, tr("Confirm Installation"),
807 tr("Do you really want to install the fonts package?"),
808 QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) return;
809 // create logger
810 logger = new ProgressLoggerGui(this);
811 logger->show();
812 installFonts();
815 bool RbUtilQt::installFontsAuto()
817 installFonts();
819 return !m_error;
822 void RbUtilQt::installFonts()
824 // create zip installer
825 installer = new ZipInstaller(this);
827 installer->setUrl(RbSettings::value(RbSettings::FontUrl).toString());
828 installer->setLogSection("Fonts");
829 installer->setLogVersion(versmap.value("arch_date"));
830 installer->setMountPoint(RbSettings::value(RbSettings::Mountpoint).toString());
831 if(!RbSettings::value(RbSettings::CacheDisabled).toBool())
832 installer->setCache(true);
834 connect(installer, SIGNAL(done(bool)), this, SLOT(installdone(bool)));
835 connect(installer, SIGNAL(logItem(QString, int)), logger, SLOT(addItem(QString, int)));
836 connect(installer, SIGNAL(logProgress(int, int)), logger, SLOT(setProgress(int, int)));
837 connect(installer, SIGNAL(done(bool)), logger, SLOT(setFinished()));
838 connect(logger, SIGNAL(aborted()), installer, SLOT(abort()));
839 installer->install();
843 void RbUtilQt::installVoice()
845 if(chkConfig(true)) return;
847 if(m_gotInfo == false)
849 QMessageBox::warning(this, tr("Warning"),
850 tr("The Application is still downloading Information about new Builds."
851 " Please try again shortly."));
852 return;
855 if(QMessageBox::question(this, tr("Confirm Installation"),
856 tr("Do you really want to install the voice file?"),
857 QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) return;
858 // create logger
859 logger = new ProgressLoggerGui(this);
860 logger->show();
862 // create zip installer
863 installer = new ZipInstaller(this);
865 QString voiceurl = RbSettings::value(RbSettings::VoiceUrl).toString();
867 voiceurl += RbSettings::value(RbSettings::CurBuildserverModel).toString() + "-" +
868 versmap.value("arch_date") + "-english.zip";
869 qDebug() << "[RbUtil] voicefile URL:" << voiceurl;
871 installer->setUrl(voiceurl);
872 installer->setLogSection("Voice");
873 installer->setLogVersion(versmap.value("arch_date"));
874 installer->setMountPoint(RbSettings::value(RbSettings::Mountpoint).toString());
875 if(!RbSettings::value(RbSettings::CacheDisabled).toBool())
876 installer->setCache(true);
877 connect(installer, SIGNAL(logItem(QString, int)), logger, SLOT(addItem(QString, int)));
878 connect(installer, SIGNAL(logProgress(int, int)), logger, SLOT(setProgress(int, int)));
879 connect(installer, SIGNAL(done(bool)), logger, SLOT(setFinished()));
880 connect(logger, SIGNAL(aborted()), installer, SLOT(abort()));
881 installer->install();
885 void RbUtilQt::installDoomBtn()
887 if(chkConfig(true)) return;
888 if(!hasDoom()){
889 QMessageBox::critical(this, tr("Error"),
890 tr("Your device doesn't have a doom plugin. Aborting."));
891 return;
894 if(QMessageBox::question(this, tr("Confirm Installation"),
895 tr("Do you really want to install the game addon files?"),
896 QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) return;
897 // create logger
898 logger = new ProgressLoggerGui(this);
899 logger->show();
901 installDoom();
903 bool RbUtilQt::installDoomAuto()
905 installDoom();
906 return !m_error;
909 bool RbUtilQt::hasDoom()
911 QFile doomrock(RbSettings::value(RbSettings::Mountpoint).toString()
912 +"/.rockbox/rocks/games/doom.rock");
913 return doomrock.exists();
916 void RbUtilQt::installDoom()
918 // create zip installer
919 installer = new ZipInstaller(this);
921 installer->setUrl(RbSettings::value(RbSettings::DoomUrl).toString());
922 installer->setLogSection("Game Addons");
923 installer->setLogVersion(versmap.value("arch_date"));
924 installer->setMountPoint(RbSettings::value(RbSettings::Mountpoint).toString());
925 if(!RbSettings::value(RbSettings::CacheDisabled).toBool())
926 installer->setCache(true);
927 connect(installer, SIGNAL(done(bool)), this, SLOT(installdone(bool)));
928 connect(installer, SIGNAL(logItem(QString, int)), logger, SLOT(addItem(QString, int)));
929 connect(installer, SIGNAL(logProgress(int, int)), logger, SLOT(setProgress(int, int)));
930 connect(installer, SIGNAL(done(bool)), logger, SLOT(setFinished()));
931 connect(logger, SIGNAL(aborted()), installer, SLOT(abort()));
932 installer->install();
936 void RbUtilQt::installThemes()
938 if(chkConfig(true)) return;
939 ThemesInstallWindow* tw = new ThemesInstallWindow(this);
940 tw->setModal(true);
941 tw->show();
944 void RbUtilQt::createTalkFiles(void)
946 if(chkConfig(true)) return;
947 InstallTalkWindow *installWindow = new InstallTalkWindow(this);
949 connect(installWindow, SIGNAL(settingsUpdated()), this, SLOT(downloadInfo()));
950 connect(installWindow, SIGNAL(settingsUpdated()), this, SLOT(updateSettings()));
951 installWindow->show();
955 void RbUtilQt::createVoiceFile(void)
957 if(chkConfig(true)) return;
958 CreateVoiceWindow *installWindow = new CreateVoiceWindow(this);
960 connect(installWindow, SIGNAL(settingsUpdated()), this, SLOT(downloadInfo()));
961 connect(installWindow, SIGNAL(settingsUpdated()), this, SLOT(updateSettings()));
962 installWindow->show();
965 void RbUtilQt::uninstall(void)
967 if(chkConfig(true)) return;
968 UninstallWindow *uninstallWindow = new UninstallWindow(this);
969 uninstallWindow->show();
973 void RbUtilQt::uninstallBootloader(void)
975 if(chkConfig(true)) return;
976 if(QMessageBox::question(this, tr("Confirm Uninstallation"),
977 tr("Do you really want to uninstall the Bootloader?"),
978 QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) return;
979 // create logger
980 ProgressLoggerGui* logger = new ProgressLoggerGui(this);
981 logger->setProgressVisible(false);
982 logger->show();
984 QString platform = RbSettings::value(RbSettings::Platform).toString();
986 // create installer
987 BootloaderInstallBase *bl;
988 QString type = RbSettings::value(RbSettings::CurBootloaderMethod).toString();
989 if(type == "mi4") {
990 bl = new BootloaderInstallMi4(this);
992 else if(type == "hex") {
993 bl = new BootloaderInstallHex(this);
995 else if(type == "sansa") {
996 bl = new BootloaderInstallSansa(this);
998 else if(type == "ipod") {
999 bl = new BootloaderInstallIpod(this);
1001 else if(type == "file") {
1002 bl = new BootloaderInstallFile(this);
1004 else {
1005 logger->addItem(tr("No uninstall method known."), LOGERROR);
1006 logger->setFinished();
1007 return;
1010 QStringList blfile = RbSettings::value(RbSettings::CurBootloaderFile).toStringList();
1011 QStringList blfilepath;
1012 for(int a = 0; a < blfile.size(); a++) {
1013 blfilepath.append(RbSettings::value(RbSettings::Mountpoint).toString()
1014 + blfile.at(a));
1016 bl->setBlFile(blfilepath);
1018 connect(bl, SIGNAL(logItem(QString, int)), logger, SLOT(addItem(QString, int)));
1019 connect(bl, SIGNAL(logProgress(int, int)), logger, SLOT(setProgress(int, int)));
1021 int result;
1022 result = bl->uninstall();
1024 logger->setFinished();
1029 void RbUtilQt::downloadManual(void)
1031 if(chkConfig(true)) return;
1032 if(QMessageBox::question(this, tr("Confirm download"),
1033 tr("Do you really want to download the manual? The manual will be saved "
1034 "to the root folder of your player."),
1035 QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes)
1036 return;
1038 buildInfo.open();
1039 QSettings info(buildInfo.fileName(), QSettings::IniFormat, this);
1040 buildInfo.close();
1042 QString manual = RbSettings::value(RbSettings::CurManual).toString();
1043 if(manual.isEmpty())
1044 manual = "rockbox-" + RbSettings::value(RbSettings::Platform).toString();
1046 QString date = (info.value("dailies/date").toString());
1048 QString manualurl;
1049 QString target;
1050 QString section;
1051 if(ui.radioPdf->isChecked()) {
1052 target = "/" + manual + ".pdf";
1053 section = "Manual (PDF)";
1055 else {
1056 target = "/" + manual + "-" + date + "-html.zip";
1057 section = "Manual (HTML)";
1059 manualurl = RbSettings::value(RbSettings::ManualUrl).toString() + "/" + target;
1060 qDebug() << "[RbUtil] Manual URL:" << manualurl;
1062 ProgressLoggerGui* logger = new ProgressLoggerGui(this);
1063 logger->show();
1064 installer = new ZipInstaller(this);
1065 installer->setMountPoint(RbSettings::value(RbSettings::Mountpoint).toString());
1066 if(!RbSettings::value(RbSettings::CacheDisabled).toBool())
1067 installer->setCache(true);
1068 installer->setLogSection(section);
1069 installer->setLogVersion(date);
1070 installer->setUrl(manualurl);
1071 installer->setUnzip(false);
1072 installer->setTarget(target);
1073 connect(installer, SIGNAL(logItem(QString, int)), logger, SLOT(addItem(QString, int)));
1074 connect(installer, SIGNAL(logProgress(int, int)), logger, SLOT(setProgress(int, int)));
1075 connect(installer, SIGNAL(done(bool)), logger, SLOT(setFinished()));
1076 connect(logger, SIGNAL(aborted()), installer, SLOT(abort()));
1077 installer->install();
1081 void RbUtilQt::installPortable(void)
1083 if(QMessageBox::question(this, tr("Confirm installation"),
1084 tr("Do you really want to install Rockbox Utility to your player? "
1085 "After installation you can run it from the players hard drive."),
1086 QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes)
1087 return;
1089 ProgressLoggerGui* logger = new ProgressLoggerGui(this);
1090 logger->setProgressMax(0);
1091 logger->setProgressValue(0);
1092 logger->show();
1093 logger->addItem(tr("Installing Rockbox Utility"), LOGINFO);
1095 // check mountpoint
1096 if(!QFileInfo(RbSettings::value(RbSettings::Mountpoint).toString()).isDir()) {
1097 logger->addItem(tr("Mount point is wrong!"),LOGERROR);
1098 logger->setFinished();
1099 return;
1102 // remove old files first.
1103 QFile::remove(RbSettings::value(RbSettings::Mountpoint).toString()
1104 + "/RockboxUtility.exe");
1105 QFile::remove(RbSettings::value(RbSettings::Mountpoint).toString()
1106 + "/RockboxUtility.ini");
1107 // copy currently running binary and currently used settings file
1108 if(!QFile::copy(qApp->applicationFilePath(),
1109 RbSettings::value(RbSettings::Mountpoint).toString()
1110 + "/RockboxUtility.exe")) {
1111 logger->addItem(tr("Error installing Rockbox Utility"), LOGERROR);
1112 logger->setFinished();
1113 return;
1115 logger->addItem(tr("Installing user configuration"), LOGINFO);
1116 if(!QFile::copy(RbSettings::userSettingFilename(),
1117 RbSettings::value(RbSettings::Mountpoint).toString()
1118 + "/RockboxUtility.ini")) {
1119 logger->addItem(tr("Error installing user configuration"), LOGERROR);
1120 logger->setFinished();
1121 return;
1123 logger->addItem(tr("Successfully installed Rockbox Utility."), LOGOK);
1124 logger->setFinished();
1125 logger->setProgressMax(1);
1126 logger->setProgressValue(1);
1131 void RbUtilQt::updateInfo()
1133 qDebug() << "[RbUtil] updating server info";
1135 QSettings log(RbSettings::value(RbSettings::Mountpoint).toString()
1136 + "/.rockbox/rbutil.log", QSettings::IniFormat, this);
1137 QStringList groups = log.childGroups();
1138 QList<QTreeWidgetItem *> items;
1139 QTreeWidgetItem *w, *w2;
1140 QString min, max;
1141 int olditems = 0;
1143 // remove old list entries (if any)
1144 int l = ui.treeInfo->topLevelItemCount();
1145 while(l--) {
1146 QTreeWidgetItem *m;
1147 m = ui.treeInfo->takeTopLevelItem(l);
1148 // delete childs (single level deep, no recursion here)
1149 int n = m->childCount();
1150 while(n--)
1151 delete m->child(n);
1153 // get and populate new items
1154 for(int a = 0; a < groups.size(); a++) {
1155 log.beginGroup(groups.at(a));
1156 QStringList keys = log.allKeys();
1157 w = new QTreeWidgetItem;
1158 w->setFlags(Qt::ItemIsEnabled);
1159 w->setText(0, groups.at(a));
1160 items.append(w);
1161 // get minimum and maximum version information so we can hilight old files
1162 min = max = log.value(keys.at(0)).toString();
1163 for(int b = 0; b < keys.size(); b++) {
1164 if(log.value(keys.at(b)).toString() > max)
1165 max = log.value(keys.at(b)).toString();
1166 if(log.value(keys.at(b)).toString() < min)
1167 min = log.value(keys.at(b)).toString();
1170 for(int b = 0; b < keys.size(); b++) {
1171 QString file;
1172 file = RbSettings::value(RbSettings::Mountpoint).toString() + "/" + keys.at(b);
1173 if(QFileInfo(file).isDir())
1174 continue;
1175 w2 = new QTreeWidgetItem(w, QStringList() << "/"
1176 + keys.at(b) << log.value(keys.at(b)).toString());
1177 if(log.value(keys.at(b)).toString() != max) {
1178 w2->setForeground(0, QBrush(QColor(255, 0, 0)));
1179 w2->setForeground(1, QBrush(QColor(255, 0, 0)));
1180 olditems++;
1182 items.append(w2);
1184 log.endGroup();
1185 if(min != max)
1186 w->setData(1, Qt::DisplayRole, QString("%1 / %2").arg(min, max));
1187 else
1188 w->setData(1, Qt::DisplayRole, max);
1190 ui.treeInfo->insertTopLevelItems(0, items);
1191 ui.treeInfo->resizeColumnToContents(0);
1195 QUrl RbUtilQt::proxy()
1197 if(RbSettings::value(RbSettings::ProxyType) == "manual")
1198 return QUrl(RbSettings::value(RbSettings::Proxy).toString());
1199 else if(RbSettings::value(RbSettings::ProxyType) == "system")
1200 return System::systemProxy();
1201 return QUrl("");
1205 bool RbUtilQt::chkConfig(bool warn)
1207 bool error = false;
1208 if(RbSettings::value(RbSettings::Platform).toString().isEmpty()
1209 || RbSettings::value(RbSettings::Mountpoint).toString().isEmpty()
1210 || !QFileInfo(RbSettings::value(RbSettings::Mountpoint).toString()).isWritable()) {
1211 error = true;
1213 if(warn) QMessageBox::critical(this, tr("Configuration error"),
1214 tr("Your configuration is invalid. Please go to the configuration "
1215 "dialog and make sure the selected values are correct."));
1217 return error;