Fix cache path selection on Windows only allowing to select drives (FS#10013 by Yoshi...
[kugel-rb/myfork.git] / rbutil / rbutilqt / configure.cpp
blob3271818af41748db628c85bae3655b46ec59dc22
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 "configure.h"
24 #include "autodetection.h"
25 #include "ui_configurefrm.h"
26 #include "browsedirtree.h"
27 #include "encoders.h"
28 #include "tts.h"
29 #include "detect.h"
31 #include <stdio.h>
32 #if defined(Q_OS_WIN32)
33 #if defined(UNICODE)
34 #define _UNICODE
35 #endif
36 #include <tchar.h>
37 #include <windows.h>
38 #endif
40 #define DEFAULT_LANG "English (en)"
41 #define DEFAULT_LANG_CODE "en"
43 Config::Config(QWidget *parent,int index) : QDialog(parent)
45 programPath = qApp->applicationDirPath() + "/";
46 ui.setupUi(this);
47 ui.tabConfiguration->setCurrentIndex(index);
48 ui.radioManualProxy->setChecked(true);
49 QRegExpValidator *proxyValidator = new QRegExpValidator(this);
50 QRegExp validate("[0-9]*");
51 proxyValidator->setRegExp(validate);
52 ui.proxyPort->setValidator(proxyValidator);
53 #if !defined(Q_OS_LINUX) && !defined(Q_OS_WIN32)
54 ui.radioSystemProxy->setEnabled(false); // not on macox for now
55 #endif
56 // build language list and sort alphabetically
57 QStringList langs = findLanguageFiles();
58 for(int i = 0; i < langs.size(); ++i)
59 lang.insert(languageName(langs.at(i))
60 + QString(" (%1)").arg(langs.at(i)), langs.at(i));
61 lang.insert(DEFAULT_LANG, DEFAULT_LANG_CODE);
62 QMap<QString, QString>::const_iterator i = lang.constBegin();
63 while (i != lang.constEnd()) {
64 ui.listLanguages->addItem(i.key());
65 i++;
67 ui.listLanguages->setSelectionMode(QAbstractItemView::SingleSelection);
68 ui.proxyPass->setEchoMode(QLineEdit::Password);
69 ui.treeDevices->setAlternatingRowColors(true);
70 ui.listLanguages->setAlternatingRowColors(true);
72 this->setModal(true);
74 connect(ui.buttonOk, SIGNAL(clicked()), this, SLOT(accept()));
75 connect(ui.buttonCancel, SIGNAL(clicked()), this, SLOT(abort()));
76 connect(ui.radioNoProxy, SIGNAL(toggled(bool)), this, SLOT(setNoProxy(bool)));
77 connect(ui.radioSystemProxy, SIGNAL(toggled(bool)), this, SLOT(setSystemProxy(bool)));
78 connect(ui.browseMountPoint, SIGNAL(clicked()), this, SLOT(browseFolder()));
79 connect(ui.buttonAutodetect,SIGNAL(clicked()),this,SLOT(autodetect()));
80 connect(ui.buttonCacheBrowse, SIGNAL(clicked()), this, SLOT(browseCache()));
81 connect(ui.buttonCacheClear, SIGNAL(clicked()), this, SLOT(cacheClear()));
82 connect(ui.configTts, SIGNAL(clicked()), this, SLOT(configTts()));
83 connect(ui.configEncoder, SIGNAL(clicked()), this, SLOT(configEnc()));
84 connect(ui.comboTts, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTtsState(int)));
85 connect(ui.treeDevices, SIGNAL(itemSelectionChanged()), this, SLOT(updateEncState()));
91 void Config::accept()
93 qDebug() << "Config::accept()";
94 QString errormsg = tr("The following errors occurred:") + "<ul>";
95 bool error = false;
97 // proxy: save entered proxy values, not displayed.
98 if(ui.radioManualProxy->isChecked()) {
99 proxy.setScheme("http");
100 proxy.setUserName(ui.proxyUser->text());
101 proxy.setPassword(ui.proxyPass->text());
102 proxy.setHost(ui.proxyHost->text());
103 proxy.setPort(ui.proxyPort->text().toInt());
106 settings->setProxy(proxy.toString());
107 qDebug() << "new proxy:" << proxy;
108 // proxy type
109 QString proxyType;
110 if(ui.radioNoProxy->isChecked()) proxyType = "none";
111 else if(ui.radioSystemProxy->isChecked()) proxyType = "system";
112 else proxyType = "manual";
113 settings->setProxyType(proxyType);
115 // language
116 if(settings->curLang() != language && !language.isEmpty()) {
117 QMessageBox::information(this, tr("Language changed"),
118 tr("You need to restart the application for the changed language to take effect."));
119 settings->setLang(language);
122 // mountpoint
123 QString mp = ui.mountPoint->text();
124 if(mp.isEmpty()) {
125 errormsg += "<li>" + tr("No mountpoint given") + "</li>";
126 error = true;
128 else if(!QFileInfo(mp).exists()) {
129 errormsg += "<li>" + tr("Mountpoint does not exist") + "</li>";
130 error = true;
132 else if(!QFileInfo(mp).isDir()) {
133 errormsg += "<li>" + tr("Mountpoint is not a directory.") + "</li>";
134 error = true;
136 else if(!QFileInfo(mp).isWritable()) {
137 errormsg += "<li>" + tr("Mountpoint is not writeable") + "</li>";
138 error = true;
140 else {
141 settings->setMountpoint(QDir::fromNativeSeparators(mp));
144 // platform
145 QString nplat;
146 if(ui.treeDevices->selectedItems().size() != 0) {
147 nplat = ui.treeDevices->selectedItems().at(0)->data(0, Qt::UserRole).toString();
148 settings->setCurPlatform(nplat);
150 else {
151 errormsg += "<li>" + tr("No player selected") + "</li>";
152 error = true;
155 // cache settings
156 if(QFileInfo(ui.cachePath->text()).isDir()) {
157 if(!QFileInfo(ui.cachePath->text()).isWritable()) {
158 errormsg += "<li>" + tr("Cache path not writeable. Leave path empty "
159 "to default to systems temporary path.") + "</li>";
160 error = true;
162 else
163 settings->setCachePath(ui.cachePath->text());
165 else // default to system temp path
166 settings->setCachePath(QDir::tempPath());
167 settings->setCacheDisable(ui.cacheDisable->isChecked());
168 settings->setCacheOffline(ui.cacheOfflineMode->isChecked());
170 // tts settings
171 int i = ui.comboTts->currentIndex();
172 settings->setCurTTS(ui.comboTts->itemData(i).toString());
174 settings->setCurVersion(PUREVERSION);
176 errormsg += "</ul>";
177 errormsg += tr("You need to fix the above errors before you can continue.");
179 if(error) {
180 QMessageBox::critical(this, tr("Configuration error"), errormsg);
182 else {
183 // sync settings
184 settings->sync();
185 this->close();
186 emit settingsUpdated();
191 void Config::abort()
193 qDebug() << "Config::abort()";
194 this->close();
197 void Config::setSettings(RbSettings* sett)
199 settings = sett;
201 setUserSettings();
202 setDevices();
205 void Config::setUserSettings()
207 // set proxy
208 proxy = settings->proxy();
210 if(proxy.port() > 0)
211 ui.proxyPort->setText(QString("%1").arg(proxy.port()));
212 else ui.proxyPort->setText("");
213 ui.proxyHost->setText(proxy.host());
214 ui.proxyUser->setText(proxy.userName());
215 ui.proxyPass->setText(proxy.password());
217 QString proxyType = settings->proxyType();
218 if(proxyType == "manual") ui.radioManualProxy->setChecked(true);
219 else if(proxyType == "system") ui.radioSystemProxy->setChecked(true);
220 else ui.radioNoProxy->setChecked(true);
222 // set language selection
223 QList<QListWidgetItem*> a;
224 QString b;
225 // find key for lang value
226 QMap<QString, QString>::const_iterator i = lang.constBegin();
227 while (i != lang.constEnd()) {
228 if(i.value() == settings->curLang()) {
229 b = i.key();
230 break;
232 else if(settings->curLang().startsWith(i.value(), Qt::CaseInsensitive)) {
233 // check if there is a base language (en -> en_US, etc.)
234 b = i.key();
235 break;
237 i++;
239 a = ui.listLanguages->findItems(b, Qt::MatchExactly);
240 if(a.size() > 0)
241 ui.listLanguages->setCurrentItem(a.at(0));
242 // don't connect before language list has been set up to prevent
243 // triggering the signal by selecting the saved language.
244 connect(ui.listLanguages, SIGNAL(itemSelectionChanged()), this, SLOT(updateLanguage()));
246 // devices tab
247 ui.mountPoint->setText(QDir::toNativeSeparators(settings->mountpoint()));
249 // cache tab
250 if(!QFileInfo(settings->cachePath()).isDir())
251 settings->setCachePath(QDir::tempPath());
252 ui.cachePath->setText(QDir::toNativeSeparators(settings->cachePath()));
253 ui.cacheDisable->setChecked(settings->cacheDisabled());
254 ui.cacheOfflineMode->setChecked(settings->cacheOffline());
255 updateCacheInfo(settings->cachePath());
259 void Config::updateCacheInfo(QString path)
261 QList<QFileInfo> fs;
262 fs = QDir(path + "/rbutil-cache/").entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
263 qint64 sz = 0;
264 for(int i = 0; i < fs.size(); i++) {
265 sz += fs.at(i).size();
266 qDebug() << fs.at(i).fileName() << fs.at(i).size();
268 ui.cacheSize->setText(tr("Current cache size is %L1 kiB.")
269 .arg(sz/1024));
273 void Config::setDevices()
276 // setup devices table
277 qDebug() << "Config::setDevices()";
279 QStringList platformList = settings->allPlatforms();
281 QMap <QString, QString> manuf;
282 QMap <QString, QString> devcs;
283 for(int it = 0; it < platformList.size(); it++)
285 QString curname = settings->name(platformList.at(it));
286 QString curbrand = settings->brand(platformList.at(it));
287 manuf.insertMulti(curbrand, platformList.at(it));
288 devcs.insert(platformList.at(it), curname);
291 QString platform;
292 platform = devcs.value(settings->curPlatform());
294 // set up devices table
295 ui.treeDevices->header()->hide();
296 ui.treeDevices->expandAll();
297 ui.treeDevices->setColumnCount(1);
298 QList<QTreeWidgetItem *> items;
300 // get manufacturers
301 QStringList brands = manuf.uniqueKeys();
302 QTreeWidgetItem *w;
303 QTreeWidgetItem *w2;
304 QTreeWidgetItem *w3 = 0;
305 for(int c = 0; c < brands.size(); c++) {
306 qDebug() << brands.at(c);
307 w = new QTreeWidgetItem();
308 w->setFlags(Qt::ItemIsEnabled);
309 w->setText(0, brands.at(c));
310 items.append(w);
312 // go through platforms again for sake of order
313 for(int it = 0; it < platformList.size(); it++) {
315 QString curname = settings->name(platformList.at(it));
316 QString curbrand = settings->brand(platformList.at(it));
318 if(curbrand != brands.at(c)) continue;
319 qDebug() << "adding:" << brands.at(c) << curname;
320 w2 = new QTreeWidgetItem(w, QStringList(curname));
321 w2->setData(0, Qt::UserRole, platformList.at(it));
323 if(platform.contains(curname)) {
324 w2->setSelected(true);
325 w->setExpanded(true);
326 w3 = w2; // save pointer to hilight old selection
328 items.append(w2);
331 ui.treeDevices->insertTopLevelItems(0, items);
332 if(w3 != 0)
333 ui.treeDevices->setCurrentItem(w3); // hilight old selection
335 // tts / encoder tab
337 //encoders
338 updateEncState();
340 //tts
341 QStringList ttslist = TTSBase::getTTSList();
342 for(int a = 0; a < ttslist.size(); a++)
343 ui.comboTts->addItem(TTSBase::getTTSName(ttslist.at(a)), ttslist.at(a));
344 //update index of combobox
345 int index = ui.comboTts->findData(settings->curTTS());
346 if(index < 0) index = 0;
347 ui.comboTts->setCurrentIndex(index);
348 updateTtsState(index);
353 void Config::updateTtsState(int index)
355 QString ttsName = ui.comboTts->itemData(index).toString();
356 TTSBase* tts = TTSBase::getTTS(ttsName);
357 tts->setCfg(settings);
359 if(tts->configOk())
361 ui.configTTSstatus->setText(tr("Configuration OK"));
362 ui.configTTSstatusimg->setPixmap(QPixmap(QString::fromUtf8(":/icons/go-next.png")));
364 else
366 ui.configTTSstatus->setText(tr("Configuration INVALID"));
367 ui.configTTSstatusimg->setPixmap(QPixmap(QString::fromUtf8(":/icons/dialog-error.png")));
371 void Config::updateEncState()
373 // FIXME: this is a workaround to make the encoder follow the device selection
374 // even with the settings (and thus the device) being saved. Needs to be redone
375 // properly later by extending the settings object
376 if(ui.treeDevices->selectedItems().size() == 0)
377 return;
379 QString devname = ui.treeDevices->selectedItems().at(0)->data(0, Qt::UserRole).toString();
380 QString olddevice = settings->curPlatform();
381 settings->setCurPlatform(devname);
382 QString encoder = settings->curEncoder();
383 ui.encoderName->setText(EncBase::getEncoderName(settings->curEncoder()));
384 settings->setCurPlatform(olddevice);
386 EncBase* enc = EncBase::getEncoder(encoder);
387 enc->setCfg(settings);
389 if(enc->configOk())
391 ui.configEncstatus->setText(tr("Configuration OK"));
392 ui.configEncstatusimg->setPixmap(QPixmap(QString::fromUtf8(":/icons/go-next.png")));
394 else
396 ui.configEncstatus->setText(tr("Configuration INVALID"));
397 ui.configEncstatusimg->setPixmap(QPixmap(QString::fromUtf8(":/icons/dialog-error.png")));
401 void Config::setNoProxy(bool checked)
403 bool i = !checked;
404 ui.proxyPort->setEnabled(i);
405 ui.proxyHost->setEnabled(i);
406 ui.proxyUser->setEnabled(i);
407 ui.proxyPass->setEnabled(i);
411 void Config::setSystemProxy(bool checked)
413 bool i = !checked;
414 ui.proxyPort->setEnabled(i);
415 ui.proxyHost->setEnabled(i);
416 ui.proxyUser->setEnabled(i);
417 ui.proxyPass->setEnabled(i);
418 if(checked) {
419 // save values in input box
420 proxy.setScheme("http");
421 proxy.setUserName(ui.proxyUser->text());
422 proxy.setPassword(ui.proxyPass->text());
423 proxy.setHost(ui.proxyHost->text());
424 proxy.setPort(ui.proxyPort->text().toInt());
425 // show system values in input box
426 QUrl envproxy = Detect::systemProxy();
428 ui.proxyHost->setText(envproxy.host());
430 ui.proxyPort->setText(QString("%1").arg(envproxy.port()));
431 ui.proxyUser->setText(envproxy.userName());
432 ui.proxyPass->setText(envproxy.password());
435 else {
436 ui.proxyHost->setText(proxy.host());
437 if(proxy.port() > 0)
438 ui.proxyPort->setText(QString("%1").arg(proxy.port()));
439 else ui.proxyPort->setText("");
440 ui.proxyUser->setText(proxy.userName());
441 ui.proxyPass->setText(proxy.password());
447 QStringList Config::findLanguageFiles()
449 QDir dir(programPath);
450 QStringList fileNames;
451 QStringList langs;
452 fileNames = dir.entryList(QStringList("*.qm"), QDir::Files, QDir::Name);
454 QDir resDir(":/lang");
455 fileNames += resDir.entryList(QStringList("*.qm"), QDir::Files, QDir::Name);
457 QRegExp exp("^rbutil_(.*)\\.qm");
458 for(int i = 0; i < fileNames.size(); i++) {
459 QString a = fileNames.at(i);
460 a.replace(exp, "\\1");
461 langs.append(a);
463 langs.sort();
464 qDebug() << "Config::findLanguageFiles()" << langs;
466 return langs;
470 QString Config::languageName(const QString &qmFile)
472 QTranslator translator;
474 QString file = "rbutil_" + qmFile;
475 if(!translator.load(file, programPath))
476 translator.load(file, ":/lang");
478 return translator.translate("Configure", "English",
479 "This is the localized language name, i.e. your language.");
483 void Config::updateLanguage()
485 qDebug() << "updateLanguage()";
486 QList<QListWidgetItem*> a = ui.listLanguages->selectedItems();
487 if(a.size() > 0)
488 language = lang.value(a.at(0)->text());
489 qDebug() << language;
493 void Config::browseFolder()
495 browser = new BrowseDirtree(this,tr("Select your device"));
496 #if defined(Q_OS_LINUX) || defined(Q_OS_MACX)
497 browser->setFilter(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
498 #elif defined(Q_OS_WIN32)
499 browser->setFilter(QDir::Drives);
500 #endif
501 #if defined(Q_OS_MACX)
502 browser->setRoot("/Volumes");
503 #elif defined(Q_OS_LINUX)
504 browser->setDir("/media");
505 #endif
506 if( ui.mountPoint->text() != "" )
508 browser->setDir(ui.mountPoint->text());
510 browser->show();
511 connect(browser, SIGNAL(itemChanged(QString)), this, SLOT(setMountpoint(QString)));
515 void Config::browseCache()
517 cbrowser = new BrowseDirtree(this);
518 #if defined(Q_OS_LINUX) || defined(Q_OS_MACX)
519 cbrowser->setFilter(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
520 #elif defined(Q_OS_WIN32)
521 cbrowser->setFilter(QDir::Drives | QDir::AllDirs | QDir::NoDotAndDotDot);
522 #endif
523 cbrowser->setDir(ui.cachePath->text());
524 connect(cbrowser, SIGNAL(itemChanged(QString)), this, SLOT(setCache(QString)));
525 cbrowser->show();
529 void Config::setMountpoint(QString m)
531 ui.mountPoint->setText(m);
535 void Config::setCache(QString c)
537 ui.cachePath->setText(c);
538 updateCacheInfo(c);
542 void Config::autodetect()
544 Autodetection detector(this);
545 detector.setSettings(settings);
546 // disable tree during detection as "working" feedback.
547 // TODO: replace the tree view with a splash screen during this time.
548 ui.treeDevices->setEnabled(false);
549 this->setCursor(Qt::WaitCursor);
550 QCoreApplication::processEvents();
552 if(detector.detect()) //let it detect
554 QString devicename = detector.getDevice();
555 // deexpand all items
556 for(int a = 0; a < ui.treeDevices->topLevelItemCount(); a++)
557 ui.treeDevices->topLevelItem(a)->setExpanded(false);
558 //deselect the selected item(s)
559 for(int a = 0; a < ui.treeDevices->selectedItems().size(); a++)
560 ui.treeDevices->selectedItems().at(a)->setSelected(false);
562 // find the new item
563 // enumerate all platform items
564 QList<QTreeWidgetItem*> itmList= ui.treeDevices->findItems("*",Qt::MatchWildcard);
565 for(int i=0; i< itmList.size();i++)
567 //enumerate device items
568 for(int j=0;j < itmList.at(i)->childCount();j++)
570 QString data = itmList.at(i)->child(j)->data(0, Qt::UserRole).toString();
572 if(devicename == data) // item found
574 itmList.at(i)->child(j)->setSelected(true); //select the item
575 itmList.at(i)->setExpanded(true); //expand the platform item
576 //ui.treeDevices->indexOfTopLevelItem(itmList.at(i)->child(j));
577 break;
581 this->unsetCursor();
583 if(!detector.errdev().isEmpty()) {
584 QString text;
585 if(detector.errdev() == "sansae200")
586 text = tr("Sansa e200 in MTP mode found!\n"
587 "You need to change your player to MSC mode for installation. ");
588 if(detector.errdev() == "h10")
589 text = tr("H10 20GB in MTP mode found!\n"
590 "You need to change your player to UMS mode for installation. ");
591 text += tr("Unless you changed this installation will fail!");
593 QMessageBox::critical(this, tr("Fatal error"), text, QMessageBox::Ok);
594 return;
596 if(!detector.incompatdev().isEmpty()) {
597 QString text;
598 // we need to set the platform here to get the brand from the
599 // settings object
600 settings->setCurPlatform(detector.incompatdev());
601 text = tr("Detected an unsupported %1 player variant. Sorry, "
602 "Rockbox doesn't run on your player.").arg(settings->curBrand());
604 QMessageBox::critical(this, tr("Fatal error: incompatible player found"),
605 text, QMessageBox::Ok);
606 return;
609 if(detector.getMountPoint() != "" )
611 ui.mountPoint->setText(QDir::toNativeSeparators(detector.getMountPoint()));
613 else
615 QMessageBox::warning(this, tr("Autodetection"),
616 tr("Could not detect a Mountpoint.\n"
617 "Select your Mountpoint manually."),
618 QMessageBox::Ok ,QMessageBox::Ok);
621 else
623 this->unsetCursor();
624 QMessageBox::warning(this, tr("Autodetection"),
625 tr("Could not detect a device.\n"
626 "Select your device and Mountpoint manually."),
627 QMessageBox::Ok ,QMessageBox::Ok);
630 ui.treeDevices->setEnabled(true);
633 void Config::cacheClear()
635 if(QMessageBox::critical(this, tr("Really delete cache?"),
636 tr("Do you really want to delete the cache? "
637 "Make absolutely sure this setting is correct as it will "
638 "remove <b>all</b> files in this folder!").arg(ui.cachePath->text()),
639 QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes)
640 return;
642 QString cache = ui.cachePath->text() + "/rbutil-cache/";
643 if(!QFileInfo(cache).isDir()) {
644 QMessageBox::critical(this, tr("Path wrong!"),
645 tr("The cache path is invalid. Aborting."), QMessageBox::Ok);
646 return;
648 QDir dir(cache);
649 QStringList fn;
650 fn = dir.entryList(QStringList("*"), QDir::Files, QDir::Name);
651 qDebug() << fn;
653 for(int i = 0; i < fn.size(); i++) {
654 QString f = cache + fn.at(i);
655 QFile::remove(f);
656 qDebug() << "removed:" << f;
658 updateCacheInfo(settings->cachePath());
662 void Config::configTts()
664 int index = ui.comboTts->currentIndex();
665 TTSBase* tts = TTSBase::getTTS(ui.comboTts->itemData(index).toString());
667 tts->setCfg(settings);
668 tts->showCfg();
669 updateTtsState(ui.comboTts->currentIndex());
673 void Config::configEnc()
675 EncBase* enc = EncBase::getEncoder(settings->curEncoder());
677 enc->setCfg(settings);
678 enc->showCfg();
679 updateEncState();