From c077c91e90bd3d221abb06c2bdafd31492243b93 Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Sat, 21 Dec 2013 19:18:56 +0100 Subject: Remove OSX hack that never worked anyway --- gui/MainWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gui/MainWindow.cpp') diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index d91fc862..a2a2d885 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -97,7 +97,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi setWindowTitle(QString("MultiMC %1").arg(MMC->version().toString())); // OSX magic. - setUnifiedTitleAndToolBarOnMac(true); + // setUnifiedTitleAndToolBarOnMac(true); // The instance action toolbar customizations { -- cgit From d5075263206631a06747cfa7bf5f1b7db425390d Mon Sep 17 00:00:00 2001 From: ashka Date: Sun, 22 Dec 2013 22:43:16 +0100 Subject: Fixed updater not restarting MultiMC after update. --- gui/MainWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gui/MainWindow.cpp') diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index a2a2d885..179f881f 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -462,7 +462,7 @@ void MainWindow::downloadUpdates(QString repo, int versionId, bool installOnExit if (installOnExit) MMC->setUpdateOnExit(updateTask.updateFilesDir()); else - MMC->installUpdates(updateTask.updateFilesDir()); + MMC->installUpdates(updateTask.updateFilesDir(), true); } } -- cgit From b1ec7841e04f2a60f54895e1646bc33486fd9fbf Mon Sep 17 00:00:00 2001 From: robotbrainify Date: Tue, 24 Dec 2013 16:00:07 -0500 Subject: Get the updater to display a no update found message. --- gui/MainWindow.cpp | 5 ++- logic/updater/UpdateChecker.cpp | 71 +++++++++++++++++++++++++---------------- logic/updater/UpdateChecker.h | 6 ++-- tests/tst_UpdateChecker.cpp | 2 +- 4 files changed, 53 insertions(+), 31 deletions(-) (limited to 'gui/MainWindow.cpp') diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index 179f881f..7241f26b 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -681,7 +681,10 @@ void MainWindow::on_actionConfig_Folder_triggered() void MainWindow::on_actionCheckUpdate_triggered() { auto updater = MMC->updateChecker(); - updater->checkForUpdate(); + connect(updater.get(), &UpdateChecker::noUpdateFound, [this](){ + CustomMessageBox::selectable(this, "No update found.", "No MultiMC update was found!\nYou are using the latest version.")->exec(); + }); + updater->checkForUpdate(true); } void MainWindow::on_actionSettings_triggered() diff --git a/logic/updater/UpdateChecker.cpp b/logic/updater/UpdateChecker.cpp index af56288c..d0795c0d 100644 --- a/logic/updater/UpdateChecker.cpp +++ b/logic/updater/UpdateChecker.cpp @@ -47,14 +47,16 @@ bool UpdateChecker::hasChannels() const return !m_channels.isEmpty(); } -void UpdateChecker::checkForUpdate() +void UpdateChecker::checkForUpdate(bool notifyNoUpdate) { QLOG_DEBUG() << "Checking for updates."; - // If the channel list hasn't loaded yet, load it and defer checking for updates until later. + // If the channel list hasn't loaded yet, load it and defer checking for updates until + // later. if (!m_chanListLoaded) { - QLOG_DEBUG() << "Channel list isn't loaded yet. Loading channel list and deferring update check."; + QLOG_DEBUG() << "Channel list isn't loaded yet. Loading channel list and deferring " + "update check."; m_checkUpdateWaiting = true; updateChanList(); return; @@ -72,7 +74,8 @@ void UpdateChecker::checkForUpdate() // TODO: Allow user to select channels. For now, we'll just use the current channel. QString updateChannel = m_currentChannel; - // Find the desired channel within the channel list and get its repo URL. If if cannot be found, error. + // Find the desired channel within the channel list and get its repo URL. If if cannot be + // found, error. m_repoUrl = ""; for (ChannelListEntry entry : m_channels) { @@ -91,20 +94,22 @@ void UpdateChecker::checkForUpdate() auto job = new NetJob("GoUpdate Repository Index"); job->addNetAction(ByteArrayDownload::make(indexUrl)); - connect(job, SIGNAL(succeeded()), SLOT(updateCheckFinished())); + connect(job, &NetJob::succeeded, [this, notifyNoUpdate]() + { updateCheckFinished(notifyNoUpdate); }); connect(job, SIGNAL(failed()), SLOT(updateCheckFailed())); indexJob.reset(job); job->start(); } -void UpdateChecker::updateCheckFinished() +void UpdateChecker::updateCheckFinished(bool notifyNoUpdate) { QLOG_DEBUG() << "Finished downloading repo index. Checking for new versions."; QJsonParseError jsonError; QByteArray data; { - ByteArrayDownloadPtr dl = std::dynamic_pointer_cast(indexJob->first()); + ByteArrayDownloadPtr dl = + std::dynamic_pointer_cast(indexJob->first()); data = dl->m_data; indexJob.reset(); } @@ -112,7 +117,8 @@ void UpdateChecker::updateCheckFinished() QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); if (jsonError.error != QJsonParseError::NoError || !jsonDoc.isObject()) { - QLOG_ERROR() << "Failed to parse GoUpdate repository index. JSON error" << jsonError.errorString() << "at offset" << jsonError.offset; + QLOG_ERROR() << "Failed to parse GoUpdate repository index. JSON error" + << jsonError.errorString() << "at offset" << jsonError.offset; return; } @@ -122,7 +128,8 @@ void UpdateChecker::updateCheckFinished() int apiVersion = object.value("ApiVersion").toVariant().toInt(&success); if (apiVersion != API_VERSION || !success) { - QLOG_ERROR() << "Failed to check for updates. API version mismatch. We're using" << API_VERSION << "server has" << apiVersion; + QLOG_ERROR() << "Failed to check for updates. API version mismatch. We're using" + << API_VERSION << "server has" << apiVersion; return; } @@ -132,19 +139,27 @@ void UpdateChecker::updateCheckFinished() for (QJsonValue versionVal : versions) { QJsonObject version = versionVal.toObject(); - if (newestVersion.value("Id").toVariant().toInt() < version.value("Id").toVariant().toInt()) + if (newestVersion.value("Id").toVariant().toInt() < + version.value("Id").toVariant().toInt()) { - QLOG_DEBUG() << "Found newer version with ID" << version.value("Id").toVariant().toInt(); + QLOG_DEBUG() << "Found newer version with ID" + << version.value("Id").toVariant().toInt(); newestVersion = version; } } - // We've got the version with the greatest ID number. Now compare it to our current build number and update if they're different. + // We've got the version with the greatest ID number. Now compare it to our current build + // number and update if they're different. int newBuildNumber = newestVersion.value("Id").toVariant().toInt(); if (newBuildNumber != MMC->version().build) { // Update! - emit updateAvailable(m_repoUrl, newestVersion.value("Name").toVariant().toString(), newBuildNumber); + emit updateAvailable(m_repoUrl, newestVersion.value("Name").toVariant().toString(), + newBuildNumber); + } + else if (notifyNoUpdate) + { + emit noUpdateFound(); } m_updateChecking = false; @@ -163,12 +178,13 @@ void UpdateChecker::updateChanList() if (m_channelListUrl.isEmpty()) { QLOG_ERROR() << "Failed to update channel list. No channel list URL set." - << "If you'd like to use MultiMC's update system, please pass the channel list URL to CMake at compile time."; + << "If you'd like to use MultiMC's update system, please pass the channel " + "list URL to CMake at compile time."; return; } m_chanListLoading = true; - NetJob* job = new NetJob("Update System Channel List"); + NetJob *job = new NetJob("Update System Channel List"); job->addNetAction(ByteArrayDownload::make(QUrl(m_channelListUrl))); QObject::connect(job, &NetJob::succeeded, this, &UpdateChecker::chanListDownloadFinished); QObject::connect(job, &NetJob::failed, this, &UpdateChecker::chanListDownloadFailed); @@ -180,7 +196,8 @@ void UpdateChecker::chanListDownloadFinished() { QByteArray data; { - ByteArrayDownloadPtr dl = std::dynamic_pointer_cast(chanListJob->first()); + ByteArrayDownloadPtr dl = + std::dynamic_pointer_cast(chanListJob->first()); data = dl->m_data; chanListJob.reset(); } @@ -190,17 +207,20 @@ void UpdateChecker::chanListDownloadFinished() if (jsonError.error != QJsonParseError::NoError) { // TODO: Report errors to the user. - QLOG_ERROR() << "Failed to parse channel list JSON:" << jsonError.errorString() << "at" << jsonError.offset; + QLOG_ERROR() << "Failed to parse channel list JSON:" << jsonError.errorString() << "at" + << jsonError.offset; return; } - + QJsonObject object = jsonDoc.object(); bool success = false; int formatVersion = object.value("format_version").toVariant().toInt(&success); if (formatVersion != CHANLIST_FORMAT || !success) { - QLOG_ERROR() << "Failed to check for updates. Channel list format version mismatch. We're using" << CHANLIST_FORMAT << "server has" << formatVersion; + QLOG_ERROR() + << "Failed to check for updates. Channel list format version mismatch. We're using" + << CHANLIST_FORMAT << "server has" << formatVersion; return; } @@ -210,12 +230,10 @@ void UpdateChecker::chanListDownloadFinished() for (QJsonValue chanVal : channelArray) { QJsonObject channelObj = chanVal.toObject(); - ChannelListEntry entry{ - channelObj.value("id").toVariant().toString(), - channelObj.value("name").toVariant().toString(), - channelObj.value("description").toVariant().toString(), - channelObj.value("url").toVariant().toString() - }; + ChannelListEntry entry{channelObj.value("id").toVariant().toString(), + channelObj.value("name").toVariant().toString(), + channelObj.value("description").toVariant().toString(), + channelObj.value("url").toVariant().toString()}; if (entry.id.isEmpty() || entry.name.isEmpty() || entry.url.isEmpty()) { QLOG_ERROR() << "Channel list entry with empty ID, name, or URL. Skipping."; @@ -233,7 +251,7 @@ void UpdateChecker::chanListDownloadFinished() // If we're waiting to check for updates, do that now. if (m_checkUpdateWaiting) - checkForUpdate(); + checkForUpdate(false); emit channelListLoaded(); } @@ -244,4 +262,3 @@ void UpdateChecker::chanListDownloadFailed() QLOG_ERROR() << "Failed to download channel list."; emit channelListLoaded(); } - diff --git a/logic/updater/UpdateChecker.h b/logic/updater/UpdateChecker.h index 5b7efc05..a47e8903 100644 --- a/logic/updater/UpdateChecker.h +++ b/logic/updater/UpdateChecker.h @@ -25,7 +25,7 @@ class UpdateChecker : public QObject public: UpdateChecker(); - void checkForUpdate(); + void checkForUpdate(bool notifyNoUpdate); void setCurrentChannel(const QString &channel) { m_currentChannel = channel; } void setChannelListUrl(const QString &url) { m_channelListUrl = url; } @@ -65,8 +65,10 @@ signals: //! Signal emitted when the channel list finishes loading or fails to load. void channelListLoaded(); + void noUpdateFound(); + private slots: - void updateCheckFinished(); + void updateCheckFinished(bool notifyNoUpdate); void updateCheckFailed(); void chanListDownloadFinished(); diff --git a/tests/tst_UpdateChecker.cpp b/tests/tst_UpdateChecker.cpp index af3ae802..162d0009 100644 --- a/tests/tst_UpdateChecker.cpp +++ b/tests/tst_UpdateChecker.cpp @@ -149,7 +149,7 @@ slots: checker.m_channels[0].url = QUrl::fromLocalFile(QDir::current().absoluteFilePath("tests/data/")).toString(); - checker.checkForUpdate(); + checker.checkForUpdate(false); QVERIFY(updateAvailableSpy.wait()); QList res = result; -- cgit From 8d0ca72abb10b0cb77816d44f3f768865cc23aef Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Tue, 24 Dec 2013 23:38:37 +0100 Subject: Log SSL errors, give common solutions --- gui/MainWindow.cpp | 27 ++++++++++++++++++++++----- gui/dialogs/EditAccountDialog.cpp | 7 +++++++ gui/dialogs/EditAccountDialog.h | 3 +++ gui/dialogs/EditAccountDialog.ui | 6 ++++++ logic/auth/YggdrasilTask.cpp | 24 ++++++++++++++++++++++++ logic/auth/YggdrasilTask.h | 2 ++ 6 files changed, 64 insertions(+), 5 deletions(-) (limited to 'gui/MainWindow.cpp') diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index 179f881f..4fb4489f 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -865,6 +865,8 @@ void MainWindow::doLaunch() if (!account.get()) return; + QString failReason = tr("Your account is currently not logged in. Please enter " + "your password to log in again."); // do the login. if the account has an access token, try to refresh it first. if (account->accountStatus() != NotVerified) { @@ -879,13 +881,28 @@ void MainWindow::doLaunch() { updateInstance(m_selectedInstance, account); } - // revert from online to verified. + else + { + if (!task->successful()) + { + failReason = task->failReason(); + } + if (loginWithPassword(account, failReason)) + updateInstance(m_selectedInstance, account); + } + // in any case, revert from online to verified. + account->downgrade(); + } + else + { + if (loginWithPassword(account, failReason)) + { + updateInstance(m_selectedInstance, account); + account->downgrade(); + } + // in any case, revert from online to verified. account->downgrade(); - return; } - if (loginWithPassword(account, tr("Your account is currently not logged in. Please enter " - "your password to log in again."))) - updateInstance(m_selectedInstance, account); } bool MainWindow::loginWithPassword(MojangAccountPtr account, const QString &errorMsg) diff --git a/gui/dialogs/EditAccountDialog.cpp b/gui/dialogs/EditAccountDialog.cpp index dd3f0523..a1bd5591 100644 --- a/gui/dialogs/EditAccountDialog.cpp +++ b/gui/dialogs/EditAccountDialog.cpp @@ -15,6 +15,8 @@ #include "EditAccountDialog.h" #include "ui_EditAccountDialog.h" +#include +#include EditAccountDialog::EditAccountDialog(const QString &text, QWidget *parent, int flags) : QDialog(parent), ui(new Ui::EditAccountDialog) @@ -33,6 +35,11 @@ EditAccountDialog::~EditAccountDialog() delete ui; } +void EditAccountDialog::on_label_linkActivated(const QString &link) +{ + QDesktopServices::openUrl(QUrl(link)); +} + QString EditAccountDialog::username() const { return ui->userTextBox->text(); diff --git a/gui/dialogs/EditAccountDialog.h b/gui/dialogs/EditAccountDialog.h index be3a88d8..83f25124 100644 --- a/gui/dialogs/EditAccountDialog.h +++ b/gui/dialogs/EditAccountDialog.h @@ -52,6 +52,9 @@ public: PasswordField, }; +private slots: + void on_label_linkActivated(const QString &link); + private: Ui::EditAccountDialog *ui; }; diff --git a/gui/dialogs/EditAccountDialog.ui b/gui/dialogs/EditAccountDialog.ui index 1a8f9dba..5f727bd4 100644 --- a/gui/dialogs/EditAccountDialog.ui +++ b/gui/dialogs/EditAccountDialog.ui @@ -19,6 +19,12 @@ Message label placeholder. + + Qt::RichText + + + Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + diff --git a/logic/auth/YggdrasilTask.cpp b/logic/auth/YggdrasilTask.cpp index 573dd57a..3ba53bd7 100644 --- a/logic/auth/YggdrasilTask.cpp +++ b/logic/auth/YggdrasilTask.cpp @@ -48,6 +48,7 @@ void YggdrasilTask::executeTask() connect(m_netReply, &QNetworkReply::finished, this, &YggdrasilTask::processReply); connect(m_netReply, &QNetworkReply::uploadProgress, this, &YggdrasilTask::refreshTimers); connect(m_netReply, &QNetworkReply::downloadProgress, this, &YggdrasilTask::refreshTimers); + connect(m_netReply, &QNetworkReply::sslErrors, this, &YggdrasilTask::sslErrors); timeout_keeper.setSingleShot(true); timeout_keeper.start(timeout_max); counter.setSingleShot(false); @@ -75,10 +76,33 @@ void YggdrasilTask::abort() m_netReply->abort(); } +void YggdrasilTask::sslErrors(QList errors) +{ + int i = 1; + for(auto error: errors) + { + QLOG_ERROR() << "LOGIN SSL Error #" << i << " : " << error.errorString(); + auto cert = error.certificate(); + QLOG_ERROR() << "Certificate in question:\n" << cert.toText(); + i++; + } +} + void YggdrasilTask::processReply() { setStatus(getStateMessage(STATE_PROCESSING_RESPONSE)); + if (m_netReply->error() == QNetworkReply::SslHandshakeFailedError) + { + emitFailed(tr("SSL Handshake failed.
There might be a few causes for it:
" + "
    " + "
  • You use Windows XP and need to update your root certificates
  • " + "
  • Some device on your network is interfering with SSL traffic. In that case, you have bigger worries than Minecraft not starting.
  • " + "
  • Possibly something else. Check the MultiMC log file for details
  • " + "
")); + return; + } + // any network errors lead to offline mode right now if (m_netReply->error() >= QNetworkReply::ConnectionRefusedError && m_netReply->error() <= QNetworkReply::UnknownNetworkError) diff --git a/logic/auth/YggdrasilTask.h b/logic/auth/YggdrasilTask.h index 1f81a2d0..85f5a1e1 100644 --- a/logic/auth/YggdrasilTask.h +++ b/logic/auth/YggdrasilTask.h @@ -20,6 +20,7 @@ #include #include #include +#include #include "logic/auth/MojangAccount.h" @@ -99,6 +100,7 @@ slots: void processReply(); void refreshTimers(qint64, qint64); void heartbeat(); + void sslErrors(QList); public slots: -- cgit From 8edd0100e852cda9f44abd12cc06931542a2004a Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Wed, 25 Dec 2013 02:46:06 +0100 Subject: Fix more updater derps. * Updater requires unix style paths on input. * No update notification was getting cloned with every check --- gui/MainWindow.cpp | 14 +++++++++----- logic/updater/DownloadUpdateTask.cpp | 13 +++++-------- 2 files changed, 14 insertions(+), 13 deletions(-) (limited to 'gui/MainWindow.cpp') diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index 006f5b8e..bafccb1b 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -248,8 +248,14 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi // set up the updater object. auto updater = MMC->updateChecker(); - QObject::connect(updater.get(), &UpdateChecker::updateAvailable, this, - &MainWindow::updateAvailable); + connect(updater.get(), &UpdateChecker::updateAvailable, this, + &MainWindow::updateAvailable); + connect(updater.get(), &UpdateChecker::noUpdateFound, [this]() + { + CustomMessageBox::selectable( + this, tr("No update found."), + tr("No MultiMC update was found!\nYou are using the latest version."))->exec(); + }); // if automatic update checks are allowed, start one. if (MMC->settings()->get("AutoUpdate").toBool()) on_actionCheckUpdate_triggered(); @@ -681,9 +687,7 @@ void MainWindow::on_actionConfig_Folder_triggered() void MainWindow::on_actionCheckUpdate_triggered() { auto updater = MMC->updateChecker(); - connect(updater.get(), &UpdateChecker::noUpdateFound, [this](){ - CustomMessageBox::selectable(this, "No update found.", "No MultiMC update was found!\nYou are using the latest version.")->exec(); - }); + updater->checkForUpdate(true); } diff --git a/logic/updater/DownloadUpdateTask.cpp b/logic/updater/DownloadUpdateTask.cpp index 5f05b0ba..057ca436 100644 --- a/logic/updater/DownloadUpdateTask.cpp +++ b/logic/updater/DownloadUpdateTask.cpp @@ -438,9 +438,6 @@ bool DownloadUpdateTask::writeInstallScript(UpdateOperationList &opsList, QStrin { QDomElement file = doc.createElement("file"); - QString native_file = QDir::toNativeSeparators(op.file); - QString native_dest = QDir::toNativeSeparators(op.dest); - switch (op.type) { case UpdateOperation::OP_COPY: @@ -449,8 +446,8 @@ bool DownloadUpdateTask::writeInstallScript(UpdateOperationList &opsList, QStrin QDomElement name = doc.createElement("source"); QDomElement path = doc.createElement("dest"); QDomElement mode = doc.createElement("mode"); - name.appendChild(doc.createTextNode(native_file)); - path.appendChild(doc.createTextNode(native_dest)); + name.appendChild(doc.createTextNode(op.file)); + path.appendChild(doc.createTextNode(op.dest)); // We need to add a 0 at the beginning here, because Qt doesn't convert to octal // correctly. mode.appendChild(doc.createTextNode("0" + QString::number(op.mode, 8))); @@ -458,16 +455,16 @@ bool DownloadUpdateTask::writeInstallScript(UpdateOperationList &opsList, QStrin file.appendChild(path); file.appendChild(mode); installFiles.appendChild(file); - QLOG_DEBUG() << "Will install file" << native_file; + QLOG_DEBUG() << "Will install file " << op.file << " to " << op.dest; } break; case UpdateOperation::OP_DELETE: { // Delete the file. - file.appendChild(doc.createTextNode(native_file)); + file.appendChild(doc.createTextNode(op.file)); removeFiles.appendChild(file); - QLOG_DEBUG() << "Will remove file" << native_file; + QLOG_DEBUG() << "Will remove file" << op.file; } break; -- cgit From 30d4f5981d3220386bd320534048594fc364d0e9 Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Fri, 27 Dec 2013 12:50:24 +0100 Subject: Rearrange logiv for OneSix version change --- gui/MainWindow.cpp | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) (limited to 'gui/MainWindow.cpp') diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index bafccb1b..d16226eb 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -1026,22 +1026,9 @@ void MainWindow::on_actionChangeInstMCVersion_triggered() VersionSelectDialog vselect(m_selectedInstance->versionList().get(), tr("Change Minecraft version"), this); vselect.setFilter(1, "OneSix"); - if (vselect.exec() && vselect.selectedVersion()) - { - if (m_selectedInstance->versionIsCustom()) - { - auto result = CustomMessageBox::selectable( - this, tr("Are you sure?"), - tr("This will remove any library/version customization you did previously. " - "This includes things like Forge install and similar."), - QMessageBox::Warning, QMessageBox::Ok | QMessageBox::Abort, - QMessageBox::Abort)->exec(); - - if (result != QMessageBox::Ok) - return; - } - m_selectedInstance->setIntendedVersionId(vselect.selectedVersion()->descriptor()); - } + if(!vselect.exec() || !vselect.selectedVersion()) + return; + if (!MMC->accounts()->anyAccountIsValid()) { CustomMessageBox::selectable( @@ -1051,7 +1038,22 @@ void MainWindow::on_actionChangeInstMCVersion_triggered() QMessageBox::Warning)->show(); return; } - auto updateTask = m_selectedInstance->doUpdate(false /*only_prepare*/); + + if (m_selectedInstance->versionIsCustom()) + { + auto result = CustomMessageBox::selectable( + this, tr("Are you sure?"), + tr("This will remove any library/version customization you did previously. " + "This includes things like Forge install and similar."), + QMessageBox::Warning, QMessageBox::Ok | QMessageBox::Abort, + QMessageBox::Abort)->exec(); + + if (result != QMessageBox::Ok) + return; + } + m_selectedInstance->setIntendedVersionId(vselect.selectedVersion()->descriptor()); + + auto updateTask = m_selectedInstance->doUpdate(false); if (!updateTask) { return; -- cgit From 952b63f68de93e8acf7aab81373661dae8d5098b Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Tue, 31 Dec 2013 01:24:28 +0100 Subject: Refactor icon lists heavily * Icon list now uses a filesystem watcher for updates * Icon folder is user-customizable * All the little details. ALL OF THEM. --- CMakeLists.txt | 9 +- MultiMC.cpp | 12 +- gui/MainWindow.cpp | 31 +++- gui/MainWindow.h | 6 +- gui/dialogs/CopyInstanceDialog.cpp | 2 +- gui/dialogs/IconPickerDialog.cpp | 2 +- gui/dialogs/NewInstanceDialog.cpp | 2 +- gui/dialogs/SettingsDialog.cpp | 14 ++ gui/dialogs/SettingsDialog.h | 3 + gui/dialogs/SettingsDialog.ui | 23 ++- logic/BaseInstance.cpp | 10 ++ logic/BaseInstance.h | 3 + logic/LegacyInstance.cpp | 2 +- logic/icons/IconList.cpp | 351 +++++++++++++++++++++++++++++++++++++ logic/icons/IconList.h | 77 ++++++++ logic/icons/MMCIcon.cpp | 89 ++++++++++ logic/icons/MMCIcon.h | 52 ++++++ logic/lists/IconList.cpp | 271 ---------------------------- logic/lists/IconList.h | 54 ------ logic/lists/InstanceList.cpp | 7 +- 20 files changed, 665 insertions(+), 355 deletions(-) create mode 100644 logic/icons/IconList.cpp create mode 100644 logic/icons/IconList.h create mode 100644 logic/icons/MMCIcon.cpp create mode 100644 logic/icons/MMCIcon.h delete mode 100644 logic/lists/IconList.cpp delete mode 100644 logic/lists/IconList.h (limited to 'gui/MainWindow.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index 555890bb..62fa2c09 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -372,8 +372,6 @@ logic/LegacyFTBInstance.cpp # Lists logic/lists/InstanceList.h logic/lists/InstanceList.cpp -logic/lists/IconList.h -logic/lists/IconList.cpp logic/lists/BaseVersionList.h logic/lists/BaseVersionList.cpp logic/lists/MinecraftVersionList.h @@ -385,6 +383,13 @@ logic/lists/ForgeVersionList.cpp logic/lists/JavaVersionList.h logic/lists/JavaVersionList.cpp +# Icons +logic/icons/MMCIcon.h +logic/icons/MMCIcon.cpp +logic/icons/IconList.h +logic/icons/IconList.cpp + + # misc model/view logic/EnabledItemFilter.h logic/EnabledItemFilter.cpp diff --git a/MultiMC.cpp b/MultiMC.cpp index 865d0cf1..fe83fbd1 100644 --- a/MultiMC.cpp +++ b/MultiMC.cpp @@ -13,7 +13,7 @@ #include "gui/dialogs/VersionSelectDialog.h" #include "logic/lists/InstanceList.h" #include "logic/auth/MojangAccountList.h" -#include "logic/lists/IconList.h" +#include "logic/icons/IconList.h" #include "logic/lists/LwjglVersionList.h" #include "logic/lists/MinecraftVersionList.h" #include "logic/lists/ForgeVersionList.h" @@ -382,6 +382,7 @@ void MultiMC::initGlobalSettings() m_settings->registerSetting(new Setting("InstanceDir", "instances")); m_settings->registerSetting(new Setting("CentralModsDir", "mods")); m_settings->registerSetting(new Setting("LWJGLDir", "lwjgl")); + m_settings->registerSetting(new Setting("IconsDir", "icons")); // Editors m_settings->registerSetting(new Setting("JsonEditor", QString())); @@ -420,15 +421,6 @@ void MultiMC::initGlobalSettings() m_settings->registerSetting(new Setting("InstSortMode", "Name")); m_settings->registerSetting(new Setting("SelectedInstance", QString())); - // Persistent value for the client ID - m_settings->registerSetting(new Setting("YggdrasilClientToken", "")); - QString currentYggID = m_settings->get("YggdrasilClientToken").toString(); - if (currentYggID.isEmpty()) - { - QUuid uuid = QUuid::createUuid(); - m_settings->set("YggdrasilClientToken", uuid.toString()); - } - // Window state and geometry m_settings->registerSetting(new Setting("MainWindowState", "")); m_settings->registerSetting(new Setting("MainWindowGeometry", "")); diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index d16226eb..2ba0d509 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -66,7 +66,7 @@ #include "logic/lists/InstanceList.h" #include "logic/lists/MinecraftVersionList.h" #include "logic/lists/LwjglVersionList.h" -#include "logic/lists/IconList.h" +#include "logic/icons/IconList.h" #include "logic/lists/JavaVersionList.h" #include "logic/auth/flows/AuthenticateTask.h" @@ -165,6 +165,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi connect(view->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(instanceChanged(const QModelIndex &, const QModelIndex &))); + + // track icon changes and update the toolbar! + connect(MMC->icons().get(), SIGNAL(iconUpdated(QString)), SLOT(iconUpdated(QString))); + // model reset -> selection is invalid. All the instance pointers are wrong. // FIXME: stop using POINTERS everywhere connect(MMC->instances().get(), SIGNAL(dataIsInvalid()), SLOT(selectionBad())); @@ -635,11 +639,27 @@ void MainWindow::on_actionChangeInstIcon_triggered() if (dlg.result() == QDialog::Accepted) { m_selectedInstance->setIconKey(dlg.selectedIconKey); + /* auto ico = MMC->icons()->getIcon(dlg.selectedIconKey); ui->actionChangeInstIcon->setIcon(ico); + */ + } +} + +void MainWindow::iconUpdated(QString icon) +{ + if(icon == m_currentInstIcon) + { + ui->actionChangeInstIcon->setIcon(MMC->icons()->getIcon(m_currentInstIcon)); } } +void MainWindow::updateInstanceToolIcon(QString new_icon) +{ + m_currentInstIcon = new_icon; + ui->actionChangeInstIcon->setIcon(MMC->icons()->getIcon(m_currentInstIcon)); +} + void MainWindow::on_actionChangeInstGroup_triggered() { if (!m_selectedInstance) @@ -1095,7 +1115,6 @@ void MainWindow::instanceChanged(const QModelIndex ¤t, const QModelIndex & .value())) { ui->instanceToolBar->setEnabled(true); - QString iconKey = m_selectedInstance->iconKey(); renameButton->setText(m_selectedInstance->name()); ui->actionChangeInstLWJGLVersion->setEnabled( m_selectedInstance->menuActionEnabled("actionChangeInstLWJGLVersion")); @@ -1104,8 +1123,7 @@ void MainWindow::instanceChanged(const QModelIndex ¤t, const QModelIndex & ui->actionChangeInstMCVersion->setEnabled( m_selectedInstance->menuActionEnabled("actionChangeInstMCVersion")); m_statusLeft->setText(m_selectedInstance->getStatusbarDescription()); - auto ico = MMC->icons()->getIcon(iconKey); - ui->actionChangeInstIcon->setIcon(ico); + updateInstanceToolIcon(m_selectedInstance->iconKey()); MMC->settings()->set("SelectedInstance", m_selectedInstance->id()); } @@ -1120,12 +1138,11 @@ void MainWindow::instanceChanged(const QModelIndex ¤t, const QModelIndex & void MainWindow::selectionBad() { m_selectedInstance = nullptr; - QString iconKey = "infinity"; + statusBar()->clearMessage(); ui->instanceToolBar->setEnabled(false); renameButton->setText(tr("Rename Instance")); - auto ico = MMC->icons()->getIcon(iconKey); - ui->actionChangeInstIcon->setIcon(ico); + updateInstanceToolIcon("infinity"); } void MainWindow::on_actionEditInstNotes_triggered() diff --git a/gui/MainWindow.h b/gui/MainWindow.h index befe93e6..007c2e34 100644 --- a/gui/MainWindow.h +++ b/gui/MainWindow.h @@ -145,6 +145,9 @@ slots: void assetsFailed(); void assetsFinished(); + // called when an icon is changed in the icon model. + void iconUpdated(QString); + public slots: void instanceActivated(QModelIndex); @@ -171,6 +174,7 @@ slots: protected: bool eventFilter(QObject *obj, QEvent *ev); void setCatBackground(bool enabled); + void updateInstanceToolIcon(QString new_icon); private: Ui::MainWindow *ui; @@ -180,9 +184,9 @@ private: MinecraftProcess *proc; ConsoleWindow *console; LabeledToolButton *renameButton; - QToolButton *changeIconButton; BaseInstance *m_selectedInstance; + QString m_currentInstIcon; Task *m_versionLoadTask; diff --git a/gui/dialogs/CopyInstanceDialog.cpp b/gui/dialogs/CopyInstanceDialog.cpp index 9d7ac30c..4095408b 100644 --- a/gui/dialogs/CopyInstanceDialog.cpp +++ b/gui/dialogs/CopyInstanceDialog.cpp @@ -27,7 +27,7 @@ #include "logic/InstanceFactory.h" #include "logic/BaseVersion.h" -#include "logic/lists/IconList.h" +#include "logic/icons/IconList.h" #include "logic/lists/MinecraftVersionList.h" #include "logic/tasks/Task.h" #include "logic/BaseInstance.h" diff --git a/gui/dialogs/IconPickerDialog.cpp b/gui/dialogs/IconPickerDialog.cpp index 99d6dc9a..cb832d95 100644 --- a/gui/dialogs/IconPickerDialog.cpp +++ b/gui/dialogs/IconPickerDialog.cpp @@ -25,7 +25,7 @@ #include "gui/Platform.h" #include "gui/widgets/InstanceDelegate.h" -#include "logic/lists/IconList.h" +#include "logic/icons/IconList.h" IconPickerDialog::IconPickerDialog(QWidget *parent) : QDialog(parent), ui(new Ui::IconPickerDialog) diff --git a/gui/dialogs/NewInstanceDialog.cpp b/gui/dialogs/NewInstanceDialog.cpp index 5b2cd086..c7b273af 100644 --- a/gui/dialogs/NewInstanceDialog.cpp +++ b/gui/dialogs/NewInstanceDialog.cpp @@ -19,7 +19,7 @@ #include "logic/InstanceFactory.h" #include "logic/BaseVersion.h" -#include "logic/lists/IconList.h" +#include "logic/icons/IconList.h" #include "logic/lists/MinecraftVersionList.h" #include "logic/tasks/Task.h" diff --git a/gui/dialogs/SettingsDialog.cpp b/gui/dialogs/SettingsDialog.cpp index 30a973da..569c8f63 100644 --- a/gui/dialogs/SettingsDialog.cpp +++ b/gui/dialogs/SettingsDialog.cpp @@ -102,6 +102,18 @@ void SettingsDialog::on_instDirBrowseBtn_clicked() ui->instDirTextBox->setText(cooked_dir); } } +void SettingsDialog::on_iconsDirBrowseBtn_clicked() +{ + QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Icons Directory"), + ui->iconsDirTextBox->text()); + QString cooked_dir = NormalizePath(raw_dir); + + // do not allow current dir - it's dirty. Do not allow dirs that don't exist + if (!cooked_dir.isEmpty() && QDir(cooked_dir).exists()) + { + ui->iconsDirTextBox->setText(cooked_dir); + } +} void SettingsDialog::on_modsDirBrowseBtn_clicked() { @@ -205,6 +217,7 @@ void SettingsDialog::applySettings(SettingsObject *s) s->set("InstanceDir", ui->instDirTextBox->text()); s->set("CentralModsDir", ui->modsDirTextBox->text()); s->set("LWJGLDir", ui->lwjglDirTextBox->text()); + s->set("IconsDir", ui->iconsDirTextBox->text()); // Editors QString jsonEditor = ui->jsonEditorTextBox->text(); @@ -271,6 +284,7 @@ void SettingsDialog::loadSettings(SettingsObject *s) ui->instDirTextBox->setText(s->get("InstanceDir").toString()); ui->modsDirTextBox->setText(s->get("CentralModsDir").toString()); ui->lwjglDirTextBox->setText(s->get("LWJGLDir").toString()); + ui->iconsDirTextBox->setText(s->get("IconsDir").toString()); // Editors ui->jsonEditorTextBox->setText(s->get("JsonEditor").toString()); diff --git a/gui/dialogs/SettingsDialog.h b/gui/dialogs/SettingsDialog.h index 01357c91..bcf57a80 100644 --- a/gui/dialogs/SettingsDialog.h +++ b/gui/dialogs/SettingsDialog.h @@ -55,8 +55,11 @@ slots: void on_lwjglDirBrowseBtn_clicked(); + void on_jsonEditorBrowseBtn_clicked(); + void on_iconsDirBrowseBtn_clicked(); + void on_maximizedCheckBox_clicked(bool checked); void on_buttonBox_accepted(); diff --git a/gui/dialogs/SettingsDialog.ui b/gui/dialogs/SettingsDialog.ui index ec4d156e..dbc8ca88 100644 --- a/gui/dialogs/SettingsDialog.ui +++ b/gui/dialogs/SettingsDialog.ui @@ -215,6 +215,9 @@ + + + @@ -229,9 +232,6 @@ - - - @@ -239,6 +239,23 @@ + + + + + + + Icons: + + + + + + + ... + + +
diff --git a/logic/BaseInstance.cpp b/logic/BaseInstance.cpp index bc82fee1..b39db03b 100644 --- a/logic/BaseInstance.cpp +++ b/logic/BaseInstance.cpp @@ -27,6 +27,7 @@ #include "pathutils.h" #include "lists/MinecraftVersionList.h" +#include "logic/icons/IconList.h" BaseInstance::BaseInstance(BaseInstancePrivate *d_in, const QString &rootDir, SettingsObject *settings_obj, QObject *parent) @@ -38,6 +39,7 @@ BaseInstance::BaseInstance(BaseInstancePrivate *d_in, const QString &rootDir, settings().registerSetting(new Setting("name", "Unnamed Instance")); settings().registerSetting(new Setting("iconKey", "default")); + connect(MMC->icons().get(), SIGNAL(iconUpdated(QString)), SLOT(iconUpdated(QString))); settings().registerSetting(new Setting("notes", "")); settings().registerSetting(new Setting("lastLaunchTime", 0)); @@ -93,6 +95,14 @@ BaseInstance::BaseInstance(BaseInstancePrivate *d_in, const QString &rootDir, "AutoCloseConsole", globalSettings->getSetting("AutoCloseConsole"))); } +void BaseInstance::iconUpdated(QString key) +{ + if(iconKey() == key) + { + emit propertiesChanged(this); + } +} + void BaseInstance::nuke() { QDir(instanceRoot()).removeRecursively(); diff --git a/logic/BaseInstance.h b/logic/BaseInstance.h index 5f426676..01d6dc7d 100644 --- a/logic/BaseInstance.h +++ b/logic/BaseInstance.h @@ -184,6 +184,9 @@ signals: */ void nuked(BaseInstance *inst); +protected slots: + void iconUpdated(QString key); + protected: std::shared_ptr inst_d; }; diff --git a/logic/LegacyInstance.cpp b/logic/LegacyInstance.cpp index 5c82b837..08d7c147 100644 --- a/logic/LegacyInstance.cpp +++ b/logic/LegacyInstance.cpp @@ -27,7 +27,7 @@ #include "logic/MinecraftProcess.h" #include "logic/LegacyUpdate.h" -#include "logic/lists/IconList.h" +#include "logic/icons/IconList.h" #include "gui/dialogs/LegacyModEditDialog.h" diff --git a/logic/icons/IconList.cpp b/logic/icons/IconList.cpp new file mode 100644 index 00000000..1e692d1d --- /dev/null +++ b/logic/icons/IconList.cpp @@ -0,0 +1,351 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "IconList.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_SIZE 1024 + +IconList::IconList(QObject *parent) : QAbstractListModel(parent) +{ + // add builtin icons + QDir instance_icons(":/icons/instances/"); + auto file_info_list = instance_icons.entryInfoList(QDir::Files, QDir::Name); + for (auto file_info : file_info_list) + { + QString key = file_info.baseName(); + addIcon(key, key, file_info.absoluteFilePath(), MMCIcon::Builtin); + } + + m_watcher.reset(new QFileSystemWatcher()); + is_watching = false; + connect(m_watcher.get(), SIGNAL(directoryChanged(QString)), + SLOT(directoryChanged(QString))); + connect(m_watcher.get(), SIGNAL(fileChanged(QString)), SLOT(fileChanged(QString))); + + auto setting = MMC->settings()->getSetting("IconsDir"); + QString path = setting->get().toString(); + connect(setting, SIGNAL(settingChanged(const Setting &, QVariant)), + SLOT(settingChanged(const Setting &, QVariant))); + directoryChanged(path); +} + +void IconList::directoryChanged(const QString &path) +{ + QDir new_dir (path); + if(m_dir.absolutePath() != new_dir.absolutePath()) + { + m_dir.setPath(path); + m_dir.refresh(); + if(is_watching) + stopWatching(); + startWatching(); + } + if(!m_dir.exists()) + if(!ensureFolderPathExists(m_dir.absolutePath())) + return; + m_dir.refresh(); + auto new_list = m_dir.entryList(QDir::Files, QDir::Name); + for (auto it = new_list.begin(); it != new_list.end(); it++) + { + QString &foo = (*it); + foo = m_dir.filePath(foo); + } + auto new_set = new_list.toSet(); + QList current_list; + for (auto &it : icons) + { + if (!it.has(MMCIcon::FileBased)) + continue; + current_list.push_back(it.m_images[MMCIcon::FileBased].filename); + } + QSet current_set = current_list.toSet(); + + QSet to_remove = current_set; + to_remove -= new_set; + + QSet to_add = new_set; + to_add -= current_set; + + for (auto remove : to_remove) + { + QLOG_INFO() << "Removing " << remove; + QFileInfo rmfile(remove); + QString key = rmfile.baseName(); + int idx = getIconIndex(key); + if (idx == -1) + continue; + icons[idx].remove(MMCIcon::FileBased); + if (icons[idx].type() == MMCIcon::ToBeDeleted) + { + beginRemoveRows(QModelIndex(), idx, idx); + icons.remove(idx); + reindex(); + endRemoveRows(); + } + else + { + dataChanged(index(idx), index(idx)); + } + m_watcher->removePath(remove); + emit iconUpdated(key); + } + + for (auto add : to_add) + { + QLOG_INFO() << "Adding " << add; + QFileInfo addfile(add); + QString key = addfile.baseName(); + if (addIcon(key, QString(), addfile.filePath(), MMCIcon::FileBased)) + { + m_watcher->addPath(add); + emit iconUpdated(key); + } + } +} + +void IconList::fileChanged(const QString &path) +{ + QLOG_INFO() << "Checking " << path; + QFileInfo checkfile(path); + if (!checkfile.exists()) + return; + QString key = checkfile.baseName(); + int idx = getIconIndex(key); + if (idx == -1) + return; + QIcon icon(path); + if (!icon.availableSizes().size()) + return; + + icons[idx].m_images[MMCIcon::FileBased].icon = icon; + dataChanged(index(idx), index(idx)); + emit iconUpdated(key); +} + +void IconList::settingChanged(const Setting &setting, QVariant value) +{ + if(setting.configKey() != "IconsDir") + return; + + directoryChanged(value.toString()); +} + +void IconList::startWatching() +{ + auto abs_path = m_dir.absolutePath(); + ensureFolderPathExists(abs_path); + is_watching = m_watcher->addPath(abs_path); + if (is_watching) + { + QLOG_INFO() << "Started watching " << abs_path; + } + else + { + QLOG_INFO() << "Failed to start watching " << abs_path; + } +} + +void IconList::stopWatching() +{ + m_watcher->removePaths(m_watcher->files()); + m_watcher->removePaths(m_watcher->directories()); + is_watching = false; +} + +QStringList IconList::mimeTypes() const +{ + QStringList types; + types << "text/uri-list"; + return types; +} +Qt::DropActions IconList::supportedDropActions() const +{ + return Qt::CopyAction; +} + +bool IconList::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, + const QModelIndex &parent) +{ + if (action == Qt::IgnoreAction) + return true; + // check if the action is supported + if (!data || !(action & supportedDropActions())) + return false; + + // files dropped from outside? + if (data->hasUrls()) + { + auto urls = data->urls(); + QStringList iconFiles; + for (auto url : urls) + { + // only local files may be dropped... + if (!url.isLocalFile()) + continue; + iconFiles += url.toLocalFile(); + } + installIcons(iconFiles); + return true; + } + return false; +} + +Qt::ItemFlags IconList::flags(const QModelIndex &index) const +{ + Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index); + if (index.isValid()) + return Qt::ItemIsDropEnabled | defaultFlags; + else + return Qt::ItemIsDropEnabled | defaultFlags; +} + +QVariant IconList::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + int row = index.row(); + + if (row < 0 || row >= icons.size()) + return QVariant(); + + switch (role) + { + case Qt::DecorationRole: + return icons[row].icon(); + case Qt::DisplayRole: + return icons[row].name(); + case Qt::UserRole: + return icons[row].m_key; + default: + return QVariant(); + } +} + +int IconList::rowCount(const QModelIndex &parent) const +{ + return icons.size(); +} + +void IconList::installIcons(QStringList iconFiles) +{ + for (QString file : iconFiles) + { + QFileInfo fileinfo(file); + if (!fileinfo.isReadable() || !fileinfo.isFile()) + continue; + QString target = PathCombine("icons", fileinfo.fileName()); + + QString suffix = fileinfo.suffix(); + if (suffix != "jpeg" && suffix != "png" && suffix != "jpg") + continue; + + if (!QFile::copy(file, target)) + continue; + } +} + +bool IconList::deleteIcon(QString key) +{ + int iconIdx = getIconIndex(key); + if (iconIdx == -1) + return false; + auto &iconEntry = icons[iconIdx]; + if (iconEntry.has(MMCIcon::FileBased)) + { + return QFile::remove(iconEntry.m_images[MMCIcon::FileBased].filename); + } + return false; +} + +bool IconList::addIcon(QString key, QString name, QString path, MMCIcon::Type type) +{ + // replace the icon even? is the input valid? + QIcon icon(path); + if (!icon.availableSizes().size()) + return false; + auto iter = name_index.find(key); + if (iter != name_index.end()) + { + auto &oldOne = icons[*iter]; + oldOne.replace(type, icon, path); + dataChanged(index(*iter), index(*iter)); + return true; + } + else + { + // add a new icon + beginInsertRows(QModelIndex(), icons.size(), icons.size()); + { + MMCIcon mmc_icon; + mmc_icon.m_name = name; + mmc_icon.m_key = key; + mmc_icon.replace(type, icon, path); + icons.push_back(mmc_icon); + name_index[key] = icons.size() - 1; + } + endInsertRows(); + return true; + } +} + +void IconList::reindex() +{ + name_index.clear(); + int i = 0; + for (auto &iter : icons) + { + name_index[iter.m_key] = i; + i++; + } +} + +QIcon IconList::getIcon(QString key) +{ + int icon_index = getIconIndex(key); + + if (icon_index != -1) + return icons[icon_index].icon(); + + // Fallback for icons that don't exist. + icon_index = getIconIndex("infinity"); + + if (icon_index != -1) + return icons[icon_index].icon(); + return QIcon(); +} + +int IconList::getIconIndex(QString key) +{ + if (key == "default") + key = "infinity"; + + auto iter = name_index.find(key); + if (iter != name_index.end()) + return *iter; + + return -1; +} + +//#include "IconList.moc" \ No newline at end of file diff --git a/logic/icons/IconList.h b/logic/icons/IconList.h new file mode 100644 index 00000000..322411d1 --- /dev/null +++ b/logic/icons/IconList.h @@ -0,0 +1,77 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include "MMCIcon.h" +#include "setting.h" + +class QFileSystemWatcher; + +class IconList : public QAbstractListModel +{ + Q_OBJECT +public: + explicit IconList(QObject *parent = 0); + virtual ~IconList() {}; + + QIcon getIcon(QString key); + int getIconIndex(QString key); + + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + + bool addIcon(QString key, QString name, QString path, MMCIcon::Type type); + bool deleteIcon(QString key); + + virtual QStringList mimeTypes() const; + virtual Qt::DropActions supportedDropActions() const; + virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, + const QModelIndex &parent); + virtual Qt::ItemFlags flags(const QModelIndex &index) const; + + void installIcons(QStringList iconFiles); + + void startWatching(); + void stopWatching(); + +signals: + void iconUpdated(QString key); + +private: + // hide copy constructor + IconList(const IconList &) = delete; + // hide assign op + IconList &operator=(const IconList &) = delete; + void reindex(); + +protected +slots: + void directoryChanged(const QString &path); + void fileChanged(const QString &path); + void settingChanged(const Setting & setting, QVariant value); +private: + std::shared_ptr m_watcher; + bool is_watching; + QMap name_index; + QVector icons; + QDir m_dir; +}; diff --git a/logic/icons/MMCIcon.cpp b/logic/icons/MMCIcon.cpp new file mode 100644 index 00000000..d721513d --- /dev/null +++ b/logic/icons/MMCIcon.cpp @@ -0,0 +1,89 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MMCIcon.h" +#include + +MMCIcon::Type operator--(MMCIcon::Type &t, int) +{ + MMCIcon::Type temp = t; + switch (t) + { + case MMCIcon::Type::Builtin: + t = MMCIcon::Type::ToBeDeleted; + break; + case MMCIcon::Type::Transient: + t = MMCIcon::Type::Builtin; + break; + case MMCIcon::Type::FileBased: + t = MMCIcon::Type::Transient; + break; + default: + { + } + } + return temp; +} + +MMCIcon::Type MMCIcon::type() const +{ + return m_current_type; +} + +QString MMCIcon::name() const +{ + if (m_name.size()) + return m_name; + return m_key; +} + +bool MMCIcon::has(MMCIcon::Type _type) const +{ + return m_images[_type].present(); +} + +QIcon MMCIcon::icon() const +{ + if (m_current_type == Type::ToBeDeleted) + return QIcon(); + return m_images[m_current_type].icon; +} + +void MMCIcon::remove(Type rm_type) +{ + m_images[rm_type].filename = QString(); + m_images[rm_type].icon = QIcon(); + for (auto iter = rm_type; iter != Type::ToBeDeleted; iter--) + { + if (m_images[iter].present()) + { + m_current_type = iter; + return; + } + } + m_current_type = Type::ToBeDeleted; +} + +void MMCIcon::replace(MMCIcon::Type new_type, QIcon icon, QString path) +{ + QFileInfo foo(path); + if (new_type > m_current_type || m_current_type == MMCIcon::ToBeDeleted) + { + m_current_type = new_type; + } + m_images[new_type].icon = icon; + m_images[new_type].changed = foo.lastModified(); + m_images[new_type].filename = path; +} diff --git a/logic/icons/MMCIcon.h b/logic/icons/MMCIcon.h new file mode 100644 index 00000000..5e4b3bb6 --- /dev/null +++ b/logic/icons/MMCIcon.h @@ -0,0 +1,52 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include +struct MMCImage +{ + QIcon icon; + QString filename; + QDateTime changed; + bool present() const + { + return !icon.isNull(); + } +}; + +struct MMCIcon +{ + enum Type : unsigned + { + Builtin, + Transient, + FileBased, + ICONS_TOTAL, + ToBeDeleted + }; + QString m_key; + QString m_name; + MMCImage m_images[ICONS_TOTAL]; + Type m_current_type = ToBeDeleted; + + Type type() const; + QString name() const; + bool has(Type _type) const; + QIcon icon() const; + void remove(Type rm_type); + void replace(Type new_type, QIcon icon, QString path = QString()); +}; diff --git a/logic/lists/IconList.cpp b/logic/lists/IconList.cpp deleted file mode 100644 index ecfb8c3c..00000000 --- a/logic/lists/IconList.cpp +++ /dev/null @@ -1,271 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "IconList.h" -#include -#include -#include -#include -#include -#include -#define MAX_SIZE 1024 - -struct entry -{ - QString key; - QString name; - QIcon icon; - bool is_builtin; - QString filename; -}; - -class Private : public QObject -{ - Q_OBJECT -public: - QMap index; - QVector icons; - Private() - { - } -}; - -IconList::IconList() : QAbstractListModel(), d(new Private()) -{ - QDir instance_icons(":/icons/instances/"); - auto file_info_list = instance_icons.entryInfoList(QDir::Files, QDir::Name); - for (auto file_info : file_info_list) - { - QString key = file_info.baseName(); - addIcon(key, key, file_info.absoluteFilePath(), true); - } - - // FIXME: get from settings - ensureFolderPathExists("icons"); - QDir user_icons("icons"); - file_info_list = user_icons.entryInfoList(QDir::Files, QDir::Name); - for (auto file_info : file_info_list) - { - QString filename = file_info.absoluteFilePath(); - QString key = file_info.baseName(); - addIcon(key, key, filename); - } -} - -IconList::~IconList() -{ - delete d; - d = nullptr; -} - -QStringList IconList::mimeTypes() const -{ - QStringList types; - types << "text/uri-list"; - return types; -} -Qt::DropActions IconList::supportedDropActions() const -{ - return Qt::CopyAction; -} - -bool IconList::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, - const QModelIndex &parent) -{ - if (action == Qt::IgnoreAction) - return true; - // check if the action is supported - if (!data || !(action & supportedDropActions())) - return false; - - // files dropped from outside? - if (data->hasUrls()) - { - /* - bool was_watching = is_watching; - if(was_watching) - stopWatching(); - */ - auto urls = data->urls(); - QStringList iconFiles; - for (auto url : urls) - { - // only local files may be dropped... - if (!url.isLocalFile()) - continue; - iconFiles += url.toLocalFile(); - } - installIcons(iconFiles); - /* - if(was_watching) - startWatching(); - */ - return true; - } - return false; -} - -Qt::ItemFlags IconList::flags(const QModelIndex &index) const -{ - Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index); - if (index.isValid()) - return Qt::ItemIsDropEnabled | defaultFlags; - else - return Qt::ItemIsDropEnabled | defaultFlags; -} - -QVariant IconList::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - int row = index.row(); - - if (row < 0 || row >= d->icons.size()) - return QVariant(); - - switch (role) - { - case Qt::DecorationRole: - return d->icons[row].icon; - case Qt::DisplayRole: - return d->icons[row].name; - case Qt::UserRole: - return d->icons[row].key; - default: - return QVariant(); - } -} - -int IconList::rowCount(const QModelIndex &parent) const -{ - return d->icons.size(); -} - -void IconList::installIcons(QStringList iconFiles) -{ - for (QString file : iconFiles) - { - QFileInfo fileinfo(file); - if (!fileinfo.isReadable() || !fileinfo.isFile()) - continue; - QString target = PathCombine("icons", fileinfo.fileName()); - - QString suffix = fileinfo.suffix(); - if (suffix != "jpeg" && suffix != "png" && suffix != "jpg") - continue; - - if (!QFile::copy(file, target)) - continue; - - QString key = fileinfo.baseName(); - addIcon(key, key, target); - } -} - -bool IconList::deleteIcon(QString key) -{ - int iconIdx = getIconIndex(key); - if (iconIdx == -1) - return false; - auto &iconEntry = d->icons[iconIdx]; - if (iconEntry.is_builtin) - return false; - if (QFile::remove(iconEntry.filename)) - { - beginRemoveRows(QModelIndex(), iconIdx, iconIdx); - d->icons.remove(iconIdx); - reindex(); - endRemoveRows(); - } - return true; -} - -bool IconList::addIcon(QString key, QString name, QString path, bool is_builtin) -{ - auto iter = d->index.find(key); - if (iter != d->index.end()) - { - if (d->icons[*iter].is_builtin) - return false; - - QIcon icon(path); - if (icon.isNull()) - return false; - - auto &oldOne = d->icons[*iter]; - - if (!QFile::remove(oldOne.filename)) - return false; - - // replace the icon - oldOne = {key, name, icon, is_builtin, path}; - dataChanged(index(*iter), index(*iter)); - return true; - } - else - { - QIcon icon(path); - if (icon.isNull()) - return false; - - // add a new icon - beginInsertRows(QModelIndex(), d->icons.size(), d->icons.size()); - d->icons.push_back({key, name, icon, is_builtin, path}); - d->index[key] = d->icons.size() - 1; - endInsertRows(); - return true; - } -} - -void IconList::reindex() -{ - d->index.clear(); - int i = 0; - for (auto &iter : d->icons) - { - d->index[iter.key] = i; - i++; - } -} - -QIcon IconList::getIcon(QString key) -{ - int icon_index = getIconIndex(key); - - if (icon_index != -1) - return d->icons[icon_index].icon; - - // Fallback for icons that don't exist. - icon_index = getIconIndex("infinity"); - - if (icon_index != -1) - return d->icons[icon_index].icon; - return QIcon(); -} - -int IconList::getIconIndex(QString key) -{ - if (key == "default") - key = "infinity"; - - auto iter = d->index.find(key); - if (iter != d->index.end()) - return *iter; - - return -1; -} - -#include "IconList.moc" \ No newline at end of file diff --git a/logic/lists/IconList.h b/logic/lists/IconList.h deleted file mode 100644 index 40ad043b..00000000 --- a/logic/lists/IconList.h +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include - -class Private; - -class IconList : public QAbstractListModel -{ -public: - IconList(); - virtual ~IconList(); - - QIcon getIcon(QString key); - int getIconIndex(QString key); - - virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; - - bool addIcon(QString key, QString name, QString path, bool is_builtin = false); - bool deleteIcon(QString key); - - virtual QStringList mimeTypes() const; - virtual Qt::DropActions supportedDropActions() const; - virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, - const QModelIndex &parent); - virtual Qt::ItemFlags flags(const QModelIndex &index) const; - - void installIcons(QStringList iconFiles); - -private: - // hide copy constructor - IconList(const IconList &) = delete; - // hide assign op - IconList &operator=(const IconList &) = delete; - void reindex(); - Private *d; -}; diff --git a/logic/lists/InstanceList.cpp b/logic/lists/InstanceList.cpp index 0ecb387d..48a2865a 100644 --- a/logic/lists/InstanceList.cpp +++ b/logic/lists/InstanceList.cpp @@ -28,7 +28,7 @@ #include "MultiMC.h" #include "logic/lists/InstanceList.h" -#include "logic/lists/IconList.h" +#include "logic/icons/IconList.h" #include "logic/lists/MinecraftVersionList.h" #include "logic/BaseInstance.h" #include "logic/InstanceFactory.h" @@ -356,12 +356,13 @@ void InstanceList::loadForgeInstances(QMap groupMap) QString iconKey = record.logo; iconKey.remove(QRegularExpression("\\..*")); - MMC->icons()->addIcon(iconKey, iconKey, PathCombine(templateDir, record.logo), true); + MMC->icons()->addIcon(iconKey, iconKey, PathCombine(templateDir, record.logo), + MMCIcon::Transient); if (!QFileInfo(PathCombine(instanceDir, "instance.cfg")).exists()) { BaseInstance *instPtr = NULL; - auto & factory = InstanceFactory::get(); + auto &factory = InstanceFactory::get(); auto version = MMC->minecraftlist()->findVersion(record.mcVersion); if (!version) { -- cgit From ad7711b87cbbf96ebfd23b7fb7f6c2c1c319905d Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Tue, 31 Dec 2013 01:49:07 +0100 Subject: Fix silly bug with icon not changing on the toolbar when the icon key changes. --- gui/MainWindow.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'gui/MainWindow.cpp') diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index 2ba0d509..9cb79ea3 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -639,10 +639,8 @@ void MainWindow::on_actionChangeInstIcon_triggered() if (dlg.result() == QDialog::Accepted) { m_selectedInstance->setIconKey(dlg.selectedIconKey); - /* auto ico = MMC->icons()->getIcon(dlg.selectedIconKey); ui->actionChangeInstIcon->setIcon(ico); - */ } } -- cgit From 821fb5e0ae5b231224fdc56a053109b675006f34 Mon Sep 17 00:00:00 2001 From: Sky Date: Wed, 1 Jan 2014 14:56:26 +0000 Subject: Move assets migration to a task. Needs threading. --- CMakeLists.txt | 2 + gui/MainWindow.cpp | 26 ++++++- gui/MainWindow.h | 1 + logic/assets/AssetsMigrateTask.cpp | 141 +++++++++++++++++++++++++++++++++++++ logic/assets/AssetsMigrateTask.h | 18 +++++ logic/assets/AssetsUtils.cpp | 83 ++-------------------- logic/assets/AssetsUtils.h | 2 +- main.cpp | 1 + 8 files changed, 193 insertions(+), 81 deletions(-) create mode 100644 logic/assets/AssetsMigrateTask.cpp create mode 100644 logic/assets/AssetsMigrateTask.h (limited to 'gui/MainWindow.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index 301d8640..896dd926 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -414,6 +414,8 @@ logic/JavaCheckerJob.h logic/JavaCheckerJob.cpp # Assets +logic/assets/AssetsMigrateTask.h +logic/assets/AssetsMigrateTask.cpp logic/assets/AssetsUtils.h logic/assets/AssetsUtils.cpp ) diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index 9cb79ea3..42470bb0 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -88,6 +88,7 @@ #include "logic/LegacyInstance.h" #include "logic/assets/AssetsUtils.h" +#include "logic/assets/AssetsMigrateTask.h" #include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) @@ -286,8 +287,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi // removing this looks stupid view->setFocus(); - - AssetsUtils::migrateOldAssets(); } MainWindow::~MainWindow() @@ -1163,6 +1162,29 @@ void MainWindow::instanceEnded() this->show(); } +void MainWindow::checkMigrateLegacyAssets() +{ + int legacyAssets = AssetsUtils::findLegacyAssets(); + if(legacyAssets > 0) + { + ProgressDialog migrateDlg(this); + AssetsMigrateTask migrateTask(legacyAssets, &migrateDlg); + + if (migrateDlg.exec(&migrateTask)) + { + QLOG_INFO() << "Assets migration task completed successfully"; + } + else + { + QLOG_INFO() << "Assets migration task reported failure"; + } + } + else + { + QLOG_INFO() << "Didn't find any legacy assets to migrate"; + } +} + void MainWindow::checkSetDefaultJava() { bool askForJava = false; diff --git a/gui/MainWindow.h b/gui/MainWindow.h index 007c2e34..d6b7b845 100644 --- a/gui/MainWindow.h +++ b/gui/MainWindow.h @@ -51,6 +51,7 @@ public: void openWebPage(QUrl url); void checkSetDefaultJava(); + void checkMigrateLegacyAssets(); private slots: diff --git a/logic/assets/AssetsMigrateTask.cpp b/logic/assets/AssetsMigrateTask.cpp new file mode 100644 index 00000000..be45718d --- /dev/null +++ b/logic/assets/AssetsMigrateTask.cpp @@ -0,0 +1,141 @@ +#include "AssetsMigrateTask.h" +#include "MultiMC.h" +#include "logger/QsLog.h" +#include +#include +#include +#include "gui/dialogs/CustomMessageBox.h" +#include + +AssetsMigrateTask::AssetsMigrateTask(int expected, QObject *parent) + : Task(parent) +{ + this->m_expected = expected; +} + +void AssetsMigrateTask::executeTask() +{ + this->setStatus(tr("Migrating legacy assets...")); + this->setProgress(0); + + QDir assets_dir("assets"); + if (!assets_dir.exists()) + { + emitFailed("Assets directory didn't exist"); + return; + } + assets_dir.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot); + int base_length = assets_dir.path().length(); + + QList blacklist = {"indexes", "objects", "virtual"}; + + if (!assets_dir.exists("objects")) + assets_dir.mkdir("objects"); + QDir objects_dir("assets/objects"); + + QDirIterator iterator(assets_dir, QDirIterator::Subdirectories); + int successes = 0; + int failures = 0; + while (iterator.hasNext()) + { + QString currentDir = iterator.next(); + currentDir = currentDir.remove(0, base_length + 1); + + bool ignore = false; + for (QString blacklisted : blacklist) + { + if (currentDir.startsWith(blacklisted)) + ignore = true; + } + + if (!iterator.fileInfo().isDir() && !ignore) + { + QString filename = iterator.filePath(); + + QFile input(filename); + input.open(QIODevice::ReadOnly | QIODevice::WriteOnly); + QString sha1sum = + QCryptographicHash::hash(input.readAll(), QCryptographicHash::Sha1) + .toHex() + .constData(); + + QString object_name = filename.remove(0, base_length + 1); + QLOG_DEBUG() << "Processing" << object_name << ":" << sha1sum << input.size(); + + QString object_tlk = sha1sum.left(2); + QString object_tlk_dir = objects_dir.path() + "/" + object_tlk; + + QDir tlk_dir(object_tlk_dir); + if (!tlk_dir.exists()) + objects_dir.mkdir(object_tlk); + + QString new_filename = tlk_dir.path() + "/" + sha1sum; + QFile new_object(new_filename); + if (!new_object.exists()) + { + bool rename_success = input.rename(new_filename); + QLOG_DEBUG() << " Doesn't exist, copying to" << new_filename << ":" + << QString::number(rename_success); + if (rename_success) + successes++; + else + failures++; + } + else + { + input.remove(); + QLOG_DEBUG() << " Already exists, deleting original and not copying."; + } + + this->setProgress(100 * ((successes + failures) / (float) this->m_expected)); + } + } + + if (successes + failures == 0) + { + this->setProgress(100); + QLOG_DEBUG() << "No legacy assets needed importing."; + } + else + { + QLOG_DEBUG() << "Finished copying legacy assets:" << successes << "successes and" + << failures << "failures."; + + this->setStatus("Cleaning up legacy assets..."); + this->setProgress(100); + + QDirIterator cleanup_iterator(assets_dir); + + while (cleanup_iterator.hasNext()) + { + QString currentDir = cleanup_iterator.next(); + currentDir = currentDir.remove(0, base_length + 1); + + bool ignore = false; + for (QString blacklisted : blacklist) + { + if (currentDir.startsWith(blacklisted)) + ignore = true; + } + + if (cleanup_iterator.fileInfo().isDir() && !ignore) + { + QString path = cleanup_iterator.filePath(); + QDir folder(path); + + QLOG_DEBUG() << "Cleaning up legacy assets folder:" << path; + + folder.removeRecursively(); + } + } + } + + if(failures > 0) + { + emitFailed(QString("Failed to migrate %1 legacy assets").arg(failures)); + } + else + { + emitSucceeded(); + } +} diff --git a/logic/assets/AssetsMigrateTask.h b/logic/assets/AssetsMigrateTask.h new file mode 100644 index 00000000..d8d58c97 --- /dev/null +++ b/logic/assets/AssetsMigrateTask.h @@ -0,0 +1,18 @@ +#pragma once +#include "logic/tasks/Task.h" +#include +#include +#include + +class AssetsMigrateTask : public Task +{ + Q_OBJECT +public: + explicit AssetsMigrateTask(int expected, QObject* parent=0); + +protected: + virtual void executeTask(); + +private: + int m_expected; +}; diff --git a/logic/assets/AssetsUtils.cpp b/logic/assets/AssetsUtils.cpp index 11d928cf..bca7773d 100644 --- a/logic/assets/AssetsUtils.cpp +++ b/logic/assets/AssetsUtils.cpp @@ -25,23 +25,18 @@ namespace AssetsUtils { -void migrateOldAssets() +int findLegacyAssets() { QDir assets_dir("assets"); if (!assets_dir.exists()) - return; + return 0; assets_dir.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot); int base_length = assets_dir.path().length(); QList blacklist = {"indexes", "objects", "virtual"}; - if (!assets_dir.exists("objects")) - assets_dir.mkdir("objects"); - QDir objects_dir("assets/objects"); - QDirIterator iterator(assets_dir, QDirIterator::Subdirectories); - int successes = 0; - int failures = 0; + int found = 0; while (iterator.hasNext()) { QString currentDir = iterator.next(); @@ -56,79 +51,11 @@ void migrateOldAssets() if (!iterator.fileInfo().isDir() && !ignore) { - QString filename = iterator.filePath(); - - QFile input(filename); - input.open(QIODevice::ReadOnly | QIODevice::WriteOnly); - QString sha1sum = - QCryptographicHash::hash(input.readAll(), QCryptographicHash::Sha1) - .toHex() - .constData(); - - QString object_name = filename.remove(0, base_length + 1); - QLOG_DEBUG() << "Processing" << object_name << ":" << sha1sum << input.size(); - - QString object_tlk = sha1sum.left(2); - QString object_tlk_dir = objects_dir.path() + "/" + object_tlk; - - QDir tlk_dir(object_tlk_dir); - if (!tlk_dir.exists()) - objects_dir.mkdir(object_tlk); - - QString new_filename = tlk_dir.path() + "/" + sha1sum; - QFile new_object(new_filename); - if (!new_object.exists()) - { - bool rename_success = input.rename(new_filename); - QLOG_DEBUG() << " Doesn't exist, copying to" << new_filename << ":" - << QString::number(rename_success); - if (rename_success) - successes++; - else - failures++; - } - else - { - input.remove(); - QLOG_DEBUG() << " Already exists, deleting original and not copying."; - } + found++; } } - if (successes + failures == 0) - { - QLOG_DEBUG() << "No legacy assets needed importing."; - } - else - { - QLOG_DEBUG() << "Finished copying legacy assets:" << successes << "successes and" - << failures << "failures."; - - QDirIterator cleanup_iterator(assets_dir); - - while (cleanup_iterator.hasNext()) - { - QString currentDir = cleanup_iterator.next(); - currentDir = currentDir.remove(0, base_length + 1); - - bool ignore = false; - for (QString blacklisted : blacklist) - { - if (currentDir.startsWith(blacklisted)) - ignore = true; - } - - if (cleanup_iterator.fileInfo().isDir() && !ignore) - { - QString path = cleanup_iterator.filePath(); - QDir folder(path); - - QLOG_DEBUG() << "Cleaning up legacy assets folder:" << path; - - folder.removeRecursively(); - } - } - } + return found; } /* diff --git a/logic/assets/AssetsUtils.h b/logic/assets/AssetsUtils.h index 5276d5a5..aaacc2db 100644 --- a/logic/assets/AssetsUtils.h +++ b/logic/assets/AssetsUtils.h @@ -34,6 +34,6 @@ struct AssetsIndex namespace AssetsUtils { -void migrateOldAssets(); bool loadAssetsIndexJson(QString file, AssetsIndex* index); +int findLegacyAssets(); } diff --git a/main.cpp b/main.cpp index fb75765a..89eef72f 100644 --- a/main.cpp +++ b/main.cpp @@ -8,6 +8,7 @@ int main_gui(MultiMC &app) mainWin.restoreState(QByteArray::fromBase64(MMC->settings()->get("MainWindowState").toByteArray())); mainWin.restoreGeometry(QByteArray::fromBase64(MMC->settings()->get("MainWindowGeometry").toByteArray())); mainWin.show(); + mainWin.checkMigrateLegacyAssets(); mainWin.checkSetDefaultJava(); auto exitCode = app.exec(); -- cgit From 0e78d34d4cbed0ceb913ee70e89f36462bfe1dc6 Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Wed, 1 Jan 2014 19:21:58 +0100 Subject: ThreadTask for all your ThreadNeeds Use only when absolutely required. --- CMakeLists.txt | 8 ++++++-- gui/MainWindow.cpp | 18 ++++++++++------- logic/assets/AssetsMigrateTask.cpp | 2 ++ logic/tasks/ThreadTask.cpp | 41 ++++++++++++++++++++++++++++++++++++++ logic/tasks/ThreadTask.h | 25 +++++++++++++++++++++++ 5 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 logic/tasks/ThreadTask.cpp create mode 100644 logic/tasks/ThreadTask.h (limited to 'gui/MainWindow.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index 896dd926..39ff15c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,11 +47,13 @@ find_package(Qt5Core REQUIRED) find_package(Qt5Widgets REQUIRED) find_package(Qt5Network REQUIRED) find_package(Qt5Test REQUIRED) +find_package(Qt5Concurrent REQUIRED) find_package(Qt5LinguistTools REQUIRED) include_directories( ${Qt5Core_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS} + ${Qt5Concurrent_INCLUDE_DIRS} ${Qt5Network_INCLUDE_DIRS} ${Qt5Test_INCLUDE_DIRS} ) @@ -398,6 +400,8 @@ logic/EnabledItemFilter.cpp logic/tasks/ProgressProvider.h logic/tasks/Task.h logic/tasks/Task.cpp +logic/tasks/ThreadTask.h +logic/tasks/ThreadTask.cpp logic/tasks/SequentialTask.h logic/tasks/SequentialTask.cpp @@ -512,8 +516,8 @@ ADD_EXECUTABLE(MultiMC MACOSX_BUNDLE WIN32 main.cpp ${MULTIMC_RCS}) # Link TARGET_LINK_LIBRARIES(MultiMC MultiMC_common) TARGET_LINK_LIBRARIES(MultiMC_common xz-embedded unpack200 quazip libUtil libSettings libGroupView ${MultiMC_LINK_ADDITIONAL_LIBS}) -QT5_USE_MODULES(MultiMC Core Widgets Network Xml ${MultiMC_QT_ADDITIONAL_MODULES}) -QT5_USE_MODULES(MultiMC_common Core Widgets Network Xml ${MultiMC_QT_ADDITIONAL_MODULES}) +QT5_USE_MODULES(MultiMC Core Widgets Network Xml Concurrent ${MultiMC_QT_ADDITIONAL_MODULES}) +QT5_USE_MODULES(MultiMC_common Core Widgets Network Xml Concurrent ${MultiMC_QT_ADDITIONAL_MODULES}) ADD_DEPENDENCIES(MultiMC_common MultiMCLauncher JavaCheck) ################################ INSTALLATION AND PACKAGING ################################ diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index 42470bb0..b55be903 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -90,6 +90,7 @@ #include "logic/assets/AssetsUtils.h" #include "logic/assets/AssetsMigrateTask.h" #include +#include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { @@ -1169,14 +1170,17 @@ void MainWindow::checkMigrateLegacyAssets() { ProgressDialog migrateDlg(this); AssetsMigrateTask migrateTask(legacyAssets, &migrateDlg); - - if (migrateDlg.exec(&migrateTask)) { - QLOG_INFO() << "Assets migration task completed successfully"; - } - else - { - QLOG_INFO() << "Assets migration task reported failure"; + ThreadTask threadTask(&migrateTask); + + if (migrateDlg.exec(&threadTask)) + { + QLOG_INFO() << "Assets migration task completed successfully"; + } + else + { + QLOG_INFO() << "Assets migration task reported failure"; + } } } else diff --git a/logic/assets/AssetsMigrateTask.cpp b/logic/assets/AssetsMigrateTask.cpp index be45718d..7c1f5204 100644 --- a/logic/assets/AssetsMigrateTask.cpp +++ b/logic/assets/AssetsMigrateTask.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "gui/dialogs/CustomMessageBox.h" #include @@ -139,3 +140,4 @@ void AssetsMigrateTask::executeTask() emitSucceeded(); } } + diff --git a/logic/tasks/ThreadTask.cpp b/logic/tasks/ThreadTask.cpp new file mode 100644 index 00000000..ddd1dee5 --- /dev/null +++ b/logic/tasks/ThreadTask.cpp @@ -0,0 +1,41 @@ +#include "ThreadTask.h" +#include +ThreadTask::ThreadTask(Task * internal, QObject *parent) : Task(parent), m_internal(internal) +{ +} + +void ThreadTask::start() +{ + connect(m_internal, SIGNAL(failed(QString)), SLOT(iternal_failed(QString))); + connect(m_internal, SIGNAL(progress(qint64,qint64)), SLOT(iternal_progress(qint64,qint64))); + connect(m_internal, SIGNAL(started()), SLOT(iternal_started())); + connect(m_internal, SIGNAL(status(QString)), SLOT(iternal_status(QString))); + connect(m_internal, SIGNAL(succeeded()), SLOT(iternal_succeeded())); + m_running = true; + QtConcurrent::run(m_internal, &Task::start); +} + +void ThreadTask::iternal_failed(QString reason) +{ + emitFailed(reason); +} + +void ThreadTask::iternal_progress(qint64 current, qint64 total) +{ + progress(current, total); +} + +void ThreadTask::iternal_started() +{ + emit started(); +} + +void ThreadTask::iternal_status(QString status) +{ + setStatus(status); +} + +void ThreadTask::iternal_succeeded() +{ + emitSucceeded(); +} diff --git a/logic/tasks/ThreadTask.h b/logic/tasks/ThreadTask.h new file mode 100644 index 00000000..718dbc91 --- /dev/null +++ b/logic/tasks/ThreadTask.h @@ -0,0 +1,25 @@ +#pragma once + +#include "Task.h" + +class ThreadTask : public Task +{ + Q_OBJECT +public: + explicit ThreadTask(Task * internal, QObject * parent = nullptr); + +protected: + void executeTask() {}; + +public slots: + virtual void start(); + +private slots: + void iternal_started(); + void iternal_progress(qint64 current, qint64 total); + void iternal_succeeded(); + void iternal_failed(QString reason); + void iternal_status(QString status); +private: + Task * m_internal; +}; \ No newline at end of file -- cgit