7#include <QQmlComponent>
8#include <QDesktopServices>
11#include <simgear/package/Root.hxx>
12#include <simgear/package/Catalog.hxx>
38 simgear::pkg::RootRef(
globals->packageRoot()));
49 m_sceneryPaths->saveToSettings(
"scenery-paths-v2");
52 m_sceneryPaths->loadFromSettings(
"scenery-paths-v2");
55 m_aircraftPaths->loadFromSettings(
"aircraft-paths-v2");
58 setLocalAircraftPaths();
62 m_aircraftPaths->saveToSettings(
"aircraft-paths-v2");
63 setLocalAircraftPaths();
67 int size = settings.beginReadArray(
"addon-modules");
68 for (
int i = 0;
i < size; ++
i) {
69 settings.setArrayIndex(
i);
71 QString path = settings.value(
"path").toString();
72 const SGPath addonPath(path.toStdString());
73 if (!addonPath.exists()) {
78 m_addonModulePaths.push_back( path );
79 bool enable = settings.value(
"enable").toBool();
83 m_addonsModuleModel->append(path, addon, enable);
85 catch (
const sg_exception &e) {
86 std::string msg =
"Error getting add-on metadata: " + e.getFormattedMessage();
87 SG_LOG(SG_GENERAL, SG_ALERT, msg);
92 qmlRegisterUncreatableType<AddOnsController>(
"FlightGear.Launcher", 1, 0,
"AddOnsControllers",
"no");
93 qmlRegisterUncreatableType<CatalogListModel>(
"FlightGear.Launcher", 1, 0,
"CatalogListModel",
"no");
94 qmlRegisterUncreatableType<AddonsModel>(
"FlightGear.Launcher", 1, 0,
"AddonsModel",
"no");
95 qmlRegisterUncreatableType<PathListModel>(
"FlightGear.Launcher", 1, 0,
"PathListMode",
"no");
101void AddOnsController::setLocalAircraftPaths()
108 for (
const auto& arg : commandLineAircraftPaths) {
110 for (
const auto&
p : SGPath::pathsFromUtf8(arg)) {
111 paths.append(QString::fromStdString(
p.utf8Str()));
115 paths.append(m_aircraftPaths->enabledPaths());
116 aircraftCache->setPaths(paths);
117 aircraftCache->scanDirs();
122 return m_aircraftPaths;
127 return m_sceneryPaths;
132 return m_addonModulePaths;
137 QString path = QFileDialog::getExistingDirectory(
nullptr, tr(
"Choose aircraft folder"));
138 if (path.isEmpty()) {
150 if (d.exists(
"Aircraft")) {
151 QString
p2 = d.filePath(
"Aircraft");
161 mb.setText(tr(
"No aircraft found in the folder '%1' - add anyway?").arg(path));
162 mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
163 mb.setDefaultButton(QMessageBox::No);
166 if (mb.result() == QMessageBox::No) {
173 m_aircraftPaths->appendPath(path);
180 QString path = QFileDialog::getExistingDirectory(
nullptr, tr(
"Choose addon module folder"));
181 if (path.isEmpty()) {
187 SGPath
p(path.toStdString());
188 bool isValid =
false;
190 for (
const auto& file: {
"addon-metadata.xml",
"addon-main.nas"}) {
191 if ((
p / file).exists()) {
199 mb.setText(tr(
"The folder '%1' doesn't appear to contain an addon module - add anyway?").arg(path));
200 mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
201 mb.setDefaultButton(QMessageBox::No);
202 mb.setInformativeText(tr(
"Added modules should contain at least both of the following "
203 "files: addon-metadata.xml, addon-main.nas."));
206 if (mb.result() == QMessageBox::No) {
212 const SGPath addonPath(path.toStdString());
217 if (!m_addonsModuleModel->append(path, addon,
true)) {
220 }
catch (
const sg_exception &e) {
221 std::string msg =
"Error getting add-on metadata: " + e.getFormattedMessage();
222 SG_LOG(SG_GENERAL, SG_ALERT, msg);
230 QString path = QFileDialog::getExistingDirectory(
nullptr, tr(
"Choose scenery folder"));
231 if (path.isEmpty()) {
237 SGPath
p(path.toStdString());
238 bool isValid =
false;
240 for (
const auto& dir: {
"Objects",
"Terrain",
"Buildings",
"Roads",
"Pylons",
"NavData",
"Airports",
"Orthophotos",
"vpb"}) {
241 if ((
p / dir).exists()) {
249 mb.setText(tr(
"The folder '%1' doesn't appear to contain scenery - add anyway?").arg(path));
250 mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
251 mb.setDefaultButton(QMessageBox::No);
252 mb.setInformativeText(tr(
"Added scenery should contain at least one of the following "
253 "folders: Objects, Terrain, Buildings, Roads, Pylons, NavData, Airports, Orthophotos, vpb."));
256 if (mb.result() == QMessageBox::No) {
261 m_sceneryPaths->appendPath(path);
268 QString downloadDir = settings.value(
"download-dir").toString();
270 if (dlg.exec() == QDialog::Accepted) {
279 QUrl u = QUrl::fromLocalFile(path);
280 QDesktopServices::openUrl(u);
300 settings.beginWriteArray(
"addon-modules");
302 if (m_addonsModuleModel->containsPath(path)) {
303 settings.setArrayIndex(
i++);
304 settings.setValue(
"path", path);
305 settings.setValue(
"enable", m_addonsModuleModel->getPathEnable(path));
318 settings.setValue(
"hide-official-catalog-message",
true);
319 }
else if (s ==
"add-official") {
321 m_catalogs->installDefaultCatalog(
false);
327bool AddOnsController::shouldShowOfficialCatalogMessage()
const
330 bool showOfficialCatalogMesssage = !
globals->get_subsystem<
FGHTTPClient>()->isDefaultCatalogInstalled();
331 if (settings.value(
"hide-official-catalog-message").toBool()) {
332 showOfficialCatalogMesssage =
false;
334 return showOfficialCatalogMesssage;
340 return globals->get_subsystem<FGHTTPClient>()->isDefaultCatalogInstalled();
345 return shouldShowOfficialCatalogMessage();
348void AddOnsController::onCatalogsChanged()
360 settings.beginWriteArray(
"addon-modules");
361 for (
const auto& path : m_addonModulePaths) {
362 settings.setArrayIndex(
i++);
363 settings.setValue(
"path", path);
364 settings.setValue(
"enable", m_addonsModuleModel->getPathEnable(path));
372 Q_FOREACH(QString path, m_sceneryPaths->enabledPaths()) {
373 m_config->setArg(
"fg-scenery", path);
377 Q_FOREACH(QString path, m_aircraftPaths->enabledPaths()) {
378 m_config->setArg(
"fg-aircraft", path);
382 for (
const auto& catRef :
globals->packageRoot()->catalogs()) {
383 const auto catAircraftPath = catRef->installRoot() /
"Aircraft";
384 m_config->setArg(
"fg-aircraft", QString::fromStdString(catAircraftPath.utf8Str()));
390 int size = settings.beginReadArray(
"addon-modules");
391 for (
int i = 0;
i < size; ++
i) {
392 settings.setArrayIndex(
i);
394 QString path = settings.value(
"path").toString();
395 const SGPath addonPath(path.toStdString());
396 if (!addonPath.exists()) {
401 bool enable = settings.value(
"enable").toBool();
403 m_config->setArg(
"addon", path);
412 return options->isOptionSet(
"fg-scenery") ||
options->isOptionSet(
"fg-aircraft");
bool options(int, char **)
void setAddons(AddonsModel *addons)
void onAddonsChanged(void)
Q_INVOKABLE QString addAircraftPath() const
Q_INVOKABLE QString addSceneryPath() const
Q_INVOKABLE QString addAddOnModulePath() const
bool showNoOfficialHangar
Q_INVOKABLE void officialCatalogAction(QString s)
PathListModel * sceneryPaths
void isOfficialHangarRegisteredChanged()
Q_INVOKABLE void openDirectory(QString path)
AddOnsController(LauncherMainWindow *parent, LaunchConfig *config)
void setModulePaths(QStringList modulePaths)
bool havePathsFromCommandLine
void modulePathsChanged(QStringList modulePaths)
Q_INVOKABLE QString installCustomScenery()
bool isOfficialHangarRegistered
void showNoOfficialHangarChanged()
PathListModel * aircraftPaths
static Addon fromAddonDir(const SGPath &addonPath)
static bool isCandidateAircraftPath(QString path)
@helper to determine if a particular path is likely to contain aircraft or not.
static LocalAircraftCache * instance()
void enabledPathsChanged()
string_list valuesForOption(const std::string &key) const
return all values for a multi-valued option
static Options * sharedInstance()
void addSentryBreadcrumb(const std::string &, const std::string &)
void launcherSetSceneryPaths()