Sync from quickmods

This commit is contained in:
Petr Mrázek 2014-09-06 18:16:56 +02:00
parent 36efcf8d3c
commit 20cb97a35a
57 changed files with 569 additions and 326 deletions

View File

@ -251,12 +251,12 @@ MultiMC::MultiMC(int &argc, char **argv, bool root_override) : QApplication(argc
std::shared_ptr<BaseProfilerFactory>(new JVisualVMFactory())); std::shared_ptr<BaseProfilerFactory>(new JVisualVMFactory()));
for (auto profiler : m_profilers.values()) for (auto profiler : m_profilers.values())
{ {
profiler->registerSettings(m_settings.get()); profiler->registerSettings(m_settings);
} }
m_tools.insert("mcedit", std::shared_ptr<BaseDetachedToolFactory>(new MCEditFactory())); m_tools.insert("mcedit", std::shared_ptr<BaseDetachedToolFactory>(new MCEditFactory()));
for (auto tool : m_tools.values()) for (auto tool : m_tools.values())
{ {
tool->registerSettings(m_settings.get()); tool->registerSettings(m_settings);
} }
// launch instance, if that's what should be done // launch instance, if that's what should be done

View File

@ -1,6 +1,8 @@
#pragma once #pragma once
#include <QString> #include <QString>
#include <QList>
#include "libutil_config.h" #include "libutil_config.h"
class QUrl; class QUrl;
@ -10,10 +12,12 @@ namespace Util
struct Version struct Version
{ {
Version(const QString &str); Version(const QString &str);
Version() {}
bool operator<(const Version &other) const; bool operator<(const Version &other) const;
bool operator<=(const Version &other) const; bool operator<=(const Version &other) const;
bool operator>(const Version &other) const; bool operator>(const Version &other) const;
bool operator>=(const Version &other) const;
bool operator==(const Version &other) const; bool operator==(const Version &other) const;
bool operator!=(const Version &other) const; bool operator!=(const Version &other) const;
@ -24,9 +28,34 @@ struct Version
private: private:
QString m_string; QString m_string;
struct Section
{
explicit Section(const QString &str, const int num) : numValid(true), number(num), string(str) {}
explicit Section(const QString &str) : numValid(false), string(str) {}
explicit Section() {}
bool numValid;
int number;
QString string;
inline bool operator!=(const Section &other) const
{
return (numValid && other.numValid) ? (number != other.number) : (string != other.string);
}
inline bool operator<(const Section &other) const
{
return (numValid && other.numValid) ? (number < other.number) : (string < other.string);
}
inline bool operator>(const Section &other) const
{
return (numValid && other.numValid) ? (number > other.number) : (string > other.string);
}
};
QList<Section> m_sections;
void parse();
}; };
LIBUTIL_EXPORT QUrl expandQMURL(const QString &in);
LIBUTIL_EXPORT bool versionIsInInterval(const QString &version, const QString &interval); LIBUTIL_EXPORT bool versionIsInInterval(const QString &version, const QString &interval);
LIBUTIL_EXPORT bool versionIsInInterval(const Version &version, const QString &interval);
} }

View File

@ -7,42 +7,20 @@
Util::Version::Version(const QString &str) : m_string(str) Util::Version::Version(const QString &str) : m_string(str)
{ {
parse();
} }
bool Util::Version::operator<(const Version &other) const bool Util::Version::operator<(const Version &other) const
{ {
QStringList parts1 = m_string.split('.'); const int size = qMax(m_sections.size(), other.m_sections.size());
QStringList parts2 = other.m_string.split('.'); for (int i = 0; i < size; ++i)
while (!parts1.isEmpty() && !parts2.isEmpty())
{ {
QString part1 = parts1.isEmpty() ? "0" : parts1.takeFirst(); const Section sec1 = (i >= m_sections.size()) ? Section("0", 0) : m_sections.at(i);
QString part2 = parts2.isEmpty() ? "0" : parts2.takeFirst(); const Section sec2 =
bool ok1 = false; (i >= other.m_sections.size()) ? Section("0", 0) : other.m_sections.at(i);
bool ok2 = false; if (sec1 != sec2)
int int1 = part1.toInt(&ok1);
int int2 = part2.toInt(&ok2);
if (ok1 && ok2)
{ {
if (int1 == int2) return sec1 < sec2;
{
continue;
}
else
{
return int1 < int2;
}
}
else
{
if (part1 == part2)
{
continue;
}
else
{
return part1 < part2;
}
} }
} }
@ -54,77 +32,35 @@ bool Util::Version::operator<=(const Util::Version &other) const
} }
bool Util::Version::operator>(const Version &other) const bool Util::Version::operator>(const Version &other) const
{ {
QStringList parts1 = m_string.split('.'); const int size = qMax(m_sections.size(), other.m_sections.size());
QStringList parts2 = other.m_string.split('.'); for (int i = 0; i < size; ++i)
while (!parts1.isEmpty() && !parts2.isEmpty())
{ {
QString part1 = parts1.isEmpty() ? "0" : parts1.takeFirst(); const Section sec1 = (i >= m_sections.size()) ? Section("0", 0) : m_sections.at(i);
QString part2 = parts2.isEmpty() ? "0" : parts2.takeFirst(); const Section sec2 =
bool ok1 = false; (i >= other.m_sections.size()) ? Section("0", 0) : other.m_sections.at(i);
bool ok2 = false; if (sec1 != sec2)
int int1 = part1.toInt(&ok1);
int int2 = part2.toInt(&ok2);
if (ok1 && ok2)
{ {
if (int1 == int2) return sec1 > sec2;
{
continue;
}
else
{
return int1 > int2;
}
}
else
{
if (part1 == part2)
{
continue;
}
else
{
return part1 > part2;
}
} }
} }
return false; return false;
} }
bool Util::Version::operator>=(const Version &other) const
{
return *this > other || *this == other;
}
bool Util::Version::operator==(const Version &other) const bool Util::Version::operator==(const Version &other) const
{ {
QStringList parts1 = m_string.split('.'); const int size = qMax(m_sections.size(), other.m_sections.size());
QStringList parts2 = other.m_string.split('.'); for (int i = 0; i < size; ++i)
while (!parts1.isEmpty() && !parts2.isEmpty())
{ {
QString part1 = parts1.isEmpty() ? "0" : parts1.takeFirst(); const Section sec1 = (i >= m_sections.size()) ? Section("0", 0) : m_sections.at(i);
QString part2 = parts2.isEmpty() ? "0" : parts2.takeFirst(); const Section sec2 =
bool ok1 = false; (i >= other.m_sections.size()) ? Section("0", 0) : other.m_sections.at(i);
bool ok2 = false; if (sec1 != sec2)
int int1 = part1.toInt(&ok1);
int int2 = part2.toInt(&ok2);
if (ok1 && ok2)
{ {
if (int1 == int2) return false;
{
continue;
}
else
{
return false;
}
}
else
{
if (part1 == part2)
{
continue;
}
else
{
return false;
}
} }
} }
@ -135,45 +71,41 @@ bool Util::Version::operator!=(const Version &other) const
return !operator==(other); return !operator==(other);
} }
QUrl Util::expandQMURL(const QString &in) void Util::Version::parse()
{ {
QUrl inUrl(in); m_sections.clear();
if (inUrl.scheme() == "github")
QStringList parts = m_string.split('.');
for (const auto part : parts)
{ {
// needed because QUrl makes the host all lower cases bool ok = false;
const QString repo = in.mid(in.indexOf(inUrl.host(), 0, Qt::CaseInsensitive), inUrl.host().size()); int num = part.toInt(&ok);
QUrl out; if (ok)
out.setScheme("https"); {
out.setHost("raw.github.com"); m_sections.append(Section(part, num));
out.setPath(QString("/%1/%2/%3%4") }
.arg(inUrl.userInfo(), repo, else
inUrl.fragment().isEmpty() ? "master" : inUrl.fragment(), inUrl.path())); {
return out; m_sections.append(Section(part));
} }
else if (inUrl.scheme() == "mcf")
{
QUrl out;
out.setScheme("http");
out.setHost("www.minecraftforum.net");
out.setPath(QString("/topic/%1-").arg(inUrl.path()));
return out;
}
else
{
return in;
} }
} }
bool Util::versionIsInInterval(const QString &version, const QString &interval) bool Util::versionIsInInterval(const QString &version, const QString &interval)
{ {
if (interval.isEmpty() || version == interval) return versionIsInInterval(Util::Version(version), interval);
}
bool Util::versionIsInInterval(const Version &version, const QString &interval)
{
if (interval.isEmpty() || version.toString() == interval)
{ {
return true; return true;
} }
// Interval notation is used // Interval notation is used
QRegularExpression exp( QRegularExpression exp(
"(?<start>[\\[\\]\\(\\)])(?<bottom>.*?)(,(?<top>.*?))?(?<end>[\\[\\]\\(\\)])"); "(?<start>[\\[\\]\\(\\)])(?<bottom>.*?)(,(?<top>.*?))?(?<end>[\\[\\]\\(\\)]),?");
QRegularExpressionMatch match = exp.match(interval); QRegularExpressionMatch match = exp.match(interval);
if (match.hasMatch()) if (match.hasMatch())
{ {
@ -185,11 +117,12 @@ bool Util::versionIsInInterval(const QString &version, const QString &interval)
// check if in range (bottom) // check if in range (bottom)
if (!bottom.isEmpty()) if (!bottom.isEmpty())
{ {
if ((start == '[') && !(version >= bottom)) const auto bottomVersion = Util::Version(bottom);
if ((start == '[') && !(version >= bottomVersion))
{ {
return false; return false;
} }
else if ((start == '(') && !(version > bottom)) else if ((start == '(') && !(version > bottomVersion))
{ {
return false; return false;
} }
@ -198,11 +131,12 @@ bool Util::versionIsInInterval(const QString &version, const QString &interval)
// check if in range (top) // check if in range (top)
if (!top.isEmpty()) if (!top.isEmpty())
{ {
if ((end == ']') && !(version <= top)) const auto topVersion = Util::Version(top);
if ((end == ']') && !(version <= topVersion))
{ {
return false; return false;
} }
else if ((end == ')') && !(version < top)) else if ((end == ')') && !(version < topVersion))
{ {
return false; return false;
} }

View File

@ -65,9 +65,9 @@
#include "gui/pages/global/MultiMCPage.h" #include "gui/pages/global/MultiMCPage.h"
#include "gui/pages/global/ExternalToolsPage.h" #include "gui/pages/global/ExternalToolsPage.h"
#include "gui/pages/global/AccountListPage.h" #include "gui/pages/global/AccountListPage.h"
#include "pages/global/ProxyPage.h" #include "gui/pages/global/ProxyPage.h"
#include "pages/global/JavaPage.h" #include "gui/pages/global/JavaPage.h"
#include "pages/global/MinecraftPage.h" #include "gui/pages/global/MinecraftPage.h"
#include "gui/ConsoleWindow.h" #include "gui/ConsoleWindow.h"
#include "pagedialog/PageDialog.h" #include "pagedialog/PageDialog.h"
@ -91,6 +91,7 @@
#include "logic/net/NetJob.h" #include "logic/net/NetJob.h"
#include "logic/BaseInstance.h" #include "logic/BaseInstance.h"
#include "logic/OneSixInstance.h"
#include "logic/InstanceFactory.h" #include "logic/InstanceFactory.h"
#include "logic/MinecraftProcess.h" #include "logic/MinecraftProcess.h"
#include "logic/OneSixUpdate.h" #include "logic/OneSixUpdate.h"

View File

@ -387,7 +387,7 @@
</action> </action>
<action name="actionEditInstance"> <action name="actionEditInstance">
<property name="text"> <property name="text">
<string>Edit Mods</string> <string>Edit Instance</string>
</property> </property>
<property name="iconText"> <property name="iconText">
<string>Edit Instance</string> <string>Edit Instance</string>

View File

@ -4,7 +4,7 @@
bool lastfirst(QModelIndexList &list, int &first, int &last) bool lastfirst(QModelIndexList &list, int &first, int &last)
{ {
if (!list.size()) if (list.isEmpty())
return false; return false;
first = last = list[0].row(); first = last = list[0].row();
for (auto item : list) for (auto item : list)
@ -37,4 +37,4 @@ void showWebsiteForMod(QWidget *parentDlg, Mod &m)
QObject::tr("The mod author didn't provide a website link for this mod."), QObject::tr("The mod author didn't provide a website link for this mod."),
QMessageBox::Warning); QMessageBox::Warning);
} }
} }

View File

@ -38,15 +38,6 @@ NewInstanceDialog::NewInstanceDialog(QWidget *parent)
ui->setupUi(this); ui->setupUi(this);
resize(minimumSizeHint()); resize(minimumSizeHint());
layout()->setSizeConstraint(QLayout::SetFixedSize); layout()->setSizeConstraint(QLayout::SetFixedSize);
/*
if (!MinecraftVersionList::getMainList().isLoaded())
{
TaskDialog *taskDlg = new TaskDialog(this);
Task *loadTask = MinecraftVersionList::getMainList().getLoadTask();
loadTask->setParent(taskDlg);
taskDlg->exec(loadTask);
}
*/
setSelectedVersion(MMC->minecraftlist()->getLatestStable(), true); setSelectedVersion(MMC->minecraftlist()->getLatestStable(), true);
InstIconKey = "infinity"; InstIconKey = "infinity";
ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey)); ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));

View File

@ -16,6 +16,7 @@
#pragma once #pragma once
#include <QDialog> #include <QDialog>
#include "logic/BaseVersion.h" #include "logic/BaseVersion.h"
namespace Ui namespace Ui

View File

@ -113,16 +113,10 @@ void drawProgressOverlay(QPainter *painter, const QStyleOptionViewItemV4 &option
void drawBadges(QPainter *painter, const QStyleOptionViewItemV4 &option, BaseInstance *instance) void drawBadges(QPainter *painter, const QStyleOptionViewItemV4 &option, BaseInstance *instance)
{ {
QList<QString> pixmaps; QList<QString> pixmaps;
for (auto flag : instance->flags()) const BaseInstance::InstanceFlags flags = instance->flags();
if (flags & BaseInstance::VersionBrokenFlag)
{ {
switch (flag) pixmaps.append("broken");
{
case BaseInstance::VersionBrokenFlag:
pixmaps.append("broken");
break;
default:
break;
}
} }
// begin easter eggs // begin easter eggs
@ -160,7 +154,7 @@ void drawBadges(QPainter *painter, const QStyleOptionViewItemV4 &option, BaseIns
{ {
return; return;
} }
const QPixmap pixmap = ListViewDelegate::requestPixmap(it.next()).scaled( const QPixmap pixmap = ListViewDelegate::requestBadgePixmap(it.next()).scaled(
itemSide, itemSide, Qt::KeepAspectRatio, Qt::FastTransformation); itemSide, itemSide, Qt::KeepAspectRatio, Qt::FastTransformation);
painter->drawPixmap(option.rect.width() - x * itemSide + qMax(x - 1, 0) * spacing - itemSide, painter->drawPixmap(option.rect.width() - x * itemSide + qMax(x - 1, 0) * spacing - itemSide,
y * itemSide + qMax(y - 1, 0) * spacing, itemSide, itemSide, y * itemSide + qMax(y - 1, 0) * spacing, itemSide, itemSide,
@ -354,7 +348,7 @@ QSize ListViewDelegate::sizeHint(const QStyleOptionViewItem &option,
return sz; return sz;
} }
QPixmap ListViewDelegate::requestPixmap(const QString &key) QPixmap ListViewDelegate::requestBadgePixmap(const QString &key)
{ {
if (!m_pixmapCache.contains(key)) if (!m_pixmapCache.contains(key))
{ {

View File

@ -23,7 +23,7 @@ class ListViewDelegate : public QStyledItemDelegate
public: public:
explicit ListViewDelegate(QObject *parent = 0); explicit ListViewDelegate(QObject *parent = 0);
static QPixmap requestPixmap(const QString &key); static QPixmap requestBadgePixmap(const QString &key);
protected: protected:
void paint(QPainter *painter, const QStyleOptionViewItem &option, void paint(QPainter *painter, const QStyleOptionViewItem &option,

View File

@ -29,6 +29,7 @@
#include <cmdutils.h> #include <cmdutils.h>
#include "logic/minecraft/MinecraftVersionList.h" #include "logic/minecraft/MinecraftVersionList.h"
#include "logic/icons/IconList.h" #include "logic/icons/IconList.h"
#include "logic/InstanceList.h"
BaseInstance::BaseInstance(BaseInstancePrivate *d_in, const QString &rootDir, BaseInstance::BaseInstance(BaseInstancePrivate *d_in, const QString &rootDir,
SettingsObject *settings_obj, QObject *parent) SettingsObject *settings_obj, QObject *parent)
@ -143,10 +144,12 @@ QString BaseInstance::minecraftRoot() const
InstanceList *BaseInstance::instList() const InstanceList *BaseInstance::instList() const
{ {
if (parent()->inherits("InstanceList")) return qobject_cast<InstanceList *>(parent());
return (InstanceList *)parent(); }
else
return NULL; InstancePtr BaseInstance::getSharedPtr()
{
return instList()->getInstanceById(id());
} }
std::shared_ptr<BaseVersionList> BaseInstance::versionList() const std::shared_ptr<BaseVersionList> BaseInstance::versionList() const
@ -160,13 +163,12 @@ SettingsObject &BaseInstance::settings() const
return *d->m_settings; return *d->m_settings;
} }
QSet<BaseInstance::InstanceFlag> BaseInstance::flags() const BaseInstance::InstanceFlags BaseInstance::flags() const
{ {
I_D(const BaseInstance); I_D(const BaseInstance);
return QSet<InstanceFlag>(d->m_flags); return d->m_flags;
} }
void BaseInstance::setFlags(const InstanceFlags &flags)
void BaseInstance::setFlags(const QSet<InstanceFlag> &flags)
{ {
I_D(BaseInstance); I_D(BaseInstance);
if (flags != d->m_flags) if (flags != d->m_flags)
@ -176,10 +178,24 @@ void BaseInstance::setFlags(const QSet<InstanceFlag> &flags)
emit propertiesChanged(this); emit propertiesChanged(this);
} }
} }
void BaseInstance::setFlag(const BaseInstance::InstanceFlag flag)
{
I_D(BaseInstance);
d->m_flags |= flag;
emit flagsChanged();
emit propertiesChanged(this);
}
void BaseInstance::unsetFlag(const BaseInstance::InstanceFlag flag)
{
I_D(BaseInstance);
d->m_flags &= ~flag;
emit flagsChanged();
emit propertiesChanged(this);
}
bool BaseInstance::canLaunch() const bool BaseInstance::canLaunch() const
{ {
return !flags().contains(VersionBrokenFlag); return !(flags() & VersionBrokenFlag);
} }
bool BaseInstance::reload() bool BaseInstance::reload()

View File

@ -34,6 +34,10 @@ class OneSixUpdate;
class InstanceList; class InstanceList;
class BaseInstancePrivate; class BaseInstancePrivate;
// pointer for lazy people
class BaseInstance;
typedef std::shared_ptr<BaseInstance> InstancePtr;
/*! /*!
* \brief Base class for instances. * \brief Base class for instances.
* This class implements many functions that are common between instances and * This class implements many functions that are common between instances and
@ -163,6 +167,8 @@ public:
*/ */
InstanceList *instList() const; InstanceList *instList() const;
InstancePtr getSharedPtr();
/*! /*!
* \brief Gets a pointer to this instance's version list. * \brief Gets a pointer to this instance's version list.
* \return A pointer to the available version list for this instance. * \return A pointer to the available version list for this instance.
@ -193,11 +199,14 @@ public:
enum InstanceFlag enum InstanceFlag
{ {
NoFlags = 0x00, VersionBrokenFlag = 0x01,
VersionBrokenFlag = 0x01 UpdateAvailable = 0x02
}; };
QSet<InstanceFlag> flags() const; Q_DECLARE_FLAGS(InstanceFlags, InstanceFlag)
void setFlags(const QSet<InstanceFlag> &flags); InstanceFlags flags() const;
void setFlags(const InstanceFlags &flags);
void setFlag(const InstanceFlag flag);
void unsetFlag(const InstanceFlag flag);
bool canLaunch() const; bool canLaunch() const;
@ -226,7 +235,6 @@ protected:
std::shared_ptr<BaseInstancePrivate> inst_d; std::shared_ptr<BaseInstancePrivate> inst_d;
}; };
// pointer for lazy people Q_DECLARE_METATYPE(std::shared_ptr<BaseInstance>)
typedef std::shared_ptr<BaseInstance> InstancePtr;
Q_DECLARE_METATYPE(BaseInstance::InstanceFlag) Q_DECLARE_METATYPE(BaseInstance::InstanceFlag)
Q_DECLARE_OPERATORS_FOR_FLAGS(BaseInstance::InstanceFlags)

View File

@ -31,6 +31,6 @@ public:
QString m_rootDir; QString m_rootDir;
QString m_group; QString m_group;
std::shared_ptr<SettingsObject> m_settings; std::shared_ptr<SettingsObject> m_settings;
QSet<BaseInstance::InstanceFlag> m_flags; BaseInstance::InstanceFlags m_flags;
bool m_isRunning = false; bool m_isRunning = false;
}; };

View File

@ -24,6 +24,7 @@
*/ */
struct BaseVersion struct BaseVersion
{ {
virtual ~BaseVersion() {}
/*! /*!
* A string used to identify this version in config files. * A string used to identify this version in config files.
* This should be unique within the version list or shenanigans will occur. * This should be unique within the version list or shenanigans will occur.

View File

@ -52,19 +52,19 @@ InstanceFactory::InstLoadError InstanceFactory::loadInstance(InstancePtr &inst,
// FIXME: replace with a map lookup, where instance classes register their types // FIXME: replace with a map lookup, where instance classes register their types
if (inst_type == "OneSix" || inst_type == "Nostalgia") if (inst_type == "OneSix" || inst_type == "Nostalgia")
{ {
inst.reset(new OneSixInstance(instDir, m_settings, this)); inst.reset(new OneSixInstance(instDir, m_settings));
} }
else if (inst_type == "Legacy") else if (inst_type == "Legacy")
{ {
inst.reset(new LegacyInstance(instDir, m_settings, this)); inst.reset(new LegacyInstance(instDir, m_settings));
} }
else if (inst_type == "LegacyFTB") else if (inst_type == "LegacyFTB")
{ {
inst.reset(new LegacyFTBInstance(instDir, m_settings, this)); inst.reset(new LegacyFTBInstance(instDir, m_settings));
} }
else if (inst_type == "OneSixFTB") else if (inst_type == "OneSixFTB")
{ {
inst.reset(new OneSixFTBInstance(instDir, m_settings, this)); inst.reset(new OneSixFTBInstance(instDir, m_settings));
} }
else else
{ {
@ -82,11 +82,15 @@ InstanceFactory::InstCreateError InstanceFactory::createInstance(InstancePtr &in
QLOG_DEBUG() << instDir.toUtf8(); QLOG_DEBUG() << instDir.toUtf8();
if (!rootDir.exists() && !rootDir.mkpath(".")) if (!rootDir.exists() && !rootDir.mkpath("."))
{ {
QLOG_ERROR() << "Can't create instance folder" << instDir;
return InstanceFactory::CantCreateDir; return InstanceFactory::CantCreateDir;
} }
auto mcVer = std::dynamic_pointer_cast<MinecraftVersion>(version); auto mcVer = std::dynamic_pointer_cast<MinecraftVersion>(version);
if (!mcVer) if (!mcVer)
{
QLOG_ERROR() << "Can't create instance for non-existing MC version";
return InstanceFactory::NoSuchVersion; return InstanceFactory::NoSuchVersion;
}
auto m_settings = new INISettingsObject(PathCombine(instDir, "instance.cfg")); auto m_settings = new INISettingsObject(PathCombine(instDir, "instance.cfg"));
m_settings->registerSetting("InstanceType", "Legacy"); m_settings->registerSetting("InstanceType", "Legacy");
@ -94,7 +98,7 @@ InstanceFactory::InstCreateError InstanceFactory::createInstance(InstancePtr &in
if (type == NormalInst) if (type == NormalInst)
{ {
m_settings->set("InstanceType", "OneSix"); m_settings->set("InstanceType", "OneSix");
inst.reset(new OneSixInstance(instDir, m_settings, this)); inst.reset(new OneSixInstance(instDir, m_settings));
inst->setIntendedVersionId(version->descriptor()); inst->setIntendedVersionId(version->descriptor());
inst->setShouldUseCustomBaseJar(false); inst->setShouldUseCustomBaseJar(false);
} }
@ -103,14 +107,14 @@ InstanceFactory::InstCreateError InstanceFactory::createInstance(InstancePtr &in
if(mcVer->usesLegacyLauncher()) if(mcVer->usesLegacyLauncher())
{ {
m_settings->set("InstanceType", "LegacyFTB"); m_settings->set("InstanceType", "LegacyFTB");
inst.reset(new LegacyFTBInstance(instDir, m_settings, this)); inst.reset(new LegacyFTBInstance(instDir, m_settings));
inst->setIntendedVersionId(version->descriptor()); inst->setIntendedVersionId(version->descriptor());
inst->setShouldUseCustomBaseJar(false); inst->setShouldUseCustomBaseJar(false);
} }
else else
{ {
m_settings->set("InstanceType", "OneSixFTB"); m_settings->set("InstanceType", "OneSixFTB");
inst.reset(new OneSixFTBInstance(instDir, m_settings, this)); inst.reset(new OneSixFTBInstance(instDir, m_settings));
inst->setIntendedVersionId(version->descriptor()); inst->setIntendedVersionId(version->descriptor());
inst->setShouldUseCustomBaseJar(false); inst->setShouldUseCustomBaseJar(false);
} }

View File

@ -26,7 +26,7 @@ struct BaseVersion;
class BaseInstance; class BaseInstance;
/*! /*!
* The \bInstanceFactory\b is a singleton that manages loading and creating instances. * The \b InstanceFactory\b is a singleton that manages loading and creating instances.
*/ */
class InstanceFactory : public QObject class InstanceFactory : public QObject
{ {

View File

@ -7,7 +7,7 @@ LegacyFTBInstance::LegacyFTBInstance(const QString &rootDir, SettingsObject *set
QString LegacyFTBInstance::getStatusbarDescription() QString LegacyFTBInstance::getStatusbarDescription()
{ {
if (flags().contains(VersionBrokenFlag)) if (flags() & VersionBrokenFlag)
{ {
return "Legacy FTB: " + intendedVersionId() + " (broken)"; return "Legacy FTB: " + intendedVersionId() + " (broken)";
} }

View File

@ -287,7 +287,7 @@ QString LegacyInstance::defaultCustomBaseJar() const
QString LegacyInstance::getStatusbarDescription() QString LegacyInstance::getStatusbarDescription()
{ {
if (flags().contains(VersionBrokenFlag)) if (flags() & VersionBrokenFlag)
{ {
return tr("Legacy : %1 (broken)").arg(intendedVersionId()); return tr("Legacy : %1 (broken)").arg(intendedVersionId());
} }

View File

@ -1,13 +1,26 @@
#include "MMCJson.h" #include "MMCJson.h"
#include <QString> #include <QString>
#include <QUrl>
#include <QStringList> #include <QStringList>
#include <math.h> #include <math.h>
QJsonDocument MMCJson::parseDocument(const QByteArray &data, const QString &what)
{
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(data, &error);
if (error.error != QJsonParseError::NoError)
{
throw JSONValidationError(what + " is not valid JSON: " + error.errorString() + " at " + error.offset);
}
return doc;
}
bool MMCJson::ensureBoolean(const QJsonValue val, const QString what) bool MMCJson::ensureBoolean(const QJsonValue val, const QString what)
{ {
if (!val.isBool()) if (!val.isBool())
throw JSONValidationError(what + " is not boolean"); throw JSONValidationError(what + " is not boolean");
return val.isBool(); return val.toBool();
} }
QJsonValue MMCJson::ensureExists(QJsonValue val, const QString what) QJsonValue MMCJson::ensureExists(QJsonValue val, const QString what)
@ -24,6 +37,15 @@ QJsonArray MMCJson::ensureArray(const QJsonValue val, const QString what)
return val.toArray(); return val.toArray();
} }
QJsonArray MMCJson::ensureArray(const QJsonDocument &val, const QString &what)
{
if (!val.isArray())
{
throw JSONValidationError(what + " is not an array");
}
return val.array();
}
double MMCJson::ensureDouble(const QJsonValue val, const QString what) double MMCJson::ensureDouble(const QJsonValue val, const QString what)
{ {
if (!val.isDouble()) if (!val.isDouble())
@ -60,9 +82,36 @@ QString MMCJson::ensureString(const QJsonValue val, const QString what)
return val.toString(); return val.toString();
} }
QUrl MMCJson::ensureUrl(const QJsonValue &val, const QString &what)
{
const QUrl url = QUrl(ensureString(val, what));
if (!url.isValid())
{
throw JSONValidationError(what + " is not an url");
}
return url;
}
QJsonDocument MMCJson::parseFile(const QString &filename, const QString &what)
{
QFile f(filename);
if (!f.open(QFile::ReadOnly))
{
throw FileOpenError(f);
}
return parseDocument(f.readAll(), what);
}
int MMCJson::ensureInteger(const QJsonValue val, QString what, const int def)
{
if (val.isUndefined())
return def;
return ensureInteger(val, what);
}
void MMCJson::writeString(QJsonObject &to, QString key, QString value) void MMCJson::writeString(QJsonObject &to, QString key, QString value)
{ {
if(value.size()) if (!value.isEmpty())
{ {
to.insert(key, value); to.insert(key, value);
} }
@ -70,7 +119,7 @@ void MMCJson::writeString(QJsonObject &to, QString key, QString value)
void MMCJson::writeStringList(QJsonObject &to, QString key, QStringList values) void MMCJson::writeStringList(QJsonObject &to, QString key, QStringList values)
{ {
if(values.size()) if (!values.isEmpty())
{ {
QJsonArray array; QJsonArray array;
for(auto value: values) for(auto value: values)
@ -81,3 +130,13 @@ void MMCJson::writeStringList(QJsonObject &to, QString key, QStringList values)
} }
} }
QStringList MMCJson::ensureStringList(const QJsonValue val, QString what)
{
const QJsonArray array = ensureArray(val, what);
QStringList out;
for (const auto value : array)
{
out.append(ensureString(value));
}
return out;
}

View File

@ -9,17 +9,29 @@
#include <QJsonObject> #include <QJsonObject>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonArray> #include <QJsonArray>
#include <QFile>
#include <memory>
#include "MMCError.h" #include "MMCError.h"
class JSONValidationError : public MMCError class JSONValidationError : public MMCError
{ {
public: public:
JSONValidationError(QString cause) : MMCError(cause) {}; JSONValidationError(QString cause) : MMCError(cause) {}
virtual ~JSONValidationError() noexcept {} };
class FileOpenError : public MMCError
{
public:
FileOpenError(const QFile &file) : MMCError(QObject::tr("Error opening %1: %2").arg(file.fileName(), file.errorString())) {}
}; };
namespace MMCJson namespace MMCJson
{ {
/// parses the data into a json document. throws if there's a parse error
QJsonDocument parseDocument(const QByteArray &data, const QString &what);
/// tries to open and then parses the specified file. throws if there's an error
QJsonDocument parseFile(const QString &filename, const QString &what);
/// make sure the value exists. throw otherwise. /// make sure the value exists. throw otherwise.
QJsonValue ensureExists(QJsonValue val, const QString what = "value"); QJsonValue ensureExists(QJsonValue val, const QString what = "value");
@ -27,39 +39,63 @@ QJsonValue ensureExists(QJsonValue val, const QString what = "value");
QJsonObject ensureObject(const QJsonValue val, const QString what = "value"); QJsonObject ensureObject(const QJsonValue val, const QString what = "value");
/// make sure the document is converted into an object. throw otherwise. /// make sure the document is converted into an object. throw otherwise.
QJsonObject ensureObject(const QJsonDocument val, const QString what = "value"); QJsonObject ensureObject(const QJsonDocument val, const QString what = "document");
/// make sure the value is converted into an array. throw otherwise. /// make sure the value is converted into an array. throw otherwise.
QJsonArray ensureArray(const QJsonValue val, QString what = "value"); QJsonArray ensureArray(const QJsonValue val, QString what = "value");
/// make sure the document is converted into an array. throw otherwise.
QJsonArray ensureArray(const QJsonDocument &val, const QString &what = "document");
/// make sure the value is converted into a string. throw otherwise. /// make sure the value is converted into a string. throw otherwise.
QString ensureString(const QJsonValue val, QString what = "value"); QString ensureString(const QJsonValue val, QString what = "value");
/// make sure the value is converted into a string that's parseable as an url. throw otherwise.
QUrl ensureUrl(const QJsonValue &val, const QString &what = "value");
/// make sure the value is converted into a boolean. throw otherwise. /// make sure the value is converted into a boolean. throw otherwise.
bool ensureBoolean(const QJsonValue val, QString what = "value"); bool ensureBoolean(const QJsonValue val, QString what = "value");
/// make sure the value is converted into an integer. throw otherwise. /// make sure the value is converted into an integer. throw otherwise.
int ensureInteger(const QJsonValue val, QString what = "value"); int ensureInteger(const QJsonValue val, QString what = "value");
/// make sure the value is converted into an integer. throw otherwise. this version will return the default value if the field is undefined.
int ensureInteger(const QJsonValue val, QString what, const int def);
/// make sure the value is converted into a double precision floating number. throw otherwise. /// make sure the value is converted into a double precision floating number. throw otherwise.
double ensureDouble(const QJsonValue val, QString what = "value"); double ensureDouble(const QJsonValue val, QString what = "value");
QStringList ensureStringList(const QJsonValue val, QString what);
void writeString(QJsonObject & to, QString key, QString value); void writeString(QJsonObject & to, QString key, QString value);
void writeStringList (QJsonObject & to, QString key, QStringList values); void writeStringList(QJsonObject & to, QString key, QStringList values);
template <typename T> template <typename T>
void writeObjectList (QJsonObject & to, QString key, QList<T> values) void writeObjectList(QJsonObject & to, QString key, QList<std::shared_ptr<T>> values)
{ {
if(values.size()) if (!values.isEmpty())
{ {
QJsonArray array; QJsonArray array;
for(auto value: values) for (auto value: values)
{ {
array.append(value->toJson()); array.append(value->toJson());
} }
to.insert(key, array); to.insert(key, array);
} }
} }
template <typename T>
void writeObjectList(QJsonObject & to, QString key, QList<T> values)
{
if (!values.isEmpty())
{
QJsonArray array;
for (auto value: values)
{
array.append(value.toJson());
}
to.insert(key, array);
}
}
} }

View File

@ -118,7 +118,7 @@ bool OneSixFTBInstance::providesVersionFile() const
QString OneSixFTBInstance::getStatusbarDescription() QString OneSixFTBInstance::getStatusbarDescription()
{ {
if (flags().contains(VersionBrokenFlag)) if (flags() & VersionBrokenFlag)
{ {
return "OneSix FTB: " + intendedVersionId() + " (broken)"; return "OneSix FTB: " + intendedVersionId() + " (broken)";
} }

View File

@ -418,7 +418,7 @@ void OneSixInstance::reloadVersion()
try try
{ {
d->version->reload(externalPatches()); d->version->reload(externalPatches());
d->m_flags.remove(VersionBrokenFlag); unsetFlag(VersionBrokenFlag);
emit versionReloaded(); emit versionReloaded();
} }
catch (VersionIncomplete &error) catch (VersionIncomplete &error)
@ -427,7 +427,7 @@ void OneSixInstance::reloadVersion()
catch (MMCError &error) catch (MMCError &error)
{ {
d->version->clear(); d->version->clear();
d->m_flags.insert(VersionBrokenFlag); setFlag(VersionBrokenFlag);
// TODO: rethrow to show some error message(s)? // TODO: rethrow to show some error message(s)?
emit versionReloaded(); emit versionReloaded();
throw; throw;
@ -464,7 +464,7 @@ QString OneSixInstance::getStatusbarDescription()
{ {
traits.append(tr("custom")); traits.append(tr("custom"));
} }
if (flags().contains(VersionBrokenFlag)) if (flags() & VersionBrokenFlag)
{ {
traits.append(tr("broken")); traits.append(tr("broken"));
} }
@ -569,3 +569,8 @@ QStringList OneSixInstance::extraArguments() const
} }
return list; return list;
} }
std::shared_ptr<OneSixInstance> OneSixInstance::getSharedPtr()
{
return std::dynamic_pointer_cast<OneSixInstance>(BaseInstance::getSharedPtr());
}

View File

@ -96,8 +96,11 @@ public:
virtual bool providesVersionFile() const; virtual bool providesVersionFile() const;
bool reload() override; bool reload() override;
virtual QStringList extraArguments() const override; virtual QStringList extraArguments() const override;
std::shared_ptr<OneSixInstance> getSharedPtr();
signals: signals:
void versionReloaded(); void versionReloaded();
@ -105,3 +108,5 @@ private:
QStringList processMinecraftArgs(AuthSessionPtr account); QStringList processMinecraftArgs(AuthSessionPtr account);
QDir reconstructAssets(std::shared_ptr<InstanceVersion> version); QDir reconstructAssets(std::shared_ptr<InstanceVersion> version);
}; };
Q_DECLARE_METATYPE(std::shared_ptr<OneSixInstance>)

View File

@ -29,11 +29,11 @@ class ForgeInstaller : public BaseInstaller
friend class ForgeInstallTask; friend class ForgeInstallTask;
public: public:
ForgeInstaller(); ForgeInstaller();
virtual ~ForgeInstaller(){}; virtual ~ForgeInstaller(){}
virtual ProgressProvider *createInstallTask(OneSixInstance *instance, BaseVersionPtr version, QObject *parent) override; virtual ProgressProvider *createInstallTask(OneSixInstance *instance, BaseVersionPtr version, QObject *parent) override;
virtual QString id() const override { return "net.minecraftforge"; }
protected: protected:
virtual QString id() const override { return "net.minecraftforge"; }
void prepare(const QString &filename, const QString &universalUrl); void prepare(const QString &filename, const QString &universalUrl);
bool add(OneSixInstance *to) override; bool add(OneSixInstance *to) override;
bool addLegacy(OneSixInstance *to); bool addLegacy(OneSixInstance *to);

View File

@ -38,3 +38,5 @@ struct ForgeVersion : public BaseVersion
QString installer_filename; QString installer_filename;
bool is_recommended = false; bool is_recommended = false;
}; };
Q_DECLARE_METATYPE(ForgeVersionPtr)

View File

@ -59,22 +59,10 @@ public:
{ {
return javacheckers.size(); return javacheckers.size();
} }
virtual void getProgress(qint64 &current, qint64 &total)
{
current = current_progress;
total = total_progress;
}
;
virtual QString getStatus() const
{
return m_job_name;
}
;
virtual bool isRunning() const virtual bool isRunning() const
{ {
return m_running; return m_running;
} }
;
signals: signals:
void started(); void started();

View File

@ -28,13 +28,10 @@ public:
void prepare(LiteLoaderVersionPtr version); void prepare(LiteLoaderVersionPtr version);
bool add(OneSixInstance *to) override; bool add(OneSixInstance *to) override;
virtual QString id() const override { return "com.mumfrey.liteloader"; }
ProgressProvider *createInstallTask(OneSixInstance *instance, BaseVersionPtr version, QObject *parent) override; ProgressProvider *createInstallTask(OneSixInstance *instance, BaseVersionPtr version, QObject *parent) override;
private: private:
virtual QString id() const override
{
return "com.mumfrey.liteloader";
}
LiteLoaderVersionPtr m_version; LiteLoaderVersionPtr m_version;
}; };

View File

@ -111,3 +111,5 @@ protected:
CacheDownloadPtr listDownload; CacheDownloadPtr listDownload;
LiteLoaderVersionList *m_list; LiteLoaderVersionList *m_list;
}; };
Q_DECLARE_METATYPE(LiteLoaderVersionPtr)

View File

@ -264,6 +264,14 @@ QList<std::shared_ptr<OneSixLibrary> > InstanceVersion::getActiveNormalLibs()
{ {
if (lib->isActive() && !lib->isNative()) if (lib->isActive() && !lib->isNative())
{ {
for (auto other : output)
{
if (other->rawName() == lib->rawName())
{
QLOG_WARN() << "Multiple libraries with name" << lib->rawName() << "in library list!";
continue;
}
}
output.append(lib); output.append(lib);
} }
} }

View File

@ -140,10 +140,10 @@ public:
QString appletClass; QString appletClass;
/// the list of libs - both active and inactive, native and java /// the list of libs - both active and inactive, native and java
QList<std::shared_ptr<OneSixLibrary>> libraries; QList<OneSixLibraryPtr> libraries;
/// same, but only vanilla. /// same, but only vanilla.
QList<std::shared_ptr<OneSixLibrary>> vanillaLibraries; QList<OneSixLibraryPtr> vanillaLibraries;
/// traits, collected from all the version files (version files can only add) /// traits, collected from all the version files (version files can only add)
QSet<QString> traits; QSet<QString> traits;

View File

@ -116,15 +116,10 @@ void MinecraftVersionList::loadBuiltinList()
{ {
QLOG_INFO() << "Loading builtin version list."; QLOG_INFO() << "Loading builtin version list.";
// grab the version list data from internal resources. // grab the version list data from internal resources.
QResource versionList(":/versions/minecraft.json"); const QJsonDocument doc =
QFile filez(versionList.absoluteFilePath()); MMCJson::parseFile(":/versions/minecraft.json",
filez.open(QIODevice::ReadOnly); "builtin version list");
auto data = filez.readAll(); const QJsonObject root = doc.object();
// parse the data as json
QJsonParseError jsonError;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
QJsonObject root = jsonDoc.object();
// parse all the versions // parse all the versions
for (const auto version : MMCJson::ensureArray(root.value("versions"))) for (const auto version : MMCJson::ensureArray(root.value("versions")))

View File

@ -48,5 +48,4 @@ public:
/// Constructor /// Constructor
OneSixLibrary(RawLibraryPtr base); OneSixLibrary(RawLibraryPtr base);
static OneSixLibraryPtr fromRawLibrary(RawLibraryPtr lib); static OneSixLibraryPtr fromRawLibrary(RawLibraryPtr lib);
}; };

View File

@ -288,6 +288,11 @@ static const int currentOrderFileVersion = 1;
bool VersionBuilder::readOverrideOrders(OneSixInstance *instance, PatchOrder &order) bool VersionBuilder::readOverrideOrders(OneSixInstance *instance, PatchOrder &order)
{ {
QFile orderFile(instance->instanceRoot() + "/order.json"); QFile orderFile(instance->instanceRoot() + "/order.json");
if (!orderFile.exists())
{
QLOG_WARN() << "Order file doesn't exist. Ignoring.";
return false;
}
if (!orderFile.open(QFile::ReadOnly)) if (!orderFile.open(QFile::ReadOnly))
{ {
QLOG_ERROR() << "Couldn't open" << orderFile.fileName() QLOG_ERROR() << "Couldn't open" << orderFile.fileName()

View File

@ -22,8 +22,7 @@ int findLibraryByName(QList<OneSixLibraryPtr> haystack, const GradleSpecifier &n
int retval = -1; int retval = -1;
for (int i = 0; i < haystack.size(); ++i) for (int i = 0; i < haystack.size(); ++i)
{ {
if (haystack.at(i)->rawName().matchName(needle))
if(haystack.at(i)->rawName().matchName(needle))
{ {
// only one is allowed. // only one is allowed.
if (retval != -1) if (retval != -1)
@ -67,7 +66,7 @@ VersionFilePtr VersionFile::fromJson(const QJsonDocument &doc, const QString &fi
out->mcVersion = root.value("mcVersion").toString(); out->mcVersion = root.value("mcVersion").toString();
out->filename = filename; out->filename = filename;
auto readString = [root](const QString & key, QString & variable) auto readString = [root](const QString &key, QString &variable)
{ {
if (root.contains(key)) if (root.contains(key))
{ {
@ -75,15 +74,14 @@ VersionFilePtr VersionFile::fromJson(const QJsonDocument &doc, const QString &fi
} }
}; };
auto readStringRet = [root](const QString & key)->QString auto readStringRet = [root](const QString &key) -> QString
{ {
if (root.contains(key)) if (root.contains(key))
{ {
return ensureString(root.value(key)); return ensureString(root.value(key));
} }
return QString(); return QString();
} };
;
// FIXME: This should be ignored when applying. // FIXME: This should be ignored when applying.
if (!isFTB) if (!isFTB)

View File

@ -53,16 +53,42 @@ void ByteArrayDownload::downloadError(QNetworkReply::NetworkError error)
QLOG_ERROR() << "Error getting URL:" << m_url.toString().toLocal8Bit() QLOG_ERROR() << "Error getting URL:" << m_url.toString().toLocal8Bit()
<< "Network error: " << error; << "Network error: " << error;
m_status = Job_Failed; m_status = Job_Failed;
m_errorString = m_reply->errorString();
} }
void ByteArrayDownload::downloadFinished() void ByteArrayDownload::downloadFinished()
{ {
if (m_followRedirects)
{
QVariant redirect = m_reply->header(QNetworkRequest::LocationHeader);
QString redirectURL;
if(redirect.isValid())
{
redirectURL = redirect.toString();
}
// FIXME: This is a hack for https://bugreports.qt-project.org/browse/QTBUG-41061
else if(m_reply->hasRawHeader("Location"))
{
auto data = m_reply->rawHeader("Location");
if(data.size() > 2 && data[0] == '/' && data[1] == '/')
redirectURL = m_reply->url().scheme() + ":" + data;
}
if (!redirectURL.isEmpty())
{
m_url = QUrl(redirect.toString());
QLOG_INFO() << "Following redirect to " << m_url.toString();
start();
return;
}
}
// if the download succeeded // if the download succeeded
if (m_status != Job_Failed) if (m_status != Job_Failed)
{ {
// nothing went wrong... // nothing went wrong...
m_status = Job_Finished; m_status = Job_Finished;
m_data = m_reply->readAll(); m_data = m_reply->readAll();
m_content_type = m_reply->header(QNetworkRequest::ContentTypeHeader).toString();
m_reply.reset(); m_reply.reset();
emit succeeded(m_index_within_job); emit succeeded(m_index_within_job);
return; return;

View File

@ -31,6 +31,10 @@ public:
/// if not saving to file, downloaded data is placed here /// if not saving to file, downloaded data is placed here
QByteArray m_data; QByteArray m_data;
QString m_errorString;
bool m_followRedirects = false;
public public
slots: slots:
virtual void start(); virtual void start();

View File

@ -101,6 +101,30 @@ void CacheDownload::downloadError(QNetworkReply::NetworkError error)
} }
void CacheDownload::downloadFinished() void CacheDownload::downloadFinished()
{ {
if (m_followRedirects)
{
QVariant redirect = m_reply->header(QNetworkRequest::LocationHeader);
QString redirectURL;
if(redirect.isValid())
{
redirectURL = redirect.toString();
}
// FIXME: This is a hack for https://bugreports.qt-project.org/browse/QTBUG-41061
else if(m_reply->hasRawHeader("Location"))
{
auto data = m_reply->rawHeader("Location");
if(data.size() > 2 && data[0] == '/' && data[1] == '/')
redirectURL = m_reply->url().scheme() + ":" + data;
}
if (!redirectURL.isEmpty())
{
m_url = QUrl(redirect.toString());
QLOG_INFO() << "Following redirect to " << m_url.toString();
start();
return;
}
}
// if the download succeeded // if the download succeeded
if (m_status == Job_Failed) if (m_status == Job_Failed)
{ {

View File

@ -36,6 +36,8 @@ private:
bool wroteAnyData = false; bool wroteAnyData = false;
public: public:
bool m_followRedirects = false;
explicit CacheDownload(QUrl url, MetaEntryPtr entry); explicit CacheDownload(QUrl url, MetaEntryPtr entry);
static CacheDownloadPtr make(QUrl url, MetaEntryPtr entry) static CacheDownloadPtr make(QUrl url, MetaEntryPtr entry)
{ {

View File

@ -55,6 +55,9 @@ public:
/// the network reply /// the network reply
std::shared_ptr<QNetworkReply> m_reply; std::shared_ptr<QNetworkReply> m_reply;
/// the content of the content-type header
QString m_content_type;
/// source URL /// source URL
QUrl m_url; QUrl m_url;

View File

@ -30,8 +30,8 @@ class NetJob : public ProgressProvider
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit NetJob(QString job_name) : ProgressProvider(), m_job_name(job_name) {}; explicit NetJob(QString job_name) : ProgressProvider(), m_job_name(job_name) {}
virtual ~NetJob() {}; virtual ~NetJob() {}
template <typename T> bool addNetAction(T action) template <typename T> bool addNetAction(T action)
{ {
NetActionPtr base = std::static_pointer_cast<NetAction>(action); NetActionPtr base = std::static_pointer_cast<NetAction>(action);
@ -62,7 +62,10 @@ public:
{ {
return downloads[index]; return downloads[index];
} }
; const NetActionPtr at(const int index)
{
return downloads.at(index);
}
NetActionPtr first() NetActionPtr first()
{ {
if (downloads.size()) if (downloads.size())
@ -73,21 +76,10 @@ public:
{ {
return downloads.size(); return downloads.size();
} }
virtual void getProgress(qint64 &current, qint64 &total)
{
current = current_progress;
total = total_progress;
}
;
virtual QString getStatus() const
{
return m_job_name;
}
virtual bool isRunning() const virtual bool isRunning() const
{ {
return m_running; return m_running;
} }
;
QStringList getFailedFiles(); QStringList getFailedFiles();
signals: signals:
void started(); void started();

View File

@ -32,9 +32,7 @@ signals:
void status(QString status); void status(QString status);
public: public:
virtual ~ProgressProvider() {}; virtual ~ProgressProvider() {}
virtual QString getStatus() const = 0;
virtual void getProgress(qint64 &current, qint64 &total) = 0;
virtual bool isRunning() const = 0; virtual bool isRunning() const = 0;
public public
slots: slots:

View File

@ -1,31 +1,7 @@
#include "SequentialTask.h" #include "SequentialTask.h"
SequentialTask::SequentialTask(QObject *parent) : SequentialTask::SequentialTask(QObject *parent) : Task(parent), m_currentIndex(-1)
Task(parent), m_currentIndex(-1)
{ {
}
QString SequentialTask::getStatus() const
{
if (m_queue.isEmpty() || m_currentIndex >= m_queue.size())
{
return QString();
}
return m_queue.at(m_currentIndex)->getStatus();
}
void SequentialTask::getProgress(qint64 &current, qint64 &total)
{
current = 0;
total = 0;
for (int i = 0; i < m_queue.size(); ++i)
{
qint64 subCurrent, subTotal;
m_queue.at(i)->getProgress(subCurrent, subTotal);
current += subCurrent;
total += subTotal;
}
} }
void SequentialTask::addTask(std::shared_ptr<ProgressProvider> task) void SequentialTask::addTask(std::shared_ptr<ProgressProvider> task)
@ -55,10 +31,9 @@ void SequentialTask::startNext()
std::shared_ptr<ProgressProvider> next = m_queue[m_currentIndex]; std::shared_ptr<ProgressProvider> next = m_queue[m_currentIndex];
connect(next.get(), SIGNAL(failed(QString)), this, SLOT(subTaskFailed(QString))); connect(next.get(), SIGNAL(failed(QString)), this, SLOT(subTaskFailed(QString)));
connect(next.get(), SIGNAL(status(QString)), this, SLOT(subTaskStatus(QString))); connect(next.get(), SIGNAL(status(QString)), this, SLOT(subTaskStatus(QString)));
connect(next.get(), SIGNAL(progress(qint64,qint64)), this, SLOT(subTaskProgress())); connect(next.get(), SIGNAL(progress(qint64, qint64)), this, SLOT(subTaskProgress(qint64, qint64)));
connect(next.get(), SIGNAL(succeeded()), this, SLOT(startNext())); connect(next.get(), SIGNAL(succeeded()), this, SLOT(startNext()));
next->start(); next->start();
emit status(getStatus());
} }
void SequentialTask::subTaskFailed(const QString &msg) void SequentialTask::subTaskFailed(const QString &msg)
@ -69,16 +44,16 @@ void SequentialTask::subTaskStatus(const QString &msg)
{ {
setStatus(msg); setStatus(msg);
} }
void SequentialTask::subTaskProgress() void SequentialTask::subTaskProgress(qint64 current, qint64 total)
{ {
qint64 current, total; if(total == 0)
getProgress(current, total);
if (total == 0)
{ {
setProgress(0); setProgress(0);
return;
} }
else auto dcurrent = (double) current;
{ auto dtotal = (double) total;
setProgress(100 * current / total); auto partial = ((dcurrent / dtotal) * 100.0f)/* / double(m_queue.size())*/;
} // auto bigpartial = double(m_currentIndex) * 100.0f / double(m_queue.size());
setProgress(partial);
} }

View File

@ -11,9 +11,6 @@ class SequentialTask : public Task
public: public:
explicit SequentialTask(QObject *parent = 0); explicit SequentialTask(QObject *parent = 0);
virtual QString getStatus() const;
virtual void getProgress(qint64 &current, qint64 &total);
void addTask(std::shared_ptr<ProgressProvider> task); void addTask(std::shared_ptr<ProgressProvider> task);
protected: protected:
@ -24,7 +21,7 @@ slots:
void startNext(); void startNext();
void subTaskFailed(const QString &msg); void subTaskFailed(const QString &msg);
void subTaskStatus(const QString &msg); void subTaskStatus(const QString &msg);
void subTaskProgress(); void subTaskProgress(qint64 current, qint64 total);
private: private:
QQueue<std::shared_ptr<ProgressProvider> > m_queue; QQueue<std::shared_ptr<ProgressProvider> > m_queue;

View File

@ -20,29 +20,16 @@ Task::Task(QObject *parent) : ProgressProvider(parent)
{ {
} }
QString Task::getStatus() const
{
return m_statusString;
}
void Task::setStatus(const QString &new_status) void Task::setStatus(const QString &new_status)
{ {
m_statusString = new_status;
emit status(new_status); emit status(new_status);
} }
void Task::setProgress(int new_progress) void Task::setProgress(int new_progress)
{ {
m_progress = new_progress;
emit progress(new_progress, 100); emit progress(new_progress, 100);
} }
void Task::getProgress(qint64 &current, qint64 &total)
{
current = m_progress;
total = 100;
}
void Task::start() void Task::start()
{ {
m_running = true; m_running = true;
@ -61,6 +48,7 @@ void Task::emitFailed(QString reason)
void Task::emitSucceeded() void Task::emitSucceeded()
{ {
if (!m_running) { return; } // Don't succeed twice.
m_running = false; m_running = false;
m_succeeded = true; m_succeeded = true;
QLOG_INFO() << "Task succeeded"; QLOG_INFO() << "Task succeeded";

View File

@ -26,8 +26,6 @@ public:
explicit Task(QObject *parent = 0); explicit Task(QObject *parent = 0);
virtual ~Task() {}; virtual ~Task() {};
virtual QString getStatus() const;
virtual void getProgress(qint64 &current, qint64 &total);
virtual bool isRunning() const; virtual bool isRunning() const;
/*! /*!
@ -50,6 +48,7 @@ slots:
protected: protected:
virtual void executeTask() = 0; virtual void executeTask() = 0;
protected slots:
virtual void emitSucceeded(); virtual void emitSucceeded();
virtual void emitFailed(QString reason); virtual void emitFailed(QString reason);
@ -59,9 +58,8 @@ slots:
void setProgress(int progress); void setProgress(int progress);
protected: protected:
QString m_statusString;
int m_progress = 0;
bool m_running = false; bool m_running = false;
bool m_succeeded = false; bool m_succeeded = false;
QString m_failReason = ""; QString m_failReason = "";
}; };

View File

@ -43,7 +43,7 @@ public:
virtual QString name() const = 0; virtual QString name() const = 0;
virtual void registerSettings(SettingsObject *settings) = 0; virtual void registerSettings(std::shared_ptr<SettingsObject> settings) = 0;
virtual BaseExternalTool *createTool(InstancePtr instance, QObject *parent = 0) = 0; virtual BaseExternalTool *createTool(InstancePtr instance, QObject *parent = 0) = 0;

View File

@ -40,7 +40,7 @@ void JProfiler::beginProfilingImpl(MinecraftProcess *process)
m_profilerProcess = profiler; m_profilerProcess = profiler;
} }
void JProfilerFactory::registerSettings(SettingsObject *settings) void JProfilerFactory::registerSettings(std::shared_ptr<SettingsObject> settings)
{ {
settings->registerSetting("JProfilerPath"); settings->registerSetting("JProfilerPath");
settings->registerSetting("JProfilerPort", 42042); settings->registerSetting("JProfilerPort", 42042);

View File

@ -16,7 +16,7 @@ class JProfilerFactory : public BaseProfilerFactory
{ {
public: public:
QString name() const override { return "JProfiler"; } QString name() const override { return "JProfiler"; }
void registerSettings(SettingsObject *settings) override; void registerSettings(std::shared_ptr<SettingsObject> settings) override;
BaseExternalTool *createTool(InstancePtr instance, QObject *parent = 0) override; BaseExternalTool *createTool(InstancePtr instance, QObject *parent = 0) override;
bool check(QString *error) override; bool check(QString *error) override;
bool check(const QString &path, QString *error) override; bool check(const QString &path, QString *error) override;

View File

@ -37,7 +37,7 @@ void JVisualVM::beginProfilingImpl(MinecraftProcess *process)
m_profilerProcess = profiler; m_profilerProcess = profiler;
} }
void JVisualVMFactory::registerSettings(SettingsObject *settings) void JVisualVMFactory::registerSettings(std::shared_ptr<SettingsObject> settings)
{ {
QString defaultValue = QStandardPaths::findExecutable("jvisualvm"); QString defaultValue = QStandardPaths::findExecutable("jvisualvm");
if (defaultValue.isNull()) if (defaultValue.isNull())

View File

@ -16,7 +16,7 @@ class JVisualVMFactory : public BaseProfilerFactory
{ {
public: public:
QString name() const override { return "JVisualVM"; } QString name() const override { return "JVisualVM"; }
void registerSettings(SettingsObject *settings) override; void registerSettings(std::shared_ptr<SettingsObject> settings) override;
BaseExternalTool *createTool(InstancePtr instance, QObject *parent = 0) override; BaseExternalTool *createTool(InstancePtr instance, QObject *parent = 0) override;
bool check(QString *error) override; bool check(QString *error) override;
bool check(const QString &path, QString *error) override; bool check(const QString &path, QString *error) override;

View File

@ -43,7 +43,7 @@ void MCEditTool::runImpl()
#endif #endif
} }
void MCEditFactory::registerSettings(SettingsObject *settings) void MCEditFactory::registerSettings(std::shared_ptr<SettingsObject> settings)
{ {
settings->registerSetting("MCEditPath"); settings->registerSetting("MCEditPath");
} }

View File

@ -16,7 +16,7 @@ class MCEditFactory : public BaseDetachedToolFactory
{ {
public: public:
QString name() const override { return "MCEdit"; } QString name() const override { return "MCEdit"; }
void registerSettings(SettingsObject *settings) override; void registerSettings(std::shared_ptr<SettingsObject> settings) override;
BaseExternalTool *createTool(InstancePtr instance, QObject *parent = 0) override; BaseExternalTool *createTool(InstancePtr instance, QObject *parent = 0) override;
bool check(QString *error) override; bool check(QString *error) override;
bool check(const QString &path, QString *error) override; bool check(const QString &path, QString *error) override;

View File

@ -38,6 +38,9 @@
<file>herobrine.png</file> <file>herobrine.png</file>
<file>derp.png</file> <file>derp.png</file>
<!-- Update. GPLv2, https://code.google.com/p/gnome-colors/ -->
<file>updateavailable.png</file>
<!-- Source: http://www.iconarchive.com/show/cat-icons-by-fasticon/Cat-Brown-icon.html --> <!-- Source: http://www.iconarchive.com/show/cat-icons-by-fasticon/Cat-Brown-icon.html -->
<file>kitten.png</file> <file>kitten.png</file>
<!-- Source: http://www.iconarchive.com/show/crystal-clear-icons-by-everaldo/Filesystem-file-broken-icon.html --> <!-- Source: http://www.iconarchive.com/show/crystal-clear-icons-by-everaldo/Filesystem-file-broken-icon.html -->

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -24,6 +24,7 @@ endmacro()
add_unit_test(pathutils tst_pathutils.cpp) add_unit_test(pathutils tst_pathutils.cpp)
add_unit_test(gradlespecifier tst_gradlespecifier.cpp) add_unit_test(gradlespecifier tst_gradlespecifier.cpp)
add_unit_test(userutils tst_userutils.cpp) add_unit_test(userutils tst_userutils.cpp)
add_unit_test(modutils tst_modutils.cpp)
add_unit_test(inifile tst_inifile.cpp) add_unit_test(inifile tst_inifile.cpp)
add_unit_test(UpdateChecker tst_UpdateChecker.cpp) add_unit_test(UpdateChecker tst_UpdateChecker.cpp)
add_unit_test(DownloadUpdateTask tst_DownloadUpdateTask.cpp) add_unit_test(DownloadUpdateTask tst_DownloadUpdateTask.cpp)

View File

@ -9,29 +9,30 @@
#include "test_config.h" #include "test_config.h"
struct TestsInternal class TestsInternal
{ {
static QByteArray readFile(const QString &fileName) public:
{ static QByteArray readFile(const QString &fileName)
QFile f(fileName); {
f.open(QFile::ReadOnly); QFile f(fileName);
return f.readAll(); f.open(QFile::ReadOnly);
} return f.readAll();
static QString readFileUtf8(const QString &fileName) }
{ static QString readFileUtf8(const QString &fileName)
return QString::fromUtf8(readFile(fileName)); {
} return QString::fromUtf8(readFile(fileName));
}
}; };
#define MULTIMC_GET_TEST_FILE(file) TestsInternal::readFile(QFINDTESTDATA( file )) #define MULTIMC_GET_TEST_FILE(file) TestsInternal::readFile(QFINDTESTDATA(file))
#define MULTIMC_GET_TEST_FILE_UTF8(file) TestsInternal::readFileUtf8(QFINDTESTDATA( file )) #define MULTIMC_GET_TEST_FILE_UTF8(file) TestsInternal::readFileUtf8(QFINDTESTDATA(file))
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
# define _MMC_EXTRA_ARGV , "-platform", "offscreen" #define _MMC_EXTRA_ARGV , "-platform", "offscreen"
# define _MMC_EXTRA_ARGC 2 #define _MMC_EXTRA_ARGC 2
#else #else
# define _MMC_EXTRA_ARGV #define _MMC_EXTRA_ARGV
# define _MMC_EXTRA_ARGC 0 #define _MMC_EXTRA_ARGC 0
#endif #endif

153
tests/tst_modutils.cpp Normal file
View File

@ -0,0 +1,153 @@
/* Copyright 2013 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <QTest>
#include "modutils.h"
#include "TestUtil.h"
class ModUtilsTest : public QObject
{
Q_OBJECT
void setupVersions()
{
QTest::addColumn<QString>("first");
QTest::addColumn<QString>("second");
QTest::addColumn<bool>("lessThan");
QTest::addColumn<bool>("equal");
QTest::newRow("equal, explicit") << "1.2.0" << "1.2.0" << false << true;
QTest::newRow("equal, implicit 1") << "1.2" << "1.2.0" << false << true;
QTest::newRow("equal, implicit 2") << "1.2.0" << "1.2" << false << true;
QTest::newRow("equal, two-digit") << "1.42" << "1.42" << false << true;
QTest::newRow("lessThan, explicit 1") << "1.2.0" << "1.2.1" << true << false;
QTest::newRow("lessThan, explicit 2") << "1.2.0" << "1.3.0" << true << false;
QTest::newRow("lessThan, explicit 3") << "1.2.0" << "2.2.0" << true << false;
QTest::newRow("lessThan, implicit 1") << "1.2" << "1.2.1" << true << false;
QTest::newRow("lessThan, implicit 2") << "1.2" << "1.3.0" << true << false;
QTest::newRow("lessThan, implicit 3") << "1.2" << "2.2.0" << true << false;
QTest::newRow("lessThan, two-digit") << "1.41" << "1.42" << true << false;
QTest::newRow("greaterThan, explicit 1") << "1.2.1" << "1.2.0" << false << false;
QTest::newRow("greaterThan, explicit 2") << "1.3.0" << "1.2.0" << false << false;
QTest::newRow("greaterThan, explicit 3") << "2.2.0" << "1.2.0" << false << false;
QTest::newRow("greaterThan, implicit 1") << "1.2.1" << "1.2" << false << false;
QTest::newRow("greaterThan, implicit 2") << "1.3.0" << "1.2" << false << false;
QTest::newRow("greaterThan, implicit 3") << "2.2.0" << "1.2" << false << false;
QTest::newRow("greaterThan, two-digit") << "1.42" << "1.41" << false << false;
}
private slots:
void initTestCase()
{
}
void cleanupTestCase()
{
}
void test_versionIsInInterval_data()
{
QTest::addColumn<QString>("version");
QTest::addColumn<QString>("interval");
QTest::addColumn<bool>("result");
QTest::newRow("empty, true") << "1.2.3" << "" << true;
QTest::newRow("one version, true") << "1.2.3" << "1.2.3" << true;
QTest::newRow("one version, false") << "1.2.3" << "1.2.2" << false;
QTest::newRow("one version inclusive <-> infinity, true") << "1.2.3" << "[1.2.3,)" << true;
QTest::newRow("one version exclusive <-> infinity, true") << "1.2.3" << "(1.2.2,)" << true;
QTest::newRow("one version inclusive <-> infitity, false") << "1.2.3" << "[1.2.4,)" << false;
QTest::newRow("one version exclusive <-> infinity, false") << "1.2.3" << "(1.2.3,)" << false;
QTest::newRow("infinity <-> one version inclusive, true") << "1.2.3" << "(,1.2.3]" << true;
QTest::newRow("infinity <-> one version exclusive, true") << "1.2.3" << "(,1.2.4)" << true;
QTest::newRow("infinity <-> one version inclusive, false") << "1.2.3" << "(,1.2.2]" << false;
QTest::newRow("infinity <-> one version exclusive, false") << "1.2.3" << "(,1.2.3)" << false;
QTest::newRow("inclusive <-> inclusive, true") << "1.2.3" << "[1.2.2,1.2.3]" << true;
QTest::newRow("inclusive <-> exclusive, true") << "1.2.3" << "[1.2.3,1.2.4)" << true;
QTest::newRow("exclusive <-> inclusive, true") << "1.2.3" << "(1.2.2,1.2.3]" << true;
QTest::newRow("exclusive <-> exclusive, true") << "1.2.3" << "(1.2.2,1.2.4)" << true;
QTest::newRow("inclusive <-> inclusive, false") << "1.2.3" << "[1.0.0,1.2.2]" << false;
QTest::newRow("inclusive <-> exclusive, false") << "1.2.3" << "[1.0.0,1.2.3)" << false;
QTest::newRow("exclusive <-> inclusive, false") << "1.2.3" << "(1.2.3,2.0.0]" << false;
QTest::newRow("exclusive <-> exclusive, false") << "1.2.3" << "(1.0.0,1.2.3)" << false;
}
void test_versionIsInInterval()
{
QFETCH(QString, version);
QFETCH(QString, interval);
QFETCH(bool, result);
QCOMPARE(Util::versionIsInInterval(version, interval), result);
}
void test_versionCompareLessThan_data()
{
setupVersions();
}
void test_versionCompareLessThan()
{
QFETCH(QString, first);
QFETCH(QString, second);
QFETCH(bool, lessThan);
QFETCH(bool, equal);
const auto v1 = Util::Version(first);
const auto v2 = Util::Version(second);
QCOMPARE(v1 < v2, lessThan);
}
void test_versionCompareGreaterThan_data()
{
setupVersions();
}
void test_versionCompareGreaterThan()
{
QFETCH(QString, first);
QFETCH(QString, second);
QFETCH(bool, lessThan);
QFETCH(bool, equal);
const auto v1 = Util::Version(first);
const auto v2 = Util::Version(second);
QCOMPARE(v1 > v2, !lessThan && !equal);
}
void test_versionCompareEqual_data()
{
setupVersions();
}
void test_versionCompareEqual()
{
QFETCH(QString, first);
QFETCH(QString, second);
QFETCH(bool, lessThan);
QFETCH(bool, equal);
const auto v1 = Util::Version(first);
const auto v2 = Util::Version(second);
QCOMPARE(v1 == v2, equal);
}
};
QTEST_GUILESS_MAIN(ModUtilsTest)
#include "tst_modutils.moc"