diff options
-rwxr-xr-x | CMakeLists.txt | 1 | ||||
-rw-r--r-- | gui/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gui/main-window.cpp | 35 | ||||
-rw-r--r-- | gui/main-window.hpp | 4 | ||||
-rw-r--r-- | gui/main.cpp | 9 | ||||
-rw-r--r-- | migration/20160906_0-mappings.cpp | 14 | ||||
-rw-r--r-- | migration/20160906_1-axis-signs.cpp | 0 | ||||
-rw-r--r-- | migration/CMakeLists.txt | 2 | ||||
-rw-r--r-- | migration/export.hpp | 28 | ||||
-rw-r--r-- | migration/migration.cpp | 129 | ||||
-rw-r--r-- | migration/migration.hpp | 72 | ||||
-rw-r--r-- | options/bundle.cpp | 10 | ||||
-rw-r--r-- | options/bundle.hpp | 6 | ||||
-rw-r--r-- | options/group.cpp | 4 | ||||
-rw-r--r-- | options/group.hpp | 5 |
15 files changed, 294 insertions, 26 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fadd0f6..c2353d70 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ file(GLOB opentrack-subprojects "qxt-mini/${C}" "macosx/${C}" "cv/${C}" + "migration/${C}" ) list(SORT opentrack-subprojects) diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index c793a65f..f33e2a3d 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -13,6 +13,7 @@ opentrack_boilerplate(opentrack EXECUTABLE BIN ${console}) set_target_properties(opentrack PROPERTIES SUFFIX "${opentrack-binary-suffix}") target_link_libraries(opentrack + opentrack-migration opentrack-logic opentrack-spline-widget opentrack-pose-widget diff --git a/gui/main-window.cpp b/gui/main-window.cpp index 94034bd6..30211128 100644 --- a/gui/main-window.cpp +++ b/gui/main-window.cpp @@ -11,6 +11,7 @@ #include "options/options.hpp" #include "opentrack-library-path.h" #include "new_file_dialog.h" +#include "migration/migration.hpp" #include <QFile> #include <QFileDialog> #include <QDesktopServices> @@ -42,7 +43,7 @@ MainWindow::MainWindow() : setFixedSize(size()); updateButtonState(false, false); - refresh_config_list(); + refresh_config_list(true); connect(ui.btnEditCurves, SIGNAL(clicked()), this, SLOT(showCurveConfiguration())); connect(ui.btnShortcuts, SIGNAL(clicked()), this, SLOT(show_options_dialog())); @@ -87,7 +88,7 @@ MainWindow::MainWindow() : } // timers - connect(&config_list_timer, SIGNAL(timeout()), this, SLOT(refresh_config_list())); + connect(&config_list_timer, &QTimer::timeout, this, [this]() { refresh_config_list(false); }); connect(&pose_update_timer, SIGNAL(timeout()), this, SLOT(showHeadPose())); connect(&det_timer, SIGNAL(timeout()), this, SLOT(maybe_start_profile_from_executable())); @@ -112,6 +113,8 @@ MainWindow::MainWindow() : (void) file.open(QFile::ReadWrite); } } + else + set_profile(group::ini_filename()); connect(this, &MainWindow::emit_start_tracker, this, [&]() -> void { qDebug() << "start tracker"; startTracker(); }, @@ -228,7 +231,7 @@ void MainWindow::register_shortcuts() work->reload_shortcuts(); } -void MainWindow::warn_on_config_not_writable() +bool MainWindow::warn_on_config_not_writable() { QString current_file = group::ini_pathname(); QFile f(current_file); @@ -237,7 +240,10 @@ void MainWindow::warn_on_config_not_writable() if (!f.isOpen()) { QMessageBox::warning(this, "Something went wrong", "Check permissions and ownership for your .ini file!", QMessageBox::Ok, QMessageBox::NoButton); + return false; } + + return true; } bool MainWindow::get_new_config_name_from_dialog(QString& ret) @@ -273,8 +279,9 @@ void MainWindow::make_empty_config() { QFile filename(dir + "/" + name); (void) filename.open(QFile::ReadWrite); - refresh_config_list(); + refresh_config_list(true); ui.iconcomboProfile->setCurrentText(name); + mark_config_as_not_needing_migration(); } } @@ -288,8 +295,9 @@ void MainWindow::make_copied_config() const QString new_name = dir + "/" + name; (void) QFile::remove(new_name); (void) QFile::copy(cur, new_name); - refresh_config_list(); + refresh_config_list(true); ui.iconcomboProfile->setCurrentText(name); + mark_config_as_not_needing_migration(); } } @@ -302,7 +310,7 @@ void MainWindow::open_config_directory() } } -void MainWindow::refresh_config_list() +void MainWindow::refresh_config_list(bool warn) { if (work) return; @@ -357,7 +365,8 @@ void MainWindow::refresh_config_list() } set_title(); - warn_on_config_not_writable(); + if (warn) + warn_on_config_not_writable(); } void MainWindow::updateButtonState(bool running, bool inertialp) @@ -776,7 +785,13 @@ bool MainWindow::is_tray_enabled() void MainWindow::set_profile(const QString &profile) { - QSettings settings(OPENTRACK_ORG); - settings.setValue(OPENTRACK_CONFIG_FILENAME_KEY, profile); - warn_on_config_not_writable(); + { + QSettings settings(OPENTRACK_ORG); + settings.setValue(OPENTRACK_CONFIG_FILENAME_KEY, profile); + } + const bool ok = warn_on_config_not_writable(); + if (ok) + // migrations are for config layout changes and other user-visible + // incompatibilities in future versions + run_migrations(); } diff --git a/gui/main-window.hpp b/gui/main-window.hpp index 75a66b0e..7cd94e93 100644 --- a/gui/main-window.hpp +++ b/gui/main-window.hpp @@ -112,7 +112,7 @@ private slots: void make_empty_config(); void make_copied_config(); void open_config_directory(); - void refresh_config_list(); + void refresh_config_list(bool warn); void startTracker(); void stopTracker(); @@ -128,6 +128,6 @@ public: MainWindow(); ~MainWindow(); static void set_working_directory(); - void warn_on_config_not_writable(); + bool warn_on_config_not_writable(); bool is_tray_enabled(); }; diff --git a/gui/main.cpp b/gui/main.cpp index e452b781..7ac822dc 100644 --- a/gui/main.cpp +++ b/gui/main.cpp @@ -7,6 +7,7 @@ # include <QString> #endif +#include "migration/migration.hpp" #include "main-window.hpp" #include "options/options.hpp" #include "compat/win32-com.hpp" @@ -23,8 +24,7 @@ using namespace options; void set_qt_style() { #if defined(_WIN32) || defined(__APPLE__) - // qt5 designer-made controls look like shit on 'doze -sh 20140921 - // also our OSX look leaves a lot to be desired -sh 20150726 + // our layouts on OSX make some control wrongly sized -sh 20160908 { const QStringList preferred { "fusion", "windowsvista", "macintosh" }; for (const auto& style_name : preferred) @@ -176,10 +176,7 @@ main(int argc, char** argv) #ifdef _MSC_VER int WINAPI -WinMain (struct HINSTANCE__ *hInstance, - struct HINSTANCE__ *hPrevInstance, - char *lpszCmdLine, - int nCmdShow) +WinMain (struct HINSTANCE__*, struct HINSTANCE__*, char*, int) { return main (__argc, __argv); } diff --git a/migration/20160906_0-mappings.cpp b/migration/20160906_0-mappings.cpp new file mode 100644 index 00000000..0ff3095a --- /dev/null +++ b/migration/20160906_0-mappings.cpp @@ -0,0 +1,14 @@ +#include "migration.hpp" + +#include <QDebug> + +using namespace migrations; + +struct foo : migration +{ + const QString& unique_date() const override { qDebug() << "foo"; static QString ret(""); return ret; } + bool should_run() const override { qDebug() << "bar"; return false; } + bool run() override { return false; } +}; + +OPENTRACK_MIGRATION(foo); diff --git a/migration/20160906_1-axis-signs.cpp b/migration/20160906_1-axis-signs.cpp new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/migration/20160906_1-axis-signs.cpp diff --git a/migration/CMakeLists.txt b/migration/CMakeLists.txt new file mode 100644 index 00000000..d220b002 --- /dev/null +++ b/migration/CMakeLists.txt @@ -0,0 +1,2 @@ +opentrack_boilerplate(opentrack-migration BIN) +target_link_libraries(opentrack-migration opentrack-logic opentrack-spline-widget) diff --git a/migration/export.hpp b/migration/export.hpp new file mode 100644 index 00000000..800ddf35 --- /dev/null +++ b/migration/export.hpp @@ -0,0 +1,28 @@ +#pragma once + +#ifdef BUILD_migration +# ifdef _WIN32 +# define OPENTRACK_MIGRATION_LINKAGE __declspec(dllexport) +# else +# define OPENTRACK_MIGRATION_LINKAGE +# endif + +# ifndef _MSC_VER +# define OPENTRACK_MIGRATION_EXPORT __attribute__ ((visibility ("default"))) OPENTRACK_MIGRATION_LINKAGE +# else +# define OPENTRACK_MIGRATION_EXPORT OPENTRACK_MIGRATION_LINKAGE +# endif + +#else + #ifdef _WIN32 + # define OPENTRACK_MIGRATION_LINKAGE __declspec(dllimport) + #else + # define OPENTRACK_MIGRATION_LINKAGE + #endif + + #ifndef _MSC_VER + # define OPENTRACK_MIGRATION_EXPORT __attribute__ ((visibility ("default"))) OPENTRACK_MIGRATION_LINKAGE + #else + # define OPENTRACK_MIGRATION_EXPORT OPENTRACK_MIGRATION_LINKAGE + #endif +#endif diff --git a/migration/migration.cpp b/migration/migration.cpp new file mode 100644 index 00000000..6e54de19 --- /dev/null +++ b/migration/migration.cpp @@ -0,0 +1,129 @@ +#include "migration.hpp" + +#include "options/options.hpp" +#include "compat/util.hpp" + +#include <QString> +#include <QSettings> +#include <QDebug> + +#include <memory> + +namespace migrations { + +namespace detail { + +void migrator::register_migration(migration* m) +{ + migrations().push_back(m); +} + +migrator::vec& migrator::migrations() +{ + static vec ret; + return ret; +} + +QString migrator::last_migration_time() +{ + QString ret; + + std::shared_ptr<QSettings> s(options::group::ini_file()); + + s->beginGroup("migrations"); + ret = s->value("last-migration-at", "19700101_00").toString(); + s->endGroup(); + + return ret; +} + +QString migrator::time_after_migrations() +{ + const vec list = sorted_migrations(); + + if (list.size() == 0u) + return QStringLiteral("19700101_00"); + + QString ret = list[list.size() - 1]->unique_date(); + ret += QStringLiteral("~"); + + return ret; +} + +void migrator::set_last_migration_time(const QString& val) +{ + std::shared_ptr<QSettings> s(options::group::ini_file()); + + s->beginGroup("migrations"); + s->setValue("last-migration-at", val); + s->endGroup(); +} + +migrator::vec migrator::sorted_migrations() +{ + vec list(migrations()); + std::sort(list.begin(), list.end(), [](const mm x, const mm y) { return x->unique_date() < y->unique_date(); }); + return list; +} + +std::vector<QString> migrator::run() +{ + vec migrations = sorted_migrations(); + vstr done; + + const QString last_migration = last_migration_time(); + + qDebug() << "migration: config" << options::group::ini_filename() << "time" << last_migration; + + for (migration* m_ : migrations) + { + migration& m(*m_); + + const QString date = m.unique_date(); + + if (date <= last_migration) + continue; + + if (m.should_run()) + { + m.run(); + done.push_back(m.name()); + } + } + + mark_config_as_not_needing_migration(); + + if (done.size()) + { + qDebug() << "migration: done" << done.size() << "units"; + for (const QString& name : done) + qDebug() << "--" << name; + qDebug() << ""; + } + + return done; +} + +} + +migration::migration() {} +migration::~migration() {} + +} // ns + +std::vector<QString> run_migrations() +{ + return migrations::detail::migrator::run(); +} + +void mark_config_as_not_needing_migration() +{ + using m = migrations::detail::migrator; + + m::mark_config_as_not_needing_migration(); +} + +void migrations::detail::migrator::mark_config_as_not_needing_migration() +{ + set_last_migration_time(time_after_migrations()); +} diff --git a/migration/migration.hpp b/migration/migration.hpp new file mode 100644 index 00000000..b9c20f15 --- /dev/null +++ b/migration/migration.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include <QString> +#include <vector> + +#include "export.hpp" + +namespace migrations { + +class migration; +class registrator; + +namespace detail { + class migrator final + { + using mm = migration*; + template<typename t> using vec_ = std::vector<t>; + using vstr = vec_<QString>; + using vec = vec_<mm>; + static vec& migrations(); + static QString last_migration_time(); + static QString time_after_migrations(); + static void set_last_migration_time(const QString& val); + migrator() = delete; + static vec sorted_migrations(); + public: + static vstr run(); + static void register_migration(migration* m); + static void mark_config_as_not_needing_migration(); + }; + + template<typename t> + struct registrator final + { + registrator() + { + static t m; + migrator::register_migration(static_cast<migration*>(&m)); + } + }; +} + +#ifndef __COUNTER__ +# error "oops, need __COUNTER__ extension for preprocessor" +#endif + +#define OPENTRACK_MIGRATION(type) static ::migrations::detail::registrator<type> opentrack_migration_registrator__ ## __COUNTER__ ## _gensym; + +#ifdef Q_CREATOR_RUN +# pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +class migration +{ + migration& operator=(const migration&) = delete; + migration(const migration&) = delete; + migration& operator=(migration&&) = delete; + migration(migration&&) = delete; + +public: + migration(); + virtual ~migration(); + virtual QString unique_date() const = 0; + virtual QString name() const = 0; + virtual bool should_run() const = 0; + virtual void run() = 0; +}; + +} + +OPENTRACK_MIGRATION_EXPORT std::vector<QString> run_migrations(); +OPENTRACK_MIGRATION_EXPORT void mark_config_as_not_needing_migration(); diff --git a/options/bundle.cpp b/options/bundle.cpp index 48689720..61be509a 100644 --- a/options/bundle.cpp +++ b/options/bundle.cpp @@ -16,6 +16,10 @@ bundle::bundle(const QString& group_name) { } +bundle::~bundle() +{ +} + void bundle::reload() { if (group_name.size()) @@ -114,7 +118,7 @@ void bundler::bundle_decf(const bundler::k& key) if (--std::get<0>(implsgl_data[key]) == 0) { - qDebug() << "bundle -" << key; + //qDebug() << "bundle -" << key; implsgl_data.erase(key); } @@ -132,7 +136,7 @@ void bundler::after_profile_changed_() mem<v> bundle_ = bundle.lock(); if (bundle_) { - qDebug() << "bundle: reverting" << kv.first << "due to profile change"; + //qDebug() << "bundle: reverting" << kv.first << "due to profile change"; bundle_->reload(); } } @@ -163,7 +167,7 @@ std::shared_ptr<bundler::v> bundler::make_bundle(const bundler::k &key) return shared; } - qDebug() << "bundle +" << key; + //qDebug() << "bundle +" << key; std::shared_ptr<v> shr(new v(key), [this](v* val) { bundle_decf(val->name()); }); diff --git a/options/bundle.hpp b/options/bundle.hpp index 20ec9eaa..3d75a8de 100644 --- a/options/bundle.hpp +++ b/options/bundle.hpp @@ -24,6 +24,8 @@ namespace options { namespace detail { +struct bundler; + class OPENTRACK_OPTIONS_EXPORT bundle final : public QObject, public virtual connector { class OPENTRACK_OPTIONS_EXPORT mutex final : public QMutex @@ -35,6 +37,8 @@ class OPENTRACK_OPTIONS_EXPORT bundle final : public QObject, public virtual con Q_OBJECT private: + friend bundler; + mutex mtx; const QString group_name; group saved; @@ -50,7 +54,7 @@ signals: void changed() const; public: bundle(const QString& group_name); - ~bundle() override {} + ~bundle() override; QString name() { return group_name; } void reload(); void store_kv(const QString& name, const QVariant& datum); diff --git a/options/group.cpp b/options/group.cpp index a2169ae5..69b79cef 100644 --- a/options/group.cpp +++ b/options/group.cpp @@ -72,7 +72,7 @@ QString group::ini_pathname() return dir + "/" + ini_filename(); } -const QStringList group::ini_list() +QStringList group::ini_list() { const auto dirname = ini_directory(); if (dirname == "") @@ -83,7 +83,7 @@ const QStringList group::ini_list() return list; } -const std::shared_ptr<QSettings> group::ini_file() +std::shared_ptr<QSettings> group::ini_file() { const auto pathname = ini_pathname(); if (pathname != "") diff --git a/options/group.hpp b/options/group.hpp index f76978ad..f5b3e523 100644 --- a/options/group.hpp +++ b/options/group.hpp @@ -17,6 +17,7 @@ class OPENTRACK_OPTIONS_EXPORT group final QString name; public: std::map<QString, QVariant> kvs; + group(const QString& name, mem<QSettings> s); group(const QString& name); void save() const; void save_deferred(QSettings& s) const; @@ -25,8 +26,8 @@ public: static QString ini_directory(); static QString ini_filename(); static QString ini_pathname(); - static const QStringList ini_list(); - static const std::shared_ptr<QSettings> ini_file(); + static QStringList ini_list(); + static std::shared_ptr<QSettings> ini_file(); template<typename t> t get(const QString& k) const |