FlightGear next
SetupRootDialog.cxx
Go to the documentation of this file.
1// SetupRootDialog.cxx - part of GUI launcher using Qt5
2//
3// Written by James Turner, started December 2014.
4//
5// Copyright (C) 2014 James Turner <zakalawe@mac.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, but
13// 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, USA.
20
21#include "config.h"
22
23#include "SetupRootDialog.hxx"
24
25#include <QFileDialog>
26#include <QDesktopServices>
27#include <QDir>
28#include <QFileInfo>
29#include <QMessageBox>
30#include <QSettings>
31#include <QDebug>
32#include <QSettings>
33#include <QUrl>
34
35#include "ui_SetupRootDialog.h"
36
37#include <Main/globals.hxx>
38#include <Main/fg_init.hxx>
39#include <Main/options.hxx>
41
42#include "QtLauncher.hxx"
43
45{
46 // return a settings key like fg-root-2018-3-0
47 return QString("fg-root-") + QString(FLIGHTGEAR_VERSION).replace('.', '-');
48}
49
50SetupRootDialog::SetupRootDialog(PromptState prompt) :
51 QDialog(),
52 m_promptState(prompt)
53{
54 m_ui.reset(new Ui::SetupRootDialog);
55 m_ui->setupUi(this);
56
57 connect(m_ui->browseButton, &QPushButton::clicked,
58 this, &SetupRootDialog::onBrowse);
59 connect(m_ui->downloadButton, &QPushButton::clicked,
60 this, &SetupRootDialog::onDownload);
61 connect(m_ui->buttonBox, &QDialogButtonBox::rejected,
62 this, &QDialog::reject);
63 connect(m_ui->useDefaultsButton, &QPushButton::clicked,
64 this, &SetupRootDialog::onUseDefaults);
65
66 // decide if the 'use defaults' button should be enabled or not
67 bool ok = defaultRootAcceptable();
68 m_ui->useDefaultsButton->setEnabled(ok);
69 m_ui->useDefaultLabel->setEnabled(ok);
70
71 m_ui->versionLabel->setText(tr("FlightGear version %1").arg(FLIGHTGEAR_VERSION));
72 m_ui->bigIcon->setPixmap(QPixmap(":/app-icon-large"));
73 updatePromptText();
74}
75
76bool SetupRootDialog::runDialog(bool usingDefaultRoot)
77{
78 SetupRootDialog::PromptState prompt =
79 usingDefaultRoot ? DefaultPathCheckFailed : ExplicitPathCheckFailed;
80 return runDialog(prompt);
81}
82
83bool SetupRootDialog::runDialog(PromptState prompt)
84{
85 // avoid double Apple menu and other weirdness if both Qt and OSG
86 // try to initialise various Cocoa structures.
88
89 SetupRootDialog dlg(prompt);
90 dlg.exec();
91 if (dlg.result() != QDialog::Accepted) {
92 return false;
93 }
94
95 return true;
96}
97
98
100{
101 QSettings settings;
102 QString path = settings.value(rootPathKey()).toString();
104 if (ask || (path == QStringLiteral("!ask"))) {
105 bool ok = runDialog(ManualChoiceRequested);
106 if (!ok) {
108 }
109
110 sgpath = globals->get_fg_root();
112 }
113
114 if (path.isEmpty()) {
116 }
117
118 if (validatePath(path) && validateVersion(path)) {
119 sgpath = SGPath::fromUtf8(path.toStdString());
121 }
122
123 // we have an existing path but it's invalid.
124 // let's see if the default root is acceptable, in which case we will
125 // switch to it. (This gives a more friendly upgrade experience).
126 if (defaultRootAcceptable()) {
128 }
129
130 // okay, we don't have an acceptable FG_DATA anywhere we can find, we
131 // have to ask the user what they want to do.
132 bool ok = runDialog(VersionCheckFailed);
133 if (!ok) {
135 }
136
137 // run dialog sets fg_root, so this
138 // behaviour is safe and correct.
139 sgpath = globals->get_fg_root();
141}
142
144{
145 QSettings settings;
146 // set the option to the magic marker value
147 settings.setValue(rootPathKey(), "!ask");
148}
149
150bool SetupRootDialog::validatePath(QString path)
151{
152 // check assorted files exist in the root location, to avoid any chance of
153 // selecting an incomplete base package. This is probably overkill but does
154 // no harm
155 QStringList files = QStringList()
156 << "version"
157 << "defaults.xml"
158 << "Materials/base/materials-base.xml"
159 << "gui/menubar.xml"
160 << "Timezone/zone.tab";
161
162 QDir d(path);
163 if (!d.exists()) {
164 return false;
165 }
166
167 Q_FOREACH(QString s, files) {
168 if (!d.exists(s)) {
169 return false;
170 }
171 }
172
173 return true;
174}
175
176bool SetupRootDialog::validateVersion(QString path)
177{
178 std::string ver = fgBasePackageVersion(SGPath::fromUtf8(path.toStdString()));
179 return (ver == FLIGHTGEAR_VERSION);
180}
181
182bool SetupRootDialog::defaultRootAcceptable()
183{
185 QString defaultRoot = QString::fromStdString(r.utf8Str());
186 return validatePath(defaultRoot) && validateVersion(defaultRoot);
187}
188
193
194void SetupRootDialog::onBrowse()
195{
196 m_browsedPath = QFileDialog::getExistingDirectory(this,
197 tr("Choose FlightGear data folder"));
198 if (m_browsedPath.isEmpty()) {
199 return;
200 }
201
202 if (!validatePath(m_browsedPath)) {
203 m_promptState = ChoseInvalidLocation;
204 updatePromptText();
205 return;
206 }
207
208 if (!validateVersion(m_browsedPath)) {
209 m_promptState = ChoseInvalidVersion;
210 updatePromptText();
211 return;
212 }
213
214 globals->set_fg_root(m_browsedPath.toStdString());
215
216 QSettings settings;
217 settings.setValue(rootPathKey(), m_browsedPath);
218
219 accept(); // we're done
220}
221
222void SetupRootDialog::onDownload()
223{
224 QString templateUrl = "https://sourceforge.net/projects/flightgear/files/release-%1/FlightGear-%2-data.txz";
225 QString majorMinorVersion = QString("%1.%2").arg(FLIGHTGEAR_MAJOR_VERSION).arg(FLIGHTGEAR_MINOR_VERSION);
226 QUrl downloadUrl(templateUrl.arg(majorMinorVersion).arg(VERSION));
227 QDesktopServices::openUrl(downloadUrl);
228}
229
230void SetupRootDialog::onUseDefaults()
231{
233 m_browsedPath = QString::fromStdString(r.utf8Str());
235 QSettings settings;
236 settings.remove(rootPathKey()); // remove any setting
237 accept();
238}
239
240void SetupRootDialog::updatePromptText()
241{
242 QString t;
243 QString curRoot = QString::fromStdString(globals->get_fg_root().utf8Str());
244 switch (m_promptState) {
245 case DefaultPathCheckFailed:
246 t = tr("This copy of FlightGear does not include the base data files. " \
247 "Please select a suitable folder containing a previously downloaded set of files.");
248 break;
249
250 case ExplicitPathCheckFailed:
251 t = tr("The requested location '%1' does not appear to be a valid set of data files for FlightGear").arg(curRoot);
252 break;
253
254 case VersionCheckFailed:
255 {
256 QString curVer = QString::fromStdString(fgBasePackageVersion(globals->get_fg_root()));
257 t = tr("Detected incompatible version of the data files: version %1 found, but this is FlightGear %2. " \
258 "(At location: '%3') " \
259 "Please install or select a matching set of data files.").arg(curVer).arg(QString::fromLatin1(FLIGHTGEAR_VERSION)).arg(curRoot);
260 break;
261 }
262
263 case ManualChoiceRequested:
264 t = tr("Please select or download a copy of the FlightGear data files.");
265 break;
266
267 case ChoseInvalidLocation:
268 t = tr("The choosen location (%1) does not appear to contain FlightGear data files. Please try another location.").arg(m_browsedPath);
269 break;
270
271 case ChoseInvalidVersion:
272 {
273 QString curVer = QString::fromStdString(fgBasePackageVersion(m_browsedPath.toStdString()));
274 t = tr("The choosen location (%1) contains files for version %2, but this is FlightGear %3. " \
275 "Please update or try another location").arg(m_browsedPath).arg(curVer).arg(QString::fromLatin1(FLIGHTGEAR_VERSION));
276 break;
277 }
278 }
279
280 m_ui->promptText->setText(t);
281}
282
const SGPath & get_fg_root() const
Definition globals.hxx:189
void set_fg_root(const SGPath &root)
Definition globals.cxx:265
static flightgear::SetupRootResult restoreUserSelectedRoot(SGPath &path)
static QString rootPathKey()
static bool runDialog(bool usingDefaultRoot)
static void askRootOnNextLaunch()
SGPath platformDefaultRoot() const
Definition options.cxx:3483
static Options * sharedInstance()
Definition options.cxx:2345
static void setPoseAsStandaloneApp(bool b)
string fgBasePackageVersion(const SGPath &base_path)
Definition fg_init.cxx:156
FGGlobals * globals
Definition globals.cxx:142
bool checkKeyboardModifiersForSettingFGRoot()