]> git.mxchange.org Git - flightgear.git/blob - src/GUI/PathsDialog.cxx
Code cleanups, code updates and fix at least on (possible) devide-by-zero
[flightgear.git] / src / GUI / PathsDialog.cxx
1 #include "PathsDialog.hxx"
2 #include "ui_PathsDialog.h"
3
4 #include <QSettings>
5 #include <QFileDialog>
6 #include <QMessageBox>
7 #include <QDebug>
8 #include <QProcess>
9
10 #include "CatalogListModel.hxx"
11 #include "AddCatalogDialog.hxx"
12 #include "AircraftModel.hxx"
13 #include "QtLauncher_private.hxx"
14
15 #include <Main/options.hxx>
16 #include <Main/globals.hxx>
17 #include <Network/HTTPClient.hxx>
18
19 AddOnsPage::AddOnsPage(QWidget *parent, simgear::pkg::RootRef root) :
20     QWidget(parent),
21     m_ui(new Ui::AddOnsPage),
22     m_packageRoot(root)
23 {
24     m_ui->setupUi(this);
25     
26     m_catalogsModel = new CatalogListModel(this, m_packageRoot);
27     m_ui->catalogsList->setModel(m_catalogsModel);
28
29  // enable drag-drop to re-order the paths
30     m_ui->sceneryPathsList->setDragEnabled(true);
31     m_ui->sceneryPathsList->setDragDropMode(QAbstractItemView::InternalMove);
32     m_ui->sceneryPathsList->setDropIndicatorShown(true);
33
34     m_ui->aircraftPathsList->setDragEnabled(true);
35     m_ui->aircraftPathsList->setDragDropMode(QAbstractItemView::InternalMove);
36     m_ui->aircraftPathsList->setDropIndicatorShown(true);
37
38     connect(m_ui->addCatalog, &QToolButton::clicked,
39             this, &AddOnsPage::onAddCatalog);
40     connect(m_ui->addDefaultCatalogButton, &QPushButton::clicked,
41             this, &AddOnsPage::onAddDefaultCatalog);
42     connect(m_ui->removeCatalog, &QToolButton::clicked,
43             this, &AddOnsPage::onRemoveCatalog);
44             
45     connect(m_ui->addSceneryPath, &QToolButton::clicked,
46             this, &AddOnsPage::onAddSceneryPath);
47     connect(m_ui->removeSceneryPath, &QToolButton::clicked,
48             this, &AddOnsPage::onRemoveSceneryPath);
49
50     connect(m_ui->addAircraftPath, &QToolButton::clicked,
51             this, &AddOnsPage::onAddAircraftPath);
52     connect(m_ui->removeAircraftPath, &QToolButton::clicked,
53             this, &AddOnsPage::onRemoveAircraftPath);
54
55     connect(m_ui->changeDownloadDir, &QPushButton::clicked,
56             this, &AddOnsPage::onChangeDownloadDir);
57
58     connect(m_ui->clearDownloadDir, &QPushButton::clicked,
59             this, &AddOnsPage::onClearDownloadDir);
60
61     connect(m_ui->changeDataDir, &QPushButton::clicked,
62             this, &AddOnsPage::onChangeDataDir);
63
64     QSettings settings;
65             
66     QStringList sceneryPaths = settings.value("scenery-paths").toStringList();
67     m_ui->sceneryPathsList->addItems(sceneryPaths);
68
69     QStringList aircraftPaths = settings.value("aircraft-paths").toStringList();
70     m_ui->aircraftPathsList->addItems(aircraftPaths);
71
72     QVariant downloadDir = settings.value("download-dir");
73     if (downloadDir.isValid()) {
74         m_downloadDir = downloadDir.toString();
75     }
76
77     updateUi();
78 }
79
80 AddOnsPage::~AddOnsPage()
81 {
82     delete m_ui;
83 }
84
85 void AddOnsPage::onAddSceneryPath()
86 {
87     QString path = QFileDialog::getExistingDirectory(this, tr("Choose scenery folder"));
88     if (!path.isEmpty()) {
89         m_ui->sceneryPathsList->addItem(path);
90         saveSceneryPaths();
91     }
92
93     // work around a Qt OS-X bug - this dialog is ending ordered
94     // behind the main settings dialog (consequence of modal-dialog
95     // showing a modla dialog showing a modial dialog)
96     window()->raise();
97 }
98
99 void AddOnsPage::onRemoveSceneryPath()
100 {
101     if (m_ui->sceneryPathsList->currentItem()) {
102         delete m_ui->sceneryPathsList->currentItem();
103         saveSceneryPaths();
104     }
105 }
106
107 void AddOnsPage::onAddAircraftPath()
108 {
109     QString path = QFileDialog::getExistingDirectory(this, tr("Choose aircraft folder"));
110     if (!path.isEmpty()) {
111         // the user might add a directory containing an 'Aircraft' subdir. Let's attempt
112         // to check for that case and handle it gracefully.
113         bool pathOk = false;
114
115         if (AircraftItemModel::isCandidateAircraftPath(path)) {
116             m_ui->aircraftPathsList->addItem(path);
117             pathOk = true;
118         } else {
119             // no aircraft in speciied path, look for Aircraft/ subdir
120             QDir d(path);
121             if (d.exists("Aircraft")) {
122                 QString p2 = d.filePath("Aircraft");
123                 if (AircraftItemModel::isCandidateAircraftPath(p2)) {
124                     m_ui->aircraftPathsList->addItem(p2);
125                     pathOk = true;
126                 }
127             }
128         }
129
130         if (!pathOk) {
131             QMessageBox mb;
132             mb.setText(QString("No aircraft found in the folder '%1' - add anyway?").arg(path));
133             mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
134             mb.setDefaultButton(QMessageBox::No);
135             mb.exec();
136
137             if (mb.result() == QMessageBox::Yes) {
138                 m_ui->aircraftPathsList->addItem(path);
139             }
140         }
141
142         saveAircraftPaths();
143     }
144     // work around a Qt OS-X bug - this dialog is ending ordered
145     // behind the main settings dialog (consequence of modal-dialog
146     // showing a modla dialog showing a modial dialog)
147     window()->raise();
148 }
149
150 void AddOnsPage::onRemoveAircraftPath()
151 {
152     if (m_ui->aircraftPathsList->currentItem()) {
153         delete m_ui->aircraftPathsList->currentItem();
154         saveAircraftPaths();
155     }
156 }
157
158 void AddOnsPage::saveAircraftPaths()
159 {
160     QSettings settings;
161     QStringList paths;
162
163     for (int i=0; i<m_ui->aircraftPathsList->count(); ++i) {
164         paths.append(m_ui->aircraftPathsList->item(i)->text());
165     }
166
167     settings.setValue("aircraft-paths", paths);
168 }
169
170 void AddOnsPage::saveSceneryPaths()
171 {
172     QSettings settings;
173     QStringList paths;
174     for (int i=0; i<m_ui->sceneryPathsList->count(); ++i) {
175         paths.append(m_ui->sceneryPathsList->item(i)->text());
176     }
177
178     settings.setValue("scenery-paths", paths);
179
180     emit sceneryPathsChanged();
181 }
182
183 void AddOnsPage::onAddCatalog()
184 {
185     QScopedPointer<AddCatalogDialog> dlg(new AddCatalogDialog(this, m_packageRoot));
186     dlg->exec();
187     if (dlg->result() == QDialog::Accepted) {
188         m_catalogsModel->refresh();
189     }
190 }
191
192 void AddOnsPage::onAddDefaultCatalog()
193 {
194     addDefaultCatalog(this);
195
196     m_catalogsModel->refresh();
197     updateUi();
198 }
199
200 void AddOnsPage::addDefaultCatalog(QWidget* pr)
201 {
202     // check it's not a duplicate somehow
203     FGHTTPClient* http = globals->get_subsystem<FGHTTPClient>();
204     if (http->isDefaultCatalogInstalled())
205         return;
206
207     QScopedPointer<AddCatalogDialog> dlg(new AddCatalogDialog(pr, globals->packageRoot()));
208     QUrl url(QString::fromStdString(http->getDefaultCatalogUrl()));
209     dlg->setUrlAndDownload(url);
210     dlg->exec();
211
212 }
213
214 void AddOnsPage::onRemoveCatalog()
215 {
216     QModelIndex mi = m_ui->catalogsList->currentIndex();
217     FGHTTPClient* http = globals->get_subsystem<FGHTTPClient>();
218
219     if (mi.isValid()) {
220         QString s = QString("Remove aircraft hangar '%1'? All installed aircraft from this "
221                             "hangar will be removed.");
222         QString pkgId = mi.data(CatalogIdRole).toString();
223
224         if (pkgId.toStdString() == http->getDefaultCatalogId()) {
225             s = QString("Remove default aircraft hangar? "
226                         "This hangar contains all the default aircraft included with FlightGear. "
227                         "If you change your mind in the future, click the 'restore' button.");
228         } else {
229             s = s.arg(mi.data(Qt::DisplayRole).toString());
230         }
231
232         QMessageBox mb;
233         mb.setText(s);
234         mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
235         mb.setDefaultButton(QMessageBox::No);
236         mb.exec();
237         
238         if (mb.result() == QMessageBox::Yes) {
239             m_packageRoot->removeCatalogById(pkgId.toStdString());
240         }
241     }
242
243     updateUi();
244 }
245
246 void AddOnsPage::onChangeDownloadDir()
247 {
248     QString path = QFileDialog::getExistingDirectory(this,
249                                                      tr("Choose downloads folder"),
250                                                      m_downloadDir);
251     if (path.isEmpty()) {
252         return; // user cancelled
253     }
254
255     m_downloadDir = path;
256     setDownloadDir();
257 }
258
259 void AddOnsPage::onClearDownloadDir()
260 {
261     // does this need an 'are you sure'?
262     m_downloadDir.clear();
263
264     setDownloadDir();
265 }
266
267 void AddOnsPage::setDownloadDir()
268 {
269     QSettings settings;
270     if (m_downloadDir.isEmpty()) {
271         settings.remove("download-dir");
272     } else {
273         settings.setValue("download-dir", m_downloadDir);
274     }
275
276     if (m_downloadDir.isEmpty()) {
277         flightgear::Options::sharedInstance()->clearOption("download-dir");
278     } else {
279         flightgear::Options::sharedInstance()->setOption("download-dir", m_downloadDir.toStdString());
280     }
281
282     emit downloadDirChanged();
283     updateUi();
284 }
285
286 void AddOnsPage::onChangeDataDir()
287 {
288     QMessageBox mbox(this);
289     mbox.setText(tr("Change the data files used by FlightGear?"));
290     mbox.setInformativeText(tr("FlightGear requires additional files to operate. "
291                                "(Also called the base package, or fg-data) "
292                                "You can restart FlightGear and choose a "
293                                "different data files location, or restore the default setting."));
294     QPushButton* quitButton = mbox.addButton(tr("Restart FlightGear now"), QMessageBox::YesRole);
295     mbox.addButton(QMessageBox::Cancel);
296     mbox.setDefaultButton(QMessageBox::Cancel);
297     mbox.setIconPixmap(QPixmap(":/app-icon-large"));
298
299     mbox.exec();
300     if (mbox.clickedButton() != quitButton) {
301         return;
302     }
303
304     {
305         QSettings settings;
306         // set the option to the magic marker value
307         settings.setValue("fg-root", "!ask");
308     } // scope the ensure settings are written nicely
309
310     QtLauncher::restartTheApp(QStringList());
311 }
312
313 void AddOnsPage::updateUi()
314 {
315     QString s = m_downloadDir;
316     if (s.isEmpty()) {
317         s = QString::fromStdString(flightgear::defaultDownloadDir());
318         s.append(tr(" (default)"));
319         m_ui->clearDownloadDir->setEnabled(false);
320     } else {
321         m_ui->clearDownloadDir->setEnabled(true);
322     }
323
324     QString m = tr("Download location: %1").arg(s);
325     m_ui->downloadLocation->setText(m);
326
327     QString dataLoc;
328     QSettings settings;
329     QString root = settings.value("fg-root").toString();
330     if (root.isNull()) {
331         dataLoc = tr("built-in");
332     } else {
333         dataLoc = root;
334     }
335
336     m_ui->dataLocation->setText(tr("Data location: %1").arg(dataLoc));
337
338
339     FGHTTPClient* http = globals->get_subsystem<FGHTTPClient>();
340     m_ui->addDefaultCatalogButton->setEnabled(!http->isDefaultCatalogInstalled());
341 }