summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt3
-rw-r--r--MultiMC.pro9
-rw-r--r--asset_test.cpp44
-rw-r--r--gui/instancesettings.cpp180
-rw-r--r--gui/instancesettings.h34
-rw-r--r--gui/instancesettings.ui416
-rw-r--r--gui/mainwindow.cpp23
-rw-r--r--gui/mainwindow.h4
-rw-r--r--gui/mainwindow.ui5
-rw-r--r--libmultimc/CMakeLists.txt6
-rw-r--r--libmultimc/include/fullversion.h69
-rw-r--r--libmultimc/include/fullversionfactory.h25
-rw-r--r--libmultimc/include/gameupdatetask.h75
-rw-r--r--libmultimc/include/instance.h46
-rw-r--r--libmultimc/include/library.h219
-rw-r--r--libmultimc/src/fullversion.cpp5
-rw-r--r--libmultimc/src/fullversionfactory.cpp206
-rw-r--r--libmultimc/src/gameupdatetask.cpp235
-rw-r--r--libmultimc/src/instance.cpp15
-rw-r--r--libmultimc/src/library.cpp37
-rw-r--r--libsettings/include/inisettingsobject.h1
-rw-r--r--libsettings/include/setting.h13
-rw-r--r--libsettings/include/settingsobject.h22
-rw-r--r--libsettings/src/inisettingsobject.cpp9
-rw-r--r--libsettings/src/setting.cpp5
-rw-r--r--libsettings/src/settingsobject.cpp20
-rw-r--r--libutil/include/dlqueue.h9
-rw-r--r--libutil/include/jobqueue.h7
-rw-r--r--libutil/src/dlqueue.cpp79
29 files changed, 1589 insertions, 232 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index afcc9587..f8df3260 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -176,6 +176,7 @@ gui/instancedelegate.h
gui/versionselectdialog.h
gui/lwjglselectdialog.h
gui/iconcache.h
+gui/instancesettings.h
multimc_pragma.h
@@ -208,6 +209,7 @@ gui/instancedelegate.cpp
gui/versionselectdialog.cpp
gui/lwjglselectdialog.cpp
gui/iconcache.cpp
+gui/instancesettings.cpp
java/javautils.cpp
java/annotations.cpp
@@ -228,6 +230,7 @@ gui/aboutdialog.ui
gui/consolewindow.ui
gui/versionselectdialog.ui
gui/lwjglselectdialog.ui
+gui/instancesettings.ui
)
diff --git a/MultiMC.pro b/MultiMC.pro
index 3f480529..6af1ec0d 100644
--- a/MultiMC.pro
+++ b/MultiMC.pro
@@ -21,7 +21,8 @@ SOURCES += main.cpp\
data/inifile.cpp \
gui/settingsdialog.cpp \
gui/modeditwindow.cpp \
- util/appsettings.cpp
+ util/appsettings.cpp \
+ gui/instancesettings.cpp
HEADERS += gui/mainwindow.h \
data/instancebase.h \
@@ -32,11 +33,13 @@ HEADERS += gui/mainwindow.h \
gui/settingsdialog.h \
gui/modeditwindow.h \
util/apputils.h \
- util/appsettings.h
+ util/appsettings.h \
+ gui/instancesettings.h
FORMS += gui/mainwindow.ui \
gui/settingsdialog.ui \
- gui/modeditwindow.ui
+ gui/modeditwindow.ui \
+ gui/instancesettings.ui
RESOURCES += \
multimc.qrc
diff --git a/asset_test.cpp b/asset_test.cpp
index fb797b97..90da314f 100644
--- a/asset_test.cpp
+++ b/asset_test.cpp
@@ -13,19 +13,11 @@ inline QDomElement getDomElementByTagName(QDomElement parent, QString tagname)
return QDomElement();
}
-// a job that removes all files from the base folder that don't match the whitelist
-// runs in whatever thread owns the queue. it is fast though.
-class NukeAndPaveJob: public Job
+class ThreadedDeleter : public QThread
{
+ Q_OBJECT
public:
- explicit NukeAndPaveJob(QString base, QStringList whitelist)
- :Job()
- {
- QDir dir(base);
- m_base = dir.absolutePath();
- m_whitelist = whitelist;
- };
- virtual void start()
+ void run()
{
QDirIterator iter(m_base, QDirIterator::Subdirectories);
QStringList nuke_list;
@@ -51,13 +43,37 @@ public:
f.remove();
}
}
- emit finish();
};
-private:
QString m_base;
QStringList m_whitelist;
};
+class NukeAndPaveJob: public Job
+{
+ Q_OBJECT
+public:
+
+ explicit NukeAndPaveJob(QString base, QStringList whitelist)
+ :Job()
+ {
+ QDir dir(base);
+ deleterThread.m_base = dir.absolutePath();
+ deleterThread.m_whitelist = whitelist;
+ };
+public slots:
+ virtual void start()
+ {
+ connect(&deleterThread, SIGNAL(finished()), SLOT(threadFinished()));
+ deleterThread.start();
+ };
+ void threadFinished()
+ {
+ emit finish();
+ }
+private:
+ ThreadedDeleter deleterThread;
+};
+
class DlMachine : public QObject
{
Q_OBJECT
@@ -84,7 +100,7 @@ public slots:
qDebug() << "Failed to process s3.amazonaws.com/Minecraft.Resources. XML error:" <<
xmlErrorMsg << ba;
}
- QRegExp etag_match(".*([a-f0-9]{32}).*");
+ //QRegExp etag_match(".*([a-f0-9]{32}).*");
QDomNodeList contents = doc.elementsByTagName("Contents");
JobList *job = new JobList();
diff --git a/gui/instancesettings.cpp b/gui/instancesettings.cpp
new file mode 100644
index 00000000..eea61ce8
--- /dev/null
+++ b/gui/instancesettings.cpp
@@ -0,0 +1,180 @@
+/* Copyright 2013 MultiMC Contributors
+ *
+ * Authors: Andrew Okin
+ * Peterix
+ * Orochimarufan <orochimarufan.x3@gmail.com>
+ *
+ * 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 "instancesettings.h"
+#include "ui_instancesettings.h"
+
+InstanceSettings::InstanceSettings( SettingsObject * obj, QWidget *parent) :
+ m_obj(obj),
+ QDialog(parent),
+ ui(new Ui::InstanceSettings)
+{
+ ui->setupUi(this);
+ loadSettings();
+}
+
+InstanceSettings::~InstanceSettings()
+{
+ delete ui;
+}
+
+void InstanceSettings::on_customCommandsGroupBox_toggled(bool state)
+{
+ ui->labelCustomCmdsDescription->setEnabled(state);
+}
+
+void InstanceSettings::on_buttonBox_accepted()
+{
+ applySettings();
+ accept();
+}
+
+void InstanceSettings::on_buttonBox_rejected()
+{
+ reject();
+}
+
+
+void InstanceSettings::applySettings()
+{
+ // Console
+ bool console = ui->consoleSettingsBox->isChecked();
+ m_obj->set("OverrideConsole", console);
+ if(console)
+ {
+ m_obj->set("ShowConsole", ui->showConsoleCheck->isChecked());
+ m_obj->set("AutoCloseConsole", ui->autoCloseConsoleCheck->isChecked());
+ }
+ else
+ {
+ m_obj->reset("ShowConsole");
+ m_obj->reset("AutoCloseConsole");
+ }
+
+ // Window Size
+ bool window = ui->windowSizeGroupBox->isChecked();
+ m_obj->set("OverrideWindow", window);
+ if(window)
+ {
+ m_obj->set("LaunchCompatMode", ui->compatModeCheckBox->isChecked());
+ m_obj->set("LaunchMaximized", ui->maximizedCheckBox->isChecked());
+ m_obj->set("MinecraftWinWidth", ui->windowWidthSpinBox->value());
+ m_obj->set("MinecraftWinHeight", ui->windowHeightSpinBox->value());
+ }
+ else
+ {
+ m_obj->reset("LaunchCompatMode");
+ m_obj->reset("LaunchMaximized");
+ m_obj->reset("MinecraftWinWidth");
+ m_obj->reset("MinecraftWinHeight");
+ }
+
+
+ // Auto Login
+ bool login = ui->accountSettingsGroupBox->isChecked();
+ m_obj->set("OverrideLogin", login);
+ if(login)
+ {
+ m_obj->set("AutoLogin", ui->autoLoginChecBox->isChecked());
+ }
+ else
+ {
+ m_obj->reset("AutoLogin");
+ }
+
+
+ // Memory
+ bool memory = ui->memoryGroupBox->isChecked();
+ m_obj->set("OverrideMemory", memory);
+ if(memory)
+ {
+ m_obj->set("MinMemAlloc", ui->minMemSpinBox->value());
+ m_obj->set("MaxMemAlloc", ui->maxMemSpinBox->value());
+ }
+ else
+ {
+ m_obj->reset("MinMemAlloc");
+ m_obj->reset("MaxMemAlloc");
+ }
+
+
+ // Java Settings
+ bool java = ui->javaSettingsGroupBox->isChecked();
+ m_obj->set("OverrideJava", java);
+ if(java)
+ {
+ m_obj->set("JavaPath", ui->javaPathTextBox->text());
+ m_obj->set("JvmArgs", ui->jvmArgsTextBox->text());
+ }
+ else
+ {
+ m_obj->reset("JavaPath");
+ m_obj->reset("JvmArgs");
+ }
+
+
+ // Custom Commands
+ bool custcmd = ui->customCommandsGroupBox->isChecked();
+ m_obj->set("OverrideCommands", custcmd);
+ if(custcmd)
+ {
+ m_obj->set("PreLaunchCommand", ui->preLaunchCmdTextBox->text());
+ m_obj->set("PostExitCommand", ui->postExitCmdTextBox->text());
+ }
+ else
+ {
+ m_obj->reset("PreLaunchCommand");
+ m_obj->reset("PostExitCommand");
+ }
+
+}
+
+void InstanceSettings::loadSettings()
+{
+ // Console
+ ui->showConsoleCheck->setChecked(m_obj->get("ShowConsole").toBool());
+ ui->autoCloseConsoleCheck->setChecked(m_obj->get("AutoCloseConsole").toBool());
+ ui->consoleSettingsBox->setChecked(m_obj->get("OverrideConsole").toBool());
+
+ // Window Size
+ ui->compatModeCheckBox->setChecked(m_obj->get("LaunchCompatMode").toBool());
+ ui->maximizedCheckBox->setChecked(m_obj->get("LaunchMaximized").toBool());
+ ui->windowWidthSpinBox->setValue(m_obj->get("MinecraftWinWidth").toInt());
+ ui->windowHeightSpinBox->setValue(m_obj->get("MinecraftWinHeight").toInt());
+ ui->windowSizeGroupBox->setChecked(m_obj->get("OverrideWindow").toBool());
+
+ // Auto Login
+ ui->autoLoginChecBox->setChecked(m_obj->get("AutoLogin").toBool());
+ ui->accountSettingsGroupBox->setChecked(m_obj->get("OverrideLogin").toBool());
+
+ // Memory
+ ui->minMemSpinBox->setValue(m_obj->get("MinMemAlloc").toInt());
+ ui->maxMemSpinBox->setValue(m_obj->get("MaxMemAlloc").toInt());
+ ui->memoryGroupBox->setChecked(m_obj->get("OverrideMemory").toBool());
+
+ // Java Settings
+ ui->javaPathTextBox->setText(m_obj->get("JavaPath").toString());
+ ui->jvmArgsTextBox->setText(m_obj->get("JvmArgs").toString());
+ ui->javaSettingsGroupBox->setChecked(m_obj->get("OverrideJava").toBool());
+
+ // Custom Commands
+ ui->preLaunchCmdTextBox->setText(m_obj->get("PreLaunchCommand").toString());
+ ui->postExitCmdTextBox->setText(m_obj->get("PostExitCommand").toString());
+ ui->customCommandsGroupBox->setChecked(m_obj->get("OverrideCommands").toBool());
+}
diff --git a/gui/instancesettings.h b/gui/instancesettings.h
new file mode 100644
index 00000000..afbd0c16
--- /dev/null
+++ b/gui/instancesettings.h
@@ -0,0 +1,34 @@
+#ifndef INSTANCESETTINGS_H
+#define INSTANCESETTINGS_H
+
+#include <QDialog>
+#include "settingsobject.h"
+
+namespace Ui {
+class InstanceSettings;
+}
+
+class InstanceSettings : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit InstanceSettings(SettingsObject *s, QWidget *parent = 0);
+ ~InstanceSettings();
+
+ void updateCheckboxStuff();
+
+ void applySettings();
+ void loadSettings();
+
+private slots:
+ void on_customCommandsGroupBox_toggled(bool arg1);
+ void on_buttonBox_accepted();
+ void on_buttonBox_rejected();
+
+private:
+ Ui::InstanceSettings *ui;
+ SettingsObject * m_obj;
+};
+
+#endif // INSTANCESETTINGS_H
diff --git a/gui/instancesettings.ui b/gui/instancesettings.ui
new file mode 100644
index 00000000..16e64100
--- /dev/null
+++ b/gui/instancesettings.ui
@@ -0,0 +1,416 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>InstanceSettings</class>
+ <widget class="QDialog" name="InstanceSettings">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>453</width>
+ <height>563</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string/>
+ </property>
+ <widget class="QTabWidget" name="settingsTabs">
+ <property name="geometry">
+ <rect>
+ <x>9</x>
+ <y>9</y>
+ <width>435</width>
+ <height>516</height>
+ </rect>
+ </property>
+ <property name="tabShape">
+ <enum>QTabWidget::Rounded</enum>
+ </property>
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="minecraftTab">
+ <attribute name="title">
+ <string>Minecraft</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QGroupBox" name="windowSizeGroupBox">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>Window Size</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <widget class="QCheckBox" name="compatModeCheckBox">
+ <property name="text">
+ <string>Compatibility mode?</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="maximizedCheckBox">
+ <property name="text">
+ <string>Start Minecraft maximized?</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QGridLayout" name="gridLayoutWindowSize">
+ <item row="1" column="0">
+ <widget class="QLabel" name="labelWindowHeight">
+ <property name="text">
+ <string>Window height:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="labelWindowWidth">
+ <property name="text">
+ <string>Window width:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QSpinBox" name="windowWidthSpinBox">
+ <property name="minimum">
+ <number>854</number>
+ </property>
+ <property name="maximum">
+ <number>65536</number>
+ </property>
+ <property name="singleStep">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>854</number>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QSpinBox" name="windowHeightSpinBox">
+ <property name="minimum">
+ <number>480</number>
+ </property>
+ <property name="maximum">
+ <number>65536</number>
+ </property>
+ <property name="value">
+ <number>480</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="consoleSettingsBox">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>Console Settings</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QCheckBox" name="showConsoleCheck">
+ <property name="text">
+ <string>Show console while the game is running?</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="autoCloseConsoleCheck">
+ <property name="text">
+ <string>Automatically close console when the game quits?</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="accountSettingsGroupBox">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>Account Settings</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_6">
+ <item>
+ <widget class="QCheckBox" name="autoLoginChecBox">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Login automatically when an instance icon is double clicked?</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacerMinecraft">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="javaTab">
+ <attribute name="title">
+ <string>Java</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <item>
+ <widget class="QGroupBox" name="memoryGroupBox">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>Memory</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="1" column="1">
+ <widget class="QSpinBox" name="maxMemSpinBox">
+ <property name="minimum">
+ <number>512</number>
+ </property>
+ <property name="maximum">
+ <number>65536</number>
+ </property>
+ <property name="singleStep">
+ <number>128</number>
+ </property>
+ <property name="value">
+ <number>1024</number>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="labelMinMem">
+ <property name="text">
+ <string>Minimum memory allocation:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="labelMaxMem">
+ <property name="text">
+ <string>Maximum memory allocation:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QSpinBox" name="minMemSpinBox">
+ <property name="minimum">
+ <number>256</number>
+ </property>
+ <property name="maximum">
+ <number>65536</number>
+ </property>
+ <property name="singleStep">
+ <number>128</number>
+ </property>
+ <property name="value">
+ <number>256</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="javaSettingsGroupBox">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>Java Settings</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="0" column="0">
+ <widget class="QLabel" name="labelJavaPath">
+ <property name="text">
+ <string>Java path:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="javaPathTextBox"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="labelJVMArgs">
+ <property name="text">
+ <string>JVM arguments:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QPushButton" name="pushButton">
+ <property name="text">
+ <string>Auto-detect</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" colspan="2">
+ <widget class="QLineEdit" name="jvmArgsTextBox"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="customCommandsGroupBox">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>Custom Commands</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_4">
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="preLaunchCmdTextBox"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="labelPostExitCmd">
+ <property name="text">
+ <string>Post-exit command:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="labelPreLaunchCmd">
+ <property name="text">
+ <string>Pre-launch command:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="postExitCmdTextBox"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="labelCustomCmdsDescription">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Pre-launch command runs before the instance launches and post-exit command runs after it exits. Both will be run in MultiMC's working directory with INST_ID, INST_DIR, and INST_NAME as environment variables.</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="geometry">
+ <rect>
+ <x>9</x>
+ <y>530</y>
+ <width>435</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </widget>
+ <tabstops>
+ <tabstop>settingsTabs</tabstop>
+ <tabstop>windowSizeGroupBox</tabstop>
+ <tabstop>compatModeCheckBox</tabstop>
+ <tabstop>maximizedCheckBox</tabstop>
+ <tabstop>windowWidthSpinBox</tabstop>
+ <tabstop>windowHeightSpinBox</tabstop>
+ <tabstop>consoleSettingsBox</tabstop>
+ <tabstop>showConsoleCheck</tabstop>
+ <tabstop>autoCloseConsoleCheck</tabstop>
+ <tabstop>accountSettingsGroupBox</tabstop>
+ <tabstop>autoLoginChecBox</tabstop>
+ <tabstop>memoryGroupBox</tabstop>
+ <tabstop>minMemSpinBox</tabstop>
+ <tabstop>maxMemSpinBox</tabstop>
+ <tabstop>javaSettingsGroupBox</tabstop>
+ <tabstop>javaPathTextBox</tabstop>
+ <tabstop>pushButton</tabstop>
+ <tabstop>jvmArgsTextBox</tabstop>
+ <tabstop>customCommandsGroupBox</tabstop>
+ <tabstop>preLaunchCmdTextBox</tabstop>
+ <tabstop>postExitCmdTextBox</tabstop>
+ <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp
index 80f737e3..f9398c8b 100644
--- a/gui/mainwindow.cpp
+++ b/gui/mainwindow.cpp
@@ -43,6 +43,7 @@
#include "gui/lwjglselectdialog.h"
#include "gui/consolewindow.h"
#include "gui/legacymodeditdialog.h"
+#include "gui/instancesettings.h"
#include "kcategorizedview.h"
#include "kcategorydrawer.h"
@@ -130,6 +131,9 @@ MainWindow::MainWindow ( QWidget *parent ) :
view->setModel ( proxymodel );
connect(view, SIGNAL(doubleClicked(const QModelIndex &)),
this, SLOT(instanceActivated(const QModelIndex &)));
+
+ connect(view, SIGNAL(clicked(const QModelIndex &)),
+ this, SLOT(instanceChanged(const QModelIndex &)));
// Load the instances.
instList.loadList();
@@ -417,7 +421,7 @@ void MainWindow::onLoginComplete(LoginResponse response)
{
Q_ASSERT_X(m_activeInst != NULL, "onLoginComplete", "no active instance is set");
- if (!m_activeInst->shouldUpdateGame())
+ if (!m_activeInst->shouldUpdate())
{
launchInstance(m_activeInst, response);
}
@@ -554,3 +558,20 @@ void MainWindow::on_actionChangeInstLWJGLVersion_triggered()
}
}
+
+void MainWindow::on_actionInstanceSettings_triggered()
+{
+ if (view->selectionModel()->selectedIndexes().count() < 1)
+ return;
+
+ Instance *inst = selectedInstance();
+ SettingsObject *s;
+ s = &inst->settings();
+ InstanceSettings settings(s, this);
+ settings.setWindowTitle(QString("Instance settings"));
+ settings.exec();
+}
+
+void MainWindow::instanceChanged(QModelIndex idx) {
+ ui->instanceToolBar->setEnabled(idx.isValid());
+}
diff --git a/gui/mainwindow.h b/gui/mainwindow.h
index f13d9395..a10d570c 100644
--- a/gui/mainwindow.h
+++ b/gui/mainwindow.h
@@ -108,8 +108,12 @@ private slots:
void on_actionChangeInstLWJGLVersion_triggered();
+ void on_actionInstanceSettings_triggered();
+
public slots:
void instanceActivated ( QModelIndex );
+
+ void instanceChanged ( QModelIndex );
void startTask(Task *task);
diff --git a/gui/mainwindow.ui b/gui/mainwindow.ui
index 771e7096..e6a82635 100644
--- a/gui/mainwindow.ui
+++ b/gui/mainwindow.ui
@@ -65,6 +65,9 @@
</widget>
<widget class="QStatusBar" name="statusBar"/>
<widget class="QToolBar" name="instanceToolBar">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
<property name="windowTitle">
<string>Instance Toolbar</string>
</property>
@@ -300,7 +303,7 @@
</action>
<action name="actionInstanceSettings">
<property name="enabled">
- <bool>false</bool>
+ <bool>true</bool>
</property>
<property name="text">
<string>Settings</string>
diff --git a/libmultimc/CMakeLists.txt b/libmultimc/CMakeLists.txt
index 0209f8a4..8adee1ec 100644
--- a/libmultimc/CMakeLists.txt
+++ b/libmultimc/CMakeLists.txt
@@ -32,6 +32,9 @@ include/instversionlist.h
include/minecraftversion.h
include/minecraftversionlist.h
+include/library.h
+include/fullversion.h
+include/fullversionfactory.h
# Tasks
include/task.h
@@ -63,6 +66,9 @@ src/instversionlist.cpp
src/minecraftversion.cpp
src/minecraftversionlist.cpp
+src/library.cpp
+src/fullversion.cpp
+src/fullversionfactory.cpp
# Tasks
src/task.cpp
diff --git a/libmultimc/include/fullversion.h b/libmultimc/include/fullversion.h
new file mode 100644
index 00000000..523ac87c
--- /dev/null
+++ b/libmultimc/include/fullversion.h
@@ -0,0 +1,69 @@
+#pragma once
+#include <QString>
+
+class Library;
+
+class FullVersion
+{
+public:
+ FullVersion()
+ {
+ minimumLauncherVersion = 0xDEADBEEF;
+ isLegacy = false;
+ }
+ // the ID - determines which jar to use! ACTUALLY IMPORTANT!
+ QString id;
+ // do we actually care about parsing this?
+ QString time;
+ // I don't think we do.
+ QString releaseTime;
+ // eh, not caring - "release" or "snapshot"
+ QString type;
+ /*
+ * DEPRECATED: Old versions of the new vanilla launcher used this
+ * ex: "username_session_version"
+ */
+ QString processArguments;
+ /*
+ * arguments that should be used for launching minecraft
+ *
+ * ex: "--username ${auth_player_name} --session ${auth_session}
+ * --version ${version_name} --gameDir ${game_directory} --assetsDir ${game_assets}"
+ */
+ QString minecraftArguments;
+ /*
+ * the minimum launcher version required by this version ... current is 4 (at point of writing)
+ */
+ int minimumLauncherVersion;
+ /*
+ * The main class to load first
+ */
+ QString mainClass;
+
+ // the list of libs. just the names for now. expand to full-blown strutures!
+ QList<QSharedPointer<Library> > libraries;
+
+ // is this actually a legacy version? if so, none of the other stuff here will be ever used.
+ // added by FullVersionFactory
+ bool isLegacy;
+
+/*
+FIXME: add support for those rules here? Looks like a pile of quick hacks to me though.
+
+ "rules": [
+ {
+ "action": "allow"
+ },
+ {
+ "action": "disallow",
+ "os": {
+ "name": "osx",
+ "version": "^10\\.5\\.\\d$"
+ }
+ }
+ ],
+ "incompatibilityReason": "There is a bug in LWJGL which makes it incompatible with OSX 10.5.8. Please go to New Profile and use 1.5.2 for now. Sorry!"
+}
+*/
+ // QList<Rule> rules;
+}; \ No newline at end of file
diff --git a/libmultimc/include/fullversionfactory.h b/libmultimc/include/fullversionfactory.h
new file mode 100644
index 00000000..60e5c983
--- /dev/null
+++ b/libmultimc/include/fullversionfactory.h
@@ -0,0 +1,25 @@
+#pragma once
+#include <QtCore>
+
+struct FullVersion;
+class Rule;
+
+class FullVersionFactory
+{
+public:
+ enum Error
+ {
+ AllOK, // all parsed OK
+ ParseError, // the file was corrupted somehow
+ UnsupportedVersion // the file was meant for a launcher version we don't support (yet)
+ } m_error;
+ QString error_string;
+
+public:
+ FullVersionFactory();
+ QSharedPointer<FullVersion> parse(QByteArray data);
+private:
+ QSharedPointer<FullVersion> parse4(QJsonObject root, QSharedPointer<FullVersion> product);
+ QList<QSharedPointer<Rule> > parse4rules(QJsonObject & baseObj);
+ QStringList legacyWhitelist;
+}; \ No newline at end of file
diff --git a/libmultimc/include/gameupdatetask.h b/libmultimc/include/gameupdatetask.h
index c3f84356..b56c448b 100644
--- a/libmultimc/include/gameupdatetask.h
+++ b/libmultimc/include/gameupdatetask.h
@@ -22,47 +22,15 @@
#include <QNetworkAccessManager>
#include <QUrl>
+#include "dlqueue.h"
#include "task.h"
#include "loginresponse.h"
#include "instance.h"
#include "libmmc_config.h"
-class FileToDownload;
-typedef QSharedPointer<FileToDownload> FileToDownloadPtr;
-
-class FileToDownload : public QObject
-{
- Q_OBJECT
-
- /*!
- * The URL to download the file from.
- */
- Q_PROPERTY(QUrl url READ url WRITE setURL)
-
- /*!
- * The path to download to.
- * This path is relative to the instance's root directory.
- */
- Q_PROPERTY(QString path READ path WRITE setPath)
-
-private:
- FileToDownload(const QUrl &url, const QString &path, QObject *parent = 0);
-public:
- static FileToDownloadPtr Create(const QUrl &url, const QString &path, QObject *parent = 0);
-
- virtual QUrl url() const { return m_dlURL; }
- virtual void setURL(const QUrl &url) { m_dlURL = url; }
-
- virtual QString path() const { return m_dlPath; }
- virtual void setPath(const QString &path) { m_dlPath = path; }
-
-private:
- QUrl m_dlURL;
- QString m_dlPath;
-};
-
+class MinecraftVersion;
/*!
* The game update task is the task that handles downloading instances' files.
@@ -92,9 +60,6 @@ public:
virtual void executeTask();
- virtual bool downloadFile(const FileToDownloadPtr file);
-
-
//////////////////////
// STATE AND STATUS //
//////////////////////
@@ -110,6 +75,10 @@ public:
*/
virtual QString getStateMessage(int state);
+private:
+ void getLegacyJar();
+ void determineNewVersion();
+
public slots:
/*!
@@ -122,7 +91,15 @@ public slots:
private slots:
- virtual void updateDownloadProgress(qint64 current, qint64 total);
+ void updateDownloadProgress(qint64 current, qint64 total);
+ void legacyJarFinished();
+ void legacyJarFailed();
+
+ void versionFileFinished();
+ void versionFileFailed();
+
+ void jarlibFinished();
+ void jarlibFailed();
signals:
/*!
@@ -143,23 +120,8 @@ private:
///////////
Instance *m_inst;
-
LoginResponse m_response;
- QNetworkAccessManager *netMgr;
-
-
-
- ////////////////////////
- // FILE DOWNLOAD LIST //
- ////////////////////////
-
- // List of URLs that the game updater will need to download.
- QList<FileToDownloadPtr> m_downloadList;
- int m_currentDownload;
-
-
-
////////////////////////////
// STATE AND STATUS STUFF //
////////////////////////////
@@ -184,6 +146,13 @@ private:
// Finished
StateFinished
};
+ JobListPtr legacyDownloadJob;
+ JobListPtr specificVersionDownloadJob;
+ JobListPtr jarlibDownloadJob;
+ JobListQueue download_queue;
+
+ // target version, determined during this task
+ MinecraftVersion *targetVersion;
};
diff --git a/libmultimc/include/instance.h b/libmultimc/include/instance.h
index 717f8816..f6857cd8 100644
--- a/libmultimc/include/instance.h
+++ b/libmultimc/include/instance.h
@@ -80,16 +80,7 @@ class LIBMULTIMC_EXPORT Instance : public QObject
* This returns true if shouldForceUpdate game is true or if the intended and
* current versions don't match.
*/
- Q_PROPERTY(bool shouldUpdateGame READ shouldUpdateGame STORED false)
-
- /*!
- * Whether or not the game will be forced to update on the next launch.
- * If this is set to true, shouldUpdateGame will be true, regardless of whether or not
- * the current and intended versions match.
- * It should be noted that this is set to false automatically when game updates are run.
- */
- Q_PROPERTY(bool shouldForceUpdateGame READ shouldForceUpdateGame WRITE setShouldForceUpdateGame)
-
+ Q_PROPERTY(bool shouldUpdate READ shouldUpdate WRITE setShouldUpdate)
/*!
* The instance's current version.
@@ -125,8 +116,11 @@ class LIBMULTIMC_EXPORT Instance : public QObject
*/
Q_PROPERTY(qint64 lastCurrentVersionUpdate READ lastCurrentVersionUpdate WRITE setLastCurrentVersionUpdate)
-
-
+ /*!
+ * Is the instance a new launcher instance? Get/Set
+ */
+ Q_PROPERTY(bool isForNewLauncher READ isForNewLauncher WRITE setIsForNewLauncher)
+
// Dirs
//! Path to the instance's .minecraft folder.
Q_PROPERTY(QString minecraftDir READ minecraftDir STORED false)
@@ -236,14 +230,17 @@ public:
virtual QString intendedVersion() const { return settings().get("IntendedJarVersion").toString(); }
virtual void setIntendedVersion(QString val) { settings().set("IntendedJarVersion", val); }
- virtual bool shouldUpdateGame() const
- { return shouldForceUpdateGame() || intendedVersion() != currentVersion(); }
-
- virtual bool shouldForceUpdateGame() const { return settings().get("ShouldForceUpdate").toBool(); }
- virtual void setShouldForceUpdateGame(bool val) { settings().set("ShouldForceUpdate", val); }
-
-
-
+ virtual bool shouldUpdate() const
+ {
+ QVariant var = settings().get("ShouldUpdate");
+ if(!var.isValid() || var.toBool() == false)
+ {
+ return intendedVersion() != currentVersion();
+ }
+ return true;
+ }
+ virtual void setShouldUpdate(bool val) { settings().set("ShouldUpdate", val); }
+
//// Timestamps ////
virtual qint64 lastLaunch() const { return settings().get("lastLaunchTime").value<qint64>(); }
@@ -256,6 +253,15 @@ public:
virtual qint64 lastCurrentVersionUpdate() const { return settings().get("lastVersionUpdate").value<qint64>(); }
virtual void setLastCurrentVersionUpdate(qint64 val) { settings().set("lastVersionUpdate", val); }
+ virtual bool isForNewLauncher()
+ {
+ return settings().get("IsForNewLauncher").value<bool>();
+ }
+
+ virtual void setIsForNewLauncher(bool value = true)
+ {
+ settings().set("IsForNewLauncher", value);
+ }
////// Directories //////
QString minecraftDir() const;
diff --git a/libmultimc/include/library.h b/libmultimc/include/library.h
new file mode 100644
index 00000000..8d97b4a6
--- /dev/null
+++ b/libmultimc/include/library.h
@@ -0,0 +1,219 @@
+/* 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.
+ */
+
+#pragma once
+
+#include <QtCore>
+
+class Library;
+
+enum OpSys
+{
+ Os_Windows,
+ Os_Linux,
+ Os_OSX,
+ Os_Other
+};
+
+OpSys OpSys_fromString(QString);
+
+#ifdef Q_OS_MAC
+ #define currentSystem Os_OSX
+#endif
+
+#ifdef Q_OS_LINUX
+ #define currentSystem Os_Linux
+#endif
+
+#ifdef Q_OS_WIN32
+ #define currentSystem Os_Windows
+#endif
+
+#ifndef currentSystem
+ #define currentSystem Os_Other
+#endif
+
+
+enum RuleAction
+{
+ Allow,
+ Disallow,
+ Defer
+};
+
+RuleAction RuleAction_fromString(QString);
+
+class Rule
+{
+protected:
+ RuleAction m_result;
+ virtual bool applies(Library * parent) = 0;
+public:
+ Rule(RuleAction result)
+ :m_result(result) {}
+ virtual ~Rule(){};
+ RuleAction apply(Library * parent)
+ {
+ if(applies(parent))
+ return m_result;
+ else
+ return Defer;
+ };
+};
+
+class OsRule : public Rule
+{
+private:
+ // the OS
+ OpSys m_system;
+ // the OS version regexp
+ QString m_version_regexp;
+protected:
+ virtual bool applies ( Library* )
+ {
+ return (m_system == currentSystem);
+ }
+ OsRule(RuleAction result, OpSys system, QString version_regexp)
+ : Rule(result), m_system(system), m_version_regexp(version_regexp) {}
+public:
+ static QSharedPointer<OsRule> create(RuleAction result, OpSys system, QString version_regexp)
+ {
+ return QSharedPointer<OsRule> (new OsRule(result, system, version_regexp));
+ }
+};
+
+class ImplicitRule : public Rule
+{
+protected:
+ virtual bool applies ( Library* )
+ {
+ return true;
+ }
+ ImplicitRule(RuleAction result)
+ : Rule(result) {}
+public:
+ static QSharedPointer<ImplicitRule> create(RuleAction result)
+ {
+ return QSharedPointer<ImplicitRule> (new ImplicitRule(result));
+ }
+};
+
+class Library
+{
+private:
+ // basic values used internally (so far)
+ QString m_name;
+ QString m_base_url;
+ QList<QSharedPointer<Rule> > m_rules;
+
+ // derived values used for real things
+ /// where to store the lib locally
+ QString m_storage_path;
+ /// where to download the lib from
+ QString m_download_path;
+ /// is this lib actuall active on the current OS?
+ bool m_is_active;
+
+ // native lib?
+ bool m_is_native;
+ QMap<OpSys, QString> m_native_suffixes;
+public:
+ QStringList extract_excludes;
+
+public:
+ /// finalize the library, processing the input values into derived values and state
+ void finalize()
+ {
+ QStringList parts = m_name.split(':');
+ QString relative = parts[0];
+ relative.replace('.','/');
+ relative += '/' + parts[1] + '/' + parts[2] + '/' + parts[1] + '-' + parts[2];
+ if(!m_is_native)
+ relative += ".jar";
+ else
+ {
+ if(m_native_suffixes.contains(currentSystem))
+ {
+ relative += "-" + m_native_suffixes[currentSystem] + ".jar";
+ }
+ else
+ {
+ // really, bad.
+ relative += ".jar";
+ }
+ }
+ m_storage_path = relative;
+ m_download_path = m_base_url + relative;
+
+ if(m_rules.empty())
+ {
+ m_is_active = true;
+ }
+ else
+ {
+ RuleAction result = Disallow;
+ for(auto rule: m_rules)
+ {
+ RuleAction temp = rule->apply( this );
+ if(temp != Defer)
+ result = temp;
+ }
+ m_is_active = (result == Allow);
+ }
+ if(m_is_native)
+ {
+ m_is_active = m_is_active && m_native_suffixes.contains(currentSystem);
+ }
+ };
+
+ Library(QString name)
+ {
+ m_is_native = false;
+ m_is_native = false;
+ m_name = name;
+ m_base_url = "https://s3.amazonaws.com/Minecraft.Download/libraries/";
+ }
+
+ void setName(QString name)
+ {
+ m_name = name;
+ }
+
+ void setBaseUrl(QString base_url)
+ {
+ m_base_url = base_url;
+ }
+
+ void setIsNative()
+ {
+ m_is_native = true;
+ }
+
+ void addNative(OpSys os, QString suffix)
+ {
+ m_is_native = true;
+ m_native_suffixes[os] = suffix;
+ }
+
+ void setRules(QList<QSharedPointer<Rule> > rules)
+ {
+ m_rules = rules;
+ }
+
+ bool applies()
+ {
+ return m_is_active;
+ }
+};
diff --git a/libmultimc/src/fullversion.cpp b/libmultimc/src/fullversion.cpp
new file mode 100644
index 00000000..53664c2a
--- /dev/null
+++ b/libmultimc/src/fullversion.cpp
@@ -0,0 +1,5 @@
+#include <QtCore>
+#include "fullversion.h"
+#include <library.h>
+
+// ECHO, echo, echo, .... \ No newline at end of file
diff --git a/libmultimc/src/fullversionfactory.cpp b/libmultimc/src/fullversionfactory.cpp
new file mode 100644
index 00000000..bb55b4a9
--- /dev/null
+++ b/libmultimc/src/fullversionfactory.cpp
@@ -0,0 +1,206 @@
+#include "fullversionfactory.h"
+#include "fullversion.h"
+#include <library.h>
+
+class LibraryFinalizer
+{
+public:
+ LibraryFinalizer(QSharedPointer<Library> library)
+ {
+ m_library = library;
+ }
+
+ QSharedPointer<Library> m_library;
+};
+
+// Library rules (if any)
+QList<QSharedPointer<Rule> > FullVersionFactory::parse4rules(QJsonObject & baseObj)
+{
+ QList<QSharedPointer<Rule> > rules;
+ auto rulesVal = baseObj.value("rules");
+ if(rulesVal.isArray())
+ {
+ QJsonArray ruleList = rulesVal.toArray();
+ for(auto ruleVal : ruleList)
+ {
+ QSharedPointer<Rule> rule;
+ if(!ruleVal.isObject())
+ continue;
+ auto ruleObj = ruleVal.toObject();
+ auto actionVal = ruleObj.value("action");
+ if(!actionVal.isString())
+ continue;
+ auto action = RuleAction_fromString(actionVal.toString());
+ if(action == Defer)
+ continue;
+
+ auto osVal = ruleObj.value("os");
+ if(!osVal.isObject())
+ {
+ // add a new implicit action rule
+ rules.append(ImplicitRule::create(action));
+ }
+ else
+ {
+ auto osObj = osVal.toObject();
+ auto osNameVal = osObj.value("name");
+ if(!osNameVal.isString())
+ continue;
+ OpSys requiredOs = OpSys_fromString(osNameVal.toString());
+ QString versionRegex = osObj.value("version").toString();
+ // add a new OS rule
+ rules.append(OsRule::create(action, requiredOs, versionRegex));
+ }
+ }
+ }
+ return rules;
+}
+
+
+QSharedPointer<FullVersion> FullVersionFactory::parse4(QJsonObject root, QSharedPointer<FullVersion> fullVersion)
+{
+ fullVersion->id = root.value("id").toString();
+
+ // if it's on our legacy list, it's legacy
+ if(legacyWhitelist.contains(fullVersion->id))
+ fullVersion->isLegacy = true;
+
+ fullVersion->mainClass = root.value("mainClass").toString();
+ auto procArgsValue = root.value("processArguments");
+ if(procArgsValue.isString())
+ {
+ fullVersion->processArguments = procArgsValue.toString();
+ QString toCompare = fullVersion->processArguments.toLower();
+ if(toCompare == "legacy")
+ {
+ fullVersion->minecraftArguments = " ${auth_player_name} ${auth_session}";
+ fullVersion->isLegacy = true;
+ }
+ else if(toCompare == "username_session")
+ {
+ fullVersion->minecraftArguments = "--username ${auth_player_name} --session ${auth_session}";
+ }
+ else if(toCompare == "username_session_version")
+ {
+ fullVersion->minecraftArguments = "--username ${auth_player_name} --session ${auth_session} --version ${profile_name}";
+ }
+ }
+
+ auto minecraftArgsValue = root.value("minecraftArguments");
+ if(minecraftArgsValue.isString())
+ {
+ fullVersion->minecraftArguments = minecraftArgsValue.toString();
+ }
+
+ fullVersion->releaseTime = root.value("releaseTime").toString();
+ fullVersion->time = root.value("time").toString();
+
+ // Iterate through the list, if it's a list.
+ auto librariesValue = root.value("libraries");
+ if(!librariesValue.isArray())
+ return fullVersion;
+
+ QJsonArray libList = root.value("libraries").toArray();
+ for (auto libVal : libList)
+ {
+ if (!libVal.isObject())
+ {
+ continue;
+ }
+
+ QJsonObject libObj = libVal.toObject();
+
+ // Library name
+ auto nameVal = libObj.value("name");
+ if(!nameVal.isString())
+ continue;
+ QSharedPointer<Library> library(new Library(nameVal.toString()));
+
+ // Extract excludes (if any)
+ auto extractVal = libObj.value("extract");
+ if(extractVal.isObject())
+ {
+ QStringList excludes;
+ auto extractObj = extractVal.toObject();
+ auto excludesVal = extractObj.value("exclude");
+ if(!excludesVal.isArray())
+ goto SKIP_EXTRACTS;
+ auto excludesList = excludesVal.toArray();
+ for(auto excludeVal : excludesList)
+ {
+ if(excludeVal.isString())
+ excludes.append(excludeVal.toString());
+ }
+ library->extract_excludes = excludes;
+ }
+ SKIP_EXTRACTS:
+
+ auto nativesVal = libObj.value("natives");
+ if(nativesVal.isObject())
+ {
+ library->setIsNative();
+ auto nativesObj = nativesVal.toObject();
+ auto iter = nativesObj.begin();
+ while(iter != nativesObj.end())
+ {
+ auto osType = OpSys_fromString(iter.key());
+ if(osType == Os_Other)
+ continue;
+ if(!iter.value().isString())
+ continue;
+ library->addNative(osType, iter.value().toString());
+ iter++;
+ }
+ }
+ library->setRules(parse4rules(libObj));
+ library->finalize();
+ fullVersion->libraries.append(library);
+ }
+ return fullVersion;
+}
+
+QSharedPointer<FullVersion> FullVersionFactory::parse(QByteArray data)
+{
+ QSharedPointer<FullVersion> readVersion(new FullVersion());
+
+ QJsonParseError jsonError;
+ QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
+
+ if (jsonError.error != QJsonParseError::NoError)
+ {
+ error_string = QString( "Error reading version file :") + " " + jsonError.errorString();
+ m_error = FullVersionFactory::ParseError;
+ return QSharedPointer<FullVersion>();
+ }
+
+ if(!jsonDoc.isObject())
+ {
+ error_string = "Error reading version file.";
+ m_error = FullVersionFactory::ParseError;
+ return QSharedPointer<FullVersion>();
+ }
+ QJsonObject root = jsonDoc.object();
+
+ readVersion->minimumLauncherVersion = root.value("minimumLauncherVersion").toDouble();
+ switch(readVersion->minimumLauncherVersion)
+ {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ return parse4(root, readVersion);
+ // ADD MORE HERE :D
+ default:
+ error_string = "Version file was for an unrecognized launcher version. RIP";
+ m_error = FullVersionFactory::UnsupportedVersion;
+ return QSharedPointer<FullVersion>();
+ }
+}
+
+
+FullVersionFactory::FullVersionFactory()
+{
+ m_error = FullVersionFactory::AllOK;
+ legacyWhitelist.append("1.5.1");
+ legacyWhitelist.append("1.5.2");
+}
diff --git a/libmultimc/src/gameupdatetask.cpp b/libmultimc/src/gameupdatetask.cpp
index c718ce71..bae85c17 100644
--- a/libmultimc/src/gameupdatetask.cpp
+++ b/libmultimc/src/gameupdatetask.cpp
@@ -25,40 +25,34 @@
#include <QDebug>
#include "minecraftversionlist.h"
+#include "fullversionfactory.h"
+#include <fullversion.h>
#include "pathutils.h"
-#include "netutils.h"
+
GameUpdateTask::GameUpdateTask(const LoginResponse &response, Instance *inst, QObject *parent) :
Task(parent), m_response(response)
{
m_inst = inst;
m_updateState = StateInit;
- m_currentDownload = 0;
}
void GameUpdateTask::executeTask()
{
updateStatus();
- QNetworkAccessManager networkMgr;
- netMgr = &networkMgr;
-
// Get a pointer to the version object that corresponds to the instance's version.
- MinecraftVersion *targetVersion = (MinecraftVersion *)MinecraftVersionList::getMainList().
+ targetVersion = (MinecraftVersion *)MinecraftVersionList::getMainList().
findVersion(m_inst->intendedVersion());
- Q_ASSERT_X(targetVersion != NULL, "game update", "instance's intended version is not an actual version");
-
- // Make directories
- QDir binDir(m_inst->binDir());
- if (!binDir.exists() && !binDir.mkpath("."))
+ if(targetVersion == NULL)
{
- error("Failed to create bin folder.");
+ //Q_ASSERT_X(targetVersion != NULL, "game update", "instance's intended version is not an actual version");
+ setState(StateFinished);
+ emit gameUpdateComplete(m_response);
return;
}
-
-
/////////////////////////
// BUILD DOWNLOAD LIST //
/////////////////////////
@@ -66,90 +60,150 @@ void GameUpdateTask::executeTask()
setState(StateDetermineURLs);
+ if (targetVersion->launcherVersion() == MinecraftVersion::Launcher16)
+ {
+ determineNewVersion();
+ }
+ else
+ {
+ getLegacyJar();
+ }
+ QEventLoop loop;
+ loop.exec();
+}
+
+void GameUpdateTask::determineNewVersion()
+{
+ QString urlstr("http://s3.amazonaws.com/Minecraft.Download/versions/");
+ urlstr += targetVersion->descriptor() + "/" + targetVersion->descriptor() + ".json";
+ auto dljob = DownloadJob::create(QUrl(urlstr));
+ specificVersionDownloadJob.reset(new JobList());
+ specificVersionDownloadJob->add(dljob);
+ connect(specificVersionDownloadJob.data(), SIGNAL(finished()), SLOT(versionFileFinished()));
+ connect(specificVersionDownloadJob.data(), SIGNAL(failed()), SLOT(versionFileFailed()));
+ connect(specificVersionDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64)));
+ download_queue.enqueue(specificVersionDownloadJob);
+}
+
+void GameUpdateTask::versionFileFinished()
+{
+ JobPtr firstJob = specificVersionDownloadJob->getFirstJob();
+ auto DlJob = firstJob.dynamicCast<DownloadJob>();
+ FullVersionFactory parser;
+ auto version = parser.parse(DlJob->m_data);
- // Add the URL for minecraft.jar
+ if(!version)
+ {
+ error(parser.error_string);
+ exit(0);
+ }
+
+ if(version->isLegacy)
+ {
+ getLegacyJar();
+ return;
+ }
+ // save the version file in $instanceId/version.json and versions/$version/$version.json
+ QString version_id = targetVersion->descriptor();
+ QString mc_dir = m_inst->minecraftDir();
+ QString inst_dir = m_inst->rootDir();
+ QString version1 = PathCombine(inst_dir, "/version.json");
+ QString version2 = QString("versions/") + version_id + "/" + version_id + ".json";
+ DownloadJob::ensurePathExists(version1);
+ DownloadJob::ensurePathExists(version2);
+ QFile vfile1 (version1);
+ QFile vfile2 (version2);
+ vfile1.open(QIODevice::Truncate | QIODevice::WriteOnly );
+ vfile2.open(QIODevice::Truncate | QIODevice::WriteOnly );
+ vfile1.write(DlJob->m_data);
+ vfile2.write(DlJob->m_data);
+ vfile1.close();
+ vfile2.close();
+
+ // download the right jar, save it in versions/$version/$version.jar
+ QString urlstr("http://s3.amazonaws.com/Minecraft.Download/versions/");
+ urlstr += targetVersion->descriptor() + "/" + targetVersion->descriptor() + ".jar";
+ QString targetstr ("versions/");
+ targetstr += targetVersion->descriptor() + "/" + targetVersion->descriptor() + ".jar";
+ auto dljob = DownloadJob::create(QUrl(urlstr), targetstr);
+
+ jarlibDownloadJob.reset(new JobList());
+ jarlibDownloadJob->add(dljob);
+ connect(jarlibDownloadJob.data(), SIGNAL(finished()), SLOT(jarlibFinished()));
+ connect(jarlibDownloadJob.data(), SIGNAL(failed()), SLOT(jarlibFailed()));
+ connect(jarlibDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64)));
+ // determine and download all the libraries, save them in libraries/whatever...
+ download_queue.enqueue(jarlibDownloadJob);
+}
+
+void GameUpdateTask::jarlibFinished()
+{
+ m_inst->setCurrentVersion(targetVersion->descriptor());
+ m_inst->setShouldUpdate(false);
+ m_inst->setIsForNewLauncher(true);
+ exit(1);
+}
+
+void GameUpdateTask::jarlibFailed()
+{
+ error("Failed to download the binary garbage. Try again. Maybe. IF YOU DARE");
+ exit(0);
+}
+
+void GameUpdateTask::versionFileFailed()
+{
+ error("Failed to download the version description. Try again.");
+ exit(0);
+}
+
+
+// this is legacy minecraft...
+void GameUpdateTask::getLegacyJar()
+{
+ // Make directories
+ QDir binDir(m_inst->binDir());
+ if (!binDir.exists() && !binDir.mkpath("."))
+ {
+ error("Failed to create bin folder.");
+ return;
+ }
+
+ // Add the URL for minecraft.jar
// This will be either 'minecraft' or the version number, depending on where
// we're downloading from.
QString jarFilename = "minecraft";
-
- // FIXME: this is NOT enough
if (targetVersion->launcherVersion() == MinecraftVersion::Launcher16)
+ {
jarFilename = targetVersion->descriptor();
+ }
QUrl mcJarURL = targetVersion->downloadURL() + jarFilename + ".jar";
qDebug() << mcJarURL.toString();
- m_downloadList.append(FileToDownload::Create(mcJarURL, PathCombine(m_inst->minecraftDir(), "bin/minecraft.jar")));
-
-
+ auto dljob = DownloadJob::create(mcJarURL, PathCombine(m_inst->minecraftDir(), "bin/minecraft.jar"));
- ////////////////////
- // DOWNLOAD FILES //
- ////////////////////
- setState(StateDownloadFiles);
- for (int i = 0; i < m_downloadList.length(); i++)
- {
- m_currentDownload = i;
- if (!downloadFile(m_downloadList[i]))
- return;
- }
-
-
-
- ///////////////////
- // INSTALL FILES //
- ///////////////////
- setState(StateInstall);
-
- // Nothing to do here yet
+ legacyDownloadJob.reset(new JobList());
+ legacyDownloadJob->add(dljob);
+ connect(legacyDownloadJob.data(), SIGNAL(finished()), SLOT(legacyJarFinished()));
+ connect(legacyDownloadJob.data(), SIGNAL(failed()), SLOT(legacyJarFailed()));
+ connect(legacyDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64)));
-
-
- //////////////
- // FINISHED //
- //////////////
+ download_queue.enqueue(legacyDownloadJob);
+}
+
+
+void GameUpdateTask::legacyJarFinished()
+{
setState(StateFinished);
emit gameUpdateComplete(m_response);
+ m_inst->setIsForNewLauncher(true);
+ exit(1);
}
-bool GameUpdateTask::downloadFile( const FileToDownloadPtr file )
+void GameUpdateTask::legacyJarFailed()
{
- setSubStatus("Downloading " + file->url().toString());
- QNetworkReply *reply = netMgr->get(QNetworkRequest(file->url()));
-
- this->connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
- SLOT(updateDownloadProgress(qint64,qint64)));
-
- NetUtils::waitForNetRequest(reply);
-
- if (reply->error() == QNetworkReply::NoError)
- {
- QString filePath = file->path();
- QFile outFile(filePath);
- if (outFile.exists() && !outFile.remove())
- {
- error("Can't delete old file " + file->path() + ": " + outFile.errorString());
- return false;
- }
-
- if (!outFile.open(QIODevice::WriteOnly))
- {
- error("Can't write to " + file->path() + ": " + outFile.errorString());
- return false;
- }
-
- outFile.write(reply->readAll());
- outFile.close();
- }
- else
- {
- error("Can't download " + file->url().toString() + ": " + reply->errorString());
- return false;
- }
-
- // TODO: Check file integrity after downloading.
-
- return true;
+ emit gameUpdateError("failed to download the minecraft.jar");
+ exit(0);
}
int GameUpdateTask::state() const
@@ -223,22 +277,7 @@ void GameUpdateTask::error(const QString &msg)
void GameUpdateTask::updateDownloadProgress(qint64 current, qint64 total)
{
// The progress on the current file is current / total
- float currentDLProgress = (float) current / (float) total; // Cast ALL the values!
-
- // The overall progress is (current progress + files downloaded) / total files to download
- float overallDLProgress = ((currentDLProgress + m_currentDownload) / (float) m_downloadList.length());
-
- // Multiply by 100 to make it a percentage.
- setProgress((int)(overallDLProgress * 100));
-}
-
-FileToDownloadPtr FileToDownload::Create(const QUrl &url, const QString &path, QObject *parent)
-{
- return FileToDownloadPtr(new FileToDownload (url, path, parent));
+ float currentDLProgress = (float) current / (float) total;
+ setProgress((int)(currentDLProgress * 100)); // convert to percentage
}
-FileToDownload::FileToDownload(const QUrl &url, const QString &path, QObject *parent) :
- QObject(parent), m_dlURL(url), m_dlPath(path)
-{
-
-}
diff --git a/libmultimc/src/instance.cpp b/libmultimc/src/instance.cpp
index 08cd6605..5fdb5064 100644
--- a/libmultimc/src/instance.cpp
+++ b/libmultimc/src/instance.cpp
@@ -34,7 +34,8 @@ Instance::Instance(const QString &rootDir, QObject *parent) :
settings().registerSetting(new Setting("iconKey", "default"));
settings().registerSetting(new Setting("notes", ""));
settings().registerSetting(new Setting("NeedsRebuild", true));
- settings().registerSetting(new Setting("ShouldForceUpdate", false));
+ settings().registerSetting(new Setting("IsForNewLauncher", false));
+ settings().registerSetting(new Setting("ShouldUpdate", false));
settings().registerSetting(new Setting("JarVersion", "Unknown"));
settings().registerSetting(new Setting("LwjglVersion", "2.9.0"));
settings().registerSetting(new Setting("IntendedJarVersion", ""));
@@ -62,6 +63,18 @@ Instance::Instance(const QString &rootDir, QObject *parent) :
// Auto login
settings().registerSetting(new OverrideSetting("AutoLogin", globalSettings->getSetting("AutoLogin")));
+
+ // Console
+ settings().registerSetting(new OverrideSetting("ShowConsole", globalSettings->getSetting("ShowConsole")));
+ settings().registerSetting(new OverrideSetting("AutoCloseConsole", globalSettings->getSetting("AutoCloseConsole")));
+
+ // Overrides
+ settings().registerSetting(new Setting("OverrideConsole", false));
+ settings().registerSetting(new Setting("OverrideWindow", false));
+ settings().registerSetting(new Setting("OverrideLogin", false));
+ settings().registerSetting(new Setting("OverrideMemory", false));
+ settings().registerSetting(new Setting("OverrideJava", false));
+ settings().registerSetting(new Setting("OverrideCommands", false));
}
QString Instance::id() const
diff --git a/libmultimc/src/library.cpp b/libmultimc/src/library.cpp
new file mode 100644
index 00000000..9d4cc6e3
--- /dev/null
+++ b/libmultimc/src/library.cpp
@@ -0,0 +1,37 @@
+/* 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 "include/library.h"
+
+RuleAction RuleAction_fromString(QString name)
+{
+ if(name == "allow")
+ return Allow;
+ if(name == "disallow")
+ return Disallow;
+ return Defer;
+}
+
+OpSys OpSys_fromString(QString name)
+{
+ if(name == "linux")
+ return Os_Linux;
+ if(name == "windows")
+ return Os_Windows;
+ if(name == "osx")
+ return Os_OSX;
+ return Os_Other;
+}
+// default url for lib:
diff --git a/libsettings/include/inisettingsobject.h b/libsettings/include/inisettingsobject.h
index 36c8e4bd..03d6fe05 100644
--- a/libsettings/include/inisettingsobject.h
+++ b/libsettings/include/inisettingsobject.h
@@ -47,6 +47,7 @@ public:
protected slots:
virtual void changeSetting(const Setting &setting, QVariant value);
+ virtual void resetSetting ( const Setting& setting );
protected:
virtual QVariant retrieveValue(const Setting &setting);
diff --git a/libsettings/include/setting.h b/libsettings/include/setting.h
index 36709729..a161ab50 100644
--- a/libsettings/include/setting.h
+++ b/libsettings/include/setting.h
@@ -84,6 +84,12 @@ signals:
*/
void settingChanged(const Setting &setting, QVariant value);
+ /*!
+ * \brief Signal emitted when this Setting object's value resets to default.
+ * \param setting A reference to the Setting that changed.
+ */
+ void settingReset(const Setting &setting);
+
public slots:
/*!
* \brief Changes the setting's value.
@@ -93,6 +99,13 @@ public slots:
*/
virtual void set(QVariant value);
+ /*!
+ * \brief Reset the setting to default
+ * This is done by emitting the settingReset() signal which will then be
+ * handled by the SettingsObject object and cause the setting to change.
+ * \param value The new value.
+ */
+ virtual void reset();
protected:
QString m_id;
QVariant m_defVal;
diff --git a/libsettings/include/settingsobject.h b/libsettings/include/settingsobject.h
index 23f0d644..a2f03699 100644
--- a/libsettings/include/settingsobject.h
+++ b/libsettings/include/settingsobject.h
@@ -100,6 +100,11 @@ public:
*/
virtual bool set(const QString &id, QVariant value);
+ /*!
+ * \brief Reverts the setting with the given ID to default.
+ * \param id The ID of the setting to reset.
+ */
+ virtual void reset(const QString &id) const;
/*!
* \brief Gets a QList with pointers to all of the registered settings.
@@ -125,6 +130,14 @@ signals:
*/
void settingChanged(const Setting &setting, QVariant value);
+ /*!
+ * \brief Signal emitted when one of this SettingsObject object's settings resets.
+ * This is usually just connected directly to each Setting object's
+ * settingReset() signals.
+ * \param setting A reference to the Setting object that changed.
+ */
+ void settingReset(const Setting &setting);
+
protected slots:
/*!
* \brief Changes a setting.
@@ -136,6 +149,15 @@ protected slots:
*/
virtual void changeSetting(const Setting &setting, QVariant value) = 0;
+ /*!
+ * \brief Resets a setting.
+ * This slot is usually connected to each Setting object's
+ * settingReset() signal. The signal is emitted, causing this slot
+ * to update the setting's value in the config file.
+ * \param setting A reference to the Setting object that changed.
+ */
+ virtual void resetSetting(const Setting &setting) = 0;
+
protected:
/*!
* \brief Connects the necessary signals to the given Setting.
diff --git a/libsettings/src/inisettingsobject.cpp b/libsettings/src/inisettingsobject.cpp
index 17b132a3..854421b6 100644
--- a/libsettings/src/inisettingsobject.cpp
+++ b/libsettings/src/inisettingsobject.cpp
@@ -40,6 +40,15 @@ void INISettingsObject::changeSetting(const Setting &setting, QVariant value)
}
}
+void INISettingsObject::resetSetting ( const Setting& setting )
+{
+ if (contains(setting.id()))
+ {
+ m_ini.remove(setting.configKey());
+ m_ini.saveFile(m_filePath);
+ }
+}
+
QVariant INISettingsObject::retrieveValue(const Setting &setting)
{
if (contains(setting.id()))
diff --git a/libsettings/src/setting.cpp b/libsettings/src/setting.cpp
index 1a4f9e13..8e60af06 100644
--- a/libsettings/src/setting.cpp
+++ b/libsettings/src/setting.cpp
@@ -47,3 +47,8 @@ void Setting::set(QVariant value)
{
emit settingChanged(*this, value);
}
+
+void Setting::reset()
+{
+ emit settingReset(*this);
+}
diff --git a/libsettings/src/settingsobject.cpp b/libsettings/src/settingsobject.cpp
index 98c7b479..bf7b8825 100644
--- a/libsettings/src/settingsobject.cpp
+++ b/libsettings/src/settingsobject.cpp
@@ -49,7 +49,7 @@ bool SettingsObject::registerSetting(Setting *setting)
// Connect signals.
connectSignals(*setting);
- qDebug(QString("Registered setting %1.").arg(setting->id()).toUtf8());
+ // qDebug(QString("Registered setting %1.").arg(setting->id()).toUtf8());
return true;
}
@@ -98,6 +98,14 @@ bool SettingsObject::set(const QString &id, QVariant value)
}
}
+void SettingsObject::reset(const QString &id) const
+{
+ Setting *setting = getSetting(id);
+ if(setting)
+ setting->reset();
+}
+
+
QList<Setting *> SettingsObject::getSettings()
{
return m_settings.values();
@@ -115,6 +123,11 @@ void SettingsObject::connectSignals(const Setting &setting)
SLOT(changeSetting(const Setting &, QVariant)));
connect(&setting, SIGNAL(settingChanged(const Setting &, QVariant)),
SIGNAL(settingChanged(const Setting &, QVariant)));
+
+ connect(&setting, SIGNAL(settingReset(Setting)),
+ SLOT(resetSetting(const Setting &)));
+ connect(&setting, SIGNAL(settingReset(Setting)),
+ SIGNAL(settingReset(const Setting &)));
}
void SettingsObject::disconnectSignals(const Setting &setting)
@@ -123,4 +136,9 @@ void SettingsObject::disconnectSignals(const Setting &setting)
this, SLOT(changeSetting(const Setting &, QVariant)));
setting.disconnect(SIGNAL(settingChanged(const Setting &, QVariant)),
this, SIGNAL(settingChanged(const Setting &, QVariant)));
+
+ setting.disconnect(SIGNAL(settingReset(const Setting &, QVariant)),
+ this, SLOT(resetSetting(const Setting &, QVariant)));
+ setting.disconnect(SIGNAL(settingReset(const Setting &, QVariant)),
+ this, SIGNAL(settingReset(const Setting &, QVariant)));
}
diff --git a/libutil/include/dlqueue.h b/libutil/include/dlqueue.h
index 9041e762..69fc22a6 100644
--- a/libutil/include/dlqueue.h
+++ b/libutil/include/dlqueue.h
@@ -5,13 +5,16 @@
/**
* A single file for the downloader/cache to process.
*/
-class DownloadJob : public Job
+class LIBUTIL_EXPORT DownloadJob : public Job
{
Q_OBJECT
public:
DownloadJob(QUrl url, QString rel_target_path = QString(), QString expected_md5 = QString());
static JobPtr create(QUrl url, QString rel_target_path = QString(), QString expected_md5 = QString());
+
+public:
+ static bool ensurePathExists(QString filenamepath);
public slots:
virtual void start();
@@ -37,8 +40,10 @@ public:
/// save to file?
bool m_save_to_file;
+ /// is the saving file already open?
+ bool m_opened_for_saving;
/// if saving to file, use the one specified in this string
- QString m_rel_target_path;
+ QString m_target_path;
/// this is the output file, if any
QFile m_output_file;
/// if not saving to file, downloaded data is placed here
diff --git a/libutil/include/jobqueue.h b/libutil/include/jobqueue.h
index 061686f6..26f49307 100644
--- a/libutil/include/jobqueue.h
+++ b/libutil/include/jobqueue.h
@@ -1,5 +1,6 @@
#pragma once
#include <QtCore>
+#include "libutil_config.h"
enum JobStatus
{
@@ -11,7 +12,7 @@ enum JobStatus
class JobList;
-class Job : public QObject
+class LIBUTIL_EXPORT Job : public QObject
{
Q_OBJECT
protected:
@@ -30,7 +31,7 @@ typedef QSharedPointer<Job> JobPtr;
/**
* A list of jobs, to be processed one by one.
*/
-class JobList : public QObject
+class LIBUTIL_EXPORT JobList : public QObject
{
friend class JobListQueue;
Q_OBJECT
@@ -127,7 +128,7 @@ typedef QSharedPointer<JobList> JobListPtr;
/**
* A queue of job lists! The job lists fail or finish as units.
*/
-class JobListQueue : public QObject
+class LIBUTIL_EXPORT JobListQueue : public QObject
{
Q_OBJECT
public:
diff --git a/libutil/src/dlqueue.cpp b/libutil/src/dlqueue.cpp
index dfc51f36..1ef8e212 100644
--- a/libutil/src/dlqueue.cpp
+++ b/libutil/src/dlqueue.cpp
@@ -1,20 +1,28 @@
#include "include/dlqueue.h"
-DownloadJob::DownloadJob ( QUrl url, QString rel_target_path, QString expected_md5 )
+DownloadJob::DownloadJob ( QUrl url, QString target_path, QString expected_md5 )
:Job()
{
m_url = url;
- m_rel_target_path = rel_target_path;
+ m_target_path = target_path;
m_expected_md5 = expected_md5;
m_check_md5 = m_expected_md5.size();
- m_save_to_file = m_rel_target_path.size();
+ m_save_to_file = m_target_path.size();
m_status = Job_NotStarted;
+ m_opened_for_saving = false;
}
-JobPtr DownloadJob::create ( QUrl url, QString rel_target_path, QString expected_md5 )
+JobPtr DownloadJob::create ( QUrl url, QString target_path, QString expected_md5 )
{
- return JobPtr ( new DownloadJob ( url, rel_target_path, expected_md5 ) );
+ return JobPtr ( new DownloadJob ( url, target_path, expected_md5 ) );
+}
+
+bool DownloadJob::ensurePathExists(QString filenamepath)
+{
+ QFileInfo a ( filenamepath );
+ QDir dir;
+ return (dir.mkpath ( a.path() ));
}
void DownloadJob::start()
@@ -22,47 +30,35 @@ void DownloadJob::start()
m_manager.reset ( new QNetworkAccessManager() );
if ( m_save_to_file )
{
- QString filename = m_rel_target_path;
+ QString filename = m_target_path;
m_output_file.setFileName ( filename );
- // if there already is a file and md5 checking is in effect
- if ( m_output_file.exists() && m_check_md5 )
+ // if there already is a file and md5 checking is in effect and it can be opened
+ if ( m_output_file.exists() && m_output_file.open ( QIODevice::ReadOnly ) )
{
- // and it can be opened
- if ( m_output_file.open ( QIODevice::ReadOnly ) )
+ // check the md5 against the expected one
+ QString hash = QCryptographicHash::hash ( m_output_file.readAll(), QCryptographicHash::Md5 ).toHex().constData();
+ m_output_file.close();
+ // skip this file if they match
+ if ( m_check_md5 && hash == m_expected_md5 )
{
- // check the md5 against the expected one
- QString hash = QCryptographicHash::hash ( m_output_file.readAll(), QCryptographicHash::Md5 ).toHex().constData();
- m_output_file.close();
- // skip this file if they match
- if ( hash == m_expected_md5 )
- {
- qDebug() << "Skipping " << m_url.toString() << ": md5 match.";
- emit finish();
- return;
- }
+ qDebug() << "Skipping " << m_url.toString() << ": md5 match.";
+ emit finish();
+ return;
+ }
+ else
+ {
+ m_expected_md5 = hash;
}
}
- QFileInfo a ( filename );
- QDir dir;
- if ( !dir.mkpath ( a.path() ) )
- {
- /*
- * error when making the folder structure
- */
- emit fail();
- return;
- }
- if ( !m_output_file.open ( QIODevice::WriteOnly ) )
+ if(!ensurePathExists(filename))
{
- /*
- * Can't open the file... the job failed
- */
emit fail();
return;
}
}
qDebug() << "Downloading " << m_url.toString();
QNetworkRequest request ( m_url );
+ request.setRawHeader(QString("If-None-Match").toLatin1(), m_expected_md5.toLatin1());
QNetworkReply * rep = m_manager->get ( request );
m_reply = QSharedPointer<QNetworkReply> ( rep, &QObject::deleteLater );
connect ( rep, SIGNAL ( downloadProgress ( qint64,qint64 ) ), SLOT ( downloadProgress ( qint64,qint64 ) ) );
@@ -121,8 +117,21 @@ void DownloadJob::downloadFinished()
void DownloadJob::downloadReadyRead()
{
- if ( m_save_to_file )
+ if( m_save_to_file )
{
+ if(!m_opened_for_saving)
+ {
+ if ( !m_output_file.open ( QIODevice::WriteOnly ) )
+ {
+ /*
+ * Can't open the file... the job failed
+ */
+ m_reply->abort();
+ emit fail();
+ return;
+ }
+ m_opened_for_saving = true;
+ }
m_output_file.write ( m_reply->readAll() );
}
}