diff options
Diffstat (limited to 'utils/rbutilqt/configure.cpp')
-rw-r--r-- | utils/rbutilqt/configure.cpp | 984 |
1 files changed, 984 insertions, 0 deletions
diff --git a/utils/rbutilqt/configure.cpp b/utils/rbutilqt/configure.cpp new file mode 100644 index 0000000000..14080a552c --- /dev/null +++ b/utils/rbutilqt/configure.cpp | |||
@@ -0,0 +1,984 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2007 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 <QMessageBox> | ||
20 | #include <QProgressDialog> | ||
21 | #include <QFileDialog> | ||
22 | #include <QUrl> | ||
23 | #ifdef QT_MULTIMEDIA_LIB | ||
24 | #include <QSound> | ||
25 | #endif | ||
26 | |||
27 | #include "version.h" | ||
28 | #include "configure.h" | ||
29 | #include "autodetection.h" | ||
30 | #include "ui_configurefrm.h" | ||
31 | #include "encoderbase.h" | ||
32 | #include "ttsbase.h" | ||
33 | #include "system.h" | ||
34 | #include "encttscfggui.h" | ||
35 | #include "rbsettings.h" | ||
36 | #include "playerbuildinfo.h" | ||
37 | #include "utils.h" | ||
38 | #include "comboboxviewdelegate.h" | ||
39 | #if defined(Q_OS_WIN32) | ||
40 | #if defined(UNICODE) | ||
41 | #define _UNICODE | ||
42 | #endif | ||
43 | #include <tchar.h> | ||
44 | #include <windows.h> | ||
45 | #endif | ||
46 | #include "rbutilqt.h" | ||
47 | |||
48 | #include "systrace.h" | ||
49 | #include "Logger.h" | ||
50 | |||
51 | #define DEFAULT_LANG "English (en)" | ||
52 | #define DEFAULT_LANG_CODE "en" | ||
53 | |||
54 | Config::Config(QWidget *parent,int index) : QDialog(parent) | ||
55 | { | ||
56 | programPath = qApp->applicationDirPath() + "/"; | ||
57 | ui.setupUi(this); | ||
58 | ui.tabConfiguration->setCurrentIndex(index); | ||
59 | ui.radioManualProxy->setChecked(true); | ||
60 | |||
61 | // build language list and sort alphabetically | ||
62 | QStringList langs = findLanguageFiles(); | ||
63 | for(int i = 0; i < langs.size(); ++i) | ||
64 | lang.insert(languageName(langs.at(i)) | ||
65 | + QString(" (%1)").arg(langs.at(i)), langs.at(i)); | ||
66 | lang.insert(DEFAULT_LANG, DEFAULT_LANG_CODE); | ||
67 | QMap<QString, QString>::const_iterator i = lang.constBegin(); | ||
68 | while (i != lang.constEnd()) { | ||
69 | ui.listLanguages->addItem(i.key()); | ||
70 | i++; | ||
71 | } | ||
72 | |||
73 | ComboBoxViewDelegate *delegate = new ComboBoxViewDelegate(this); | ||
74 | ui.mountPoint->setItemDelegate(delegate); | ||
75 | #if !defined(DBG) | ||
76 | ui.mountPoint->setEditable(false); | ||
77 | #endif | ||
78 | |||
79 | ui.listLanguages->setSelectionMode(QAbstractItemView::SingleSelection); | ||
80 | ui.proxyPass->setEchoMode(QLineEdit::Password); | ||
81 | ui.treeDevices->setAlternatingRowColors(true); | ||
82 | ui.listLanguages->setAlternatingRowColors(true); | ||
83 | |||
84 | /* Explicitly set some widgets to have left-to-right layout */ | ||
85 | ui.treeDevices->setLayoutDirection(Qt::LeftToRight); | ||
86 | ui.mountPoint->setLayoutDirection(Qt::LeftToRight); | ||
87 | ui.proxyHost->setLayoutDirection(Qt::LeftToRight); | ||
88 | ui.proxyPort->setLayoutDirection(Qt::LeftToRight); | ||
89 | ui.proxyUser->setLayoutDirection(Qt::LeftToRight); | ||
90 | ui.proxyPass->setLayoutDirection(Qt::LeftToRight); | ||
91 | ui.listLanguages->setLayoutDirection(Qt::LeftToRight); | ||
92 | ui.cachePath->setLayoutDirection(Qt::LeftToRight); | ||
93 | ui.comboTts->setLayoutDirection(Qt::LeftToRight); | ||
94 | |||
95 | this->setModal(true); | ||
96 | |||
97 | connect(ui.buttonOk, SIGNAL(clicked()), this, SLOT(accept())); | ||
98 | connect(ui.buttonCancel, SIGNAL(clicked()), this, SLOT(abort())); | ||
99 | connect(ui.radioNoProxy, SIGNAL(toggled(bool)), this, SLOT(setNoProxy(bool))); | ||
100 | connect(ui.radioSystemProxy, SIGNAL(toggled(bool)), this, SLOT(setSystemProxy(bool))); | ||
101 | connect(ui.refreshMountPoint, SIGNAL(clicked()), this, SLOT(refreshMountpoint())); | ||
102 | connect(ui.buttonAutodetect,SIGNAL(clicked()),this,SLOT(autodetect())); | ||
103 | connect(ui.buttonCacheBrowse, SIGNAL(clicked()), this, SLOT(browseCache())); | ||
104 | connect(ui.buttonCacheClear, SIGNAL(clicked()), this, SLOT(cacheClear())); | ||
105 | connect(ui.configTts, SIGNAL(clicked()), this, SLOT(configTts())); | ||
106 | connect(ui.configEncoder, SIGNAL(clicked()), this, SLOT(configEnc())); | ||
107 | connect(ui.comboTts, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTtsState(int))); | ||
108 | connect(ui.treeDevices, SIGNAL(itemSelectionChanged()), this, SLOT(updateEncState())); | ||
109 | connect(ui.testTTS,SIGNAL(clicked()),this,SLOT(testTts())); | ||
110 | connect(ui.showDisabled, SIGNAL(toggled(bool)), this, SLOT(showDisabled(bool))); | ||
111 | connect(ui.mountPoint, SIGNAL(editTextChanged(QString)), this, SLOT(updateMountpoint(QString))); | ||
112 | connect(ui.mountPoint, SIGNAL(currentIndexChanged(int)), this, SLOT(updateMountpoint(int))); | ||
113 | connect(ui.checkShowProxyPassword, SIGNAL(toggled(bool)), this, SLOT(showProxyPassword(bool))); | ||
114 | // delete this dialog after it finished automatically. | ||
115 | connect(this, SIGNAL(finished(int)), this, SLOT(deleteLater())); | ||
116 | |||
117 | setUserSettings(); | ||
118 | setDevices(); | ||
119 | } | ||
120 | |||
121 | |||
122 | void Config::accept() | ||
123 | { | ||
124 | LOG_INFO() << "checking configuration"; | ||
125 | QString errormsg = tr("The following errors occurred:") + "<ul>"; | ||
126 | bool error = false; | ||
127 | |||
128 | // proxy: save entered proxy values, not displayed. | ||
129 | if(ui.radioManualProxy->isChecked()) { | ||
130 | proxy.setScheme("http"); | ||
131 | proxy.setUserName(ui.proxyUser->text()); | ||
132 | proxy.setPassword(ui.proxyPass->text()); | ||
133 | proxy.setHost(ui.proxyHost->text()); | ||
134 | proxy.setPort(ui.proxyPort->value()); | ||
135 | } | ||
136 | |||
137 | // Encode the password using base64 before storing it to the configuration | ||
138 | // file. | ||
139 | // There are two reasons for doing this: | ||
140 | // - QUrl::toEncoded() has problems with some characters like the colon and | ||
141 | // @. Those are not percent encoded, causing the string getting parsed | ||
142 | // wrongly when reading it back (see FS#12166). | ||
143 | // - The password is cleartext in the configuration file. | ||
144 | // While using base64 doesn't provide any real security either it's at | ||
145 | // least better than plaintext. | ||
146 | // Since this program is open source any fixed mechanism to obfuscate / | ||
147 | // encrypt the password isn't much help either since anyone interested in | ||
148 | // the password can look at the sources. The best way would be to | ||
149 | // eventually use host OS functionality to store the password. | ||
150 | QUrl p = proxy; | ||
151 | p.setPassword(proxy.password().toUtf8().toBase64()); | ||
152 | RbSettings::setValue(RbSettings::Proxy, p.toString()); | ||
153 | LOG_INFO() << "setting proxy to:" << proxy.toString(QUrl::RemovePassword); | ||
154 | // proxy type | ||
155 | QString proxyType; | ||
156 | if(ui.radioNoProxy->isChecked()) proxyType = "none"; | ||
157 | else if(ui.radioSystemProxy->isChecked()) proxyType = "system"; | ||
158 | else proxyType = "manual"; | ||
159 | RbSettings::setValue(RbSettings::ProxyType, proxyType); | ||
160 | |||
161 | RbSettings::setValue(RbSettings::Language, language); | ||
162 | |||
163 | // make sure mountpoint is read from dropdown box | ||
164 | if(mountpoint.isEmpty()) { | ||
165 | updateMountpoint(ui.mountPoint->currentIndex()); | ||
166 | } | ||
167 | |||
168 | // mountpoint | ||
169 | if(mountpoint.isEmpty()) { | ||
170 | errormsg += "<li>" + tr("No mountpoint given") + "</li>"; | ||
171 | error = true; | ||
172 | } | ||
173 | else if(!QFileInfo::exists(mountpoint)) { | ||
174 | errormsg += "<li>" + tr("Mountpoint does not exist") + "</li>"; | ||
175 | error = true; | ||
176 | } | ||
177 | else if(!QFileInfo(mountpoint).isDir()) { | ||
178 | errormsg += "<li>" + tr("Mountpoint is not a directory.") + "</li>"; | ||
179 | error = true; | ||
180 | } | ||
181 | else if(!QFileInfo(mountpoint).isWritable()) { | ||
182 | errormsg += "<li>" + tr("Mountpoint is not writeable") + "</li>"; | ||
183 | error = true; | ||
184 | } | ||
185 | else { | ||
186 | RbSettings::setValue(RbSettings::Mountpoint, | ||
187 | QDir::fromNativeSeparators(mountpoint)); | ||
188 | } | ||
189 | |||
190 | // platform | ||
191 | QString nplat; | ||
192 | if(ui.treeDevices->selectedItems().size() != 0) { | ||
193 | nplat = ui.treeDevices->selectedItems().at(0)->data(0, Qt::UserRole).toString(); | ||
194 | RbSettings::setValue(RbSettings::Platform, nplat); | ||
195 | } | ||
196 | else { | ||
197 | errormsg += "<li>" + tr("No player selected") + "</li>"; | ||
198 | error = true; | ||
199 | } | ||
200 | |||
201 | // cache settings | ||
202 | if(QFileInfo(ui.cachePath->text()).isDir()) { | ||
203 | if(!QFileInfo(ui.cachePath->text()).isWritable()) { | ||
204 | errormsg += "<li>" + tr("Cache path not writeable. Leave path empty " | ||
205 | "to default to systems temporary path.") + "</li>"; | ||
206 | error = true; | ||
207 | } | ||
208 | else | ||
209 | RbSettings::setValue(RbSettings::CachePath, ui.cachePath->text()); | ||
210 | } | ||
211 | else // default to system temp path | ||
212 | RbSettings::setValue(RbSettings::CachePath, QDir::tempPath()); | ||
213 | RbSettings::setValue(RbSettings::CacheDisabled, ui.cacheDisable->isChecked()); | ||
214 | |||
215 | // tts settings | ||
216 | RbSettings::setValue(RbSettings::UseTtsCorrections, ui.ttsCorrections->isChecked()); | ||
217 | int i = ui.comboTts->currentIndex(); | ||
218 | RbSettings::setValue(RbSettings::Tts, ui.comboTts->itemData(i).toString()); | ||
219 | |||
220 | RbSettings::setValue(RbSettings::RbutilVersion, PUREVERSION); | ||
221 | |||
222 | errormsg += "</ul>"; | ||
223 | errormsg += tr("You need to fix the above errors before you can continue."); | ||
224 | |||
225 | if(error) { | ||
226 | QMessageBox::critical(this, tr("Configuration error"), errormsg); | ||
227 | } | ||
228 | else { | ||
229 | // sync settings | ||
230 | RbSettings::sync(); | ||
231 | this->close(); | ||
232 | emit settingsUpdated(); | ||
233 | } | ||
234 | } | ||
235 | |||
236 | |||
237 | void Config::abort() | ||
238 | { | ||
239 | LOG_INFO() << "aborted."; | ||
240 | this->close(); | ||
241 | } | ||
242 | |||
243 | |||
244 | void Config::setUserSettings() | ||
245 | { | ||
246 | // set proxy | ||
247 | proxy.setUrl(RbSettings::value(RbSettings::Proxy).toString(), | ||
248 | QUrl::StrictMode); | ||
249 | // password is base64 encoded in configuration. | ||
250 | QByteArray pw = QByteArray::fromBase64(proxy.password().toUtf8()); | ||
251 | proxy.setPassword(pw); | ||
252 | |||
253 | ui.proxyPort->setValue(proxy.port()); | ||
254 | ui.proxyHost->setText(proxy.host()); | ||
255 | ui.proxyUser->setText(proxy.userName()); | ||
256 | ui.proxyPass->setText(proxy.password()); | ||
257 | |||
258 | QString proxyType = RbSettings::value(RbSettings::ProxyType).toString(); | ||
259 | if(proxyType == "manual") ui.radioManualProxy->setChecked(true); | ||
260 | else if(proxyType == "system") ui.radioSystemProxy->setChecked(true); | ||
261 | else ui.radioNoProxy->setChecked(true); | ||
262 | |||
263 | // set language selection | ||
264 | QList<QListWidgetItem*> a; | ||
265 | QString b; | ||
266 | // find key for lang value | ||
267 | QMap<QString, QString>::const_iterator i = lang.constBegin(); | ||
268 | QString l = RbSettings::value(RbSettings::Language).toString(); | ||
269 | if(l.isEmpty()) | ||
270 | l = QLocale::system().name(); | ||
271 | while (i != lang.constEnd()) { | ||
272 | if(i.value() == l) { | ||
273 | b = i.key(); | ||
274 | break; | ||
275 | } | ||
276 | else if(l.startsWith(i.value(), Qt::CaseInsensitive)) { | ||
277 | // check if there is a base language (en -> en_US, etc.) | ||
278 | b = i.key(); | ||
279 | break; | ||
280 | } | ||
281 | i++; | ||
282 | } | ||
283 | a = ui.listLanguages->findItems(b, Qt::MatchExactly); | ||
284 | if(a.size() > 0) | ||
285 | ui.listLanguages->setCurrentItem(a.at(0)); | ||
286 | // don't connect before language list has been set up to prevent | ||
287 | // triggering the signal by selecting the saved language. | ||
288 | connect(ui.listLanguages, SIGNAL(itemSelectionChanged()), this, SLOT(updateLanguage())); | ||
289 | |||
290 | // devices tab | ||
291 | refreshMountpoint(); | ||
292 | mountpoint = QDir::toNativeSeparators(RbSettings::value(RbSettings::Mountpoint).toString()); | ||
293 | setMountpoint(mountpoint); | ||
294 | |||
295 | // cache tab | ||
296 | if(!QFileInfo(RbSettings::value(RbSettings::CachePath).toString()).isDir()) | ||
297 | RbSettings::setValue(RbSettings::CachePath, QDir::tempPath()); | ||
298 | ui.cachePath->setText(QDir::toNativeSeparators(RbSettings::value(RbSettings::CachePath).toString())); | ||
299 | ui.cacheDisable->setChecked(RbSettings::value(RbSettings::CacheDisabled).toBool()); | ||
300 | updateCacheInfo(RbSettings::value(RbSettings::CachePath).toString()); | ||
301 | |||
302 | // TTS tab | ||
303 | ui.ttsCorrections->setChecked(RbSettings::value(RbSettings::UseTtsCorrections).toBool()); | ||
304 | } | ||
305 | |||
306 | |||
307 | void Config::updateCacheInfo(QString path) | ||
308 | { | ||
309 | qint64 sz = Utils::recursiveFolderSize(path + "/rbutil-cache"); | ||
310 | ui.cacheSize->setText(tr("Current cache size is %L1 kiB.") | ||
311 | .arg(sz/1024)); | ||
312 | } | ||
313 | |||
314 | |||
315 | void Config::showProxyPassword(bool show) | ||
316 | { | ||
317 | if(show) | ||
318 | ui.proxyPass->setEchoMode(QLineEdit::Normal); | ||
319 | else | ||
320 | ui.proxyPass->setEchoMode(QLineEdit::Password); | ||
321 | } | ||
322 | |||
323 | |||
324 | void Config::showDisabled(bool show) | ||
325 | { | ||
326 | LOG_INFO() << "disabled targets shown:" << show; | ||
327 | if(show) | ||
328 | QMessageBox::warning(this, tr("Showing disabled targets"), | ||
329 | tr("You just enabled showing targets that are marked disabled. " | ||
330 | "Disabled targets are not recommended to end users. Please " | ||
331 | "use this option only if you know what you are doing.")); | ||
332 | setDevices(); | ||
333 | |||
334 | } | ||
335 | |||
336 | |||
337 | void Config::setDevices() | ||
338 | { | ||
339 | |||
340 | // setup devices table | ||
341 | LOG_INFO() << "setting up devices list"; | ||
342 | |||
343 | QStringList targets; | ||
344 | if(ui.showDisabled->isChecked()) | ||
345 | targets = PlayerBuildInfo::instance()->value( | ||
346 | PlayerBuildInfo::TargetNamesAll).toStringList(); | ||
347 | else | ||
348 | targets = PlayerBuildInfo::instance()->value( | ||
349 | PlayerBuildInfo::TargetNamesEnabled).toStringList(); | ||
350 | |||
351 | QMultiMap <QString, QString> manuf; | ||
352 | for(int it = 0; it < targets.size(); it++) | ||
353 | { | ||
354 | QString curbrand = PlayerBuildInfo::instance()->value( | ||
355 | PlayerBuildInfo::Brand, targets.at(it)).toString(); | ||
356 | manuf.insert(curbrand, targets.at(it)); | ||
357 | } | ||
358 | |||
359 | // set up devices table | ||
360 | ui.treeDevices->header()->hide(); | ||
361 | ui.treeDevices->expandAll(); | ||
362 | ui.treeDevices->setColumnCount(1); | ||
363 | QList<QTreeWidgetItem *> items; | ||
364 | |||
365 | // get manufacturers | ||
366 | QStringList brands = manuf.uniqueKeys(); | ||
367 | QTreeWidgetItem *w; | ||
368 | QTreeWidgetItem *w2; | ||
369 | QTreeWidgetItem *w3 = nullptr; | ||
370 | |||
371 | QString selected = RbSettings::value(RbSettings::Platform).toString(); | ||
372 | for(int c = 0; c < brands.size(); c++) { | ||
373 | w = new QTreeWidgetItem(); | ||
374 | w->setFlags(Qt::ItemIsEnabled); | ||
375 | w->setText(0, brands.at(c)); | ||
376 | items.append(w); | ||
377 | // go through platforms and add all players matching the current brand | ||
378 | for(int it = 0; it < targets.size(); it++) { | ||
379 | // skip if not current brand | ||
380 | if(!manuf.values(brands.at(c)).contains(targets.at(it))) | ||
381 | continue; | ||
382 | // construct display name | ||
383 | QString curname = QString("%1 (%2)").arg( | ||
384 | PlayerBuildInfo::instance()->value(PlayerBuildInfo::DisplayName, | ||
385 | targets.at(it)).toString(), | ||
386 | PlayerBuildInfo::instance()->statusAsString(targets.at(it))); | ||
387 | LOG_INFO() << "add supported device:" << brands.at(c) << curname; | ||
388 | w2 = new QTreeWidgetItem(w, QStringList(curname)); | ||
389 | w2->setData(0, Qt::UserRole, targets.at(it)); | ||
390 | |||
391 | if(targets.at(it) == selected) { | ||
392 | w2->setSelected(true); | ||
393 | w->setExpanded(true); | ||
394 | w3 = w2; // save pointer to hilight old selection | ||
395 | } | ||
396 | items.append(w2); | ||
397 | } | ||
398 | } | ||
399 | // remove any old items in list | ||
400 | QTreeWidgetItem* widgetitem; | ||
401 | do { | ||
402 | widgetitem = ui.treeDevices->takeTopLevelItem(0); | ||
403 | delete widgetitem; | ||
404 | } | ||
405 | while(widgetitem); | ||
406 | // add new items | ||
407 | ui.treeDevices->insertTopLevelItems(0, items); | ||
408 | if(w3 != nullptr) { | ||
409 | ui.treeDevices->setCurrentItem(w3); // hilight old selection | ||
410 | ui.treeDevices->scrollToItem(w3); | ||
411 | } | ||
412 | |||
413 | // tts / encoder tab | ||
414 | |||
415 | //encoders | ||
416 | updateEncState(); | ||
417 | |||
418 | //tts | ||
419 | QStringList ttslist = TTSBase::getTTSList(); | ||
420 | for(int a = 0; a < ttslist.size(); a++) | ||
421 | ui.comboTts->addItem(TTSBase::getTTSName(ttslist.at(a)), ttslist.at(a)); | ||
422 | //update index of combobox | ||
423 | int index = ui.comboTts->findData(RbSettings::value(RbSettings::Tts).toString()); | ||
424 | if(index < 0) index = 0; | ||
425 | ui.comboTts->setCurrentIndex(index); | ||
426 | updateTtsState(index); | ||
427 | |||
428 | } | ||
429 | |||
430 | |||
431 | void Config::updateTtsState(int index) | ||
432 | { | ||
433 | QString ttsName = ui.comboTts->itemData(index).toString(); | ||
434 | TTSBase* tts = TTSBase::getTTS(this,ttsName); | ||
435 | |||
436 | if(!tts) | ||
437 | { | ||
438 | QMessageBox::critical(this, tr("TTS error"), | ||
439 | tr("The selected TTS failed to initialize. You can't use this TTS.")); | ||
440 | return; | ||
441 | } | ||
442 | |||
443 | if(tts->configOk()) | ||
444 | { | ||
445 | ui.configTTSstatus->setText(tr("Configuration OK")); | ||
446 | ui.configTTSstatusimg->setPixmap(QPixmap(QString::fromUtf8(":/icons/go-next.svg"))); | ||
447 | #ifdef QT_MULTIMEDIA_LIB | ||
448 | ui.testTTS->setEnabled(true); | ||
449 | #else | ||
450 | ui.testTTS->setEnabled(false); | ||
451 | #endif | ||
452 | } | ||
453 | else | ||
454 | { | ||
455 | ui.configTTSstatus->setText(tr("Configuration INVALID")); | ||
456 | ui.configTTSstatusimg->setPixmap(QPixmap(QString::fromUtf8(":/icons/dialog-error.svg"))); | ||
457 | ui.testTTS->setEnabled(false); | ||
458 | } | ||
459 | |||
460 | delete tts; /* Config objects are never deleted (in fact, they are leaked..), so we can't rely on QObject, | ||
461 | since that would delete the TTSBase instance on application exit*/ | ||
462 | } | ||
463 | |||
464 | void Config::updateEncState() | ||
465 | { | ||
466 | if(ui.treeDevices->selectedItems().size() == 0) | ||
467 | return; | ||
468 | |||
469 | QString devname = ui.treeDevices->selectedItems().at(0)->data(0, Qt::UserRole).toString(); | ||
470 | QString encoder = PlayerBuildInfo::instance()->value( | ||
471 | PlayerBuildInfo::Encoder, devname).toString(); | ||
472 | ui.encoderName->setText(EncoderBase::getEncoderName( | ||
473 | PlayerBuildInfo::instance()->value(PlayerBuildInfo::Encoder, devname).toString())); | ||
474 | |||
475 | EncoderBase* enc = EncoderBase::getEncoder(this,encoder); | ||
476 | |||
477 | if(enc->configOk()) | ||
478 | { | ||
479 | ui.configEncstatus->setText(tr("Configuration OK")); | ||
480 | ui.configEncstatusimg->setPixmap(QPixmap(QString::fromUtf8(":/icons/go-next.svg"))); | ||
481 | } | ||
482 | else | ||
483 | { | ||
484 | ui.configEncstatus->setText(tr("Configuration INVALID")); | ||
485 | ui.configEncstatusimg->setPixmap(QPixmap(QString::fromUtf8(":/icons/dialog-error.svg"))); | ||
486 | } | ||
487 | } | ||
488 | |||
489 | |||
490 | void Config::setNoProxy(bool checked) | ||
491 | { | ||
492 | ui.proxyPort->setEnabled(!checked); | ||
493 | ui.proxyHost->setEnabled(!checked); | ||
494 | ui.proxyUser->setEnabled(!checked); | ||
495 | ui.proxyPass->setEnabled(!checked); | ||
496 | ui.checkShowProxyPassword->setEnabled(!checked); | ||
497 | ui.checkShowProxyPassword->setChecked(false); | ||
498 | showProxyPassword(false); | ||
499 | } | ||
500 | |||
501 | |||
502 | void Config::setSystemProxy(bool checked) | ||
503 | { | ||
504 | setNoProxy(checked); | ||
505 | if(checked) { | ||
506 | // save values in input box | ||
507 | proxy.setScheme("http"); | ||
508 | proxy.setUserName(ui.proxyUser->text()); | ||
509 | proxy.setPassword(ui.proxyPass->text()); | ||
510 | proxy.setHost(ui.proxyHost->text()); | ||
511 | proxy.setPort(ui.proxyPort->value()); | ||
512 | // show system values in input box | ||
513 | QUrl envproxy = System::systemProxy(); | ||
514 | LOG_INFO() << "setting system proxy" << envproxy; | ||
515 | |||
516 | ui.proxyHost->setText(envproxy.host()); | ||
517 | ui.proxyPort->setValue(envproxy.port()); | ||
518 | ui.proxyUser->setText(envproxy.userName()); | ||
519 | ui.proxyPass->setText(envproxy.password()); | ||
520 | |||
521 | if(envproxy.host().isEmpty() || envproxy.port() == -1) { | ||
522 | LOG_WARNING() << "system proxy is invalid."; | ||
523 | QMessageBox::warning(this, tr("Proxy Detection"), | ||
524 | tr("The System Proxy settings are invalid!\n" | ||
525 | "Rockbox Utility can't work with this proxy settings. " | ||
526 | "Make sure the system proxy is set correctly. Note that " | ||
527 | "\"proxy auto-config (PAC)\" scripts are not supported by " | ||
528 | "Rockbox Utility. If your system uses this you need " | ||
529 | "to use manual proxy settings."), | ||
530 | QMessageBox::Ok ,QMessageBox::Ok); | ||
531 | // the current proxy settings are invalid. Check the saved proxy | ||
532 | // type again. | ||
533 | if(RbSettings::value(RbSettings::ProxyType).toString() == "manual") | ||
534 | ui.radioManualProxy->setChecked(true); | ||
535 | else | ||
536 | ui.radioNoProxy->setChecked(true); | ||
537 | } | ||
538 | |||
539 | } | ||
540 | else { | ||
541 | ui.proxyHost->setText(proxy.host()); | ||
542 | ui.proxyPort->setValue(proxy.port()); | ||
543 | ui.proxyUser->setText(proxy.userName()); | ||
544 | ui.proxyPass->setText(proxy.password()); | ||
545 | } | ||
546 | |||
547 | } | ||
548 | |||
549 | |||
550 | QStringList Config::findLanguageFiles() | ||
551 | { | ||
552 | QDir dir(programPath); | ||
553 | QStringList fileNames; | ||
554 | QStringList langs; | ||
555 | fileNames = dir.entryList(QStringList("*.qm"), QDir::Files, QDir::Name); | ||
556 | |||
557 | QDir resDir(":/lang"); | ||
558 | fileNames += resDir.entryList(QStringList("*.qm"), QDir::Files, QDir::Name); | ||
559 | |||
560 | QRegExp exp("^rbutil_(.*)\\.qm"); | ||
561 | for(int i = 0; i < fileNames.size(); i++) { | ||
562 | QString a = fileNames.at(i); | ||
563 | a.replace(exp, "\\1"); | ||
564 | langs.append(a); | ||
565 | } | ||
566 | langs.sort(); | ||
567 | LOG_INFO() << "available lang files:" << langs; | ||
568 | |||
569 | return langs; | ||
570 | } | ||
571 | |||
572 | |||
573 | QString Config::languageName(const QString &qmFile) | ||
574 | { | ||
575 | QTranslator translator; | ||
576 | |||
577 | QString file = "rbutil_" + qmFile; | ||
578 | if(!translator.load(file, programPath)) | ||
579 | translator.load(file, ":/lang"); | ||
580 | |||
581 | return translator.translate("Configure", "English", | ||
582 | "This is the localized language name, i.e. your language."); | ||
583 | } | ||
584 | |||
585 | |||
586 | void Config::updateLanguage() | ||
587 | { | ||
588 | LOG_INFO() << "update selected language"; | ||
589 | |||
590 | // remove all old translators | ||
591 | for(int i = 0; i < RbUtilQt::translators.size(); ++i) { | ||
592 | qApp->removeTranslator(RbUtilQt::translators.at(i)); | ||
593 | // do not delete old translators, this confuses Qt. | ||
594 | } | ||
595 | RbUtilQt::translators.clear(); | ||
596 | QList<QListWidgetItem*> a = ui.listLanguages->selectedItems(); | ||
597 | if(a.size() > 0) | ||
598 | language = lang.value(a.at(0)->text()); | ||
599 | LOG_INFO() << "new language:" << language; | ||
600 | |||
601 | QTranslator *translator = new QTranslator(qApp); | ||
602 | QTranslator *qttrans = new QTranslator(qApp); | ||
603 | QString absolutePath = QCoreApplication::instance()->applicationDirPath(); | ||
604 | |||
605 | if(!translator->load("rbutil_" + language, absolutePath)) | ||
606 | translator->load("rbutil_" + language, ":/lang"); | ||
607 | if(!qttrans->load("qt_" + language, | ||
608 | QLibraryInfo::location(QLibraryInfo::TranslationsPath))) | ||
609 | qttrans->load("qt_" + language, ":/lang"); | ||
610 | |||
611 | qApp->installTranslator(translator); | ||
612 | qApp->installTranslator(qttrans); | ||
613 | //: This string is used to indicate the writing direction. Translate it | ||
614 | //: to "RTL" (without quotes) for RTL languages. Anything else will get | ||
615 | //: treated as LTR language. | ||
616 | if(QObject::tr("LTR") == "RTL") | ||
617 | qApp->setLayoutDirection(Qt::RightToLeft); | ||
618 | else | ||
619 | qApp->setLayoutDirection(Qt::LeftToRight); | ||
620 | |||
621 | RbUtilQt::translators.append(translator); | ||
622 | RbUtilQt::translators.append(qttrans); | ||
623 | |||
624 | QLocale::setDefault(QLocale(language)); | ||
625 | |||
626 | } | ||
627 | |||
628 | |||
629 | void Config::browseCache() | ||
630 | { | ||
631 | QString old = ui.cachePath->text(); | ||
632 | if(!QFileInfo(old).isDir()) | ||
633 | old = QDir::tempPath(); | ||
634 | QString c = QFileDialog::getExistingDirectory(this, tr("Set Cache Path"), old); | ||
635 | if(c.isEmpty()) | ||
636 | c = old; | ||
637 | else if(!QFileInfo(c).isDir()) | ||
638 | c = QDir::tempPath(); | ||
639 | ui.cachePath->setText(QDir::toNativeSeparators(c)); | ||
640 | updateCacheInfo(c); | ||
641 | } | ||
642 | |||
643 | |||
644 | void Config::refreshMountpoint() | ||
645 | { | ||
646 | // avoid QComboBox to send signals during rebuild to avoid changing to an | ||
647 | // unwanted item. | ||
648 | ui.mountPoint->blockSignals(true); | ||
649 | ui.mountPoint->clear(); | ||
650 | QStringList mps = Utils::mountpoints(Utils::MountpointsSupported); | ||
651 | for(int i = 0; i < mps.size(); ++i) { | ||
652 | // add mountpoint as user data so we can change the displayed string | ||
653 | // later (to include volume label or similar) | ||
654 | // Skip unwritable mountpoints, they are not useable for us. | ||
655 | if(QFileInfo(mps.at(i)).isWritable()) { | ||
656 | QString description = tr("%1 (%2 GiB of %3 GiB free)") | ||
657 | .arg(Utils::filesystemName(mps.at(i))) | ||
658 | .arg((double)Utils::filesystemFree(mps.at(i))/(1<<30), 0, 'f', 2) | ||
659 | .arg((double)Utils::filesystemTotal(mps.at(i))/(1<<30), 0, 'f', 2); | ||
660 | ui.mountPoint->addItem(QDir::toNativeSeparators(mps.at(i)), description); | ||
661 | } | ||
662 | else { | ||
663 | LOG_WARNING() << "mountpoint not writable, skipping:" << mps.at(i); | ||
664 | } | ||
665 | } | ||
666 | if(!mountpoint.isEmpty()) { | ||
667 | setMountpoint(mountpoint); | ||
668 | } | ||
669 | ui.mountPoint->blockSignals(false); | ||
670 | } | ||
671 | |||
672 | |||
673 | void Config::updateMountpoint(QString m) | ||
674 | { | ||
675 | if(!m.isEmpty()) { | ||
676 | mountpoint = QDir::fromNativeSeparators(m); | ||
677 | LOG_INFO() << "Mountpoint set to" << mountpoint; | ||
678 | } | ||
679 | } | ||
680 | |||
681 | |||
682 | void Config::updateMountpoint(int idx) | ||
683 | { | ||
684 | if(idx == -1) { | ||
685 | return; | ||
686 | } | ||
687 | QString mp = ui.mountPoint->itemText(idx); | ||
688 | if(!mp.isEmpty()) { | ||
689 | mountpoint = QDir::fromNativeSeparators(mp); | ||
690 | LOG_INFO() << "Mountpoint set to" << mountpoint; | ||
691 | } | ||
692 | } | ||
693 | |||
694 | |||
695 | void Config::setMountpoint(QString m) | ||
696 | { | ||
697 | if(m.isEmpty()) { | ||
698 | return; | ||
699 | } | ||
700 | int index = ui.mountPoint->findText(QDir::toNativeSeparators(m)); | ||
701 | if(index != -1) { | ||
702 | ui.mountPoint->setCurrentIndex(index); | ||
703 | } | ||
704 | else { | ||
705 | // keep a mountpoint that is not in the list for convenience (to allow | ||
706 | // easier development) | ||
707 | ui.mountPoint->addItem(QDir::toNativeSeparators(m)); | ||
708 | ui.mountPoint->setCurrentIndex(ui.mountPoint->findText(m)); | ||
709 | } | ||
710 | LOG_INFO() << "Mountpoint set to" << mountpoint; | ||
711 | } | ||
712 | |||
713 | |||
714 | void Config::autodetect() | ||
715 | { | ||
716 | Autodetection detector(this); | ||
717 | // disable tree during detection as "working" feedback. | ||
718 | // TODO: replace the tree view with a splash screen during this time. | ||
719 | ui.treeDevices->setEnabled(false); | ||
720 | this->setCursor(Qt::WaitCursor); | ||
721 | QCoreApplication::processEvents(); | ||
722 | |||
723 | detector.detect(); | ||
724 | QList<struct Autodetection::Detected> detected; | ||
725 | detected = detector.detected(); | ||
726 | this->unsetCursor(); | ||
727 | if(detected.size() > 1) { | ||
728 | // FIXME: handle multiple found players. | ||
729 | QString msg; | ||
730 | msg = tr("Multiple devices have been detected. Please disconnect " | ||
731 | "all players but one and try again."); | ||
732 | msg += "<br/>"; | ||
733 | msg += tr("Detected devices:"); | ||
734 | msg += "<ul>"; | ||
735 | for(int i = 0; i < detected.size(); ++i) { | ||
736 | QString mp = detected.at(i).mountpoint; | ||
737 | if(mp.isEmpty()) { | ||
738 | mp = tr("(unknown)"); | ||
739 | } | ||
740 | msg += QString("<li>%1</li>").arg(tr("%1 at %2").arg( | ||
741 | PlayerBuildInfo::instance()->value( | ||
742 | PlayerBuildInfo::DisplayName, | ||
743 | detected.at(i).device).toString(), | ||
744 | QDir::toNativeSeparators(mp))); | ||
745 | } | ||
746 | msg += "</ul>"; | ||
747 | msg += tr("Note: detecting connected devices might be ambiguous. " | ||
748 | "You might have less devices connected than listed. " | ||
749 | "In this case it might not be possible to detect your " | ||
750 | "player unambiguously."); | ||
751 | QMessageBox::information(this, tr("Device Detection"), msg); | ||
752 | ui.treeDevices->setEnabled(true); | ||
753 | } | ||
754 | else if(detected.size() == 0) { | ||
755 | QMessageBox::warning(this, tr("Device Detection"), | ||
756 | tr("Could not detect a device.\n" | ||
757 | "Select your device and Mountpoint manually."), | ||
758 | QMessageBox::Ok ,QMessageBox::Ok); | ||
759 | ui.treeDevices->setEnabled(true); | ||
760 | } | ||
761 | else if(detected.at(0).status != Autodetection::PlayerOk | ||
762 | && detected.at(0).status != Autodetection::PlayerAmbiguous) { | ||
763 | QString msg; | ||
764 | switch(detected.at(0).status) { | ||
765 | case Autodetection::PlayerIncompatible: | ||
766 | msg += tr("Detected an unsupported player:\n%1\n" | ||
767 | "Sorry, Rockbox doesn't run on your player.") | ||
768 | .arg(PlayerBuildInfo::instance()->value( | ||
769 | PlayerBuildInfo::DisplayName, | ||
770 | detected.at(0).device).toString()); | ||
771 | break; | ||
772 | case Autodetection::PlayerMtpMode: | ||
773 | msg = tr("%1 in MTP mode found!\n" | ||
774 | "You need to change your player to MSC mode for installation. ") | ||
775 | .arg(PlayerBuildInfo::instance()->value( | ||
776 | PlayerBuildInfo::DisplayName, | ||
777 | detected.at(0).device).toString()); | ||
778 | break; | ||
779 | case Autodetection::PlayerWrongFilesystem: | ||
780 | if(PlayerBuildInfo::instance()->value( | ||
781 | PlayerBuildInfo::BootloaderMethod, detected.at(0).device) == "ipod") { | ||
782 | msg = tr("%1 \"MacPod\" found!\n" | ||
783 | "Rockbox needs a FAT formatted Ipod (so-called \"WinPod\") " | ||
784 | "to run. ").arg(PlayerBuildInfo::instance()->value( | ||
785 | PlayerBuildInfo::DisplayName, | ||
786 | detected.at(0).device).toString()); | ||
787 | } | ||
788 | else { | ||
789 | msg = tr("The player contains an incompatible filesystem.\n" | ||
790 | "Make sure you selected the correct mountpoint and " | ||
791 | "the player is set up to use a filesystem compatible " | ||
792 | "with Rockbox."); | ||
793 | } | ||
794 | break; | ||
795 | case Autodetection::PlayerError: | ||
796 | default: | ||
797 | msg += tr("An unknown error occured during player detection."); | ||
798 | break; | ||
799 | } | ||
800 | QMessageBox::information(this, tr("Device Detection"), msg); | ||
801 | ui.treeDevices->setEnabled(true); | ||
802 | } | ||
803 | else { | ||
804 | selectDevice(detected.at(0).device, detected.at(0).mountpoint); | ||
805 | } | ||
806 | |||
807 | } | ||
808 | |||
809 | void Config::selectDevice(QString device, QString mountpoint) | ||
810 | { | ||
811 | // collapse all items | ||
812 | for(int a = 0; a < ui.treeDevices->topLevelItemCount(); a++) | ||
813 | ui.treeDevices->topLevelItem(a)->setExpanded(false); | ||
814 | // deselect the selected item(s) | ||
815 | for(int a = 0; a < ui.treeDevices->selectedItems().size(); a++) | ||
816 | ui.treeDevices->selectedItems().at(a)->setSelected(false); | ||
817 | |||
818 | // find the new item | ||
819 | // enumerate all platform items | ||
820 | QList<QTreeWidgetItem*> itmList | ||
821 | = ui.treeDevices->findItems("*",Qt::MatchWildcard); | ||
822 | for(int i=0; i< itmList.size();i++) | ||
823 | { | ||
824 | //enumerate device items | ||
825 | for(int j=0;j < itmList.at(i)->childCount();j++) | ||
826 | { | ||
827 | QString data = itmList.at(i)->child(j)->data(0, Qt::UserRole).toString(); | ||
828 | // unset bold flag | ||
829 | QFont f = itmList.at(i)->child(j)->font(0); | ||
830 | f.setBold(false); | ||
831 | itmList.at(i)->child(j)->setFont(0, f); | ||
832 | |||
833 | if(device == data) // item found | ||
834 | { | ||
835 | f.setBold(true); | ||
836 | itmList.at(i)->child(j)->setFont(0, f); | ||
837 | itmList.at(i)->child(j)->setSelected(true); //select the item | ||
838 | itmList.at(i)->setExpanded(true); //expand the platform item | ||
839 | //ui.treeDevices->indexOfTopLevelItem(itmList.at(i)->child(j)); | ||
840 | ui.treeDevices->scrollToItem(itmList.at(i)->child(j)); | ||
841 | break; | ||
842 | } | ||
843 | } | ||
844 | } | ||
845 | this->unsetCursor(); | ||
846 | |||
847 | if(!mountpoint.isEmpty()) | ||
848 | { | ||
849 | setMountpoint(mountpoint); | ||
850 | } | ||
851 | else | ||
852 | { | ||
853 | QMessageBox::warning(this, tr("Autodetection"), | ||
854 | tr("Could not detect a Mountpoint.\n" | ||
855 | "Select your Mountpoint manually."), | ||
856 | QMessageBox::Ok, QMessageBox::Ok); | ||
857 | } | ||
858 | ui.treeDevices->setEnabled(true); | ||
859 | } | ||
860 | |||
861 | |||
862 | void Config::cacheClear() | ||
863 | { | ||
864 | if(QMessageBox::critical(this, tr("Really delete cache?"), | ||
865 | tr("Do you really want to delete the cache? " | ||
866 | "Make absolutely sure this setting is correct as it will " | ||
867 | "remove <b>all</b> files in this folder!"), | ||
868 | QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) | ||
869 | return; | ||
870 | |||
871 | QString cache = ui.cachePath->text() + "/rbutil-cache/"; | ||
872 | if(!QFileInfo(cache).isDir()) { | ||
873 | QMessageBox::critical(this, tr("Path wrong!"), | ||
874 | tr("The cache path is invalid. Aborting."), QMessageBox::Ok); | ||
875 | return; | ||
876 | } | ||
877 | QDir dir(cache); | ||
878 | dir.removeRecursively(); | ||
879 | updateCacheInfo(RbSettings::value(RbSettings::CachePath).toString()); | ||
880 | } | ||
881 | |||
882 | |||
883 | void Config::configTts() | ||
884 | { | ||
885 | int index = ui.comboTts->currentIndex(); | ||
886 | TTSBase* tts = TTSBase::getTTS(this,ui.comboTts->itemData(index).toString()); | ||
887 | EncTtsCfgGui gui(this,tts,TTSBase::getTTSName(ui.comboTts->itemData(index).toString())); | ||
888 | gui.exec(); | ||
889 | updateTtsState(ui.comboTts->currentIndex()); | ||
890 | delete tts; /* Config objects are never deleted (in fact, they are | ||
891 | leaked..), so we can't rely on QObject, since that would | ||
892 | delete the TTSBase instance on application exit */ | ||
893 | } | ||
894 | |||
895 | void Config::testTts() | ||
896 | { | ||
897 | #ifdef QT_MULTIMEDIA_LIB | ||
898 | QString errstr; | ||
899 | int index = ui.comboTts->currentIndex(); | ||
900 | TTSBase* tts; | ||
901 | tts = TTSBase::getTTS(this,ui.comboTts->itemData(index).toString()); | ||
902 | if(!tts) | ||
903 | { | ||
904 | QMessageBox::critical(this, tr("TTS error"), | ||
905 | tr("The selected TTS failed to initialize. You can't use this TTS.")); | ||
906 | return; | ||
907 | } | ||
908 | ui.testTTS->setEnabled(false); | ||
909 | if(!tts->configOk()) | ||
910 | { | ||
911 | QMessageBox::warning(this,tr("TTS configuration invalid"), | ||
912 | tr("TTS configuration invalid. \n Please configure TTS engine.")); | ||
913 | return; | ||
914 | } | ||
915 | if(!tts->start(&errstr)) | ||
916 | { | ||
917 | QMessageBox::warning(this,tr("Could not start TTS engine."), | ||
918 | tr("Could not start TTS engine.\n") + errstr | ||
919 | + tr("\nPlease configure TTS engine.")); | ||
920 | ui.testTTS->setEnabled(true); | ||
921 | return; | ||
922 | } | ||
923 | |||
924 | QString filename; | ||
925 | QTemporaryFile file(this); | ||
926 | // keep filename empty if the TTS can do speaking for itself. | ||
927 | if(!(tts->capabilities() & TTSBase::CanSpeak)) { | ||
928 | file.open(); | ||
929 | filename = file.fileName(); | ||
930 | file.close(); | ||
931 | } | ||
932 | |||
933 | if(tts->voice(tr("Rockbox Utility Voice Test"),filename,&errstr) == FatalError) | ||
934 | { | ||
935 | tts->stop(); | ||
936 | QMessageBox::warning(this,tr("Could not voice test string."), | ||
937 | tr("Could not voice test string.\n") + errstr | ||
938 | + tr("\nPlease configure TTS engine.")); | ||
939 | ui.testTTS->setEnabled(false); | ||
940 | return; | ||
941 | } | ||
942 | tts->stop(); | ||
943 | if(!filename.isEmpty()) { | ||
944 | QSound::play(filename); | ||
945 | } | ||
946 | ui.testTTS->setEnabled(true); | ||
947 | delete tts; /* Config objects are never deleted (in fact, they are | ||
948 | leaked..), so we can't rely on QObject, since that would | ||
949 | delete the TTSBase instance on application exit */ | ||
950 | #endif | ||
951 | } | ||
952 | |||
953 | void Config::configEnc() | ||
954 | { | ||
955 | if(ui.treeDevices->selectedItems().size() == 0) | ||
956 | return; | ||
957 | |||
958 | QString devname = ui.treeDevices->selectedItems().at(0)->data(0, Qt::UserRole).toString(); | ||
959 | QString encoder = PlayerBuildInfo::instance()->value( | ||
960 | PlayerBuildInfo::Encoder, devname).toString(); | ||
961 | ui.encoderName->setText( | ||
962 | EncoderBase::getEncoderName(PlayerBuildInfo::instance()->value( | ||
963 | PlayerBuildInfo::Encoder, devname).toString())); | ||
964 | |||
965 | |||
966 | EncoderBase* enc = EncoderBase::getEncoder(this,encoder); | ||
967 | |||
968 | EncTtsCfgGui gui(this,enc,EncoderBase::getEncoderName(encoder)); | ||
969 | gui.exec(); | ||
970 | |||
971 | updateEncState(); | ||
972 | } | ||
973 | |||
974 | |||
975 | void Config::changeEvent(QEvent *e) | ||
976 | { | ||
977 | if(e->type() == QEvent::LanguageChange) { | ||
978 | ui.retranslateUi(this); | ||
979 | updateCacheInfo(ui.cachePath->text()); | ||
980 | } else { | ||
981 | QWidget::changeEvent(e); | ||
982 | } | ||
983 | } | ||
984 | |||