summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Mrázek <peterix@gmail.com>2014-09-06 21:01:23 +0200
committerPetr Mrázek <peterix@gmail.com>2014-09-06 21:01:23 +0200
commitb00e63dbe8d0acaae503e63d614ee20b9e9ede2e (patch)
treeadc9a8442d20fe717879224036ee0b768dfa392d
parent20cb97a35af5097e9d3b2062c0dfcb5f2e5fff5c (diff)
downloadMultiMC-b00e63dbe8d0acaae503e63d614ee20b9e9ede2e.tar
MultiMC-b00e63dbe8d0acaae503e63d614ee20b9e9ede2e.tar.gz
MultiMC-b00e63dbe8d0acaae503e63d614ee20b9e9ede2e.tar.lz
MultiMC-b00e63dbe8d0acaae503e63d614ee20b9e9ede2e.tar.xz
MultiMC-b00e63dbe8d0acaae503e63d614ee20b9e9ede2e.zip
More sync from quickmods
Also a small VersionSelectDialog refactor
-rw-r--r--.travis.yml2
-rw-r--r--CMakeLists.txt17
-rw-r--r--depends/LogicalGui/CMakeLists.txt7
-rw-r--r--depends/LogicalGui/LogicalGui.h254
-rw-r--r--gui/dialogs/ProgressDialog.cpp2
-rw-r--r--gui/dialogs/VersionSelectDialog.cpp101
-rw-r--r--gui/dialogs/VersionSelectDialog.h6
-rw-r--r--gui/groupview/InstanceDelegate.cpp4
-rw-r--r--logic/OneSixFTBInstance.cpp12
-rw-r--r--logic/OneSixFTBInstance.h1
10 files changed, 378 insertions, 28 deletions
diff --git a/.travis.yml b/.travis.yml
index 4ed123de..5d8dd880 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,7 +9,7 @@ before_install:
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- sudo apt-get update -qq
install:
- - sudo apt-get install -y -qq cmake qt52base qt52svg qt52tools qt52x11extras
+ - sudo apt-get install -y -qq cmake qt52base qt52svg qt52tools qt52x11extras qt52webkit
- sudo apt-get install -y -qq g++-4.8
- if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi
before_script:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d11d21f9..47c5c9da 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -48,6 +48,7 @@ find_package(Qt5Network REQUIRED)
find_package(Qt5Test REQUIRED)
find_package(Qt5Xml REQUIRED)
find_package(Qt5LinguistTools REQUIRED)
+find_package(Qt5WebKitWidgets REQUIRED)
include_directories(
${Qt5Core_INCLUDE_DIRS}
@@ -186,6 +187,12 @@ else()
set(MultiMC_UPDATER_FORCE_LOCAL_value "false")
endif()
+#### For QuickMods
+option(MultiMC_WEBKIT_INSPECTOR "Enable the QWebInspector for debugging" OFF)
+if(MultiMC_WEBKIT_INSPECTOR)
+ add_definitions(-DWEBKIT_INSPECTOR)
+endif()
+
#### Custom target to just print the version.
add_custom_target(version echo "Version: ${MultiMC_VERSION_STRING}")
@@ -257,6 +264,10 @@ include_directories(${LIBUTIL_INCLUDE_DIR})
# Add the updater
add_subdirectory(mmc_updater)
+# Add the GUI -> Logic connection header
+add_subdirectory(depends/LogicalGui)
+include_directories(${LOGICALGUI_INCLUDE_DIR})
+
################################ FILES ################################
######## Sources and headers ########
@@ -744,9 +755,9 @@ 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 ${MultiMC_LINK_ADDITIONAL_LIBS})
-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})
+target_link_libraries(MultiMC_common xz-embedded unpack200 quazip libUtil LogicalGui ${MultiMC_LINK_ADDITIONAL_LIBS})
+qt5_use_modules(MultiMC Core Widgets Network Xml Concurrent WebKitWidgets ${MultiMC_QT_ADDITIONAL_MODULES})
+qt5_use_modules(MultiMC_common Core Widgets Network Xml Concurrent WebKitWidgets ${MultiMC_QT_ADDITIONAL_MODULES})
################################ INSTALLATION AND PACKAGING ################################
diff --git a/depends/LogicalGui/CMakeLists.txt b/depends/LogicalGui/CMakeLists.txt
new file mode 100644
index 00000000..9fb03a03
--- /dev/null
+++ b/depends/LogicalGui/CMakeLists.txt
@@ -0,0 +1,7 @@
+project(LogicalGui)
+
+# Set the include dir path.
+set(LOGICALGUI_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE)
+
+add_library(LogicalGui STATIC LogicalGui.h)
+qt5_use_modules(LogicalGui Core)
diff --git a/depends/LogicalGui/LogicalGui.h b/depends/LogicalGui/LogicalGui.h
new file mode 100644
index 00000000..4034459e
--- /dev/null
+++ b/depends/LogicalGui/LogicalGui.h
@@ -0,0 +1,254 @@
+/* Copyright 2014 Jan Dalheimer
+ *
+ * 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 <QObject>
+#include <QMetaMethod>
+#include <QThread>
+#include <QCoreApplication>
+#include <QSemaphore>
+#include <memory>
+
+#if QT_VERSION == QT_VERSION_CHECK(5, 1, 1)
+#include <5.1.1/QtCore/private/qobject_p.h>
+#elif QT_VERSION == QT_VERSION_CHECK(5, 2, 0)
+#include <5.2.0/QtCore/private/qobject_p.h>
+#elif QT_VERSION == QT_VERSION_CHECK(5, 2, 1)
+#include <5.2.1/QtCore/private/qobject_p.h>
+#elif QT_VERSION == QT_VERSION_CHECK(5, 3, 0)
+#include <5.3.0/QtCore/private/qobject_p.h>
+#elif QT_VERSION == QT_VERSION_CHECK(5, 3, 1)
+#include <5.3.1/QtCore/private/qobject_p.h>
+#else
+#error Please add support for this version of Qt
+#endif
+
+class Bindable
+{
+ friend class tst_LogicalGui;
+
+public:
+ Bindable(Bindable *parent = 0) : m_parent(parent)
+ {
+ }
+ virtual ~Bindable()
+ {
+ }
+
+ void setBindableParent(Bindable *parent)
+ {
+ m_parent = parent;
+ }
+
+ void bind(const QString &id, const QObject *receiver, const char *methodSignature)
+ {
+ auto mo = receiver->metaObject();
+ Q_ASSERT_X(mo, "Bindable::bind",
+ "Invalid metaobject. Did you forget the QObject macro?");
+ const QMetaMethod method = mo->method(mo->indexOfMethod(
+ QMetaObject::normalizedSignature(methodSignature + 1).constData()));
+ Q_ASSERT_X(method.isValid(), "Bindable::bind", "Invalid method signature");
+ m_bindings.insert(id, Binding(receiver, method));
+ }
+ template <typename Func>
+ void bind(const QString &id,
+ const typename QtPrivate::FunctionPointer<Func>::Object *receiver, Func slot)
+ {
+ typedef QtPrivate::FunctionPointer<Func> SlotType;
+ m_bindings.insert(
+ id,
+ Binding(receiver, new QtPrivate::QSlotObject<Func, typename SlotType::Arguments,
+ typename SlotType::ReturnType>(slot)));
+ }
+ template <typename Func> void bind(const QString &id, Func slot)
+ {
+ typedef QtPrivate::FunctionPointer<Func> SlotType;
+ m_bindings.insert(
+ id,
+ Binding(nullptr, new QtPrivate::QSlotObject<Func, typename SlotType::Arguments,
+ typename SlotType::ReturnType>(slot)));
+ }
+ void unbind(const QString &id)
+ {
+ m_bindings.remove(id);
+ }
+
+private:
+ struct Binding
+ {
+ Binding(const QObject *receiver, const QMetaMethod &method)
+ : receiver(receiver), method(method)
+ {
+ }
+ Binding(const QObject *receiver, QtPrivate::QSlotObjectBase *object)
+ : receiver(receiver), object(object)
+ {
+ }
+ Binding()
+ {
+ }
+ const QObject *receiver;
+ QMetaMethod method;
+ QtPrivate::QSlotObjectBase *object = nullptr;
+ };
+ QMap<QString, Binding> m_bindings;
+
+ Bindable *m_parent;
+
+private:
+ inline Qt::ConnectionType connectionType(const QObject *receiver)
+ {
+ return receiver == nullptr ? Qt::DirectConnection
+ : (QThread::currentThread() == receiver->thread()
+ ? Qt::DirectConnection
+ : Qt::BlockingQueuedConnection);
+ }
+
+protected:
+ template <typename Ret, typename... Params> Ret wait(const QString &id, Params... params)
+ {
+ static_assert(!std::is_same<Ret, void>::value, "You need to use Bindable::waitVoid");
+
+ if (!m_bindings.contains(id) && m_parent)
+ {
+ return m_parent->wait<Ret, Params...>(id, params...);
+ }
+ Q_ASSERT(m_bindings.contains(id));
+ const auto binding = m_bindings[id];
+ const Qt::ConnectionType type = connectionType(binding.receiver);
+ Ret ret;
+ if (binding.object)
+ {
+ void *args[] = {&ret,
+ const_cast<void *>(reinterpret_cast<const void *>(&params))...};
+ if (type == Qt::BlockingQueuedConnection)
+ {
+ QSemaphore semaphore;
+ QMetaCallEvent *ev =
+ new QMetaCallEvent(binding.object, nullptr, -1, 0, 0, args, &semaphore);
+ QCoreApplication::postEvent(const_cast<QObject *>(binding.receiver), ev);
+ semaphore.acquire();
+ }
+ else
+ {
+ binding.object->call(const_cast<QObject *>(binding.receiver), args);
+ }
+ }
+ else
+ {
+ const QMetaMethod method = binding.method;
+ Q_ASSERT_X(method.parameterCount() == sizeof...(params), "Bindable::wait",
+ qPrintable(QString("Incompatible argument count (expected %1, got %2)")
+ .arg(method.parameterCount(), sizeof...(params))));
+ Q_ASSERT_X(
+ qMetaTypeId<Ret>() != QMetaType::UnknownType, "Bindable::wait",
+ "Requested return type is not registered, please use the Q_DECLARE_METATYPE "
+ "macro to make it known to Qt's meta-object system");
+ Q_ASSERT_X(
+ method.returnType() == qMetaTypeId<Ret>() ||
+ QMetaType::hasRegisteredConverterFunction(method.returnType(),
+ qMetaTypeId<Ret>()),
+ "Bindable::wait",
+ qPrintable(
+ QString(
+ "Requested return type (%1) is incompatible method return type (%2)")
+ .arg(QMetaType::typeName(qMetaTypeId<Ret>()),
+ QMetaType::typeName(method.returnType()))));
+ const auto retArg = QReturnArgument<Ret>(
+ QMetaType::typeName(qMetaTypeId<Ret>()),
+ ret); // because Q_RETURN_ARG doesn't work with templates...
+ method.invoke(const_cast<QObject *>(binding.receiver), type, retArg,
+ Q_ARG(Params, params)...);
+ }
+ return ret;
+ }
+ template <typename... Params>
+ typename std::enable_if<sizeof...(Params) != 0, void>::type waitVoid(const QString &id,
+ Params... params)
+ {
+ if (!m_bindings.contains(id) && m_parent)
+ {
+ m_parent->waitVoid<Params...>(id, params...);
+ return;
+ }
+ Q_ASSERT(m_bindings.contains(id));
+ const auto binding = m_bindings[id];
+ const Qt::ConnectionType type = connectionType(binding.receiver);
+ if (binding.object)
+ {
+ void *args[] = {0, const_cast<void *>(reinterpret_cast<const void *>(&params))...};
+ if (type == Qt::BlockingQueuedConnection)
+ {
+ QSemaphore semaphore;
+ QMetaCallEvent *ev =
+ new QMetaCallEvent(binding.object, nullptr, -1, 0, 0, args, &semaphore);
+ QCoreApplication::postEvent(const_cast<QObject *>(binding.receiver), ev);
+ semaphore.acquire();
+ }
+ else
+ {
+ binding.object->call(const_cast<QObject *>(binding.receiver), args);
+ }
+ }
+ else
+ {
+ const QMetaMethod method = binding.method;
+ Q_ASSERT_X(method.parameterCount() == sizeof...(params), "Bindable::wait",
+ qPrintable(QString("Incompatible argument count (expected %1, got %2)")
+ .arg(method.parameterCount(), sizeof...(params))));
+ method.invoke(const_cast<QObject *>(binding.receiver), type,
+ Q_ARG(Params, params)...);
+ }
+ }
+ void waitVoid(const QString &id)
+ {
+ if (!m_bindings.contains(id) && m_parent)
+ {
+ m_parent->waitVoid(id);
+ return;
+ }
+ Q_ASSERT(m_bindings.contains(id));
+ const auto binding = m_bindings[id];
+ const Qt::ConnectionType type = connectionType(binding.receiver);
+ if (binding.object)
+ {
+ void *args[] = {0};
+ if (type == Qt::BlockingQueuedConnection)
+ {
+ QSemaphore semaphore;
+ QMetaCallEvent *ev =
+ new QMetaCallEvent(binding.object, nullptr, -1, 0, 0, args, &semaphore);
+ QCoreApplication::postEvent(const_cast<QObject *>(binding.receiver), ev);
+ semaphore.acquire();
+ }
+ else
+ {
+ binding.object->call(const_cast<QObject *>(binding.receiver), args);
+ }
+ }
+ else
+ {
+ const QMetaMethod method = binding.method;
+ Q_ASSERT_X(method.parameterCount() == 0, "Bindable::wait",
+ qPrintable(QString("Incompatible argument count (expected %1, got %2)")
+ .arg(method.parameterCount(), 0)));
+ method.invoke(const_cast<QObject *>(binding.receiver), type);
+ }
+ }
+};
+
+// used frequently
+Q_DECLARE_METATYPE(bool *)
diff --git a/gui/dialogs/ProgressDialog.cpp b/gui/dialogs/ProgressDialog.cpp
index ba14cca2..8adaace5 100644
--- a/gui/dialogs/ProgressDialog.cpp
+++ b/gui/dialogs/ProgressDialog.cpp
@@ -71,7 +71,7 @@ int ProgressDialog::exec(ProgressProvider *task)
if(task->isRunning())
return QDialog::exec();
else
- return 0;
+ return QDialog::Accepted;
}
ProgressProvider *ProgressDialog::getTask()
diff --git a/gui/dialogs/VersionSelectDialog.cpp b/gui/dialogs/VersionSelectDialog.cpp
index 2745eccc..83a1993f 100644
--- a/gui/dialogs/VersionSelectDialog.cpp
+++ b/gui/dialogs/VersionSelectDialog.cpp
@@ -24,10 +24,72 @@
#include <logic/BaseVersion.h>
#include <logic/BaseVersionList.h>
#include <logic/tasks/Task.h>
+#include <depends/util/include/modutils.h>
+#include "logger/QsLog.h"
+
+class VersionSelectProxyModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+public:
+ VersionSelectProxyModel(QObject *parent = 0) : QSortFilterProxyModel(parent)
+ {
+ }
+
+ struct Filter
+ {
+ QString string;
+ bool exact = false;
+ };
+
+ QHash<int, Filter> filters() const
+ {
+ return m_filters;
+ }
+ void setFilter(const int column, const QString &filter, const bool exact)
+ {
+ Filter f;
+ f.string = filter;
+ f.exact = exact;
+ m_filters[column] = f;
+ invalidateFilter();
+ }
+ void clearFilters()
+ {
+ m_filters.clear();
+ invalidateFilter();
+ }
+
+protected:
+ bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
+ {
+ for (auto it = m_filters.begin(); it != m_filters.end(); ++it)
+ {
+ const QString version =
+ sourceModel()->index(source_row, it.key()).data().toString();
+
+ if (it.value().exact)
+ {
+ if (version != it.value().string)
+ {
+ return false;
+ }
+ continue;
+ }
+
+ if (!Util::versionIsInInterval(version, it.value().string))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ QHash<int, Filter> m_filters;
+};
VersionSelectDialog::VersionSelectDialog(BaseVersionList *vlist, QString title, QWidget *parent,
bool cancelable)
- : QDialog(parent), ui(new Ui::VersionSelectDialog)
+ : QDialog(parent), ui(new Ui::VersionSelectDialog), m_useLatest(false)
{
MultiMCPlatform::fixWM_CLASS(this);
ui->setupUi(this);
@@ -36,7 +98,7 @@ VersionSelectDialog::VersionSelectDialog(BaseVersionList *vlist, QString title,
m_vlist = vlist;
- m_proxyModel = new QSortFilterProxyModel(this);
+ m_proxyModel = new VersionSelectProxyModel(this);
m_proxyModel->setSourceModel(vlist);
ui->listView->setModel(m_proxyModel);
@@ -66,18 +128,41 @@ void VersionSelectDialog::setResizeOn(int column)
ui->listView->header()->setSectionResizeMode(resizeOnColumn, QHeaderView::Stretch);
}
+void VersionSelectDialog::setUseLatest(const bool useLatest)
+{
+ m_useLatest = useLatest;
+}
+
int VersionSelectDialog::exec()
{
QDialog::open();
if (!m_vlist->isLoaded())
+ {
loadList();
+ }
+ m_proxyModel->invalidate();
+ if (m_proxyModel->rowCount() == 0)
+ {
+ QLOG_DEBUG() << "No rows in version list";
+ return QDialog::Rejected;
+ }
+ if (m_proxyModel->rowCount() == 1 || m_useLatest)
+ {
+ ui->listView->selectionModel()->setCurrentIndex(m_proxyModel->index(0, 0),
+ QItemSelectionModel::ClearAndSelect);
+ return QDialog::Accepted;
+ }
return QDialog::exec();
}
void VersionSelectDialog::loadList()
{
- ProgressDialog *taskDlg = new ProgressDialog(this);
Task *loadTask = m_vlist->getLoadTask();
+ if (!loadTask)
+ {
+ return;
+ }
+ ProgressDialog *taskDlg = new ProgressDialog(this);
loadTask->setParent(taskDlg);
taskDlg->exec(loadTask);
delete taskDlg;
@@ -97,14 +182,12 @@ void VersionSelectDialog::on_refreshButton_clicked()
void VersionSelectDialog::setExactFilter(int column, QString filter)
{
- m_proxyModel->setFilterKeyColumn(column);
- // m_proxyModel->setFilterFixedString(filter);
- m_proxyModel->setFilterRegExp(QRegExp(QString("^%1$").arg(filter.replace(".", "\\.")),
- Qt::CaseInsensitive, QRegExp::RegExp));
+ m_proxyModel->setFilter(column, filter, true);
}
void VersionSelectDialog::setFuzzyFilter(int column, QString filter)
{
- m_proxyModel->setFilterKeyColumn(column);
- m_proxyModel->setFilterWildcard(filter);
+ m_proxyModel->setFilter(column, filter, false);
}
+
+#include "VersionSelectDialog.moc"
diff --git a/gui/dialogs/VersionSelectDialog.h b/gui/dialogs/VersionSelectDialog.h
index 34df4d23..70ee9635 100644
--- a/gui/dialogs/VersionSelectDialog.h
+++ b/gui/dialogs/VersionSelectDialog.h
@@ -27,6 +27,8 @@ namespace Ui
class VersionSelectDialog;
}
+class VersionSelectProxyModel;
+
class VersionSelectDialog : public QDialog
{
Q_OBJECT
@@ -47,6 +49,7 @@ public:
void setExactFilter(int column, QString filter);
void setEmptyString(QString emptyString);
void setResizeOn(int column);
+ void setUseLatest(const bool useLatest);
private
slots:
@@ -57,7 +60,8 @@ private:
BaseVersionList *m_vlist;
- QSortFilterProxyModel *m_proxyModel;
+ VersionSelectProxyModel *m_proxyModel;
int resizeOnColumn = 0;
+ bool m_useLatest;
};
diff --git a/gui/groupview/InstanceDelegate.cpp b/gui/groupview/InstanceDelegate.cpp
index e49e1552..a8e5ee83 100644
--- a/gui/groupview/InstanceDelegate.cpp
+++ b/gui/groupview/InstanceDelegate.cpp
@@ -118,6 +118,10 @@ void drawBadges(QPainter *painter, const QStyleOptionViewItemV4 &option, BaseIns
{
pixmaps.append("broken");
}
+ if (flags & BaseInstance::UpdateAvailable)
+ {
+ pixmaps.append("updateavailable");
+ }
// begin easter eggs
if (instance->name().contains("btw", Qt::CaseInsensitive) ||
diff --git a/logic/OneSixFTBInstance.cpp b/logic/OneSixFTBInstance.cpp
index 903c4437..2be74c3c 100644
--- a/logic/OneSixFTBInstance.cpp
+++ b/logic/OneSixFTBInstance.cpp
@@ -15,18 +15,6 @@ OneSixFTBInstance::OneSixFTBInstance(const QString &rootDir, SettingsObject *set
{
}
-void OneSixFTBInstance::init()
-{
- try
- {
- reloadVersion();
- }
- catch(MMCError & e)
- {
- // QLOG_ERROR() << "Caught exception on instance init: " << e.cause();
- }
-}
-
void OneSixFTBInstance::copy(const QDir &newDir)
{
QStringList libraryNames;
diff --git a/logic/OneSixFTBInstance.h b/logic/OneSixFTBInstance.h
index ecfa2231..1f9df8ab 100644
--- a/logic/OneSixFTBInstance.h
+++ b/logic/OneSixFTBInstance.h
@@ -12,7 +12,6 @@ public:
QObject *parent = 0);
virtual ~OneSixFTBInstance(){};
- void init() override;
void copy(const QDir &newDir) override;
virtual QString getStatusbarDescription();