diff options
65 files changed, 2661 insertions, 333 deletions
diff --git a/.travis.yml b/.travis.yml index ad0bdee5..9ed7a045 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,6 @@ before_script: - cd build - cmake -DCMAKE_PREFIX_PATH=/opt/qt53/lib/cmake .. script: - - make -j4 - - make test ARGS="-V" + - make -j4 && make test ARGS="-V" notifications: email: false diff --git a/application/CMakeLists.txt b/application/CMakeLists.txt index d7cb5777..d3962819 100644 --- a/application/CMakeLists.txt +++ b/application/CMakeLists.txt @@ -251,6 +251,8 @@ SET(MULTIMC_SOURCES widgets/ServerStatus.h widgets/VersionListView.cpp widgets/VersionListView.h + widgets/ProgressWidget.h + widgets/ProgressWidget.cpp # GUI - instance group view diff --git a/application/MainWindow.cpp b/application/MainWindow.cpp index 9ff120bd..99c94bf8 100644 --- a/application/MainWindow.cpp +++ b/application/MainWindow.cpp @@ -383,6 +383,7 @@ namespace Ui { #include "JavaCommon.h" #include "InstancePageProvider.h" #include "minecraft/SkinUtils.h" +#include "resources/Resource.h" //#include "minecraft/LegacyInstance.h" @@ -1758,7 +1759,7 @@ void MainWindow::launchInstance(InstancePtr instance, AuthSessionPtr session, this->hide(); console = new ConsoleWindow(proc); - connect(console, SIGNAL(isClosing()), this, SLOT(instanceEnded())); + connect(console, &ConsoleWindow::isClosing, this, &MainWindow::instanceEnded); proc->setHeader("MultiMC version: " + BuildConfig.printableVersionString() + "\n\n"); proc->arm(); diff --git a/application/MultiMC.cpp b/application/MultiMC.cpp index 39cc8503..2c6b387c 100644 --- a/application/MultiMC.cpp +++ b/application/MultiMC.cpp @@ -40,6 +40,8 @@ #include "settings/Setting.h" #include "trans/TranslationDownloader.h" +#include "resources/Resource.h" +#include "resources/IconResourceHandler.h" #include "ftb/FTBPlugin.h" @@ -331,6 +333,37 @@ void MultiMC::initIcons() { ENV.m_icons->directoryChanged(value.toString()); }); + + Resource::registerTransformer([](const QVariantMap &map) -> QIcon + { + QIcon icon; + for (auto it = map.constBegin(); it != map.constEnd(); ++it) + { + icon.addFile(it.key(), QSize(it.value().toInt(), it.value().toInt())); + } + return icon; + }); + Resource::registerTransformer([](const QVariantMap &map) -> QPixmap + { + QVariantList sizes = map.values(); + if (sizes.isEmpty()) + { + return QPixmap(); + } + std::sort(sizes.begin(), sizes.end()); + if (sizes.last().toInt() != -1) // only scalable available + { + return QPixmap(map.key(sizes.last())); + } + else + { + return QPixmap(); + } + }); + Resource::registerTransformer([](const QByteArray &data) -> QPixmap + { return QPixmap::fromImage(QImage::fromData(data)); }); + Resource::registerTransformer([](const QByteArray &data) -> QIcon + { return QIcon(QPixmap::fromImage(QImage::fromData(data))); }); } @@ -610,6 +643,7 @@ void MultiMC::installUpdates(const QString updateFilesDir, UpdateFlags flags) void MultiMC::setIconTheme(const QString& name) { XdgIcon::setThemeName(name); + IconResourceHandler::setTheme(name); } QIcon MultiMC::getThemedIcon(const QString& name) diff --git a/application/MultiMC.h b/application/MultiMC.h index 8215e4ad..e4a54115 100644 --- a/application/MultiMC.h +++ b/application/MultiMC.h @@ -146,13 +146,10 @@ private slots: private: void initLogger(); - void initIcons(); - void initGlobalSettings(bool test_mode); - void initTranslations(); - void initSSL(); + void initSSL(); private: friend class UpdateCheckerTest; diff --git a/application/main.cpp b/application/main.cpp index 111a61ac..12c97f09 100644 --- a/application/main.cpp +++ b/application/main.cpp @@ -13,7 +13,6 @@ int main_gui(MultiMC &app) mainWin.checkInstancePathForProblems(); return app.exec(); } - int main(int argc, char *argv[]) { // initialize Qt diff --git a/application/pages/VersionPage.cpp b/application/pages/VersionPage.cpp index cbb5c107..efc0b446 100644 --- a/application/pages/VersionPage.cpp +++ b/application/pages/VersionPage.cpp @@ -47,7 +47,7 @@ #include <minecraft/MinecraftVersion.h> #include <minecraft/MinecraftVersionList.h> #include "icons/IconList.h" - +#include "Exception.h" QIcon VersionPage::icon() const { @@ -118,7 +118,7 @@ bool VersionPage::reloadMinecraftProfile() m_inst->reloadProfile(); return true; } - catch (MMCError &e) + catch (Exception &e) { QMessageBox::critical(this, tr("Error"), e.cause()); return false; @@ -199,7 +199,7 @@ void VersionPage::on_resetOrderBtn_clicked() { m_version->resetOrder(); } - catch (MMCError &e) + catch (Exception &e) { QMessageBox::critical(this, tr("Error"), e.cause()); } @@ -212,7 +212,7 @@ void VersionPage::on_moveUpBtn_clicked() { m_version->move(currentRow(), MinecraftProfile::MoveUp); } - catch (MMCError &e) + catch (Exception &e) { QMessageBox::critical(this, tr("Error"), e.cause()); } @@ -225,7 +225,7 @@ void VersionPage::on_moveDownBtn_clicked() { m_version->move(currentRow(), MinecraftProfile::MoveDown); } - catch (MMCError &e) + catch (Exception &e) { QMessageBox::critical(this, tr("Error"), e.cause()); } diff --git a/application/pages/global/AccountListPage.h b/application/pages/global/AccountListPage.h index bfadc1bd..7803e044 100644 --- a/application/pages/global/AccountListPage.h +++ b/application/pages/global/AccountListPage.h @@ -21,7 +21,7 @@ #include "pages/BasePage.h" #include "auth/MojangAccountList.h" -#include <MultiMC.h> +#include "MultiMC.h" namespace Ui { diff --git a/application/resources/multimc/150x150/hourglass.png b/application/resources/multimc/150x150/hourglass.png Binary files differnew file mode 100644 index 00000000..f2623d1e --- /dev/null +++ b/application/resources/multimc/150x150/hourglass.png diff --git a/application/resources/multimc/16x16/hourglass.png b/application/resources/multimc/16x16/hourglass.png Binary files differnew file mode 100644 index 00000000..ab36234b --- /dev/null +++ b/application/resources/multimc/16x16/hourglass.png diff --git a/application/resources/multimc/22x22/hourglass.png b/application/resources/multimc/22x22/hourglass.png Binary files differnew file mode 100644 index 00000000..8cb343ac --- /dev/null +++ b/application/resources/multimc/22x22/hourglass.png diff --git a/application/resources/multimc/32x32/hourglass.png b/application/resources/multimc/32x32/hourglass.png Binary files differnew file mode 100644 index 00000000..a558ec99 --- /dev/null +++ b/application/resources/multimc/32x32/hourglass.png diff --git a/application/resources/multimc/48x48/hourglass.png b/application/resources/multimc/48x48/hourglass.png Binary files differnew file mode 100644 index 00000000..8f10ab7a --- /dev/null +++ b/application/resources/multimc/48x48/hourglass.png diff --git a/application/resources/multimc/index.theme b/application/resources/multimc/index.theme index 5f7d3f3f..a21fea2c 100644 --- a/application/resources/multimc/index.theme +++ b/application/resources/multimc/index.theme @@ -35,6 +35,9 @@ Size=64 [256x256] Size=256 +[150x150] +Size=150 + [scalable] Size=48 Type=Scalable diff --git a/application/resources/multimc/multimc.qrc b/application/resources/multimc/multimc.qrc index 4ced586a..31a7b44f 100644 --- a/application/resources/multimc/multimc.qrc +++ b/application/resources/multimc/multimc.qrc @@ -207,6 +207,13 @@ <file>48x48/log.png</file> <file>64x64/log.png</file> + <!-- Hour glass, CC-BY, http://findicons.com/icon/84653/hourglass?id=360551 --> + <file>16x16/hourglass.png</file> + <file>22x22/hourglass.png</file> + <file>32x32/hourglass.png</file> + <file>48x48/hourglass.png</file> + <file>150x150/hourglass.png</file> + <!-- placeholder when loading screenshot images --> <file>scalable/screenshot-placeholder.svg</file> </qresource> diff --git a/application/widgets/ProgressWidget.cpp b/application/widgets/ProgressWidget.cpp new file mode 100644 index 00000000..7b51eca0 --- /dev/null +++ b/application/widgets/ProgressWidget.cpp @@ -0,0 +1,74 @@ +// Licensed under the Apache-2.0 license. See README.md for details. + +#include "ProgressWidget.h" + +#include <QProgressBar> +#include <QLabel> +#include <QVBoxLayout> +#include <QEventLoop> + +#include "tasks/Task.h" + +ProgressWidget::ProgressWidget(QWidget *parent) + : QWidget(parent) +{ + m_label = new QLabel(this); + m_label->setWordWrap(true); + m_bar = new QProgressBar(this); + m_bar->setMinimum(0); + m_bar->setMaximum(100); + QVBoxLayout *layout = new QVBoxLayout(this); + layout->addWidget(m_label); + layout->addWidget(m_bar); + layout->addStretch(); + setLayout(layout); +} + +void ProgressWidget::start(std::shared_ptr<Task> task) +{ + if (m_task) + { + disconnect(m_task.get(), 0, this, 0); + } + m_task = task; + connect(m_task.get(), &Task::finished, this, &ProgressWidget::handleTaskFinish); + connect(m_task.get(), &Task::status, this, &ProgressWidget::handleTaskStatus); + connect(m_task.get(), &Task::progress, this, &ProgressWidget::handleTaskProgress); + connect(m_task.get(), &Task::destroyed, this, &ProgressWidget::taskDestroyed); + if (!m_task->isRunning()) + { + QMetaObject::invokeMethod(m_task.get(), "start", Qt::QueuedConnection); + } +} +bool ProgressWidget::exec(std::shared_ptr<Task> task) +{ + QEventLoop loop; + connect(task.get(), &Task::finished, &loop, &QEventLoop::quit); + start(task); + if (task->isRunning()) + { + loop.exec(); + } + return task->successful(); +} + +void ProgressWidget::handleTaskFinish() +{ + if (!m_task->successful()) + { + m_label->setText(m_task->failReason()); + } +} +void ProgressWidget::handleTaskStatus(const QString &status) +{ + m_label->setText(status); +} +void ProgressWidget::handleTaskProgress(qint64 current, qint64 total) +{ + m_bar->setMaximum(total); + m_bar->setValue(current); +} +void ProgressWidget::taskDestroyed() +{ + m_task = nullptr; +} diff --git a/application/widgets/ProgressWidget.h b/application/widgets/ProgressWidget.h new file mode 100644 index 00000000..08d8a157 --- /dev/null +++ b/application/widgets/ProgressWidget.h @@ -0,0 +1,32 @@ +// Licensed under the Apache-2.0 license. See README.md for details. + +#pragma once + +#include <QWidget> +#include <memory> + +class Task; +class QProgressBar; +class QLabel; + +class ProgressWidget : public QWidget +{ + Q_OBJECT +public: + explicit ProgressWidget(QWidget *parent = nullptr); + +public slots: + void start(std::shared_ptr<Task> task); + bool exec(std::shared_ptr<Task> task); + +private slots: + void handleTaskFinish(); + void handleTaskStatus(const QString &status); + void handleTaskProgress(qint64 current, qint64 total); + void taskDestroyed(); + +private: + QLabel *m_label; + QProgressBar *m_bar; + std::shared_ptr<Task> m_task; +}; diff --git a/logic/AbstractCommonModel.cpp b/logic/AbstractCommonModel.cpp new file mode 100644 index 00000000..71d75829 --- /dev/null +++ b/logic/AbstractCommonModel.cpp @@ -0,0 +1,133 @@ +/* Copyright 2015 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AbstractCommonModel.h" + +BaseAbstractCommonModel::BaseAbstractCommonModel(const Qt::Orientation orientation, QObject *parent) + : QAbstractListModel(parent), m_orientation(orientation) +{ +} + +int BaseAbstractCommonModel::rowCount(const QModelIndex &parent) const +{ + return m_orientation == Qt::Horizontal ? entryCount() : size(); +} +int BaseAbstractCommonModel::columnCount(const QModelIndex &parent) const +{ + return m_orientation == Qt::Horizontal ? size() : entryCount(); +} +QVariant BaseAbstractCommonModel::data(const QModelIndex &index, int role) const +{ + if (!hasIndex(index.row(), index.column(), index.parent())) + { + return QVariant(); + } + const int i = m_orientation == Qt::Horizontal ? index.column() : index.row(); + const int entry = m_orientation == Qt::Horizontal ? index.row() : index.column(); + return formatData(i, role, get(i, entry, role)); +} +QVariant BaseAbstractCommonModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation != m_orientation && role == Qt::DisplayRole) + { + return entryTitle(section); + } + else + { + return QVariant(); + } +} +bool BaseAbstractCommonModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + const int i = m_orientation == Qt::Horizontal ? index.column() : index.row(); + const int entry = m_orientation == Qt::Horizontal ? index.row() : index.column(); + const bool result = set(i, entry, role, sanetizeData(i, role, value)); + if (result) + { + emit dataChanged(index, index, QVector<int>() << role); + } + return result; +} +Qt::ItemFlags BaseAbstractCommonModel::flags(const QModelIndex &index) const +{ + if (!hasIndex(index.row(), index.column(), index.parent())) + { + return Qt::NoItemFlags; + } + + const int entry = m_orientation == Qt::Horizontal ? index.row() : index.column(); + if (canSet(entry)) + { + return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEnabled; + } + else + { + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; + } +} + +void BaseAbstractCommonModel::notifyAboutToAddObject(const int at) +{ + if (m_orientation == Qt::Horizontal) + { + beginInsertColumns(QModelIndex(), at, at); + } + else + { + beginInsertRows(QModelIndex(), at, at); + } +} +void BaseAbstractCommonModel::notifyObjectAdded() +{ + if (m_orientation == Qt::Horizontal) + { + endInsertColumns(); + } + else + { + endInsertRows(); + } +} +void BaseAbstractCommonModel::notifyAboutToRemoveObject(const int at) +{ + if (m_orientation == Qt::Horizontal) + { + beginRemoveColumns(QModelIndex(), at, at); + } + else + { + beginRemoveRows(QModelIndex(), at, at); + } +} +void BaseAbstractCommonModel::notifyObjectRemoved() +{ + if (m_orientation == Qt::Horizontal) + { + endRemoveColumns(); + } + else + { + endRemoveRows(); + } +} + +void BaseAbstractCommonModel::notifyBeginReset() +{ + beginResetModel(); +} +void BaseAbstractCommonModel::notifyEndReset() +{ + endResetModel(); +} diff --git a/logic/AbstractCommonModel.h b/logic/AbstractCommonModel.h new file mode 100644 index 00000000..31b86a23 --- /dev/null +++ b/logic/AbstractCommonModel.h @@ -0,0 +1,462 @@ +/* Copyright 2015 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <QAbstractListModel> +#include <type_traits> +#include <functional> +#include <memory> + +class BaseAbstractCommonModel : public QAbstractListModel +{ + Q_OBJECT +public: + explicit BaseAbstractCommonModel(const Qt::Orientation orientation, QObject *parent = nullptr); + + // begin QAbstractItemModel interface + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role) override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + // end QAbstractItemModel interface + + virtual int size() const = 0; + virtual int entryCount() const = 0; + + virtual QVariant formatData(const int index, int role, const QVariant &data) const { return data; } + virtual QVariant sanetizeData(const int index, int role, const QVariant &data) const { return data; } + +protected: + virtual QVariant get(const int index, const int entry, const int role) const = 0; + virtual bool set(const int index, const int entry, const int role, const QVariant &value) = 0; + virtual bool canSet(const int entry) const = 0; + virtual QString entryTitle(const int entry) const = 0; + + void notifyAboutToAddObject(const int at); + void notifyObjectAdded(); + void notifyAboutToRemoveObject(const int at); + void notifyObjectRemoved(); + void notifyBeginReset(); + void notifyEndReset(); + + const Qt::Orientation m_orientation; +}; + +template<typename Object> +class AbstractCommonModel : public BaseAbstractCommonModel +{ +public: + explicit AbstractCommonModel(const Qt::Orientation orientation) + : BaseAbstractCommonModel(orientation) {} + virtual ~AbstractCommonModel() {} + + int size() const override { return m_objects.size(); } + int entryCount() const override { return m_entries.size(); } + + void append(const Object &object) + { + notifyAboutToAddObject(size()); + m_objects.append(object); + notifyObjectAdded(); + } + void prepend(const Object &object) + { + notifyAboutToAddObject(0); + m_objects.prepend(object); + notifyObjectAdded(); |
