From 9a06348f999ac60cde8e2dd8f7bfa9c1d43faa69 Mon Sep 17 00:00:00 2001 From: Rogier Date: Sat, 4 Jul 2015 07:42:17 +0200 Subject: [PATCH 1/4] More changes to .gitignore --- .gitignore | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index a380dad..0bc8bfa 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,7 @@ Makefile MinetestMapperGui *.o -moc_mainwindow.cpp -qrc_minetestmappergui.cpp -ui_mainwindow.h +moc_*.cpp +qrc_*.cpp +ui_*.h From 20b8e532344b669d6653529889c2d7eb632a60f0 Mon Sep 17 00:00:00 2001 From: Rogier Date: Sat, 4 Jul 2015 07:42:23 +0200 Subject: [PATCH 2/4] Make minetestmapper location configurable. Search for & propose candidates. --- MinetestMapperGui.pro | 9 +- configdialog.cpp | 197 ++++++++++++++++++++++++++++++++++++++++++ configdialog.h | 56 ++++++++++++ configdialog.ui | 101 ++++++++++++++++++++++ mainwindow.cpp | 77 ++++++++++++++++- mainwindow.h | 10 +++ mainwindow.ui | 6 ++ 7 files changed, 450 insertions(+), 6 deletions(-) create mode 100644 configdialog.cpp create mode 100644 configdialog.h create mode 100644 configdialog.ui diff --git a/MinetestMapperGui.pro b/MinetestMapperGui.pro index 6bc7a51..2a9f229 100644 --- a/MinetestMapperGui.pro +++ b/MinetestMapperGui.pro @@ -15,12 +15,15 @@ TEMPLATE = app SOURCES += main.cpp\ mainwindow.cpp \ - colorlineedit.cpp + colorlineedit.cpp \ + configdialog.cpp HEADERS += mainwindow.h \ - colorlineedit.h + colorlineedit.h \ + configdialog.h -FORMS += mainwindow.ui +FORMS += mainwindow.ui \ + configdialog.ui RESOURCES += \ minetestmappergui.qrc diff --git a/configdialog.cpp b/configdialog.cpp new file mode 100644 index 0000000..7c53bdd --- /dev/null +++ b/configdialog.cpp @@ -0,0 +1,197 @@ +#include +#include +#include +#include +#include +#include + +#include "configdialog.h" +#include "ui_configdialog.h" +#include "mainwindow.h" + +const QString ConfigSettings::defaultMapperExecutableName("minetestmapper"); +QStringList ConfigSettings::predefinedMapperLocations; + +ConfigSettings::InitStatics::InitStatics() +{ + #ifndef Q_OS_WIN + ConfigSettings::predefinedMapperLocations << "/bin/" + defaultMapperExecutableName; + ConfigSettings::predefinedMapperLocations << "/usr/bin/" + defaultMapperExecutableName; + ConfigSettings::predefinedMapperLocations << "/usr/local/bin/" + defaultMapperExecutableName; + #endif +} + + +ConfigDialog::ConfigDialog(const ConfigSettings &settings, MainWindow *app, QWidget *parent) : + QDialog(parent), + ui(new Ui::ConfigDialog), + settings(settings), + application(app) +{ + ui->setupUi(this); + executableList = ConfigSettings::getMapperExecutables(); + QString standardExecutable; + if (!executableList.empty()) + standardExecutable = executableList.at(0); + if (standardExecutable != "") + executableList.push_front(tr("---Automatic--- (Currently: %1)").arg(standardExecutable)); + else + executableList.push_front(tr("---Automatic--- (Currently: NONE - Minetestmapper Not Found)")); + ui->path_Minetestmapper->addItems(executableList); + ui->path_Minetestmapper->setCurrentIndex(0); + if (settings.mapperPath != "") { + ui->path_Minetestmapper->setCurrentText(settings.mapperPath); + if (ui->path_Minetestmapper->currentText() != settings.mapperPath) { + // Unfortunately, adding it means that the saved path can be chosen again, even if it + // does not exist. Can't avoid that, as we still want it to be the *current* value... + executableList.push_back(settings.mapperPath); + ui->path_Minetestmapper->addItem(settings.mapperPath); + ui->path_Minetestmapper->setCurrentText(settings.mapperPath); + // TODO: make the combobox editable (also solves the problem above) + } + } +} + +ConfigDialog::~ConfigDialog() +{ + delete ui; +} + +void ConfigDialog::on_browseMapper_clicked() +{ + #ifdef Q_OS_WIN + QString fileType = tr("Executable (*.exe)"); + #else + QString fileType; + #endif + + bool selectionSeemsOK; + QString fileName; + if (ui->path_Minetestmapper->currentIndex() != 0) { + fileName = ui->path_Minetestmapper->currentText(); + } + else if (ui->path_Minetestmapper->count() > 0) { + fileName = ui->path_Minetestmapper->itemText(1); + } + else { + #ifdef Q_OS_WIN + fileName = QCoreApplication::applicationDirPath(); + #else + fileName = QDir::currentPath(); + #endif + } + do { + fileName = QFileDialog::getOpenFileName(this, tr("Select Mapper Location"), + fileName, + fileType); + if (fileName != "" && !(QFile(fileName).permissions() & QFileDevice::ExeUser)) { + selectionSeemsOK = false; + QMessageBox::critical(this, tr("Invalid minetestmapper executable"), + tr("ERROR: The selected file is not executable")); + } + else { + // TODO: verify if it is minetestmapper (?) -> invoke with --help ? + selectionSeemsOK = true; + } + } while (!selectionSeemsOK); + + if(fileName != "") { + settings.mapperPath = fileName; + ui->path_Minetestmapper->setCurrentText(fileName); + if (ui->path_Minetestmapper->currentText() != fileName) { + executableList.push_back(fileName); + ui->path_Minetestmapper->addItem(fileName); + ui->path_Minetestmapper->setCurrentText(fileName); + } + } +} + +QString ConfigSettings::getDefaultMapperExecutable(void) +{ + QStringList locations = getMapperExecutables(); + if (locations.empty()) return ""; + else return locations.at(0); +} + +void ConfigSettings::addMapperExecutablesToList(QStringList &existingList, QStringList &pathList) +{ + QString prevLocation; + for (; ! pathList.empty(); pathList.pop_front()) { + QString location = QStandardPaths::findExecutable(ConfigSettings::defaultMapperExecutableName, pathList); + if (location != "" && prevLocation != location) { + prevLocation = location; + int count = existingList.count(); + int i; + for (i = 0; i < count; i++) { + if (existingList[i] == location) + break; + } + if (i >= count) + existingList << location; + } + } +} + +QStringList ConfigSettings::getMapperExecutables(void) +{ + QStringList mapperLocations; + QStringList moreLocations = ConfigSettings::predefinedMapperLocations; + + // On windows, check installation directory of minetestmappergui, & give precedence over anything else + #ifdef Q_OS_WIN + QString appDir = QCoreApplication::applicationDirPath(); + QString mapperFileName; + + mapperFileName = QStandardPaths::findExecutable(ConfigSettings::defaultMapperExecutableName, QStringList(appDir)); + if (mapperFileName != "") + mapperLocations << mapperFileName; + + mapperFileName = QStandardPaths::findExecutable(ConfigSettings::defaultMapperExecutableName, QStringList(appDir + '/' + ConfigSettings::defaultMapperExecutableName)); + if (mapperFileName != "") + mapperLocations << mapperFileName; + + mapperFileName = QStandardPaths::findExecutable(ConfigSettings::defaultMapperExecutableName, QStringList(appDir + "/mapper")); + if (mapperFileName != "") + mapperLocations << mapperFileName; + #endif + + // Find all minetestmappers in PATH. Unfortunately, it seems that QT can't do this directly... + QStringList path = QProcessEnvironment::systemEnvironment().value("PATH").split(":"); + addMapperExecutablesToList(mapperLocations, path); + + // Find all minetestmappers in QStandardPaths::ApplicationsLocation, add if not already added + QStringList appLocations = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation); + addMapperExecutablesToList(mapperLocations, appLocations); + + // Add locations from moreLocations that were not already added + addMapperExecutablesToList(mapperLocations, moreLocations); + + return mapperLocations; +} + + +void ConfigDialog::on_path_Minetestmapper_currentIndexChanged(int index) +{ + if (index == 0) + settings.mapperPath = ""; + else + settings.mapperPath = ui->path_Minetestmapper->currentText(); +} + + + +void ConfigDialog::on_CancelButton_clicked() +{ + application->closeConfigDialog(); +} + +void ConfigDialog::on_ApplyButton_clicked() +{ + application->updateConfigSettings(settings); +} + +void ConfigDialog::on_OKButton_clicked() +{ + on_ApplyButton_clicked(); + on_CancelButton_clicked(); +} diff --git a/configdialog.h b/configdialog.h new file mode 100644 index 0000000..fa8d60a --- /dev/null +++ b/configdialog.h @@ -0,0 +1,56 @@ +#ifndef CONFIGDIALOG_H +#define CONFIGDIALOG_H + +#include + + +namespace Ui { +class ConfigDialog; +} +class MainWindow; + +struct ConfigSettings +{ + QString mapperPath; + + static QStringList getMapperExecutables(void); + static QString getDefaultMapperExecutable(void); + static const QString defaultMapperExecutableName; + static QStringList predefinedMapperLocations; + +private: + struct InitStatics { InitStatics(void); }; + static const InitStatics initStatics; + friend struct InitStatics; + + static void addMapperExecutablesToList(QStringList &existingList, QStringList &pathList); +}; + +class ConfigDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ConfigDialog(const ConfigSettings &settings, MainWindow *app, QWidget *parent = 0); + ~ConfigDialog(); + +private: + Ui::ConfigDialog *ui; + QStringList executableList; + ConfigSettings settings; + MainWindow *application; + +protected slots: + +private slots: + + void on_browseMapper_clicked(); + + void on_path_Minetestmapper_currentIndexChanged(int index); + + void on_CancelButton_clicked(); + void on_ApplyButton_clicked(); + void on_OKButton_clicked(); +}; + +#endif // CONFIGDIALOG_H diff --git a/configdialog.ui b/configdialog.ui new file mode 100644 index 0000000..c2cf779 --- /dev/null +++ b/configdialog.ui @@ -0,0 +1,101 @@ + + + ConfigDialog + + + + 0 + 0 + 483 + 66 + + + + Dialog + + + + + + + 0 + 0 + + + + Browse + + + + :/open:/open + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Cancel + + + + + + + Apply + + + + + + + OK + + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Mapper Location: + + + + + + + + + + diff --git a/mainwindow.cpp b/mainwindow.cpp index ca74f61..773e6d0 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -9,6 +9,8 @@ #include #include +#include "configdialog.h" + #if defined(Q_OS_WIN) static const QString qSettingsOrganisation("addi"); static const QString qSettingsApplicationPrefix("Minetestmapper_"); @@ -45,7 +47,8 @@ InitStatics::InitStatics(void) MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), - ui(new Ui::MainWindow) + ui(new Ui::MainWindow), + configDialog(NULL) { #ifndef Q_OS_WIN if (!migrateSettingsProfiles()) @@ -191,11 +194,39 @@ void MainWindow::changeEvent(QEvent* event) MainWindow::~MainWindow() { + if (configDialog) { + delete configDialog; + configDialog = NULL; + } delete ui; } void MainWindow::on_button_generate_clicked() { + + QFile mapperBinary; + if (currentSettings.mapperPath == "") + mapperBinary.setFileName(ConfigSettings::getDefaultMapperExecutable()); + else + mapperBinary.setFileName(currentSettings.mapperPath); + if (!mapperBinary.exists()) { + if (currentSettings.mapperPath == "") + QMessageBox::critical(this, tr("Minetestmapper not found"), + tr("ERROR: No minetestmapper executable could not be found

" + "Please configure one (Edit->Preferences)")); + else + QMessageBox::critical(this, tr("Minetestmapper not found"), + tr("ERROR: Configured minetestmapper executable (%1) could not be found

" + "Please configure one (Edit->Preferences)").arg(currentSettings.mapperPath)); + return; + } else if (!(mapperBinary.permissions() & QFileDevice::ExeUser)) { + QMessageBox::critical(this, tr("Minetestmapper not executable"), + tr("ERROR: The configured minetestmapper (%1) is not executable" + "Please configure a valid minetestmapper executable (Edit->Preferences)") + .arg(mapperBinary.fileName())); + return; + } + QDir worldPath = QDir(ui->path_World->text()); if(!worldPath.exists()||worldPath.path()=="."||worldPath.path()=="/"){ QMessageBox::critical(this, tr("no input world selected"), @@ -372,9 +403,10 @@ void MainWindow::on_button_generate_clicked() } myProcess = new QProcess(this); + #ifdef Q_OS_WIN myProcess->setWorkingDirectory(appDir); - QString program = appDir+"/mapper/minetestmapper"; - myProcess->setProgram(program); + #endif + myProcess->setProgram(mapperBinary.fileName()); qDebug()<setArguments(arguments); @@ -672,6 +704,10 @@ void MainWindow::writeProfile(QString profile) //todo: check the current profile settings.beginGroup("Mapper"); + //'currentSettings' + settings.setValue("path_minetestmapper", currentSettings.mapperPath); + + //tab1 General settings.setValue("path_OutputImage", ui->path_OutputImage->text()); settings.setValue("path_World", ui->path_World->text()); settings.setValue("backend",ui->backend->currentIndex()); @@ -743,6 +779,9 @@ void MainWindow::readProfile(QString profile) { QSettings settings(QSettings::IniFormat,QSettings::UserScope,qSettingsOrganisation, qSettingsApplicationPrefix+"profile_"+profile); settings.beginGroup("Mapper"); + //'currentSettings' + currentSettings.mapperPath = settings.value("path_minetestmapper").toString(); + //tab1 Genral ui->path_World->setText(settings.value("path_World",QDir::homePath()).toString()); ui->path_OutputImage->setText(settings.value("path_OutputImage",QDir::homePath().append("/map.png")).toString()); @@ -963,3 +1002,35 @@ void MainWindow::on_tileorigin_clicked() { ui->tiles_map->setText(tr("map origin (top left)")); } + +void MainWindow::on_actionPreferences_triggered() +{ + if (!configDialog) { + configDialog = new ConfigDialog(currentSettings, this, this); + configDialog->show(); + } else { + configDialog->show(); + configDialog->activateWindow(); + } +} + +void MainWindow::closeConfigDialog(void) +{ + if (configDialog) { + delete configDialog; + configDialog = NULL; + } +} + +void MainWindow::updateConfigSettings(const ConfigSettings &newSettings) +{ + if (newSettings.mapperPath != currentSettings.mapperPath) { + // Update all 'auto' paths (colors files, ...) ??? + // (currently there are none, but in the future, + // colors files could be searched for relative to the minetestmapper path. + // If the mapper path changes, the paths of the possible colors files + // may change as well + } + currentSettings = newSettings; +} + diff --git a/mainwindow.h b/mainwindow.h index c151b92..52a9bdd 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -17,6 +17,7 @@ #include #endif +#include "configdialog.h" namespace Ui { class MainWindow; @@ -30,6 +31,10 @@ public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); + // Interaction with config dialog + void closeConfigDialog(void); + void updateConfigSettings(const ConfigSettings &newSettings); + protected: void closeEvent(QCloseEvent* event); // this event is called, when a new translator is loaded or the system language is changed @@ -93,6 +98,8 @@ private slots: void on_tileorigin_clicked(); + void on_actionPreferences_triggered(); + private: Ui::MainWindow *ui; QProgressBar *progressBar; @@ -103,6 +110,9 @@ private: QWinTaskbarButton *taskbarButton; QWinTaskbarProgress *taskbarProgress; #endif + ConfigSettings currentSettings; + ConfigDialog *configDialog; + void finishUiInitialisation(void); // loads a language by the given language shortcur (e.g. de, en) diff --git a/mainwindow.ui b/mainwindow.ui index b396756..21485d3 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -2283,6 +2283,7 @@ + @@ -2568,6 +2569,11 @@ p, li { white-space: pre-wrap; } Open map after creation with the default png viewer + + + &Preferences + + From 505686ff8aab5dcbc917d6e55c4eedcf804cc5ec Mon Sep 17 00:00:00 2001 From: Rogier Date: Sat, 4 Jul 2015 07:42:27 +0200 Subject: [PATCH 3/4] Add function to obtain minetestmapper version --- configdialog.cpp | 36 ++++++++++++++++++++++++++++++++++++ configdialog.h | 3 +++ mainwindow.cpp | 2 ++ 3 files changed, 41 insertions(+) diff --git a/configdialog.cpp b/configdialog.cpp index 7c53bdd..5c8d3ad 100644 --- a/configdialog.cpp +++ b/configdialog.cpp @@ -12,6 +12,9 @@ const QString ConfigSettings::defaultMapperExecutableName("minetestmapper"); QStringList ConfigSettings::predefinedMapperLocations; +QString ConfigSettings::versionUnknown("(unknown)"); +QString ConfigSettings::versionError("(error)"); + ConfigSettings::InitStatics::InitStatics() { #ifndef Q_OS_WIN @@ -106,6 +109,39 @@ void ConfigDialog::on_browseMapper_clicked() } } +QString ConfigSettings::getMapperVersion(const QString &mapperBinary, QWidget *parent) +{ + QProcess mapperProcess(parent); + mapperProcess.setProgram(mapperBinary); + mapperProcess.setArguments(QStringList("--version")); + mapperProcess.start(); + if (!mapperProcess.waitForStarted(1000)) { + mapperProcess.terminate(); + return ConfigSettings::versionError; + } + if (!mapperProcess.waitForFinished(1000)) { + mapperProcess.terminate(); + if (!mapperProcess.waitForFinished(1000)) { + mapperProcess.kill(); + } + return ConfigSettings::versionError; + } + + QByteArray dataRaw; + QString data; + dataRaw = mapperProcess.readAllStandardError(); + data = QString(dataRaw).trimmed(); + if (data.contains("unrecognized option")) { + return ConfigSettings::versionUnknown; + } + dataRaw = mapperProcess.readAllStandardOutput(); + data = QString(dataRaw).trimmed(); + if (!data.contains("Version-ID:")) { + return ConfigSettings::versionUnknown; + } + return data.replace(QRegularExpression(".*Version-ID: *"),""); +} + QString ConfigSettings::getDefaultMapperExecutable(void) { QStringList locations = getMapperExecutables(); diff --git a/configdialog.h b/configdialog.h index fa8d60a..51760d6 100644 --- a/configdialog.h +++ b/configdialog.h @@ -13,10 +13,13 @@ struct ConfigSettings { QString mapperPath; + static QString versionUnknown; + static QString versionError; static QStringList getMapperExecutables(void); static QString getDefaultMapperExecutable(void); static const QString defaultMapperExecutableName; static QStringList predefinedMapperLocations; + static QString getMapperVersion(const QString &mapperBinary, QWidget *parent = NULL); private: struct InitStatics { InitStatics(void); }; diff --git a/mainwindow.cpp b/mainwindow.cpp index 773e6d0..9c1cecf 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -227,6 +227,8 @@ void MainWindow::on_button_generate_clicked() return; } + qDebug() << QString("Minetestmapper version: ") + ConfigSettings::getMapperVersion(mapperBinary.fileName(), this); + QDir worldPath = QDir(ui->path_World->text()); if(!worldPath.exists()||worldPath.path()=="."||worldPath.path()=="/"){ QMessageBox::critical(this, tr("no input world selected"), From 1e91517af443b9c09510f6a0783c28b652cd16c2 Mon Sep 17 00:00:00 2001 From: Rogier Date: Sat, 4 Jul 2015 07:42:31 +0200 Subject: [PATCH 4/4] Add a function to obtain a list of supported minetestmapper options (depending on how accurately the --help option reports them...) --- configdialog.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ configdialog.h | 8 ++++++++ 2 files changed, 56 insertions(+) diff --git a/configdialog.cpp b/configdialog.cpp index 5c8d3ad..c2121b5 100644 --- a/configdialog.cpp +++ b/configdialog.cpp @@ -14,6 +14,10 @@ QStringList ConfigSettings::predefinedMapperLocations; QString ConfigSettings::versionUnknown("(unknown)"); QString ConfigSettings::versionError("(error)"); +QString ConfigSettings::optionsVersionKey("(version)"); +QString ConfigSettings::optionsTreeKey("(github-tree)"); +QString ConfigSettings::optionsTreeMinetest("minetest"); +QString ConfigSettings::optionsTreeRogier5("Rogier5"); ConfigSettings::InitStatics::InitStatics() { @@ -142,6 +146,50 @@ QString ConfigSettings::getMapperVersion(const QString &mapperBinary, QWidget *p return data.replace(QRegularExpression(".*Version-ID: *"),""); } + +// Also store the deduced github source tree and the version in the list +QMap ConfigSettings::getMapperOptions(const QString &mapperBinary, QWidget *parent) +{ + QRegularExpression optionRegex("^(|-[a-zA-Z].*)(--[a-zA-Z0-9][a-zA-Z0-9-_]+)( *(.*[^ \t\r\n]))?[ \t\r\n]*$"); + QMap options; + QProcess mapperProcess(parent); + mapperProcess.setProgram(mapperBinary); + mapperProcess.setArguments(QStringList("--help")); + mapperProcess.start(); + if (!mapperProcess.waitForStarted(1000)) { + mapperProcess.terminate(); + return options; + } + if (!mapperProcess.waitForFinished(1000)) { + mapperProcess.terminate(); + if (!mapperProcess.waitForFinished(1000)) { + mapperProcess.kill(); + } + return options; + } + + QByteArray helpTextRaw = mapperProcess.readAllStandardOutput(); + QStringList helpText = QString(helpTextRaw).trimmed().split("\n"); + for (int i = 0; i < helpText.count(); i++) { + QString helpLine = helpText[i].trimmed(); + if (helpLine.contains("Color format: '#000000'")) { + options[ConfigSettings::optionsTreeKey] = ConfigSettings::optionsTreeMinetest; + } + else if (helpLine.contains("X and Y coordinate formats:")) { + options[ConfigSettings::optionsTreeKey] = ConfigSettings::optionsTreeRogier5; + } + QString option = helpLine; + option.replace(optionRegex, "\\2"); + if (option[1] != '-' || option.contains(' ')) continue; + QString arguments = helpLine; + arguments.replace(optionRegex, "\\4"); + if (arguments == helpLine) arguments = ""; + options[option] = arguments; + } + options[ConfigSettings::optionsVersionKey] = getMapperVersion(mapperBinary, parent); + return options; +} + QString ConfigSettings::getDefaultMapperExecutable(void) { QStringList locations = getMapperExecutables(); diff --git a/configdialog.h b/configdialog.h index 51760d6..32427dd 100644 --- a/configdialog.h +++ b/configdialog.h @@ -2,6 +2,8 @@ #define CONFIGDIALOG_H #include +#include +#include namespace Ui { @@ -15,11 +17,17 @@ struct ConfigSettings static QString versionUnknown; static QString versionError; + static QString optionsVersionKey; + static QString optionsTreeKey; + static QString optionsTreeMinetest; + static QString optionsTreeRogier5; + static QStringList getMapperExecutables(void); static QString getDefaultMapperExecutable(void); static const QString defaultMapperExecutableName; static QStringList predefinedMapperLocations; static QString getMapperVersion(const QString &mapperBinary, QWidget *parent = NULL); + static QMap getMapperOptions(const QString &mapperBinary, QWidget *parent = NULL); private: struct InitStatics { InitStatics(void); };