GH-952 Hardcore version page tweakery

Version patches get a lot of new flags that determine which actions are allowed
Version page respects the flags
Customize, revert and edit for version patches
Builting patches can be customized
This commit is contained in:
Petr Mrázek 2015-05-17 23:38:28 +02:00
parent 6ab6a450f6
commit 743af4769e
15 changed files with 553 additions and 156 deletions

View File

@ -67,16 +67,14 @@ VersionPage::VersionPage(OneSixInstance *inst, QWidget *parent)
m_version = m_inst->getMinecraftProfile(); m_version = m_inst->getMinecraftProfile();
if (m_version) if (m_version)
{ {
ui->libraryTreeView->setModel(m_version.get()); ui->packageView->setModel(m_version.get());
ui->libraryTreeView->installEventFilter(this); ui->packageView->installEventFilter(this);
ui->libraryTreeView->setSelectionMode(QAbstractItemView::SingleSelection); ui->packageView->setSelectionMode(QAbstractItemView::SingleSelection);
connect(ui->libraryTreeView->selectionModel(), &QItemSelectionModel::currentChanged, connect(ui->packageView->selectionModel(), &QItemSelectionModel::currentChanged,
this, &VersionPage::versionCurrent); this, &VersionPage::versionCurrent);
updateVersionControls(); updateVersionControls();
// select first item. // select first item.
auto index = ui->libraryTreeView->model()->index(0,0); preselect(0);
if(index.isValid())
ui->libraryTreeView->setCurrentIndex(index);
} }
else else
{ {
@ -95,14 +93,15 @@ void VersionPage::updateVersionControls()
{ {
ui->forgeBtn->setEnabled(true); ui->forgeBtn->setEnabled(true);
ui->liteloaderBtn->setEnabled(true); ui->liteloaderBtn->setEnabled(true);
updateButtons();
} }
void VersionPage::disableVersionControls() void VersionPage::disableVersionControls()
{ {
ui->forgeBtn->setEnabled(false); ui->forgeBtn->setEnabled(false);
ui->liteloaderBtn->setEnabled(false); ui->liteloaderBtn->setEnabled(false);
ui->reloadLibrariesBtn->setEnabled(false); ui->reloadBtn->setEnabled(false);
ui->removeLibraryBtn->setEnabled(false); updateButtons();
} }
bool VersionPage::reloadMinecraftProfile() bool VersionPage::reloadMinecraftProfile()
@ -126,21 +125,22 @@ bool VersionPage::reloadMinecraftProfile()
} }
} }
void VersionPage::on_reloadLibrariesBtn_clicked() void VersionPage::on_reloadBtn_clicked()
{ {
reloadMinecraftProfile(); reloadMinecraftProfile();
} }
void VersionPage::on_removeLibraryBtn_clicked() void VersionPage::on_removeBtn_clicked()
{ {
if (ui->libraryTreeView->currentIndex().isValid()) if (ui->packageView->currentIndex().isValid())
{ {
// FIXME: use actual model, not reloading. // FIXME: use actual model, not reloading.
if (!m_version->remove(ui->libraryTreeView->currentIndex().row())) if (!m_version->remove(ui->packageView->currentIndex().row()))
{ {
QMessageBox::critical(this, tr("Error"), tr("Couldn't remove file")); QMessageBox::critical(this, tr("Error"), tr("Couldn't remove file"));
} }
} }
updateButtons();
} }
void VersionPage::on_jarmodBtn_clicked() void VersionPage::on_jarmodBtn_clicked()
@ -150,9 +150,10 @@ void VersionPage::on_jarmodBtn_clicked()
{ {
m_version->installJarMods(list); m_version->installJarMods(list);
} }
updateButtons();
} }
void VersionPage::on_resetLibraryOrderBtn_clicked() void VersionPage::on_resetOrderBtn_clicked()
{ {
try try
{ {
@ -162,43 +163,36 @@ void VersionPage::on_resetLibraryOrderBtn_clicked()
{ {
QMessageBox::critical(this, tr("Error"), e.cause()); QMessageBox::critical(this, tr("Error"), e.cause());
} }
updateButtons();
} }
void VersionPage::on_moveLibraryUpBtn_clicked() void VersionPage::on_moveUpBtn_clicked()
{ {
if (ui->libraryTreeView->selectionModel()->selectedRows().isEmpty())
{
return;
}
try try
{ {
const int row = ui->libraryTreeView->selectionModel()->selectedRows().first().row(); m_version->move(currentRow(), MinecraftProfile::MoveUp);
m_version->move(row, MinecraftProfile::MoveUp);
} }
catch (MMCError &e) catch (MMCError &e)
{ {
QMessageBox::critical(this, tr("Error"), e.cause()); QMessageBox::critical(this, tr("Error"), e.cause());
} }
updateButtons();
} }
void VersionPage::on_moveLibraryDownBtn_clicked() void VersionPage::on_moveDownBtn_clicked()
{ {
if (ui->libraryTreeView->selectionModel()->selectedRows().isEmpty())
{
return;
}
try try
{ {
const int row = ui->libraryTreeView->selectionModel()->selectedRows().first().row(); m_version->move(currentRow(), MinecraftProfile::MoveDown);
m_version->move(row, MinecraftProfile::MoveDown);
} }
catch (MMCError &e) catch (MMCError &e)
{ {
QMessageBox::critical(this, tr("Error"), e.cause()); QMessageBox::critical(this, tr("Error"), e.cause());
} }
updateButtons();
} }
void VersionPage::on_changeMCVersionBtn_clicked() void VersionPage::on_changeVersionBtn_clicked()
{ {
VersionSelectDialog vselect(m_inst->versionList().get(), tr("Change Minecraft version"), VersionSelectDialog vselect(m_inst->versionList().get(), tr("Change Minecraft version"),
this); this);
@ -239,6 +233,7 @@ void VersionPage::on_changeMCVersionBtn_clicked()
ProgressDialog tDialog(this); ProgressDialog tDialog(this);
connect(updateTask.get(), SIGNAL(failed(QString)), SLOT(onGameUpdateError(QString))); connect(updateTask.get(), SIGNAL(failed(QString)), SLOT(onGameUpdateError(QString)));
tDialog.exec(updateTask.get()); tDialog.exec(updateTask.get());
updateButtons();
} }
void VersionPage::on_forgeBtn_clicked() void VersionPage::on_forgeBtn_clicked()
@ -253,6 +248,7 @@ void VersionPage::on_forgeBtn_clicked()
ProgressDialog dialog(this); ProgressDialog dialog(this);
dialog.exec( dialog.exec(
ForgeInstaller().createInstallTask(m_inst, vselect.selectedVersion(), this)); ForgeInstaller().createInstallTask(m_inst, vselect.selectedVersion(), this));
preselect(m_version->rowCount(QModelIndex())-1);
} }
} }
@ -269,32 +265,59 @@ void VersionPage::on_liteloaderBtn_clicked()
ProgressDialog dialog(this); ProgressDialog dialog(this);
dialog.exec( dialog.exec(
LiteLoaderInstaller().createInstallTask(m_inst, vselect.selectedVersion(), this)); LiteLoaderInstaller().createInstallTask(m_inst, vselect.selectedVersion(), this));
preselect(m_version->rowCount(QModelIndex())-1);
} }
} }
void VersionPage::versionCurrent(const QModelIndex &current, const QModelIndex &previous) void VersionPage::versionCurrent(const QModelIndex &current, const QModelIndex &previous)
{ {
if (!current.isValid()) currentIdx = current.row();
updateButtons(currentIdx);
}
void VersionPage::preselect(int row)
{
if(row < 0)
{ {
ui->removeLibraryBtn->setDisabled(true); row = 0;
ui->moveLibraryDownBtn->setDisabled(true); }
ui->moveLibraryUpBtn->setDisabled(true); if(row >= m_version->rowCount(QModelIndex()))
{
row = m_version->rowCount(QModelIndex()) - 1;
}
if(row < 0)
{
return;
}
auto model_index = m_version->index(row);
ui->packageView->selectionModel()->select(model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
updateButtons(row);
}
void VersionPage::updateButtons(int row)
{
if(row == -1)
row = currentRow();
auto patch = m_version->versionPatch(row);
if (!patch)
{
ui->removeBtn->setDisabled(true);
ui->moveDownBtn->setDisabled(true);
ui->moveUpBtn->setDisabled(true);
ui->changeVersionBtn->setDisabled(true);
ui->editBtn->setDisabled(true);
ui->customizeBtn->setDisabled(true);
ui->revertBtn->setDisabled(true);
} }
else else
{ {
bool enabled = m_version->canRemove(current.row()); ui->removeBtn->setEnabled(patch->isRemovable());
ui->removeLibraryBtn->setEnabled(enabled); ui->moveDownBtn->setEnabled(patch->isMoveable());
ui->moveLibraryDownBtn->setEnabled(enabled); ui->moveUpBtn->setEnabled(patch->isMoveable());
ui->moveLibraryUpBtn->setEnabled(enabled); ui->changeVersionBtn->setEnabled(patch->isVersionChangeable());
} ui->editBtn->setEnabled(patch->isEditable());
QString selectedId = m_version->versionFileId(current.row()); ui->customizeBtn->setEnabled(patch->isCustomizable());
if (selectedId == "net.minecraft") ui->revertBtn->setEnabled(patch->isRevertible());
{
ui->changeMCVersionBtn->setEnabled(true);
}
else
{
ui->changeMCVersionBtn->setEnabled(false);
} }
} }
@ -303,3 +326,68 @@ void VersionPage::onGameUpdateError(QString error)
CustomMessageBox::selectable(this, tr("Error updating instance"), error, CustomMessageBox::selectable(this, tr("Error updating instance"), error,
QMessageBox::Warning)->show(); QMessageBox::Warning)->show();
} }
ProfilePatchPtr VersionPage::current()
{
auto row = currentRow();
if(row < 0)
{
return nullptr;
}
return m_version->versionPatch(row);
}
int VersionPage::currentRow()
{
if (ui->packageView->selectionModel()->selectedRows().isEmpty())
{
return -1;
}
return ui->packageView->selectionModel()->selectedRows().first().row();
}
void VersionPage::on_customizeBtn_clicked()
{
auto version = currentRow();
if(version == -1)
{
return;
}
if(!m_version->customize(version))
{
// TODO: some error box here
}
updateButtons();
preselect(currentIdx);
}
void VersionPage::on_editBtn_clicked()
{
auto version = current();
if(!version)
{
return;
}
auto filename = version->getPatchFilename();
if(!QFileInfo::exists(filename))
{
qWarning() << "file" << filename << "can't be opened for editing, doesn't exist!";
return;
}
MMC->openJsonEditor(filename);
}
void VersionPage::on_revertBtn_clicked()
{
auto version = currentRow();
if(version == -1)
{
return;
}
if(!m_version->revert(version))
{
// TODO: some error box here
}
updateButtons();
preselect(currentIdx);
}

View File

@ -46,22 +46,29 @@ public:
return "Instance-version"; return "Instance-version";
} }
virtual bool shouldDisplay() const; virtual bool shouldDisplay() const;
private
slots:
// version tab private slots:
void on_forgeBtn_clicked(); void on_forgeBtn_clicked();
void on_liteloaderBtn_clicked(); void on_liteloaderBtn_clicked();
void on_reloadLibrariesBtn_clicked(); void on_reloadBtn_clicked();
void on_removeLibraryBtn_clicked(); void on_removeBtn_clicked();
void on_resetLibraryOrderBtn_clicked(); void on_resetOrderBtn_clicked();
void on_moveLibraryUpBtn_clicked(); void on_moveUpBtn_clicked();
void on_moveLibraryDownBtn_clicked(); void on_moveDownBtn_clicked();
void on_jarmodBtn_clicked(); void on_jarmodBtn_clicked();
void on_revertBtn_clicked();
void on_editBtn_clicked();
void on_customizeBtn_clicked();
void updateVersionControls(); void updateVersionControls();
void disableVersionControls(); void disableVersionControls();
void on_changeMCVersionBtn_clicked(); void on_changeVersionBtn_clicked();
private:
ProfilePatchPtr current();
int currentRow();
void updateButtons(int row = -1);
void preselect(int row = 0);
protected: protected:
/// FIXME: this shouldn't be necessary! /// FIXME: this shouldn't be necessary!
@ -71,9 +78,9 @@ private:
Ui::VersionPage *ui; Ui::VersionPage *ui;
std::shared_ptr<MinecraftProfile> m_version; std::shared_ptr<MinecraftProfile> m_version;
OneSixInstance *m_inst; OneSixInstance *m_inst;
int currentIdx = 0;
public public slots:
slots:
void versionCurrent(const QModelIndex &current, const QModelIndex &previous); void versionCurrent(const QModelIndex &current, const QModelIndex &previous);
private slots: private slots:

View File

@ -11,7 +11,7 @@
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Version</string> <string>Package Versions</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin"> <property name="leftMargin">
@ -37,7 +37,7 @@
</attribute> </attribute>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
<item> <item>
<widget class="ModListView" name="libraryTreeView"> <widget class="ModListView" name="packageView">
<property name="verticalScrollBarPolicy"> <property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum> <enum>Qt::ScrollBarAlwaysOn</enum>
</property> </property>
@ -65,16 +65,19 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="changeMCVersionBtn"> <widget class="QPushButton" name="changeVersionBtn">
<property name="toolTip">
<string>Change version of the selected package.</string>
</property>
<property name="text"> <property name="text">
<string>Change version</string> <string>Change version</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="moveLibraryUpBtn"> <widget class="QPushButton" name="moveUpBtn">
<property name="toolTip"> <property name="toolTip">
<string>This isn't implemented yet.</string> <string>Make the selected package apply sooner.</string>
</property> </property>
<property name="text"> <property name="text">
<string>Move up</string> <string>Move up</string>
@ -82,9 +85,9 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="moveLibraryDownBtn"> <widget class="QPushButton" name="moveDownBtn">
<property name="toolTip"> <property name="toolTip">
<string>This isn't implemented yet.</string> <string>Make the selected package apply later.</string>
</property> </property>
<property name="text"> <property name="text">
<string>Move down</string> <string>Move down</string>
@ -92,12 +95,58 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="removeLibraryBtn"> <widget class="QPushButton" name="removeBtn">
<property name="toolTip">
<string>Remove selected package from the instance.</string>
</property>
<property name="text"> <property name="text">
<string>Remove</string> <string>Remove</string>
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="LineSeparator" name="separator_4" native="true"/>
</item>
<item>
<widget class="QLabel" name="label_10">
<property name="text">
<string>Edit</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="customizeBtn">
<property name="toolTip">
<string>Customize selected package.</string>
</property>
<property name="text">
<string>Customize</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="editBtn">
<property name="toolTip">
<string>Edit selected package.</string>
</property>
<property name="text">
<string>Edit</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="revertBtn">
<property name="toolTip">
<string>Revert the selected package to default.</string>
</property>
<property name="text">
<string>Revert</string>
</property>
</widget>
</item>
<item> <item>
<widget class="LineSeparator" name="separator" native="true"/> <widget class="LineSeparator" name="separator" native="true"/>
</item> </item>
@ -114,7 +163,7 @@
<item> <item>
<widget class="QPushButton" name="forgeBtn"> <widget class="QPushButton" name="forgeBtn">
<property name="toolTip"> <property name="toolTip">
<string>Replace any current custom version with Minecraft Forge</string> <string>Install the Minecraft Forge package.</string>
</property> </property>
<property name="text"> <property name="text">
<string>Install Forge</string> <string>Install Forge</string>
@ -123,6 +172,9 @@
</item> </item>
<item> <item>
<widget class="QPushButton" name="liteloaderBtn"> <widget class="QPushButton" name="liteloaderBtn">
<property name="toolTip">
<string>Install the LiteLoader package.</string>
</property>
<property name="text"> <property name="text">
<string>Install LiteLoader</string> <string>Install LiteLoader</string>
</property> </property>
@ -130,6 +182,9 @@
</item> </item>
<item> <item>
<widget class="QPushButton" name="jarmodBtn"> <widget class="QPushButton" name="jarmodBtn">
<property name="toolTip">
<string>Add a mod into the Minecraft jar file.</string>
</property>
<property name="text"> <property name="text">
<string>Add jar mod</string> <string>Add jar mod</string>
</property> </property>
@ -149,9 +204,9 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="resetLibraryOrderBtn"> <widget class="QPushButton" name="resetOrderBtn">
<property name="toolTip"> <property name="toolTip">
<string>This isn't implemented yet.</string> <string>Reset apply order of packages.</string>
</property> </property>
<property name="text"> <property name="text">
<string>Reset order</string> <string>Reset order</string>
@ -159,7 +214,10 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="reloadLibrariesBtn"> <widget class="QPushButton" name="reloadBtn">
<property name="toolTip">
<string>Reload all packages.</string>
</property>
<property name="text"> <property name="text">
<string>Reload</string> <string>Reload</string>
</property> </property>
@ -199,6 +257,22 @@
<container>1</container> <container>1</container>
</customwidget> </customwidget>
</customwidgets> </customwidgets>
<tabstops>
<tabstop>tabWidget</tabstop>
<tabstop>packageView</tabstop>
<tabstop>changeVersionBtn</tabstop>
<tabstop>moveUpBtn</tabstop>
<tabstop>moveDownBtn</tabstop>
<tabstop>removeBtn</tabstop>
<tabstop>customizeBtn</tabstop>
<tabstop>editBtn</tabstop>
<tabstop>revertBtn</tabstop>
<tabstop>forgeBtn</tabstop>
<tabstop>liteloaderBtn</tabstop>
<tabstop>jarmodBtn</tabstop>
<tabstop>resetOrderBtn</tabstop>
<tabstop>reloadBtn</tabstop>
</tabstops>
<resources/> <resources/>
<connections/> <connections/>
</ui> </ui>

View File

@ -26,6 +26,7 @@ void FTBProfileStrategy::loadDefaultBuiltinPatches()
auto file = ProfileUtils::parseJsonFile(QFileInfo(mcJson), false); auto file = ProfileUtils::parseJsonFile(QFileInfo(mcJson), false);
file->fileId = "net.minecraft"; file->fileId = "net.minecraft";
file->name = QObject::tr("Minecraft (tracked)"); file->name = QObject::tr("Minecraft (tracked)");
file->setVanilla(true);
if(file->version.isEmpty()) if(file->version.isEmpty())
{ {
file->version = mcVersion; file->version = mcVersion;
@ -59,6 +60,7 @@ void FTBProfileStrategy::loadDefaultBuiltinPatches()
addLib->insertType = RawLibrary::Prepend; addLib->insertType = RawLibrary::Prepend;
} }
file->fileId = "org.multimc.ftb.pack"; file->fileId = "org.multimc.ftb.pack";
file->setVanilla(true);
file->name = QObject::tr("%1 (FTB pack)").arg(m_instance->name()); file->name = QObject::tr("%1 (FTB pack)").arg(m_instance->name());
if(file->version.isEmpty()) if(file->version.isEmpty())
{ {
@ -117,6 +119,8 @@ void FTBProfileStrategy::loadUserPatches()
throw VersionBuildError( throw VersionBuildError(
QObject::tr("load id %1 does not match internal id %2").arg(id, file->fileId)); QObject::tr("load id %1 does not match internal id %2").arg(id, file->fileId));
} }
file->setRemovable(true);
file->setMovable(true);
profile->appendPatch(file); profile->appendPatch(file);
} }
// now load the rest by internal preference. // now load the rest by internal preference.
@ -140,6 +144,8 @@ void FTBProfileStrategy::loadUserPatches()
throw VersionBuildError(QObject::tr("%1 has the same order as %2") throw VersionBuildError(QObject::tr("%1 has the same order as %2")
.arg(file->fileId, files[file->order].second->fileId)); .arg(file->fileId, files[file->order].second->fileId));
} }
file->setRemovable(true);
file->setMovable(true);
files.insert(file->order, qMakePair(info.fileName(), file)); files.insert(file->order, qMakePair(info.fileName(), file));
} }
for (auto order : files.keys()) for (auto order : files.keys())
@ -170,13 +176,17 @@ bool FTBProfileStrategy::resetOrder()
return false; return false;
} }
bool FTBProfileStrategy::removePatch(ProfilePatchPtr patch)
{
return false;
}
bool FTBProfileStrategy::installJarMods(QStringList filepaths) bool FTBProfileStrategy::installJarMods(QStringList filepaths)
{ {
return false; return false;
} }
bool FTBProfileStrategy::customizePatch(ProfilePatchPtr patch)
{
return false;
}
bool FTBProfileStrategy::revertPatch(ProfilePatchPtr patch)
{
return false;
}

View File

@ -13,7 +13,8 @@ public:
virtual bool resetOrder() override; virtual bool resetOrder() override;
virtual bool saveOrder(ProfileUtils::PatchOrder order) override; virtual bool saveOrder(ProfileUtils::PatchOrder order) override;
virtual bool installJarMods(QStringList filepaths) override; virtual bool installJarMods(QStringList filepaths) override;
virtual bool removePatch(ProfilePatchPtr patch) override; virtual bool customizePatch (ProfilePatchPtr patch) override;
virtual bool revertPatch (ProfilePatchPtr patch) override;
protected: protected:
void loadDefaultBuiltinPatches(); void loadDefaultBuiltinPatches();

View File

@ -91,22 +91,18 @@ void MinecraftProfile::appendPatch(ProfilePatchPtr patch)
endInsertRows(); endInsertRows();
} }
bool MinecraftProfile::canRemove(const int index) const
{
return VersionPatches.at(index)->isMoveable();
}
bool MinecraftProfile::remove(const int index) bool MinecraftProfile::remove(const int index)
{ {
if (!canRemove(index)) auto patch = versionPatch(index);
if (!patch->isRemovable())
{ {
qDebug() << "Patch" << index << "is non-removable"; qDebug() << "Patch" << patch->getPatchID() << "is non-removable";
return false; return false;
} }
if(!m_strategy->removePatch(VersionPatches.at(index))) if(!m_strategy->removePatch(patch))
{ {
qCritical() << "Patch" << index << "could not be removed"; qCritical() << "Patch" << patch->getPatchID() << "could not be removed";
return false; return false;
} }
@ -132,6 +128,46 @@ bool MinecraftProfile::remove(const QString id)
return false; return false;
} }
bool MinecraftProfile::customize(int index)
{
auto patch = versionPatch(index);
if (!patch->isCustomizable())
{
qDebug() << "Patch" << patch->getPatchID() << "is not customizable";
return false;
}
if(!m_strategy->customizePatch(patch))
{
qCritical() << "Patch" << patch->getPatchID() << "could not be customized";
return false;
}
reapply();
saveCurrentOrder();
// FIXME: maybe later in unstable
// emit dataChanged(createIndex(index, 0), createIndex(index, columnCount(QModelIndex()) - 1));
return true;
}
bool MinecraftProfile::revert(int index)
{
auto patch = versionPatch(index);
if (!patch->isRevertible())
{
qDebug() << "Patch" << patch->getPatchID() << "is not revertible";
return false;
}
if(!m_strategy->revertPatch(patch))
{
qCritical() << "Patch" << patch->getPatchID() << "could not be reverted";
return false;
}
reapply();
saveCurrentOrder();
// FIXME: maybe later in unstable
// emit dataChanged(createIndex(index, 0), createIndex(index, columnCount(QModelIndex()) - 1));
return true;
}
QString MinecraftProfile::versionFileId(const int index) const QString MinecraftProfile::versionFileId(const int index) const
{ {
if (index < 0 || index >= VersionPatches.size()) if (index < 0 || index >= VersionPatches.size())
@ -150,13 +186,13 @@ ProfilePatchPtr MinecraftProfile::versionPatch(const QString &id)
return file; return file;
} }
} }
return 0; return nullptr;
} }
ProfilePatchPtr MinecraftProfile::versionPatch(int index) ProfilePatchPtr MinecraftProfile::versionPatch(int index)
{ {
if(index < 0 || index >= VersionPatches.size()) if(index < 0 || index >= VersionPatches.size())
return 0; return nullptr;
return VersionPatches[index]; return VersionPatches[index];
} }
@ -172,37 +208,28 @@ bool MinecraftProfile::isVanilla()
bool MinecraftProfile::revertToVanilla() bool MinecraftProfile::revertToVanilla()
{ {
/*
beginResetModel();
// remove patches, if present // remove patches, if present
auto it = VersionPatches.begin(); auto VersionPatchesCopy = VersionPatches;
while (it != VersionPatches.end()) for(auto & it: VersionPatchesCopy)
{ {
if ((*it)->isMoveable()) if (!it->isCustom())
{ {
if(!preremove(*it)) continue;
}
if(it->isRevertible() || it->isRemovable())
{ {
endResetModel(); if(!remove(it->getPatchID()))
{
qWarning() << "Couldn't remove" << it->getPatchID() << "from profile!";
reapply();
saveCurrentOrder(); saveCurrentOrder();
return false; return false;
} }
if(!QFile::remove((*it)->getPatchFilename()))
{
endResetModel();
saveCurrentOrder();
return false;
} }
it = VersionPatches.erase(it);
}
else
it++;
} }
reapply(); reapply();
endResetModel();
saveCurrentOrder(); saveCurrentOrder();
return true; return true;
*/
return false;
} }
QList<std::shared_ptr<OneSixLibrary> > MinecraftProfile::getActiveNormalLibs() QList<std::shared_ptr<OneSixLibrary> > MinecraftProfile::getActiveNormalLibs()

View File

@ -60,9 +60,6 @@ public:
/// DEPRECATED, remove ASAP /// DEPRECATED, remove ASAP
int getFreeOrderNumber(); int getFreeOrderNumber();
/// Can patch file # be removed?
bool canRemove(const int index) const;
enum MoveDirection { MoveUp, MoveDown }; enum MoveDirection { MoveUp, MoveDown };
/// move patch file # up or down the list /// move patch file # up or down the list
void move(const int index, const MoveDirection direction); void move(const int index, const MoveDirection direction);
@ -73,6 +70,10 @@ public:
/// remove patch file by id - including files/records /// remove patch file by id - including files/records
bool remove(const QString id); bool remove(const QString id);
bool customize(int index);
bool revert(int index);
void resetOrder(); void resetOrder();
/// reload all profile patches from storage, clear the profile and apply the patches /// reload all profile patches from storage, clear the profile and apply the patches

View File

@ -60,11 +60,20 @@ void MinecraftVersion::applyFileTo(MinecraftProfile *version)
getVersionFile()->applyTo(version); getVersionFile()->applyTo(version);
} }
QJsonDocument MinecraftVersion::toJson(bool saveOrder)
{
return getVersionFile()->toJson(saveOrder);
}
VersionFilePtr MinecraftVersion::getVersionFile() VersionFilePtr MinecraftVersion::getVersionFile()
{ {
QFileInfo versionFile(QString("versions/%1/%1.dat").arg(m_descriptor)); QFileInfo versionFile(QString("versions/%1/%1.dat").arg(m_descriptor));
return ProfileUtils::parseBinaryJsonFile(versionFile); auto loadedVersionFile = ProfileUtils::parseBinaryJsonFile(versionFile);
loadedVersionFile->name = "Minecraft";
//FIXME: possibly not the best place for this... but w/e
loadedVersionFile->setCustomizable(true);
return loadedVersionFile;
} }

View File

@ -48,9 +48,35 @@ public: /* methods */
bool needsUpdate(); bool needsUpdate();
bool hasUpdate(); bool hasUpdate();
virtual bool isCustom() override; virtual bool isCustom() override;
virtual bool isMoveable() override
{
return false;
}
virtual bool isCustomizable() override
{
return true;
}
virtual bool isRemovable() override
{
return false;
}
virtual bool isRevertible() override
{
return false;
}
virtual bool isEditable() override
{
return false;
}
virtual bool isVersionChangeable() override
{
return true;
}
VersionFilePtr getVersionFile(); VersionFilePtr getVersionFile();
virtual QJsonDocument toJson(bool saveOrder) override;
private: /* methods */ private: /* methods */
void applyFileTo(MinecraftProfile *version); void applyFileTo(MinecraftProfile *version);

View File

@ -13,6 +13,14 @@ class NullProfileStrategy: public ProfileStrategy
{ {
return false; return false;
} }
virtual bool customizePatch(ProfilePatchPtr patch)
{
return false;
}
virtual bool revertPatch(ProfilePatchPtr patch)
{
return false;
}
virtual bool resetOrder() virtual bool resetOrder()
{ {
return false; return false;

View File

@ -76,9 +76,9 @@ void OneSixProfileStrategy::upgradeDeprecatedFiles()
} }
} }
void OneSixProfileStrategy::loadDefaultBuiltinPatches() void OneSixProfileStrategy::loadDefaultBuiltinPatches()
{ {
{
auto mcJson = PathCombine(m_instance->instanceRoot(), "patches" , "net.minecraft.json"); auto mcJson = PathCombine(m_instance->instanceRoot(), "patches" , "net.minecraft.json");
// load up the base minecraft patch // load up the base minecraft patch
ProfilePatchPtr minecraftPatch; ProfilePatchPtr minecraftPatch;
@ -90,6 +90,7 @@ void OneSixProfileStrategy::loadDefaultBuiltinPatches()
file->version = m_instance->intendedVersionId(); file->version = m_instance->intendedVersionId();
} }
file->setVanilla(false); file->setVanilla(false);
file->setRevertible(true);
minecraftPatch = std::dynamic_pointer_cast<ProfilePatch>(file); minecraftPatch = std::dynamic_pointer_cast<ProfilePatch>(file);
} }
else else
@ -103,19 +104,34 @@ void OneSixProfileStrategy::loadDefaultBuiltinPatches()
} }
minecraftPatch->setOrder(-2); minecraftPatch->setOrder(-2);
profile->appendPatch(minecraftPatch); profile->appendPatch(minecraftPatch);
}
{
// TODO: this is obviously fake. auto lwjglJson = PathCombine(m_instance->instanceRoot(), "patches" , "org.lwjgl.json");
ProfilePatchPtr lwjglPatch;
if(QFile::exists(lwjglJson))
{
auto file = ProfileUtils::parseJsonFile(QFileInfo(lwjglJson), false);
file->setVanilla(false);
file->setRevertible(true);
lwjglPatch = std::dynamic_pointer_cast<ProfilePatch>(file);
}
else
{
// NOTE: this is obviously fake, is fixed in unstable.
QResource LWJGL(":/versions/LWJGL/2.9.1.json"); QResource LWJGL(":/versions/LWJGL/2.9.1.json");
auto lwjgl = ProfileUtils::parseJsonFile(LWJGL.absoluteFilePath(), false); auto lwjgl = ProfileUtils::parseJsonFile(LWJGL.absoluteFilePath(), false);
auto lwjglPatch = std::dynamic_pointer_cast<ProfilePatch>(lwjgl); lwjgl->setVanilla(true);
lwjgl->setCustomizable(true);
lwjglPatch = std::dynamic_pointer_cast<ProfilePatch>(lwjgl);
}
if (!lwjglPatch) if (!lwjglPatch)
{ {
throw VersionIncomplete("org.lwjgl"); throw VersionIncomplete("org.lwjgl");
} }
lwjglPatch->setOrder(-1); lwjglPatch->setOrder(-1);
lwjgl->setVanilla(true);
profile->appendPatch(lwjglPatch); profile->appendPatch(lwjglPatch);
}
} }
void OneSixProfileStrategy::loadUserPatches() void OneSixProfileStrategy::loadUserPatches()
@ -149,6 +165,8 @@ void OneSixProfileStrategy::loadUserPatches()
throw VersionBuildError( throw VersionBuildError(
QObject::tr("load id %1 does not match internal id %2").arg(id, file->fileId)); QObject::tr("load id %1 does not match internal id %2").arg(id, file->fileId));
} }
file->setRemovable(true);
file->setMovable(true);
profile->appendPatch(file); profile->appendPatch(file);
} }
// now load the rest by internal preference. // now load the rest by internal preference.
@ -172,6 +190,8 @@ void OneSixProfileStrategy::loadUserPatches()
throw VersionBuildError(QObject::tr("%1 has the same order as %2") throw VersionBuildError(QObject::tr("%1 has the same order as %2")
.arg(file->fileId, files[file->order].second->fileId)); .arg(file->fileId, files[file->order].second->fileId));
} }
file->setRemovable(true);
file->setMovable(true);
files.insert(file->order, qMakePair(info.fileName(), file)); files.insert(file->order, qMakePair(info.fileName(), file));
} }
for (auto order : files.keys()) for (auto order : files.keys())
@ -243,6 +263,74 @@ bool OneSixProfileStrategy::removePatch(ProfilePatchPtr patch)
return ok; return ok;
} }
bool OneSixProfileStrategy::customizePatch(ProfilePatchPtr patch)
{
if(patch->isCustom())
{
return false;
}
auto filename = PathCombine(m_instance->instanceRoot(), "patches" , patch->getPatchID() + ".json");
if(!ensureFilePathExists(filename))
{
return false;
}
QSaveFile jsonFile(filename);
if(!jsonFile.open(QIODevice::WriteOnly))
{
return false;
}
auto document = patch->toJson(true);
jsonFile.write(document.toJson());
if(!jsonFile.commit())
{
return false;
}
try
{
load();
}
catch (VersionIncomplete &error)
{
qDebug() << "Version was incomplete:" << error.cause();
}
catch (MMCError &error)
{
qWarning() << "Version could not be loaded:" << error.cause();
}
return true;
}
bool OneSixProfileStrategy::revertPatch(ProfilePatchPtr patch)
{
if(!patch->isCustom())
{
// already not custom
return true;
}
auto filename = patch->getPatchFilename();
if(!QFile::exists(filename))
{
// already gone / not custom
return true;
}
// just kill the file and reload
bool result = QFile::remove(filename);
try
{
load();
}
catch (VersionIncomplete &error)
{
qDebug() << "Version was incomplete:" << error.cause();
}
catch (MMCError &error)
{
qWarning() << "Version could not be loaded:" << error.cause();
}
return result;
}
bool OneSixProfileStrategy::installJarMods(QStringList filepaths) bool OneSixProfileStrategy::installJarMods(QStringList filepaths)
{ {
QString patchDir = PathCombine(m_instance->instanceRoot(), "patches"); QString patchDir = PathCombine(m_instance->instanceRoot(), "patches");

View File

@ -13,6 +13,8 @@ public:
virtual bool saveOrder(ProfileUtils::PatchOrder order) override; virtual bool saveOrder(ProfileUtils::PatchOrder order) override;
virtual bool installJarMods(QStringList filepaths) override; virtual bool installJarMods(QStringList filepaths) override;
virtual bool removePatch(ProfilePatchPtr patch) override; virtual bool removePatch(ProfilePatchPtr patch) override;
virtual bool customizePatch(ProfilePatchPtr patch) override;
virtual bool revertPatch(ProfilePatchPtr patch) override;
protected: protected:
void loadDefaultBuiltinPatches(); void loadDefaultBuiltinPatches();

View File

@ -2,6 +2,7 @@
#include <memory> #include <memory>
#include <QList> #include <QList>
#include <QJsonDocument>
#include "JarMod.h" #include "JarMod.h"
class MinecraftProfile; class MinecraftProfile;
@ -10,15 +11,20 @@ class ProfilePatch
public: public:
virtual ~ProfilePatch(){}; virtual ~ProfilePatch(){};
virtual void applyTo(MinecraftProfile *version) = 0; virtual void applyTo(MinecraftProfile *version) = 0;
virtual QJsonDocument toJson(bool saveOrder) = 0;
virtual bool isMinecraftVersion() = 0; virtual bool isMinecraftVersion() = 0;
virtual bool hasJarMods() = 0; virtual bool hasJarMods() = 0;
virtual QList<JarmodPtr> getJarMods() = 0; virtual QList<JarmodPtr> getJarMods() = 0;
virtual bool isMoveable() virtual bool isMoveable() = 0;
{ virtual bool isCustomizable() = 0;
return getOrder() >= 0; virtual bool isRevertible() = 0;
} virtual bool isRemovable() = 0;
virtual bool isCustom() = 0;
virtual bool isEditable() = 0;
virtual bool isVersionChangeable() = 0;
virtual void setOrder(int order) = 0; virtual void setOrder(int order) = 0;
virtual int getOrder() = 0; virtual int getOrder() = 0;
@ -26,7 +32,6 @@ public:
virtual QString getPatchName() = 0; virtual QString getPatchName() = 0;
virtual QString getPatchVersion() = 0; virtual QString getPatchVersion() = 0;
virtual QString getPatchFilename() = 0; virtual QString getPatchFilename() = 0;
virtual bool isCustom() = 0;
}; };
typedef std::shared_ptr<ProfilePatch> ProfilePatchPtr; typedef std::shared_ptr<ProfilePatch> ProfilePatchPtr;

View File

@ -25,6 +25,11 @@ public:
/// remove any files or records that constitute the version patch /// remove any files or records that constitute the version patch
virtual bool removePatch(ProfilePatchPtr jarMod) = 0; virtual bool removePatch(ProfilePatchPtr jarMod) = 0;
/// make the patch custom, if possible
virtual bool customizePatch(ProfilePatchPtr patch) = 0;
/// revert the custom patch to 'vanilla', if possible
virtual bool revertPatch(ProfilePatchPtr patch) = 0;
protected: protected:
MinecraftProfile *profile; MinecraftProfile *profile;
}; };

View File

@ -20,7 +20,7 @@ class VersionFile : public ProfilePatch
public: /* methods */ public: /* methods */
static VersionFilePtr fromJson(const QJsonDocument &doc, const QString &filename, static VersionFilePtr fromJson(const QJsonDocument &doc, const QString &filename,
const bool requireOrder); const bool requireOrder);
QJsonDocument toJson(bool saveOrder); virtual QJsonDocument toJson(bool saveOrder) override;
virtual void applyTo(MinecraftProfile *version) override; virtual void applyTo(MinecraftProfile *version) override;
virtual bool isMinecraftVersion() override; virtual bool isMinecraftVersion() override;
@ -53,18 +53,64 @@ public: /* methods */
{ {
return filename; return filename;
} }
virtual bool isCustom() virtual bool isCustom() override
{ {
return !isVanilla; return !m_isVanilla;
}; };
virtual bool isCustomizable() override
{
return m_isCustomizable;
}
virtual bool isRemovable() override
{
return m_isRemovable;
}
virtual bool isRevertible() override
{
return m_isRevertible;
}
virtual bool isMoveable() override
{
return m_isMovable;
}
virtual bool isEditable() override
{
return isCustom();
}
virtual bool isVersionChangeable() override
{
return false;
}
void setVanilla (bool state) void setVanilla (bool state)
{ {
isVanilla = state; m_isVanilla = state;
} }
void setRemovable (bool state)
{
m_isRemovable = state;
}
void setRevertible (bool state)
{
m_isRevertible = state;
}
void setCustomizable (bool state)
{
m_isCustomizable = state;
}
void setMovable (bool state)
{
m_isMovable = state;
}
public: /* data */ public: /* data */
int order = 0; int order = 0;
bool isVanilla = false; bool m_isVanilla = false;
bool m_isRemovable = false;
bool m_isRevertible = false;
bool m_isCustomizable = false;
bool m_isMovable = false;
QString name; QString name;
QString fileId; QString fileId;
QString version; QString version;