changeset 50:36ee5dd46fd3

Add GUI New Mainwindow that allows to set output formats and input files through a GUI.
author Andre Heinecke <andre.heinecke@intevation.de>
date Tue, 19 Jul 2016 12:19:45 +0200
parents a849b1de248f
children e9cc707838d1
files src/CMakeLists.txt src/constants.h src/filenamerequester.cpp src/filenamerequester.h src/l10n/main_de_DE.ts src/main.cpp src/mainwindow.cpp src/mainwindow.h
diffstat 8 files changed, 675 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/src/CMakeLists.txt	Tue Jul 19 12:18:57 2016 +0200
+++ b/src/CMakeLists.txt	Tue Jul 19 12:19:45 2016 +0200
@@ -17,6 +17,9 @@
     converter.cpp
     strhelp.c
     cconvert_options.h
+    icons/icon.rc
+    filenamerequester.cpp
+    mainwindow.cpp
 )
 
 find_package(Qt5LinguistTools)
@@ -36,6 +39,7 @@
         ${CMAKE_CURRENT_SOURCE_DIR}/l10n/main_de_DE.ts)
 endif()
 
+qt5_add_resources(APPLICATION_SRC icons/icons.qrc)
 
 add_executable(${PROJECT_NAME}
     ${_add_executable_params}
--- a/src/constants.h	Tue Jul 19 12:18:57 2016 +0200
+++ b/src/constants.h	Tue Jul 19 12:19:45 2016 +0200
@@ -91,4 +91,14 @@
 #define HTML_COL2_PERCENT 30
 #define HTML_COL3_PERCENT 35
 
+/**
+ * @brief name of the default icon. Only used on Linux to load
+ * the file from the resource. */
+#define ICON_NAME ":/64_icon-pdf.png"
+
+
+#define DEFAULT_DIR QStandardPaths::DownloadLocation
+
+#define MAX_FILENAME_COUNT 10000
+
 #endif // CONSTANTS_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/filenamerequester.cpp	Tue Jul 19 12:19:45 2016 +0200
@@ -0,0 +1,183 @@
+/* Copyright (C) 2016 by ETH Zürich
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU GPL (v>=2)
+ * and comes with ABSOLUTELY NO WARRANTY!
+ * See LICENSE.txt for details.
+ */
+
+/* This file was originally taken from Libkleo where the license was:
+    ui/filenamerequester.cpp
+
+    This file is part of Kleopatra, the KDE keymanager
+    Copyright (c) 2007 Klarälvdalens Datakonsult AB
+
+    Kleopatra 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.
+
+    Kleopatra 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
+
+    In addition, as a special exception, the copyright holders give
+    permission to link the code of this program with any edition of
+    the Qt library by Trolltech AS, Norway (or with modified versions
+    of Qt that use the same license as Qt), and distribute linked
+    combinations including the two.  You must obey the GNU General
+    Public License in all respects for all of the code used other than
+    Qt.  If you modify this file, you may extend this exception to
+    your version of the file, but you are not obligated to do so.  If
+    you do not wish to do so, delete this exception statement from
+    your version.
+*/
+
+#include "filenamerequester.h"
+
+#include <QLineEdit>
+
+#include <QHBoxLayout>
+#include <QToolButton>
+#include <QCompleter>
+#include <QDirModel>
+#include <QString>
+#include <QFileDialog>
+#include <QApplication>
+#include <QStyle>
+
+class FileNameRequester::Private
+{
+    friend class FileNameRequester;
+    FileNameRequester *const q;
+public:
+    explicit Private(FileNameRequester *qq);
+    ~Private();
+
+private:
+    void slotButtonClicked();
+
+private:
+    QDirModel  dirmodel;
+    QCompleter completer;
+
+    QLineEdit    lineedit;
+    QToolButton  button;
+    QHBoxLayout hlay;
+
+    QString nameFilter;
+    bool existingOnly;
+};
+
+FileNameRequester::Private::Private(FileNameRequester *qq)
+    : q(qq),
+      dirmodel(),
+      completer(&dirmodel),
+      lineedit(q),
+      button(q),
+      hlay(q),
+      nameFilter(),
+      existingOnly(true)
+{
+    dirmodel.setObjectName(QStringLiteral("dirmodel"));
+    completer.setObjectName(QStringLiteral("completer"));
+    lineedit.setObjectName(QStringLiteral("lineedit"));
+    button.setObjectName(QStringLiteral("button"));
+    hlay.setObjectName(QStringLiteral("hlay"));
+
+    button.setIcon(QApplication::style()->standardIcon(QStyle::SP_DirIcon));
+    lineedit.setCompleter(&completer);
+    lineedit.setClearButtonEnabled(true);
+    hlay.setMargin(0);
+    hlay.addWidget(&lineedit);
+    hlay.addWidget(&button);
+
+    connect(&button, SIGNAL(clicked()), q, SLOT(slotButtonClicked()));
+    connect(&lineedit, &QLineEdit::textChanged, q, &FileNameRequester::fileNameChanged);
+}
+
+FileNameRequester::Private::~Private() {}
+
+FileNameRequester::FileNameRequester(QWidget *p)
+    : QWidget(p), d(new Private(this))
+{
+
+}
+
+FileNameRequester::FileNameRequester(QDir::Filters f, QWidget *p)
+    : QWidget(p), d(new Private(this))
+{
+    d->dirmodel.setFilter(f);
+}
+
+FileNameRequester::~FileNameRequester()
+{
+    delete d;
+}
+
+void FileNameRequester::setFileName(const QString &file)
+{
+    d->lineedit.setText(file);
+}
+
+QString FileNameRequester::fileName() const
+{
+    return d->lineedit.text();
+}
+
+void FileNameRequester::setExistingOnly(bool on)
+{
+    d->existingOnly = on;
+}
+
+bool FileNameRequester::existingOnly() const
+{
+    return d->existingOnly;
+}
+
+void FileNameRequester::setFilter(QDir::Filters f)
+{
+    d->dirmodel.setFilter(f);
+}
+
+QDir::Filters FileNameRequester::filter() const
+{
+    return d->dirmodel.filter();
+}
+
+void FileNameRequester::setNameFilter(const QString &nameFilter)
+{
+    d->nameFilter = nameFilter;
+}
+
+QString FileNameRequester::nameFilter() const
+{
+    return d->nameFilter;
+}
+
+void FileNameRequester::Private::slotButtonClicked()
+{
+    const QString fileName = q->requestFileName();
+    if (!fileName.isEmpty()) {
+        q->setFileName(fileName);
+    }
+}
+
+QString FileNameRequester::requestFileName()
+{
+    const QDir::Filters filters = filter();
+    if ((filters & QDir::Dirs) && !(filters & QDir::Files)) {
+        return QFileDialog::getExistingDirectory(this);
+    } else if (d->existingOnly) {
+        return QFileDialog::getOpenFileName(this, QString(), QString(), d->nameFilter);
+    } else {
+        return QFileDialog::getSaveFileName(this, QString(), QString(), d->nameFilter);
+    }
+}
+
+#include "moc_filenamerequester.cpp"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/filenamerequester.h	Tue Jul 19 12:19:45 2016 +0200
@@ -0,0 +1,73 @@
+/* -*- mode: c++; c-basic-offset:4 -*-
+    ui/filenamerequester.h
+
+    This file is part of Kleopatra, the KDE keymanager
+    Copyright (c) 2007 Klarälvdalens Datakonsult AB
+
+    Kleopatra 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.
+
+    Kleopatra 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
+
+    In addition, as a special exception, the copyright holders give
+    permission to link the code of this program with any edition of
+    the Qt library by Trolltech AS, Norway (or with modified versions
+    of Qt that use the same license as Qt), and distribute linked
+    combinations including the two.  You must obey the GNU General
+    Public License in all respects for all of the code used other than
+    Qt.  If you modify this file, you may extend this exception to
+    your version of the file, but you are not obligated to do so.  If
+    you do not wish to do so, delete this exception statement from
+    your version.
+*/
+
+#ifndef __KLEOPATRA_UI_FILENAMEREQUESTER_H__
+#define __KLEOPATRA_UI_FILENAMEREQUESTER_H__
+
+#include <QWidget>
+
+#include <QDir>
+
+class FileNameRequester : public QWidget
+{
+    Q_OBJECT
+    Q_PROPERTY(QString fileName READ fileName WRITE setFileName)
+    Q_PROPERTY(bool existingOnly READ existingOnly WRITE setExistingOnly)
+public:
+    explicit FileNameRequester(QWidget *parent = Q_NULLPTR);
+    explicit FileNameRequester(QDir::Filters filter, QWidget *parent = Q_NULLPTR);
+    ~FileNameRequester();
+
+    void setFileName(const QString &name);
+    QString fileName() const;
+
+    void setExistingOnly(bool on);
+    bool existingOnly() const;
+
+    void setFilter(QDir::Filters f);
+    QDir::Filters filter() const;
+
+    void setNameFilter(const QString &nameFilter);
+    QString nameFilter() const;
+
+Q_SIGNALS:
+    void fileNameChanged(const QString &filename);
+
+private:
+    virtual QString requestFileName();
+
+private:
+    class Private;
+    Private *d;
+    Q_PRIVATE_SLOT(d, void slotButtonClicked())
+};
+#endif /* __KLEOPATRA_UI_FILENAMEREQUESTER_H__ */
--- a/src/l10n/main_de_DE.ts	Tue Jul 19 12:18:57 2016 +0200
+++ b/src/l10n/main_de_DE.ts	Tue Jul 19 12:19:45 2016 +0200
@@ -42,6 +42,84 @@
     </message>
 </context>
 <context>
+    <name>MainWindow</name>
+    <message>
+        <location filename="../mainwindow.cpp" line="49"/>
+        <source>Input File:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mainwindow.cpp" line="57"/>
+        <source>Export Folder:</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mainwindow.cpp" line="68"/>
+        <source>PDF</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mainwindow.cpp" line="69"/>
+        <source>Convert into PDF Format.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mainwindow.cpp" line="70"/>
+        <source>HTML</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mainwindow.cpp" line="71"/>
+        <source>Convert into HTML Format.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mainwindow.cpp" line="72"/>
+        <source>XLSX</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mainwindow.cpp" line="73"/>
+        <source>Convert into XLSX Format.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mainwindow.cpp" line="83"/>
+        <source>mandatory</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mainwindow.cpp" line="85"/>
+        <source>Title (e.g. Feedback Questions SS2016)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mainwindow.cpp" line="92"/>
+        <source>Convert</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mainwindow.cpp" line="110"/>
+        <source>Error!</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mainwindow.cpp" line="159"/>
+        <source>Failed to create output directory.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mainwindow.cpp" line="165"/>
+        <source>Failed to open &quot;%1&quot; for reading.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../mainwindow.cpp" line="199"/>
+        <source>Failed to find an available free name for &quot;%1&quot; please choose another folder.</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>QObject</name>
     <message>
         <location filename="../cconvert_options.h" line="22"/>
--- a/src/main.cpp	Tue Jul 19 12:18:57 2016 +0200
+++ b/src/main.cpp	Tue Jul 19 12:19:45 2016 +0200
@@ -16,6 +16,7 @@
 #include "strhelp.h"
 #include "converter.h"
 #include "cconvert_options.h"
+#include "mainwindow.h"
 
 #include <QApplication>
 #include <QCommandLineParser>
@@ -133,19 +134,29 @@
     if (args.size()) {
         infile = args.first();
     }
-    Converter conv(infile, parser.values("output"),
-                   parser.value("title"));
-
-    conv.start();
-    conv.wait();
 
-    const QStringList errors = conv.errors();
-    if (errors.isEmpty()) {
-        return 0;
+    MainWindow *mainWin = Q_NULLPTR;
+    const QStringList outputs = parser.values("output");
+    const QString title = parser.value("title");
+    if (outputs.isEmpty() || title.isEmpty()) {
+        mainWin = new MainWindow();
+        mainWin->setTitle(title);
+        mainWin->show();
+        app.exec();
+        delete mainWin;
     } else {
-        Q_FOREACH (const QString err, errors) {
-            qCritical() << err;
+        Converter conv(infile, parser.values("output"),
+                       parser.value("title"));
+
+        conv.start();
+        conv.wait();
+        const QStringList errors = conv.errors();
+        if (!errors.isEmpty()) {
+            Q_FOREACH (const QString err, errors) {
+                qCritical() << err;
+            }
+            return 1;
         }
     }
-    return 1;
+    return 0;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mainwindow.cpp	Tue Jul 19 12:19:45 2016 +0200
@@ -0,0 +1,234 @@
+/* Copyright (C) 2016 by ETH Zürich
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU GPL (v>=2)
+ * and comes with ABSOLUTELY NO WARRANTY!
+ * See LICENSE.txt for details.
+ */
+
+/** @file See mainwindow.h */
+#include "mainwindow.h"
+
+#include "constants.h"
+#include "converter.h"
+#include "filenamerequester.h"
+
+#include <QApplication>
+#include <QCheckBox>
+#include <QDebug>
+#include <QDialogButtonBox>
+#include <QDesktopServices>
+#include <QDir>
+#include <QGroupBox>
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QLineEdit>
+#include <QMessageBox>
+#include <QMimeData>
+#include <QPushButton>
+#include <QUrl>
+#include <QStandardPaths>
+#include <QStyle>
+#include <QVBoxLayout>
+#include <QWidget>
+#include <QGridLayout>
+
+MainWindow::MainWindow() {
+    setupGUI();
+    readSettings();
+#ifndef Q_OS_WIN
+    QIcon windowIcon = QIcon(ICON_NAME);
+    setWindowIcon(windowIcon);
+    setWindowTitle(QStringLiteral(APPNAME));
+#endif
+}
+
+void MainWindow::setupGUI() {
+    auto vLay = new QVBoxLayout;
+    auto inoutLay = new QGridLayout;
+    auto inputLabel = new QLabel(tr("Input File:"));
+    inoutLay->addWidget(inputLabel, 0, 0);
+    mInputRequester = new FileNameRequester(QDir::Files);
+    mInputRequester->setExistingOnly(true);
+    inputLabel->setBuddy(mInputRequester);
+
+    inoutLay->addWidget(mInputRequester, 0, 1);
+
+    auto outLabel = new QLabel(tr("Export Folder:"));
+    inoutLay->addWidget(outLabel, 1, 0);
+    mOutRequester = new FileNameRequester(QDir::Dirs);
+    mOutRequester->setExistingOnly(false);
+    inoutLay->addWidget(mOutRequester, 1, 1);
+    outLabel->setBuddy(mOutRequester);
+
+    vLay->addLayout(inoutLay);
+
+    auto optionsGrp = new QGroupBox("Export Options:");
+    auto optionsLay = new QVBoxLayout;
+    mPdfChk = new QCheckBox(tr("PDF"));
+    mPdfChk->setToolTip(tr("Convert into PDF Format."));
+    mHtmlChk = new QCheckBox(tr("HTML"));
+    mHtmlChk->setToolTip(tr("Convert into HTML Format."));
+    mXlsxChk = new QCheckBox(tr("XLSX"));
+    mXlsxChk->setToolTip(tr("Convert into XLSX Format."));
+
+    optionsLay->addWidget(mPdfChk);
+    optionsLay->addWidget(mHtmlChk);
+    optionsLay->addWidget(mXlsxChk);
+    optionsGrp->setLayout(optionsLay);
+    vLay->addWidget(optionsGrp);
+
+    mTitleEdit = new QLineEdit;
+    auto titleLay = new QHBoxLayout;
+    auto titleLabel = new QLabel(QStringLiteral("<small>") + tr("mandatory") +
+                                 QStringLiteral("</small>"));
+    mTitleEdit->setPlaceholderText(tr("Title (e.g. Feedback Questions SS2016)"));
+    titleLay->addWidget(mTitleEdit);
+    titleLay->addWidget(titleLabel);
+    vLay->addLayout(titleLay);
+    vLay->addStretch(1);
+    auto btns = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Close);
+    mConvertBtn = btns->button(QDialogButtonBox::Ok);
+    mConvertBtn->setText(tr("Convert"));
+    vLay->addWidget(btns);
+
+    auto widget = new QWidget;
+    widget->setLayout(vLay);
+    setCentralWidget(widget);
+    checkCompleted();
+
+    connect(mConvertBtn, &QPushButton::clicked, this, &MainWindow::doConvert);
+    connect(mPdfChk, &QCheckBox::stateChanged, this, &MainWindow::checkCompleted);
+    connect(mHtmlChk, &QCheckBox::stateChanged, this, &MainWindow::checkCompleted);
+    connect(mXlsxChk, &QCheckBox::stateChanged, this, &MainWindow::checkCompleted);
+    connect(mTitleEdit, &QLineEdit::textChanged, this, &MainWindow::checkCompleted);
+    connect(mInputRequester, &FileNameRequester::fileNameChanged, this, &MainWindow::checkCompleted);
+    connect(mOutRequester, &FileNameRequester::fileNameChanged, this, &MainWindow::checkCompleted);
+}
+
+void MainWindow::showErrorMessage(const QString& errMsg) {
+    QMessageBox::warning(this, tr("Error!"), errMsg);
+}
+
+void MainWindow::closeEvent(QCloseEvent *event) {
+    mSettings.setValue("geometry", saveGeometry());
+    mSettings.setValue("windowState", saveState());
+    QMainWindow::closeEvent(event);
+}
+
+void MainWindow::readSettings() {
+    if (mSettings.contains("geometry")) {
+        restoreGeometry(mSettings.value("geometry").toByteArray());
+        restoreState(mSettings.value("windowState").toByteArray());
+    }
+
+    setInputFile(mSettings.value("lastInput",
+                 QStandardPaths::writableLocation(DEFAULT_DIR)).toString());
+    mOutRequester->setFileName(mSettings.value("lastOutput",
+                 QStandardPaths::writableLocation(DEFAULT_DIR)).toString());
+
+    mPdfChk->setChecked(mSettings.value("pdfChk", true).toBool());
+    mHtmlChk->setChecked(mSettings.value("htmlChk", false).toBool());
+    mXlsxChk->setChecked(mSettings.value("xlsxChk", false).toBool());
+}
+
+void MainWindow::setInputFile(const QString& file)
+{
+    mInputRequester->setFileName(file);
+}
+
+void MainWindow::setTitle(const QString& title) {
+    mTitleEdit->setText(title);
+}
+
+void MainWindow::checkCompleted() {
+    if (!mTitleEdit->text().isEmpty() &&
+        (mPdfChk->isChecked() || mXlsxChk->isChecked() || mHtmlChk->isChecked())) {
+        mConvertBtn->setEnabled(true);
+    } else {
+        mConvertBtn->setEnabled(false);
+    }
+}
+
+void MainWindow::doConvert() {
+    /* Construct output names */
+    QStringList outNames;
+
+    QDir outDir(mOutRequester->fileName());
+    if (!outDir.exists() && !outDir.mkpath(mOutRequester->fileName())) {
+        showErrorMessage(tr("Failed to create output directory."));
+        return;
+    }
+
+    const QFileInfo fi(mInputRequester->fileName());
+    if (!fi.exists() || !fi.isReadable()) {
+        showErrorMessage(tr("Failed to open \"%1\" for reading.").arg(mInputRequester->fileName()));
+        return;
+    }
+    if (mPdfChk->isChecked()) {
+        outNames << outDir.absoluteFilePath(fi.baseName() + QStringLiteral(".pdf"));
+    }
+    if (mHtmlChk->isChecked()) {
+        outNames << outDir.absoluteFilePath(fi.baseName() + QStringLiteral(".html"));
+    }
+    if (mXlsxChk->isChecked()) {
+        outNames << outDir.absoluteFilePath(fi.baseName() + QStringLiteral(".xslx"));
+    }
+
+    QStringList cleanedNames;
+    foreach (const QString &name, outNames) {
+        const QFileInfo fi2(name);
+        if (!fi2.exists()) {
+            cleanedNames << name;
+            continue;
+        }
+        /* File exists. Lets try a number. */
+        bool replacementFound = false;
+        for (int i = 1; i < MAX_FILENAME_COUNT; i++) {
+            const QString newName = outDir.absoluteFilePath(QStringLiteral("%1_%2.%3").arg(
+                    fi2.baseName()).arg(i).arg(fi2.suffix()));
+            const QFileInfo fi3(newName);
+            if (!fi3.exists()) {
+                qDebug() << "Using " << newName << " as replacement because other files exist.";
+                cleanedNames << newName;
+                replacementFound = true;
+                break;
+            }
+        }
+        if (!replacementFound) {
+            showErrorMessage(tr("Failed to find an available free name for \"%1\" please choose another folder.").arg(name));
+            return;
+        }
+    }
+
+    mSettings.setValue("lastInput", mInputRequester->fileName());
+    mSettings.setValue("lastOutput", mOutRequester->fileName());
+    mSettings.setValue("pdfChk", mPdfChk->isChecked());
+    mSettings.setValue("xlsxChk", mXlsxChk->isChecked());
+    mSettings.setValue("htmlChk", mHtmlChk->isChecked());
+
+    /* Convert away */
+    Converter conv(mInputRequester->fileName(), cleanedNames, mTitleEdit->text());
+
+    conv.start();
+    hide();
+    qDebug() << "Waiting for conversion.";
+    conv.wait();
+    qDebug() << "Conversion done.";
+    const QStringList errors = conv.errors();
+    if (!errors.isEmpty()) {
+        Q_FOREACH (const QString err, errors) {
+            showErrorMessage(err);
+        }
+    }
+
+    if (cleanedNames.size() == 1) {
+        qDebug() << "Opening: " << QUrl(QStringLiteral("file:///%1").arg(cleanedNames[0]), QUrl::TolerantMode);
+        QDesktopServices::openUrl(QUrl(QStringLiteral("file:///%1").arg(cleanedNames[0]), QUrl::TolerantMode));
+    } else {
+        qDebug() << "Opening: " << QUrl(QStringLiteral("file:///%1").arg(outDir.path()), QUrl::TolerantMode);
+        QDesktopServices::openUrl(QUrl(QStringLiteral("file:///%1").arg(outDir.path()), QUrl::TolerantMode));
+    }
+
+    close();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mainwindow.h	Tue Jul 19 12:19:45 2016 +0200
@@ -0,0 +1,71 @@
+/* Copyright (C) 2016 by ETH Zürich
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU GPL (v>=2)
+ * and comes with ABSOLUTELY NO WARRANTY!
+ * See LICENSE.txt for details.
+ */
+
+
+/** @file The Main UI class.
+ *
+ * Parent class of all dialogs and graphical user interaction.
+ */
+#include <QMainWindow>
+#include <QSettings>
+
+class QPushButton;
+class QLineEdit;
+class QCheckBox;
+class FileNameRequester;
+
+/**
+ * @class MainWindow
+ * @brief The mainwindow of the application.
+ * @details Holds the input fields and export options.
+ */
+class MainWindow : public QMainWindow
+{
+    Q_OBJECT
+
+public:
+    MainWindow();
+
+protected:
+    /** @brief UI setup */
+    void setupGUI();
+
+    /** @brief Cleanup and save the current state */
+    virtual void closeEvent(QCloseEvent *event);
+
+    /** @brief Restores the last window state */
+    void readSettings();
+
+public slots:
+    /** @brief directly set an input file. */
+    void setInputFile(const QString& file);
+
+    /** @brief Prefill title with @title. */
+    void setTitle(const QString& title);
+
+protected slots:
+    /** @brief Show an error dialog to the user. */
+    void showErrorMessage(const QString& errMsg);
+
+    /** @brief check if all mandataory fields are set. */
+    void checkCompleted();
+
+    /** @brief Do the actual conversion. */
+    void doConvert();
+
+private:
+    QSettings mSettings;
+
+    FileNameRequester* mInputRequester;
+    FileNameRequester* mOutRequester;
+    QLineEdit *mTitleEdit;
+    QPushButton *mConvertBtn;
+    QCheckBox *mPdfChk,
+              *mXlsxChk,
+              *mHtmlChk;
+};
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)