2015-03-07 23:52:03 +00:00
|
|
|
// QtLauncher.cxx - GUI launcher dialog using Qt5
|
|
|
|
//
|
|
|
|
// Written by James Turner, started December 2014.
|
|
|
|
//
|
|
|
|
// Copyright (C) 2014 James Turner <zakalawe@mac.com>
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License as
|
|
|
|
// published by the Free Software Foundation; either version 2 of the
|
|
|
|
// License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful, but
|
|
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
2014-12-26 12:20:51 +00:00
|
|
|
#include "QtLauncher.hxx"
|
|
|
|
|
2016-02-02 20:44:46 +00:00
|
|
|
#include <locale.h>
|
|
|
|
|
2014-12-26 12:20:51 +00:00
|
|
|
// Qt
|
2017-05-16 11:51:46 +00:00
|
|
|
#include <QtGlobal>
|
|
|
|
#include <QString>
|
2014-12-26 12:20:51 +00:00
|
|
|
#include <QProgressDialog>
|
|
|
|
#include <QDir>
|
|
|
|
#include <QFileInfo>
|
|
|
|
#include <QPixmap>
|
|
|
|
#include <QTimer>
|
|
|
|
#include <QDebug>
|
|
|
|
#include <QCompleter>
|
|
|
|
#include <QListView>
|
|
|
|
#include <QSettings>
|
|
|
|
#include <QUrl>
|
|
|
|
#include <QAction>
|
2015-03-05 17:39:37 +00:00
|
|
|
#include <QDateTime>
|
2015-03-06 18:52:06 +00:00
|
|
|
#include <QApplication>
|
2015-10-16 01:05:17 +00:00
|
|
|
#include <QSpinBox>
|
|
|
|
#include <QDoubleSpinBox>
|
2016-08-08 22:13:57 +00:00
|
|
|
#include <QThread>
|
2017-02-20 00:19:13 +00:00
|
|
|
#include <QProcess>
|
2014-12-26 12:20:51 +00:00
|
|
|
|
|
|
|
// Simgear
|
|
|
|
#include <simgear/timing/timestamp.hxx>
|
|
|
|
#include <simgear/props/props_io.hxx>
|
|
|
|
#include <simgear/structure/exception.hxx>
|
2015-03-10 08:30:55 +00:00
|
|
|
#include <simgear/structure/subsystem_mgr.hxx>
|
2014-12-26 12:20:51 +00:00
|
|
|
#include <simgear/misc/sg_path.hxx>
|
2015-08-03 20:53:56 +00:00
|
|
|
#include <simgear/package/Catalog.hxx>
|
|
|
|
#include <simgear/package/Package.hxx>
|
|
|
|
#include <simgear/package/Install.hxx>
|
2017-01-29 15:16:28 +00:00
|
|
|
#include <simgear/debug/logstream.hxx>
|
2014-12-26 12:20:51 +00:00
|
|
|
|
|
|
|
#include <Main/globals.hxx>
|
2016-07-08 08:36:42 +00:00
|
|
|
#include <Main/fg_props.hxx>
|
2014-12-26 12:20:51 +00:00
|
|
|
#include <Navaids/NavDataCache.hxx>
|
2015-10-16 01:05:17 +00:00
|
|
|
#include <Navaids/navrecord.hxx>
|
2015-11-26 16:48:23 +00:00
|
|
|
#include <Navaids/SHPParser.hxx>
|
2017-01-25 20:41:40 +00:00
|
|
|
#include <Airports/airport.hxx>
|
2015-10-16 01:05:17 +00:00
|
|
|
|
2014-12-26 12:20:51 +00:00
|
|
|
#include <Main/options.hxx>
|
2015-03-10 08:30:55 +00:00
|
|
|
#include <Main/fg_init.hxx>
|
2015-03-06 18:52:06 +00:00
|
|
|
#include <Viewer/WindowBuilder.hxx>
|
2015-03-10 08:30:55 +00:00
|
|
|
#include <Network/HTTPClient.hxx>
|
2014-12-26 12:20:51 +00:00
|
|
|
|
2017-02-20 00:19:13 +00:00
|
|
|
#include "LauncherMainWindow.hxx"
|
2017-07-19 18:24:33 +00:00
|
|
|
#include "LaunchConfig.hxx"
|
2017-01-30 07:00:37 +00:00
|
|
|
|
2014-12-26 12:20:51 +00:00
|
|
|
using namespace flightgear;
|
2015-08-03 20:53:56 +00:00
|
|
|
using namespace simgear::pkg;
|
Split flightgear::initApp() to make it usable even without FGGlobals initialized
- Add an optional argument to flightgear::initApp(): doInitQSettings.
This argument defaults to true, preserving initApp()'s behavior in
this respect. If this argument is set to false, FGGlobals doesn't have
to be initialized.
- New function flightgear::initQSettings(), called by
flightgear::initApp() when its 'doInitQSettings' argument is true.
This allows initializing the QSettings exactly when it is needed.
- New function flightgear::checkKeyboardModifiersForSettingFGRoot().
The code it contains used to be run from initApp(), which is
undesirable because:
1) initApp() is not only called at FG initialization (fgMainInit()),
but also from QtMessageBox(), from QtFileDialog::exec() and twice
from Options::setupRoot(). However, checking the Alt and Shift
modifiers to set 'fg-root' in QSettings to the special value
"!ask" only makes sense in fgMainInit(), not in these other
places.
2) This code relies on the QSettings to be set up, and therefore on
FGGlobals. Thus, freeing initApp() of its dependency on FGGlobals
requires splitting this keyboard modifiers checking code out of
initApp().
2016-12-26 20:45:44 +00:00
|
|
|
using std::string;
|
2014-12-26 12:20:51 +00:00
|
|
|
|
|
|
|
namespace { // anonymous namespace
|
|
|
|
|
|
|
|
void initNavCache()
|
|
|
|
{
|
2015-03-19 17:01:38 +00:00
|
|
|
QString baseLabel = QT_TR_NOOP("Initialising navigation data, this may take several minutes");
|
2015-03-08 00:40:22 +00:00
|
|
|
NavDataCache* cache = NavDataCache::createInstance();
|
2014-12-26 12:20:51 +00:00
|
|
|
if (cache->isRebuildRequired()) {
|
2015-03-19 17:01:38 +00:00
|
|
|
QProgressDialog rebuildProgress(baseLabel,
|
2014-12-26 12:20:51 +00:00
|
|
|
QString() /* cancel text */,
|
2016-04-13 14:15:27 +00:00
|
|
|
0, 100, Q_NULLPTR,
|
|
|
|
Qt::Dialog
|
|
|
|
| Qt::CustomizeWindowHint
|
|
|
|
| Qt::WindowTitleHint
|
|
|
|
| Qt::WindowSystemMenuHint
|
|
|
|
| Qt::MSWindowsFixedSizeDialogHint);
|
2014-12-26 12:20:51 +00:00
|
|
|
rebuildProgress.setWindowModality(Qt::WindowModal);
|
|
|
|
rebuildProgress.show();
|
|
|
|
|
2015-03-19 17:01:38 +00:00
|
|
|
NavDataCache::RebuildPhase phase = cache->rebuild();
|
|
|
|
|
|
|
|
while (phase != NavDataCache::REBUILD_DONE) {
|
2014-12-26 12:20:51 +00:00
|
|
|
// sleep to give the rebuild thread more time
|
|
|
|
SGTimeStamp::sleepForMSec(50);
|
2015-03-19 17:01:38 +00:00
|
|
|
phase = cache->rebuild();
|
2015-10-16 01:05:17 +00:00
|
|
|
|
2015-03-19 17:01:38 +00:00
|
|
|
switch (phase) {
|
2016-10-19 11:01:35 +00:00
|
|
|
case NavDataCache::REBUILD_READING_APT_DAT_FILES:
|
|
|
|
rebuildProgress.setLabelText(QT_TR_NOOP("Reading airport data"));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NavDataCache::REBUILD_LOADING_AIRPORTS:
|
|
|
|
rebuildProgress.setLabelText(QT_TR_NOOP("Loading airports"));
|
2015-03-19 17:01:38 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case NavDataCache::REBUILD_FIXES:
|
|
|
|
rebuildProgress.setLabelText(QT_TR_NOOP("Loading waypoint data"));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NavDataCache::REBUILD_NAVAIDS:
|
|
|
|
rebuildProgress.setLabelText(QT_TR_NOOP("Loading navigation data"));
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case NavDataCache::REBUILD_POIS:
|
|
|
|
rebuildProgress.setLabelText(QT_TR_NOOP("Loading point-of-interest data"));
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
rebuildProgress.setLabelText(baseLabel);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (phase == NavDataCache::REBUILD_UNKNOWN) {
|
|
|
|
rebuildProgress.setValue(0);
|
|
|
|
rebuildProgress.setMaximum(0);
|
|
|
|
} else {
|
|
|
|
rebuildProgress.setValue(cache->rebuildPhaseCompletionPercentage());
|
|
|
|
rebuildProgress.setMaximum(100);
|
|
|
|
}
|
|
|
|
|
2014-12-26 12:20:51 +00:00
|
|
|
QCoreApplication::processEvents();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-08 22:13:57 +00:00
|
|
|
class NaturalEarthDataLoaderThread : public QThread
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
|
|
|
|
2016-08-09 08:38:54 +00:00
|
|
|
NaturalEarthDataLoaderThread() :
|
|
|
|
m_lineInsertCount(0)
|
2016-08-08 22:13:57 +00:00
|
|
|
{
|
|
|
|
connect(this, &QThread::finished, this, &NaturalEarthDataLoaderThread::onFinished);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual void run() Q_DECL_OVERRIDE
|
|
|
|
{
|
|
|
|
SGTimeStamp st;
|
|
|
|
st.stamp();
|
|
|
|
|
|
|
|
loadNaturalEarthFile("ne_10m_coastline.shp", flightgear::PolyLine::COASTLINE, false);
|
|
|
|
loadNaturalEarthFile("ne_10m_rivers_lake_centerlines.shp", flightgear::PolyLine::RIVER, false);
|
|
|
|
loadNaturalEarthFile("ne_10m_lakes.shp", flightgear::PolyLine::LAKE, true);
|
|
|
|
|
|
|
|
qDebug() << "load basic data took" << st.elapsedMSec();
|
|
|
|
|
|
|
|
st.stamp();
|
|
|
|
loadNaturalEarthFile("ne_10m_urban_areas.shp", flightgear::PolyLine::URBAN, true);
|
|
|
|
|
|
|
|
qDebug() << "loading urban areas took:" << st.elapsedMSec();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2016-08-15 22:10:06 +00:00
|
|
|
Q_SLOT void onFinished()
|
2016-08-08 22:13:57 +00:00
|
|
|
{
|
2016-08-09 08:38:54 +00:00
|
|
|
flightgear::PolyLineList::const_iterator begin = m_parsedLines.begin() + m_lineInsertCount;
|
2016-08-12 09:48:34 +00:00
|
|
|
unsigned int numToAdd = std::min<unsigned long>(1000UL, m_parsedLines.size() - m_lineInsertCount);
|
2016-08-09 08:38:54 +00:00
|
|
|
flightgear::PolyLineList::const_iterator end = begin + numToAdd;
|
|
|
|
flightgear::PolyLine::bulkAddToSpatialIndex(begin, end);
|
|
|
|
|
|
|
|
if (end == m_parsedLines.end()) {
|
|
|
|
deleteLater(); // commit suicide
|
|
|
|
} else {
|
|
|
|
m_lineInsertCount += 1000;
|
2016-08-11 21:32:29 +00:00
|
|
|
QTimer::singleShot(50, this, SLOT(onFinished()));
|
2016-08-09 08:38:54 +00:00
|
|
|
}
|
2016-08-08 22:13:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void loadNaturalEarthFile(const std::string& aFileName,
|
|
|
|
flightgear::PolyLine::Type aType,
|
|
|
|
bool areClosed)
|
|
|
|
{
|
|
|
|
SGPath path(globals->get_fg_root());
|
|
|
|
path.append( "Geodata" );
|
|
|
|
path.append(aFileName);
|
|
|
|
if (!path.exists())
|
|
|
|
return; // silently fail for now
|
|
|
|
|
|
|
|
flightgear::PolyLineList lines;
|
|
|
|
flightgear::SHPParser::parsePolyLines(path, aType, m_parsedLines, areClosed);
|
|
|
|
}
|
2017-02-19 22:59:39 +00:00
|
|
|
|
2016-08-08 22:13:57 +00:00
|
|
|
flightgear::PolyLineList m_parsedLines;
|
2016-08-09 08:38:54 +00:00
|
|
|
unsigned int m_lineInsertCount;
|
2016-08-08 22:13:57 +00:00
|
|
|
};
|
|
|
|
|
2014-12-26 12:20:51 +00:00
|
|
|
} // of anonymous namespace
|
|
|
|
|
2015-10-16 01:05:17 +00:00
|
|
|
static void initQtResources()
|
|
|
|
{
|
|
|
|
Q_INIT_RESOURCE(resources);
|
|
|
|
}
|
|
|
|
|
2017-02-19 22:59:39 +00:00
|
|
|
|
2017-01-25 20:41:40 +00:00
|
|
|
|
2017-01-29 15:16:28 +00:00
|
|
|
static void simgearMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
|
|
|
{
|
|
|
|
sgDebugPriority mappedPriority = SG_WARN;
|
|
|
|
switch (type) {
|
|
|
|
case QtDebugMsg: mappedPriority = SG_DEBUG; break;
|
2017-02-01 16:36:48 +00:00
|
|
|
#if QT_VERSION >= 0x050500
|
2017-01-29 15:16:28 +00:00
|
|
|
case QtInfoMsg: mappedPriority = SG_INFO; break;
|
2017-02-01 16:36:48 +00:00
|
|
|
#endif
|
2017-01-29 15:16:28 +00:00
|
|
|
case QtWarningMsg: mappedPriority = SG_WARN; break;
|
|
|
|
case QtCriticalMsg: mappedPriority = SG_ALERT; break;
|
|
|
|
case QtFatalMsg: mappedPriority = SG_POPUP; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char* nullFile = "";
|
|
|
|
const char* file = context.file ? context.file : nullFile;
|
|
|
|
sglog().log(SG_GUI, mappedPriority, file, context.line, msg.toStdString());
|
|
|
|
if (type == QtFatalMsg) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-16 01:05:17 +00:00
|
|
|
namespace flightgear
|
|
|
|
{
|
|
|
|
|
2017-06-07 15:25:19 +00:00
|
|
|
// making this a unique ptr ensures the QApplication will be deleted
|
|
|
|
// event if we forget to call shutdownQtApp. Cleanly destroying this is
|
|
|
|
// important so QPA resources, in particular the XCB thread, are exited
|
|
|
|
// cleanly on quit. However, at present, the official policy is that static
|
|
|
|
// destruction is too late to call this, hence why we have shutdownQtApp()
|
|
|
|
|
|
|
|
std::unique_ptr<QApplication> static_qApp;
|
|
|
|
|
Split flightgear::initApp() to make it usable even without FGGlobals initialized
- Add an optional argument to flightgear::initApp(): doInitQSettings.
This argument defaults to true, preserving initApp()'s behavior in
this respect. If this argument is set to false, FGGlobals doesn't have
to be initialized.
- New function flightgear::initQSettings(), called by
flightgear::initApp() when its 'doInitQSettings' argument is true.
This allows initializing the QSettings exactly when it is needed.
- New function flightgear::checkKeyboardModifiersForSettingFGRoot().
The code it contains used to be run from initApp(), which is
undesirable because:
1) initApp() is not only called at FG initialization (fgMainInit()),
but also from QtMessageBox(), from QtFileDialog::exec() and twice
from Options::setupRoot(). However, checking the Alt and Shift
modifiers to set 'fg-root' in QSettings to the special value
"!ask" only makes sense in fgMainInit(), not in these other
places.
2) This code relies on the QSettings to be set up, and therefore on
FGGlobals. Thus, freeing initApp() of its dependency on FGGlobals
requires splitting this keyboard modifiers checking code out of
initApp().
2016-12-26 20:45:44 +00:00
|
|
|
// Only requires FGGlobals to be initialized if 'doInitQSettings' is true.
|
|
|
|
// Safe to call several times.
|
|
|
|
void initApp(int& argc, char** argv, bool doInitQSettings)
|
2015-10-16 01:05:17 +00:00
|
|
|
{
|
|
|
|
static bool qtInitDone = false;
|
2015-11-26 16:49:55 +00:00
|
|
|
static int s_argc;
|
|
|
|
|
2015-10-16 01:05:17 +00:00
|
|
|
if (!qtInitDone) {
|
|
|
|
qtInitDone = true;
|
2016-02-02 20:44:46 +00:00
|
|
|
|
|
|
|
sglog().setLogLevels( SG_ALL, SG_INFO );
|
|
|
|
initQtResources(); // can't be called from a namespace
|
|
|
|
|
2015-11-26 16:49:55 +00:00
|
|
|
s_argc = argc; // QApplication only stores a reference to argc,
|
|
|
|
// and may crash if it is freed
|
|
|
|
// http://doc.qt.io/qt-5/qguiapplication.html#QGuiApplication
|
2015-10-16 01:05:17 +00:00
|
|
|
|
2017-01-29 15:16:28 +00:00
|
|
|
// log to simgear instead of the console from Qt, so we go to
|
|
|
|
// whichever log locations SimGear has configured
|
|
|
|
qInstallMessageHandler(simgearMessageOutput);
|
|
|
|
|
2018-04-27 08:53:49 +00:00
|
|
|
// ensure we use desktop OpenGL, don't even fall back to ANGLE, since
|
|
|
|
// this gets into a knot on Optimus setups (since we export the magic
|
|
|
|
// Optimus / AMD symbols in main.cxx).
|
|
|
|
QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
|
2018-07-03 08:48:49 +00:00
|
|
|
|
|
|
|
// becuase on Windows, Qt only supports integer scaling factors,
|
|
|
|
// forceibly enabling HighDpiScaling is controversial.
|
|
|
|
// leave things unset here, so users can use env var
|
|
|
|
// QT_AUTO_SCREEN_SCALE_FACTOR=1 to enable it at runtime
|
|
|
|
|
|
|
|
//#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
|
|
|
|
// QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
|
|
|
//#endif
|
2017-06-07 15:25:19 +00:00
|
|
|
static_qApp.reset(new QApplication(s_argc, argv));
|
|
|
|
static_qApp->setOrganizationName("FlightGear");
|
|
|
|
static_qApp->setApplicationName("FlightGear");
|
|
|
|
static_qApp->setOrganizationDomain("flightgear.org");
|
2015-10-16 01:05:17 +00:00
|
|
|
|
2017-05-16 11:51:46 +00:00
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
|
2017-06-07 15:25:19 +00:00
|
|
|
static_qApp->setDesktopFileName(
|
2017-05-16 11:51:46 +00:00
|
|
|
QStringLiteral("org.flightgear.FlightGear.desktop"));
|
|
|
|
#endif
|
|
|
|
|
2016-02-02 20:44:46 +00:00
|
|
|
// reset numeric / collation locales as described at:
|
|
|
|
// http://doc.qt.io/qt-5/qcoreapplication.html#details
|
|
|
|
::setlocale(LC_NUMERIC, "C");
|
|
|
|
::setlocale(LC_COLLATE, "C");
|
Split flightgear::initApp() to make it usable even without FGGlobals initialized
- Add an optional argument to flightgear::initApp(): doInitQSettings.
This argument defaults to true, preserving initApp()'s behavior in
this respect. If this argument is set to false, FGGlobals doesn't have
to be initialized.
- New function flightgear::initQSettings(), called by
flightgear::initApp() when its 'doInitQSettings' argument is true.
This allows initializing the QSettings exactly when it is needed.
- New function flightgear::checkKeyboardModifiersForSettingFGRoot().
The code it contains used to be run from initApp(), which is
undesirable because:
1) initApp() is not only called at FG initialization (fgMainInit()),
but also from QtMessageBox(), from QtFileDialog::exec() and twice
from Options::setupRoot(). However, checking the Alt and Shift
modifiers to set 'fg-root' in QSettings to the special value
"!ask" only makes sense in fgMainInit(), not in these other
places.
2) This code relies on the QSettings to be set up, and therefore on
FGGlobals. Thus, freeing initApp() of its dependency on FGGlobals
requires splitting this keyboard modifiers checking code out of
initApp().
2016-12-26 20:45:44 +00:00
|
|
|
}
|
2016-02-02 20:44:46 +00:00
|
|
|
|
Split flightgear::initApp() to make it usable even without FGGlobals initialized
- Add an optional argument to flightgear::initApp(): doInitQSettings.
This argument defaults to true, preserving initApp()'s behavior in
this respect. If this argument is set to false, FGGlobals doesn't have
to be initialized.
- New function flightgear::initQSettings(), called by
flightgear::initApp() when its 'doInitQSettings' argument is true.
This allows initializing the QSettings exactly when it is needed.
- New function flightgear::checkKeyboardModifiersForSettingFGRoot().
The code it contains used to be run from initApp(), which is
undesirable because:
1) initApp() is not only called at FG initialization (fgMainInit()),
but also from QtMessageBox(), from QtFileDialog::exec() and twice
from Options::setupRoot(). However, checking the Alt and Shift
modifiers to set 'fg-root' in QSettings to the special value
"!ask" only makes sense in fgMainInit(), not in these other
places.
2) This code relies on the QSettings to be set up, and therefore on
FGGlobals. Thus, freeing initApp() of its dependency on FGGlobals
requires splitting this keyboard modifiers checking code out of
initApp().
2016-12-26 20:45:44 +00:00
|
|
|
if (doInitQSettings) {
|
|
|
|
initQSettings();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-07 15:25:19 +00:00
|
|
|
void shutdownQtApp()
|
|
|
|
{
|
2018-07-02 22:13:36 +00:00
|
|
|
// restore default message handler, otherwise Qt logging on
|
|
|
|
// shutdown crashes once sglog is killed
|
|
|
|
qInstallMessageHandler(nullptr);
|
2017-06-07 15:25:19 +00:00
|
|
|
static_qApp.reset();
|
|
|
|
}
|
|
|
|
|
Split flightgear::initApp() to make it usable even without FGGlobals initialized
- Add an optional argument to flightgear::initApp(): doInitQSettings.
This argument defaults to true, preserving initApp()'s behavior in
this respect. If this argument is set to false, FGGlobals doesn't have
to be initialized.
- New function flightgear::initQSettings(), called by
flightgear::initApp() when its 'doInitQSettings' argument is true.
This allows initializing the QSettings exactly when it is needed.
- New function flightgear::checkKeyboardModifiersForSettingFGRoot().
The code it contains used to be run from initApp(), which is
undesirable because:
1) initApp() is not only called at FG initialization (fgMainInit()),
but also from QtMessageBox(), from QtFileDialog::exec() and twice
from Options::setupRoot(). However, checking the Alt and Shift
modifiers to set 'fg-root' in QSettings to the special value
"!ask" only makes sense in fgMainInit(), not in these other
places.
2) This code relies on the QSettings to be set up, and therefore on
FGGlobals. Thus, freeing initApp() of its dependency on FGGlobals
requires splitting this keyboard modifiers checking code out of
initApp().
2016-12-26 20:45:44 +00:00
|
|
|
// Requires FGGlobals to be initialized. Safe to call several times.
|
|
|
|
void initQSettings()
|
|
|
|
{
|
|
|
|
static bool qSettingsInitDone = false;
|
|
|
|
|
|
|
|
if (!qSettingsInitDone) {
|
|
|
|
qSettingsInitDone = true;
|
|
|
|
string fgHome = globals->get_fg_home().utf8Str();
|
|
|
|
|
|
|
|
QSettings::setDefaultFormat(QSettings::IniFormat);
|
|
|
|
QSettings::setPath(QSettings::IniFormat, QSettings::UserScope,
|
|
|
|
QString::fromStdString(fgHome));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool checkKeyboardModifiersForSettingFGRoot()
|
|
|
|
{
|
|
|
|
initQSettings();
|
|
|
|
|
|
|
|
Qt::KeyboardModifiers mods = qApp->queryKeyboardModifiers();
|
|
|
|
if (mods & (Qt::AltModifier | Qt::ShiftModifier)) {
|
|
|
|
qWarning() << "Alt/shift pressed during launch";
|
|
|
|
QSettings settings;
|
|
|
|
settings.setValue("fg-root", "!ask");
|
|
|
|
return true;
|
2015-10-16 01:05:17 +00:00
|
|
|
}
|
Split flightgear::initApp() to make it usable even without FGGlobals initialized
- Add an optional argument to flightgear::initApp(): doInitQSettings.
This argument defaults to true, preserving initApp()'s behavior in
this respect. If this argument is set to false, FGGlobals doesn't have
to be initialized.
- New function flightgear::initQSettings(), called by
flightgear::initApp() when its 'doInitQSettings' argument is true.
This allows initializing the QSettings exactly when it is needed.
- New function flightgear::checkKeyboardModifiersForSettingFGRoot().
The code it contains used to be run from initApp(), which is
undesirable because:
1) initApp() is not only called at FG initialization (fgMainInit()),
but also from QtMessageBox(), from QtFileDialog::exec() and twice
from Options::setupRoot(). However, checking the Alt and Shift
modifiers to set 'fg-root' in QSettings to the special value
"!ask" only makes sense in fgMainInit(), not in these other
places.
2) This code relies on the QSettings to be set up, and therefore on
FGGlobals. Thus, freeing initApp() of its dependency on FGGlobals
requires splitting this keyboard modifiers checking code out of
initApp().
2016-12-26 20:45:44 +00:00
|
|
|
|
|
|
|
return false;
|
2015-10-16 01:05:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-20 00:19:13 +00:00
|
|
|
void restartTheApp()
|
2014-12-26 12:20:51 +00:00
|
|
|
{
|
2017-02-20 00:19:13 +00:00
|
|
|
QStringList fgArgs;
|
2014-12-26 12:20:51 +00:00
|
|
|
|
2017-02-20 00:19:13 +00:00
|
|
|
// Spawn a new instance of myApplication:
|
|
|
|
QProcess proc;
|
|
|
|
QStringList args;
|
2014-12-26 12:20:51 +00:00
|
|
|
|
2018-07-02 22:13:36 +00:00
|
|
|
// ensure we release whatever mutex/lock file we have in home,
|
|
|
|
// so the new instance runs in writeable mode
|
|
|
|
fgShutdownHome();
|
|
|
|
|
2017-02-20 00:19:13 +00:00
|
|
|
#if defined(Q_OS_MAC)
|
|
|
|
QDir dir(qApp->applicationDirPath()); // returns the 'MacOS' dir
|
|
|
|
dir.cdUp(); // up to 'contents' dir
|
|
|
|
dir.cdUp(); // up to .app dir
|
|
|
|
// see 'man open' for details, but '-n' ensures we launch a new instance,
|
|
|
|
// and we want to pass remaining arguments to us, not open.
|
|
|
|
args << "-n" << dir.absolutePath() << "--args" << "--launcher" << fgArgs;
|
|
|
|
qDebug() << "args" << args;
|
|
|
|
proc.startDetached("open", args);
|
|
|
|
#else
|
|
|
|
args << "--launcher" << fgArgs;
|
|
|
|
proc.startDetached(qApp->applicationFilePath(), args);
|
2017-01-30 07:00:37 +00:00
|
|
|
#endif
|
2017-02-20 00:19:13 +00:00
|
|
|
qApp->exit(-1);
|
2014-12-26 12:20:51 +00:00
|
|
|
}
|
|
|
|
|
2015-10-16 01:05:17 +00:00
|
|
|
|
2017-02-20 00:19:13 +00:00
|
|
|
void launcherSetSceneryPaths()
|
2016-01-10 22:38:01 +00:00
|
|
|
{
|
|
|
|
globals->clear_fg_scenery();
|
|
|
|
|
2017-02-20 00:19:13 +00:00
|
|
|
// mimic what options.cxx does, so we can find airport data for parking
|
2016-01-10 22:38:01 +00:00
|
|
|
// positions
|
|
|
|
QSettings settings;
|
|
|
|
// append explicit scenery paths
|
|
|
|
Q_FOREACH(QString path, settings.value("scenery-paths").toStringList()) {
|
|
|
|
globals->append_fg_scenery(path.toStdString());
|
|
|
|
}
|
|
|
|
|
|
|
|
// append the TerraSync path
|
|
|
|
QString downloadDir = settings.value("download-dir").toString();
|
|
|
|
if (downloadDir.isEmpty()) {
|
2016-06-23 13:26:34 +00:00
|
|
|
downloadDir = QString::fromStdString(flightgear::defaultDownloadDir().utf8Str());
|
2016-01-10 22:38:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SGPath terraSyncDir(downloadDir.toStdString());
|
|
|
|
terraSyncDir.append("TerraSync");
|
|
|
|
if (terraSyncDir.exists()) {
|
2016-06-21 11:29:04 +00:00
|
|
|
globals->append_fg_scenery(terraSyncDir);
|
2016-01-10 22:38:01 +00:00
|
|
|
}
|
|
|
|
|
2016-08-19 11:12:02 +00:00
|
|
|
// add the installation path since it contains default airport data,
|
|
|
|
// if terrasync is disabled or on first-launch
|
|
|
|
globals->append_fg_scenery(globals->get_fg_root() / "Scenery");
|
|
|
|
|
2016-01-10 22:38:01 +00:00
|
|
|
}
|
|
|
|
|
2017-02-20 00:19:13 +00:00
|
|
|
bool runLauncherDialog()
|
2015-10-16 01:05:17 +00:00
|
|
|
{
|
2017-02-20 00:19:13 +00:00
|
|
|
// Used for NavDataCache initialization: needed to find the apt.dat files
|
|
|
|
launcherSetSceneryPaths();
|
|
|
|
// startup the nav-cache now. This pre-empts normal startup of
|
|
|
|
// the cache, but no harm done. (Providing scenery paths are consistent)
|
2017-01-26 00:31:41 +00:00
|
|
|
|
2017-02-20 00:19:13 +00:00
|
|
|
initNavCache();
|
2014-12-26 12:20:51 +00:00
|
|
|
|
2017-07-19 18:24:33 +00:00
|
|
|
auto options = flightgear::Options::sharedInstance();
|
|
|
|
if (options->isOptionSet("download-dir")) {
|
|
|
|
// user set download-dir on command line, don't mess with it in the
|
|
|
|
// launcher GUI. We'll disable the UI.
|
|
|
|
LaunchConfig::setEnableDownloadDirUI(false);
|
|
|
|
} else {
|
|
|
|
QSettings settings;
|
2017-12-15 15:42:36 +00:00
|
|
|
QString downloadDir = settings.value("download-dir").toString();
|
2017-07-19 18:24:33 +00:00
|
|
|
if (!downloadDir.isEmpty()) {
|
|
|
|
options->setOption("download-dir", downloadDir.toStdString());
|
|
|
|
}
|
2016-11-07 11:54:38 +00:00
|
|
|
}
|
2014-12-26 12:20:51 +00:00
|
|
|
|
2017-02-20 00:19:13 +00:00
|
|
|
fgInitPackageRoot();
|
2016-01-10 18:56:46 +00:00
|
|
|
|
2017-02-20 00:19:13 +00:00
|
|
|
// startup the HTTP system now since packages needs it
|
|
|
|
FGHTTPClient* http = globals->add_new_subsystem<FGHTTPClient>();
|
2014-12-26 12:20:51 +00:00
|
|
|
|
2017-02-20 00:19:13 +00:00
|
|
|
// we guard against re-init in the global phase; bind and postinit
|
|
|
|
// will happen as normal
|
|
|
|
http->init();
|
2014-12-26 12:20:51 +00:00
|
|
|
|
2017-02-20 00:19:13 +00:00
|
|
|
NaturalEarthDataLoaderThread* naturalEarthLoader = new NaturalEarthDataLoaderThread;
|
|
|
|
naturalEarthLoader->start();
|
2016-07-08 08:36:42 +00:00
|
|
|
|
2017-02-20 00:19:13 +00:00
|
|
|
// avoid double Apple menu and other weirdness if both Qt and OSG
|
|
|
|
// try to initialise various Cocoa structures.
|
|
|
|
flightgear::WindowBuilder::setPoseAsStandaloneApp(false);
|
2014-12-26 12:20:51 +00:00
|
|
|
|
2017-02-20 00:19:13 +00:00
|
|
|
LauncherMainWindow dlg;
|
|
|
|
dlg.show();
|
2016-01-10 19:47:57 +00:00
|
|
|
|
2017-02-20 00:19:13 +00:00
|
|
|
int appResult = qApp->exec();
|
|
|
|
if (appResult <= 0) {
|
|
|
|
return false; // quit
|
2016-01-10 19:47:57 +00:00
|
|
|
}
|
2015-10-25 00:40:41 +00:00
|
|
|
|
2017-02-20 00:19:13 +00:00
|
|
|
// don't set scenery paths twice
|
|
|
|
globals->clear_fg_scenery();
|
2015-11-03 21:28:36 +00:00
|
|
|
|
2017-02-20 00:19:13 +00:00
|
|
|
return true;
|
2014-12-26 12:20:51 +00:00
|
|
|
}
|
|
|
|
|
2017-02-20 00:19:13 +00:00
|
|
|
bool runInAppLauncherDialog()
|
2014-12-26 12:20:51 +00:00
|
|
|
{
|
2017-02-20 00:19:13 +00:00
|
|
|
LauncherMainWindow dlg;
|
|
|
|
bool accepted = dlg.execInApp();
|
|
|
|
if (!accepted) {
|
|
|
|
return false;
|
2014-12-26 12:20:51 +00:00
|
|
|
}
|
|
|
|
|
2017-02-20 00:19:13 +00:00
|
|
|
return true;
|
2016-02-24 19:50:37 +00:00
|
|
|
}
|
|
|
|
|
2017-02-20 00:19:13 +00:00
|
|
|
} // of namespace flightgear
|
2016-01-17 19:10:22 +00:00
|
|
|
|
2015-10-16 01:05:17 +00:00
|
|
|
#include "QtLauncher.moc"
|