aboutsummaryrefslogtreecommitdiff
path: root/lib/configuration/configuration.h
blob: 15245368c9ef0ee8fbe25ee3f6fc61973944541d (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
133
134
/*
 * 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(QObject *parent = nullptr);
    ~Configuration() = default;

    bool parse(const std::string &path);
    bool parse(int argc, char **argv);

    const std::vector<boost::shared_ptr<boost::program_options::option_description>> &options()
    {
        return configuration_desc.options();
    }

    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;
        }

        if constexpr(std::is_same_v<T, QString>) {
            return std::optional<QString>(QString::fromStdString(this->value<std::string>(path).value()));
            //return std::optional<QString>(vm[path].as<const char*>());

        } else if constexpr(std::is_same_v<T, QStringList>) {
            QStringList r;
            for(const std::string &item : this->value<std::vector<std::string>>(path).value()) {
                r.append(QString::fromStdString(item));
            }
            return std::optional<QStringList>(r);

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

            if(vm[path].value().type() == typeid(int)) {
                return std::optional<std::string>(std::to_string(vm[path].as<int>()));
            }

            if(vm[path].value().type() == typeid(bool)) {
                return std::optional<std::string>(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);
            }

            return std::optional<std::string>(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);

        action->setShortcut(QKeySequence::fromString(value<QString>(name).value()));
        connect(this, &Configuration::settingChanged, action, [=](const std::string &path, const QString &value) {
            if(path == name)
                action->setShortcut(QKeySequence::fromString(value));
        });
    }

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

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

private:
    boost::program_options::options_description commandLine_desc;
    boost::program_options::options_description configuration_desc;
    boost::program_options::positional_options_description arguments_desc;
    boost::program_options::variables_map vm;

    const std::string m_homePath;
};

#endif // SMOLBOTE_CONFIGURATION_H