From 165d5d7b3abc1c331365227a4028bc3ee590f055 Mon Sep 17 00:00:00 2001
From: Sergey Fedorov <barracuda@macos-powerpc.org>
Date: Tue, 11 Aug 2026 06:18:27 +0000
Subject: [PATCH 1/2] Add Qt4 build support behind QT_VERSION guards

Converseen's Qt5-only surface is small enough to emulate, so the tree can
target Qt4, Qt5 and Qt6 from one source. Every Qt4 path sits behind a
QT_VERSION guard, leaving Qt5/Qt6 behavior unchanged.

New src/qt4compat.h provides, for Qt4 only:
  - a QStandardPaths shim over QDesktopServices::storageLocation()/XDG that
    resolves to the same paths Qt5 uses, so existing settings are still found
  - QCommandLineOption/QCommandLineParser supporting aliases, "-o value",
    "--opt=value", valueless flags, --help and --version. Unknown options are
    skipped rather than fatal, so the macOS Finder's -psn_x_y argument does
    not stop the bundle from launching
  - Q_OS_MACOS/Q_OS_OSX aliases for Qt4's Q_OS_MAC

Guarded at the call sites:
  - QStorageInfo::rootPath() falls back to "/" (only AppImage differs)
  - QScreen/QGuiApplication device pixel ratio falls back to 1.0
  - AA_EnableHighDpiScaling, AA_UseHighDpiPixmaps, setDesktopFileName
  - QtConcurrent/QFutureWatcher includes; the directory scan runs inline
  - QComboBox::currentTextChanged() -> currentIndexChanged()
  - QHeaderView::setSectionResizeMode() -> setResizeMode()

The .ui files drop 3 toolTipDuration properties (all -1, the default) and 2
stepType properties, which Qt4's uic cannot emit. Adaptive stepping is
restored from code under a Qt 5.12 guard, so Qt5/Qt6 lose nothing.
showGroupSeparator is left alone: it is stdset="0", so uic emits setProperty()
and Qt4 treats it as a no-op.

Build with -DUSE_QT4=ON, or plain qmake, which detects QT_MAJOR_VERSION.
Qt4 builds use C++11, since Qt4 headers still use the register keyword.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PYgCCiu49ZE7W7TqTdxhBi
---
 CMakeLists.txt                 |  25 ++-
 converseen.pro                 |   8 +-
 src/dialogconversionstatus.cpp |   5 +
 src/globals.cpp                |   8 +
 src/inisettings.cpp            |   5 +
 src/main.cpp                   |  11 +-
 src/mainwindowimpl.cpp         |  54 ++++-
 src/qt4compat.h                | 347 +++++++++++++++++++++++++++++++++
 src/translator.cpp             |  16 +-
 ui/dialogquality.ui            |   6 -
 ui/mainwindow.ui               |   9 -
 11 files changed, 473 insertions(+), 21 deletions(-)
 create mode 100644 src/qt4compat.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index eb2778f..fbcb177 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -13,17 +13,30 @@ project(
 set(PROJECT_NAME_CAPITALIZED "Converseen")
 
 option(USE_QT6 "Enable this if you want to use Qt6, instead of Qt5" NO)
+option(USE_QT4 "Enable this if you want to use Qt4, instead of Qt5 (legacy platforms)" NO)
 option(MACOS_DEPLOY "Enable this if you want to deploy the program on MacOS" NO)
 
 set(GUI "converseen")
 set(QT_USE_QTNETWORK TRUE)
-set(CMAKE_CXX_STANDARD 17)
+
+if (USE_QT4)
+    # Qt4 headers predate C++17 and still use the 'register' storage class.
+    set(CMAKE_CXX_STANDARD 11)
+else ()
+    set(CMAKE_CXX_STANDARD 17)
+endif()
+
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
 include(GNUInstallDirs)
 
 if (USE_QT6)
     find_package(Qt6 COMPONENTS Core Gui Network Widgets LinguistTools Concurrent REQUIRED)
+elseif (USE_QT4)
+    # Qt4 keeps the widgets in QtGui and QtConcurrent in QtCore, so there are
+    # no Widgets/Concurrent components to request.
+    find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED)
+    include(${QT_USE_FILE})
 else ()
     find_package(Qt5 COMPONENTS Core Gui Network Widgets LinguistTools Concurrent REQUIRED)
 endif()
@@ -155,6 +168,11 @@ if (USE_QT6)
     qt6_wrap_cpp(converseen_MOC_SRCS ${converseen_HEADERS})
     qt6_add_resources(converseen_RESOURCES ${converseen_RESOURCES})
     qt6_add_translation(converseen_RESOURCES ${converseen_LANG})
+elseif (USE_QT4)
+    qt4_wrap_ui(converseen_UIS_H ${converseen_UIS})
+    qt4_wrap_cpp(converseen_MOC_SRCS ${converseen_HEADERS})
+    qt4_add_resources(converseen_RESOURCES ${converseen_RESOURCES})
+    qt4_add_translation(converseen_RESOURCES ${converseen_LANG})
 else ()
     qt5_wrap_ui(converseen_UIS_H ${converseen_UIS})
     qt5_wrap_cpp(converseen_MOC_SRCS ${converseen_HEADERS})
@@ -247,6 +265,11 @@ if (USE_QT6)
 		Qt6::Concurrent
         ${ImageMagick_LIBRARIES}
     )
+elseif (USE_QT4)
+    target_link_libraries(${GUI}
+        ${QT_LIBRARIES}
+        ${ImageMagick_LIBRARIES}
+    )
 else()
     target_link_libraries(${GUI}
         Qt5::Core
diff --git a/converseen.pro b/converseen.pro
index c4d894e..7123505 100755
--- a/converseen.pro
+++ b/converseen.pro
@@ -1,9 +1,15 @@
 TEMPLATE = app
-QT = gui core network widgets concurrent
+
+# Qt4 keeps the widgets in QtGui and QtConcurrent in QtCore.
+QT = gui core network
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets concurrent
+
 CONFIG += qt \
  release \
  warn_on
 
+equals(QT_MAJOR_VERSION, 4): CONFIG += c++11
+
 win32:CONFIG += entrypoint
 
 macx {
diff --git a/src/dialogconversionstatus.cpp b/src/dialogconversionstatus.cpp
index 730e0e0..97af6f9 100755
--- a/src/dialogconversionstatus.cpp
+++ b/src/dialogconversionstatus.cpp
@@ -44,7 +44,12 @@ DialogConversionStatus::DialogConversionStatus(QWidget *parent) :
     connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(openDir(QAction*)));
     connect(actionOpenAllDirs, SIGNAL(triggered()), this, SLOT(openAllDirs()));
 
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
     treeWidget->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
+#else
+    // QHeaderView::setResizeMode() was renamed to setSectionResizeMode() in Qt5.
+    treeWidget->header()->setResizeMode(1, QHeaderView::ResizeToContents);
+#endif
 }
 
 void DialogConversionStatus::setup(int n_images)
diff --git a/src/globals.cpp b/src/globals.cpp
index 865d458..e18bd24 100755
--- a/src/globals.cpp
+++ b/src/globals.cpp
@@ -21,8 +21,13 @@
 *
 */
 
+#include <QtGlobal>
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
 #include <QScreen>
 #include <QGuiApplication>
+#endif
+
 #include "globals.h"
 
 QString globals::Globals::m_sig;
@@ -52,10 +57,13 @@ qreal globals::Globals::scaleFactor()
 {
     qreal scale = 1.0;
 
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
     if (QGuiApplication::screens().count() > 0) {
         QScreen *screen = QGuiApplication::screens().at(0);
         scale = screen->devicePixelRatio();
     }
+#endif
+    // Qt4 has no per-screen device pixel ratio: it always renders at 1x.
 
     return scale;
 }
diff --git a/src/inisettings.cpp b/src/inisettings.cpp
index 39e3667..76fb1fe 100755
--- a/src/inisettings.cpp
+++ b/src/inisettings.cpp
@@ -21,7 +21,12 @@
 *
 */
 
+#include "qt4compat.h"
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
 #include <QStandardPaths>
+#endif
+
 #include "inisettings.h"
 
 #define INIFILENAME ".converseen.conf"
diff --git a/src/main.cpp b/src/main.cpp
index da06095..fd8a8cc 100755
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -24,11 +24,16 @@
 #include <QApplication>
 #include <QLibraryInfo>
 #include <QDir>
-#include <QCommandLineParser>
 #include <QWidget>
 #include <QStyleFactory>
 #include <Magick++.h>
 
+#include "qt4compat.h"
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
+#include <QCommandLineParser>
+#endif
+
 #include "mainwindowimpl.h"
 #include "inisettings.h"
 
@@ -48,7 +53,9 @@ int main(int argc, char ** argv)
 
 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
     QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
+#endif
 
+#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
     QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
     QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
 #endif
@@ -60,7 +67,9 @@ int main(int argc, char ** argv)
     if (theme != "none")
         app.setStyle(QStyleFactory::create(theme));
 
+#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
     app.setDesktopFileName("net.fasterland.converseen");
+#endif
 
     QCommandLineOption winMagickPathOption({{"m", "debugMagickWindowsPath"}, "Set the default ImageMagick path on Windows (for debug purpose only!).", "C:\\MagickInstallPath"});
     QCommandLineOption importTxtListOption({{"l", "list"}, "Reads a txt file with a list of files to be imported.", "list.txt"});
diff --git a/src/mainwindowimpl.cpp b/src/mainwindowimpl.cpp
index 1095435..1897df6 100755
--- a/src/mainwindowimpl.cpp
+++ b/src/mainwindowimpl.cpp
@@ -25,10 +25,16 @@
 #include <QTimer>
 #include <QStyleFactory>
 #include <QImageReader>
-#include <QtConcurrent>
-#include <QFutureWatcher>
 #include <QProgressDialog>
 #include <string>
+
+#include "qt4compat.h"
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+#include <QtConcurrent>
+#include <QFutureWatcher>
+#endif
+
 #include "mainwindowimpl.h"
 #include "dialogoptions.h"
 #include "dialoginfo.h"
@@ -47,6 +53,12 @@ MainWindowImpl::MainWindowImpl(QWidget * parent)
 {
     setupUi(this);
 
+#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
+    // Set from code rather than the .ui file, which has to stay parseable by Qt4's uic.
+    spin_geoWidth->setStepType(QAbstractSpinBox::AdaptiveDecimalStepType);
+    spin_geoHeight->setStepType(QAbstractSpinBox::AdaptiveDecimalStepType);
+#endif
+
     iAList = new QList<ImageAttributes>;
     convertThread = new Converter(this);
     dlgCStatus = new DialogConversionStatus(this);
@@ -64,7 +76,12 @@ MainWindowImpl::MainWindowImpl(QWidget * parent)
     connect(spin_geoWidth, SIGNAL(editingFinished()), this, SLOT(relativeSizeW()));
     connect(spin_geoHeight, SIGNAL(editingFinished()), this, SLOT(relativeSizeH()));
 
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
     connect(comboResizeValues, SIGNAL(currentTextChanged(QString)), this, SLOT(selectGeometryUnit(QString)));
+#else
+    // QComboBox::currentTextChanged() arrived in Qt5.
+    connect(comboResizeValues, SIGNAL(currentIndexChanged(QString)), this, SLOT(selectGeometryUnit(QString)));
+#endif
 
     connect(checkRename, SIGNAL(stateChanged(int)), this, SLOT(enableRenameLine()));
     connect(radioPrefixSuffix, SIGNAL(clicked()), this, SLOT(enableProgressiveSpin()));
@@ -96,7 +113,12 @@ MainWindowImpl::MainWindowImpl(QWidget * parent)
     adjustSize();
     dockWidget->adjustSize();
 
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
     treeWidget->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
+#else
+    // QHeaderView::setResizeMode() was renamed to setSectionResizeMode() in Qt5.
+    treeWidget->header()->setResizeMode(0, QHeaderView::ResizeToContents);
+#endif
 
     treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
     createContextMenu();
@@ -410,6 +432,7 @@ void MainWindowImpl::loadDirectoryFiles(
     QApplication::setOverrideCursor(Qt::WaitCursor);
     progress->show();
 
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
     auto *watcher = new QFutureWatcher<QStringList>(this);
 
     connect(watcher, &QFutureWatcher<QStringList>::finished,
@@ -443,6 +466,33 @@ void MainWindowImpl::loadDirectoryFiles(
 
             return fileNames;
         }));
+#else
+    /*
+     * Qt4's QtConcurrent::run() only accepts functors exposing a result_type
+     * typedef, which lambdas do not provide, and its connect() has no
+     * pointer-to-member-function overload. The scan therefore runs inline here,
+     * as it did before the threaded version was introduced.
+     */
+    QApplication::processEvents();
+
+    QStringList fileNames;
+
+    QDirIterator it(directory,
+                    readableFiltersList,
+                    QDir::Files,
+                    flag);
+
+    while (it.hasNext())
+        fileNames << it.next();
+
+    if (!fileNames.isEmpty())
+        loadFiles(fileNames);
+
+    progress->close();
+    progress->deleteLater();
+
+    QApplication::restoreOverrideCursor();
+#endif
 }
 
 void MainWindowImpl::loadFiles(QStringList fileNames)
diff --git a/src/qt4compat.h b/src/qt4compat.h
new file mode 100644
index 0000000..1e2e7d5
--- /dev/null
+++ b/src/qt4compat.h
@@ -0,0 +1,347 @@
+/*
+* This file is part of Converseen, an open-source batch image converter
+* and resizer.
+*
+* (C) Francesco Mondello 2009 - 2026
+*
+* 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 3 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, see <http://www.gnu.org/licenses/>.
+*
+* Contact e-mail: Francesco Mondello <faster3ck@gmail.com>
+*
+*/
+
+/*
+ * Qt4 compatibility shims.
+ *
+ * Converseen targets Qt5/Qt6, but the Qt5-only surface it relies on is small
+ * enough to emulate. This header provides the missing pieces when building
+ * against Qt4; under Qt5 and Qt6 it expands to nothing.
+ */
+
+#ifndef QT4COMPAT_H
+#define QT4COMPAT_H
+
+#include <QtGlobal>
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
+
+#include <QCoreApplication>
+#include <QDesktopServices>
+#include <QDir>
+#include <QMap>
+#include <QString>
+#include <QStringList>
+#include <QTextStream>
+
+#include <cstdio>
+#include <cstdlib>
+
+/*
+ * Platform macros: Qt 5.0 introduced Q_OS_OSX and Qt 5.4 Q_OS_MACOS, both
+ * spelled Q_OS_MAC (or Q_OS_MACX) in Qt4.
+ */
+#if defined(Q_OS_MAC)
+#  ifndef Q_OS_MACOS
+#    define Q_OS_MACOS
+#  endif
+#  ifndef Q_OS_OSX
+#    define Q_OS_OSX
+#  endif
+#endif
+
+/*
+ * QStandardPaths (Qt 5.0). Only the locations Converseen actually asks for are
+ * resolved properly; anything else falls back to Qt4's DataLocation.
+ */
+class QStandardPaths
+{
+public:
+    enum StandardLocation {
+        DesktopLocation,
+        DocumentsLocation,
+        FontsLocation,
+        ApplicationsLocation,
+        MusicLocation,
+        MoviesLocation,
+        PicturesLocation,
+        TempLocation,
+        HomeLocation,
+        AppLocalDataLocation,
+        CacheLocation,
+        GenericDataLocation,
+        RuntimeLocation,
+        ConfigLocation,
+        DownloadLocation,
+        GenericCacheLocation,
+        GenericConfigLocation,
+        AppDataLocation,
+        AppConfigLocation
+    };
+
+    static QString writableLocation(StandardLocation type)
+    {
+        switch (type) {
+        case ConfigLocation:
+        case GenericConfigLocation:
+        case AppConfigLocation:
+#if defined(Q_OS_WIN)
+            return QDesktopServices::storageLocation(QDesktopServices::DataLocation);
+#elif defined(Q_OS_MAC)
+            return QDir::homePath() + QLatin1String("/Library/Preferences");
+#else
+        {
+            const QString xdgConfigHome =
+                QString::fromLocal8Bit(qgetenv("XDG_CONFIG_HOME"));
+
+            return xdgConfigHome.isEmpty()
+                ? QDir::homePath() + QLatin1String("/.config")
+                : xdgConfigHome;
+        }
+#endif
+        case HomeLocation:
+            return QDir::homePath();
+
+        case TempLocation:
+            return QDir::tempPath();
+
+        default:
+            return QDesktopServices::storageLocation(QDesktopServices::DataLocation);
+        }
+    }
+
+    static QStringList standardLocations(StandardLocation type)
+    {
+        return QStringList() << writableLocation(type);
+    }
+};
+
+/*
+ * QCommandLineOption / QCommandLineParser (Qt 5.2), reduced to the subset
+ * Converseen uses: named options with an optional value, --help and --version.
+ */
+class QCommandLineOption
+{
+public:
+    // Qt4's QList requires a default-constructible value type.
+    QCommandLineOption() {}
+
+    QCommandLineOption(const QStringList &names,
+                       const QString &description = QString(),
+                       const QString &valueName = QString())
+        : m_names(names)
+        , m_description(description)
+        , m_valueName(valueName)
+    {
+    }
+
+    QCommandLineOption(const QString &name,
+                       const QString &description = QString(),
+                       const QString &valueName = QString())
+        : m_names(QStringList(name))
+        , m_description(description)
+        , m_valueName(valueName)
+    {
+    }
+
+    QStringList names() const { return m_names; }
+    QString description() const { return m_description; }
+    QString valueName() const { return m_valueName; }
+
+private:
+    QStringList m_names;
+    QString m_description;
+    QString m_valueName;
+};
+
+class QCommandLineParser
+{
+public:
+    QCommandLineParser()
+        : m_helpAdded(false)
+        , m_versionAdded(false)
+    {
+    }
+
+    void setApplicationDescription(const QString &description)
+    {
+        m_description = description;
+    }
+
+    QString applicationDescription() const { return m_description; }
+
+    bool addOption(const QCommandLineOption &option)
+    {
+        m_options.append(option);
+        return true;
+    }
+
+    QCommandLineOption addHelpOption()
+    {
+        QCommandLineOption option(QStringList() << QLatin1String("h") << QLatin1String("help"),
+                                  QLatin1String("Displays this help."));
+        m_options.append(option);
+        m_helpAdded = true;
+
+        return option;
+    }
+
+    QCommandLineOption addVersionOption()
+    {
+        QCommandLineOption option(QStringList() << QLatin1String("v") << QLatin1String("version"),
+                                  QLatin1String("Displays version information."));
+        m_options.append(option);
+        m_versionAdded = true;
+
+        return option;
+    }
+
+    void process(const QCoreApplication &app)
+    {
+        process(app.arguments());
+    }
+
+    void process(const QStringList &arguments)
+    {
+        for (int i = 1; i < arguments.count(); i++) {
+            QString argument = arguments.at(i);
+
+            if (!argument.startsWith(QLatin1Char('-'))) {
+                m_positionalArguments.append(argument);
+                continue;
+            }
+
+            while (argument.startsWith(QLatin1Char('-')))
+                argument.remove(0, 1);
+
+            QString inlineValue;
+            bool hasInlineValue = false;
+
+            const int separator = argument.indexOf(QLatin1Char('='));
+
+            if (separator >= 0) {
+                inlineValue = argument.mid(separator + 1);
+                argument = argument.left(separator);
+                hasInlineValue = true;
+            }
+
+            const QCommandLineOption *option = findOption(argument);
+
+            /*
+             * Unknown options are ignored rather than fatal: on macOS the
+             * Finder appends a -psn_x_y process serial number to argv, and
+             * bailing out there would stop the bundle from launching.
+             */
+            if (!option)
+                continue;
+
+            const QString key = option->names().first();
+
+            if (option->valueName().isEmpty())
+                m_values.insert(key, QString());
+            else if (hasInlineValue)
+                m_values.insert(key, inlineValue);
+            else if (i + 1 < arguments.count())
+                m_values.insert(key, arguments.at(++i));
+            else
+                m_values.insert(key, QString());
+        }
+
+        if (m_helpAdded && m_values.contains(QLatin1String("h")))
+            showHelp(0);
+
+        if (m_versionAdded && m_values.contains(QLatin1String("v"))) {
+            QTextStream(stdout) << QCoreApplication::applicationName()
+                                << QLatin1Char(' ')
+                                << QCoreApplication::applicationVersion()
+                                << endl;
+            ::exit(0);
+        }
+    }
+
+    bool isSet(const QCommandLineOption &option) const
+    {
+        return m_values.contains(option.names().first());
+    }
+
+    QString value(const QCommandLineOption &option) const
+    {
+        return m_values.value(option.names().first());
+    }
+
+    QStringList positionalArguments() const { return m_positionalArguments; }
+
+    void showHelp(int exitCode = 0)
+    {
+        QTextStream out(stdout);
+
+        out << QLatin1String("Usage: ") << QCoreApplication::applicationFilePath()
+            << QLatin1String(" [options]") << endl;
+
+        if (!m_description.isEmpty())
+            out << m_description << endl;
+
+        out << endl << QLatin1String("Options:") << endl;
+
+        for (int i = 0; i < m_options.count(); i++) {
+            const QCommandLineOption &option = m_options.at(i);
+            QStringList flags = option.names();
+
+            for (int n = 0; n < flags.count(); n++)
+                flags[n] = (flags.at(n).length() == 1 ? QLatin1String("-") : QLatin1String("--"))
+                           + flags.at(n);
+
+            QString entry = QLatin1String("  ") + flags.join(QLatin1String(", "));
+
+            if (!option.valueName().isEmpty())
+                entry += QLatin1String(" <") + option.valueName() + QLatin1Char('>');
+
+            out << entry;
+
+            if (!option.description().isEmpty()) {
+                if (entry.length() < 32)
+                    out << QString(32 - entry.length(), QLatin1Char(' '));
+                else
+                    out << endl << QString(32, QLatin1Char(' '));
+
+                out << option.description();
+            }
+
+            out << endl;
+        }
+
+        ::exit(exitCode);
+    }
+
+private:
+    const QCommandLineOption *findOption(const QString &name) const
+    {
+        for (int i = 0; i < m_options.count(); i++) {
+            if (m_options.at(i).names().contains(name))
+                return &m_options.at(i);
+        }
+
+        return 0;
+    }
+
+    QString m_description;
+    QList<QCommandLineOption> m_options;
+    QMap<QString, QString> m_values;
+    QStringList m_positionalArguments;
+    bool m_helpAdded;
+    bool m_versionAdded;
+};
+
+#endif // QT_VERSION < 5.0.0
+
+#endif // QT4COMPAT_H
diff --git a/src/translator.cpp b/src/translator.cpp
index 930011c..2fa5e58 100755
--- a/src/translator.cpp
+++ b/src/translator.cpp
@@ -24,9 +24,17 @@
 #include <QLibraryInfo>
 #include <QLocale>
 #include <QDir>
-#include <QStorageInfo>
 #include <QCoreApplication>
+
+#include "qt4compat.h"
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
+#include <QStorageInfo>
+#endif
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
 #include <QStandardPaths>
+#endif
 
 #include "translator.h"
 #include "inisettings.h"
@@ -76,8 +84,14 @@ QString Translator::findLangDir()
     QString binDir = QCoreApplication::applicationDirPath();
     QString langDir = "";
 
+#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
     QStorageInfo storage(qApp->applicationDirPath());
     QString rootPath = storage.rootPath();
+#else
+    // Qt4 has no QStorageInfo. The root of the volume holding the binary only
+    // differs from "/" for relocatable bundles (AppImage), which Qt4 never targets.
+    QString rootPath = QLatin1String("/");
+#endif
 
 #if defined(Q_OS_LINUX)
     QStringList langDirs;
diff --git a/ui/dialogquality.ui b/ui/dialogquality.ui
index be1ed72..83f81d1 100755
--- a/ui/dialogquality.ui
+++ b/ui/dialogquality.ui
@@ -156,9 +156,6 @@
          <property name="toolTip">
           <string/>
          </property>
-         <property name="toolTipDuration">
-          <number>-1</number>
-         </property>
          <property name="whatsThis">
           <string/>
          </property>
@@ -207,9 +204,6 @@
               <property name="toolTip">
                <string/>
               </property>
-              <property name="toolTipDuration">
-               <number>-1</number>
-              </property>
               <property name="maximum">
                <number>9</number>
               </property>
diff --git a/ui/mainwindow.ui b/ui/mainwindow.ui
index 62325dc..aa926ec 100755
--- a/ui/mainwindow.ui
+++ b/ui/mainwindow.ui
@@ -867,9 +867,6 @@ p, li { white-space: pre-wrap; }
                       <property name="maximum">
                        <double>262144.000000000000000</double>
                       </property>
-                      <property name="stepType">
-                       <enum>QAbstractSpinBox::StepType::AdaptiveDecimalStepType</enum>
-                      </property>
                       <property name="value">
                        <double>100.000000000000000</double>
                       </property>
@@ -910,9 +907,6 @@ p, li { white-space: pre-wrap; }
                       <property name="maximum">
                        <double>262144.000000000000000</double>
                       </property>
-                      <property name="stepType">
-                       <enum>QAbstractSpinBox::StepType::AdaptiveDecimalStepType</enum>
-                      </property>
                       <property name="value">
                        <double>100.000000000000000</double>
                       </property>
@@ -967,9 +961,6 @@ p, li { white-space: pre-wrap; }
                       <property name="toolTip">
                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:700;&quot;&gt;Link Aspect Ratio with Selected Image&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Automatically adjusts the aspect ratio values when you enter a value in the &lt;span style=&quot; font-weight:700;&quot;&gt;Width/Height&lt;/span&gt; fields.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
                       </property>
-                      <property name="toolTipDuration">
-                       <number>-1</number>
-                      </property>
                       <property name="statusTip">
                        <string/>
                       </property>
