NOISSUE tabs -> spaces
This commit is contained in:
@ -27,45 +27,45 @@
|
||||
class ParsingValidator : public Net::Validator
|
||||
{
|
||||
public: /* con/des */
|
||||
ParsingValidator(Meta::BaseEntity *entity) : m_entity(entity)
|
||||
{
|
||||
};
|
||||
virtual ~ParsingValidator()
|
||||
{
|
||||
};
|
||||
ParsingValidator(Meta::BaseEntity *entity) : m_entity(entity)
|
||||
{
|
||||
};
|
||||
virtual ~ParsingValidator()
|
||||
{
|
||||
};
|
||||
|
||||
public: /* methods */
|
||||
bool init(QNetworkRequest &) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool write(QByteArray & data) override
|
||||
{
|
||||
this->data.append(data);
|
||||
return true;
|
||||
}
|
||||
bool abort() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool validate(QNetworkReply &) override
|
||||
{
|
||||
auto fname = m_entity->localFilename();
|
||||
try
|
||||
{
|
||||
m_entity->parse(Json::requireObject(Json::requireDocument(data, fname), fname));
|
||||
return true;
|
||||
}
|
||||
catch (const Exception &e)
|
||||
{
|
||||
qWarning() << "Unable to parse response:" << e.cause();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool init(QNetworkRequest &) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool write(QByteArray & data) override
|
||||
{
|
||||
this->data.append(data);
|
||||
return true;
|
||||
}
|
||||
bool abort() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool validate(QNetworkReply &) override
|
||||
{
|
||||
auto fname = m_entity->localFilename();
|
||||
try
|
||||
{
|
||||
m_entity->parse(Json::requireObject(Json::requireDocument(data, fname), fname));
|
||||
return true;
|
||||
}
|
||||
catch (const Exception &e)
|
||||
{
|
||||
qWarning() << "Unable to parse response:" << e.cause();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private: /* data */
|
||||
QByteArray data;
|
||||
Meta::BaseEntity *m_entity;
|
||||
QByteArray data;
|
||||
Meta::BaseEntity *m_entity;
|
||||
};
|
||||
|
||||
Meta::BaseEntity::~BaseEntity()
|
||||
@ -74,89 +74,89 @@ Meta::BaseEntity::~BaseEntity()
|
||||
|
||||
QUrl Meta::BaseEntity::url() const
|
||||
{
|
||||
return QUrl("https://v1.meta.multimc.org").resolved(localFilename());
|
||||
return QUrl("https://v1.meta.multimc.org").resolved(localFilename());
|
||||
}
|
||||
|
||||
bool Meta::BaseEntity::loadLocalFile()
|
||||
{
|
||||
const QString fname = QDir("meta").absoluteFilePath(localFilename());
|
||||
if (!QFile::exists(fname))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// TODO: check if the file has the expected checksum
|
||||
try
|
||||
{
|
||||
parse(Json::requireObject(Json::requireDocument(fname, fname), fname));
|
||||
return true;
|
||||
}
|
||||
catch (const Exception &e)
|
||||
{
|
||||
qDebug() << QString("Unable to parse file %1: %2").arg(fname, e.cause());
|
||||
// just make sure it's gone and we never consider it again.
|
||||
QFile::remove(fname);
|
||||
return false;
|
||||
}
|
||||
const QString fname = QDir("meta").absoluteFilePath(localFilename());
|
||||
if (!QFile::exists(fname))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// TODO: check if the file has the expected checksum
|
||||
try
|
||||
{
|
||||
parse(Json::requireObject(Json::requireDocument(fname, fname), fname));
|
||||
return true;
|
||||
}
|
||||
catch (const Exception &e)
|
||||
{
|
||||
qDebug() << QString("Unable to parse file %1: %2").arg(fname, e.cause());
|
||||
// just make sure it's gone and we never consider it again.
|
||||
QFile::remove(fname);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Meta::BaseEntity::load(Net::Mode loadType)
|
||||
{
|
||||
// load local file if nothing is loaded yet
|
||||
if(!isLoaded())
|
||||
{
|
||||
if(loadLocalFile())
|
||||
{
|
||||
m_loadStatus = LoadStatus::Local;
|
||||
}
|
||||
}
|
||||
// if we need remote update, run the update task
|
||||
if(loadType == Net::Mode::Offline || !shouldStartRemoteUpdate())
|
||||
{
|
||||
return;
|
||||
}
|
||||
NetJob *job = new NetJob(QObject::tr("Download of meta file %1").arg(localFilename()));
|
||||
auto url = this->url();
|
||||
auto entry = ENV.metacache()->resolveEntry("meta", localFilename());
|
||||
entry->setStale(true);
|
||||
auto dl = Net::Download::makeCached(url, entry);
|
||||
/*
|
||||
* The validator parses the file and loads it into the object.
|
||||
* If that fails, the file is not written to storage.
|
||||
*/
|
||||
dl->addValidator(new ParsingValidator(this));
|
||||
job->addNetAction(dl);
|
||||
m_updateStatus = UpdateStatus::InProgress;
|
||||
m_updateTask.reset(job);
|
||||
QObject::connect(job, &NetJob::succeeded, [&]()
|
||||
{
|
||||
m_loadStatus = LoadStatus::Remote;
|
||||
m_updateStatus = UpdateStatus::Succeeded;
|
||||
m_updateTask.reset();
|
||||
});
|
||||
QObject::connect(job, &NetJob::failed, [&]()
|
||||
{
|
||||
m_updateStatus = UpdateStatus::Failed;
|
||||
m_updateTask.reset();
|
||||
});
|
||||
m_updateTask->start();
|
||||
// load local file if nothing is loaded yet
|
||||
if(!isLoaded())
|
||||
{
|
||||
if(loadLocalFile())
|
||||
{
|
||||
m_loadStatus = LoadStatus::Local;
|
||||
}
|
||||
}
|
||||
// if we need remote update, run the update task
|
||||
if(loadType == Net::Mode::Offline || !shouldStartRemoteUpdate())
|
||||
{
|
||||
return;
|
||||
}
|
||||
NetJob *job = new NetJob(QObject::tr("Download of meta file %1").arg(localFilename()));
|
||||
auto url = this->url();
|
||||
auto entry = ENV.metacache()->resolveEntry("meta", localFilename());
|
||||
entry->setStale(true);
|
||||
auto dl = Net::Download::makeCached(url, entry);
|
||||
/*
|
||||
* The validator parses the file and loads it into the object.
|
||||
* If that fails, the file is not written to storage.
|
||||
*/
|
||||
dl->addValidator(new ParsingValidator(this));
|
||||
job->addNetAction(dl);
|
||||
m_updateStatus = UpdateStatus::InProgress;
|
||||
m_updateTask.reset(job);
|
||||
QObject::connect(job, &NetJob::succeeded, [&]()
|
||||
{
|
||||
m_loadStatus = LoadStatus::Remote;
|
||||
m_updateStatus = UpdateStatus::Succeeded;
|
||||
m_updateTask.reset();
|
||||
});
|
||||
QObject::connect(job, &NetJob::failed, [&]()
|
||||
{
|
||||
m_updateStatus = UpdateStatus::Failed;
|
||||
m_updateTask.reset();
|
||||
});
|
||||
m_updateTask->start();
|
||||
}
|
||||
|
||||
bool Meta::BaseEntity::isLoaded() const
|
||||
{
|
||||
return m_loadStatus > LoadStatus::NotLoaded;
|
||||
return m_loadStatus > LoadStatus::NotLoaded;
|
||||
}
|
||||
|
||||
bool Meta::BaseEntity::shouldStartRemoteUpdate() const
|
||||
{
|
||||
// TODO: version-locks and offline mode?
|
||||
return m_updateStatus != UpdateStatus::InProgress;
|
||||
// TODO: version-locks and offline mode?
|
||||
return m_updateStatus != UpdateStatus::InProgress;
|
||||
}
|
||||
|
||||
shared_qobject_ptr<Task> Meta::BaseEntity::getCurrentTask()
|
||||
{
|
||||
if(m_updateStatus == UpdateStatus::InProgress)
|
||||
{
|
||||
return m_updateTask;
|
||||
}
|
||||
return nullptr;
|
||||
if(m_updateStatus == UpdateStatus::InProgress)
|
||||
{
|
||||
return m_updateTask;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -28,41 +28,41 @@ namespace Meta
|
||||
class MULTIMC_LOGIC_EXPORT BaseEntity
|
||||
{
|
||||
public: /* types */
|
||||
using Ptr = std::shared_ptr<BaseEntity>;
|
||||
enum class LoadStatus
|
||||
{
|
||||
NotLoaded,
|
||||
Local,
|
||||
Remote
|
||||
};
|
||||
enum class UpdateStatus
|
||||
{
|
||||
NotDone,
|
||||
InProgress,
|
||||
Failed,
|
||||
Succeeded
|
||||
};
|
||||
using Ptr = std::shared_ptr<BaseEntity>;
|
||||
enum class LoadStatus
|
||||
{
|
||||
NotLoaded,
|
||||
Local,
|
||||
Remote
|
||||
};
|
||||
enum class UpdateStatus
|
||||
{
|
||||
NotDone,
|
||||
InProgress,
|
||||
Failed,
|
||||
Succeeded
|
||||
};
|
||||
|
||||
public:
|
||||
virtual ~BaseEntity();
|
||||
virtual ~BaseEntity();
|
||||
|
||||
virtual void parse(const QJsonObject &obj) = 0;
|
||||
virtual void parse(const QJsonObject &obj) = 0;
|
||||
|
||||
virtual QString localFilename() const = 0;
|
||||
virtual QUrl url() const;
|
||||
virtual QString localFilename() const = 0;
|
||||
virtual QUrl url() const;
|
||||
|
||||
bool isLoaded() const;
|
||||
bool shouldStartRemoteUpdate() const;
|
||||
bool isLoaded() const;
|
||||
bool shouldStartRemoteUpdate() const;
|
||||
|
||||
void load(Net::Mode loadType);
|
||||
shared_qobject_ptr<Task> getCurrentTask();
|
||||
void load(Net::Mode loadType);
|
||||
shared_qobject_ptr<Task> getCurrentTask();
|
||||
|
||||
protected: /* methods */
|
||||
bool loadLocalFile();
|
||||
bool loadLocalFile();
|
||||
|
||||
private:
|
||||
LoadStatus m_loadStatus = LoadStatus::NotLoaded;
|
||||
UpdateStatus m_updateStatus = UpdateStatus::NotDone;
|
||||
shared_qobject_ptr<Task> m_updateTask;
|
||||
LoadStatus m_loadStatus = LoadStatus::NotLoaded;
|
||||
UpdateStatus m_updateStatus = UpdateStatus::NotDone;
|
||||
shared_qobject_ptr<Task> m_updateTask;
|
||||
};
|
||||
}
|
||||
|
@ -21,128 +21,128 @@
|
||||
namespace Meta
|
||||
{
|
||||
Index::Index(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
}
|
||||
Index::Index(const QVector<VersionListPtr> &lists, QObject *parent)
|
||||
: QAbstractListModel(parent), m_lists(lists)
|
||||
: QAbstractListModel(parent), m_lists(lists)
|
||||
{
|
||||
for (int i = 0; i < m_lists.size(); ++i)
|
||||
{
|
||||
m_uids.insert(m_lists.at(i)->uid(), m_lists.at(i));
|
||||
connectVersionList(i, m_lists.at(i));
|
||||
}
|
||||
for (int i = 0; i < m_lists.size(); ++i)
|
||||
{
|
||||
m_uids.insert(m_lists.at(i)->uid(), m_lists.at(i));
|
||||
connectVersionList(i, m_lists.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
QVariant Index::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (index.parent().isValid() || index.row() < 0 || index.row() >= m_lists.size())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
if (index.parent().isValid() || index.row() < 0 || index.row() >= m_lists.size())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
VersionListPtr list = m_lists.at(index.row());
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
switch (index.column())
|
||||
{
|
||||
case 0: return list->humanReadable();
|
||||
default: break;
|
||||
}
|
||||
case UidRole: return list->uid();
|
||||
case NameRole: return list->name();
|
||||
case ListPtrRole: return QVariant::fromValue(list);
|
||||
}
|
||||
return QVariant();
|
||||
VersionListPtr list = m_lists.at(index.row());
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
switch (index.column())
|
||||
{
|
||||
case 0: return list->humanReadable();
|
||||
default: break;
|
||||
}
|
||||
case UidRole: return list->uid();
|
||||
case NameRole: return list->name();
|
||||
case ListPtrRole: return QVariant::fromValue(list);
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
int Index::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return m_lists.size();
|
||||
return m_lists.size();
|
||||
}
|
||||
int Index::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
QVariant Index::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole && section == 0)
|
||||
{
|
||||
return tr("Name");
|
||||
}
|
||||
else
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole && section == 0)
|
||||
{
|
||||
return tr("Name");
|
||||
}
|
||||
else
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
bool Index::hasUid(const QString &uid) const
|
||||
{
|
||||
return m_uids.contains(uid);
|
||||
return m_uids.contains(uid);
|
||||
}
|
||||
|
||||
VersionListPtr Index::get(const QString &uid)
|
||||
{
|
||||
VersionListPtr out = m_uids.value(uid, nullptr);
|
||||
if(!out)
|
||||
{
|
||||
out = std::make_shared<VersionList>(uid);
|
||||
m_uids[uid] = out;
|
||||
}
|
||||
return out;
|
||||
VersionListPtr out = m_uids.value(uid, nullptr);
|
||||
if(!out)
|
||||
{
|
||||
out = std::make_shared<VersionList>(uid);
|
||||
m_uids[uid] = out;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
VersionPtr Index::get(const QString &uid, const QString &version)
|
||||
{
|
||||
auto list = get(uid);
|
||||
return list->getVersion(version);
|
||||
auto list = get(uid);
|
||||
return list->getVersion(version);
|
||||
}
|
||||
|
||||
void Index::parse(const QJsonObject& obj)
|
||||
{
|
||||
parseIndex(obj, this);
|
||||
parseIndex(obj, this);
|
||||
}
|
||||
|
||||
void Index::merge(const std::shared_ptr<Index> &other)
|
||||
{
|
||||
const QVector<VersionListPtr> lists = std::dynamic_pointer_cast<Index>(other)->m_lists;
|
||||
// initial load, no need to merge
|
||||
if (m_lists.isEmpty())
|
||||
{
|
||||
beginResetModel();
|
||||
m_lists = lists;
|
||||
for (int i = 0; i < lists.size(); ++i)
|
||||
{
|
||||
m_uids.insert(lists.at(i)->uid(), lists.at(i));
|
||||
connectVersionList(i, lists.at(i));
|
||||
}
|
||||
endResetModel();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const VersionListPtr &list : lists)
|
||||
{
|
||||
if (m_uids.contains(list->uid()))
|
||||
{
|
||||
m_uids[list->uid()]->mergeFromIndex(list);
|
||||
}
|
||||
else
|
||||
{
|
||||
beginInsertRows(QModelIndex(), m_lists.size(), m_lists.size());
|
||||
connectVersionList(m_lists.size(), list);
|
||||
m_lists.append(list);
|
||||
m_uids.insert(list->uid(), list);
|
||||
endInsertRows();
|
||||
}
|
||||
}
|
||||
}
|
||||
const QVector<VersionListPtr> lists = std::dynamic_pointer_cast<Index>(other)->m_lists;
|
||||
// initial load, no need to merge
|
||||
if (m_lists.isEmpty())
|
||||
{
|
||||
beginResetModel();
|
||||
m_lists = lists;
|
||||
for (int i = 0; i < lists.size(); ++i)
|
||||
{
|
||||
m_uids.insert(lists.at(i)->uid(), lists.at(i));
|
||||
connectVersionList(i, lists.at(i));
|
||||
}
|
||||
endResetModel();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const VersionListPtr &list : lists)
|
||||
{
|
||||
if (m_uids.contains(list->uid()))
|
||||
{
|
||||
m_uids[list->uid()]->mergeFromIndex(list);
|
||||
}
|
||||
else
|
||||
{
|
||||
beginInsertRows(QModelIndex(), m_lists.size(), m_lists.size());
|
||||
connectVersionList(m_lists.size(), list);
|
||||
m_lists.append(list);
|
||||
m_uids.insert(list->uid(), list);
|
||||
endInsertRows();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Index::connectVersionList(const int row, const VersionListPtr &list)
|
||||
{
|
||||
connect(list.get(), &VersionList::nameChanged, this, [this, row]()
|
||||
{
|
||||
emit dataChanged(index(row), index(row), QVector<int>() << Qt::DisplayRole);
|
||||
});
|
||||
connect(list.get(), &VersionList::nameChanged, this, [this, row]()
|
||||
{
|
||||
emit dataChanged(index(row), index(row), QVector<int>() << Qt::DisplayRole);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -31,41 +31,41 @@ using VersionPtr = std::shared_ptr<class Version>;
|
||||
|
||||
class MULTIMC_LOGIC_EXPORT Index : public QAbstractListModel, public BaseEntity
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Index(QObject *parent = nullptr);
|
||||
explicit Index(const QVector<VersionListPtr> &lists, QObject *parent = nullptr);
|
||||
explicit Index(QObject *parent = nullptr);
|
||||
explicit Index(const QVector<VersionListPtr> &lists, QObject *parent = nullptr);
|
||||
|
||||
enum
|
||||
{
|
||||
UidRole = Qt::UserRole,
|
||||
NameRole,
|
||||
ListPtrRole
|
||||
};
|
||||
enum
|
||||
{
|
||||
UidRole = Qt::UserRole,
|
||||
NameRole,
|
||||
ListPtrRole
|
||||
};
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) 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;
|
||||
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;
|
||||
|
||||
QString localFilename() const override { return "index.json"; }
|
||||
QString localFilename() const override { return "index.json"; }
|
||||
|
||||
// queries
|
||||
VersionListPtr get(const QString &uid);
|
||||
VersionPtr get(const QString &uid, const QString &version);
|
||||
bool hasUid(const QString &uid) const;
|
||||
// queries
|
||||
VersionListPtr get(const QString &uid);
|
||||
VersionPtr get(const QString &uid, const QString &version);
|
||||
bool hasUid(const QString &uid) const;
|
||||
|
||||
QVector<VersionListPtr> lists() const { return m_lists; }
|
||||
QVector<VersionListPtr> lists() const { return m_lists; }
|
||||
|
||||
public: // for usage by parsers only
|
||||
void merge(const std::shared_ptr<Index> &other);
|
||||
void parse(const QJsonObject &obj) override;
|
||||
void merge(const std::shared_ptr<Index> &other);
|
||||
void parse(const QJsonObject &obj) override;
|
||||
|
||||
private:
|
||||
QVector<VersionListPtr> m_lists;
|
||||
QHash<QString, VersionListPtr> m_uids;
|
||||
QVector<VersionListPtr> m_lists;
|
||||
QHash<QString, VersionListPtr> m_uids;
|
||||
|
||||
void connectVersionList(const int row, const VersionListPtr &list);
|
||||
void connectVersionList(const int row, const VersionListPtr &list);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -7,36 +7,36 @@
|
||||
|
||||
class IndexTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
private
|
||||
slots:
|
||||
void test_isProvidedByEnv()
|
||||
{
|
||||
QVERIFY(ENV.metadataIndex());
|
||||
QCOMPARE(ENV.metadataIndex(), ENV.metadataIndex());
|
||||
}
|
||||
void test_isProvidedByEnv()
|
||||
{
|
||||
QVERIFY(ENV.metadataIndex());
|
||||
QCOMPARE(ENV.metadataIndex(), ENV.metadataIndex());
|
||||
}
|
||||
|
||||
void test_hasUid_and_getList()
|
||||
{
|
||||
Meta::Index windex({std::make_shared<Meta::VersionList>("list1"), std::make_shared<Meta::VersionList>("list2"), std::make_shared<Meta::VersionList>("list3")});
|
||||
QVERIFY(windex.hasUid("list1"));
|
||||
QVERIFY(!windex.hasUid("asdf"));
|
||||
QVERIFY(windex.get("list2") != nullptr);
|
||||
QCOMPARE(windex.get("list2")->uid(), QString("list2"));
|
||||
QVERIFY(windex.get("adsf") != nullptr);
|
||||
}
|
||||
void test_hasUid_and_getList()
|
||||
{
|
||||
Meta::Index windex({std::make_shared<Meta::VersionList>("list1"), std::make_shared<Meta::VersionList>("list2"), std::make_shared<Meta::VersionList>("list3")});
|
||||
QVERIFY(windex.hasUid("list1"));
|
||||
QVERIFY(!windex.hasUid("asdf"));
|
||||
QVERIFY(windex.get("list2") != nullptr);
|
||||
QCOMPARE(windex.get("list2")->uid(), QString("list2"));
|
||||
QVERIFY(windex.get("adsf") != nullptr);
|
||||
}
|
||||
|
||||
void test_merge()
|
||||
{
|
||||
Meta::Index windex({std::make_shared<Meta::VersionList>("list1"), std::make_shared<Meta::VersionList>("list2"), std::make_shared<Meta::VersionList>("list3")});
|
||||
QCOMPARE(windex.lists().size(), 3);
|
||||
windex.merge(std::shared_ptr<Meta::Index>(new Meta::Index({std::make_shared<Meta::VersionList>("list1"), std::make_shared<Meta::VersionList>("list2"), std::make_shared<Meta::VersionList>("list3")})));
|
||||
QCOMPARE(windex.lists().size(), 3);
|
||||
windex.merge(std::shared_ptr<Meta::Index>(new Meta::Index({std::make_shared<Meta::VersionList>("list4"), std::make_shared<Meta::VersionList>("list2"), std::make_shared<Meta::VersionList>("list5")})));
|
||||
QCOMPARE(windex.lists().size(), 5);
|
||||
windex.merge(std::shared_ptr<Meta::Index>(new Meta::Index({std::make_shared<Meta::VersionList>("list6")})));
|
||||
QCOMPARE(windex.lists().size(), 6);
|
||||
}
|
||||
void test_merge()
|
||||
{
|
||||
Meta::Index windex({std::make_shared<Meta::VersionList>("list1"), std::make_shared<Meta::VersionList>("list2"), std::make_shared<Meta::VersionList>("list3")});
|
||||
QCOMPARE(windex.lists().size(), 3);
|
||||
windex.merge(std::shared_ptr<Meta::Index>(new Meta::Index({std::make_shared<Meta::VersionList>("list1"), std::make_shared<Meta::VersionList>("list2"), std::make_shared<Meta::VersionList>("list3")})));
|
||||
QCOMPARE(windex.lists().size(), 3);
|
||||
windex.merge(std::shared_ptr<Meta::Index>(new Meta::Index({std::make_shared<Meta::VersionList>("list4"), std::make_shared<Meta::VersionList>("list2"), std::make_shared<Meta::VersionList>("list5")})));
|
||||
QCOMPARE(windex.lists().size(), 5);
|
||||
windex.merge(std::shared_ptr<Meta::Index>(new Meta::Index({std::make_shared<Meta::VersionList>("list6")})));
|
||||
QCOMPARE(windex.lists().size(), 6);
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_GUILESS_MAIN(IndexTest)
|
||||
|
@ -30,141 +30,141 @@ namespace Meta
|
||||
|
||||
MetadataVersion currentFormatVersion()
|
||||
{
|
||||
return MetadataVersion::InitialRelease;
|
||||
return MetadataVersion::InitialRelease;
|
||||
}
|
||||
|
||||
// Index
|
||||
static std::shared_ptr<Index> parseIndexInternal(const QJsonObject &obj)
|
||||
{
|
||||
const QVector<QJsonObject> objects = requireIsArrayOf<QJsonObject>(obj, "packages");
|
||||
QVector<VersionListPtr> lists;
|
||||
lists.reserve(objects.size());
|
||||
std::transform(objects.begin(), objects.end(), std::back_inserter(lists), [](const QJsonObject &obj)
|
||||
{
|
||||
VersionListPtr list = std::make_shared<VersionList>(requireString(obj, "uid"));
|
||||
list->setName(ensureString(obj, "name", QString()));
|
||||
return list;
|
||||
});
|
||||
return std::make_shared<Index>(lists);
|
||||
const QVector<QJsonObject> objects = requireIsArrayOf<QJsonObject>(obj, "packages");
|
||||
QVector<VersionListPtr> lists;
|
||||
lists.reserve(objects.size());
|
||||
std::transform(objects.begin(), objects.end(), std::back_inserter(lists), [](const QJsonObject &obj)
|
||||
{
|
||||
VersionListPtr list = std::make_shared<VersionList>(requireString(obj, "uid"));
|
||||
list->setName(ensureString(obj, "name", QString()));
|
||||
return list;
|
||||
});
|
||||
return std::make_shared<Index>(lists);
|
||||
}
|
||||
|
||||
// Version
|
||||
static VersionPtr parseCommonVersion(const QString &uid, const QJsonObject &obj)
|
||||
{
|
||||
VersionPtr version = std::make_shared<Version>(uid, requireString(obj, "version"));
|
||||
version->setTime(QDateTime::fromString(requireString(obj, "releaseTime"), Qt::ISODate).toMSecsSinceEpoch() / 1000);
|
||||
version->setType(ensureString(obj, "type", QString()));
|
||||
version->setRecommended(ensureBoolean(obj, QString("recommended"), false));
|
||||
version->setVolatile(ensureBoolean(obj, QString("volatile"), false));
|
||||
RequireSet requires, conflicts;
|
||||
parseRequires(obj, &requires, "requires");
|
||||
parseRequires(obj, &conflicts, "conflicts");
|
||||
version->setRequires(requires, conflicts);
|
||||
return version;
|
||||
VersionPtr version = std::make_shared<Version>(uid, requireString(obj, "version"));
|
||||
version->setTime(QDateTime::fromString(requireString(obj, "releaseTime"), Qt::ISODate).toMSecsSinceEpoch() / 1000);
|
||||
version->setType(ensureString(obj, "type", QString()));
|
||||
version->setRecommended(ensureBoolean(obj, QString("recommended"), false));
|
||||
version->setVolatile(ensureBoolean(obj, QString("volatile"), false));
|
||||
RequireSet requires, conflicts;
|
||||
parseRequires(obj, &requires, "requires");
|
||||
parseRequires(obj, &conflicts, "conflicts");
|
||||
version->setRequires(requires, conflicts);
|
||||
return version;
|
||||
}
|
||||
|
||||
static std::shared_ptr<Version> parseVersionInternal(const QJsonObject &obj)
|
||||
{
|
||||
VersionPtr version = parseCommonVersion(requireString(obj, "uid"), obj);
|
||||
VersionPtr version = parseCommonVersion(requireString(obj, "uid"), obj);
|
||||
|
||||
version->setData(OneSixVersionFormat::versionFileFromJson(QJsonDocument(obj),
|
||||
QString("%1/%2.json").arg(version->uid(), version->version()),
|
||||
obj.contains("order")));
|
||||
return version;
|
||||
version->setData(OneSixVersionFormat::versionFileFromJson(QJsonDocument(obj),
|
||||
QString("%1/%2.json").arg(version->uid(), version->version()),
|
||||
obj.contains("order")));
|
||||
return version;
|
||||
}
|
||||
|
||||
// Version list / package
|
||||
static std::shared_ptr<VersionList> parseVersionListInternal(const QJsonObject &obj)
|
||||
{
|
||||
const QString uid = requireString(obj, "uid");
|
||||
const QString uid = requireString(obj, "uid");
|
||||
|
||||
const QVector<QJsonObject> versionsRaw = requireIsArrayOf<QJsonObject>(obj, "versions");
|
||||
QVector<VersionPtr> versions;
|
||||
versions.reserve(versionsRaw.size());
|
||||
std::transform(versionsRaw.begin(), versionsRaw.end(), std::back_inserter(versions), [uid](const QJsonObject &vObj)
|
||||
{
|
||||
auto version = parseCommonVersion(uid, vObj);
|
||||
version->setProvidesRecommendations();
|
||||
return version;
|
||||
});
|
||||
const QVector<QJsonObject> versionsRaw = requireIsArrayOf<QJsonObject>(obj, "versions");
|
||||
QVector<VersionPtr> versions;
|
||||
versions.reserve(versionsRaw.size());
|
||||
std::transform(versionsRaw.begin(), versionsRaw.end(), std::back_inserter(versions), [uid](const QJsonObject &vObj)
|
||||
{
|
||||
auto version = parseCommonVersion(uid, vObj);
|
||||
version->setProvidesRecommendations();
|
||||
return version;
|
||||
});
|
||||
|
||||
VersionListPtr list = std::make_shared<VersionList>(uid);
|
||||
list->setName(ensureString(obj, "name", QString()));
|
||||
list->setVersions(versions);
|
||||
return list;
|
||||
VersionListPtr list = std::make_shared<VersionList>(uid);
|
||||
list->setName(ensureString(obj, "name", QString()));
|
||||
list->setVersions(versions);
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
MetadataVersion parseFormatVersion(const QJsonObject &obj, bool required)
|
||||
{
|
||||
if (!obj.contains("formatVersion"))
|
||||
{
|
||||
if(required)
|
||||
{
|
||||
return MetadataVersion::Invalid;
|
||||
}
|
||||
return MetadataVersion::InitialRelease;
|
||||
}
|
||||
if (!obj.value("formatVersion").isDouble())
|
||||
{
|
||||
return MetadataVersion::Invalid;
|
||||
}
|
||||
switch(obj.value("formatVersion").toInt())
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
return MetadataVersion::InitialRelease;
|
||||
default:
|
||||
return MetadataVersion::Invalid;
|
||||
}
|
||||
if (!obj.contains("formatVersion"))
|
||||
{
|
||||
if(required)
|
||||
{
|
||||
return MetadataVersion::Invalid;
|
||||
}
|
||||
return MetadataVersion::InitialRelease;
|
||||
}
|
||||
if (!obj.value("formatVersion").isDouble())
|
||||
{
|
||||
return MetadataVersion::Invalid;
|
||||
}
|
||||
switch(obj.value("formatVersion").toInt())
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
return MetadataVersion::InitialRelease;
|
||||
default:
|
||||
return MetadataVersion::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
void serializeFormatVersion(QJsonObject& obj, Meta::MetadataVersion version)
|
||||
{
|
||||
if(version == MetadataVersion::Invalid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
obj.insert("formatVersion", int(version));
|
||||
if(version == MetadataVersion::Invalid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
obj.insert("formatVersion", int(version));
|
||||
}
|
||||
|
||||
void parseIndex(const QJsonObject &obj, Index *ptr)
|
||||
{
|
||||
const MetadataVersion version = parseFormatVersion(obj);
|
||||
switch (version)
|
||||
{
|
||||
case MetadataVersion::InitialRelease:
|
||||
ptr->merge(parseIndexInternal(obj));
|
||||
break;
|
||||
case MetadataVersion::Invalid:
|
||||
throw ParseException(QObject::tr("Unknown format version!"));
|
||||
}
|
||||
const MetadataVersion version = parseFormatVersion(obj);
|
||||
switch (version)
|
||||
{
|
||||
case MetadataVersion::InitialRelease:
|
||||
ptr->merge(parseIndexInternal(obj));
|
||||
break;
|
||||
case MetadataVersion::Invalid:
|
||||
throw ParseException(QObject::tr("Unknown format version!"));
|
||||
}
|
||||
}
|
||||
|
||||
void parseVersionList(const QJsonObject &obj, VersionList *ptr)
|
||||
{
|
||||
const MetadataVersion version = parseFormatVersion(obj);
|
||||
switch (version)
|
||||
{
|
||||
case MetadataVersion::InitialRelease:
|
||||
ptr->merge(parseVersionListInternal(obj));
|
||||
break;
|
||||
case MetadataVersion::Invalid:
|
||||
throw ParseException(QObject::tr("Unknown format version!"));
|
||||
}
|
||||
const MetadataVersion version = parseFormatVersion(obj);
|
||||
switch (version)
|
||||
{
|
||||
case MetadataVersion::InitialRelease:
|
||||
ptr->merge(parseVersionListInternal(obj));
|
||||
break;
|
||||
case MetadataVersion::Invalid:
|
||||
throw ParseException(QObject::tr("Unknown format version!"));
|
||||
}
|
||||
}
|
||||
|
||||
void parseVersion(const QJsonObject &obj, Version *ptr)
|
||||
{
|
||||
const MetadataVersion version = parseFormatVersion(obj);
|
||||
switch (version)
|
||||
{
|
||||
case MetadataVersion::InitialRelease:
|
||||
ptr->merge(parseVersionInternal(obj));
|
||||
break;
|
||||
case MetadataVersion::Invalid:
|
||||
throw ParseException(QObject::tr("Unknown format version!"));
|
||||
}
|
||||
const MetadataVersion version = parseFormatVersion(obj);
|
||||
switch (version)
|
||||
{
|
||||
case MetadataVersion::InitialRelease:
|
||||
ptr->merge(parseVersionInternal(obj));
|
||||
break;
|
||||
case MetadataVersion::Invalid:
|
||||
throw ParseException(QObject::tr("Unknown format version!"));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -174,44 +174,44 @@ void parseVersion(const QJsonObject &obj, Version *ptr)
|
||||
*/
|
||||
void parseRequires(const QJsonObject& obj, RequireSet* ptr, const char * keyName)
|
||||
{
|
||||
if(obj.contains(keyName))
|
||||
{
|
||||
QSet<QString> requires;
|
||||
auto reqArray = requireArray(obj, keyName);
|
||||
auto iter = reqArray.begin();
|
||||
while(iter != reqArray.end())
|
||||
{
|
||||
auto reqObject = requireObject(*iter);
|
||||
auto uid = requireString(reqObject, "uid");
|
||||
auto equals = ensureString(reqObject, "equals", QString());
|
||||
auto suggests = ensureString(reqObject, "suggests", QString());
|
||||
ptr->insert({uid, equals, suggests});
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
if(obj.contains(keyName))
|
||||
{
|
||||
QSet<QString> requires;
|
||||
auto reqArray = requireArray(obj, keyName);
|
||||
auto iter = reqArray.begin();
|
||||
while(iter != reqArray.end())
|
||||
{
|
||||
auto reqObject = requireObject(*iter);
|
||||
auto uid = requireString(reqObject, "uid");
|
||||
auto equals = ensureString(reqObject, "equals", QString());
|
||||
auto suggests = ensureString(reqObject, "suggests", QString());
|
||||
ptr->insert({uid, equals, suggests});
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
void serializeRequires(QJsonObject& obj, RequireSet* ptr, const char * keyName)
|
||||
{
|
||||
if(!ptr || ptr->empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
QJsonArray arrOut;
|
||||
for(auto &iter: *ptr)
|
||||
{
|
||||
QJsonObject reqOut;
|
||||
reqOut.insert("uid", iter.uid);
|
||||
if(!iter.equalsVersion.isEmpty())
|
||||
{
|
||||
reqOut.insert("equals", iter.equalsVersion);
|
||||
}
|
||||
if(!iter.suggests.isEmpty())
|
||||
{
|
||||
reqOut.insert("suggests", iter.suggests);
|
||||
}
|
||||
arrOut.append(reqOut);
|
||||
}
|
||||
obj.insert(keyName, arrOut);
|
||||
if(!ptr || ptr->empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
QJsonArray arrOut;
|
||||
for(auto &iter: *ptr)
|
||||
{
|
||||
QJsonObject reqOut;
|
||||
reqOut.insert("uid", iter.uid);
|
||||
if(!iter.equalsVersion.isEmpty())
|
||||
{
|
||||
reqOut.insert("equals", iter.equalsVersion);
|
||||
}
|
||||
if(!iter.suggests.isEmpty())
|
||||
{
|
||||
reqOut.insert("suggests", iter.suggests);
|
||||
}
|
||||
arrOut.append(reqOut);
|
||||
}
|
||||
obj.insert(keyName, arrOut);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,39 +30,39 @@ class VersionList;
|
||||
|
||||
enum class MetadataVersion
|
||||
{
|
||||
Invalid = -1,
|
||||
InitialRelease = 1
|
||||
Invalid = -1,
|
||||
InitialRelease = 1
|
||||
};
|
||||
|
||||
class ParseException : public Exception
|
||||
{
|
||||
public:
|
||||
using Exception::Exception;
|
||||
using Exception::Exception;
|
||||
};
|
||||
struct Require
|
||||
{
|
||||
bool operator==(const Require & rhs) const
|
||||
{
|
||||
return uid == rhs.uid;
|
||||
}
|
||||
bool operator<(const Require & rhs) const
|
||||
{
|
||||
return uid < rhs.uid;
|
||||
}
|
||||
bool deepEquals(const Require & rhs) const
|
||||
{
|
||||
return uid == rhs.uid
|
||||
&& equalsVersion == rhs.equalsVersion
|
||||
&& suggests == rhs.suggests;
|
||||
}
|
||||
QString uid;
|
||||
QString equalsVersion;
|
||||
QString suggests;
|
||||
bool operator==(const Require & rhs) const
|
||||
{
|
||||
return uid == rhs.uid;
|
||||
}
|
||||
bool operator<(const Require & rhs) const
|
||||
{
|
||||
return uid < rhs.uid;
|
||||
}
|
||||
bool deepEquals(const Require & rhs) const
|
||||
{
|
||||
return uid == rhs.uid
|
||||
&& equalsVersion == rhs.equalsVersion
|
||||
&& suggests == rhs.suggests;
|
||||
}
|
||||
QString uid;
|
||||
QString equalsVersion;
|
||||
QString suggests;
|
||||
};
|
||||
|
||||
inline Q_DECL_PURE_FUNCTION uint qHash(const Require &key, uint seed = 0) Q_DECL_NOTHROW
|
||||
{
|
||||
return qHash(key.uid, seed);
|
||||
return qHash(key.uid, seed);
|
||||
}
|
||||
|
||||
using RequireSet = std::set<Require>;
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "minecraft/ComponentList.h"
|
||||
|
||||
Meta::Version::Version(const QString &uid, const QString &version)
|
||||
: BaseVersion(), m_uid(uid), m_version(version)
|
||||
: BaseVersion(), m_uid(uid), m_version(version)
|
||||
{
|
||||
}
|
||||
|
||||
@ -31,110 +31,110 @@ Meta::Version::~Version()
|
||||
|
||||
QString Meta::Version::descriptor()
|
||||
{
|
||||
return m_version;
|
||||
return m_version;
|
||||
}
|
||||
QString Meta::Version::name()
|
||||
{
|
||||
if(m_data)
|
||||
return m_data->name;
|
||||
return m_uid;
|
||||
if(m_data)
|
||||
return m_data->name;
|
||||
return m_uid;
|
||||
}
|
||||
QString Meta::Version::typeString() const
|
||||
{
|
||||
return m_type;
|
||||
return m_type;
|
||||
}
|
||||
|
||||
QDateTime Meta::Version::time() const
|
||||
{
|
||||
return QDateTime::fromMSecsSinceEpoch(m_time * 1000, Qt::UTC);
|
||||
return QDateTime::fromMSecsSinceEpoch(m_time * 1000, Qt::UTC);
|
||||
}
|
||||
|
||||
void Meta::Version::parse(const QJsonObject& obj)
|
||||
{
|
||||
parseVersion(obj, this);
|
||||
parseVersion(obj, this);
|
||||
}
|
||||
|
||||
void Meta::Version::mergeFromList(const Meta::VersionPtr& other)
|
||||
{
|
||||
if(other->m_providesRecommendations)
|
||||
{
|
||||
if(m_recommended != other->m_recommended)
|
||||
{
|
||||
setRecommended(other->m_recommended);
|
||||
}
|
||||
}
|
||||
if (m_type != other->m_type)
|
||||
{
|
||||
setType(other->m_type);
|
||||
}
|
||||
if (m_time != other->m_time)
|
||||
{
|
||||
setTime(other->m_time);
|
||||
}
|
||||
if (m_requires != other->m_requires)
|
||||
{
|
||||
m_requires = other->m_requires;
|
||||
}
|
||||
if (m_conflicts != other->m_conflicts)
|
||||
{
|
||||
m_conflicts = other->m_conflicts;
|
||||
}
|
||||
if(m_volatile != other->m_volatile)
|
||||
{
|
||||
setVolatile(other->m_volatile);
|
||||
}
|
||||
if(other->m_providesRecommendations)
|
||||
{
|
||||
if(m_recommended != other->m_recommended)
|
||||
{
|
||||
setRecommended(other->m_recommended);
|
||||
}
|
||||
}
|
||||
if (m_type != other->m_type)
|
||||
{
|
||||
setType(other->m_type);
|
||||
}
|
||||
if (m_time != other->m_time)
|
||||
{
|
||||
setTime(other->m_time);
|
||||
}
|
||||
if (m_requires != other->m_requires)
|
||||
{
|
||||
m_requires = other->m_requires;
|
||||
}
|
||||
if (m_conflicts != other->m_conflicts)
|
||||
{
|
||||
m_conflicts = other->m_conflicts;
|
||||
}
|
||||
if(m_volatile != other->m_volatile)
|
||||
{
|
||||
setVolatile(other->m_volatile);
|
||||
}
|
||||
}
|
||||
|
||||
void Meta::Version::merge(const VersionPtr &other)
|
||||
{
|
||||
mergeFromList(other);
|
||||
if(other->m_data)
|
||||
{
|
||||
setData(other->m_data);
|
||||
}
|
||||
mergeFromList(other);
|
||||
if(other->m_data)
|
||||
{
|
||||
setData(other->m_data);
|
||||
}
|
||||
}
|
||||
|
||||
QString Meta::Version::localFilename() const
|
||||
{
|
||||
return m_uid + '/' + m_version + ".json";
|
||||
return m_uid + '/' + m_version + ".json";
|
||||
}
|
||||
|
||||
void Meta::Version::setType(const QString &type)
|
||||
{
|
||||
m_type = type;
|
||||
emit typeChanged();
|
||||
m_type = type;
|
||||
emit typeChanged();
|
||||
}
|
||||
|
||||
void Meta::Version::setTime(const qint64 time)
|
||||
{
|
||||
m_time = time;
|
||||
emit timeChanged();
|
||||
m_time = time;
|
||||
emit timeChanged();
|
||||
}
|
||||
|
||||
void Meta::Version::setRequires(const Meta::RequireSet &requires, const Meta::RequireSet &conflicts)
|
||||
{
|
||||
m_requires = requires;
|
||||
m_conflicts = conflicts;
|
||||
emit requiresChanged();
|
||||
m_requires = requires;
|
||||
m_conflicts = conflicts;
|
||||
emit requiresChanged();
|
||||
}
|
||||
|
||||
void Meta::Version::setVolatile(bool volatile_)
|
||||
{
|
||||
m_volatile = volatile_;
|
||||
m_volatile = volatile_;
|
||||
}
|
||||
|
||||
|
||||
void Meta::Version::setData(const VersionFilePtr &data)
|
||||
{
|
||||
m_data = data;
|
||||
m_data = data;
|
||||
}
|
||||
|
||||
void Meta::Version::setProvidesRecommendations()
|
||||
{
|
||||
m_providesRecommendations = true;
|
||||
m_providesRecommendations = true;
|
||||
}
|
||||
|
||||
void Meta::Version::setRecommended(bool recommended)
|
||||
{
|
||||
m_recommended = recommended;
|
||||
m_recommended = recommended;
|
||||
}
|
||||
|
@ -36,82 +36,82 @@ using VersionPtr = std::shared_ptr<class Version>;
|
||||
|
||||
class MULTIMC_LOGIC_EXPORT Version : public QObject, public BaseVersion, public BaseEntity
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public: /* con/des */
|
||||
explicit Version(const QString &uid, const QString &version);
|
||||
virtual ~Version();
|
||||
explicit Version(const QString &uid, const QString &version);
|
||||
virtual ~Version();
|
||||
|
||||
QString descriptor() override;
|
||||
QString name() override;
|
||||
QString typeString() const override;
|
||||
QString descriptor() override;
|
||||
QString name() override;
|
||||
QString typeString() const override;
|
||||
|
||||
QString uid() const
|
||||
{
|
||||
return m_uid;
|
||||
}
|
||||
QString version() const
|
||||
{
|
||||
return m_version;
|
||||
}
|
||||
QString type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
QDateTime time() const;
|
||||
qint64 rawTime() const
|
||||
{
|
||||
return m_time;
|
||||
}
|
||||
const Meta::RequireSet &requires() const
|
||||
{
|
||||
return m_requires;
|
||||
}
|
||||
VersionFilePtr data() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
bool isRecommended() const
|
||||
{
|
||||
return m_recommended;
|
||||
}
|
||||
bool isLoaded() const
|
||||
{
|
||||
return m_data != nullptr;
|
||||
}
|
||||
QString uid() const
|
||||
{
|
||||
return m_uid;
|
||||
}
|
||||
QString version() const
|
||||
{
|
||||
return m_version;
|
||||
}
|
||||
QString type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
QDateTime time() const;
|
||||
qint64 rawTime() const
|
||||
{
|
||||
return m_time;
|
||||
}
|
||||
const Meta::RequireSet &requires() const
|
||||
{
|
||||
return m_requires;
|
||||
}
|
||||
VersionFilePtr data() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
bool isRecommended() const
|
||||
{
|
||||
return m_recommended;
|
||||
}
|
||||
bool isLoaded() const
|
||||
{
|
||||
return m_data != nullptr;
|
||||
}
|
||||
|
||||
void merge(const VersionPtr &other);
|
||||
void mergeFromList(const VersionPtr &other);
|
||||
void parse(const QJsonObject &obj) override;
|
||||
void merge(const VersionPtr &other);
|
||||
void mergeFromList(const VersionPtr &other);
|
||||
void parse(const QJsonObject &obj) override;
|
||||
|
||||
QString localFilename() const override;
|
||||
QString localFilename() const override;
|
||||
|
||||
public: // for usage by format parsers only
|
||||
void setType(const QString &type);
|
||||
void setTime(const qint64 time);
|
||||
void setRequires(const Meta::RequireSet &requires, const Meta::RequireSet &conflicts);
|
||||
void setVolatile(bool volatile_);
|
||||
void setRecommended(bool recommended);
|
||||
void setProvidesRecommendations();
|
||||
void setData(const VersionFilePtr &data);
|
||||
void setType(const QString &type);
|
||||
void setTime(const qint64 time);
|
||||
void setRequires(const Meta::RequireSet &requires, const Meta::RequireSet &conflicts);
|
||||
void setVolatile(bool volatile_);
|
||||
void setRecommended(bool recommended);
|
||||
void setProvidesRecommendations();
|
||||
void setData(const VersionFilePtr &data);
|
||||
|
||||
signals:
|
||||
void typeChanged();
|
||||
void timeChanged();
|
||||
void requiresChanged();
|
||||
void typeChanged();
|
||||
void timeChanged();
|
||||
void requiresChanged();
|
||||
|
||||
private:
|
||||
bool m_providesRecommendations = false;
|
||||
bool m_recommended = false;
|
||||
QString m_name;
|
||||
QString m_uid;
|
||||
QString m_version;
|
||||
QString m_type;
|
||||
qint64 m_time = 0;
|
||||
Meta::RequireSet m_requires;
|
||||
Meta::RequireSet m_conflicts;
|
||||
bool m_volatile = false;
|
||||
VersionFilePtr m_data;
|
||||
bool m_providesRecommendations = false;
|
||||
bool m_recommended = false;
|
||||
QString m_name;
|
||||
QString m_uid;
|
||||
QString m_version;
|
||||
QString m_type;
|
||||
qint64 m_time = 0;
|
||||
Meta::RequireSet m_requires;
|
||||
Meta::RequireSet m_conflicts;
|
||||
bool m_volatile = false;
|
||||
VersionFilePtr m_data;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -24,222 +24,222 @@
|
||||
namespace Meta
|
||||
{
|
||||
VersionList::VersionList(const QString &uid, QObject *parent)
|
||||
: BaseVersionList(parent), m_uid(uid)
|
||||
: BaseVersionList(parent), m_uid(uid)
|
||||
{
|
||||
setObjectName("Version list: " + uid);
|
||||
setObjectName("Version list: " + uid);
|
||||
}
|
||||
|
||||
shared_qobject_ptr<Task> VersionList::getLoadTask()
|
||||
{
|
||||
load(Net::Mode::Online);
|
||||
return getCurrentTask();
|
||||
load(Net::Mode::Online);
|
||||
return getCurrentTask();
|
||||
}
|
||||
|
||||
bool VersionList::isLoaded()
|
||||
{
|
||||
return BaseEntity::isLoaded();
|
||||
return BaseEntity::isLoaded();
|
||||
}
|
||||
|
||||
const BaseVersionPtr VersionList::at(int i) const
|
||||
{
|
||||
return m_versions.at(i);
|
||||
return m_versions.at(i);
|
||||
}
|
||||
int VersionList::count() const
|
||||
{
|
||||
return m_versions.size();
|
||||
return m_versions.size();
|
||||
}
|
||||
|
||||
void VersionList::sortVersions()
|
||||
{
|
||||
beginResetModel();
|
||||
std::sort(m_versions.begin(), m_versions.end(), [](const VersionPtr &a, const VersionPtr &b)
|
||||
{
|
||||
return *a.get() < *b.get();
|
||||
});
|
||||
endResetModel();
|
||||
beginResetModel();
|
||||
std::sort(m_versions.begin(), m_versions.end(), [](const VersionPtr &a, const VersionPtr &b)
|
||||
{
|
||||
return *a.get() < *b.get();
|
||||
});
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
QVariant VersionList::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid() || index.row() < 0 || index.row() >= m_versions.size() || index.parent().isValid())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
if (!index.isValid() || index.row() < 0 || index.row() >= m_versions.size() || index.parent().isValid())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
VersionPtr version = m_versions.at(index.row());
|
||||
VersionPtr version = m_versions.at(index.row());
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case VersionPointerRole: return QVariant::fromValue(std::dynamic_pointer_cast<BaseVersion>(version));
|
||||
case VersionRole:
|
||||
case VersionIdRole:
|
||||
return version->version();
|
||||
case ParentVersionRole:
|
||||
{
|
||||
// FIXME: HACK: this should be generic and be replaced by something else. Anything that is a hard 'equals' dep is a 'parent uid'.
|
||||
auto & reqs = version->requires();
|
||||
auto iter = std::find_if(reqs.begin(), reqs.end(), [](const Require & req)
|
||||
{
|
||||
return req.uid == "net.minecraft";
|
||||
});
|
||||
if (iter != reqs.end())
|
||||
{
|
||||
return (*iter).equalsVersion;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
case TypeRole: return version->type();
|
||||
switch (role)
|
||||
{
|
||||
case VersionPointerRole: return QVariant::fromValue(std::dynamic_pointer_cast<BaseVersion>(version));
|
||||
case VersionRole:
|
||||
case VersionIdRole:
|
||||
return version->version();
|
||||
case ParentVersionRole:
|
||||
{
|
||||
// FIXME: HACK: this should be generic and be replaced by something else. Anything that is a hard 'equals' dep is a 'parent uid'.
|
||||
auto & reqs = version->requires();
|
||||
auto iter = std::find_if(reqs.begin(), reqs.end(), [](const Require & req)
|
||||
{
|
||||
return req.uid == "net.minecraft";
|
||||
});
|
||||
if (iter != reqs.end())
|
||||
{
|
||||
return (*iter).equalsVersion;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
case TypeRole: return version->type();
|
||||
|
||||
case UidRole: return version->uid();
|
||||
case TimeRole: return version->time();
|
||||
case RequiresRole: return QVariant::fromValue(version->requires());
|
||||
case SortRole: return version->rawTime();
|
||||
case VersionPtrRole: return QVariant::fromValue(version);
|
||||
case RecommendedRole: return version->isRecommended();
|
||||
// FIXME: this should be determined in whatever view/proxy is used...
|
||||
// case LatestRole: return version == getLatestStable();
|
||||
default: return QVariant();
|
||||
}
|
||||
case UidRole: return version->uid();
|
||||
case TimeRole: return version->time();
|
||||
case RequiresRole: return QVariant::fromValue(version->requires());
|
||||
case SortRole: return version->rawTime();
|
||||
case VersionPtrRole: return QVariant::fromValue(version);
|
||||
case RecommendedRole: return version->isRecommended();
|
||||
// FIXME: this should be determined in whatever view/proxy is used...
|
||||
// case LatestRole: return version == getLatestStable();
|
||||
default: return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
BaseVersionList::RoleList VersionList::providesRoles() const
|
||||
{
|
||||
return {VersionPointerRole, VersionRole, VersionIdRole, ParentVersionRole,
|
||||
TypeRole, UidRole, TimeRole, RequiresRole, SortRole,
|
||||
RecommendedRole, LatestRole, VersionPtrRole};
|
||||
return {VersionPointerRole, VersionRole, VersionIdRole, ParentVersionRole,
|
||||
TypeRole, UidRole, TimeRole, RequiresRole, SortRole,
|
||||
RecommendedRole, LatestRole, VersionPtrRole};
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> VersionList::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles = BaseVersionList::roleNames();
|
||||
roles.insert(UidRole, "uid");
|
||||
roles.insert(TimeRole, "time");
|
||||
roles.insert(SortRole, "sort");
|
||||
roles.insert(RequiresRole, "requires");
|
||||
return roles;
|
||||
QHash<int, QByteArray> roles = BaseVersionList::roleNames();
|
||||
roles.insert(UidRole, "uid");
|
||||
roles.insert(TimeRole, "time");
|
||||
roles.insert(SortRole, "sort");
|
||||
roles.insert(RequiresRole, "requires");
|
||||
return roles;
|
||||
}
|
||||
|
||||
QString VersionList::localFilename() const
|
||||
{
|
||||
return m_uid + "/index.json";
|
||||
return m_uid + "/index.json";
|
||||
}
|
||||
|
||||
QString VersionList::humanReadable() const
|
||||
{
|
||||
return m_name.isEmpty() ? m_uid : m_name;
|
||||
return m_name.isEmpty() ? m_uid : m_name;
|
||||
}
|
||||
|
||||
VersionPtr VersionList::getVersion(const QString &version)
|
||||
{
|
||||
VersionPtr out = m_lookup.value(version, nullptr);
|
||||
if(!out)
|
||||
{
|
||||
out = std::make_shared<Version>(m_uid, version);
|
||||
m_lookup[version] = out;
|
||||
}
|
||||
return out;
|
||||
VersionPtr out = m_lookup.value(version, nullptr);
|
||||
if(!out)
|
||||
{
|
||||
out = std::make_shared<Version>(m_uid, version);
|
||||
m_lookup[version] = out;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void VersionList::setName(const QString &name)
|
||||
{
|
||||
m_name = name;
|
||||
emit nameChanged(name);
|
||||
m_name = name;
|
||||
emit nameChanged(name);
|
||||
}
|
||||
|
||||
void VersionList::setVersions(const QVector<VersionPtr> &versions)
|
||||
{
|
||||
beginResetModel();
|
||||
m_versions = versions;
|
||||
std::sort(m_versions.begin(), m_versions.end(), [](const VersionPtr &a, const VersionPtr &b)
|
||||
{
|
||||
return a->rawTime() > b->rawTime();
|
||||
});
|
||||
for (int i = 0; i < m_versions.size(); ++i)
|
||||
{
|
||||
m_lookup.insert(m_versions.at(i)->version(), m_versions.at(i));
|
||||
setupAddedVersion(i, m_versions.at(i));
|
||||
}
|
||||
beginResetModel();
|
||||
m_versions = versions;
|
||||
std::sort(m_versions.begin(), m_versions.end(), [](const VersionPtr &a, const VersionPtr &b)
|
||||
{
|
||||
return a->rawTime() > b->rawTime();
|
||||
});
|
||||
for (int i = 0; i < m_versions.size(); ++i)
|
||||
{
|
||||
m_lookup.insert(m_versions.at(i)->version(), m_versions.at(i));
|
||||
setupAddedVersion(i, m_versions.at(i));
|
||||
}
|
||||
|
||||
// FIXME: this is dumb, we have 'recommended' as part of the metadata already...
|
||||
auto recommendedIt = std::find_if(m_versions.constBegin(), m_versions.constEnd(), [](const VersionPtr &ptr) { return ptr->type() == "release"; });
|
||||
m_recommended = recommendedIt == m_versions.constEnd() ? nullptr : *recommendedIt;
|
||||
endResetModel();
|
||||
// FIXME: this is dumb, we have 'recommended' as part of the metadata already...
|
||||
auto recommendedIt = std::find_if(m_versions.constBegin(), m_versions.constEnd(), [](const VersionPtr &ptr) { return ptr->type() == "release"; });
|
||||
m_recommended = recommendedIt == m_versions.constEnd() ? nullptr : *recommendedIt;
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void VersionList::parse(const QJsonObject& obj)
|
||||
{
|
||||
parseVersionList(obj, this);
|
||||
parseVersionList(obj, this);
|
||||
}
|
||||
|
||||
// FIXME: this is dumb, we have 'recommended' as part of the metadata already...
|
||||
static const Meta::VersionPtr &getBetterVersion(const Meta::VersionPtr &a, const Meta::VersionPtr &b)
|
||||
{
|
||||
if(!a)
|
||||
return b;
|
||||
if(!b)
|
||||
return a;
|
||||
if(a->type() == b->type())
|
||||
{
|
||||
// newer of same type wins
|
||||
return (a->rawTime() > b->rawTime() ? a : b);
|
||||
}
|
||||
// 'release' type wins
|
||||
return (a->type() == "release" ? a : b);
|
||||
if(!a)
|
||||
return b;
|
||||
if(!b)
|
||||
return a;
|
||||
if(a->type() == b->type())
|
||||
{
|
||||
// newer of same type wins
|
||||
return (a->rawTime() > b->rawTime() ? a : b);
|
||||
}
|
||||
// 'release' type wins
|
||||
return (a->type() == "release" ? a : b);
|
||||
}
|
||||
|
||||
void VersionList::mergeFromIndex(const VersionListPtr &other)
|
||||
{
|
||||
if (m_name != other->m_name)
|
||||
{
|
||||
setName(other->m_name);
|
||||
}
|
||||
if (m_name != other->m_name)
|
||||
{
|
||||
setName(other->m_name);
|
||||
}
|
||||
}
|
||||
|
||||
void VersionList::merge(const VersionListPtr &other)
|
||||
{
|
||||
if (m_name != other->m_name)
|
||||
{
|
||||
setName(other->m_name);
|
||||
}
|
||||
if (m_name != other->m_name)
|
||||
{
|
||||
setName(other->m_name);
|
||||
}
|
||||
|
||||
// TODO: do not reset the whole model. maybe?
|
||||
beginResetModel();
|
||||
m_versions.clear();
|
||||
if(other->m_versions.isEmpty())
|
||||
{
|
||||
qWarning() << "Empty list loaded ...";
|
||||
}
|
||||
for (const VersionPtr &version : other->m_versions)
|
||||
{
|
||||
// we already have the version. merge the contents
|
||||
if (m_lookup.contains(version->version()))
|
||||
{
|
||||
m_lookup.value(version->version())->mergeFromList(version);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_lookup.insert(version->uid(), version);
|
||||
}
|
||||
// connect it.
|
||||
setupAddedVersion(m_versions.size(), version);
|
||||
m_versions.append(version);
|
||||
m_recommended = getBetterVersion(m_recommended, version);
|
||||
}
|
||||
endResetModel();
|
||||
// TODO: do not reset the whole model. maybe?
|
||||
beginResetModel();
|
||||
m_versions.clear();
|
||||
if(other->m_versions.isEmpty())
|
||||
{
|
||||
qWarning() << "Empty list loaded ...";
|
||||
}
|
||||
for (const VersionPtr &version : other->m_versions)
|
||||
{
|
||||
// we already have the version. merge the contents
|
||||
if (m_lookup.contains(version->version()))
|
||||
{
|
||||
m_lookup.value(version->version())->mergeFromList(version);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_lookup.insert(version->uid(), version);
|
||||
}
|
||||
// connect it.
|
||||
setupAddedVersion(m_versions.size(), version);
|
||||
m_versions.append(version);
|
||||
m_recommended = getBetterVersion(m_recommended, version);
|
||||
}
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void VersionList::setupAddedVersion(const int row, const VersionPtr &version)
|
||||
{
|
||||
// FIXME: do not disconnect from everythin, disconnect only the lambdas here
|
||||
version->disconnect();
|
||||
connect(version.get(), &Version::requiresChanged, this, [this, row]() { emit dataChanged(index(row), index(row), QVector<int>() << RequiresRole); });
|
||||
connect(version.get(), &Version::timeChanged, this, [this, row]() { emit dataChanged(index(row), index(row), QVector<int>() << TimeRole << SortRole); });
|
||||
connect(version.get(), &Version::typeChanged, this, [this, row]() { emit dataChanged(index(row), index(row), QVector<int>() << TypeRole); });
|
||||
// FIXME: do not disconnect from everythin, disconnect only the lambdas here
|
||||
version->disconnect();
|
||||
connect(version.get(), &Version::requiresChanged, this, [this, row]() { emit dataChanged(index(row), index(row), QVector<int>() << RequiresRole); });
|
||||
connect(version.get(), &Version::timeChanged, this, [this, row]() { emit dataChanged(index(row), index(row), QVector<int>() << TimeRole << SortRole); });
|
||||
connect(version.get(), &Version::typeChanged, this, [this, row]() { emit dataChanged(index(row), index(row), QVector<int>() << TypeRole); });
|
||||
}
|
||||
|
||||
BaseVersionPtr VersionList::getRecommended() const
|
||||
{
|
||||
return m_recommended;
|
||||
return m_recommended;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,75 +27,75 @@ using VersionListPtr = std::shared_ptr<class VersionList>;
|
||||
|
||||
class MULTIMC_LOGIC_EXPORT VersionList : public BaseVersionList, public BaseEntity
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString uid READ uid CONSTANT)
|
||||
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString uid READ uid CONSTANT)
|
||||
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
|
||||
public:
|
||||
explicit VersionList(const QString &uid, QObject *parent = nullptr);
|
||||
explicit VersionList(const QString &uid, QObject *parent = nullptr);
|
||||
|
||||
enum Roles
|
||||
{
|
||||
UidRole = Qt::UserRole + 100,
|
||||
TimeRole,
|
||||
RequiresRole,
|
||||
VersionPtrRole
|
||||
};
|
||||
enum Roles
|
||||
{
|
||||
UidRole = Qt::UserRole + 100,
|
||||
TimeRole,
|
||||
RequiresRole,
|
||||
VersionPtrRole
|
||||
};
|
||||
|
||||
shared_qobject_ptr<Task> getLoadTask() override;
|
||||
bool isLoaded() override;
|
||||
const BaseVersionPtr at(int i) const override;
|
||||
int count() const override;
|
||||
void sortVersions() override;
|
||||
shared_qobject_ptr<Task> getLoadTask() override;
|
||||
bool isLoaded() override;
|
||||
const BaseVersionPtr at(int i) const override;
|
||||
int count() const override;
|
||||
void sortVersions() override;
|
||||
|
||||
BaseVersionPtr getRecommended() const override;
|
||||
BaseVersionPtr getRecommended() const override;
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
RoleList providesRoles() const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
RoleList providesRoles() const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
QString localFilename() const override;
|
||||
QString localFilename() const override;
|
||||
|
||||
QString uid() const
|
||||
{
|
||||
return m_uid;
|
||||
}
|
||||
QString name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
QString humanReadable() const;
|
||||
QString uid() const
|
||||
{
|
||||
return m_uid;
|
||||
}
|
||||
QString name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
QString humanReadable() const;
|
||||
|
||||
VersionPtr getVersion(const QString &version);
|
||||
VersionPtr getVersion(const QString &version);
|
||||
|
||||
QVector<VersionPtr> versions() const
|
||||
{
|
||||
return m_versions;
|
||||
}
|
||||
QVector<VersionPtr> versions() const
|
||||
{
|
||||
return m_versions;
|
||||
}
|
||||
|
||||
public: // for usage only by parsers
|
||||
void setName(const QString &name);
|
||||
void setVersions(const QVector<VersionPtr> &versions);
|
||||
void merge(const VersionListPtr &other);
|
||||
void mergeFromIndex(const VersionListPtr &other);
|
||||
void parse(const QJsonObject &obj) override;
|
||||
void setName(const QString &name);
|
||||
void setVersions(const QVector<VersionPtr> &versions);
|
||||
void merge(const VersionListPtr &other);
|
||||
void mergeFromIndex(const VersionListPtr &other);
|
||||
void parse(const QJsonObject &obj) override;
|
||||
|
||||
signals:
|
||||
void nameChanged(const QString &name);
|
||||
void nameChanged(const QString &name);
|
||||
|
||||
protected slots:
|
||||
void updateListData(QList<BaseVersionPtr>) override
|
||||
{
|
||||
}
|
||||
void updateListData(QList<BaseVersionPtr>) override
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
QVector<VersionPtr> m_versions;
|
||||
QHash<QString, VersionPtr> m_lookup;
|
||||
QString m_uid;
|
||||
QString m_name;
|
||||
QVector<VersionPtr> m_versions;
|
||||
QHash<QString, VersionPtr> m_lookup;
|
||||
QString m_uid;
|
||||
QString m_name;
|
||||
|
||||
VersionPtr m_recommended;
|
||||
VersionPtr m_recommended;
|
||||
|
||||
void setupAddedVersion(const int row, const VersionPtr &version);
|
||||
void setupAddedVersion(const int row, const VersionPtr &version);
|
||||
};
|
||||
}
|
||||
Q_DECLARE_METATYPE(Meta::VersionListPtr)
|
||||
|
Reference in New Issue
Block a user