ScreenTranslator/src/service/updates.h

190 lines
5.0 KiB
C++

#pragma once
#include <QDate>
#include <QStyledItemDelegate>
#include <QUrl>
class QNetworkAccessManager;
class QNetworkReply;
class QTreeView;
namespace update
{
enum class State { NotAvailable, NotInstalled, UpdateAvailable, Actual };
enum class Action { NoAction, Remove, Install };
struct File {
QVector<QUrl> urls;
QString rawPath;
QString expandedPath;
QString downloadPath;
QString md5;
QDateTime versionDate;
int progress{0};
};
using UserActions = std::multimap<Action, File>;
class UpdateDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit UpdateDelegate(QObject* parent = nullptr);
void paint(QPainter* painter, const QStyleOptionViewItem& option,
const QModelIndex& index) const override;
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,
Size,
Version,
Progress,
Files,
Count
};
explicit Model(QObject* parent = nullptr);
void initView(QTreeView* view);
QString parse(const QByteArray& data);
void setExpansions(const std::map<QString, QString>& expansions);
UserActions userActions() const;
void updateStates();
bool hasUpdates() const;
void updateProgress(const QUrl& url, int progress);
void resetProgress();
void selectAllUpdates();
void resetActions();
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<File> files;
bool checkOnly{false};
std::vector<std::unique_ptr<Component>> children;
Component* parent{nullptr};
int index{-1};
int progress{0};
int size{0};
};
std::unique_ptr<Component> parse(const QJsonObject& json) const;
void updateProgress(Component& component, const QUrl& url, int progress);
void updateState(Component& component);
bool hasUpdates(const Component& component) const;
void fillUserActions(UserActions& actions, Component& component) const;
State currentState(const File& file) const;
QString expanded(const QString& source) const;
void emitColumnsChanged(const QModelIndex& parent);
Component* toComponent(const QModelIndex& index) const;
QModelIndex toIndex(const Component& component, int column) const;
std::unique_ptr<Component> root_;
std::map<QString, QString> expansions_;
};
class Installer
{
public:
explicit Installer(const UserActions& actions);
bool commit();
QString errorString() const;
private:
void remove(const File& file);
void install(const File& file);
void checkRemove(const File& file);
void checkInstall(const File& file);
bool checkIsPossible();
UserActions actions_;
QStringList errors_;
};
class Loader : public QObject
{
Q_OBJECT
public:
using Urls = QVector<QUrl>;
explicit Loader(const Urls& updateUrls, QObject* parent = nullptr);
void checkForUpdates();
void applyUserActions();
Model* model() const;
signals:
void updatesAvailable();
void updated();
void error(const QString& error);
private:
void handleReply(QNetworkReply* reply);
bool handleComponentReply(QNetworkReply* reply);
void handleUpdateReply(QNetworkReply* reply);
QString toError(QNetworkReply& reply) const;
void finishUpdate(const QString& error = {});
void commitUpdate();
void updateProgress(qint64 bytesSent, qint64 bytesTotal);
bool startDownload(File& file);
void startDownloadUpdates(const QUrl& previous);
QNetworkAccessManager* network_;
Model* model_;
Urls updateUrls_;
QString downloadPath_;
std::map<QNetworkReply*, File*> downloads_;
UserActions currentActions_;
};
class AutoChecker : public QObject
{
Q_OBJECT
public:
explicit AutoChecker(Loader& loader, QObject* parent = nullptr);
~AutoChecker();
bool isLastCheckDateChanged() const;
QDateTime lastCheckDate() const;
void setCheckIntervalDays(int days);
void setLastCheckDate(const QDateTime& dt);
private:
void handleModelReset();
void scheduleNextCheck();
Loader& loader_;
bool isLastCheckDateChanged_{false};
int checkIntervalDays_{0};
QDateTime lastCheckDate_;
std::unique_ptr<QTimer> timer_;
};
} // namespace update