1 // -*- C++ -*-
2 // $Id: mainwindow.cpp,v 1.27 2010-11-01 03:30:42 robertl Exp $
3 //------------------------------------------------------------------------
4 //
5 // Copyright (C) 2009 S. Khai Mong <khai@mangrai.com>.
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20 // USA.
21 //
22 #include <QtCore/QByteArray> // for QByteArray
23 #include <QtCore/QDate> // for QDate
24 #include <QtCore/QDateTime> // for QDateTime
25 #include <QtCore/QDir> // for QDir
26 #include <QtCore/QEvent> // for QEvent (& QEvent::LanguageChange, QEvent::LocaleChange)
27 #include <QtCore/QFile> // for QFile
28 #include <QtCore/QFileInfo> // for QFileInfo
29 #include <QtCore/QLocale> // for QLocale
30 #include <QtCore/QMimeData> // for QMimeData
31 #include <QtCore/QProcess> // for QProcess, QProcess::NotRunning
32 #include <QtCore/QRegExp> // for QRegExp
33 #include <QtCore/QSettings> // for QSettings
34 #include <QtCore/QTemporaryFile> // for QTemporaryFile
35 #include <QtCore/QTime> // for QTime
36 #include <QtCore/QUrl> // for QUrl
37 #include <QtCore/QVariant> // for QVariant
38 #include <QtCore/Qt> // for SmoothTransformation, WaitCursor
39 #include <QtCore/QtGlobal> // for foreach
40 #include <QtGui/QCursor> // for QCursor
41 #include <QtGui/QDesktopServices> // for QDesktopServices
42 #include <QtGui/QIcon> // for QIcon
43 #include <QtGui/QImage> // for QImage
44 #include <QtWidgets/QApplication> // for QApplication, qApp
45 #include <QtWidgets/QCheckBox> // for QCheckBox
46 #include <QtWidgets/QDialogButtonBox> // for QDialogButtonBox
47 #include <QtWidgets/QFileDialog> // for QFileDialog
48 #include <QtWidgets/QMessageBox> // for QMessageBox, operator|, QMessageBox::Yes, QMessageBox::No
49 #include <QtWidgets/QPlainTextEdit> // for QPlainTextEdit
50 #include <QtWidgets/QPushButton> // for QPushButton
51 #include <QtWidgets/QRadioButton> // for QRadioButton
52 #include <QtWidgets/QStackedWidget> // for QStackedWidget
53
54 #include <cstdlib> // for exit
55
56 #include "mainwindow.h"
57 #include "../gbversion.h" // for VERSION
58 #include "aboutdlg.h" // for AboutDlg
59 #include "advdlg.h" // for AdvDlg
60 #include "appname.h" // for appName
61 #include "babeldata.h" // for BabelData
62 #include "donate.h" // for Donate
63 #include "filterdlg.h" // for FilterDialog
64 #include "formatload.h" // for FormatLoad
65 #include "gmapdlg.h" // for GMapDialog
66 #include "help.h" // for ShowHelp
67 #include "optionsdlg.h" // for OptionsDlg
68 #include "preferences.h" // for Preferences
69 #include "processwait.h" // for ProcessWaitDialog
70 #include "upgrade.h" // for UpgradeCheck
71 #include "version_mismatch.h" // for VersionMismatch
72
73
74
75 const int BabelData::noType_ = -1;
76 const int BabelData::fileType_ = 0;
77 const int BabelData::deviceType_ = 1;
78
79 #define FAKE_LANGUAGE_MENU 0
80
81 //------------------------------------------------------------------------
findBabelVersion()82 QString MainWindow::findBabelVersion()
83 {
84 QProcess babel;
85 babel.start(QApplication::applicationDirPath() + "/gpsbabel", QStringList() << "-V");
86 if (!babel.waitForStarted()) {
87 return QString();
88 }
89 babel.closeWriteChannel();
90 if (!babel.waitForFinished()) {
91 return QString();
92 }
93
94 QString str = babel.readAll();
95 isBeta_ = str.contains("-beta");
96 str.replace("Version", "");
97 str.replace("GPSBabel", "");
98 str.replace(QRegExp("^[\\s]*"), "");
99 str.replace(QRegExp("[\\s]+$"), "");
100 str = str.simplified();
101 return str;
102 }
103
104 //------------------------------------------------------------------------
105 // Decides whether available beta upgrades are suggested to user for download.
allowBetaUpgrades()106 bool MainWindow::allowBetaUpgrades()
107 {
108 // If this is a beta version (which means the user consciously downloaded
109 // it and decided to be on the beta track or the user has ticked the
110 // 'suggest beta upgrade' box, allow betas to be suggested for installation.
111 return isBeta_ || babelData_.allowBetaUpgrades_;
112 }
113
114 //------------------------------------------------------------------------
MakeOptions(const QList<FormatOption> & options)115 static QString MakeOptions(const QList<FormatOption>& options)
116 {
117 QString str;
118 for (int i = 0; i< options.size(); i++) {
119 FormatOption option = options[i];
120 QVariant default_value = option.getDefaultValue();
121 if (option.getSelected()) {
122 // For OPTbool, 'selected' is the key, not value.
123 if (option.getType() == FormatOption::OPTbool) {
124 // Only write "foo=1" if that's not already the default.
125 if (default_value != "1") {
126 str += "," + option.getName() + "=1";
127 }
128 } else {
129 str += "," + option.getName() + "=" + option.getValue().toString();
130 }
131 } else {
132 // For every boolean option not selected, explicitly
133 // turn it off here, but only if the default isn't zero
134 // or given.
135 if (option.getType() == FormatOption::OPTbool &&
136 default_value != "0" &&
137 default_value != "") {
138 str += "," + option.getName() + "=0";
139 }
140 }
141 }
142 return str;
143 }
144
145 //------------------------------------------------------------------------
MakeOptionsNoLeadingComma(const QList<FormatOption> & options)146 static QString MakeOptionsNoLeadingComma(const QList<FormatOption>& options)
147 {
148 QString str = MakeOptions(options);
149 return (str.length()) != 0 ? str.mid(1) : str;
150
151 }
152
153 //------------------------------------------------------------------------
MainWindow(QWidget * parent)154 MainWindow::MainWindow(QWidget* parent): QMainWindow(parent)
155 {
156 ui_.setupUi(this);
157 setWindowTitle(appName);
158 babelVersion_ = findBabelVersion();
159 fmtChgInterlock_ = false;
160 loadDeviceNameCombos();
161
162 connect(ui_.inputFileOptBtn, SIGNAL(clicked()), this, SLOT(inputFileOptBtnClicked()));
163 connect(ui_.inputDeviceOptBtn, SIGNAL(clicked()), this, SLOT(inputDeviceOptBtnClicked()));
164 connect(ui_.inputFileNameBrowseBtn, SIGNAL(clicked()), this, SLOT(browseInputFile()));
165
166 ui_.outputFileOptBtn->setAutoExclusive(false);
167 ui_.outputDeviceOptBtn->setAutoExclusive(false);
168 connect(ui_.outputFileOptBtn, SIGNAL(clicked()), this, SLOT(outputFileOptBtnClicked()));
169 connect(ui_.outputDeviceOptBtn, SIGNAL(clicked()), this, SLOT(outputDeviceOptBtnClicked()));
170 connect(ui_.outputFileNameBrowseBtn, SIGNAL(clicked()), this, SLOT(browseOutputFile()));
171
172 connect(ui_.actionQuit, SIGNAL(triggered()), this, SLOT(closeActionX()));
173 connect(ui_.actionHelp, SIGNAL(triggered()), this, SLOT(helpActionX()));
174 connect(ui_.actionAbout, SIGNAL(triggered()), this, SLOT(aboutActionX()));
175 connect(ui_.actionVisit_Website, SIGNAL(triggered()), this, SLOT(visitWebsiteActionX()));
176 connect(ui_.actionMake_a_Donation, SIGNAL(triggered()), this, SLOT(donateActionX()));
177 connect(ui_.actionUpgradeCheck, SIGNAL(triggered()), this, SLOT(upgradeCheckActionX()));
178 connect(ui_.actionPreferences, SIGNAL(triggered()), this, SLOT(preferencesActionX()));
179
180 connect(ui_.inputFormatCombo, SIGNAL(currentIndexChanged(int)),
181 this, SLOT(inputFormatChanged(int)));
182 connect(ui_.outputFormatCombo, SIGNAL(currentIndexChanged(int)),
183 this, SLOT(outputFormatChanged(int)));
184 connect(ui_.inputOptionsBtn, SIGNAL(clicked()),
185 this, SLOT(inputOptionButtonClicked()));
186 connect(ui_.outputOptionsBtn, SIGNAL(clicked()),
187 this, SLOT(outputOptionButtonClicked()));
188 connect(ui_.moreOptionButton, SIGNAL(clicked()),
189 this, SLOT(moreOptionButtonClicked()));
190
191 connect(ui_.buttonBox, SIGNAL(accepted()), this, SLOT(applyActionX()));
192 connect(ui_.buttonBox, SIGNAL(rejected()), this, SLOT(closeActionX()));
193 connect(ui_.buttonBox, SIGNAL(helpRequested()), this, SLOT(helpActionX()));
194
195 connect(ui_.xlateFiltersBtn, SIGNAL(clicked()), this, SLOT(filtersClicked()));
196
197 connect(ui_.inputFileNameText, SIGNAL(textEdited(QString)), this, SLOT(inputFileNameEdited()));
198 connect(ui_.outputFileNameText, SIGNAL(textEdited(QString)), this, SLOT(outputFileNameEdited()));
199
200 #if defined (Q_OS_WIN)
201 // Windows users like the colored buttons. They look out of place elsewhere.
202 ui_.buttonBox->button(QDialogButtonBox::Ok)->setIcon(QIcon(":/images/runit.png"));
203 ui_.buttonBox->button(QDialogButtonBox::Close)->setIcon(QIcon(":/images/exit.png"));
204 #endif
205
206 ui_.inputOptionsText->setReadOnly(true);
207 ui_.outputOptionsText->setReadOnly(true);
208 #if 0
209 // 02/28/10 - let's try letting people edit these outside the browse.
210 ui.inputFileNameText->setReadOnly(true);
211 ui.outputFileNameText->setReadOnly(true);
212 #else
213 setAcceptDrops(true);
214 #endif
215 lights_[0] = QPixmap::fromImage(QImage(":/images/00.png").scaledToHeight(20, Qt::SmoothTransformation));
216 lights_[1] = QPixmap::fromImage(QImage(":/images/01.png").scaledToHeight(20, Qt::SmoothTransformation));
217 lights_[2] = QPixmap::fromImage(QImage(":/images/10.png").scaledToHeight(20, Qt::SmoothTransformation));
218 lights_[3] = QPixmap::fromImage(QImage(":/images/11.png").scaledToHeight(20, Qt::SmoothTransformation));
219
220 ui_.outputWindow->setReadOnly(true);
221
222 langPath_ = "/usr/local/share/gpsbabel";
223 langPath_.append("/translations/");
224
225 // Start up in the current system language.
226 loadLanguage(QLocale::system().name());
227 loadFormats();
228 #if FAKE_LANGUAGE_MENU
229 createLanguageMenu();
230 #endif
231
232 //--- Restore from registry
233 restoreSettings();
234
235 upgrade = new UpgradeCheck(parent, formatList_, babelData_);
236 if (babelData_.startupVersionCheck_) {
237 upgrade->checkForUpgrade(babelVersion_, babelData_.upgradeCheckTime_,
238 allowBetaUpgrades());
239 }
240
241 if (!babelData_.ignoreVersionMismatch_ && babelVersion_ != VERSION) {
242 VersionMismatch vm(nullptr, babelVersion_, QString(VERSION));
243
244 vm.exec();
245 babelData_.ignoreVersionMismatch_ = vm.neverAgain();
246 }
247 }
248
249 //------------------------------------------------------------------------
~MainWindow()250 MainWindow::~MainWindow()
251 {
252
253 delete upgrade;
254
255 }
256 //------------------------------------------------------------------------
257 // Dynamic language switching courtesy of
258 // http://developer.qt.nokia.com/wiki/How_to_create_a_multi_language_application
259 // We create the menu entries dynamically, dependant on the existing
260 // translations.
261 #if FAKE_LANGUAGE_MENU
createLanguageMenu(void)262 void MainWindow::createLanguageMenu(void)
263 {
264 QActionGroup* langGroup = new QActionGroup(ui.menuHelp);
265 langGroup->setExclusive(true);
266 connect(langGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotLanguageChanged(QAction*)));
267
268 // format systems language
269 QString defaultLocale = QLocale::system().name(); // e.g. "de_DE"
270 defaultLocale.truncate(defaultLocale.lastIndexOf('_')); // e.g. "de"
271
272 QDir dir(langPath);
273 QStringList fileNames = dir.entryList(QStringList("GPSBabelFE*.qm"));
274
275 for (int i = 0; i < fileNames.size(); ++i) {
276 // get locale extracted by filename
277 QString locale;
278 locale = fileNames[i]; // "TranslationExample_de.qm"
279 locale.truncate(locale.lastIndexOf('.')); // "TranslationExample_de"
280 locale.remove(0, locale.indexOf('_') + 1); // "de"
281
282 QString lang = QLocale::languageToString(QLocale(locale).language());
283
284 QAction* action = new QAction(lang, this);
285 action->setCheckable(true);
286 action->setData(locale);
287
288 ui.menuHelp->addAction(action);
289 langGroup->addAction(action);
290
291 // set default translators and language checked
292 if (defaultLocale == locale) {
293 action->setChecked(true);
294 }
295 }
296 }
297 #endif // FAKE_LANGUAGE_MENU
298
299 //------------------------------------------------------------------------
300 // Called every time, when a menu entry of the language menu is called
slotLanguageChanged(QAction * action)301 void MainWindow::slotLanguageChanged(QAction* action)
302 {
303 if (nullptr != action) {
304 // load the language dependant on the action content.
305 loadLanguage(action->data().toString());
306 }
307 }
308
switchTranslator(QTranslator & translator,const QString & filename)309 void MainWindow::switchTranslator(QTranslator& translator, const QString& filename)
310 {
311 // remove the old translator
312 qApp->removeTranslator(&translator);
313
314 // load the new translator
315 if (translator.load(filename, langPath_)) {
316 qApp->installTranslator(&translator);
317 }
318 }
319
loadLanguage(const QString & rLanguage)320 void MainWindow::loadLanguage(const QString& rLanguage)
321 {
322 if (currLang_ != rLanguage) {
323 currLang_ = rLanguage;
324 QLocale locale = QLocale(currLang_);
325 QLocale::setDefault(locale);
326
327 switchTranslator(translator_, QString("gpsbabelfe_%1.qm").arg(rLanguage));
328 switchTranslator(translatorCore_, QString("gpsbabel_%1.qm").arg(rLanguage));
329 switchTranslator(translatorQt_, QString("qt_%1.qm").arg(rLanguage));
330 }
331 }
332
changeEvent(QEvent * event)333 void MainWindow::changeEvent(QEvent* event)
334 {
335 if (nullptr != event) {
336 switch (event->type()) {
337 // This event is sent if a translator is loaded.
338 case QEvent::LanguageChange:
339 ui_.retranslateUi(this);
340 break;
341 // This event is sent if the system language changes.
342 case QEvent::LocaleChange: {
343 QString locale = QLocale::system().name();
344 locale.truncate(locale.lastIndexOf('_'));
345 loadLanguage(locale);
346 }
347 break;
348 default:
349 break;
350 }
351 }
352
353 QMainWindow::changeEvent(event);
354 }
355
356 //------------------------------------------------------------------------
loadInputDeviceNameCombo(const QString & format)357 void MainWindow::loadInputDeviceNameCombo(const QString& format)
358 {
359 ui_.inputDeviceNameCombo->clear();
360 // Later, we can probe the system for multiple USB devices and populate
361 // here.
362 if (formatSupportsUSB(format)) {
363 ui_.inputDeviceNameCombo->addItem("usb:");
364 }
365 if (formatSupportsSerial(format)) {
366 osLoadDeviceNameCombos(ui_.inputDeviceNameCombo);
367 }
368 // If only one choice, just disable it.
369 ui_.inputDeviceNameCombo->setEnabled(ui_.inputDeviceNameCombo->count() > 1);
370 }
371
372 //------------------------------------------------------------------------
loadOutputDeviceNameCombo(const QString & format)373 void MainWindow::loadOutputDeviceNameCombo(const QString& format)
374 {
375 ui_.outputDeviceNameCombo->clear();
376 // Later, we can probe the system for multiple USB devices and populate
377 // here.
378 if (formatSupportsUSB(format)) {
379 ui_.outputDeviceNameCombo->addItem("usb:");
380 }
381 if (formatSupportsSerial(format)) {
382 osLoadDeviceNameCombos(ui_.outputDeviceNameCombo);
383 }
384 // If only one choice, just disable it.
385 ui_.outputDeviceNameCombo->setEnabled(ui_.outputDeviceNameCombo->count() > 1);
386 }
387
388 //------------------------------------------------------------------------
loadDeviceNameCombos()389 void MainWindow::loadDeviceNameCombos()
390 {
391 loadInputDeviceNameCombo("");
392 loadOutputDeviceNameCombo("");
393 }
394 //------------------------------------------------------------------------
inputFileOptBtnClicked()395 void MainWindow::inputFileOptBtnClicked()
396 {
397 fmtChgInterlock_ = true;
398 QString fmt = babelData_.inputFileFormat_;
399 ui_.inputStackedWidget->setCurrentWidget(ui_.inputFilePage);
400 QList<int>indices = inputFileFormatIndices();
401 ui_.inputFormatCombo->clear();
402 for (int i=0; i<indices.size(); i++) {
403 int k = indices[i];
404 if (!formatList_[k].isHidden()) {
405 ui_.inputFormatCombo->addItem(formatList_[k].getDescription(), QVariant(k));
406 }
407 }
408 setComboToFormat(ui_.inputFormatCombo, fmt, true);
409 fmtChgInterlock_ = false;
410 }
411
412 //------------------------------------------------------------------------
inputDeviceOptBtnClicked()413 void MainWindow::inputDeviceOptBtnClicked()
414 {
415 fmtChgInterlock_ = true;
416 QString fmt = babelData_.inputDeviceFormat_;
417 ui_.inputStackedWidget->setCurrentWidget(ui_.inputDevicePage);
418 QList<int>indices = inputDeviceFormatIndices();
419 ui_.inputFormatCombo->clear();
420 for (int i=0; i<indices.size(); i++) {
421 int k = indices[i];
422 if (!formatList_[k].isHidden()) {
423 ui_.inputFormatCombo->addItem(formatList_[k].getDescription(), QVariant(k));
424 }
425 }
426 setComboToFormat(ui_.inputFormatCombo, fmt, false);
427 fmtChgInterlock_ = false;
428 }
429
430 //------------------------------------------------------------------------
outputFileOptBtnClicked()431 void MainWindow:: outputFileOptBtnClicked()
432 {
433 fmtChgInterlock_ = true;
434 if (ui_.outputFileOptBtn->isChecked()) {
435 ui_.outputFilePage->setEnabled(true);
436 ui_.outputDeviceOptBtn->setChecked(false);
437 QString fmt = babelData_.outputFileFormat_;
438 ui_.outputStackedWidget->setCurrentWidget(ui_.outputFilePage);
439 QList<int>indices = outputFileFormatIndices();
440 ui_.outputFormatCombo->clear();
441 for (int i=0; i<indices.size(); i++) {
442 int k = indices[i];
443 if (!formatList_[k].isHidden()) {
444 ui_.outputFormatCombo->addItem(formatList_[k].getDescription(), QVariant(k));
445 }
446 }
447 setComboToFormat(ui_.outputFormatCombo, fmt, true);
448 } else {
449 ui_.outputStackedWidget->setCurrentWidget(ui_.outputFilePage);
450 ui_.outputFilePage->setEnabled(false);
451 }
452 fmtChgInterlock_ = false;
453 }
454
455 //------------------------------------------------------------------------
outputDeviceOptBtnClicked()456 void MainWindow:: outputDeviceOptBtnClicked()
457 {
458 fmtChgInterlock_ = true;
459 if (ui_.outputDeviceOptBtn->isChecked()) {
460 ui_.outputDevicePage->setEnabled(true);
461 ui_.outputFileOptBtn->setChecked(false);
462 QString fmt = babelData_.outputDeviceFormat_;
463 ui_.outputStackedWidget->setCurrentWidget(ui_.outputDevicePage);
464 QList<int>indices = outputDeviceFormatIndices();
465 ui_.outputFormatCombo->clear();
466 for (int i=0; i<indices.size(); i++) {
467 int k = indices[i];
468 if (!formatList_[k].isHidden()) {
469 ui_.outputFormatCombo->addItem(formatList_[k].getDescription(), QVariant(k));
470 }
471 }
472 setComboToFormat(ui_.outputFormatCombo, fmt, false);
473 } else {
474 ui_.outputStackedWidget->setCurrentWidget(ui_.outputDevicePage);
475 ui_.outputDevicePage->setEnabled(false);
476 }
477 fmtChgInterlock_ = false;
478 }
inputFileNameEdited()479 void MainWindow::inputFileNameEdited()
480 {
481 babelData_.inputFileNames_.clear();
482 babelData_.inputFileNames_ << ui_.inputFileNameText->text();
483 }
484
outputFileNameEdited()485 void MainWindow::outputFileNameEdited()
486 {
487 babelData_.outputFileName_ = ui_.outputFileNameText->text();
488
489 }
490
491 //------------------------------------------------------------------------
filterForFormat(int idx)492 QString MainWindow::filterForFormat(int idx)
493 {
494 QString str = formatList_[idx].getDescription();
495 str.replace(QRegExp("\\("), "[");
496 str.replace(QRegExp("\\)"), "]");
497 QStringList extensions = formatList_[idx].getExtensions();
498
499 // If we don't have any meaningful extensions available for this format,
500 // don't be clever here; just fall through to "All files" case.
501 if (!extensions.empty() && !extensions[0].isEmpty()) {
502 str += " (";
503 for (int i=0; i<extensions.size(); i++) {
504 if (i!= 0) {
505 str += " ";
506 }
507 str += "*." + extensions[i];
508 }
509 str += ");;";
510 }
511 str += "All Files (*.*)";
512 return str;
513 }
514 //------------------------------------------------------------------------
ensureExtensionPresent(const QString & name,int idx)515 QString MainWindow::ensureExtensionPresent(const QString& name, int idx)
516 {
517 QString outname = name;
518 if (QFileInfo(name).suffix().length() == 0) {
519 QStringList extensions = formatList_[idx].getExtensions();
520 if (!extensions.empty() && !extensions[0].isEmpty()) {
521 outname += "." + extensions[0];
522 }
523 }
524 return outname;
525 }
526
527 //------------------------------------------------------------------------
filterForFormatIncludes(int idx,const QString & fmt)528 bool MainWindow::filterForFormatIncludes(int idx, const QString& fmt)
529 {
530 QStringList extensions = formatList_[idx].getExtensions();
531 for (int i=0; i<extensions.size(); i++) {
532 if (fmt == extensions[i]) {
533 return true;
534 }
535 }
536 return false;
537 }
538
539 //------------------------------------------------------------------------
currentComboFormatIndex(QComboBox * comboBox)540 int MainWindow::currentComboFormatIndex(QComboBox* comboBox)
541 {
542 int idx = comboBox->currentIndex();
543 if (idx<0 || idx >= comboBox->count()) {
544 // QMessageBox::critical(0, appName, "*** Internal Error -- current combo index is invalid!");
545 return 0;
546 }
547 return comboBox->itemData(idx).toInt();
548 }
549 //------------------------------------------------------------------------
browseInputFile()550 void MainWindow::browseInputFile()
551 {
552 QString startFile = !babelData_.inputFileNames_.empty() ? babelData_.inputFileNames_[0] : babelData_.inputBrowse_;
553 int idx = currentComboFormatIndex(ui_.inputFormatCombo);
554 QFileInfo finfo(startFile);
555 if (!finfo.isDir() && (!filterForFormatIncludes(idx, finfo.suffix()))) {
556 startFile = finfo.dir().absolutePath();
557 }
558
559 QStringList userList =
560 QFileDialog::getOpenFileNames(nullptr, tr("Select one or more input files"),
561 startFile,
562 filterForFormat(idx));
563 if (!userList.empty()) {
564 babelData_.inputBrowse_ = userList[0];
565 babelData_.inputFileNames_ = userList;
566 QString str;
567 for (int i=0; i<babelData_.inputFileNames_.size(); i++) {
568 if (i != 0) {
569 str += ", ";
570 }
571 str += "\"" + babelData_.inputFileNames_[i] + "\"";
572 }
573 ui_.inputFileNameText->setText(str);
574 }
575 }
576
577 //------------------------------------------------------------------------
browseOutputFile()578 void MainWindow::browseOutputFile()
579 {
580 int idx = currentComboFormatIndex(ui_.outputFormatCombo);
581 QString startFile = babelData_.outputFileName_.length() == 0 ? babelData_.outputBrowse_ : babelData_.outputFileName_;
582 QFileInfo finfo(startFile);
583 if (!finfo.isDir() && (!filterForFormatIncludes(idx, finfo.suffix()))) {
584 startFile = finfo.dir().absolutePath();
585 }
586
587 QString str =
588 QFileDialog::getSaveFileName(nullptr, tr("Output File Name"),
589 startFile,
590 filterForFormat(idx));
591 if (str.length() != 0) {
592 str = ensureExtensionPresent(str, idx);
593 babelData_.outputBrowse_ = str;
594 babelData_.outputFileName_ = str;
595 ui_.outputFileNameText->setText(str);
596 }
597 }
598
599 //------------------------------------------------------------------------
inputFileFormatIndices()600 QList<int> MainWindow::inputFileFormatIndices()
601 {
602 QList<int>indices;
603 for (int i=0; i<formatList_.size(); i++) {
604 if (formatList_[i].isReadSomething() && formatList_[i].isFileFormat()) {
605 indices<<i;
606 }
607 }
608 return indices;
609 }
610
611 //------------------------------------------------------------------------
inputDeviceFormatIndices()612 QList<int> MainWindow::inputDeviceFormatIndices()
613 {
614 QList<int>indices;
615 for (int i=0; i<formatList_.size(); i++) {
616 if (formatList_[i].isReadSomething() && formatList_[i].isDeviceFormat()) {
617 indices<<i;
618 }
619 }
620 return indices;
621 }
622
623 //------------------------------------------------------------------------
outputFileFormatIndices()624 QList<int> MainWindow::outputFileFormatIndices()
625 {
626 QList<int>indices;
627 for (int i=0; i<formatList_.size(); i++) {
628 if (formatList_[i].isWriteSomething() && formatList_[i].isFileFormat()) {
629 indices<<i;
630 }
631 }
632 return indices;
633 }
634
635 //------------------------------------------------------------------------
outputDeviceFormatIndices()636 QList<int> MainWindow::outputDeviceFormatIndices()
637 {
638 QList<int>indices;
639 for (int i=0; i<formatList_.size(); i++) {
640 if (formatList_[i].isWriteSomething() && formatList_[i].isDeviceFormat()) {
641 indices<<i;
642 }
643 }
644 return indices;
645 }
646
647 //------------------------------------------------------------------------
loadFormats()648 void MainWindow::loadFormats()
649 {
650 if (!FormatLoad().getFormats(formatList_)) {
651 QMessageBox::information(nullptr, QString(appName),
652 tr("Error reading format configuration. "
653 "Check that the backend program \"gpsbabel\" is properly installed "
654 "and is in the current PATH\n\n"
655 "This program cannot continue."));
656 exit(1);
657 }
658 if (inputFileFormatIndices().empty() ||
659 inputDeviceFormatIndices().empty() ||
660 outputFileFormatIndices().empty() ||
661 outputDeviceFormatIndices().empty()) {
662 QMessageBox::information(nullptr, QString(appName),
663 tr("Some file/device formats were not found during initialization. "
664 "Check that the backend program \"gpsbabel\" is properly installed "
665 "and is in the current PATH\n\n"
666 "This program cannot continue."));
667 exit(1);
668 }
669 }
670 //------------------------------------------------------------------------
iconIndex(bool a,bool b)671 static int iconIndex(bool a, bool b)
672 {
673 return ((a?1:0)*2) + (b?1:0);
674 }
675
676 //------------------------------------------------------------------------
setIndicatorLights(QLabel * label,const QString & type,int code)677 void MainWindow::setIndicatorLights(QLabel* label, const QString& type, int code)
678 {
679 label->setPixmap(lights_[code]);
680 QString s;
681 switch (code) {
682 default:
683 case 0:
684 s = tr("Input and output formats do not support %1").arg(type);
685 break;
686 case 1:
687 s = tr("Input does not support %1; output format supports %1").arg(type);
688 break;
689 case 2:
690 s = tr("Input format supports %1; output format does not support %1").arg(type);
691 break;
692 case 3:
693 s = tr("Both input and output formats support %1").arg(type);
694 break;
695 }
696 label->setToolTip(s);
697 }
698
699 //------------------------------------------------------------------------
crossCheckInOutFormats()700 void MainWindow::crossCheckInOutFormats()
701 {
702 if (ui_.inputFormatCombo->count() == 0 ||
703 ui_.outputFormatCombo->count() == 0) {
704 // During format/device switch this is true
705 return;
706 }
707 Format ifmt = formatList_[currentComboFormatIndex(ui_.inputFormatCombo)];
708 Format ofmt = formatList_[currentComboFormatIndex(ui_.outputFormatCombo)];
709
710 ui_.xlateWayPtsCk->setEnabled(ifmt.isReadWaypoints() && ofmt.isWriteWaypoints());
711 ui_.xlateTracksCk->setEnabled(ifmt.isReadTracks() && ofmt.isWriteTracks());
712 ui_.xlateRoutesCk->setEnabled(ifmt.isReadRoutes() && ofmt.isWriteRoutes());
713
714 setIndicatorLights(ui_.wayPtLabel, tr("waypoints"), iconIndex(ifmt.isReadWaypoints(), ofmt.isWriteWaypoints()));
715 setIndicatorLights(ui_.trackLabel, tr("tracks"), iconIndex(ifmt.isReadTracks(), ofmt.isWriteTracks()));
716 setIndicatorLights(ui_.routeLabel, tr("routes"), iconIndex(ifmt.isReadRoutes(), ofmt.isWriteRoutes()));
717 }
718
719 //------------------------------------------------------------------------
displayOptionsText(QLineEdit * le,QComboBox * combo,bool isInput)720 void MainWindow::displayOptionsText(QLineEdit* le, QComboBox* combo, bool isInput)
721 {
722 int fidx = combo->itemData(combo->currentIndex()).toInt();
723 if (isInput) {
724 le->setText(MakeOptionsNoLeadingComma(formatList_[fidx].getInputOptions()));
725 } else {
726 le->setText(MakeOptionsNoLeadingComma(formatList_[fidx].getOutputOptions()));
727 }
728
729 }
730
731 //------------------------------------------------------------------------
setComboToFormat(QComboBox * comboBox,const QString & name,bool isFile)732 void MainWindow::setComboToFormat(QComboBox* comboBox, const QString& name, bool isFile)
733 {
734 int fidx = -1;
735 for (int i=0; i<formatList_.size(); i++) {
736 if (formatList_[i].getName() == name &&
737 formatList_[i].isFileFormat() == isFile) {
738 fidx = i;
739 break;
740 }
741 }
742 if (fidx >=0) {
743 for (int i=0; i<comboBox->count(); i++) {
744 if (comboBox->itemData(i).toInt() == fidx) {
745 comboBox->setCurrentIndex(i);
746 break;
747 }
748 }
749 }
750 }
751
752 //------------------------------------------------------------------------
formatSupportsUSB(const QString & format)753 bool MainWindow::formatSupportsUSB(const QString& format)
754 {
755 return (format == "garmin" || format == "delbin");
756 }
757
758 //------------------------------------------------------------------------
formatSupportsSerial(const QString & format)759 bool MainWindow::formatSupportsSerial(const QString& format)
760 {
761 return (format != "delbin");
762 }
763
764 //------------------------------------------------------------------------
inputFormatChanged(int comboIdx)765 void MainWindow::inputFormatChanged(int comboIdx)
766 {
767 if (fmtChgInterlock_) {
768 return;
769 }
770 int fidx = ui_.inputFormatCombo->itemData(comboIdx).toInt();
771 ui_.inputOptionsBtn->setEnabled(!formatList_[fidx].getInputOptions().empty());
772 displayOptionsText(ui_.inputOptionsText, ui_.inputFormatCombo, true);
773 crossCheckInOutFormats();
774
775 if (ui_.inputFileOptBtn->isChecked()) {
776 babelData_.inputFileFormat_ =formatList_[fidx].getName();
777 } else {
778 babelData_.inputDeviceFormat_ = formatList_[fidx].getName();
779 }
780
781 loadInputDeviceNameCombo(formatList_[fidx].getName());
782 }
783
784 //------------------------------------------------------------------------
outputFormatChanged(int comboIdx)785 void MainWindow::outputFormatChanged(int comboIdx)
786 {
787 if (fmtChgInterlock_) {
788 return;
789 }
790 int fidx = ui_.outputFormatCombo->itemData(comboIdx).toInt();
791 ui_.outputOptionsBtn->setEnabled(!formatList_[fidx].getOutputOptions().empty());
792 displayOptionsText(ui_.outputOptionsText, ui_.outputFormatCombo, false);
793 crossCheckInOutFormats();
794
795 if (ui_.outputFileOptBtn->isChecked()) {
796 babelData_.outputFileFormat_ =formatList_[fidx].getName();
797 } else if (ui_.outputDeviceOptBtn->isChecked()) {
798 babelData_.outputDeviceFormat_ = formatList_[fidx].getName();
799 }
800
801 loadOutputDeviceNameCombo(formatList_[fidx].getName());
802 }
803
804 //------------------------------------------------------------------------
inputOptionButtonClicked()805 void MainWindow::inputOptionButtonClicked()
806 {
807 int fidx = currentComboFormatIndex(ui_.inputFormatCombo);
808 if (formatList_[fidx].getInputOptionsRef()->empty()) {
809 QMessageBox::information
810 (nullptr, appName,
811 tr("There are no input options for format \"%1\"").arg(formatList_[fidx].getDescription()));
812 } else {
813 OptionsDlg optionDlg(nullptr,
814 formatList_[fidx].getName(),
815 formatList_[fidx].getInputOptionsRef(),
816 formatList_[fidx].getHtml());
817 optionDlg.setWindowTitle(QString(appName) + " - " + tr("Options for %1").arg(formatList_[fidx].getName()));
818 optionDlg.exec();
819 displayOptionsText(ui_.inputOptionsText, ui_.inputFormatCombo, true);
820 }
821 }
822
823 //------------------------------------------------------------------------
outputOptionButtonClicked()824 void MainWindow::outputOptionButtonClicked()
825 {
826 int fidx = currentComboFormatIndex(ui_.outputFormatCombo);
827 if (formatList_[fidx].getOutputOptionsRef()->empty()) {
828 QMessageBox::information
829 (nullptr, appName,
830 tr("There are no output options for format \"%1\"").arg(formatList_[fidx].getDescription()));
831 } else {
832 OptionsDlg optionDlg(nullptr,
833 formatList_[fidx].getName(),
834 formatList_[fidx].getOutputOptionsRef(),
835 formatList_[fidx].getHtml());
836 optionDlg.setWindowTitle(QString(appName) + " - " + tr("Options for %1").arg(formatList_[fidx].getName()));
837 optionDlg.exec();
838 displayOptionsText(ui_.outputOptionsText, ui_.outputFormatCombo, false);
839 }
840 }
841
842
843
844 //------------------------------------------------------------------------
isOkToGo()845 bool MainWindow::isOkToGo()
846 {
847 if (!((ui_.xlateWayPtsCk->isChecked() && ui_.xlateWayPtsCk->isEnabled()) ||
848 (ui_.xlateRoutesCk->isChecked() && ui_.xlateRoutesCk->isEnabled()) ||
849 (ui_.xlateTracksCk->isChecked() && ui_.xlateTracksCk->isEnabled()))) {
850 QMessageBox::information(nullptr, QString(appName), tr("No valid waypoints/routes/tracks translation specified"));
851 return false;
852 }
853
854 // Paper over what didn't happen in inputBrowse() if the user edited
855 // the filename fields directly.
856 if ((babelData_.inputType_ == BabelData::fileType_) &&
857 (babelData_.inputFileNames_.empty()) &&
858 (!ui_.inputFileNameText->text().isEmpty())) {
859 babelData_.inputFileNames_ << ui_.inputFileNameText->text();
860 }
861 if ((babelData_.outputType_ == BabelData::fileType_) &&
862 (babelData_.outputFileName_.size() == 0) &&
863 (!ui_.outputFileNameText->text().isEmpty())) {
864 babelData_.outputFileName_ = ui_.outputFileNameText->text();
865 }
866
867 if ((babelData_.inputType_ == BabelData::fileType_) &&
868 (babelData_.inputFileNames_.empty())) {
869 QMessageBox::information(nullptr, QString(appName), tr("No input file specified"));
870 return false;
871 }
872
873 if (babelData_.outputType_ == BabelData::noType_ && babelData_.previewGmap_) {
874 }
875 if (babelData_.outputType_ == BabelData::noType_ && !babelData_.previewGmap_) {
876 QMessageBox::information(nullptr, QString(appName), tr("No valid output specified"));
877 return false;
878 }
879 if (babelData_.outputType_ == BabelData::fileType_ &&
880 babelData_.outputFileName_.length() == 0) {
881 QMessageBox::information(nullptr, QString(appName), tr("No output file specified"));
882 return false;
883 }
884 return true;
885 }
886
887 //------------------------------------------------------------------------
runGpsbabel(const QStringList & args,QString & errorString,QString & outputString)888 bool MainWindow::runGpsbabel(const QStringList& args, QString& errorString,
889 QString& outputString)
890 {
891 auto* proc = new QProcess(nullptr);
892 QString name = "gpsbabel";
893 proc->start(QApplication::applicationDirPath() + '/' + name, args);
894 auto* waitDlg = new ProcessWaitDialog(nullptr, proc);
895
896 if (proc->state() == QProcess::NotRunning) {
897 errorString = QString(tr("Process \"%1\" did not start")).arg(name);
898 return false;
899 }
900
901 waitDlg->show();
902 waitDlg->exec();
903 int exitCode = -1;
904 bool retStatus = false;
905 if (waitDlg->getExitedNormally()) {
906 exitCode = waitDlg->getExitCode();
907 if (exitCode == 0) {
908 retStatus = true;
909 } else {
910 errorString =
911 QString(tr("Process exited unsuccessfully with code %1"))
912 .arg(exitCode);
913 retStatus = false;
914 }
915 } else {
916 retStatus = false;
917 errorString = waitDlg->getErrorString();
918 }
919 outputString = waitDlg->getOutputString();
920 delete proc;
921 delete waitDlg;
922 return retStatus;
923 }
924
925 //------------------------------------------------------------------------
formatIndexFromName(bool isFile,const QString & nm)926 int MainWindow::formatIndexFromName(bool isFile, const QString& nm)
927 {
928 for (int i= 0; i<formatList_.size(); i++) {
929 if (nm == formatList_[i].getName() && formatList_[i].isFileFormat() == isFile) {
930 return i;
931 }
932 }
933 return 0;
934 }
935
936 //------------------------------------------------------------------------
charSetFromCombo(QComboBox * combo)937 QString MainWindow::charSetFromCombo(QComboBox* combo)
938 {
939 int i = combo->itemData((combo->currentIndex())).toInt();
940 return (i >=0) ? charSets_[i] : QString();
941 }
942
943 //------------------------------------------------------------------------
setComboToCharSet(QComboBox * combo,const QString & cset)944 void MainWindow::setComboToCharSet(QComboBox* combo, const QString& cset)
945 {
946 for (int i=0; i<charSets_.size(); i++) {
947 if (charSets_[i] == cset) {
948 combo->setCurrentIndex(i+1); // first index is default;
949 }
950 }
951 }
952 //------------------------------------------------------------------------
applyActionX()953 void MainWindow::applyActionX()
954 {
955 getWidgetValues();
956 if (!isOkToGo()) {
957 return;
958 }
959
960 QStringList args;
961
962 if (babelData_.debugLevel_ >=0) {
963 args << QString("-D%1").arg(babelData_.debugLevel_);
964 }
965 if (babelData_.synthShortNames_) {
966 args << "-s";
967 }
968
969 Format ifmt = formatList_[currentComboFormatIndex(ui_.inputFormatCombo)];
970 Format ofmt = formatList_[currentComboFormatIndex(ui_.outputFormatCombo)];
971
972 if (babelData_.xlateWayPts_ && ifmt.isReadWaypoints() && ofmt.isWriteWaypoints()) {
973 args << "-w";
974 }
975 if (babelData_.xlateRoutes_ && ifmt.isReadRoutes() && ofmt.isWriteRoutes()) {
976 args << "-r";
977 }
978 if (babelData_.xlateTracks_ && ifmt.isReadTracks() && ofmt.isWriteTracks()) {
979 args << "-t";
980 }
981
982 // Input type, with options
983 bool iisFile = (babelData_.inputType_ == BabelData::fileType_);
984 int fidx = formatIndexFromName(iisFile, iisFile ?
985 babelData_.inputFileFormat_ : babelData_.inputDeviceFormat_);
986 args << "-i";
987 args << (formatList_[fidx].getName() + MakeOptions(formatList_[fidx].getInputOptions()));
988
989 // Input file(s) or device
990 int read_use_count = 0;
991 if (babelData_.inputType_ == BabelData::fileType_) {
992 for (int i=0; i<babelData_.inputFileNames_.size(); i++) {
993 args << "-f" << babelData_.inputFileNames_[i];
994 read_use_count++;
995 }
996 } else {
997 args << "-f" << babelData_.inputDeviceName_;
998 read_use_count++;
999 }
1000 formatList_[fidx].bumpReadUseCount(read_use_count);
1001
1002 // --- Filters!
1003 args << filterData_.getAllFilterStrings();
1004
1005 // Output type, with options
1006 if (babelData_.outputType_ != BabelData::noType_) {
1007 bool outIsFile = (babelData_.outputType_ == BabelData::fileType_);
1008 fidx = formatIndexFromName(outIsFile, (outIsFile ?
1009 babelData_.outputFileFormat_ : babelData_.outputDeviceFormat_));
1010 args << "-o";
1011 args << (formatList_[fidx].getName() + MakeOptions(formatList_[fidx].getOutputOptions()));
1012
1013 // output file or device option
1014 if (outIsFile) {
1015 if (babelData_.outputFileName_ != "") {
1016 args << "-F" << babelData_.outputFileName_;
1017 }
1018 } else if (babelData_.outputType_ == BabelData::deviceType_) {
1019 args << "-F" << babelData_.outputDeviceName_;
1020 }
1021 // GUI only ever writes a single file at a time.
1022 formatList_[fidx].bumpWriteUseCount(1);
1023 }
1024
1025 // Now output for preview in google maps
1026 QString tempName;
1027 if (babelData_.previewGmap_) {
1028 QTemporaryFile ftemp;
1029 ftemp.open();
1030 tempName = ftemp.fileName();
1031 ftemp.close();
1032
1033 // Ideally, expost this in the UI. For now, just split the track
1034 // if we've no recorded fixes for > 5 mins and we've moved > 300 meters.
1035 //args << "-x";
1036 //args << "track,pack,sdistance=0.3k,split=5m";
1037
1038 args << "-o";
1039 args << "gpx";
1040 args << "-F" << tempName;
1041 }
1042
1043 ui_.outputWindow->clear();
1044 ui_.outputWindow->appendPlainText("gpsbabel " + args.join(" "));
1045
1046 QString errorString;
1047 QString outputString;
1048 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1049 bool x = runGpsbabel(args, errorString, outputString);
1050 QApplication::restoreOverrideCursor();
1051
1052 ui_.outputWindow->appendPlainText(outputString);
1053 if (x) {
1054 ui_.outputWindow->appendPlainText(tr("Translation successful"));
1055 if (babelData_.previewGmap_) {
1056 this->hide();
1057 GMapDialog dlg(nullptr, tempName, babelData_.debugLevel_ >=1 ? ui_.outputWindow : nullptr);
1058 dlg.show();
1059 dlg.exec();
1060 QFile(tempName).remove();
1061 this->show();
1062 }
1063 } else {
1064 ui_.outputWindow->appendPlainText(tr("Error running gpsbabel: %1\n").arg(errorString));
1065 }
1066 }
1067
1068 //------------------------------------------------------------------------
closeActionX()1069 void MainWindow::closeActionX()
1070 {
1071 QDateTime wt= upgrade->getUpgradeWarningTime();
1072 if (wt.isValid()) {
1073 babelData_.upgradeCheckTime_ = wt;
1074 }
1075 babelData_.runCount_++;
1076
1077 QDateTime now = QDateTime::currentDateTime();
1078 if ((babelData_.runCount_ == 1) ||
1079 ((babelData_.runCount_ > 5) && (babelData_.donateSplashed_.daysTo(now) > 30))) {
1080 Donate donate(nullptr);
1081 if (babelData_.donateSplashed_.date() == QDate(2010,1,1)) {
1082 donate.showNever(false);
1083 }
1084 donate.exec();
1085 babelData_.donateSplashed_ = now;
1086 }
1087 saveSettings();
1088 delete upgrade;
1089 upgrade = nullptr;
1090 qApp->exit(0);
1091 }
1092
1093 //------------------------------------------------------------------------
closeEvent(QCloseEvent *)1094 void MainWindow::closeEvent(QCloseEvent* /*event*/)
1095 {
1096 closeActionX();
1097 }
1098
1099 //------------------------------------------------------------------------
donateActionX()1100 void MainWindow::donateActionX()
1101 {
1102 QDesktopServices::openUrl(QString("https://www.gpsbabel.org/contribute.html?gbversion=" VERSION));
1103 }
1104
1105 //------------------------------------------------------------------------
visitWebsiteActionX()1106 void MainWindow::visitWebsiteActionX()
1107 {
1108 QDesktopServices::openUrl(QString("https://www.gpsbabel.org"));
1109 }
1110
1111 //------------------------------------------------------------------------
dragEnterEvent(QDragEnterEvent * event)1112 void MainWindow::dragEnterEvent(QDragEnterEvent* event)
1113 {
1114 event->acceptProposedAction();
1115 }
1116
dropEvent(QDropEvent * event)1117 void MainWindow::dropEvent(QDropEvent* event)
1118 {
1119 foreach (QString format, event->mimeData()->formats()) {
1120 if (format == "text/uri-list") {
1121 QList<QUrl> urlList = event->mimeData()->urls();
1122 babelData_.inputFileNames_.clear();
1123 for (int i = 0; i < urlList.size(); ++i) {
1124 QFileInfo file_info(urlList.at(i).toLocalFile());
1125 QString name = file_info.filePath();
1126 QString ext = file_info.suffix();
1127
1128 QString fmt = getFormatNameForExtension(ext);
1129 setComboToFormat(ui_.inputFormatCombo, fmt, true);
1130 ui_.inputFileNameText->setText(name);
1131 babelData_.inputFileNames_ << ui_.inputFileNameText->text();
1132 event->acceptProposedAction();
1133 }
1134 }
1135 }
1136 }
1137 //------------------------------------------------------------------------
setComboToDevice(QComboBox * comboBox,const QString & name)1138 void MainWindow::setComboToDevice(QComboBox* comboBox, const QString& name)
1139 {
1140 for (int i=0; i<comboBox->count(); i++) {
1141 if (comboBox->itemText(i) == name) {
1142 comboBox->setCurrentIndex(i);
1143 break;
1144 }
1145 }
1146 }
1147
1148 //------------------------------------------------------------------------
saveSettings()1149 void MainWindow::saveSettings()
1150 {
1151 getWidgetValues();
1152
1153 QSettings settings;
1154 babelData_.saveSettings(settings);
1155 for (int i=0; i<formatList_.size(); i++) {
1156 formatList_[i].saveSettings(settings);
1157 }
1158 for (int i=0; i<filterData_.filters.size(); i++) {
1159 filterData_.filters[i]->saveSettings(settings);
1160 }
1161 }
1162
1163 //------------------------------------------------------------------------
restoreSettings()1164 void MainWindow::restoreSettings()
1165 {
1166 QSettings settings;
1167 babelData_.restoreSettings(settings);
1168 for (int i=0; i<formatList_.size(); i++) {
1169 formatList_[i].restoreSettings(settings);
1170 }
1171
1172 for (int i=0; i<filterData_.filters.size(); i++) {
1173 filterData_.filters[i]->restoreSettings(settings);
1174 }
1175
1176 setWidgetValues();
1177 }
1178
1179 //------------------------------------------------------------------------
resetFormatDefaults()1180 void MainWindow::resetFormatDefaults()
1181 {
1182 int ret = QMessageBox::warning
1183 (this, QString(appName),
1184 tr("Are you sure you want to reset all format options to default values?"),
1185 QMessageBox::Yes | QMessageBox::No);
1186 if (ret == QMessageBox::Yes) {
1187 for (int i=0; i<formatList_.size(); i++) {
1188 formatList_[i].setToDefault();
1189 }
1190 displayOptionsText(ui_.inputOptionsText, ui_.inputFormatCombo, true);
1191 displayOptionsText(ui_.outputOptionsText, ui_.outputFormatCombo, false);
1192 }
1193 }
1194
1195 //------------------------------------------------------------------------
moreOptionButtonClicked()1196 void MainWindow::moreOptionButtonClicked()
1197 {
1198 AdvDlg advDlg(nullptr, babelData_.synthShortNames_,
1199 babelData_.previewGmap_, babelData_.debugLevel_);
1200 connect(advDlg.formatButton(), SIGNAL(clicked()),
1201 this, SLOT(resetFormatDefaults()));
1202 advDlg.exec();
1203 }
1204 //------------------------------------------------------------------------
aboutActionX()1205 void MainWindow::aboutActionX()
1206 {
1207 AboutDlg aboutDlg(nullptr, babelVersion_, QString(appName) + QString(" " VERSION), babelData_.installationUuid_);
1208 aboutDlg.setWindowTitle(tr("About %1").arg(appName));
1209 aboutDlg.exec();
1210 }
1211
1212 //------------------------------------------------------------------------
upgradeCheckActionX()1213 void MainWindow::upgradeCheckActionX()
1214 {
1215 upgrade->checkForUpgrade(babelVersion_,
1216 QDateTime(QDate(2000, 1, 1), QTime(0, 0)),
1217 allowBetaUpgrades());
1218 }
1219
1220 //------------------------------------------------------------------------
preferencesActionX()1221 void MainWindow::preferencesActionX()
1222 {
1223 Preferences preferences(nullptr, formatList_, babelData_);
1224 preferences.exec();
1225
1226 // We may have changed the list of displayed formats. Resynchronize.
1227 setWidgetValues();
1228 }
1229
1230
1231 //------------------------------------------------------------------------
helpActionX()1232 void MainWindow::helpActionX()
1233 {
1234 ShowHelp("index.html");
1235 }
1236 //------------------------------------------------------------------------
filtersClicked()1237 void MainWindow::filtersClicked()
1238 {
1239 FilterDialog dlg(nullptr, filterData_);
1240 dlg.runDialog();
1241 updateFilterStatus();
1242 }
1243
1244
1245 //------------------------------------------------------------------------
updateFilterStatus()1246 void MainWindow::updateFilterStatus()
1247 {
1248 bool filterActive = !filterData_.getAllFilterStrings().empty();
1249 ui_.filterStatus->setEnabled(filterActive);
1250 if (filterActive) {
1251 ui_.filterStatus->setToolTip(tr("One or more data filters are active"));
1252 } else {
1253 ui_.filterStatus->setToolTip(tr("No data filters are active"));
1254 }
1255 }
1256 //------------------------------------------------------------------------
setWidgetValues()1257 void MainWindow::setWidgetValues()
1258 {
1259 if (babelData_.inputType_ == BabelData::fileType_) {
1260 ui_.inputFileOptBtn->setChecked(true);
1261 inputFileOptBtnClicked();
1262 setComboToFormat(ui_.inputFormatCombo, babelData_.inputFileFormat_, true);
1263 ui_.inputStackedWidget->setCurrentWidget(ui_.inputFilePage);
1264 } else {
1265 ui_.inputDeviceOptBtn->setChecked(true);
1266 inputDeviceOptBtnClicked();
1267 setComboToFormat(ui_.inputFormatCombo, babelData_.inputDeviceFormat_, false);
1268 loadInputDeviceNameCombo(babelData_.inputDeviceFormat_);
1269 ui_.inputStackedWidget->setCurrentWidget(ui_.inputDevicePage);
1270 }
1271 setComboToDevice(ui_.inputDeviceNameCombo, babelData_.inputDeviceName_);
1272
1273 if (babelData_.outputType_ == BabelData::fileType_) {
1274 ui_.outputFileOptBtn->setChecked(true);
1275 outputFileOptBtnClicked();
1276 setComboToFormat(ui_.outputFormatCombo, babelData_.outputFileFormat_, true);
1277 ui_.outputStackedWidget->setCurrentWidget(ui_.outputFilePage);
1278 } else if (babelData_.outputType_ == BabelData::deviceType_) {
1279 ui_.outputDeviceOptBtn->setChecked(true);
1280 outputDeviceOptBtnClicked();
1281 setComboToFormat(ui_.outputFormatCombo, babelData_.outputDeviceFormat_, false);
1282 loadOutputDeviceNameCombo(babelData_.outputDeviceFormat_);
1283 ui_.outputStackedWidget->setCurrentWidget(ui_.outputDevicePage);
1284 } else {
1285 ui_.outputFileOptBtn->setChecked(false);
1286 ui_.outputDeviceOptBtn->setChecked(false);
1287 setComboToFormat(ui_.outputFormatCombo, babelData_.outputFileFormat_, true);
1288 ui_.outputStackedWidget->setCurrentWidget(ui_.outputFilePage);
1289 ui_.outputFilePage->setDisabled(true);
1290 }
1291
1292 setComboToDevice(ui_.outputDeviceNameCombo, babelData_.outputDeviceName_);
1293
1294 ui_.xlateWayPtsCk->setChecked(babelData_.xlateWayPts_);
1295 ui_.xlateTracksCk->setChecked(babelData_.xlateTracks_);
1296 ui_.xlateRoutesCk->setChecked(babelData_.xlateRoutes_);
1297
1298 crossCheckInOutFormats();
1299 displayOptionsText(ui_.inputOptionsText, ui_.inputFormatCombo, true);
1300 displayOptionsText(ui_.outputOptionsText, ui_.outputFormatCombo, false);
1301 updateFilterStatus();
1302 }
1303
1304 //------------------------------------------------------------------------
getWidgetValues()1305 void MainWindow::getWidgetValues()
1306 {
1307 int comboIdx = ui_.inputFormatCombo->currentIndex();
1308 int fidx = ui_.inputFormatCombo->itemData(comboIdx).toInt();
1309 if (ui_.inputFileOptBtn->isChecked()) {
1310 babelData_.inputType_ = BabelData::fileType_;
1311 babelData_.inputFileFormat_ =formatList_[fidx].getName();
1312 } else {
1313 babelData_.inputType_ = BabelData::deviceType_;
1314 babelData_.inputDeviceFormat_ =formatList_[fidx].getName();
1315 }
1316 babelData_.inputDeviceName_ = ui_.inputDeviceNameCombo->currentText();
1317
1318 comboIdx = ui_.outputFormatCombo->currentIndex();
1319 fidx = ui_.outputFormatCombo->itemData(comboIdx).toInt();
1320 if (ui_.outputFileOptBtn->isChecked()) {
1321 babelData_.outputType_ = BabelData::fileType_;
1322 babelData_.outputFileFormat_ =formatList_[fidx].getName();
1323 } else if (ui_.outputDeviceOptBtn->isChecked()) {
1324 babelData_.outputType_ = BabelData::deviceType_;
1325 babelData_.outputDeviceFormat_ =formatList_[fidx].getName();
1326 } else {
1327 babelData_.outputType_ = BabelData::noType_;
1328 }
1329 babelData_.outputDeviceName_ = ui_.outputDeviceNameCombo->currentText();
1330
1331 babelData_.xlateWayPts_ = ui_.xlateWayPtsCk->isChecked();
1332 babelData_.xlateTracks_ = ui_.xlateTracksCk->isChecked();
1333 babelData_.xlateRoutes_ = ui_.xlateRoutesCk->isChecked();
1334 }
1335
1336 // This could be made faster, but any attempt to do so would have to be
1337 // careful about disabled formats. As it was written to be handled by a
1338 // drag response, performance is hardly critical.
1339 // It's also kind of dumb to return the name which SetCombo then looks up,
1340 // but there's not a 1:1 correlation between offsets in the combo box and
1341 // in the list of formats.
getFormatNameForExtension(const QString & ext)1342 QString MainWindow::getFormatNameForExtension(const QString& ext)
1343 {
1344 for (int i = 0; i < formatList_.size(); i++) {
1345 QStringList extensions = formatList_[i].getExtensions();
1346 for (int j = 0; j < extensions.size(); ++j) {
1347 if (extensions[j] == ext) {
1348 return formatList_[i].getName();
1349 }
1350 }
1351 }
1352 return nullptr;
1353 }
1354