#pragma once #include #include #include class QNetworkAccessManager; class QNetworkReply; namespace update { enum class State { NotAvailable, NotInstalled, UpdateAvailable, Actual }; enum class Action { NoAction, Remove, Install }; struct File { QUrl url; QString rawPath; QString expandedPath; QString downloadPath; QString md5; QDateTime versionDate; }; using UserActions = std::multimap; class ActionDelegate : public QStyledItemDelegate { Q_OBJECT public: explicit ActionDelegate(QObject* parent = nullptr); QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override; void setEditorData(QWidget* editor, const QModelIndex& index) const override; void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const override; }; class Model : public QAbstractItemModel { Q_OBJECT public: enum class Column { Name, State, Action, Version, Files, Count }; explicit Model(QObject* parent = nullptr); void parse(const QByteArray& data); void setExpansions(const std::map& expansions); UserActions userActions() const; void updateStates(); QModelIndex index(int row, int column, const QModelIndex& parent) const override; QModelIndex parent(const QModelIndex& child) const override; int rowCount(const QModelIndex& parent) const override; int columnCount(const QModelIndex& parent) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; QVariant data(const QModelIndex& index, int role) const override; Qt::ItemFlags flags(const QModelIndex& index) const override; bool setData(const QModelIndex& index, const QVariant& value, int role) override; private: struct Component { QString name; State state{State::NotAvailable}; Action action{Action::NoAction}; QString version; std::vector files; std::vector> children; Component* parent{nullptr}; int index{-1}; }; std::unique_ptr parse(const QJsonObject& json) const; void updateState(Component& component); void fillUserActions(UserActions& actions, Component& component) const; State currentState(const File& file) const; QString expanded(const QString& source) const; void emitColumnsChanged(const QModelIndex& parent); std::unique_ptr root_; std::map expansions_; }; class Installer { public: explicit Installer(const UserActions& actions); bool commit(); QString errorString() const; private: bool checkIsPossible(); UserActions actions_; QStringList errors_; }; class Loader : public QObject { Q_OBJECT public: explicit Loader(const QUrl& updateUrl, QObject* parent = nullptr); void checkForUpdates(); void applyUserActions(); Model* model() const; signals: void updated(); void error(const QString& error); private: void handleReply(QNetworkReply* reply); QString toError(QNetworkReply& reply) const; void finishUpdate(const QString& error = {}); void commitUpdate(); QNetworkAccessManager* network_; Model* model_; QUrl updateUrl_; QString downloadPath_; std::map componentReplyToPath_; std::unique_ptr installer_; }; } // namespace update