diff --git a/src/base/CMakeLists.txt b/src/base/CMakeLists.txt index 6e9386cc7..f3de1d9b0 100644 --- a/src/base/CMakeLists.txt +++ b/src/base/CMakeLists.txt @@ -51,6 +51,7 @@ add_library(qbt_base STATIC http/types.h iconprovider.h indexrange.h + interfaces/istringable.h logger.h net/dnsupdater.h net/downloadhandlerimpl.h diff --git a/src/base/base.pri b/src/base/base.pri index 9b5baeb9d..0893f282b 100644 --- a/src/base/base.pri +++ b/src/base/base.pri @@ -50,6 +50,7 @@ HEADERS += \ $$PWD/http/types.h \ $$PWD/iconprovider.h \ $$PWD/indexrange.h \ + $$PWD/interfaces/istringable.h \ $$PWD/logger.h \ $$PWD/net/dnsupdater.h \ $$PWD/net/downloadhandlerimpl.h \ diff --git a/src/base/interfaces/istringable.h b/src/base/interfaces/istringable.h new file mode 100644 index 000000000..5cbc36a9e --- /dev/null +++ b/src/base/interfaces/istringable.h @@ -0,0 +1,40 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2022 Mike Tzou (Chocobo1) + * + * 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 2 + * 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, 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 this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#pragma once + +class QString; + +class IStringable +{ +public: + virtual ~IStringable() = default; + + // requirement: T(const QString &) constructor for derived class `T` // TODO: try enforce it in C++20 concept + virtual QString toString() const = 0; +}; diff --git a/src/base/path.h b/src/base/path.h index fb2b97c2f..24a3bb7d6 100644 --- a/src/base/path.h +++ b/src/base/path.h @@ -35,7 +35,9 @@ #include "pathfwd.h" -class Path final +#include "base/interfaces/istringable.h" + +class Path final : public IStringable { public: Path() = default; @@ -64,7 +66,7 @@ public: Path relativePathOf(const Path &childPath) const; QString data() const; - QString toString() const; + QString toString() const override; Path &operator/=(const Path &other); Path &operator+=(const QString &str); diff --git a/src/base/settingsstorage.h b/src/base/settingsstorage.h index f9263a27f..c22081589 100644 --- a/src/base/settingsstorage.h +++ b/src/base/settingsstorage.h @@ -34,9 +34,10 @@ #include #include #include +#include #include -#include "path.h" +#include "base/interfaces/istringable.h" #include "utils/string.h" template @@ -45,7 +46,11 @@ struct IsQFlags : std::false_type {}; template struct IsQFlags> : std::true_type {}; -class SettingsStorage : public QObject +// There are 2 ways for class `T` provide serialization support into `SettingsStorage`: +// 1. If the `T` state is intended for users to edit (via a text editor), then +// implement `IStringable` interface +// 2. Otherwise, use `Q_DECLARE_METATYPE(T)` and let `QMetaType` handle the serialization +class SettingsStorage final : public QObject { Q_OBJECT SettingsStorage(); @@ -59,7 +64,12 @@ public: template T loadValue(const QString &key, const T &defaultValue = {}) const { - if constexpr (std::is_enum_v) + if constexpr (std::is_base_of_v) + { + const QString value = loadValue(key, defaultValue.toString()); + return T {value}; + } + else if constexpr (std::is_enum_v) { const auto value = loadValue(key); return Utils::String::toEnum(value, defaultValue); @@ -69,11 +79,6 @@ public: const typename T::Int value = loadValue(key, static_cast(defaultValue)); return T {value}; } - else if constexpr (std::is_same_v) - { - const auto value = loadValue(key, defaultValue.toString()); - return Path(value); - } else if constexpr (std::is_same_v) { // fast path for loading QVariant @@ -90,12 +95,12 @@ public: template void storeValue(const QString &key, const T &value) { - if constexpr (std::is_enum_v) + if constexpr (std::is_base_of_v) + storeValueImpl(key, value.toString()); + else if constexpr (std::is_enum_v) storeValueImpl(key, Utils::String::fromEnum(value)); else if constexpr (IsQFlags::value) storeValueImpl(key, static_cast(value)); - else if constexpr (std::is_same_v) - storeValueImpl(key, value.toString()); else storeValueImpl(key, QVariant::fromValue(value)); }