aboutsummaryrefslogtreecommitdiff
path: root/lib/configuration/configuration.h
blob: b05728a3b6d5161c49f1328232de13b9ac9ff4ed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
 * This file is part of smolbote. It's copyrighted by the contributors recorded
 * in the version control history of the file, available from its original
 * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote
 *
 * SPDX-License-Identifier: GPL-3.0
 */

#ifndef SMOLBOTE_CONFIGURATION_H
#define SMOLBOTE_CONFIGURATION_H

#include <QAction>
#include <QString>
#include <QStringList>
#include <QVariant>
#include <boost/program_options.hpp>
#include <optional>
#include <string>
#include <vector>

class Configuration : public QObject
{
    Q_OBJECT

public:
    explicit Configuration(int argc, char** argv, const std::string &path, QObject *parent = nullptr);
    ~Configuration() = default;

    bool exists(const char *path)
    {
        return vm.count(path) ? true : false;
    }

    template <typename T>
    std::optional<T> value(const char *path) const
    {
        // if setting doesn't exist, we crash
        // in debug builds, check if setting exists

        if(vm.count(path) == 0) {
#ifdef QT_DEBUG
            qWarning("value(%s) does not exist", path);
#endif
            return std::nullopt;
        }

        // path is guaranteed to exist, so using vm[path] is safe

        if constexpr(std::is_same_v<T, QStringList>) {
            QStringList r;
            for(const std::string &item : vm[path].as<std::vector<std::string>>()) {
                r.append(QString::fromStdString(item));
            }
            return std::optional<QStringList>(r);

        } else if constexpr(std::is_same_v<T, std::string> || std::is_same_v<T, QString>) {

            if(vm[path].value().type() == typeid(int)) {
                if constexpr(std::is_same_v<T, std::string>)
                    return std::optional<std::string>(std::to_string(vm[path].as<int>()));
                else if constexpr(std::is_same_v<T, QString>)
                    return std::optional<QString>(QString::number(vm[path].as<int>()));
            }

            if(vm[path].value().type() == typeid(bool)) {
                return std::optional<T>(vm[path].as<bool>() ? "true" : "false");
            }

            std::string r = vm[path].as<std::string>();

            // check if it's a path
            if(r.front() == '~') {
                r.replace(0, 1, m_homePath);
            }

            if constexpr(std::is_same_v<T, std::string>)
                    return std::optional<std::string>(r);
            else if constexpr(std::is_same_v<T, QString>)
                    return std::optional<QString>(QString::fromStdString(r));

        } else
            return std::optional<T>(vm[path].as<T>());
    }

    template <typename T>
    void setValue(const char *path, const T &value)
    {
        if(vm.count(path) == 0) {
            qWarning("value(%s) does not exist", path);
        }

        vm.at(path).value() = value;

        emit settingChanged(path, value);
    }

    void setShortcut(QAction *action, const char *name) const
    {
        Q_CHECK_PTR(action);

        const auto shortcutText = this->value<QString>(name);
        if(shortcutText) {
            const QString tooltip = action->toolTip();
            action->setShortcut(QKeySequence::fromString(shortcutText.value()));
            action->setToolTip(QString("%1 (%2)").arg(tooltip, shortcutText.value()));

            connect(this, &Configuration::settingChanged, action, [=](const std::string &path, const QString &value) {
                if(path == name) {
                    action->setShortcut(QKeySequence::fromString(value));
                    action->setToolTip(QString("%1 (%2)").arg(tooltip, value));
                }
            });
        }
    }

    QHash<QString, QString> section(const std::string &prefix) const;
    const boost::program_options::options_description& description() const
    {
        return configuration_desc;
    }

signals:
    void settingChanged(const std::string &path, const QString &value);

private:
    boost::program_options::options_description configuration_desc;
    boost::program_options::variables_map vm;

    const std::string m_homePath;
};

#endif // SMOLBOTE_CONFIGURATION_H