summaryrefslogtreecommitdiffstats
path: root/application
diff options
context:
space:
mode:
authorJan Dalheimer <jan@dalheimer.de>2016-04-06 23:09:30 +0200
committerPetr Mrázek <peterix@gmail.com>2016-04-30 23:59:23 +0200
commit00e5968bd28ab1df33b3a39dbac8cda99aa2a0d2 (patch)
treec930ca4f0edae9bb2bbd1a9ce2fddb2ca5a7bf32 /application
parent5ae3b2c11416eb897a08b0d9531843d0357332f8 (diff)
downloadMultiMC-00e5968bd28ab1df33b3a39dbac8cda99aa2a0d2.tar
MultiMC-00e5968bd28ab1df33b3a39dbac8cda99aa2a0d2.tar.gz
MultiMC-00e5968bd28ab1df33b3a39dbac8cda99aa2a0d2.tar.lz
MultiMC-00e5968bd28ab1df33b3a39dbac8cda99aa2a0d2.tar.xz
MultiMC-00e5968bd28ab1df33b3a39dbac8cda99aa2a0d2.zip
NOISSUE Add a skeleton of the wonko system
Diffstat (limited to 'application')
-rw-r--r--application/BuildConfig.cpp.in1
-rw-r--r--application/BuildConfig.h5
-rw-r--r--application/CMakeLists.txt9
-rw-r--r--application/VersionProxyModel.cpp11
-rw-r--r--application/WonkoGui.cpp74
-rw-r--r--application/WonkoGui.h28
-rw-r--r--application/dialogs/ProgressDialog.cpp12
-rw-r--r--application/dialogs/ProgressDialog.h3
-rw-r--r--application/pages/global/WonkoPage.cpp240
-rw-r--r--application/pages/global/WonkoPage.h57
-rw-r--r--application/pages/global/WonkoPage.ui252
-rw-r--r--application/resources/multimc/16x16/looney.pngbin0 -> 802 bytes
-rw-r--r--application/resources/multimc/256x256/looney.pngbin0 -> 68175 bytes
-rw-r--r--application/resources/multimc/32x32/looney.pngbin0 -> 2147 bytes
-rw-r--r--application/resources/multimc/64x64/looney.pngbin0 -> 6838 bytes
-rw-r--r--application/resources/multimc/multimc.qrc6
16 files changed, 692 insertions, 6 deletions
diff --git a/application/BuildConfig.cpp.in b/application/BuildConfig.cpp.in
index be1797cb..62bf53d7 100644
--- a/application/BuildConfig.cpp.in
+++ b/application/BuildConfig.cpp.in
@@ -32,6 +32,7 @@ Config::Config()
VERSION_STR = "@MultiMC_VERSION_STRING@";
NEWS_RSS_URL = "@MultiMC_NEWS_RSS_URL@";
PASTE_EE_KEY = "@MultiMC_PASTE_EE_API_KEY@";
+ WONKO_ROOT_URL = "@MultiMC_WONKO_ROOT_URL@";
}
QString Config::printableVersionString() const
diff --git a/application/BuildConfig.h b/application/BuildConfig.h
index edba18e3..64d07065 100644
--- a/application/BuildConfig.h
+++ b/application/BuildConfig.h
@@ -58,6 +58,11 @@ public:
QString PASTE_EE_KEY;
/**
+ * Root URL for wonko things. Other wonko URLs will be resolved relative to this.
+ */
+ QString WONKO_ROOT_URL;
+
+ /**
* \brief Converts the Version to a string.
* \return The version number in string format (major.minor.revision.build).
*/
diff --git a/application/CMakeLists.txt b/application/CMakeLists.txt
index e3cadf74..5983fb42 100644
--- a/application/CMakeLists.txt
+++ b/application/CMakeLists.txt
@@ -26,6 +26,10 @@ set(MultiMC_PASTE_EE_API_KEY "" CACHE STRING "API key you can get from paste.ee
#### Check the current Git commit and branch
include(GetGitRevisionDescription)
get_git_head_revision(MultiMC_GIT_REFSPEC MultiMC_GIT_COMMIT)
+
+# Root URL for wonko files
+set(MultiMC_WONKO_ROOT_URL "" CACHE STRING "Root URL for wonko stuff")
+
message(STATUS "Git commit: ${MultiMC_GIT_COMMIT}")
message(STATUS "Git refspec: ${MultiMC_GIT_REFSPEC}")
@@ -99,6 +103,8 @@ SET(MULTIMC_SOURCES
VersionProxyModel.cpp
ColorCache.h
ColorCache.cpp
+ WonkoGui.h
+ WonkoGui.cpp
# GUI - windows
MainWindow.h
@@ -163,6 +169,8 @@ SET(MULTIMC_SOURCES
pages/global/ProxyPage.h
pages/global/PasteEEPage.cpp
pages/global/PasteEEPage.h
+ pages/global/WonkoPage.cpp
+ pages/global/WonkoPage.h
# GUI - dialogs
dialogs/AboutDialog.cpp
@@ -256,6 +264,7 @@ SET(MULTIMC_UIS
pages/global/MultiMCPage.ui
pages/global/ProxyPage.ui
pages/global/PasteEEPage.ui
+ pages/global/WonkoPage.ui
# Dialogs
dialogs/CopyInstanceDialog.ui
diff --git a/application/VersionProxyModel.cpp b/application/VersionProxyModel.cpp
index 70894592..22df7e09 100644
--- a/application/VersionProxyModel.cpp
+++ b/application/VersionProxyModel.cpp
@@ -11,6 +11,8 @@ public:
VersionFilterModel(VersionProxyModel *parent) : QSortFilterProxyModel(parent)
{
m_parent = parent;
+ setSortRole(BaseVersionList::SortRole);
+ sort(0, Qt::DescendingOrder);
}
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
@@ -30,14 +32,11 @@ public:
auto versionString = data.toString();
if(it.value().exact)
{
- if (versionString != it.value().string)
- {
- return false;
- }
+ return versionString == it.value().string;
}
- else if (!versionIsInInterval(versionString, it.value().string))
+ else
{
- return false;
+ return versionIsInInterval(versionString, it.value().string);
}
}
default:
diff --git a/application/WonkoGui.cpp b/application/WonkoGui.cpp
new file mode 100644
index 00000000..4d376fdc
--- /dev/null
+++ b/application/WonkoGui.cpp
@@ -0,0 +1,74 @@
+#include "WonkoGui.h"
+
+#include "dialogs/ProgressDialog.h"
+#include "wonko/WonkoIndex.h"
+#include "wonko/WonkoVersionList.h"
+#include "wonko/WonkoVersion.h"
+#include "Env.h"
+
+WonkoIndexPtr Wonko::ensureIndexLoaded(QWidget *parent)
+{
+ if (!ENV.wonkoIndex()->isLocalLoaded())
+ {
+ ProgressDialog(parent).execWithTask(ENV.wonkoIndex()->localUpdateTask());
+ if (!ENV.wonkoIndex()->isRemoteLoaded() && ENV.wonkoIndex()->lists().size() == 0)
+ {
+ ProgressDialog(parent).execWithTask(ENV.wonkoIndex()->remoteUpdateTask());
+ }
+ }
+ return ENV.wonkoIndex();
+}
+
+WonkoVersionListPtr Wonko::ensureVersionListExists(const QString &uid, QWidget *parent)
+{
+ ensureIndexLoaded(parent);
+ if (!ENV.wonkoIndex()->isRemoteLoaded() && !ENV.wonkoIndex()->hasUid(uid))
+ {
+ ProgressDialog(parent).execWithTask(ENV.wonkoIndex()->remoteUpdateTask());
+ }
+ return ENV.wonkoIndex()->getList(uid);
+}
+WonkoVersionListPtr Wonko::ensureVersionListLoaded(const QString &uid, QWidget *parent)
+{
+ WonkoVersionListPtr list = ensureVersionListExists(uid, parent);
+ if (!list)
+ {
+ return nullptr;
+ }
+ if (!list->isLocalLoaded())
+ {
+ ProgressDialog(parent).execWithTask(list->localUpdateTask());
+ if (!list->isLocalLoaded())
+ {
+ ProgressDialog(parent).execWithTask(list->remoteUpdateTask());
+ }
+ }
+ return list->isComplete() ? list : nullptr;
+}
+
+WonkoVersionPtr Wonko::ensureVersionExists(const QString &uid, const QString &version, QWidget *parent)
+{
+ WonkoVersionListPtr list = ensureVersionListLoaded(uid, parent);
+ if (!list)
+ {
+ return nullptr;
+ }
+ return list->getVersion(version);
+}
+WonkoVersionPtr Wonko::ensureVersionLoaded(const QString &uid, const QString &version, QWidget *parent, const UpdateType update)
+{
+ WonkoVersionPtr vptr = ensureVersionExists(uid, version, parent);
+ if (!vptr)
+ {
+ return nullptr;
+ }
+ if (!vptr->isLocalLoaded() || update == AlwaysUpdate)
+ {
+ ProgressDialog(parent).execWithTask(vptr->localUpdateTask());
+ if (!vptr->isLocalLoaded() || update == AlwaysUpdate)
+ {
+ ProgressDialog(parent).execWithTask(vptr->remoteUpdateTask());
+ }
+ }
+ return vptr->isComplete() ? vptr : nullptr;
+}
diff --git a/application/WonkoGui.h b/application/WonkoGui.h
new file mode 100644
index 00000000..2b87b819
--- /dev/null
+++ b/application/WonkoGui.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <memory>
+
+class QWidget;
+class QString;
+
+using WonkoIndexPtr = std::shared_ptr<class WonkoIndex>;
+using WonkoVersionListPtr = std::shared_ptr<class WonkoVersionList>;
+using WonkoVersionPtr = std::shared_ptr<class WonkoVersion>;
+
+namespace Wonko
+{
+enum UpdateType
+{
+ AlwaysUpdate,
+ UpdateIfNeeded
+};
+
+/// Ensures that the index has been loaded, either from the local cache or remotely
+WonkoIndexPtr ensureIndexLoaded(QWidget *parent);
+/// Ensures that the given uid exists. Returns a nullptr if it doesn't.
+WonkoVersionListPtr ensureVersionListExists(const QString &uid, QWidget *parent);
+/// Ensures that the given uid exists and is loaded, either from the local cache or remotely. Returns nullptr if it doesn't exist or couldn't be loaded.
+WonkoVersionListPtr ensureVersionListLoaded(const QString &uid, QWidget *parent);
+WonkoVersionPtr ensureVersionExists(const QString &uid, const QString &version, QWidget *parent);
+WonkoVersionPtr ensureVersionLoaded(const QString &uid, const QString &version, QWidget *parent, const UpdateType update = UpdateIfNeeded);
+}
diff --git a/application/dialogs/ProgressDialog.cpp b/application/dialogs/ProgressDialog.cpp
index 17ab79cd..5d7c7968 100644
--- a/application/dialogs/ProgressDialog.cpp
+++ b/application/dialogs/ProgressDialog.cpp
@@ -97,6 +97,18 @@ int ProgressDialog::execWithTask(Task *task)
}
}
+// TODO: only provide the unique_ptr overloads
+int ProgressDialog::execWithTask(std::unique_ptr<Task> &&task)
+{
+ connect(this, &ProgressDialog::destroyed, task.get(), &Task::deleteLater);
+ return execWithTask(task.release());
+}
+int ProgressDialog::execWithTask(std::unique_ptr<Task> &task)
+{
+ connect(this, &ProgressDialog::destroyed, task.get(), &Task::deleteLater);
+ return execWithTask(task.release());
+}
+
bool ProgressDialog::handleImmediateResult(QDialog::DialogCode &result)
{
if(task->isFinished())
diff --git a/application/dialogs/ProgressDialog.h b/application/dialogs/ProgressDialog.h
index 9ddbceb1..28d4e639 100644
--- a/application/dialogs/ProgressDialog.h
+++ b/application/dialogs/ProgressDialog.h
@@ -16,6 +16,7 @@
#pragma once
#include <QDialog>
+#include <memory>
class Task;
@@ -35,6 +36,8 @@ public:
void updateSize();
int execWithTask(Task *task);
+ int execWithTask(std::unique_ptr<Task> &&task);
+ int execWithTask(std::unique_ptr<Task> &task);
void setSkipButton(bool present, QString label = QString());
diff --git a/application/pages/global/WonkoPage.cpp b/application/pages/global/WonkoPage.cpp
new file mode 100644
index 00000000..21de2347
--- /dev/null
+++ b/application/pages/global/WonkoPage.cpp
@@ -0,0 +1,240 @@
+/* Copyright 2015 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 "WonkoPage.h"
+#include "ui_WonkoPage.h"
+
+#include <QDateTime>
+#include <QSortFilterProxyModel>
+#include <QRegularExpression>
+
+#include "dialogs/ProgressDialog.h"
+#include "VersionProxyModel.h"
+
+#include "wonko/WonkoIndex.h"
+#include "wonko/WonkoVersionList.h"
+#include "wonko/WonkoVersion.h"
+#include "Env.h"
+#include "MultiMC.h"
+
+static QString formatRequires(const WonkoVersionPtr &version)
+{
+ QStringList lines;
+ for (const WonkoReference &ref : version->requires())
+ {
+ const QString readable = ENV.wonkoIndex()->hasUid(ref.uid()) ? ENV.wonkoIndex()->getList(ref.uid())->humanReadable() : ref.uid();
+ if (ref.version().isEmpty())
+ {
+ lines.append(readable);
+ }
+ else
+ {
+ lines.append(QString("%1 (%2)").arg(readable, ref.version()));
+ }
+ }
+ return lines.join('\n');
+}
+
+WonkoPage::WonkoPage(QWidget *parent) :
+ QWidget(parent),
+ ui(new Ui::WonkoPage)
+{
+ ui->setupUi(this);
+ ui->tabWidget->tabBar()->hide();
+
+ m_fileProxy = new QSortFilterProxyModel(this);
+ m_fileProxy->setSortRole(Qt::DisplayRole);
+ m_fileProxy->setSortCaseSensitivity(Qt::CaseInsensitive);
+ m_fileProxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
+ m_fileProxy->setFilterRole(Qt::DisplayRole);
+ m_fileProxy->setFilterKeyColumn(0);
+ m_fileProxy->sort(0);
+ m_fileProxy->setSourceModel(ENV.wonkoIndex().get());
+ ui->indexView->setModel(m_fileProxy);
+
+ m_filterProxy = new QSortFilterProxyModel(this);
+ m_filterProxy->setSortRole(WonkoVersionList::SortRole);
+ m_filterProxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
+ m_filterProxy->setFilterRole(Qt::DisplayRole);
+ m_filterProxy->setFilterKeyColumn(0);
+ m_filterProxy->sort(0, Qt::DescendingOrder);
+ ui->versionsView->setModel(m_filterProxy);
+
+ m_versionProxy = new VersionProxyModel(this);
+ m_filterProxy->setSourceModel(m_versionProxy);
+
+ connect(ui->indexView->selectionModel(), &QItemSelectionModel::currentChanged, this, &WonkoPage::updateCurrentVersionList);
+ connect(ui->versionsView->selectionModel(), &QItemSelectionModel::currentChanged, this, &WonkoPage::updateVersion);
+ connect(m_filterProxy, &QSortFilterProxyModel::dataChanged, this, &WonkoPage::versionListDataChanged);
+
+ updateCurrentVersionList(QModelIndex());
+ updateVersion();
+}
+
+WonkoPage::~WonkoPage()
+{
+ delete ui;
+}
+
+QIcon WonkoPage::icon() const
+{
+ return MMC->getThemedIcon("looney");
+}
+
+void WonkoPage::on_refreshIndexBtn_clicked()
+{
+ ProgressDialog(this).execWithTask(ENV.wonkoIndex()->remoteUpdateTask());
+}
+void WonkoPage::on_refreshFileBtn_clicked()
+{
+ WonkoVersionListPtr list = ui->indexView->currentIndex().data(WonkoIndex::ListPtrRole).value<WonkoVersionListPtr>();
+ if (!list)
+ {
+ return;
+ }
+ ProgressDialog(this).execWithTask(list->remoteUpdateTask());
+}
+void WonkoPage::on_refreshVersionBtn_clicked()
+{
+ WonkoVersionPtr version = ui->versionsView->currentIndex().data(WonkoVersionList::WonkoVersionPtrRole).value<WonkoVersionPtr>();
+ if (!version)
+ {
+ return;
+ }
+ ProgressDialog(this).execWithTask(version->remoteUpdateTask());
+}
+
+void WonkoPage::on_fileSearchEdit_textChanged(const QString &search)
+{
+ if (search.isEmpty())
+ {
+ m_fileProxy->setFilterFixedString(QString());
+ }
+ else
+ {
+ QStringList parts = search.split(' ');
+ std::transform(parts.begin(), parts.end(), parts.begin(), &QRegularExpression::escape);
+ m_fileProxy->setFilterRegExp(".*" + parts.join(".*") + ".*");
+ }
+}
+void WonkoPage::on_versionSearchEdit_textChanged(const QString &search)
+{
+ if (search.isEmpty())
+ {
+ m_filterProxy->setFilterFixedString(QString());
+ }
+ else
+ {
+ QStringList parts = search.split(' ');
+ std::transform(parts.begin(), parts.end(), parts.begin(), &QRegularExpression::escape);
+ m_filterProxy->setFilterRegExp(".*" + parts.join(".*") + ".*");
+ }
+}
+
+void WonkoPage::updateCurrentVersionList(const QModelIndex &index)
+{
+ if (index.isValid())
+ {
+ WonkoVersionListPtr list = index.data(WonkoIndex::ListPtrRole).value<WonkoVersionListPtr>();
+ ui->versionsBox->setEnabled(true);
+ ui->refreshFileBtn->setEnabled(true);
+ ui->fileUidLabel->setEnabled(true);
+ ui->fileUid->setText(list->uid());
+ ui->fileNameLabel->setEnabled(true);
+ ui->fileName->setText(list->name());
+ m_versionProxy->setSourceModel(list.get());
+ ui->refreshFileBtn->setText(tr("Refresh %1").arg(list->humanReadable()));
+
+ if (!list->isLocalLoaded())
+ {
+ std::unique_ptr<Task> task = list->localUpdateTask();
+ connect(task.get(), &Task::finished, this, [this, list]()
+ {
+ if (list->count() == 0 && !list->isRemoteLoaded())
+ {
+ ProgressDialog(this).execWithTask(list->remoteUpdateTask());
+ }
+ });
+ ProgressDialog(this).execWithTask(task);
+ }
+ }
+ else
+ {
+ ui->versionsBox->setEnabled(false);
+ ui->refreshFileBtn->setEnabled(false);
+ ui->fileUidLabel->setEnabled(false);
+ ui->fileUid->clear();
+ ui->fileNameLabel->setEnabled(false);
+ ui->fileName->clear();
+ m_versionProxy->setSourceModel(nullptr);
+ ui->refreshFileBtn->setText(tr("Refresh ___"));
+ }
+}
+
+void WonkoPage::versionListDataChanged(const QModelIndex &tl, const QModelIndex &br)
+{
+ if (QItemSelection(tl, br).contains(ui->versionsView->currentIndex()))
+ {
+ updateVersion();
+ }
+}
+
+void WonkoPage::updateVersion()
+{
+ WonkoVersionPtr version = std::dynamic_pointer_cast<WonkoVersion>(
+ ui->versionsView->currentIndex().data(WonkoVersionList::VersionPointerRole).value<BaseVersionPtr>());
+ if (version)
+ {
+ ui->refreshVersionBtn->setEnabled(true);
+ ui->versionVersionLabel->setEnabled(true);
+ ui->versionVersion->setText(version->version());
+ ui->versionTimeLabel->setEnabled(true);
+ ui->versionTime->setText(version->time().toString("yyyy-MM-dd HH:mm"));
+ ui->versionTypeLabel->setEnabled(true);
+ ui->versionType->setText(version->type());
+ ui->versionRequiresLabel->setEnabled(true);
+ ui->versionRequires->setText(formatRequires(version));
+ ui->refreshVersionBtn->setText(tr("Refresh %1").arg(version->version()));
+ }
+ else
+ {
+ ui->refreshVersionBtn->setEnabled(false);
+ ui->versionVersionLabel->setEnabled(false);
+ ui->versionVersion->clear();
+ ui->versionTimeLabel->setEnabled(false);
+ ui->versionTime->clear();
+ ui->versionTypeLabel->setEnabled(false);
+ ui->versionType->clear();
+ ui->versionRequiresLabel->setEnabled(false);
+ ui->versionRequires->clear();
+ ui->refreshVersionBtn->setText(tr("Refresh ___"));
+ }
+}
+
+void WonkoPage::opened()
+{
+ if (!ENV.wonkoIndex()->isLocalLoaded())
+ {
+ std::unique_ptr<Task> task = ENV.wonkoIndex()->localUpdateTask();
+ connect(task.get(), &Task::finished, this, [this]()
+ {
+ if (!ENV.wonkoIndex()->isRemoteLoaded())
+ {
+ ProgressDialog(this).execWithTask(ENV.wonkoIndex()->remoteUpdateTask());
+ }
+ });
+ ProgressDialog(this).execWithTask(task);
+ }
+}
diff --git a/application/pages/global/WonkoPage.h b/application/pages/global/WonkoPage.h
new file mode 100644
index 00000000..fd77ee0d
--- /dev/null
+++ b/application/pages/global/WonkoPage.h
@@ -0,0 +1,57 @@
+/* Copyright 2015 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 <QWidget>
+
+#include "pages/BasePage.h"
+
+namespace Ui {
+class WonkoPage;
+}
+
+class QSortFilterProxyModel;
+class VersionProxyModel;
+
+class WonkoPage : public QWidget, public BasePage
+{
+ Q_OBJECT
+public:
+ explicit WonkoPage(QWidget *parent = 0);
+ ~WonkoPage();
+
+ QString id() const override { return "wonko-global"; }
+ QString displayName() const override { return tr("Wonko"); }
+ QIcon icon() const override;
+ void opened() override;
+
+private slots:
+ void on_refreshIndexBtn_clicked();
+ void on_refreshFileBtn_clicked();
+ void on_refreshVersionBtn_clicked();
+ void on_fileSearchEdit_textChanged(const QString &search);
+ void on_versionSearchEdit_textChanged(const QString &search);
+ void updateCurrentVersionList(const QModelIndex &index);
+ void versionListDataChanged(const QModelIndex &tl, const QModelIndex &br);
+
+private:
+ Ui::WonkoPage *ui;
+ QSortFilterProxyModel *m_fileProxy;
+ QSortFilterProxyModel *m_filterProxy;
+ VersionProxyModel *m_versionProxy;
+
+ void updateVersion();
+};
diff --git a/application/pages/global/WonkoPage.ui b/application/pages/global/WonkoPage.ui
new file mode 100644
index 00000000..2d14ceca
--- /dev/null
+++ b/application/pages/global/WonkoPage.ui
@@ -0,0 +1,252 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>WonkoPage</class>
+ <widget class="QWidget" name="WonkoPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>640</width>
+ <height>480</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tab">
+ <attribute name="title">
+ <string>Tab 1</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="1" column="2">
+ <widget class="QGroupBox" name="versionsBox">
+ <property name="title">
+ <string>Versions</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QLineEdit" name="versionSearchEdit">
+ <property name="placeholderText">
+ <string>Search...</string>
+ </property>
+ <property name="clearButtonEnabled">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTreeView" name="versionsView">
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <attribute name="headerVisible">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QPushButton" name="refreshVersionBtn">
+ <property name="text">
+ <string>Refresh ___</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QFormLayout" name="formLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="versionVersionLabel">
+ <property name="text">
+ <string>Version:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="versionVersion">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="versionTimeLabel">
+ <property name="text">
+ <string>Time:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="versionTime">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="versionTypeLabel">
+ <property name="text">
+ <string>Type:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="versionType">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="versionRequiresLabel">
+ <property name="text">
+ <string>Dependencies:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLabel" name="versionRequires">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <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>
+ </item>
+ <item row="1" column="1">
+ <widget class="QGroupBox" name="versionListsBox">
+ <property name="title">
+ <string>Resources</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLineEdit" name="fileSearchEdit">
+ <property name="placeholderText">
+ <string>Search...</string>
+ </property>
+ <property name="clearButtonEnabled">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTreeView" name="indexView">
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <attribute name="headerVisible">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QPushButton" name="refreshFileBtn">
+ <property name="text">
+ <string>Refresh ___</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="fileUidLabel">
+ <property name="text">
+ <string>UID:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="fileUid">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="fileNameLabel">
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="fileName">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <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>
+ </item>
+ <item row="0" column="1" colspan="2">
+ <widget class="QPushButton" name="refreshIndexBtn">
+ <property name="text">
+ <string>Refresh Index</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/application/resources/multimc/16x16/looney.png b/application/resources/multimc/16x16/looney.png
new file mode 100644
index 00000000..ea0d7c18
--- /dev/null
+++ b/application/resources/multimc/16x16/looney.png
Binary files differ
diff --git a/application/resources/multimc/256x256/looney.png b/application/resources/multimc/256x256/looney.png
new file mode 100644
index 00000000..ac48231b
--- /dev/null
+++ b/application/resources/multimc/256x256/looney.png
Binary files differ
diff --git a/application/resources/multimc/32x32/looney.png b/application/resources/multimc/32x32/looney.png
new file mode 100644
index 00000000..74cc7b4c
--- /dev/null
+++ b/application/resources/multimc/32x32/looney.png
Binary files differ
diff --git a/application/resources/multimc/64x64/looney.png b/application/resources/multimc/64x64/looney.png
new file mode 100644
index 00000000..fbdbb856
--- /dev/null
+++ b/application/resources/multimc/64x64/looney.png
Binary files differ
diff --git a/application/resources/multimc/multimc.qrc b/application/resources/multimc/multimc.qrc
index 6a625080..3f7c5e8f 100644
--- a/application/resources/multimc/multimc.qrc
+++ b/application/resources/multimc/multimc.qrc
@@ -236,5 +236,11 @@
<!-- discord logo icon thing. from discord. traced from bitmap -->
<file>scalable/discord.svg</file>
+
+ <!-- Looney, used for Wonko, Monty Python -->
+ <file>16x16/looney.png</file>
+ <file>32x32/looney.png</file>
+ <file>64x64/looney.png</file>
+ <file>256x256/looney.png</file>
</qresource>
</RCC>