aboutsummaryrefslogtreecommitdiff
path: root/application
diff options
context:
space:
mode:
Diffstat (limited to 'application')
-rw-r--r--application/CMakeLists.txt28
-rw-r--r--application/MainWindow.cpp3
-rw-r--r--application/MainWindow.h4
-rw-r--r--application/MultiMC.cpp76
-rw-r--r--application/MultiMC.h2
-rw-r--r--application/dialogs/AboutDialog.cpp81
-rw-r--r--application/dialogs/AboutDialog.ui30
-rw-r--r--application/dialogs/CopyInstanceDialog.cpp19
-rw-r--r--application/dialogs/CopyInstanceDialog.h3
-rw-r--r--application/dialogs/CopyInstanceDialog.ui16
-rw-r--r--application/dialogs/EditAccountDialog.ui2
-rw-r--r--application/dialogs/LoginDialog.ui2
-rw-r--r--application/dialogs/NewInstanceDialog.cpp20
-rw-r--r--application/groupview/AccessibleGroupView.cpp4
-rw-r--r--application/groupview/AccessibleGroupView_p.h4
-rw-r--r--application/groupview/GroupView.cpp6
-rw-r--r--application/main.cpp1
-rwxr-xr-xapplication/package/linux/multimc.desktop2
-rw-r--r--application/package/ubuntu/multimc/DEBIAN/control4
-rw-r--r--application/pages/global/AccountListPage.cpp3
-rw-r--r--application/pages/global/PackagesPage.cpp224
-rw-r--r--application/pages/global/PackagesPage.h57
-rw-r--r--application/pages/global/PackagesPage.ui252
-rw-r--r--application/pages/global/ProxyPage.cpp2
-rw-r--r--application/pages/instance/ModFolderPage.cpp20
-rw-r--r--application/pages/instance/VersionPage.cpp15
-rw-r--r--application/pages/instance/VersionPage.h3
-rw-r--r--application/pages/instance/VersionPage.ui20
-rw-r--r--application/pages/modplatform/TechnicPage.cpp26
-rw-r--r--application/pages/modplatform/TechnicPage.h61
-rw-r--r--application/pages/modplatform/TechnicPage.ui113
-rw-r--r--application/pages/modplatform/TwitchPage.cpp60
-rw-r--r--application/pages/modplatform/TwitchPage.ui62
-rw-r--r--application/pages/modplatform/legacy_ftb/ListModel.cpp (renamed from application/pages/modplatform/FtbListModel.cpp)68
-rw-r--r--application/pages/modplatform/legacy_ftb/ListModel.h (renamed from application/pages/modplatform/FtbListModel.h)30
-rw-r--r--application/pages/modplatform/legacy_ftb/Page.cpp (renamed from application/pages/modplatform/FTBPage.cpp)114
-rw-r--r--application/pages/modplatform/legacy_ftb/Page.h (renamed from application/pages/modplatform/FTBPage.h)59
-rw-r--r--application/pages/modplatform/legacy_ftb/Page.ui (renamed from application/pages/modplatform/FTBPage.ui)4
-rw-r--r--application/pages/modplatform/twitch/TwitchData.h38
-rw-r--r--application/pages/modplatform/twitch/TwitchModel.cpp314
-rw-r--r--application/pages/modplatform/twitch/TwitchModel.h76
-rw-r--r--application/pages/modplatform/twitch/TwitchPage.cpp111
-rw-r--r--application/pages/modplatform/twitch/TwitchPage.h (renamed from application/pages/modplatform/TwitchPage.h)20
-rw-r--r--application/pages/modplatform/twitch/TwitchPage.ui88
-rw-r--r--application/resources/assets/assets.qrc7
-rw-r--r--application/resources/assets/deadglitch.svg66
-rw-r--r--application/resources/assets/underconstruction.pngbin14490 -> 0 bytes
-rw-r--r--application/widgets/DropLabel.cpp41
-rw-r--r--application/widgets/DropLabel.h20
-rw-r--r--application/widgets/ServerStatus.cpp2
-rw-r--r--application/widgets/VersionListView.cpp2
51 files changed, 1101 insertions, 1184 deletions
diff --git a/application/CMakeLists.txt b/application/CMakeLists.txt
index ce204ae5..53c21866 100644
--- a/application/CMakeLists.txt
+++ b/application/CMakeLists.txt
@@ -125,20 +125,19 @@ SET(MULTIMC_SOURCES
pages/global/ProxyPage.h
pages/global/PasteEEPage.cpp
pages/global/PasteEEPage.h
- pages/global/PackagesPage.cpp
- pages/global/PackagesPage.h
# GUI - platform pages
pages/modplatform/VanillaPage.cpp
pages/modplatform/VanillaPage.h
- pages/modplatform/FTBPage.cpp
- pages/modplatform/FTBPage.h
- pages/modplatform/FtbListModel.h
- pages/modplatform/FtbListModel.cpp
- pages/modplatform/TwitchPage.cpp
- pages/modplatform/TwitchPage.h
- pages/modplatform/TechnicPage.cpp
- pages/modplatform/TechnicPage.h
+ pages/modplatform/legacy_ftb/Page.cpp
+ pages/modplatform/legacy_ftb/Page.h
+ pages/modplatform/legacy_ftb/ListModel.h
+ pages/modplatform/legacy_ftb/ListModel.cpp
+ pages/modplatform/twitch/TwitchData.h
+ pages/modplatform/twitch/TwitchModel.cpp
+ pages/modplatform/twitch/TwitchModel.h
+ pages/modplatform/twitch/TwitchPage.cpp
+ pages/modplatform/twitch/TwitchPage.h
pages/modplatform/ImportPage.cpp
pages/modplatform/ImportPage.h
@@ -182,6 +181,8 @@ SET(MULTIMC_SOURCES
widgets/Common.h
widgets/CustomCommands.cpp
widgets/CustomCommands.h
+ widgets/DropLabel.cpp
+ widgets/DropLabel.h
widgets/FocusLineEdit.cpp
widgets/FocusLineEdit.h
widgets/IconLabel.cpp
@@ -251,13 +252,11 @@ SET(MULTIMC_UIS
pages/global/MultiMCPage.ui
pages/global/ProxyPage.ui
pages/global/PasteEEPage.ui
- pages/global/PackagesPage.ui
# Platform pages
pages/modplatform/VanillaPage.ui
- pages/modplatform/FTBPage.ui
- pages/modplatform/TwitchPage.ui
- pages/modplatform/TechnicPage.ui
+ pages/modplatform/legacy_ftb/Page.ui
+ pages/modplatform/twitch/TwitchPage.ui
pages/modplatform/ImportPage.ui
# Dialogs
@@ -281,7 +280,6 @@ SET(MULTIMC_UIS
)
set(MULTIMC_QRCS
- resources/assets/assets.qrc
resources/backgrounds/backgrounds.qrc
resources/multimc/multimc.qrc
resources/pe_dark/pe_dark.qrc
diff --git a/application/MainWindow.cpp b/application/MainWindow.cpp
index 5122e240..34ffc54b 100644
--- a/application/MainWindow.cpp
+++ b/application/MainWindow.cpp
@@ -578,6 +578,7 @@ public:
MainWindow->resize(800, 600);
MainWindow->setWindowIcon(MMC->getThemedIcon("logo"));
MainWindow->setWindowTitle("MultiMC 5");
+ MainWindow->setAccessibleName("MultiMC");
createMainToolbar(MainWindow);
@@ -1357,7 +1358,7 @@ void MainWindow::on_actionCopyInstance_triggered()
if (!copyInstDlg.exec())
return;
- auto copyTask = new InstanceCopyTask(m_selectedInstance, copyInstDlg.shouldCopySaves());
+ auto copyTask = new InstanceCopyTask(m_selectedInstance, copyInstDlg.shouldCopySaves(), copyInstDlg.shouldKeepPlaytime());
copyTask->setName(copyInstDlg.instName());
copyTask->setGroup(copyInstDlg.instGroup());
copyTask->setIcon(copyInstDlg.iconKey());
diff --git a/application/MainWindow.h b/application/MainWindow.h
index a415b5e8..00b8e043 100644
--- a/application/MainWindow.h
+++ b/application/MainWindow.h
@@ -57,6 +57,8 @@ public:
void checkInstancePathForProblems();
void updatesAllowedChanged(bool allowed);
+
+ void droppedURLs(QList<QUrl> urls);
signals:
void isClosing();
@@ -180,8 +182,6 @@ private slots:
*/
void downloadUpdates(GoUpdate::Status status);
- void droppedURLs(QList<QUrl> urls);
-
void konamiTriggered();
void globalSettingsClosed();
diff --git a/application/MultiMC.cpp b/application/MultiMC.cpp
index c95d85be..a8d26498 100644
--- a/application/MultiMC.cpp
+++ b/application/MultiMC.cpp
@@ -15,7 +15,6 @@
#include "pages/global/ExternalToolsPage.h"
#include "pages/global/AccountListPage.h"
#include "pages/global/PasteEEPage.h"
-#include "pages/global/PackagesPage.h"
#include "pages/global/CustomCommandsPage.h"
#include "themes/ITheme.h"
@@ -35,6 +34,7 @@
#include <QNetworkAccessManager>
#include <QTranslator>
#include <QLibraryInfo>
+#include <QList>
#include <QStringList>
#include <QDebug>
#include <QStyleFactory>
@@ -146,6 +146,27 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv)
startTime = QDateTime::currentDateTime();
+#ifdef Q_OS_LINUX
+ {
+ QFile osrelease("/proc/sys/kernel/osrelease");
+ if (osrelease.open(QFile::ReadOnly | QFile::Text)) {
+ QTextStream in(&osrelease);
+ auto contents = in.readAll();
+ if(
+ contents.contains("WSL", Qt::CaseInsensitive) ||
+ contents.contains("Microsoft", Qt::CaseInsensitive)
+ ) {
+ showFatalErrorMessage(
+ "Unsupported system detected!",
+ "Linux-on-Windows distributions are not supported.\n\n"
+ "Please use the Windows MultiMC binary when playing on Windows."
+ );
+ return;
+ }
+ }
+ }
+#endif
+
// Don't quit on hiding the last window
this->setQuitOnLastWindowClosed(false);
@@ -174,6 +195,10 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv)
// --alive
parser.addSwitch("alive");
parser.addDocumentation("alive", "Write a small '" + liveCheckFile + "' file after MultiMC starts");
+ // --import
+ parser.addOption("import");
+ parser.addShortOpt("import", 'I');
+ parser.addDocumentation("import", "Import instance from specified zip (local path or URL)");
// parse the arguments
try
@@ -208,6 +233,7 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv)
}
m_instanceIdToLaunch = args["launch"].toString();
m_liveCheck = args["alive"].toBool();
+ m_zipToImport = args["import"].toUrl();
QString origcwdPath = QDir::currentPath();
QString binPath = applicationDirPath();
@@ -279,13 +305,20 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv)
connect(m_peerInstance, &LocalPeer::messageReceived, this, &MultiMC::messageReceived);
if(m_peerInstance->isClient())
{
+ int timeout = 2000;
+
if(m_instanceIdToLaunch.isEmpty())
{
- m_peerInstance->sendMessage("activate", 2000);
+ m_peerInstance->sendMessage("activate", timeout);
+
+ if(!m_zipToImport.isEmpty())
+ {
+ m_peerInstance->sendMessage("import " + m_zipToImport.toString(), timeout);
+ }
}
else
{
- m_peerInstance->sendMessage(m_instanceIdToLaunch, 2000);
+ m_peerInstance->sendMessage("launch " + m_instanceIdToLaunch, timeout);
}
m_status = MultiMC::Succeeded;
return;
@@ -527,7 +560,6 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv)
m_globalSettingsProvider->addPage<LanguagePage>();
m_globalSettingsProvider->addPage<CustomCommandsPage>();
m_globalSettingsProvider->addPage<ProxyPage>();
- // m_globalSettingsProvider->addPage<PackagesPage>();
m_globalSettingsProvider->addPage<ExternalToolsPage>();
m_globalSettingsProvider->addPage<AccountListPage>();
m_globalSettingsProvider->addPage<PasteEEPage>();
@@ -535,7 +567,9 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv)
qDebug() << "<> Settings loaded.";
}
+#ifndef QT_NO_ACCESSIBILITY
QAccessible::installFactory(groupViewAccessibleFactory);
+#endif /* !QT_NO_ACCESSIBILITY */
// load translations
{
@@ -812,6 +846,11 @@ void MultiMC::performMainStartupAction()
showMainWindow(false);
qDebug() << "<> Main window shown.";
}
+ if(!m_zipToImport.isEmpty())
+ {
+ qDebug() << "<> Importing instance from zip:" << m_zipToImport;
+ m_mainWindow->droppedURLs({ m_zipToImport });
+ }
}
void MultiMC::showFatalErrorMessage(const QString& title, const QString& content)
@@ -848,18 +887,41 @@ void MultiMC::messageReceived(const QString& message)
qDebug() << "Received message" << message << "while still initializing. It will be ignored.";
return;
}
- if(message == "activate")
+
+ QString command = message.section(' ', 0, 0);
+
+ if(command == "activate")
{
showMainWindow();
}
- else
+ else if(command == "import")
+ {
+ QString arg = message.section(' ', 1);
+ if(arg.isEmpty())
+ {
+ qWarning() << "Received" << command << "message without a zip path/URL.";
+ return;
+ }
+ m_mainWindow->droppedURLs({ QUrl(arg) });
+ }
+ else if(command == "launch")
{
- auto inst = instances()->getInstanceById(message);
+ QString arg = message.section(' ', 1);
+ if(arg.isEmpty())
+ {
+ qWarning() << "Received" << command << "message without an instance ID.";
+ return;
+ }
+ auto inst = instances()->getInstanceById(arg);
if(inst)
{
launch(inst, true, nullptr);
}
}
+ else
+ {
+ qWarning() << "Received invalid message" << message;
+ }
}
void MultiMC::analyticsSettingChanged(const Setting&, QVariant value)
diff --git a/application/MultiMC.h b/application/MultiMC.h
index d7c727e0..e6588a14 100644
--- a/application/MultiMC.h
+++ b/application/MultiMC.h
@@ -6,6 +6,7 @@
#include <QFlag>
#include <QIcon>
#include <QDateTime>
+#include <QUrl>
#include <updater/GoUpdate.h>
#include <BaseInstance.h>
@@ -221,5 +222,6 @@ private:
public:
QString m_instanceIdToLaunch;
bool m_liveCheck = false;
+ QUrl m_zipToImport;
std::unique_ptr<QFile> logFile;
};
diff --git a/application/dialogs/AboutDialog.cpp b/application/dialogs/AboutDialog.cpp
index ca1dfd94..c4e4ee24 100644
--- a/application/dialogs/AboutDialog.cpp
+++ b/application/dialogs/AboutDialog.cpp
@@ -23,56 +23,44 @@
#include "HoeDown.h"
+namespace {
// Credits
// This is a hack, but I can't think of a better way to do this easily without screwing with QTextDocument...
-static QString getCreditsHtml(QStringList patrons)
+QString getCreditsHtml(QStringList patrons)
{
- QString creditsHtml = QObject::tr(
- "<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.0//EN' 'http://www.w3.org/TR/REC-html40/strict.dtd'>"
- "<html>"
- ""
- "<head>"
- "<meta name='qrichtext' content='1' />"
- "<style type='text/css'>"
- "p { white-space: pre-wrap; margin-top:2px; margin-bottom:2px; }"
- "</style>"
- "</head>"
- ""
- "<body style=' font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;'>"
- ""
- "<h3>MultiMC Developers</h3>"
- "<p>Andrew Okin &lt;<a href='mailto:forkk@forkk.net'>forkk@forkk.net</a>&gt;</p>"
- "<p>Petr Mrázek &lt;<a href='mailto:peterix@gmail.com'>peterix@gmail.com</a>&gt;</p>"
- "<p>Sky Welch &lt;<a href='mailto:multimc@bunnies.io'>multimc@bunnies.io</a>&gt;</p>"
- "<p>Jan (02JanDal) &lt;<a href='mailto:02jandal@gmail.com'>02jandal@gmail.com</a>&gt;</p>"
- "<p>RoboSky &lt;<a href='https://twitter.com/RoboSky_'>@RoboSky_</a>&gt;</p>"
- ""
- "<h3>With thanks to</h3>"
- "<p>Orochimarufan &lt;<a href='mailto:orochimarufan.x3@gmail.com'>orochimarufan.x3@gmail.com</a>&gt;</p>"
- "<p>TakSuyu &lt;<a href='mailto:taksuyu@gmail.com'>taksuyu@gmail.com</a>&gt;</p>"
- "<p>Kilobyte &lt;<a href='mailto:stiepen22@gmx.de'>stiepen22@gmx.de</a>&gt;</p>"
- "<p>Rootbear75 &lt;<a href='https://twitter.com/rootbear75'>@rootbear75</a>&gt;</p>"
- ""
- "<h3>Patrons</h3>"
- "%1"
- ""
- "</body>"
- "</html>");
- if (patrons.isEmpty())
- return creditsHtml.arg(QObject::tr("<p>Loading...</p>"));
- else
- {
- QString patronsStr;
+ QString patronsHeading = QObject::tr("Patrons", "About Credits");
+ QString output;
+ QTextStream stream(&output);
+ stream << "<center>\n";
+ // TODO: possibly retrieve from git history at build time?
+ stream << "<h3>" << QObject::tr("MultiMC Developers", "About Credits") << "</h3>\n";
+ stream << "<p>Andrew Okin &lt;<a href='mailto:forkk@forkk.net'>forkk@forkk.net</a>&gt;</p>\n";
+ stream << "<p>Petr Mrázek &lt;<a href='mailto:peterix@gmail.com'>peterix@gmail.com</a>&gt;</p>\n";
+ stream << "<p>Sky Welch &lt;<a href='mailto:multimc@bunnies.io'>multimc@bunnies.io</a>&gt;</p>\n";
+ stream << "<p>Jan (02JanDal) &lt;<a href='mailto:02jandal@gmail.com'>02jandal@gmail.com</a>&gt;</p>\n";
+ stream << "<p>RoboSky &lt;<a href='https://twitter.com/RoboSky_'>@RoboSky_</a>&gt;</p>\n";
+ stream << "<br />\n";
+
+ stream << "<h3>" << QObject::tr("With thanks to", "About Credits") << "</h3>\n";
+ stream << "<p>Orochimarufan &lt;<a href='mailto:orochimarufan.x3@gmail.com'>orochimarufan.x3@gmail.com</a>&gt;</p>\n";
+ stream << "<p>TakSuyu &lt;<a href='mailto:taksuyu@gmail.com'>taksuyu@gmail.com</a>&gt;</p>\n";
+ stream << "<p>Kilobyte &lt;<a href='mailto:stiepen22@gmx.de'>stiepen22@gmx.de</a>&gt;</p>\n";
+ stream << "<p>Rootbear75 &lt;<a href='https://twitter.com/rootbear75'>@rootbear75</a>&gt;</p>\n";
+ stream << "<p>Zeker Zhayard &lt;<a href='https://twitter.com/zeker_zhayard'>@Zeker_Zhayard</a>&gt;</p>\n";
+ stream << "<br />\n";
+
+ if(!patrons.isEmpty()) {
+ stream << "<h3>" << QObject::tr("Patrons", "About Credits") << "</h3>\n";
for (QString patron : patrons)
{
- patronsStr.append(QString("<p>%1</p>").arg(patron));
+ stream << "<p>" << patron << "</p>\n";
}
-
- return creditsHtml.arg(patronsStr);
}
+ stream << "</center>\n";
+ return output;
}
-static QString getLicenseHtml()
+QString getLicenseHtml()
{
HoeDown hoedown;
QFile dataFile(":/documents/COPYING.md");
@@ -81,6 +69,8 @@ static QString getLicenseHtml()
return output;
}
+}
+
AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent), ui(new Ui::AboutDialog)
{
ui->setupUi(this);
@@ -109,6 +99,15 @@ AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent), ui(new Ui::AboutDia
else
ui->channelLabel->setVisible(false);
+ ui->redistributionText->setHtml(tr(
+"<p>We keep MultiMC open source because we think it's important to be able to see the source code for a project like this, and we do so using the Apache license.</p>\n"
+"<p>Part of the reason for using the Apache license is we don't want people using the &quot;MultiMC&quot; name when redistributing the project. "
+"This means people must take the time to go through the source code and remove all references to &quot;MultiMC&quot;, including but not limited to the project "
+"icon and the title of windows, (no <b>MultiMC-fork</b> in the title).</p>\n"
+"<p>The Apache license covers reasonable use for the name - a mention of the project's origins in the About dialog and the license is acceptable. "
+"However, it should be abundantly clear that the project is a fork <b>without</b> implying that you have our blessing.</p>"
+ ));
+
connect(ui->closeButton, SIGNAL(clicked()), SLOT(close()));
connect(ui->aboutQt, &QPushButton::clicked, &QApplication::aboutQt);
diff --git a/application/dialogs/AboutDialog.ui b/application/dialogs/AboutDialog.ui
index 47ec0293..c4096b32 100644
--- a/application/dialogs/AboutDialog.ui
+++ b/application/dialogs/AboutDialog.ui
@@ -217,16 +217,6 @@
</property>
</widget>
</item>
- <item>
- <widget class="QLineEdit" name="translationInfo">
- <property name="text">
- <string extracomment="Hey, Translator, feel free to put credit to you here">No Language file loaded.</string>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- </item>
</layout>
</widget>
<widget class="QWidget" name="licenseTab">
@@ -263,18 +253,7 @@
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
- <widget class="QTextEdit" name="textEdit">
- <property name="html">
- <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
-&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
-p, li { white-space: pre-wrap; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Noto Sans'; font-size:12pt; font-weight:400; font-style:normal;&quot;&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Bitstream Vera Sans'; font-size:11pt;&quot;&gt;We keep MultiMC open source because we think it's important to be able to see the source code for a project like this, and we do so using the Apache license.&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Bitstream Vera Sans'; font-size:11pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Bitstream Vera Sans'; font-size:11pt;&quot;&gt;Part of the reason for using the Apache license is we don't want people using the &amp;quot;MultiMC&amp;quot; name when redistributing the project. This means people must take the time to go through the source code and remove all references to &amp;quot;MultiMC&amp;quot;, including but not limited to the project icon and the title of windows, (no *MultiMC-fork* in the title).&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Bitstream Vera Sans'; font-size:11pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Bitstream Vera Sans'; font-size:11pt;&quot;&gt;The Apache license covers reasonable use for the name - a mention of the project's origins in the About dialog and the license is acceptable. However, it should be abundantly clear that the project is a fork &lt;/span&gt;&lt;span style=&quot; font-family:'Bitstream Vera Sans'; font-size:11pt; font-weight:600;&quot;&gt;without&lt;/span&gt;&lt;span style=&quot; font-family:'Bitstream Vera Sans'; font-size:11pt;&quot;&gt; implying that you have our blessing.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
+ <widget class="QTextEdit" name="redistributionText">
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
@@ -323,14 +302,11 @@ p, li { white-space: pre-wrap; }
<tabstops>
<tabstop>tabWidget</tabstop>
<tabstop>creditsText</tabstop>
- <tabstop>translationInfo</tabstop>
<tabstop>licenseText</tabstop>
- <tabstop>textEdit</tabstop>
+ <tabstop>redistributionText</tabstop>
<tabstop>aboutQt</tabstop>
<tabstop>closeButton</tabstop>
</tabstops>
- <resources>
- <include location="../../resources/multimc/multimc.qrc"/>
- </resources>
+ <resources/>
<connections/>
</ui>
diff --git a/application/dialogs/CopyInstanceDialog.cpp b/application/dialogs/CopyInstanceDialog.cpp
index 6100860c..ab76e737 100644
--- a/application/dialogs/CopyInstanceDialog.cpp
+++ b/application/dialogs/CopyInstanceDialog.cpp
@@ -53,6 +53,7 @@ CopyInstanceDialog::CopyInstanceDialog(InstancePtr original, QWidget *parent)
ui->groupBox->setCurrentIndex(index);
ui->groupBox->lineEdit()->setPlaceholderText(tr("No group"));
ui->copySavesCheckbox->setChecked(m_copySaves);
+ ui->keepPlaytimeCheckbox->setChecked(m_keepPlaytime);
}
CopyInstanceDialog::~CopyInstanceDialog()
@@ -123,3 +124,21 @@ void CopyInstanceDialog::on_copySavesCheckbox_stateChanged(int state)
m_copySaves = true;
}
}
+
+bool CopyInstanceDialog::shouldKeepPlaytime() const
+{
+ return m_keepPlaytime;
+}
+
+
+void CopyInstanceDialog::on_keepPlaytimeCheckbox_stateChanged(int state)
+{
+ if(state == Qt::Unchecked)
+ {
+ m_keepPlaytime = false;
+ }
+ else if(state == Qt::Checked)
+ {
+ m_keepPlaytime = true;
+ }
+}
diff --git a/application/dialogs/CopyInstanceDialog.h b/application/dialogs/CopyInstanceDialog.h
index d46e647c..2b8475b7 100644
--- a/application/dialogs/CopyInstanceDialog.h
+++ b/application/dialogs/CopyInstanceDialog.h
@@ -40,16 +40,19 @@ public:
QString instGroup() const;
QString iconKey() const;
bool shouldCopySaves() const;
+ bool shouldKeepPlaytime() const;
private
slots:
void on_iconButton_clicked();
void on_instNameTextBox_textChanged(const QString &arg1);
void on_copySavesCheckbox_stateChanged(int state);
+ void on_keepPlaytimeCheckbox_stateChanged(int state);
private:
Ui::CopyInstanceDialog *ui;
QString InstIconKey;
InstancePtr m_original;
bool m_copySaves = true;
+ bool m_keepPlaytime = true;
};
diff --git a/application/dialogs/CopyInstanceDialog.ui b/application/dialogs/CopyInstanceDialog.ui
index bbb1bbb3..fa675455 100644
--- a/application/dialogs/CopyInstanceDialog.ui
+++ b/application/dialogs/CopyInstanceDialog.ui
@@ -10,7 +10,7 @@
<x>0</x>
<y>0</y>
<width>345</width>
- <height>240</height>
+ <height>323</height>
</rect>
</property>
<property name="windowTitle">
@@ -117,6 +117,13 @@
</widget>
</item>
<item>
+ <widget class="QCheckBox" name="keepPlaytimeCheckbox">
+ <property name="text">
+ <string>Keep play time</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -128,6 +135,13 @@
</item>
</layout>
</widget>
+ <tabstops>
+ <tabstop>iconButton</tabstop>
+ <tabstop>instNameTextBox</tabstop>
+ <tabstop>groupBox</tabstop>
+ <tabstop>copySavesCheckbox</tabstop>
+ <tabstop>keepPlaytimeCheckbox</tabstop>
+ </tabstops>
<resources>
<include location="../../graphics.qrc"/>
</resources>
diff --git a/application/dialogs/EditAccountDialog.ui b/application/dialogs/EditAccountDialog.ui
index 85e235ce..e87509bc 100644
--- a/application/dialogs/EditAccountDialog.ui
+++ b/application/dialogs/EditAccountDialog.ui
@@ -30,7 +30,7 @@
<item>
<widget class="QLineEdit" name="userTextBox">
<property name="placeholderText">
- <string>Email / Username</string>
+ <string>Email</string>
</property>
</widget>
</item>
diff --git a/application/dialogs/LoginDialog.ui b/application/dialogs/LoginDialog.ui
index 99b98215..d92fbae3 100644
--- a/application/dialogs/LoginDialog.ui
+++ b/application/dialogs/LoginDialog.ui
@@ -36,7 +36,7 @@
<item>
<widget class="QLineEdit" name="userTextBox">
<property name="placeholderText">
- <string>Email / Username</string>
+ <string>Email</string>
</property>
</widget>
</item>
diff --git a/application/dialogs/NewInstanceDialog.cpp b/application/dialogs/NewInstanceDialog.cpp
index 3533763d..511f991e 100644
--- a/application/dialogs/NewInstanceDialog.cpp
+++ b/application/dialogs/NewInstanceDialog.cpp
@@ -34,11 +34,9 @@
#include "widgets/PageContainer.h"
#include <pages/modplatform/VanillaPage.h>
-#include <pages/modplatform/FTBPage.h>
-#include <pages/modplatform/TwitchPage.h>
+#include <pages/modplatform/legacy_ftb/Page.h>
+#include <pages/modplatform/twitch/TwitchPage.h>
#include <pages/modplatform/ImportPage.h>
-#include <pages/modplatform/TechnicPage.h>
-
NewInstanceDialog::NewInstanceDialog(const QString & initialGroup, const QString & url, QWidget *parent)
@@ -97,14 +95,8 @@ NewInstanceDialog::NewInstanceDialog(const QString & initialGroup, const QString
if(!url.isEmpty())
{
QUrl actualUrl(url);
- if(actualUrl.host() == "www.curseforge.com") {
- m_container->selectPage("twitch");
- twitchPage->setUrl(url);
- }
- else {
- m_container->selectPage("import");
- importPage->setUrl(url);
- }
+ m_container->selectPage("import");
+ importPage->setUrl(url);
}
updateDialogState();
@@ -133,8 +125,8 @@ QList<BasePage *> NewInstanceDialog::getPages()
{
new VanillaPage(this),
importPage,
- twitchPage,
- new FTBPage(this)
+ new LegacyFTB::Page(this),
+ twitchPage
};
}
diff --git a/application/groupview/AccessibleGroupView.cpp b/application/groupview/AccessibleGroupView.cpp
index 9a1bb821..c6541f18 100644
--- a/application/groupview/AccessibleGroupView.cpp
+++ b/application/groupview/AccessibleGroupView.cpp
@@ -6,6 +6,8 @@
#include <qaccessible.h>
#include <qheaderview.h>
+#ifndef QT_NO_ACCESSIBILITY
+
QAccessibleInterface *groupViewAccessibleFactory(const QString &classname, QObject *object)
{
QAccessibleInterface *iface = 0;
@@ -772,3 +774,5 @@ QAccessibleInterface *AccessibleGroupViewItem::child(int) const
{
return 0;
}
+
+#endif /* !QT_NO_ACCESSIBILITY */
diff --git a/application/groupview/AccessibleGroupView_p.h b/application/groupview/AccessibleGroupView_p.h
index cdec1c0a..e74da3be 100644
--- a/application/groupview/AccessibleGroupView_p.h
+++ b/application/groupview/AccessibleGroupView_p.h
@@ -1,10 +1,11 @@
#pragma once
-#include "GroupView.h"
#include "QtCore/qpointer.h"
#include <QtGui/qaccessible.h>
#include <QAccessibleWidget>
#include <QAbstractItemView>
+#ifndef QT_NO_ACCESSIBILITY
+#include "GroupView.h"
// #include <QHeaderView>
class QAccessibleTableCell;
@@ -114,3 +115,4 @@ private:
friend class AccessibleGroupView;
};
+#endif /* !QT_NO_ACCESSIBILITY */
diff --git a/application/groupview/GroupView.cpp b/application/groupview/GroupView.cpp
index ff0daee4..a1a28532 100644
--- a/application/groupview/GroupView.cpp
+++ b/application/groupview/GroupView.cpp
@@ -93,11 +93,13 @@ void GroupView::currentChanged(const QModelIndex& current, const QModelIndex& pr
{
QAbstractItemView::currentChanged(current, previous);
// TODO: for accessibility support, implement+register a factory, steal QAccessibleTable from Qt and return an instance of it for GroupView.
+#ifndef QT_NO_ACCESSIBILITY
if (QAccessible::isActive() && current.isValid()) {
QAccessibleEvent event(this, QAccessible::Focus);
event.setChild(current.row());
QAccessible::updateAccessibility(&event);
}
+#endif /* !QT_NO_ACCESSIBILITY */
}
@@ -392,6 +394,8 @@ void GroupView::mouseReleaseEvent(QMouseEvent *event)
updateGeometries();
viewport()->update();
event->accept();
+ m_pressedCategory = nullptr;
+ setState(NoState);
return;
}
else if (state() == CollapsingState)
@@ -402,6 +406,8 @@ void GroupView::mouseReleaseEvent(QMouseEvent *event)
updateGeometries();
viewport()->update();
event->accept();
+ m_pressedCategory = nullptr;
+ setState(NoState);
return;
}
}
diff --git a/application/main.cpp b/application/main.cpp
index c871bf1b..b0360c7e 100644
--- a/application/main.cpp
+++ b/application/main.cpp
@@ -43,7 +43,6 @@ int main(int argc, char *argv[])
{
Q_INIT_RESOURCE(multimc);
Q_INIT_RESOURCE(backgrounds);
- Q_INIT_RESOURCE(assets);
Q_INIT_RESOURCE(pe_dark);
Q_INIT_RESOURCE(pe_light);
diff --git a/application/package/linux/multimc.desktop b/application/package/linux/multimc.desktop
index 770f24f1..c25be047 100755
--- a/application/package/linux/multimc.desktop
+++ b/application/package/linux/multimc.desktop
@@ -1,7 +1,7 @@
[Desktop Entry]
Version=1.0
Name=MultiMC
-GenericName=MultiMC
+GenericName=Minecraft Launcher
Comment=Free, open source launcher and instance manager for Minecraft.
Type=Application
Terminal=false
diff --git a/application/package/ubuntu/multimc/DEBIAN/control b/application/package/ubuntu/multimc/DEBIAN/control
index 34c223a5..9386e945 100644
--- a/application/package/ubuntu/multimc/DEBIAN/control
+++ b/application/package/ubuntu/multimc/DEBIAN/control
@@ -1,11 +1,11 @@
Package: multimc
-Version: 1.3-1
+Version: 1.4-1
Architecture: all
Maintainer: Petr Mrázek <peterix@gmail.com>
Section: games
Priority: optional
Installed-Size: 75
-Depends: zenity, desktop-file-utils, qt5-default
+Depends: zenity, desktop-file-utils, qt5-default, wget
Recommends: openjdk-8-jre
Homepage: http://multimc.org
Description: A local install wrapper for MultiMC
diff --git a/application/pages/global/AccountListPage.cpp b/application/pages/global/AccountListPage.cpp
index c14134f3..0453ae00 100644
--- a/application/pages/global/AccountListPage.cpp
+++ b/application/pages/global/AccountListPage.cpp
@@ -103,8 +103,7 @@ void AccountListPage::listChanged()
void AccountListPage::on_actionAdd_triggered()
{
- addAccount(tr("Please enter your Mojang or Minecraft account username and password to add "
- "your account."));
+ addAccount(tr("Please enter your Minecraft account email and password to add your account."));
}
void AccountListPage::on_actionRemove_triggered()
diff --git a/application/pages/global/PackagesPage.cpp b/application/pages/global/PackagesPage.cpp
deleted file mode 100644
index 1bbbed7a..00000000
--- a/application/pages/global/PackagesPage.cpp
+++ /dev/null
@@ -1,224 +0,0 @@
-/* Copyright 2015-2019 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 "PackagesPage.h"
-#include "ui_PackagesPage.h"
-
-#include <QDateTime>
-#include <QSortFilterProxyModel>
-#include <QRegularExpression>
-
-#include "dialogs/ProgressDialog.h"
-#include "VersionProxyModel.h"
-
-#include "meta/Index.h"
-#include "meta/VersionList.h"
-#include "meta/Version.h"
-#include "Env.h"
-#include "MultiMC.h"
-
-using namespace Meta;
-
-static QString formatRequires(const VersionPtr &version)
-{
- QStringList lines;
- auto & reqs = version->requires();
- auto iter = reqs.begin();
- while (iter != reqs.end())
- {
- auto &uid = iter->uid;
- auto &version = iter->equalsVersion;
- const QString readable = ENV.metadataIndex()->hasUid(uid) ? ENV.metadataIndex()->get(uid)->humanReadable() : uid;
- if(!version.isEmpty())
- {
- lines.append(QString("%1 (%2)").arg(readable, version));
- }
- else
- {
- lines.append(QString("%1").arg(readable));
- }
- iter++;
- }
- return lines.join('\n');
-}
-
-PackagesPage::PackagesPage(QWidget *parent) :
- QWidget(parent),
- ui(new Ui::PackagesPage)
-{
- 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.metadataIndex().get());
- ui->indexView->setModel(m_fileProxy);
-
- m_filterProxy = new QSortFilterProxyModel(this);
- m_filterProxy->setSortRole(VersionList::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, &PackagesPage::updateCurrentVersionList);
- connect(ui->versionsView->selectionModel(), &QItemSelectionModel::currentChanged, this, &PackagesPage::updateVersion);
- connect(m_filterProxy, &QSortFilterProxyModel::dataChanged, this, &PackagesPage::versionListDataChanged);
-
- updateCurrentVersionList(QModelIndex());
- updateVersion();
-}
-
-PackagesPage::~PackagesPage()
-{
- delete ui;
-}
-
-QIcon PackagesPage::icon() const
-{
- return MMC->getThemedIcon("packages");
-}
-
-void PackagesPage::on_refreshIndexBtn_clicked()
-{
- ENV.metadataIndex()->load(Net::Mode::Online);
-}
-void PackagesPage::on_refreshFileBtn_clicked()
-{
- VersionListPtr list = ui->indexView->currentIndex().data(Index::ListPtrRole).value<VersionListPtr>();
- if (!list)
- {
- return;
- }
- list->load(Net::Mode::Online);
-}
-void PackagesPage::on_refreshVersionBtn_clicked()
-{
- VersionPtr version = ui->versionsView->currentIndex().data(VersionList::VersionPtrRole).value<VersionPtr>();
- if (!version)
- {
- return;
- }
- version->load(Net::Mode::Online);
-}
-
-void PackagesPage::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 PackagesPage::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 PackagesPage::updateCurrentVersionList(const QModelIndex &index)
-{
- if (index.isValid())
- {
- VersionListPtr list = index.data(Index::ListPtrRole).value<VersionListPtr>();
- 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()));
- list->load(Net::Mode::Offline);
- }
- 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 PackagesPage::versionListDataChanged(const QModelIndex &tl, const QModelIndex &br)
-{
- if (QItemSelection(tl, br).contains(ui->versionsView->currentIndex()))
- {
- updateVersion();
- }
-}
-
-void PackagesPage::updateVersion()
-{
- VersionPtr version = std::dynamic_pointer_cast<Version>(
- ui->versionsView->currentIndex().data(VersionList::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 PackagesPage::openedImpl()
-{
- ENV.metadataIndex()->load(Net::Mode::Offline);
-}
diff --git a/application/pages/global/PackagesPage.h b/application/pages/global/PackagesPage.h
deleted file mode 100644
index 872961a5..00000000
--- a/application/pages/global/PackagesPage.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* Copyright 2015-2019 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 PackagesPage;
-}
-
-class QSortFilterProxyModel;
-class VersionProxyModel;
-
-class PackagesPage : public QWidget, public BasePage
-{
- Q_OBJECT
-public:
- explicit PackagesPage(QWidget *parent = 0);
- ~PackagesPage();
-
- QString id() const override { return "packages-global"; }
- QString displayName() const override { return tr("Packages"); }
- QIcon icon() const override;
- void openedImpl() 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::PackagesPage *ui;
- QSortFilterProxyModel *m_fileProxy;
- QSortFilterProxyModel *m_filterProxy;
- VersionProxyModel *m_versionProxy;
-
- void updateVersion();
-};
diff --git a/application/pages/global/PackagesPage.ui b/application/pages/global/PackagesPage.ui
deleted file mode 100644
index 158bf1b4..00000000
--- a/application/pages/global/PackagesPage.ui
+++ /dev/null
@@ -1,252 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>PackagesPage</class>
- <widget class="QWidget" name="PackagesPage">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>636</width>
- <height>621</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/pages/global/ProxyPage.cpp b/application/pages/global/ProxyPage.cpp
index ee56a54e..3f0e766b 100644
--- a/application/pages/global/ProxyPage.cpp
+++ b/application/pages/global/ProxyPage.cpp
@@ -95,7 +95,7 @@ void ProxyPage::loadSettings()
ui->proxyHTTPBtn->setChecked(true);
ui->proxyAddrEdit->setText(s->get("ProxyAddr").toString());
- ui->proxyPortEdit->setValue(s->get("ProxyPort").value<qint16>());
+ ui->proxyPortEdit->setValue(s->get("ProxyPort").value<uint16_t>());
ui->proxyUserEdit->setText(s->get("ProxyUser").toString());
ui->proxyPassEdit->setText(s->get("ProxyPass").toString());
}
diff --git a/application/pages/instance/ModFolderPage.cpp b/application/pages/instance/ModFolderPage.cpp
index d449f8bf..ec4bf3c9 100644
--- a/application/pages/instance/ModFolderPage.cpp
+++ b/application/pages/instance/ModFolderPage.cpp
@@ -51,6 +51,26 @@ public:
}
protected:
+ bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const override {
+ ModFolderModel *model = qobject_cast<ModFolderModel *>(sourceModel());
+ if(!model) {
+ return false;
+ }
+ const auto &mod = model->at(source_row);
+ if(mod.name().contains(filterRegExp())) {
+ return true;
+ }
+ if(mod.description().contains(filterRegExp())) {
+ return true;
+ }
+ for(auto & author: mod.authors()) {
+ if (author.contains(filterRegExp())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
bool lessThan(const QModelIndex & source_left, const QModelIndex & source_right) const override
{
ModFolderModel *model = qobject_cast<ModFolderModel *>(sourceModel());
diff --git a/application/pages/instance/VersionPage.cpp b/application/pages/instance/VersionPage.cpp
index 8ca55934..c7a8dc30 100644
--- a/application/pages/instance/VersionPage.cpp
+++ b/application/pages/instance/VersionPage.cpp
@@ -43,6 +43,7 @@
#include "icons/IconList.h"
#include "Exception.h"
#include "Version.h"
+#include "DesktopServices.h"
#include <meta/Index.h>
#include <meta/VersionList.h>
@@ -60,7 +61,7 @@ public:
virtual QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const override
{
- QVariant var = QIdentityProxyModel::data(mapToSource(proxyIndex), role);
+ QVariant var = QIdentityProxyModel::data(proxyIndex, role);
int column = proxyIndex.column();
if(column == 0 && role == Qt::DecorationRole && m_parentWidget)
{
@@ -205,7 +206,7 @@ void VersionPage::updateVersionControls()
bool newCraft = controlsEnabled && (minecraftVersion >= Version("1.14"));
bool oldCraft = controlsEnabled && (minecraftVersion <= Version("1.12.2"));
ui->actionInstall_Fabric->setEnabled(newCraft);
- ui->actionInstall_Forge->setEnabled(oldCraft);
+ ui->actionInstall_Forge->setEnabled(true);
ui->actionInstall_LiteLoader->setEnabled(oldCraft);
ui->actionReload->setEnabled(true);
updateButtons();
@@ -507,6 +508,16 @@ void VersionPage::on_actionInstall_LiteLoader_triggered()
}
}
+void VersionPage::on_actionLibrariesFolder_triggered()
+{
+ DesktopServices::openDirectory(m_inst->getLocalLibraryPath(), true);
+}
+
+void VersionPage::on_actionMinecraftFolder_triggered()
+{
+ DesktopServices::openDirectory(m_inst->gameRoot(), true);
+}
+
void VersionPage::versionCurrent(const QModelIndex &current, const QModelIndex &previous)
{
currentIdx = current.row();
diff --git a/application/pages/instance/VersionPage.h b/application/pages/instance/VersionPage.h
index 5ffd32f5..769fe997 100644
--- a/application/pages/instance/VersionPage.h
+++ b/application/pages/instance/VersionPage.h
@@ -66,6 +66,9 @@ private slots:
void on_actionCustomize_triggered();
void on_actionDownload_All_triggered();
+ void on_actionMinecraftFolder_triggered();
+ void on_actionLibrariesFolder_triggered();
+
void updateVersionControls();
private:
diff --git a/application/pages/instance/VersionPage.ui b/application/pages/instance/VersionPage.ui
index 32111aa5..718ad067 100644
--- a/application/pages/instance/VersionPage.ui
+++ b/application/pages/instance/VersionPage.ui
@@ -95,6 +95,10 @@
<addaction name="actionAdd_to_Minecraft_jar"/>
<addaction name="actionReplace_Minecraft_jar"/>
<addaction name="actionAdd_Empty"/>
+ <addaction name="separator"/>
+ <addaction name="actionMinecraftFolder"/>
+ <addaction name="actionLibrariesFolder"/>
+ <addaction name="separator"/>
<addaction name="actionReload"/>
<addaction name="actionDownload_All"/>
</widget>
@@ -223,6 +227,22 @@
<string>Download the files needed to launch the instance now.</string>
</property>
</action>
+ <action name="actionMinecraftFolder">
+ <property name="text">
+ <string>Open .minecraft</string>
+ </property>
+ <property name="toolTip">
+ <string>Open the instance's .minecraft folder.</string>
+ </property>
+ </action>
+ <action name="actionLibrariesFolder">
+ <property name="text">
+ <string>Open libraries</string>
+ </property>
+ <property name="toolTip">
+ <string>Open the instance's local libraries folder.</string>
+ </property>
+ </action>
</widget>
<customwidgets>
<customwidget>
diff --git a/application/pages/modplatform/TechnicPage.cpp b/application/pages/modplatform/TechnicPage.cpp
deleted file mode 100644
index 2f95bec8..00000000
--- a/application/pages/modplatform/TechnicPage.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-#include "TechnicPage.h"
-#include "ui_TechnicPage.h"
-
-#include "MultiMC.h"
-#include "dialogs/NewInstanceDialog.h"
-
-TechnicPage::TechnicPage(NewInstanceDialog* dialog, QWidget *parent)
- : QWidget(parent), ui(new Ui::TechnicPage), dialog(dialog)
-{
- ui->setupUi(this);
-}
-
-TechnicPage::~TechnicPage()
-{
- delete ui;
-}
-
-bool TechnicPage::shouldDisplay() const
-{
- return true;
-}
-
-void TechnicPage::openedImpl()
-{
- dialog->setSuggestedPack();
-}
diff --git a/application/pages/modplatform/TechnicPage.h b/application/pages/modplatform/TechnicPage.h
deleted file mode 100644
index cc82ddf3..00000000
--- a/application/pages/modplatform/TechnicPage.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Copyright 2013-2019 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"
-#include <MultiMC.h>
-#include "tasks/Task.h"
-
-namespace Ui
-{
-class TechnicPage;
-}
-
-class NewInstanceDialog;
-
-class TechnicPage : public QWidget, public BasePage
-{
- Q_OBJECT
-
-public:
- explicit TechnicPage(NewInstanceDialog* dialog, QWidget *parent = 0);
- virtual ~TechnicPage();
- virtual QString displayName() const override
- {
- return tr("Technic");
- }
- virtual QIcon icon() const override
- {
- return MMC->getThemedIcon("technic");
- }
- virtual QString id() const override
- {
- return "technic";
- }
- virtual QString helpPage() const override
- {
- return "Technic-platform";
- }
- virtual bool shouldDisplay() const override;
-
- void openedImpl() override;
-
-private:
- Ui::TechnicPage *ui = nullptr;
- NewInstanceDialog* dialog = nullptr;
-};
diff --git a/application/pages/modplatform/TechnicPage.ui b/application/pages/modplatform/TechnicPage.ui
deleted file mode 100644
index 702427b5..00000000
--- a/application/pages/modplatform/TechnicPage.ui
+++ /dev/null
@@ -1,113 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>TechnicPage</class>
- <widget class="QWidget" name="TechnicPage">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>546</width>
- <height>405</height>
- </rect>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_5">
- <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>
- <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>
- <item>
- <widget class="QLabel" name="label">
- <property name="font">
- <font>
- <pointsize>40</pointsize>
- </font>
- </property>
- <property name="styleSheet">
- <string notr="true">color:#ffc000</string>
- </property>
- <property name="text">
- <string notr="true">UNDER</string>
- </property>
- <property name="textFormat">
- <enum>Qt::PlainText</enum>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="label_3">
- <property name="text">
- <string notr="true"/>
- </property>
- <property name="pixmap">
- <pixmap resource="../../resources/assets/assets.qrc">:/assets/underconstruction</pixmap>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QLabel" name="label_2">
- <property name="font">
- <font>
- <pointsize>40</pointsize>
- </font>
- </property>
- <property name="styleSheet">
- <string notr="true">color:#7ca32b</string>
- </property>
- <property name="text">
- <string notr="true">CONSTRUCTION</string>
- </property>
- <property name="textFormat">
- <enum>Qt::PlainText</enum>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- </widget>
- </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>
- <resources>
- <include location="../../resources/assets/assets.qrc"/>
- </resources>
- <connections/>
-</ui>
diff --git a/application/pages/modplatform/TwitchPage.cpp b/application/pages/modplatform/TwitchPage.cpp
deleted file mode 100644
index ea0f9267..00000000
--- a/application/pages/modplatform/TwitchPage.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-#include "TwitchPage.h"
-#include "ui_TwitchPage.h"
-
-#include "MultiMC.h"
-#include "dialogs/NewInstanceDialog.h"
-#include <InstanceImportTask.h>
-
-TwitchPage::TwitchPage(NewInstanceDialog* dialog, QWidget *parent)
- : QWidget(parent), ui(new Ui::TwitchPage), dialog(dialog)
-{
- ui->setupUi(this);
- connect(ui->checkButton, &QPushButton::clicked, this, &TwitchPage::triggerCheck);
-}
-
-TwitchPage::~TwitchPage()
-{
- delete ui;
-}
-
-bool TwitchPage::shouldDisplay() const
-{
- return true;
-}
-
-void TwitchPage::openedImpl()
-{
- dialog->setSuggestedPack();
-}
-
-void TwitchPage::triggerCheck(bool)
-{
- if(m_modIdResolver) {
- return;
- }
- auto task = new Flame::UrlResolvingTask(ui->lineEdit->text());
- connect(task, &Task::finished, this, &TwitchPage::checkDone);
- m_modIdResolver.reset(task);
- task->start();
-}
-
-void TwitchPage::setUrl(const QString& url)
-{
- ui->lineEdit->setText(url);
- triggerCheck(true);
-}
-
-void TwitchPage::checkDone()
-{
- auto result = m_modIdResolver->getResults();
- auto formatted = QString("Project %1, File %2").arg(result.projectId).arg(result.fileId);
- if(result.resolved && result.type == Flame::File::Type::Modpack) {
- ui->twitchLabel->setText(formatted);
- QFileInfo fi(result.fileName);
- dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(result.url));
- } else {
- ui->twitchLabel->setPixmap(QPixmap(QString::fromUtf8(":/assets/deadglitch")));
- dialog->setSuggestedPack();
- }
- m_modIdResolver.reset();
-}
diff --git a/application/pages/modplatform/TwitchPage.ui b/application/pages/modplatform/TwitchPage.ui
deleted file mode 100644
index 0db2484d..00000000
--- a/application/pages/modplatform/TwitchPage.ui
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>TwitchPage</class>
- <widget class="QWidget" name="TwitchPage">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>546</width>
- <height>405</height>
- </rect>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="1">
- <widget class="QLineEdit" name="lineEdit"/>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Twitch URL:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="0" colspan="3">
- <widget class="QLabel" name="twitchLabel">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="font">
- <font>
- <pointsize>40</pointsize>
- </font>
- </property>
- <property name="pixmap">
- <pixmap resource="../../resources/assets/assets.qrc">:/assets/deadglitch</pixmap>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- </widget>
- </item>
- <item row="0" column="2">
- <widget class="QPushButton" name="checkButton">
- <property name="text">
- <string>Check</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <tabstops>
- <tabstop>lineEdit</tabstop>
- <tabstop>checkButton</tabstop>
- </tabstops>
- <resources>
- <include location="../../resources/assets/assets.qrc"/>
- </resources>
- <connections/>
-</ui>
diff --git a/application/pages/modplatform/FtbListModel.cpp b/application/pages/modplatform/legacy_ftb/ListModel.cpp
index 51aec890..105db25a 100644
--- a/application/pages/modplatform/FtbListModel.cpp
+++ b/application/pages/modplatform/legacy_ftb/ListModel.cpp
@@ -1,4 +1,4 @@
-#include "FtbListModel.h"
+#include "ListModel.h"
#include "MultiMC.h"
#include <MMCStrings.h>
@@ -12,17 +12,19 @@
#include "net/URLConstants.h"
-FtbFilterModel::FtbFilterModel(QObject *parent) : QSortFilterProxyModel(parent)
+namespace LegacyFTB {
+
+FilterModel::FilterModel(QObject *parent) : QSortFilterProxyModel(parent)
{
currentSorting = Sorting::ByGameVersion;
sortings.insert(tr("Sort by name"), Sorting::ByName);
sortings.insert(tr("Sort by game version"), Sorting::ByGameVersion);
}
-bool FtbFilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
+bool FilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
- FtbModpack leftPack = sourceModel()->data(left, Qt::UserRole).value<FtbModpack>();
- FtbModpack rightPack = sourceModel()->data(right, Qt::UserRole).value<FtbModpack>();
+ Modpack leftPack = sourceModel()->data(left, Qt::UserRole).value<Modpack>();
+ Modpack rightPack = sourceModel()->data(right, Qt::UserRole).value<Modpack>();
if(currentSorting == Sorting::ByGameVersion) {
Version lv(leftPack.mcVersion);
@@ -38,66 +40,66 @@ bool FtbFilterModel::lessThan(const QModelIndex &left, const QModelIndex &right)
return true;
}
-bool FtbFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
+bool FilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
return true;
}
-const QMap<QString, FtbFilterModel::Sorting> FtbFilterModel::getAvailableSortings()
+const QMap<QString, FilterModel::Sorting> FilterModel::getAvailableSortings()
{
return sortings;
}
-QString FtbFilterModel::translateCurrentSorting()
+QString FilterModel::translateCurrentSorting()
{
return sortings.key(currentSorting);
}
-void FtbFilterModel::setSorting(Sorting s)
+void FilterModel::setSorting(Sorting s)
{
currentSorting = s;
invalidate();
}
-FtbFilterModel::Sorting FtbFilterModel::getCurrentSorting()
+FilterModel::Sorting FilterModel::getCurrentSorting()
{
return currentSorting;
}
-FtbListModel::FtbListModel(QObject *parent) : QAbstractListModel(parent)
+ListModel::ListModel(QObject *parent) : QAbstractListModel(parent)
{
}
-FtbListModel::~FtbListModel()
+ListModel::~ListModel()
{
}
-QString FtbListModel::translatePackType(FtbPackType type) const
+QString ListModel::translatePackType(PackType type) const
{
switch(type)
{
- case FtbPackType::Public:
+ case PackType::Public:
return tr("Public Modpack");
- case FtbPackType::ThirdParty:
+ case PackType::ThirdParty:
return tr("Third Party Modpack");
- case FtbPackType::Private:
+ case PackType::Private:
return tr("Private Modpack");
}
qWarning() << "Unknown FTB modpack type:" << int(type);
return QString();
}
-int FtbListModel::rowCount(const QModelIndex &parent) const
+int ListModel::rowCount(const QModelIndex &parent) const
{
return modpacks.size();
}
-int FtbListModel::columnCount(const QModelIndex &parent) const
+int ListModel::columnCount(const QModelIndex &parent) const
{
return 1;
}
-QVariant FtbListModel::data(const QModelIndex &index, int role) const
+QVariant ListModel::data(const QModelIndex &index, int role) const
{
int pos = index.row();
if(pos >= modpacks.size() || pos < 0 || !index.isValid())
@@ -105,7 +107,7 @@ QVariant FtbListModel::data(const QModelIndex &index, int role) const
return QString("INVALID INDEX %1").arg(pos);
}
- FtbModpack pack = modpacks.at(pos);
+ Modpack pack = modpacks.at(pos);
if(role == Qt::DisplayRole)
{
return pack.name + "\n" + translatePackType(pack.type);
@@ -129,7 +131,7 @@ QVariant FtbListModel::data(const QModelIndex &index, int role) const
return (m_logoMap.value(pack.logo));
}
QIcon icon = MMC->getThemedIcon("screenshot-placeholder");
- ((FtbListModel *)this)->requestLogo(pack.logo);
+ ((ListModel *)this)->requestLogo(pack.logo);
return icon;
}
else if(role == Qt::TextColorRole)
@@ -156,33 +158,33 @@ QVariant FtbListModel::data(const QModelIndex &index, int role) const
return QVariant();
}
-void FtbListModel::fill(FtbModpackList modpacks)
+void ListModel::fill(ModpackList modpacks)
{
beginResetModel();
this->modpacks = modpacks;
endResetModel();
}
-void FtbListModel::addPack(FtbModpack modpack)
+void ListModel::addPack(Modpack modpack)
{
beginResetModel();
this->modpacks.append(modpack);
endResetModel();
}
-void FtbListModel::clear()
+void ListModel::clear()
{
beginResetModel();
modpacks.clear();
endResetModel();
}
-FtbModpack FtbListModel::at(int row)
+Modpack ListModel::at(int row)
{
return modpacks.at(row);
}
-void FtbListModel::remove(int row)
+void ListModel::remove(int row)
{
if(row < 0 || row >= modpacks.size())
{
@@ -194,20 +196,20 @@ void FtbListModel::remove(int row)
endRemoveRows();
}
-void FtbListModel::logoLoaded(QString logo, QIcon out)
+void ListModel::logoLoaded(QString logo, QIcon out)
{
m_loadingLogos.removeAll(logo);
m_logoMap.insert(logo, out);
emit dataChanged(createIndex(0, 0), createIndex(1, 0));
}
-void FtbListModel::logoFailed(QString logo)
+void ListModel::logoFailed(QString logo)
{
m_failedLogos.append(logo);
m_loadingLogos.removeAll(logo);
}
-void FtbListModel::requestLogo(QString file)
+void ListModel::requestLogo(QString file)
{
if(m_loadingLogos.contains(file) || m_failedLogos.contains(file))
{
@@ -216,7 +218,7 @@ void FtbListModel::requestLogo(QString file)
MetaEntryPtr entry = ENV.metacache()->resolveEntry("FTBPacks", QString("logos/%1").arg(file.section(".", 0, 0)));
NetJob *job = new NetJob(QString("FTB Icon Download for %1").arg(file));
- job->addNetAction(Net::Download::makeCached(QUrl(QString(URLConstants::FTB_CDN_BASE_URL + "static/%1").arg(file)), entry));
+ job->addNetAction(Net::Download::makeCached(QUrl(QString(URLConstants::LEGACY_FTB_CDN_BASE_URL + "static/%1").arg(file)), entry));
auto fullPath = entry->getFullPath();
QObject::connect(job, &NetJob::finished, this, [this, file, fullPath]
@@ -238,7 +240,7 @@ void FtbListModel::requestLogo(QString file)
m_loadingLogos.append(file);
}
-void FtbListModel::getLogo(const QString &logo, LogoCallback callback)
+void ListModel::getLogo(const QString &logo, LogoCallback callback)
{
if(m_logoMap.contains(logo))
{
@@ -250,7 +252,9 @@ void FtbListModel::getLogo(const QString &logo, LogoCallback callback)
}
}
-Qt::ItemFlags FtbListModel::flags(const QModelIndex &index) const
+Qt::ItemFlags ListModel::flags(const QModelIndex &index) const
{
return QAbstractListModel::flags(index);
}
+
+}
diff --git a/application/pages/modplatform/FtbListModel.h b/application/pages/modplatform/legacy_ftb/ListModel.h
index 34749b24..c55df000 100644
--- a/application/pages/modplatform/FtbListModel.h
+++ b/application/pages/modplatform/legacy_ftb/ListModel.h
@@ -1,6 +1,6 @@
#pragma once
-#include <modplatform/ftb/PackHelpers.h>
+#include <modplatform/legacy_ftb/PackHelpers.h>
#include <RWStorage.h>
#include <QAbstractListModel>
@@ -11,14 +11,16 @@
#include <functional>
-typedef QMap<QString, QIcon> FtbLogoMap;
+namespace LegacyFTB {
+
+typedef QMap<QString, QIcon> FTBLogoMap;
typedef std::function<void(QString)> LogoCallback;
-class FtbFilterModel : public QSortFilterProxyModel
+class FilterModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
- FtbFilterModel(QObject* parent = Q_NULLPTR);
+ FilterModel(QObject* parent = Q_NULLPTR);
enum Sorting {
ByName,
ByGameVersion
@@ -38,18 +40,18 @@ private:
};
-class FtbListModel : public QAbstractListModel
+class ListModel : public QAbstractListModel
{
Q_OBJECT
private:
- FtbModpackList modpacks;
+ ModpackList modpacks;
QStringList m_failedLogos;
QStringList m_loadingLogos;
- FtbLogoMap m_logoMap;
+ FTBLogoMap m_logoMap;
QMap<QString, LogoCallback> waitingCallbacks;
void requestLogo(QString file);
- QString translatePackType(FtbPackType type) const;
+ QString translatePackType(PackType type) const;
private slots:
@@ -57,18 +59,20 @@ private slots:
void logoLoaded(QString logo, QIcon out);
public:
- FtbListModel(QObject *parent);
- ~FtbListModel();
+ ListModel(QObject *parent);
+ ~ListModel();
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
- void fill(FtbModpackList modpacks);
- void addPack(FtbModpack modpack);
+ void fill(ModpackList modpacks);
+ void addPack(Modpack modpack);
void clear();
void remove(int row);
- FtbModpack at(int row);
+ Modpack at(int row);
void getLogo(const QString &logo, LogoCallback callback);
};
+
+}
diff --git a/application/pages/modplatform/FTBPage.cpp b/application/pages/modplatform/legacy_ftb/Page.cpp
index dca86efd..8e40ba9e 100644
--- a/application/pages/modplatform/FTBPage.cpp
+++ b/application/pages/modplatform/legacy_ftb/Page.cpp
@@ -1,27 +1,29 @@
-#include "FTBPage.h"
-#include "ui_FTBPage.h"
+#include "Page.h"
+#include "ui_Page.h"
#include <QInputDialog>
#include "MultiMC.h"
#include "dialogs/CustomMessageBox.h"
#include "dialogs/NewInstanceDialog.h"
-#include "modplatform/ftb/FtbPackFetchTask.h"
-#include "modplatform/ftb/FtbPackInstallTask.h"
-#include "modplatform/ftb/FtbPrivatePackManager.h"
-#include "FtbListModel.h"
+#include "modplatform/legacy_ftb/PackFetchTask.h"
+#include "modplatform/legacy_ftb/PackInstallTask.h"
+#include "modplatform/legacy_ftb/PrivatePackManager.h"
+#include "ListModel.h"
-FTBPage::FTBPage(NewInstanceDialog* dialog, QWidget *parent)
- : QWidget(parent), dialog(dialog), ui(new Ui::FTBPage)
+namespace LegacyFTB {
+
+Page::Page(NewInstanceDialog* dialog, QWidget *parent)
+ : QWidget(parent), dialog(dialog), ui(new Ui::Page)
{
- ftbFetchTask.reset(new FtbPackFetchTask());
- ftbPrivatePacks.reset(new FtbPrivatePackManager());
+ ftbFetchTask.reset(new PackFetchTask());
+ ftbPrivatePacks.reset(new PrivatePackManager());
ui->setupUi(this);
{
- publicFilterModel = new FtbFilterModel(this);
- publicListModel = new FtbListModel(this);
+ publicFilterModel = new FilterModel(this);
+ publicListModel = new ListModel(this);
publicFilterModel->setSourceModel(publicListModel);
ui->publicPackList->setModel(publicFilterModel);
@@ -39,8 +41,8 @@ FTBPage::FTBPage(NewInstanceDialog* dialog, QWidget *parent)
}
{
- thirdPartyFilterModel = new FtbFilterModel(this);
- thirdPartyModel = new FtbListModel(this);
+ thirdPartyFilterModel = new FilterModel(this);
+ thirdPartyModel = new ListModel(this);
thirdPartyFilterModel->setSourceModel(thirdPartyModel);
ui->thirdPartyPackList->setModel(thirdPartyFilterModel);
@@ -53,8 +55,8 @@ FTBPage::FTBPage(NewInstanceDialog* dialog, QWidget *parent)
}
{
- privateFilterModel = new FtbFilterModel(this);
- privateListModel = new FtbListModel(this);
+ privateFilterModel = new FilterModel(this);
+ privateListModel = new ListModel(this);
privateFilterModel->setSourceModel(privateListModel);
ui->privatePackList->setModel(privateFilterModel);
@@ -69,17 +71,17 @@ FTBPage::FTBPage(NewInstanceDialog* dialog, QWidget *parent)
ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300);
- connect(ui->sortByBox, &QComboBox::currentTextChanged, this, &FTBPage::onSortingSelectionChanged);
- connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &FTBPage::onVersionSelectionItemChanged);
+ connect(ui->sortByBox, &QComboBox::currentTextChanged, this, &Page::onSortingSelectionChanged);
+ connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &Page::onVersionSelectionItemChanged);
- connect(ui->publicPackList->selectionModel(), &QItemSelectionModel::currentChanged, this, &FTBPage::onPublicPackSelectionChanged);
- connect(ui->thirdPartyPackList->selectionModel(), &QItemSelectionModel::currentChanged, this, &FTBPage::onThirdPartyPackSelectionChanged);
- connect(ui->privatePackList->selectionModel(), &QItemSelectionModel::currentChanged, this, &FTBPage::onPrivatePackSelectionChanged);
+ connect(ui->publicPackList->selectionModel(), &QItemSelectionModel::currentChanged, this, &Page::onPublicPackSelectionChanged);
+ connect(ui->thirdPartyPackList->selectionModel(), &QItemSelectionModel::currentChanged, this, &Page::onThirdPartyPackSelectionChanged);
+ connect(ui->privatePackList->selectionModel(), &QItemSelectionModel::currentChanged, this, &Page::onPrivatePackSelectionChanged);
- connect(ui->addPackBtn, &QPushButton::pressed, this, &FTBPage::onAddPackClicked);
- connect(ui->removePackBtn, &QPushButton::pressed, this, &FTBPage::onRemovePackClicked);
+ connect(ui->addPackBtn, &QPushButton::pressed, this, &Page::onAddPackClicked);
+ connect(ui->removePackBtn, &QPushButton::pressed, this, &Page::onRemovePackClicked);
- connect(ui->tabWidget, &QTabWidget::currentChanged, this, &FTBPage::onTabChanged);
+ connect(ui->tabWidget, &QTabWidget::currentChanged, this, &Page::onTabChanged);
// ui->modpackInfo->setOpenExternalLinks(true);
@@ -90,25 +92,25 @@ FTBPage::FTBPage(NewInstanceDialog* dialog, QWidget *parent)
onTabChanged(ui->tabWidget->currentIndex());
}
-FTBPage::~FTBPage()
+Page::~Page()
{
delete ui;
}
-bool FTBPage::shouldDisplay() const
+bool Page::shouldDisplay() const
{
return true;
}
-void FTBPage::openedImpl()
+void Page::openedImpl()
{
if(!initialized)
{
- connect(ftbFetchTask.get(), &FtbPackFetchTask::finished, this, &FTBPage::ftbPackDataDownloadSuccessfully);
- connect(ftbFetchTask.get(), &FtbPackFetchTask::failed, this, &FTBPage::ftbPackDataDownloadFailed);
+ connect(ftbFetchTask.get(), &PackFetchTask::finished, this, &Page::ftbPackDataDownloadSuccessfully);
+ connect(ftbFetchTask.get(), &PackFetchTask::failed, this, &Page::ftbPackDataDownloadFailed);
- connect(ftbFetchTask.get(), &FtbPackFetchTask::privateFileDownloadFinished, this, &FTBPage::ftbPrivatePackDataDownloadSuccessfully);
- connect(ftbFetchTask.get(), &FtbPackFetchTask::privateFileDownloadFailed, this, &FTBPage::ftbPrivatePackDataDownloadFailed);
+ connect(ftbFetchTask.get(), &PackFetchTask::privateFileDownloadFinished, this, &Page::ftbPrivatePackDataDownloadSuccessfully);
+ connect(ftbFetchTask.get(), &PackFetchTask::privateFileDownloadFailed, this, &Page::ftbPrivatePackDataDownloadFailed);
ftbFetchTask->fetch();
ftbPrivatePacks->load();
@@ -118,13 +120,13 @@ void FTBPage::openedImpl()
suggestCurrent();
}
-void FTBPage::suggestCurrent()
+void Page::suggestCurrent()
{
if(isOpened)
{
if(!selected.broken)
{
- dialog->setSuggestedPack(selected.name, new FtbPackInstallTask(selected, selectedVersion));
+ dialog->setSuggestedPack(selected.name, new PackInstallTask(selected, selectedVersion));
QString editedLogoName;
if(selected.logo.toLower().startsWith("ftb"))
{
@@ -137,21 +139,21 @@ void FTBPage::suggestCurrent()
editedLogoName = editedLogoName.left(editedLogoName.lastIndexOf(".png"));
- if(selected.type == FtbPackType::Public)
+ if(selected.type == PackType::Public)
{
publicListModel->getLogo(selected.logo, [this, editedLogoName](QString logo)
{
dialog->setSuggestedIconFromFile(logo, editedLogoName);
});
}
- else if (selected.type == FtbPackType::ThirdParty)
+ else if (selected.type == PackType::ThirdParty)
{
thirdPartyModel->getLogo(selected.logo, [this, editedLogoName](QString logo)
{
dialog->setSuggestedIconFromFile(logo, editedLogoName);
});
}
- else if (selected.type == FtbPackType::Private)
+ else if (selected.type == PackType::Private)
{
privateListModel->getLogo(selected.logo, [this, editedLogoName](QString logo)
{
@@ -166,23 +168,23 @@ void FTBPage::suggestCurrent()
}
}
-void FTBPage::ftbPackDataDownloadSuccessfully(FtbModpackList publicPacks, FtbModpackList thirdPartyPacks)
+void Page::ftbPackDataDownloadSuccessfully(ModpackList publicPacks, ModpackList thirdPartyPacks)
{
publicListModel->fill(publicPacks);
thirdPartyModel->fill(thirdPartyPacks);
}
-void FTBPage::ftbPackDataDownloadFailed(QString reason)
+void Page::ftbPackDataDownloadFailed(QString reason)
{
//TODO: Display the error
}
-void FTBPage::ftbPrivatePackDataDownloadSuccessfully(FtbModpack pack)
+void Page::ftbPrivatePackDataDownloadSuccessfully(Modpack pack)
{
privateListModel->addPack(pack);
}
-void FTBPage::ftbPrivatePackDataDownloadFailed(QString reason, QString packCode)
+void Page::ftbPrivatePackDataDownloadFailed(QString reason, QString packCode)
{
auto reply = QMessageBox::question(
this,
@@ -195,40 +197,40 @@ void FTBPage::ftbPrivatePackDataDownloadFailed(QString reason, QString packCode)
}
}
-void FTBPage::onPublicPackSelectionChanged(QModelIndex now, QModelIndex prev)
+void Page::onPublicPackSelectionChanged(QModelIndex now, QModelIndex prev)
{
if(!now.isValid())
{
onPackSelectionChanged();
return;
}
- FtbModpack selectedPack = publicFilterModel->data(now, Qt::UserRole).value<FtbModpack>();
+ Modpack selectedPack = publicFilterModel->data(now, Qt::UserRole).value<Modpack>();
onPackSelectionChanged(&selectedPack);
}
-void FTBPage::onThirdPartyPackSelectionChanged(QModelIndex now, QModelIndex prev)
+void Page::onThirdPartyPackSelectionChanged(QModelIndex now, QModelIndex prev)
{
if(!now.isValid())
{
onPackSelectionChanged();
return;
}
- FtbModpack selectedPack = thirdPartyFilterModel->data(now, Qt::UserRole).value<FtbModpack>();
+ Modpack selectedPack = thirdPartyFilterModel->data(now, Qt::UserRole).value<Modpack>();
onPackSelectionChanged(&selectedPack);
}
-void FTBPage::onPrivatePackSelectionChanged(QModelIndex now, QModelIndex prev)
+void Page::onPrivatePackSelectionChanged(QModelIndex now, QModelIndex prev)
{
if(!now.isValid())
{
onPackSelectionChanged();
return;
}
- FtbModpack selectedPack = privateFilterModel->data(now, Qt::UserRole).value<FtbModpack>();
+ Modpack selectedPack = privateFilterModel->data(now, Qt::UserRole).value<Modpack>();
onPackSelectionChanged(&selectedPack);
}
-void FTBPage::onPackSelectionChanged(FtbModpack* pack)
+void Page::onPackSelectionChanged(Modpack* pack)
{
ui->versionSelectionBox->clear();
if(pack)
@@ -266,7 +268,7 @@ void FTBPage::onPackSelectionChanged(FtbModpack* pack)
suggestCurrent();
}
-void FTBPage::onVersionSelectionItemChanged(QString data)
+void Page::onVersionSelectionItemChanged(QString data)
{
if(data.isNull() || data.isEmpty())
{
@@ -278,15 +280,15 @@ void FTBPage::onVersionSelectionItemChanged(QString data)
suggestCurrent();
}
-void FTBPage::onSortingSelectionChanged(QString data)
+void Page::onSortingSelectionChanged(QString data)
{
- FtbFilterModel::Sorting toSet = publicFilterModel->getAvailableSortings().value(data);
+ FilterModel::Sorting toSet = publicFilterModel->getAvailableSortings().value(data);
publicFilterModel->setSorting(toSet);
thirdPartyFilterModel->setSorting(toSet);
privateFilterModel->setSorting(toSet);
}
-void FTBPage::onTabChanged(int tab)
+void Page::onTabChanged(int tab)
{
if(tab == 1)
{
@@ -311,7 +313,7 @@ void FTBPage::onTabChanged(int tab)
QModelIndex idx = currentList->currentIndex();
if(idx.isValid())
{
- auto pack = currentModel->data(idx, Qt::UserRole).value<FtbModpack>();
+ auto pack = currentModel->data(idx, Qt::UserRole).value<Modpack>();
onPackSelectionChanged(&pack);
}
else
@@ -320,7 +322,7 @@ void FTBPage::onTabChanged(int tab)
}
}
-void FTBPage::onAddPackClicked()
+void Page::onAddPackClicked()
{
bool ok;
QString text = QInputDialog::getText(
@@ -338,7 +340,7 @@ void FTBPage::onAddPackClicked()
}
}
-void FTBPage::onRemovePackClicked()
+void Page::onRemovePackClicked()
{
auto index = ui->privatePackList->currentIndex();
if(!index.isValid())
@@ -346,7 +348,7 @@ void FTBPage::onRemovePackClicked()
return;
}
auto row = index.row();
- FtbModpack pack = privateListModel->at(row);
+ Modpack pack = privateListModel->at(row);
auto answer = QMessageBox::question(
this,
tr("Remove pack"),
@@ -362,3 +364,5 @@ void FTBPage::onRemovePackClicked()
privateListModel->remove(row);
onPackSelectionChanged();
}
+
+}
diff --git a/application/pages/modplatform/FTBPage.h b/application/pages/modplatform/legacy_ftb/Page.h
index 215252ee..ed6d1657 100644
--- a/application/pages/modplatform/FTBPage.h
+++ b/application/pages/modplatform/legacy_ftb/Page.h
@@ -22,29 +22,32 @@
#include "pages/BasePage.h"
#include <MultiMC.h>
#include "tasks/Task.h"
-#include "modplatform/ftb/PackHelpers.h"
-#include "modplatform/ftb/FtbPackFetchTask.h"
+#include "modplatform/legacy_ftb/PackHelpers.h"
+#include "modplatform/legacy_ftb/PackFetchTask.h"
#include "QObjectPtr.h"
+class NewInstanceDialog;
+
+namespace LegacyFTB {
+
namespace Ui
{
-class FTBPage;
+class Page;
}
-class FtbListModel;
-class FtbFilterModel;
-class NewInstanceDialog;
-class FtbPrivatePackListModel;
-class FtbPrivatePackFilterModel;
-class FtbPrivatePackManager;
+class ListModel;
+class FilterModel;
+class PrivatePackListModel;
+class PrivatePackFilterModel;
+class PrivatePackManager;
-class FTBPage : public QWidget, public BasePage
+class Page : public QWidget, public BasePage
{
Q_OBJECT
public:
- explicit FTBPage(NewInstanceDialog * dialog, QWidget *parent = 0);
- virtual ~FTBPage();
+ explicit Page(NewInstanceDialog * dialog, QWidget *parent = 0);
+ virtual ~Page();
QString displayName() const override
{
return tr("FTB Legacy");
@@ -55,7 +58,7 @@ public:
}
QString id() const override
{
- return "ftb";
+ return "legacy_ftb";
}
QString helpPage() const override
{
@@ -66,13 +69,13 @@ public:
private:
void suggestCurrent();
- void onPackSelectionChanged(FtbModpack *pack = nullptr);
+ void onPackSelectionChanged(Modpack *pack = nullptr);
private slots:
- void ftbPackDataDownloadSuccessfully(FtbModpackList publicPacks, FtbModpackList thirdPartyPacks);
+ void ftbPackDataDownloadSuccessfully(ModpackList publicPacks, ModpackList thirdPartyPacks);
void ftbPackDataDownloadFailed(QString reason);
- void ftbPrivatePackDataDownloadSuccessfully(FtbModpack pack);
+ void ftbPrivatePackDataDownloadSuccessfully(Modpack pack);
void ftbPrivatePackDataDownloadFailed(QString reason, QString packCode);
void onSortingSelectionChanged(QString data);
@@ -88,27 +91,29 @@ private slots:
void onRemovePackClicked();
private:
- FtbFilterModel* currentModel = nullptr;
+ FilterModel* currentModel = nullptr;
QTreeView* currentList = nullptr;
QTextBrowser* currentModpackInfo = nullptr;
bool initialized = false;
- FtbModpack selected;
+ Modpack selected;
QString selectedVersion;
- FtbListModel* publicListModel = nullptr;
- FtbFilterModel* publicFilterModel = nullptr;
+ ListModel* publicListModel = nullptr;
+ FilterModel* publicFilterModel = nullptr;
- FtbListModel *thirdPartyModel = nullptr;
- FtbFilterModel *thirdPartyFilterModel = nullptr;
+ ListModel *thirdPartyModel = nullptr;
+ FilterModel *thirdPartyFilterModel = nullptr;
- FtbListModel *privateListModel = nullptr;
- FtbFilterModel *privateFilterModel = nullptr;
+ ListModel *privateListModel = nullptr;
+ FilterModel *privateFilterModel = nullptr;
- unique_qobject_ptr<FtbPackFetchTask> ftbFetchTask;
- std::unique_ptr<FtbPrivatePackManager> ftbPrivatePacks;
+ unique_qobject_ptr<PackFetchTask> ftbFetchTask;
+ std::unique_ptr<PrivatePackManager> ftbPrivatePacks;
NewInstanceDialog* dialog = nullptr;
- Ui::FTBPage *ui = nullptr;
+ Ui::Page *ui = nullptr;
};
+
+}
diff --git a/application/pages/modplatform/FTBPage.ui b/application/pages/modplatform/legacy_ftb/Page.ui
index e5ed78cb..36fb2359 100644
--- a/application/pages/modplatform/FTBPage.ui
+++ b/application/pages/modplatform/legacy_ftb/Page.ui
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
- <class>FTBPage</class>
- <widget class="QWidget" name="FTBPage">
+ <class>LegacyFTB::Page</class>
+ <widget class="QWidget" name="LegacyFTB::Page">
<property name="geometry">
<rect>
<x>0</x>
diff --git a/application/pages/modplatform/twitch/TwitchData.h b/application/pages/modplatform/twitch/TwitchData.h
new file mode 100644
index 00000000..dd000b84
--- /dev/null
+++ b/application/pages/modplatform/twitch/TwitchData.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <QString>
+#include <QList>
+
+namespace Twitch {
+
+struct ModpackAuthor {
+ QString name;
+ QString url;
+};
+
+struct ModpackFile {
+ int addonId;
+ int fileId;
+ QString version;
+ QString mcVersion;
+ QString downloadUrl;
+};
+
+struct Modpack
+{
+ bool broken = true;
+ int addonId = 0;
+
+ QString name;
+ QString description;
+ QList<ModpackAuthor> authors;
+ QString mcVersion;
+ QString logoName;
+ QString logoUrl;
+ QString websiteUrl;
+
+ ModpackFile latestFile;
+};
+}
+
+Q_DECLARE_METATYPE(Twitch::Modpack)
diff --git a/application/pages/modplatform/twitch/TwitchModel.cpp b/application/pages/modplatform/twitch/TwitchModel.cpp
new file mode 100644
index 00000000..d9358941
--- /dev/null
+++ b/application/pages/modplatform/twitch/TwitchModel.cpp
@@ -0,0 +1,314 @@
+#include "TwitchModel.h"
+#include "MultiMC.h"
+
+#include <MMCStrings.h>
+#include <Version.h>
+
+#include <QtMath>
+#include <QLabel>
+
+#include <RWStorage.h>
+#include <Env.h>
+
+#include "net/URLConstants.h"
+
+namespace Twitch {
+
+ListModel::ListModel(QObject *parent) : QAbstractListModel(parent)
+{
+}
+
+ListModel::~ListModel()
+{
+}
+
+int ListModel::rowCount(const QModelIndex &parent) const
+{
+ return modpacks.size();
+}
+
+int ListModel::columnCount(const QModelIndex &parent) const
+{
+ return 1;
+}
+
+QVariant ListModel::data(const QModelIndex &index, int role) const
+{
+ int pos = index.row();
+ if(pos >= modpacks.size() || pos < 0 || !index.isValid())
+ {
+ return QString("INVALID INDEX %1").arg(pos);
+ }
+
+ Modpack pack = modpacks.at(pos);
+ if(role == Qt::DisplayRole)
+ {
+ return pack.name;
+ }
+ else if (role == Qt::ToolTipRole)
+ {
+ if(pack.description.length() > 100)
+ {
+ //some magic to prevent to long tooltips and replace html linebreaks
+ QString edit = pack.description.left(97);
+ edit = edit.left(edit.lastIndexOf("<br>")).left(edit.lastIndexOf(" ")).append("...");
+ return edit;
+
+ }
+ return pack.description;
+ }
+ else if(role == Qt::DecorationRole)
+ {
+ if(m_logoMap.contains(pack.logoName))
+ {
+ return (m_logoMap.value(pack.logoName));
+ }
+ QIcon icon = MMC->getThemedIcon("screenshot-placeholder");
+ ((ListModel *)this)->requestLogo(pack.logoName, pack.logoUrl);
+ return icon;
+ }
+ else if(role == Qt::UserRole)
+ {
+ QVariant v;
+ v.setValue(pack);
+ return v;
+ }
+
+ return QVariant();
+}
+
+void ListModel::logoLoaded(QString logo, QIcon out)
+{
+ m_loadingLogos.removeAll(logo);
+ m_logoMap.insert(logo, out);
+ for(int i = 0; i < modpacks.size(); i++) {
+ if(modpacks[i].logoName == logo) {
+ emit dataChanged(createIndex(i, 0), createIndex(i, 0), {Qt::DecorationRole});
+ }
+ }
+}
+
+void ListModel::logoFailed(QString logo)
+{
+ m_failedLogos.append(logo);
+ m_loadingLogos.removeAll(logo);
+}
+
+void ListModel::requestLogo(QString logo, QString url)
+{
+ if(m_loadingLogos.contains(logo) || m_failedLogos.contains(logo))
+ {
+ return;
+ }
+
+ MetaEntryPtr entry = ENV.metacache()->resolveEntry("TwitchPacks", QString("logos/%1").arg(logo.section(".", 0, 0)));
+ NetJob *job = new NetJob(QString("Twitch Icon Download %1").arg(logo));
+ job->addNetAction(Net::Download::makeCached(QUrl(url), entry));
+
+ auto fullPath = entry->getFullPath();
+ QObject::connect(job, &NetJob::finished, this, [this, logo, fullPath]
+ {
+ emit logoLoaded(logo, QIcon(fullPath));
+ if(waitingCallbacks.contains(logo))
+ {
+ waitingCallbacks.value(logo)(fullPath);
+ }
+ });
+
+ QObject::connect(job, &NetJob::failed, this, [this, logo]
+ {
+ emit logoFailed(logo);
+ });
+
+ job->start();
+
+ m_loadingLogos.append(logo);
+}
+
+void ListModel::getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback)
+{
+ if(m_logoMap.contains(logo))
+ {
+ callback(ENV.metacache()->resolveEntry("TwitchPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath());
+ }
+ else
+ {
+ requestLogo(logo, logoUrl);
+ }
+}
+
+Qt::ItemFlags ListModel::flags(const QModelIndex &index) const
+{
+ return QAbstractListModel::flags(index);
+}
+
+bool ListModel::canFetchMore(const QModelIndex& parent) const
+{
+ return searchState == CanPossiblyFetchMore;
+}
+
+void ListModel::fetchMore(const QModelIndex& parent)
+{
+ if (parent.isValid())
+ return;
+ if(nextSearchOffset == 0) {
+ qWarning() << "fetchMore with 0 offset is wrong...";
+ return;
+ }
+ performPaginatedSearch();
+}
+
+void ListModel::performPaginatedSearch()
+{
+ NetJob *netJob = new NetJob("Twitch::Search");
+ auto searchUrl = QString(
+ "https://addons-ecs.forgesvc.net/api/v2/addon/search?"
+ "categoryId=0&"
+ "gameId=432&"
+ //"gameVersion=1.12.2&"
+ "index=%1&"
+ "pageSize=25&"
+ "searchFilter=%2&"
+ "sectionId=4471&"
+ "sort=0"
+ ).arg(nextSearchOffset).arg(currentSearchTerm);
+ netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response));
+ jobPtr = netJob;
+ jobPtr->start();
+ QObject::connect(netJob, &NetJob::succeeded, this, &ListModel::searchRequestFinished);
+ QObject::connect(netJob, &NetJob::failed, this, &ListModel::searchRequestFailed);
+}
+
+void ListModel::searchWithTerm(const QString& term)
+{
+ if(currentSearchTerm == term) {
+ return;
+ }
+ currentSearchTerm = term;
+ if(jobPtr) {
+ jobPtr->abort();
+ searchState = ResetRequested;
+ return;
+ }
+ else {
+ beginResetModel();
+ modpacks.clear();
+ endResetModel();
+ searchState = None;
+ }
+ nextSearchOffset = 0;
+ performPaginatedSearch();
+}
+
+void Twitch::ListModel::searchRequestFinished()
+{
+ jobPtr.reset();
+
+ QJsonParseError parse_error;
+ QJsonDocument doc = QJsonDocument::fromJson(response, &parse_error);
+ if(parse_error.error != QJsonParseError::NoError) {
+ qWarning() << "Error while parsing JSON response from Twitch at " << parse_error.offset << " reason: " << parse_error.errorString();
+ qWarning() << response;
+ return;
+ }
+
+ QList<Modpack> newList;
+ auto objs = doc.array();
+ for(auto projectIter: objs) {
+ Modpack pack;
+ auto project = projectIter.toObject();
+ pack.addonId = project.value("id").toInt(0);
+ if (pack.addonId == 0) {
+ qWarning() << "Pack without an ID, skipping: " << pack.name;
+ continue;
+ }
+ pack.name = project.value("name").toString();
+ pack.websiteUrl = project.value("websiteUrl").toString();
+ pack.description = project.value("summary").toString();
+ bool thumbnailFound = false;
+ auto attachments = project.value("attachments").toArray();
+ for(auto attachmentIter: attachments) {
+ auto attachment = attachmentIter.toObject();
+ bool isDefault = attachment.value("isDefault").toBool(false);
+ if(isDefault) {
+ thumbnailFound = true;
+ pack.logoName = attachment.value("title").toString();
+ pack.logoUrl = attachment.value("thumbnailUrl").toString();
+ break;
+ }
+ }
+ if(!thumbnailFound) {
+ qWarning() << "Pack without an icon, skipping: " << pack.name;
+ continue;
+ }
+ auto authors = project.value("authors").toArray();
+ for(auto authorIter: authors) {
+ auto author = authorIter.toObject();
+ ModpackAuthor packAuthor;
+ packAuthor.name = author.value("name").toString();
+ packAuthor.url = author.value("url").toString();
+ pack.authors.append(packAuthor);
+ }
+ int defaultFileId = project.value("defaultFileId").toInt(0);
+ if(defaultFileId == 0) {
+ qWarning() << "Pack without default file, skipping: " << pack.name;
+ continue;
+ }
+ bool found = false;
+ auto files = project.value("latestFiles").toArray();
+ for(auto fileIter: files) {
+ auto file = fileIter.toObject();
+ int id = file.value("id").toInt(0);
+ // NOTE: for now, ignore everything that's not the default...
+ if(id != defaultFileId) {
+ continue;
+ }
+ pack.latestFile.addonId = pack.addonId;
+ pack.latestFile.fileId = id;
+ // FIXME: what to do when there's more than one, or there's no version?
+ auto versionArray = file.value("gameVersion").toArray();
+ if(versionArray.size() != 1) {
+ continue;
+ }
+ pack.latestFile.mcVersion = versionArray[0].toString();
+ pack.latestFile.version = file.value("displayName").toString();
+ pack.latestFile.downloadUrl = file.value("downloadUrl").toString();
+ found = true;
+ break;
+ }
+ if(!found) {
+ qWarning() << "Pack with no good file, skipping: " << pack.name;
+ continue;
+ }
+ pack.broken = false;
+ newList.append(pack);
+ }
+ if(objs.size() < 25) {
+ searchState = Finished;
+ } else {
+ nextSearchOffset += 25;
+ searchState = CanPossiblyFetchMore;
+ }
+ beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + newList.size() - 1);
+ modpacks.append(newList);
+ endInsertRows();
+}
+
+void Twitch::ListModel::searchRequestFailed(QString reason)
+{
+ jobPtr.reset();
+
+ if(searchState == ResetRequested) {
+ beginResetModel();
+ modpacks.clear();
+ endResetModel();
+
+ nextSearchOffset = 0;
+ performPaginatedSearch();
+ } else {
+ searchState = Finished;
+ }
+}
+
+}
+
diff --git a/application/pages/modplatform/twitch/TwitchModel.h b/application/pages/modplatform/twitch/TwitchModel.h
new file mode 100644
index 00000000..ad355c64
--- /dev/null
+++ b/application/pages/modplatform/twitch/TwitchModel.h
@@ -0,0 +1,76 @@
+#pragma once
+
+#include <modplatform/legacy_ftb/PackHelpers.h>
+#include <RWStorage.h>
+
+#include <QAbstractListModel>
+#include <QSortFilterProxyModel>
+#include <QThreadPool>
+#include <QIcon>
+#include <QStyledItemDelegate>
+#include <QList>
+#include <QString>
+#include <QStringList>
+#include <QMetaType>
+
+#include <functional>
+#include <net/NetJob.h>
+
+#include "TwitchData.h"
+
+namespace Twitch {
+
+
+typedef QMap<QString, QIcon> LogoMap;
+typedef std::function<void(QString)> LogoCallback;
+
+class ListModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ ListModel(QObject *parent);
+ virtual ~ListModel();
+
+ int rowCount(const QModelIndex &parent) const override;
+ int columnCount(const QModelIndex &parent) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+ Qt::ItemFlags flags(const QModelIndex &index) const override;
+ bool canFetchMore(const QModelIndex & parent) const override;
+ void fetchMore(const QModelIndex & parent) override;
+
+ void getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback);
+ void searchWithTerm(const QString & term);
+
+private slots:
+ void performPaginatedSearch();
+
+ void logoFailed(QString logo);
+ void logoLoaded(QString logo, QIcon out);
+
+ void searchRequestFinished();
+ void searchRequestFailed(QString reason);
+
+private:
+ void requestLogo(QString file, QString url);
+
+private:
+ QList<Modpack> modpacks;
+ QStringList m_failedLogos;
+ QStringList m_loadingLogos;
+ LogoMap m_logoMap;
+ QMap<QString, LogoCallback> waitingCallbacks;
+
+ QString currentSearchTerm;
+ int nextSearchOffset = 0;
+ enum SearchState {
+ None,
+ CanPossiblyFetchMore,
+ ResetRequested,
+ Finished
+ } searchState = None;
+ NetJobPtr jobPtr;
+ QByteArray response;
+};
+
+}
diff --git a/application/pages/modplatform/twitch/TwitchPage.cpp b/application/pages/modplatform/twitch/TwitchPage.cpp
new file mode 100644
index 00000000..1e9f9dbb
--- /dev/null
+++ b/application/pages/modplatform/twitch/TwitchPage.cpp
@@ -0,0 +1,111 @@
+#include "TwitchPage.h"
+#include "ui_TwitchPage.h"
+
+#include "MultiMC.h"
+#include "dialogs/NewInstanceDialog.h"
+#include <InstanceImportTask.h>
+#include "TwitchModel.h"
+#include <QKeyEvent>
+
+TwitchPage::TwitchPage(NewInstanceDialog* dialog, QWidget *parent)
+ : QWidget(parent), ui(new Ui::TwitchPage), dialog(dialog)
+{
+ ui->setupUi(this);
+ connect(ui->searchButton, &QPushButton::clicked, this, &TwitchPage::triggerSearch);
+ ui->searchEdit->installEventFilter(this);
+ model = new Twitch::ListModel(this);
+ ui->packView->setModel(model);
+ connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &TwitchPage::onSelectionChanged);
+}
+
+TwitchPage::~TwitchPage()
+{
+ delete ui;
+}
+
+bool TwitchPage::eventFilter(QObject* watched, QEvent* event)
+{
+ if (watched == ui->searchEdit && event->type() == QEvent::KeyPress) {
+ QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
+ if (keyEvent->key() == Qt::Key_Return) {
+ triggerSearch();
+ keyEvent->accept();
+ return true;
+ }
+ }
+ return QWidget::eventFilter(watched, event);
+}
+
+bool TwitchPage::shouldDisplay() const
+{
+ return true;
+}
+
+void TwitchPage::openedImpl()
+{
+ suggestCurrent();
+}
+
+void TwitchPage::triggerSearch()
+{
+ model->searchWithTerm(ui->searchEdit->text());
+}
+
+void TwitchPage::onSelectionChanged(QModelIndex first, QModelIndex second)
+{
+ if(!first.isValid())
+ {
+ if(isOpened)
+ {
+ dialog->setSuggestedPack();
+ }
+ ui->frame->clear();
+ return;
+ }
+
+ current = model->data(first, Qt::UserRole).value<Twitch::Modpack>();
+ QString text = "";
+ QString name = current.name;
+
+ if (current.websiteUrl.isEmpty())
+ text = name;
+ else
+ text = "<a href=\"" + current.websiteUrl + "\">" + name + "</a>";
+ if (!current.authors.empty()) {
+ auto authorToStr = [](Twitch::ModpackAuthor & author) {
+ if(author.url.isEmpty()) {
+ return author.name;
+ }
+ return QString("<a href=\"%1\">%2</a>").arg(author.url, author.name);
+ };
+ QStringList authorStrs;
+ for(auto & author: current.authors) {
+ authorStrs.push_back(authorToStr(author));
+ }
+ text += tr(" by ") + authorStrs.join(", ");
+ }
+
+ ui->frame->setModText(text);
+ ui->frame->setModDescription(current.description);
+ suggestCurrent();
+}
+
+void TwitchPage::suggestCurrent()
+{
+ if(!isOpened)
+ {
+ return;
+ }
+ if(current.broken)
+ {
+ dialog->setSuggestedPack();
+ }
+
+ dialog->setSuggestedPack(current.name, new InstanceImportTask(current.latestFile.downloadUrl));
+ QString editedLogoName;
+ editedLogoName = "twitch_" + current.logoName.section(".", 0, 0);
+ model->getLogo(current.logoName, current.logoUrl, [this, editedLogoName](QString logo)
+ {
+ dialog->setSuggestedIconFromFile(logo, editedLogoName);
+ });
+}
diff --git a/application/pages/modplatform/TwitchPage.h b/application/pages/modplatform/twitch/TwitchPage.h
index 600913cd..04e3a1c6 100644
--- a/application/pages/modplatform/TwitchPage.h
+++ b/application/pages/modplatform/twitch/TwitchPage.h
@@ -20,7 +20,7 @@
#include "pages/BasePage.h"
#include <MultiMC.h>
#include "tasks/Task.h"
-#include "modplatform/flame/UrlResolvingTask.h"
+#include "TwitchData.h"
namespace Ui
{
@@ -29,6 +29,10 @@ class TwitchPage;
class NewInstanceDialog;
+namespace Twitch {
+ class ListModel;
+}
+
class TwitchPage : public QWidget, public BasePage
{
Q_OBJECT
@@ -38,7 +42,7 @@ public:
virtual ~TwitchPage();
virtual QString displayName() const override
{
- return tr("Twitch URL");
+ return tr("Twitch");
}
virtual QIcon icon() const override
{
@@ -56,14 +60,18 @@ public:
void openedImpl() override;
- void setUrl(const QString & url);
+ bool eventFilter(QObject * watched, QEvent * event) override;
+
+private:
+ void suggestCurrent();
private slots:
- void triggerCheck(bool checked);
- void checkDone();
+ void triggerSearch();
+ void onSelectionChanged(QModelIndex first, QModelIndex second);
private:
Ui::TwitchPage *ui = nullptr;
NewInstanceDialog* dialog = nullptr;
- shared_qobject_ptr<Flame::UrlResolvingTask> m_modIdResolver;
+ Twitch::ListModel* model = nullptr;
+ Twitch::Modpack current;
};
diff --git a/application/pages/modplatform/twitch/TwitchPage.ui b/application/pages/modplatform/twitch/TwitchPage.ui
new file mode 100644
index 00000000..29bdc727
--- /dev/null
+++ b/application/pages/modplatform/twitch/TwitchPage.ui
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TwitchPage</class>
+ <widget class="QWidget" name="TwitchPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>875</width>
+ <height>745</height>
+ </rect>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLineEdit" name="searchEdit"/>
+ </item>
+ <item row="0" column="1">
+ <widget class="QPushButton" name="searchButton">
+ <property name="text">
+ <string>Search</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2">
+ <widget class="QTreeView" name="packView">
+ <property name="horizontalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOff</enum>
+ </property>
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>48</width>
+ <height>48</height>
+ </size>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ <property name="itemsExpandable">
+ <bool>false</bool>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <attribute name="headerVisible">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ </item>
+ <item row="2" column="0" colspan="2">
+ <widget class="MCModInfoFrame" name="frame">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>MCModInfoFrame</class>
+ <extends>QFrame</extends>
+ <header>widgets/MCModInfoFrame.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <tabstops>
+ <tabstop>searchEdit</tabstop>
+ <tabstop>searchButton</tabstop>
+ <tabstop>packView</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/application/resources/assets/assets.qrc b/application/resources/assets/assets.qrc
deleted file mode 100644
index 38638e7f..00000000
--- a/application/resources/assets/assets.qrc
+++ /dev/null
@@ -1,7 +0,0 @@
-<!DOCTYPE RCC>
-<RCC version="1.0">
- <qresource prefix="/assets">
- <file alias="underconstruction">underconstruction.png</file>
- <file alias="deadglitch">deadglitch.svg</file>
- </qresource>
-</RCC>
diff --git a/application/resources/assets/deadglitch.svg b/application/resources/assets/deadglitch.svg
deleted file mode 100644
index 5682b8a3..00000000
--- a/application/resources/assets/deadglitch.svg
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- class="tw-svg__asset tw-svg__asset--deadglitch tw-svg__asset--inherit"
- width="92px"
- height="96px"
- version="1.1"
- viewBox="0 0 30 30"
- x="0px"
- y="0px"
- id="svg8"
- sodipodi:docname="deadglitch.svg"
- inkscape:version="0.92.2 2405546, 2018-03-11">
- <metadata
- id="metadata14">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <defs
- id="defs12" />
- <sodipodi:namedview
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1"
- objecttolerance="10"
- gridtolerance="10"
- guidetolerance="10"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:window-width="1353"
- inkscape:window-height="828"
- id="namedview10"
- showgrid="false"
- inkscape:zoom="4.9166667"
- inkscape:cx="44.285787"
- inkscape:cy="52.833458"
- inkscape:window-x="2958"
- inkscape:window-y="702"
- inkscape:window-maximized="0"
- inkscape:current-layer="svg8" />
- <g
- id="g6"
- style="fill:#898395;fill-opacity:1">
- <path
- d="M26,17.4589613 L26,3 L4,3 L4,22.0601057 L10.0032868,22.0601057 L10.0032868,26 L14.0004537,22.0601057 L21.3322933,22.0601057 L26,17.4589613 L26,17.4589613 Z M21.0896458,26.0850335 L15.1583403,26.0850335 L11.2051771,30 L7.24798611,30 L7.24798611,26.0850335 L0,26.0850335 L0,5.21746493 L1.97773958,0 L29,0 L29,18.2620736 L21.0896458,26.0850335 L21.0896458,26.0850335 Z"
- id="path2"
- style="fill:#898395;fill-opacity:1" />
- <path
- d="M20.8587626,12.1710126 L22.4052753,13.7175252 L23.7175252,12.4052753 L22.1710126,10.8587626 L23.7175252,9.31224999 L22.4052753,8 L20.8587626,9.54651264 L19.31225,8 L18,9.31224999 L19.5465126,10.8587626 L18,12.4052753 L19.31225,13.7175252 L20.8587626,12.1710126 Z M11.8587626,12.1710126 L13.4052753,13.7175252 L14.7175252,12.4052753 L13.1710126,10.8587626 L14.7175252,9.31224999 L13.4052753,8 L11.8587626,9.54651264 L10.31225,8 L9,9.31224999 L10.5465126,10.8587626 L9,12.4052753 L10.31225,13.7175252 L11.8587626,12.1710126 Z"
- id="path4"
- style="fill:#898395;fill-opacity:1" />
- </g>
-</svg>
diff --git a/application/resources/assets/underconstruction.png b/application/resources/assets/underconstruction.png
deleted file mode 100644
index 6ae06476..00000000
--- a/application/resources/assets/underconstruction.png
+++ /dev/null
Binary files differ
diff --git a/application/widgets/DropLabel.cpp b/application/widgets/DropLabel.cpp
new file mode 100644
index 00000000..a900e57c
--- /dev/null
+++ b/application/widgets/DropLabel.cpp
@@ -0,0 +1,41 @@
+#include "DropLabel.h"
+
+#include <QMimeData>
+#include <QDropEvent>
+
+DropLabel::DropLabel(QWidget *parent) : QLabel(parent)
+{
+ setAcceptDrops(true);
+}
+
+void DropLabel::dragEnterEvent(QDragEnterEvent *event)
+{
+ event->acceptProposedAction();
+}
+
+void DropLabel::dragMoveEvent(QDragMoveEvent *event)
+{
+ event->acceptProposedAction();
+}
+
+void DropLabel::dragLeaveEvent(QDragLeaveEvent *event)
+{
+ event->accept();
+}
+
+void DropLabel::dropEvent(QDropEvent *event)
+{
+ const QMimeData *mimeData = event->mimeData();
+
+ if (!mimeData)
+ {
+ return;
+ }
+
+ if (mimeData->hasUrls()) {
+ auto urls = mimeData->urls();
+ emit droppedURLs(urls);
+ }
+
+ event->acceptProposedAction();
+}
diff --git a/application/widgets/DropLabel.h b/application/widgets/DropLabel.h
new file mode 100644
index 00000000..c5ca0bcc
--- /dev/null
+++ b/application/widgets/DropLabel.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <QLabel>
+
+class DropLabel : public QLabel
+{
+ Q_OBJECT
+
+public:
+ explicit DropLabel(QWidget *parent = nullptr);
+
+signals:
+ void droppedURLs(QList<QUrl> urls);
+
+protected:
+ void dropEvent(QDropEvent *event) override;
+ void dragEnterEvent(QDragEnterEvent *event) override;
+ void dragMoveEvent(QDragMoveEvent *event) override;
+ void dragLeaveEvent(QDragLeaveEvent *event) override;
+};
diff --git a/application/widgets/ServerStatus.cpp b/application/widgets/ServerStatus.cpp
index a7016c0c..ce0aed9c 100644
--- a/application/widgets/ServerStatus.cpp
+++ b/application/widgets/ServerStatus.cpp
@@ -125,7 +125,7 @@ void ServerStatus::addStatus(QString key, QString name)
void ServerStatus::clicked()
{
- DesktopServices::openUrl(QUrl("https://help.mojang.com/"));
+ DesktopServices::openUrl(QUrl("https://github.com/MultiMC/MultiMC5/wiki/Mojang-Services-Status"));
}
void ServerStatus::setStatus(QString key, int value)
diff --git a/application/widgets/VersionListView.cpp b/application/widgets/VersionListView.cpp
index 09df75b7..fdcb84e6 100644
--- a/application/widgets/VersionListView.cpp
+++ b/application/widgets/VersionListView.cpp
@@ -82,7 +82,9 @@ void VersionListView::setEmptyMode(VersionListView::EmptyMode mode)
void VersionListView::updateEmptyViewPort()
{
+#ifndef QT_NO_ACCESSIBILITY
setAccessibleDescription(currentEmptyString());
+#endif /* !QT_NO_ACCESSIBILITY */
if(!m_itemCount)
{