1
0
Fork 0

Allow scenery installation from the launcher.

Replaces FGadmin functionality.
This commit is contained in:
James Turner 2016-06-15 22:28:27 +01:00
parent 010d13445a
commit 3f7e59a1a5
8 changed files with 583 additions and 7 deletions

View file

@ -76,7 +76,9 @@ if (HAVE_QT)
AddCatalogDialog.ui
PathsDialog.ui
LocationWidget.ui
NoOfficialHangar.ui)
NoOfficialHangar.ui
InstallSceneryDialog.ui
)
qt5_add_resources(qrc_sources resources.qrc)
@ -109,6 +111,8 @@ if (HAVE_QT)
QtMessageBox.hxx
QtFileDialog.cxx
QtFileDialog.hxx
InstallSceneryDialog.hxx
InstallSceneryDialog.cxx
${uic_sources}
${qrc_sources})

View file

@ -0,0 +1,273 @@
// InstallSceneryDialog.cxx - part of GUI launcher using Qt5
//
// Written by James Turner, started June 2016.
//
// Copyright (C) 2016 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.
#include "InstallSceneryDialog.hxx"
#include "ui_InstallSceneryDialog.h"
#include <QPushButton>
#include <QDebug>
#include <QFileDialog>
#include <QThread>
#include <QFile>
#include <QFileInfo>
#include <QRegularExpression>
#include <QDir>
#include <QStandardPaths>
#include <Main/globals.hxx>
#include <Main/options.hxx>
#include <Include/version.h>
#include <simgear/io/untar.hxx>
class InstallSceneryThread : public QThread
{
Q_OBJECT
public:
InstallSceneryThread(QString extractDir, QStringList files) :
m_extractDir(extractDir),
m_remainingPaths(files),
m_error(false),
m_totalBytes(0),
m_bytesRead(0)
{
}
virtual void run()
{
// pre-check each file
Q_FOREACH (QString path, m_remainingPaths) {
QFileInfo finfo(path);
QString baseName = finfo.baseName();
QRegularExpression re("[e|w]\\d{2}0[n|s]\\d0", QRegularExpression::CaseInsensitiveOption);
Q_ASSERT(re.isValid());
if (!re.match(baseName).hasMatch()) {
emit extractionError(path,tr("scenery archive name is not correct."));
m_error = true;
return;
}
QFile f(path);
f.open(QIODevice::ReadOnly);
QByteArray firstData = f.read(8192);
if (!simgear::TarExtractor::isTarData((uint8_t*) firstData.data(), firstData.count())) {
emit extractionError(path,tr("file does not appear to be a scenery archive."));
m_error = true;
return;
}
m_totalBytes += f.size();
}
while (!m_remainingPaths.isEmpty() && !m_error) {
extractNextArchive();
}
}
signals:
void extractionError(QString file, QString msg);
void progress(int percent);
private:
void extractNextArchive()
{
SGPath root(m_extractDir.toStdString());
m_untar.reset(new simgear::TarExtractor(root));
QString path = m_remainingPaths.front();
m_remainingPaths.pop_front();
QFileInfo finfo(path);
QFile f(path);
f.open(QIODevice::ReadOnly);
Q_ASSERT(f.isOpen());
while (!f.atEnd()) {
QByteArray bytes = f.read(4 * 1024 * 1024);
m_untar->extractBytes(bytes.constData(), bytes.size());
m_bytesRead += bytes.size();
if (m_untar->hasError()) {
break;
}
emit progress((m_bytesRead * 100) / m_totalBytes);
}
if (m_untar->hasError() || !m_untar->isAtEndOfArchive()) {
emit extractionError(path, tr("unarchiving failed"));
m_error = true;
// try to clean up?
}
}
QString m_extractDir;
QStringList m_remainingPaths;
std::auto_ptr<simgear::TarExtractor> m_untar;
bool m_error;
quint64 m_totalBytes;
quint64 m_bytesRead;
};
InstallSceneryDialog::InstallSceneryDialog(QWidget *parent, QString downloadDir) :
QDialog(parent, Qt::Dialog
| Qt::CustomizeWindowHint
| Qt::WindowTitleHint
| Qt::WindowSystemMenuHint
| Qt::WindowContextHelpButtonHint
| Qt::MSWindowsFixedSizeDialogHint),
m_state(STATE_START),
m_downloadDir(downloadDir),
ui(new Ui::InstallSceneryDialog)
{
ui->setupUi(this);
if (m_downloadDir.isEmpty()) {
m_downloadDir = QString::fromStdString(flightgear::defaultDownloadDir());
}
QString baseIntroString = ui->introText->text();
ui->introText->setText(baseIntroString.arg(m_downloadDir));
updateUi();
}
InstallSceneryDialog::~InstallSceneryDialog()
{
delete ui;
}
void InstallSceneryDialog::updateUi()
{
QPushButton* b = ui->buttonBox->button(QDialogButtonBox::Ok);
QPushButton* cancel = ui->buttonBox->button(QDialogButtonBox::Cancel);
switch (m_state) {
case STATE_START:
b->setText(tr("Next"));
// b->setEnabled(m_catalogUrl.isValid() && !m_catalogUrl.isRelative());
break;
case STATE_EXTRACTING:
b->setEnabled(false);
cancel->setEnabled(false);
ui->stack->setCurrentIndex(1);
break;
case STATE_EXTRACT_FAILED:
b->setEnabled(false);
cancel->setEnabled(true);
ui->stack->setCurrentIndex(2);
break;
case STATE_FINISHED:
b->setEnabled(true);
cancel->setEnabled(false);
b->setText(tr("Okay"));
ui->stack->setCurrentIndex(2);
QString basicDesc = ui->resultsSummaryLabel->text();
ui->resultsSummaryLabel->setText(basicDesc.arg(sceneryPath()));
break;
}
}
void InstallSceneryDialog::accept()
{
switch (m_state) {
case STATE_START:
pickFiles();
break;
case STATE_EXTRACTING:
case STATE_EXTRACT_FAILED:
// can't happen, button is disabled
break;
case STATE_FINISHED:
// check if download path is in scenery list, add if not
QDialog::accept();
break;
}
}
void InstallSceneryDialog::reject()
{
QDialog::reject();
}
void InstallSceneryDialog::pickFiles()
{
QStringList downloads = QStandardPaths::standardLocations(QStandardPaths::DownloadLocation);
QStringList files = QFileDialog::getOpenFileNames(this, "Choose scenery to install",
downloads.first(), "*.tar *.gz *.tgz");
if (!files.isEmpty()) {
QDir d(m_downloadDir);
if (!d.exists("Scenery")) {
d.mkdir("Scenery");
}
m_state = STATE_EXTRACTING;
m_thread.reset(new InstallSceneryThread(d.filePath("Scenery"), files));
// connect up some signals
connect(m_thread.data(), &QThread::finished, this, &InstallSceneryDialog::onThreadFinished);
connect(m_thread.data(), &InstallSceneryThread::extractionError,
this, &InstallSceneryDialog::onExtractError);
connect(m_thread.data(), &InstallSceneryThread::progress,
this, &InstallSceneryDialog::onExtractProgress);
updateUi();
m_thread->start();
} else {
// user cancelled file dialog, cancel us as well
QDialog::reject();
}
}
void InstallSceneryDialog::onThreadFinished()
{
m_state = STATE_FINISHED;
updateUi();
}
void InstallSceneryDialog::onExtractError(QString file, QString msg)
{
ui->resultsSummaryLabel->setText(tr("Problems occured extracting the archive '%1': %2").arg(file).arg(msg));
m_state = STATE_EXTRACT_FAILED;
updateUi();
}
void InstallSceneryDialog::onExtractProgress(int percent)
{
ui->progressBar->setValue(percent);
}
QString InstallSceneryDialog::sceneryPath()
{
if (m_state == STATE_FINISHED) {
QDir d(m_downloadDir);
return d.filePath("Scenery");
}
return QString();
}
#include "InstallSceneryDialog.moc"

View file

@ -0,0 +1,70 @@
// InstallSceneryDialog.hxx - part of GUI launcher using Qt5
//
// Written by James Turner, started June 2016.
//
// Copyright (C) 2016 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.
#ifndef FG_GUI_INSTALL_SCENERY_DIALOG_HXX
#define FG_GUI_INSTALL_SCENERY_DIALOG_HXX
#include <QDialog>
#include <QUrl>
namespace Ui {
class InstallSceneryDialog;
}
class InstallSceneryThread;
class InstallSceneryDialog : public QDialog
{
Q_OBJECT
public:
explicit InstallSceneryDialog(QWidget *parent, QString downloadDir);
~InstallSceneryDialog();
QString sceneryPath();
private slots:
virtual void reject();
virtual void accept();
private:
void updateUi();
void pickFiles();
void onThreadFinished();
void onExtractError(QString file, QString msg);
void onExtractProgress(int percent);
enum State {
STATE_START = 0, // awaiting user input on first screen
STATE_EXTRACTING = 1, // in-progress, showing progress page
STATE_FINISHED = 2, // catalog added ok, showing summary page
STATE_EXTRACT_FAILED = 3
};
State m_state;
QString m_downloadDir;
Ui::InstallSceneryDialog *ui;
QScopedPointer<InstallSceneryThread> m_thread;
};
#endif // FG_GUI_INSTALL_SCENERY_DIALOG_HXX

View file

@ -0,0 +1,178 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>InstallSceneryDialog</class>
<widget class="QDialog" name="InstallSceneryDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>528</width>
<height>311</height>
</rect>
</property>
<property name="windowTitle">
<string>Install scenery</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QStackedWidget" name="stack">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="page">
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,1">
<item>
<widget class="QLabel" name="introText">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The easiest way to automatically install scenery is to use TerraSync. If you prefer to download and install scenery manually, you can use this dialog to extract and install the files in the correct place. (&lt;a href=&quot;http://ns334561.ip-5-196-65.eu/~fgscenery/WS2.0/scenery-2.0.1.html&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Click here to download scenery&lt;/span&gt;&lt;/a&gt;)&lt;/p&gt;&lt;p&gt;Files will be extracted and installed to a 'Scenery' folder inside your chosen downloads location (currently %1), after which you can delete the archives if you wish.&lt;/p&gt;&lt;p&gt;To begin, click 'Next' and select one more more downloaded scenery archives, which have names such as 'w010n40.tar.gz'&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2">
<layout class="QVBoxLayout" name="verticalLayout_3" stretch="0,0,0,1,0">
<item>
<widget class="QLabel" name="description">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Please wait, verifying and extracting scenery...</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="progressText">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="progressBar">
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>-1</number>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_3">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QLabel" name="resultsSummaryLabel">
<property name="text">
<string>Successfully installed the scenery files to '%1'. This location will be added to the list of additional sceneries to be used.</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>InstallSceneryDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>InstallSceneryDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View file

@ -11,6 +11,7 @@
#include "AddCatalogDialog.hxx"
#include "AircraftModel.hxx"
#include "QtLauncher_private.hxx"
#include "InstallSceneryDialog.hxx"
#include <Main/options.hxx>
#include <Main/globals.hxx>
@ -60,6 +61,8 @@ AddOnsPage::AddOnsPage(QWidget *parent, simgear::pkg::RootRef root) :
connect(m_ui->changeDataDir, &QPushButton::clicked,
this, &AddOnsPage::onChangeDataDir);
connect(m_ui->installSceneryButton, &QPushButton::clicked,
this, &AddOnsPage::onInstallScenery);
QSettings settings;
@ -180,6 +183,17 @@ void AddOnsPage::saveSceneryPaths()
emit sceneryPathsChanged();
}
bool AddOnsPage::haveSceneryPath(QString path) const
{
for (int i=0; i<m_ui->sceneryPathsList->count(); ++i) {
if (m_ui->sceneryPathsList->item(i)->text() == path) {
return true;
}
}
return false;
}
void AddOnsPage::onAddCatalog()
{
QScopedPointer<AddCatalogDialog> dlg(new AddCatalogDialog(this, m_packageRoot));
@ -310,6 +324,17 @@ void AddOnsPage::onChangeDataDir()
QtLauncher::restartTheApp(QStringList());
}
void AddOnsPage::onInstallScenery()
{
InstallSceneryDialog dlg(this, m_downloadDir);
if (dlg.exec() == QDialog::Accepted) {
if (!haveSceneryPath(dlg.sceneryPath())) {
m_ui->sceneryPathsList->addItem(dlg.sceneryPath());
saveSceneryPaths();
}
}
}
void AddOnsPage::updateUi()
{
QString s = m_downloadDir;

View file

@ -41,12 +41,14 @@ private slots:
void onClearDownloadDir();
void onChangeDataDir();
void onInstallScenery();
private:
void updateUi();
void setDownloadDir();
void saveAircraftPaths();
void saveSceneryPaths();
bool haveSceneryPath(QString path) const;
Ui::AddOnsPage* m_ui;
CatalogListModel* m_catalogsModel;

View file

@ -106,6 +106,30 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QPushButton" name="installSceneryButton">
<property name="text">
<string>Install downloaded scenery...</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">

View file

@ -1,9 +1,9 @@
add_executable(terrasync terrasync.cxx)
#add_executable(terrasync terrasync.cxx)
target_link_libraries(terrasync
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
)
#target_link_libraries(terrasync
# ${SIMGEAR_CORE_LIBRARIES}
# ${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
#)
install(TARGETS terrasync RUNTIME DESTINATION bin)
#install(TARGETS terrasync RUNTIME DESTINATION bin)