Merge branch 'develop' of https://github.com/PrismLauncher/PrismLauncher into catpacks
This commit is contained in:
commit
0a956bbc73
8
.editorconfig
Normal file
8
.editorconfig
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# EditorConfig specs and documentation: https://EditorConfig.org
|
||||||
|
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# C++ Code Style settings
|
||||||
|
[*.{c++,cc,cpp,cppm,cxx,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}]
|
||||||
|
cpp_generate_documentation_comments = doxygen_slash_star
|
@ -85,6 +85,38 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTOML_ENABLE_FLOAT16=0")
|
|||||||
# set CXXFLAGS for build targets
|
# set CXXFLAGS for build targets
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -D_FORTIFY_SOURCE=2 ${CMAKE_CXX_FLAGS_RELEASE}")
|
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -D_FORTIFY_SOURCE=2 ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||||
|
|
||||||
|
option(DEBUG_ADDRESS_SANITIZER "Enable Address Sanitizer in Debug builds" on)
|
||||||
|
|
||||||
|
# If this is a Debug build turn on address sanitiser
|
||||||
|
if (CMAKE_BUILD_TYPE STREQUAL "Debug" AND DEBUG_ADDRESS_SANITIZER)
|
||||||
|
message(STATUS "Address Sanitizer enabled for Debug builds, Turn it off with -DDEBUG_ADDRESS_SANITIZER=off")
|
||||||
|
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||||
|
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
||||||
|
# using clang with clang-cl front end
|
||||||
|
message(STATUS "Address Sanitizer available on Clang MSVC frontend")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address /O1 /Oy-")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /O1 /Oy-")
|
||||||
|
else()
|
||||||
|
# AppleClang and Clang
|
||||||
|
message(STATUS "Address Sanitizer available on Clang")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -O1 -fno-omit-frame-pointer")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -O1 -fno-omit-frame-pointer")
|
||||||
|
endif()
|
||||||
|
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||||
|
# GCC
|
||||||
|
message(STATUS "Address Sanitizer available on GCC")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -O1 -fno-omit-frame-pointer")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -O1 -fno-omit-frame-pointer")
|
||||||
|
link_libraries("asan")
|
||||||
|
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||||
|
message(STATUS "Address Sanitizer available on MSVC")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address /O1 /Oy-")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /O1 /Oy-")
|
||||||
|
else()
|
||||||
|
message(STATUS "Address Sanitizer not available on compiler ${CMAKE_CXX_COMPILER_ID}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
option(ENABLE_LTO "Enable Link Time Optimization" off)
|
option(ENABLE_LTO "Enable Link Time Optimization" off)
|
||||||
|
|
||||||
if(ENABLE_LTO)
|
if(ENABLE_LTO)
|
||||||
@ -332,7 +364,7 @@ elseif(UNIX)
|
|||||||
|
|
||||||
set(BINARY_DEST_DIR "bin")
|
set(BINARY_DEST_DIR "bin")
|
||||||
set(LIBRARY_DEST_DIR "lib${LIB_SUFFIX}")
|
set(LIBRARY_DEST_DIR "lib${LIB_SUFFIX}")
|
||||||
set(JARS_DEST_DIR "share/${Launcher_APP_BINARY_NAME}")
|
set(JARS_DEST_DIR "share/${Launcher_Name}")
|
||||||
|
|
||||||
# install as bundle with no dependencies included
|
# install as bundle with no dependencies included
|
||||||
set(INSTALL_BUNDLE "nodeps")
|
set(INSTALL_BUNDLE "nodeps")
|
||||||
@ -345,7 +377,7 @@ elseif(UNIX)
|
|||||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_SVG} DESTINATION "${KDE_INSTALL_ICONDIR}/hicolor/scalable/apps")
|
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_SVG} DESTINATION "${KDE_INSTALL_ICONDIR}/hicolor/scalable/apps")
|
||||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_mrpack_MIMEInfo} DESTINATION ${KDE_INSTALL_MIMEDIR})
|
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_mrpack_MIMEInfo} DESTINATION ${KDE_INSTALL_MIMEDIR})
|
||||||
|
|
||||||
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/launcher/qtlogging.ini" DESTINATION "${KDE_INSTALL_DATADIR}/${Launcher_Name}")
|
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/launcher/qtlogging.ini" DESTINATION "share/${Launcher_Name}")
|
||||||
|
|
||||||
if(Launcher_ManPage)
|
if(Launcher_ManPage)
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_ManPage} DESTINATION "${KDE_INSTALL_MANDIR}/man6")
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_ManPage} DESTINATION "${KDE_INSTALL_MANDIR}/man6")
|
||||||
|
@ -433,7 +433,11 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
}
|
}
|
||||||
// seach root path
|
// seach root path
|
||||||
if(!foundLoggingRules) {
|
if(!foundLoggingRules) {
|
||||||
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
||||||
|
logRulesPath = FS::PathCombine(m_rootPath, "share", BuildConfig.LAUNCHER_NAME, logRulesFile);
|
||||||
|
#else
|
||||||
logRulesPath = FS::PathCombine(m_rootPath, logRulesFile);
|
logRulesPath = FS::PathCombine(m_rootPath, logRulesFile);
|
||||||
|
#endif
|
||||||
qDebug() << "Testing" << logRulesPath << "...";
|
qDebug() << "Testing" << logRulesPath << "...";
|
||||||
foundLoggingRules = QFile::exists(logRulesPath);
|
foundLoggingRules = QFile::exists(logRulesPath);
|
||||||
}
|
}
|
||||||
@ -568,6 +572,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
|
|
||||||
// Language
|
// Language
|
||||||
m_settings->registerSetting("Language", QString());
|
m_settings->registerSetting("Language", QString());
|
||||||
|
m_settings->registerSetting("UseSystemLocale", false);
|
||||||
|
|
||||||
// Console
|
// Console
|
||||||
m_settings->registerSetting("ShowConsole", false);
|
m_settings->registerSetting("ShowConsole", false);
|
||||||
@ -918,12 +923,7 @@ bool Application::createSetupWizard()
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}();
|
}();
|
||||||
bool languageRequired = [&]()
|
bool languageRequired = settings()->get("Language").toString().isEmpty();
|
||||||
{
|
|
||||||
if (settings()->get("Language").toString().isEmpty())
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}();
|
|
||||||
bool pasteInterventionRequired = settings()->get("PastebinURL") != "";
|
bool pasteInterventionRequired = settings()->get("PastebinURL") != "";
|
||||||
bool themeInterventionRequired = settings()->get("ApplicationTheme") == "";
|
bool themeInterventionRequired = settings()->get("ApplicationTheme") == "";
|
||||||
bool wizardRequired = javaRequired || languageRequired || pasteInterventionRequired || themeInterventionRequired;
|
bool wizardRequired = javaRequired || languageRequired || pasteInterventionRequired || themeInterventionRequired;
|
||||||
@ -1577,7 +1577,7 @@ QString Application::getJarPath(QString jarFile)
|
|||||||
{
|
{
|
||||||
QStringList potentialPaths = {
|
QStringList potentialPaths = {
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
||||||
FS::PathCombine(m_rootPath, "share/" + BuildConfig.LAUNCHER_APP_BINARY_NAME),
|
FS::PathCombine(m_rootPath, "share", BuildConfig.LAUNCHER_NAME),
|
||||||
#endif
|
#endif
|
||||||
FS::PathCombine(m_rootPath, "jars"),
|
FS::PathCombine(m_rootPath, "jars"),
|
||||||
FS::PathCombine(applicationDirPath(), "jars"),
|
FS::PathCombine(applicationDirPath(), "jars"),
|
||||||
|
@ -487,6 +487,9 @@ set(API_SOURCES
|
|||||||
modplatform/helpers/HashUtils.cpp
|
modplatform/helpers/HashUtils.cpp
|
||||||
modplatform/helpers/OverrideUtils.h
|
modplatform/helpers/OverrideUtils.h
|
||||||
modplatform/helpers/OverrideUtils.cpp
|
modplatform/helpers/OverrideUtils.cpp
|
||||||
|
|
||||||
|
modplatform/helpers/ExportToModList.h
|
||||||
|
modplatform/helpers/ExportToModList.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(FTB_SOURCES
|
set(FTB_SOURCES
|
||||||
@ -913,6 +916,8 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/dialogs/ExportInstanceDialog.h
|
ui/dialogs/ExportInstanceDialog.h
|
||||||
ui/dialogs/ExportPackDialog.cpp
|
ui/dialogs/ExportPackDialog.cpp
|
||||||
ui/dialogs/ExportPackDialog.h
|
ui/dialogs/ExportPackDialog.h
|
||||||
|
ui/dialogs/ExportToModListDialog.cpp
|
||||||
|
ui/dialogs/ExportToModListDialog.h
|
||||||
ui/dialogs/IconPickerDialog.cpp
|
ui/dialogs/IconPickerDialog.cpp
|
||||||
ui/dialogs/IconPickerDialog.h
|
ui/dialogs/IconPickerDialog.h
|
||||||
ui/dialogs/ImportResourceDialog.cpp
|
ui/dialogs/ImportResourceDialog.cpp
|
||||||
@ -1060,6 +1065,7 @@ qt_wrap_ui(LAUNCHER_UI
|
|||||||
ui/dialogs/SkinUploadDialog.ui
|
ui/dialogs/SkinUploadDialog.ui
|
||||||
ui/dialogs/ExportInstanceDialog.ui
|
ui/dialogs/ExportInstanceDialog.ui
|
||||||
ui/dialogs/ExportPackDialog.ui
|
ui/dialogs/ExportPackDialog.ui
|
||||||
|
ui/dialogs/ExportToModListDialog.ui
|
||||||
ui/dialogs/IconPickerDialog.ui
|
ui/dialogs/IconPickerDialog.ui
|
||||||
ui/dialogs/ImportResourceDialog.ui
|
ui/dialogs/ImportResourceDialog.ui
|
||||||
ui/dialogs/MSALoginDialog.ui
|
ui/dialogs/MSALoginDialog.ui
|
||||||
|
@ -778,9 +778,43 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
|
|||||||
destination = PathCombine(getDesktopDir(), RemoveInvalidFilenameChars(name));
|
destination = PathCombine(getDesktopDir(), RemoveInvalidFilenameChars(name));
|
||||||
}
|
}
|
||||||
#if defined(Q_OS_MACOS)
|
#if defined(Q_OS_MACOS)
|
||||||
destination += ".command";
|
// Create the Application
|
||||||
|
QDir applicationDirectory = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + "/" + BuildConfig.LAUNCHER_NAME + " Instances/";
|
||||||
|
|
||||||
QFile f(destination);
|
if (!applicationDirectory.mkpath(".")) {
|
||||||
|
qWarning() << "Couldn't create application directory";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDir application = applicationDirectory.path() + "/" + name + ".app/";
|
||||||
|
|
||||||
|
if (application.exists()) {
|
||||||
|
qWarning() << "Application already exists!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!application.mkpath(".")) {
|
||||||
|
qWarning() << "Couldn't create application";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDir content = application.path() + "/Contents/";
|
||||||
|
QDir resources = content.path() + "/Resources/";
|
||||||
|
QDir binaryDir = content.path() + "/MacOS/";
|
||||||
|
QFile info = content.path() + "/Info.plist";
|
||||||
|
|
||||||
|
if (!(content.mkpath(".") && resources.mkpath(".") && binaryDir.mkpath("."))) {
|
||||||
|
qWarning() << "Couldn't create directories within application";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
info.open(QIODevice::WriteOnly | QIODevice::Text);
|
||||||
|
|
||||||
|
QFile(icon).rename(resources.path() + "/Icon.icns");
|
||||||
|
|
||||||
|
// Create the Command file
|
||||||
|
QString exec = binaryDir.path() + "/Run.command";
|
||||||
|
|
||||||
|
QFile f(exec);
|
||||||
f.open(QIODevice::WriteOnly | QIODevice::Text);
|
f.open(QIODevice::WriteOnly | QIODevice::Text);
|
||||||
QTextStream stream(&f);
|
QTextStream stream(&f);
|
||||||
|
|
||||||
@ -797,6 +831,28 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
|
|||||||
|
|
||||||
f.setPermissions(f.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeGroup | QFileDevice::ExeOther);
|
f.setPermissions(f.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeGroup | QFileDevice::ExeOther);
|
||||||
|
|
||||||
|
// Generate the Info.plist
|
||||||
|
QTextStream infoStream(&info);
|
||||||
|
infoStream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?> \n"
|
||||||
|
"<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
|
||||||
|
"\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"
|
||||||
|
"<plist version=\"1.0\">\n"
|
||||||
|
"<dict>\n"
|
||||||
|
" <key>CFBundleExecutable</key>\n"
|
||||||
|
" <string>Run.command</string>\n" // The path to the executable
|
||||||
|
" <key>CFBundleIconFile</key>\n"
|
||||||
|
" <string>Icon.icns</string>\n"
|
||||||
|
" <key>CFBundleName</key>\n"
|
||||||
|
" <string>" << name << "</string>\n" // Name of the application
|
||||||
|
" <key>CFBundlePackageType</key>\n"
|
||||||
|
" <string>APPL</string>\n"
|
||||||
|
" <key>CFBundleShortVersionString</key>\n"
|
||||||
|
" <string>1.0</string>\n"
|
||||||
|
" <key>CFBundleVersion</key>\n"
|
||||||
|
" <string>1.0</string>\n"
|
||||||
|
"</dict>\n"
|
||||||
|
"</plist>";
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
||||||
if (!destination.endsWith(".desktop")) // in case of isFlatpak destination is already populated
|
if (!destination.endsWith(".desktop")) // in case of isFlatpak destination is already populated
|
||||||
|
@ -65,7 +65,8 @@
|
|||||||
static const QMap<QString, ResourceAPI::ModLoaderType> modloaderMapping{
|
static const QMap<QString, ResourceAPI::ModLoaderType> modloaderMapping{
|
||||||
{"net.minecraftforge", ResourceAPI::Forge},
|
{"net.minecraftforge", ResourceAPI::Forge},
|
||||||
{"net.fabricmc.fabric-loader", ResourceAPI::Fabric},
|
{"net.fabricmc.fabric-loader", ResourceAPI::Fabric},
|
||||||
{"org.quiltmc.quilt-loader", ResourceAPI::Quilt}
|
{"org.quiltmc.quilt-loader", ResourceAPI::Quilt},
|
||||||
|
{"com.mumfrey.liteloader", ResourceAPI::LiteLoader}
|
||||||
};
|
};
|
||||||
|
|
||||||
PackProfile::PackProfile(MinecraftInstance * instance)
|
PackProfile::PackProfile(MinecraftInstance * instance)
|
||||||
|
@ -126,7 +126,7 @@ bool Mod::applyFilter(QRegularExpression filter) const
|
|||||||
return Resource::applyFilter(filter);
|
return Resource::applyFilter(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mod::destroy(QDir& index_dir, bool preserve_metadata) -> bool
|
auto Mod::destroy(QDir& index_dir, bool preserve_metadata, bool attempt_trash) -> bool
|
||||||
{
|
{
|
||||||
if (!preserve_metadata) {
|
if (!preserve_metadata) {
|
||||||
qDebug() << QString("Destroying metadata for '%1' on purpose").arg(name());
|
qDebug() << QString("Destroying metadata for '%1' on purpose").arg(name());
|
||||||
@ -139,7 +139,7 @@ auto Mod::destroy(QDir& index_dir, bool preserve_metadata) -> bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Resource::destroy();
|
return Resource::destroy(attempt_trash);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mod::details() const -> const ModDetails&
|
auto Mod::details() const -> const ModDetails&
|
||||||
|
@ -93,7 +93,7 @@ public:
|
|||||||
[[nodiscard]] bool applyFilter(QRegularExpression filter) const override;
|
[[nodiscard]] bool applyFilter(QRegularExpression filter) const override;
|
||||||
|
|
||||||
// Delete all the files of this mod
|
// Delete all the files of this mod
|
||||||
auto destroy(QDir& index_dir, bool preserve_metadata = false) -> bool;
|
auto destroy(QDir& index_dir, bool preserve_metadata = false, bool attempt_trash = true) -> bool;
|
||||||
|
|
||||||
void finishResolvingWithDetails(ModDetails&& details);
|
void finishResolvingWithDetails(ModDetails&& details);
|
||||||
|
|
||||||
|
@ -199,10 +199,10 @@ Task* ModFolderModel::createParseTask(Resource& resource)
|
|||||||
|
|
||||||
bool ModFolderModel::uninstallMod(const QString& filename, bool preserve_metadata)
|
bool ModFolderModel::uninstallMod(const QString& filename, bool preserve_metadata)
|
||||||
{
|
{
|
||||||
for(auto mod : allMods()){
|
for(auto mod : allMods()) {
|
||||||
if(mod->fileinfo().fileName() == filename){
|
if(mod->fileinfo().fileName() == filename) {
|
||||||
auto index_dir = indexDir();
|
auto index_dir = indexDir();
|
||||||
mod->destroy(index_dir, preserve_metadata);
|
mod->destroy(index_dir, preserve_metadata, false);
|
||||||
|
|
||||||
update();
|
update();
|
||||||
|
|
||||||
|
@ -148,14 +148,10 @@ bool Resource::enable(EnableAction action)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Resource::destroy()
|
bool Resource::destroy(bool attemptTrash)
|
||||||
{
|
{
|
||||||
m_type = ResourceType::UNKNOWN;
|
m_type = ResourceType::UNKNOWN;
|
||||||
|
return (attemptTrash && FS::trash(m_file_info.filePath())) || FS::deletePath(m_file_info.filePath());
|
||||||
if (FS::trash(m_file_info.filePath()))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return FS::deletePath(m_file_info.filePath());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Resource::isSymLinkUnder(const QString& instPath) const
|
bool Resource::isSymLinkUnder(const QString& instPath) const
|
||||||
|
@ -92,7 +92,7 @@ class Resource : public QObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delete all files of this resource.
|
// Delete all files of this resource.
|
||||||
bool destroy();
|
bool destroy(bool attemptTrash = true);
|
||||||
|
|
||||||
[[nodiscard]] auto isSymLink() const -> bool { return m_file_info.isSymLink(); }
|
[[nodiscard]] auto isSymLink() const -> bool { return m_file_info.isSymLink(); }
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ bool ResourceFolderModel::uninstallResource(QString file_name)
|
|||||||
{
|
{
|
||||||
for (auto& resource : m_resources) {
|
for (auto& resource : m_resources) {
|
||||||
if (resource->fileinfo().fileName() == file_name) {
|
if (resource->fileinfo().fileName() == file_name) {
|
||||||
auto res = resource->destroy();
|
auto res = resource->destroy(false);
|
||||||
|
|
||||||
update();
|
update();
|
||||||
|
|
||||||
|
@ -44,7 +44,11 @@ static const QMap<PackedResourceType, QString> s_packed_type_names = {
|
|||||||
namespace ResourceUtils {
|
namespace ResourceUtils {
|
||||||
PackedResourceType identify(QFileInfo file){
|
PackedResourceType identify(QFileInfo file){
|
||||||
if (file.exists() && file.isFile()) {
|
if (file.exists() && file.isFile()) {
|
||||||
if (ResourcePackUtils::validate(file)) {
|
if (ModUtils::validate(file)) {
|
||||||
|
// mods can contain resource and data packs so they must be tested first
|
||||||
|
qDebug() << file.fileName() << "is a mod";
|
||||||
|
return PackedResourceType::Mod;
|
||||||
|
} else if (ResourcePackUtils::validate(file)) {
|
||||||
qDebug() << file.fileName() << "is a resource pack";
|
qDebug() << file.fileName() << "is a resource pack";
|
||||||
return PackedResourceType::ResourcePack;
|
return PackedResourceType::ResourcePack;
|
||||||
} else if (TexturePackUtils::validate(file)) {
|
} else if (TexturePackUtils::validate(file)) {
|
||||||
@ -53,9 +57,6 @@ PackedResourceType identify(QFileInfo file){
|
|||||||
} else if (DataPackUtils::validate(file)) {
|
} else if (DataPackUtils::validate(file)) {
|
||||||
qDebug() << file.fileName() << "is a data pack";
|
qDebug() << file.fileName() << "is a data pack";
|
||||||
return PackedResourceType::DataPack;
|
return PackedResourceType::DataPack;
|
||||||
} else if (ModUtils::validate(file)) {
|
|
||||||
qDebug() << file.fileName() << "is a mod";
|
|
||||||
return PackedResourceType::Mod;
|
|
||||||
} else if (WorldSaveUtils::validate(file)) {
|
} else if (WorldSaveUtils::validate(file)) {
|
||||||
qDebug() << file.fileName() << "is a world save";
|
qDebug() << file.fileName() << "is a world save";
|
||||||
return PackedResourceType::WorldSave;
|
return PackedResourceType::WorldSave;
|
||||||
|
@ -103,7 +103,7 @@ void ModFolderLoadTask::executeTask()
|
|||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
auto mod = iter.next().value();
|
auto mod = iter.next().value();
|
||||||
if (mod->status() == ModStatus::NotInstalled) {
|
if (mod->status() == ModStatus::NotInstalled) {
|
||||||
mod->destroy(m_index_dir, false);
|
mod->destroy(m_index_dir, false, false);
|
||||||
iter.remove();
|
iter.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,7 +145,8 @@ void EnsureMetadataTask::executeTask()
|
|||||||
connect(project_task.get(), &Task::finished, this, [=] {
|
connect(project_task.get(), &Task::finished, this, [=] {
|
||||||
invalidade_leftover();
|
invalidade_leftover();
|
||||||
project_task->deleteLater();
|
project_task->deleteLater();
|
||||||
m_current_task = nullptr;
|
if (m_current_task)
|
||||||
|
m_current_task.reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
m_current_task = project_task;
|
m_current_task = project_task;
|
||||||
@ -154,7 +155,8 @@ void EnsureMetadataTask::executeTask()
|
|||||||
|
|
||||||
connect(version_task.get(), &Task::finished, [=] {
|
connect(version_task.get(), &Task::finished, [=] {
|
||||||
version_task->deleteLater();
|
version_task->deleteLater();
|
||||||
m_current_task = nullptr;
|
if (m_current_task)
|
||||||
|
m_current_task.reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (m_mods.size() > 1)
|
if (m_mods.size() > 1)
|
||||||
|
@ -21,6 +21,10 @@ bool Flame::FileResolvingTask::abort()
|
|||||||
|
|
||||||
void Flame::FileResolvingTask::executeTask()
|
void Flame::FileResolvingTask::executeTask()
|
||||||
{
|
{
|
||||||
|
if (m_toProcess.files.isEmpty()) { // no file to resolve so leave it empty and emit success immediately
|
||||||
|
emitSucceeded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
setStatus(tr("Resolving mod IDs..."));
|
setStatus(tr("Resolving mod IDs..."));
|
||||||
setProgress(0, 3);
|
setProgress(0, 3);
|
||||||
m_dljob.reset(new NetJob("Mod id resolver", m_network));
|
m_dljob.reset(new NetJob("Mod id resolver", m_network));
|
||||||
@ -128,12 +132,13 @@ void Flame::FileResolvingTask::netJobFinished()
|
|||||||
m_checkJob->start();
|
m_checkJob->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Flame::FileResolvingTask::modrinthCheckFinished() {
|
void Flame::FileResolvingTask::modrinthCheckFinished()
|
||||||
|
{
|
||||||
setProgress(2, 3);
|
setProgress(2, 3);
|
||||||
qDebug() << "Finished with blocked mods : " << blockedProjects.size();
|
qDebug() << "Finished with blocked mods : " << blockedProjects.size();
|
||||||
|
|
||||||
for (auto it = blockedProjects.keyBegin(); it != blockedProjects.keyEnd(); it++) {
|
for (auto it = blockedProjects.keyBegin(); it != blockedProjects.keyEnd(); it++) {
|
||||||
auto &out = *it;
|
auto& out = *it;
|
||||||
auto bytes = blockedProjects[out];
|
auto bytes = blockedProjects[out];
|
||||||
if (!out->resolved) {
|
if (!out->resolved) {
|
||||||
continue;
|
continue;
|
||||||
@ -153,15 +158,13 @@ void Flame::FileResolvingTask::modrinthCheckFinished() {
|
|||||||
out->resolved = false;
|
out->resolved = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//copy to an output list and filter out projects found on modrinth
|
// copy to an output list and filter out projects found on modrinth
|
||||||
auto block = std::make_shared<QList<File*>>();
|
auto block = std::make_shared<QList<File*>>();
|
||||||
auto it = blockedProjects.keys();
|
auto it = blockedProjects.keys();
|
||||||
std::copy_if(it.begin(), it.end(), std::back_inserter(*block), [](File *f) {
|
std::copy_if(it.begin(), it.end(), std::back_inserter(*block), [](File* f) { return !f->resolved; });
|
||||||
return !f->resolved;
|
// Display not found mods early
|
||||||
});
|
|
||||||
//Display not found mods early
|
|
||||||
if (!block->empty()) {
|
if (!block->empty()) {
|
||||||
//blocked mods found, we need the slug for displaying.... we need another job :D !
|
// blocked mods found, we need the slug for displaying.... we need another job :D !
|
||||||
m_slugJob.reset(new NetJob("Slug Job", m_network));
|
m_slugJob.reset(new NetJob("Slug Job", m_network));
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (auto mod : *block) {
|
for (auto mod : *block) {
|
||||||
@ -173,8 +176,8 @@ void Flame::FileResolvingTask::modrinthCheckFinished() {
|
|||||||
QObject::connect(dl.get(), &Net::Download::succeeded, [block, index, output]() {
|
QObject::connect(dl.get(), &Net::Download::succeeded, [block, index, output]() {
|
||||||
auto mod = block->at(index); // use the shared_ptr so it is captured and only freed when we are done
|
auto mod = block->at(index); // use the shared_ptr so it is captured and only freed when we are done
|
||||||
auto json = QJsonDocument::fromJson(*output);
|
auto json = QJsonDocument::fromJson(*output);
|
||||||
auto base = Json::requireString(Json::requireObject(Json::requireObject(Json::requireObject(json),"data"),"links"),
|
auto base =
|
||||||
"websiteUrl");
|
Json::requireString(Json::requireObject(Json::requireObject(Json::requireObject(json), "data"), "links"), "websiteUrl");
|
||||||
auto link = QString("%1/download/%2").arg(base, QString::number(mod->fileId));
|
auto link = QString("%1/download/%2").arg(base, QString::number(mod->fileId));
|
||||||
mod->websiteUrl = link;
|
mod->websiteUrl = link;
|
||||||
});
|
});
|
||||||
|
@ -23,6 +23,8 @@ class FlameAPI : public NetworkResourceAPI {
|
|||||||
|
|
||||||
[[nodiscard]] auto getSortingMethods() const -> QList<ResourceAPI::SortingMethod> override;
|
[[nodiscard]] auto getSortingMethods() const -> QList<ResourceAPI::SortingMethod> override;
|
||||||
|
|
||||||
|
static inline auto validateModLoaders(ModLoaderTypes loaders) -> bool { return loaders & (Forge | Fabric | Quilt); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static int getClassId(ModPlatform::ResourceType type)
|
static int getClassId(ModPlatform::ResourceType type)
|
||||||
{
|
{
|
||||||
|
@ -563,6 +563,8 @@ void FlameCreationTask::validateZIPResouces()
|
|||||||
if (FS::move(localPath, destPath)) {
|
if (FS::move(localPath, destPath)) {
|
||||||
return destPath;
|
return destPath;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
qDebug() << "Target folder of" << fileName << "is correct at" << targetFolder;
|
||||||
}
|
}
|
||||||
return localPath;
|
return localPath;
|
||||||
};
|
};
|
||||||
@ -584,6 +586,9 @@ void FlameCreationTask::validateZIPResouces()
|
|||||||
QString worldPath;
|
QString worldPath;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case PackedResourceType::Mod :
|
||||||
|
validatePath(fileName, targetFolder, "mods");
|
||||||
|
break;
|
||||||
case PackedResourceType::ResourcePack :
|
case PackedResourceType::ResourcePack :
|
||||||
validatePath(fileName, targetFolder, "resourcepacks");
|
validatePath(fileName, targetFolder, "resourcepacks");
|
||||||
break;
|
break;
|
||||||
@ -593,9 +598,6 @@ void FlameCreationTask::validateZIPResouces()
|
|||||||
case PackedResourceType::DataPack :
|
case PackedResourceType::DataPack :
|
||||||
validatePath(fileName, targetFolder, "datapacks");
|
validatePath(fileName, targetFolder, "datapacks");
|
||||||
break;
|
break;
|
||||||
case PackedResourceType::Mod :
|
|
||||||
validatePath(fileName, targetFolder, "mods");
|
|
||||||
break;
|
|
||||||
case PackedResourceType::ShaderPack :
|
case PackedResourceType::ShaderPack :
|
||||||
// in theroy flame API can't do this but who knows, that *may* change ?
|
// in theroy flame API can't do this but who knows, that *may* change ?
|
||||||
// better to handle it if it *does* occure in the future
|
// better to handle it if it *does* occure in the future
|
||||||
|
@ -76,13 +76,8 @@ bool Flame::File::parseFromObject(const QJsonObject& obj, bool throw_on_blocked
|
|||||||
// It is also optional
|
// It is also optional
|
||||||
type = File::Type::SingleFile;
|
type = File::Type::SingleFile;
|
||||||
|
|
||||||
if (fileName.endsWith(".zip")) {
|
|
||||||
// this is probably a resource pack
|
|
||||||
targetFolder = "resourcepacks";
|
|
||||||
} else {
|
|
||||||
// this is probably a mod, dunno what else could modpacks download
|
|
||||||
targetFolder = "mods";
|
targetFolder = "mods";
|
||||||
}
|
|
||||||
// get the hash
|
// get the hash
|
||||||
hash = QString();
|
hash = QString();
|
||||||
auto hashes = Json::ensureArray(obj, "hashes");
|
auto hashes = Json::ensureArray(obj, "hashes");
|
||||||
|
200
launcher/modplatform/helpers/ExportToModList.cpp
Normal file
200
launcher/modplatform/helpers/ExportToModList.cpp
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "ExportToModList.h"
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
|
||||||
|
namespace ExportToModList {
|
||||||
|
QString toHTML(QList<Mod*> mods, OptionalData extraData)
|
||||||
|
{
|
||||||
|
QStringList lines;
|
||||||
|
for (auto mod : mods) {
|
||||||
|
auto meta = mod->metadata();
|
||||||
|
auto modName = mod->name().toHtmlEscaped();
|
||||||
|
if (extraData & Url) {
|
||||||
|
auto url = mod->metaurl().toHtmlEscaped();
|
||||||
|
if (!url.isEmpty())
|
||||||
|
modName = QString("<a href=\"%1\">%2</a>").arg(url, modName);
|
||||||
|
}
|
||||||
|
auto line = modName;
|
||||||
|
if (extraData & Version) {
|
||||||
|
auto ver = mod->version();
|
||||||
|
if (ver.isEmpty() && meta != nullptr)
|
||||||
|
ver = meta->version().toString();
|
||||||
|
if (!ver.isEmpty())
|
||||||
|
line += QString(" [%1]").arg(ver.toHtmlEscaped());
|
||||||
|
}
|
||||||
|
if (extraData & Authors && !mod->authors().isEmpty())
|
||||||
|
line += " by " + mod->authors().join(", ").toHtmlEscaped();
|
||||||
|
lines.append(QString("<li>%1</li>").arg(line));
|
||||||
|
}
|
||||||
|
return QString("<html><body><ul>\n\t%1\n</ul></body></html>").arg(lines.join("\n\t"));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString toMarkdown(QList<Mod*> mods, OptionalData extraData)
|
||||||
|
{
|
||||||
|
QStringList lines;
|
||||||
|
for (auto mod : mods) {
|
||||||
|
auto meta = mod->metadata();
|
||||||
|
auto modName = mod->name();
|
||||||
|
if (extraData & Url) {
|
||||||
|
auto url = mod->metaurl();
|
||||||
|
if (!url.isEmpty())
|
||||||
|
modName = QString("[%1](%2)").arg(modName, url);
|
||||||
|
}
|
||||||
|
auto line = modName;
|
||||||
|
if (extraData & Version) {
|
||||||
|
auto ver = mod->version();
|
||||||
|
if (ver.isEmpty() && meta != nullptr)
|
||||||
|
ver = meta->version().toString();
|
||||||
|
if (!ver.isEmpty())
|
||||||
|
line += QString(" [%1]").arg(ver);
|
||||||
|
}
|
||||||
|
if (extraData & Authors && !mod->authors().isEmpty())
|
||||||
|
line += " by " + mod->authors().join(", ");
|
||||||
|
lines << "- " + line;
|
||||||
|
}
|
||||||
|
return lines.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString toPlainTXT(QList<Mod*> mods, OptionalData extraData)
|
||||||
|
{
|
||||||
|
QStringList lines;
|
||||||
|
for (auto mod : mods) {
|
||||||
|
auto meta = mod->metadata();
|
||||||
|
auto modName = mod->name();
|
||||||
|
|
||||||
|
auto line = modName;
|
||||||
|
if (extraData & Url) {
|
||||||
|
auto url = mod->metaurl();
|
||||||
|
if (!url.isEmpty())
|
||||||
|
line += QString(" (%1)").arg(url);
|
||||||
|
}
|
||||||
|
if (extraData & Version) {
|
||||||
|
auto ver = mod->version();
|
||||||
|
if (ver.isEmpty() && meta != nullptr)
|
||||||
|
ver = meta->version().toString();
|
||||||
|
if (!ver.isEmpty())
|
||||||
|
line += QString(" [%1]").arg(ver);
|
||||||
|
}
|
||||||
|
if (extraData & Authors && !mod->authors().isEmpty())
|
||||||
|
line += " by " + mod->authors().join(", ");
|
||||||
|
lines << line;
|
||||||
|
}
|
||||||
|
return lines.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString toJSON(QList<Mod*> mods, OptionalData extraData)
|
||||||
|
{
|
||||||
|
QJsonArray lines;
|
||||||
|
for (auto mod : mods) {
|
||||||
|
auto meta = mod->metadata();
|
||||||
|
auto modName = mod->name();
|
||||||
|
QJsonObject line;
|
||||||
|
line["name"] = modName;
|
||||||
|
if (extraData & Url) {
|
||||||
|
auto url = mod->metaurl();
|
||||||
|
if (!url.isEmpty())
|
||||||
|
line["url"] = url;
|
||||||
|
}
|
||||||
|
if (extraData & Version) {
|
||||||
|
auto ver = mod->version();
|
||||||
|
if (ver.isEmpty() && meta != nullptr)
|
||||||
|
ver = meta->version().toString();
|
||||||
|
if (!ver.isEmpty())
|
||||||
|
line["version"] = ver;
|
||||||
|
}
|
||||||
|
if (extraData & Authors && !mod->authors().isEmpty())
|
||||||
|
line["authors"] = QJsonArray::fromStringList(mod->authors());
|
||||||
|
lines << line;
|
||||||
|
}
|
||||||
|
QJsonDocument doc;
|
||||||
|
doc.setArray(lines);
|
||||||
|
return doc.toJson();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString toCSV(QList<Mod*> mods, OptionalData extraData)
|
||||||
|
{
|
||||||
|
QStringList lines;
|
||||||
|
for (auto mod : mods) {
|
||||||
|
QStringList data;
|
||||||
|
auto meta = mod->metadata();
|
||||||
|
auto modName = mod->name();
|
||||||
|
|
||||||
|
data << modName;
|
||||||
|
if (extraData & Url)
|
||||||
|
data << mod->metaurl();
|
||||||
|
if (extraData & Version) {
|
||||||
|
auto ver = mod->version();
|
||||||
|
if (ver.isEmpty() && meta != nullptr)
|
||||||
|
ver = meta->version().toString();
|
||||||
|
data << ver;
|
||||||
|
}
|
||||||
|
if (extraData & Authors) {
|
||||||
|
QString authors;
|
||||||
|
if (mod->authors().length() == 1)
|
||||||
|
authors = mod->authors().back();
|
||||||
|
else if (mod->authors().length() > 1)
|
||||||
|
authors = QString("\"%1\"").arg(mod->authors().join(","));
|
||||||
|
data << authors;
|
||||||
|
}
|
||||||
|
lines << data.join(",");
|
||||||
|
}
|
||||||
|
return lines.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString exportToModList(QList<Mod*> mods, Formats format, OptionalData extraData)
|
||||||
|
{
|
||||||
|
switch (format) {
|
||||||
|
case HTML:
|
||||||
|
return toHTML(mods, extraData);
|
||||||
|
case MARKDOWN:
|
||||||
|
return toMarkdown(mods, extraData);
|
||||||
|
case PLAINTXT:
|
||||||
|
return toPlainTXT(mods, extraData);
|
||||||
|
case JSON:
|
||||||
|
return toJSON(mods, extraData);
|
||||||
|
case CSV:
|
||||||
|
return toCSV(mods, extraData);
|
||||||
|
default: {
|
||||||
|
return QString("unknown format:%1").arg(format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString exportToModList(QList<Mod*> mods, QString lineTemplate)
|
||||||
|
{
|
||||||
|
QStringList lines;
|
||||||
|
for (auto mod : mods) {
|
||||||
|
auto meta = mod->metadata();
|
||||||
|
auto modName = mod->name();
|
||||||
|
auto url = mod->metaurl();
|
||||||
|
auto ver = mod->version();
|
||||||
|
if (ver.isEmpty() && meta != nullptr)
|
||||||
|
ver = meta->version().toString();
|
||||||
|
auto authors = mod->authors().join(", ");
|
||||||
|
lines << QString(lineTemplate)
|
||||||
|
.replace("{name}", modName)
|
||||||
|
.replace("{url}", url)
|
||||||
|
.replace("{version}", ver)
|
||||||
|
.replace("{authors}", authors);
|
||||||
|
}
|
||||||
|
return lines.join("\n");
|
||||||
|
}
|
||||||
|
} // namespace ExportToModList
|
33
launcher/modplatform/helpers/ExportToModList.h
Normal file
33
launcher/modplatform/helpers/ExportToModList.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <QList>
|
||||||
|
#include <QString>
|
||||||
|
#include "minecraft/mod/Mod.h"
|
||||||
|
|
||||||
|
namespace ExportToModList {
|
||||||
|
|
||||||
|
enum Formats { HTML, MARKDOWN, PLAINTXT, JSON, CSV, CUSTOM };
|
||||||
|
enum OptionalData {
|
||||||
|
Authors = 1 << 0,
|
||||||
|
Url = 1 << 1,
|
||||||
|
Version = 1 << 2,
|
||||||
|
};
|
||||||
|
QString exportToModList(QList<Mod*> mods, Formats format, OptionalData extraData);
|
||||||
|
QString exportToModList(QList<Mod*> mods, QString lineTemplate);
|
||||||
|
} // namespace ExportToModList
|
@ -37,16 +37,16 @@
|
|||||||
|
|
||||||
#include <QtConcurrent>
|
#include <QtConcurrent>
|
||||||
|
|
||||||
#include "MMCZip.h"
|
|
||||||
#include "BaseInstance.h"
|
#include "BaseInstance.h"
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "settings/INISettingsObject.h"
|
#include "MMCZip.h"
|
||||||
|
#include "minecraft/GradleSpecifier.h"
|
||||||
#include "minecraft/MinecraftInstance.h"
|
#include "minecraft/MinecraftInstance.h"
|
||||||
#include "minecraft/PackProfile.h"
|
#include "minecraft/PackProfile.h"
|
||||||
#include "minecraft/GradleSpecifier.h"
|
#include "settings/INISettingsObject.h"
|
||||||
|
|
||||||
#include "BuildConfig.h"
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
#include "BuildConfig.h"
|
||||||
|
|
||||||
namespace LegacyFTB {
|
namespace LegacyFTB {
|
||||||
|
|
||||||
@ -65,6 +65,7 @@ void PackInstallTask::executeTask()
|
|||||||
void PackInstallTask::downloadPack()
|
void PackInstallTask::downloadPack()
|
||||||
{
|
{
|
||||||
setStatus(tr("Downloading zip for %1").arg(m_pack.name));
|
setStatus(tr("Downloading zip for %1").arg(m_pack.name));
|
||||||
|
setProgress(1, 4);
|
||||||
setAbortable(false);
|
setAbortable(false);
|
||||||
|
|
||||||
archivePath = QString("%1/%2/%3").arg(m_pack.dir, m_version.replace(".", "_"), m_pack.file);
|
archivePath = QString("%1/%2/%3").arg(m_pack.dir, m_version.replace(".", "_"), m_pack.file);
|
||||||
@ -78,11 +79,10 @@ void PackInstallTask::downloadPack()
|
|||||||
}
|
}
|
||||||
netJobContainer->addNetAction(Net::Download::makeFile(url, archivePath));
|
netJobContainer->addNetAction(Net::Download::makeFile(url, archivePath));
|
||||||
|
|
||||||
connect(netJobContainer.get(), &NetJob::succeeded, this, &PackInstallTask::onDownloadSucceeded);
|
connect(netJobContainer.get(), &NetJob::succeeded, this, &PackInstallTask::unzip);
|
||||||
connect(netJobContainer.get(), &NetJob::failed, this, &PackInstallTask::onDownloadFailed);
|
connect(netJobContainer.get(), &NetJob::failed, this, &PackInstallTask::emitFailed);
|
||||||
connect(netJobContainer.get(), &NetJob::progress, this, &PackInstallTask::onDownloadProgress);
|
|
||||||
connect(netJobContainer.get(), &NetJob::stepProgress, this, &PackInstallTask::propogateStepProgress);
|
connect(netJobContainer.get(), &NetJob::stepProgress, this, &PackInstallTask::propogateStepProgress);
|
||||||
connect(netJobContainer.get(), &NetJob::aborted, this, &PackInstallTask::onDownloadAborted);
|
connect(netJobContainer.get(), &NetJob::aborted, this, &PackInstallTask::emitAborted);
|
||||||
|
|
||||||
netJobContainer->start();
|
netJobContainer->start();
|
||||||
|
|
||||||
@ -90,27 +90,6 @@ void PackInstallTask::downloadPack()
|
|||||||
progress(1, 4);
|
progress(1, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PackInstallTask::onDownloadSucceeded()
|
|
||||||
{
|
|
||||||
unzip();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PackInstallTask::onDownloadFailed(QString reason)
|
|
||||||
{
|
|
||||||
emitFailed(reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PackInstallTask::onDownloadProgress(qint64 current, qint64 total)
|
|
||||||
{
|
|
||||||
progress(current, total * 4);
|
|
||||||
setStatus(tr("Downloading zip for %1 (%2%)").arg(m_pack.name).arg(current / 10));
|
|
||||||
}
|
|
||||||
|
|
||||||
void PackInstallTask::onDownloadAborted()
|
|
||||||
{
|
|
||||||
emitAborted();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PackInstallTask::unzip()
|
void PackInstallTask::unzip()
|
||||||
{
|
{
|
||||||
setStatus(tr("Extracting modpack"));
|
setStatus(tr("Extracting modpack"));
|
||||||
@ -120,16 +99,17 @@ void PackInstallTask::unzip()
|
|||||||
QDir extractDir(m_stagingPath);
|
QDir extractDir(m_stagingPath);
|
||||||
|
|
||||||
m_packZip.reset(new QuaZip(archivePath));
|
m_packZip.reset(new QuaZip(archivePath));
|
||||||
if(!m_packZip->open(QuaZip::mdUnzip))
|
if (!m_packZip->open(QuaZip::mdUnzip)) {
|
||||||
{
|
|
||||||
emitFailed(tr("Failed to open modpack file %1!").arg(archivePath));
|
emitFailed(tr("Failed to open modpack file %1!").arg(archivePath));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
m_extractFuture = QtConcurrent::run(QThreadPool::globalInstance(), QOverload<QString, QString>::of(MMCZip::extractDir), archivePath, extractDir.absolutePath() + "/unzip");
|
m_extractFuture = QtConcurrent::run(QThreadPool::globalInstance(), QOverload<QString, QString>::of(MMCZip::extractDir), archivePath,
|
||||||
|
extractDir.absolutePath() + "/unzip");
|
||||||
#else
|
#else
|
||||||
m_extractFuture = QtConcurrent::run(QThreadPool::globalInstance(), MMCZip::extractDir, archivePath, extractDir.absolutePath() + "/unzip");
|
m_extractFuture =
|
||||||
|
QtConcurrent::run(QThreadPool::globalInstance(), MMCZip::extractDir, archivePath, extractDir.absolutePath() + "/unzip");
|
||||||
#endif
|
#endif
|
||||||
connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::finished, this, &PackInstallTask::onUnzipFinished);
|
connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::finished, this, &PackInstallTask::onUnzipFinished);
|
||||||
connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::canceled, this, &PackInstallTask::onUnzipCanceled);
|
connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::canceled, this, &PackInstallTask::onUnzipCanceled);
|
||||||
@ -151,11 +131,9 @@ void PackInstallTask::install()
|
|||||||
setStatus(tr("Installing modpack"));
|
setStatus(tr("Installing modpack"));
|
||||||
progress(3, 4);
|
progress(3, 4);
|
||||||
QDir unzipMcDir(m_stagingPath + "/unzip/minecraft");
|
QDir unzipMcDir(m_stagingPath + "/unzip/minecraft");
|
||||||
if(unzipMcDir.exists())
|
if (unzipMcDir.exists()) {
|
||||||
{
|
// ok, found minecraft dir, move contents to instance dir
|
||||||
//ok, found minecraft dir, move contents to instance dir
|
if (!QDir().rename(m_stagingPath + "/unzip/minecraft", m_stagingPath + "/.minecraft")) {
|
||||||
if(!QDir().rename(m_stagingPath + "/unzip/minecraft", m_stagingPath + "/.minecraft"))
|
|
||||||
{
|
|
||||||
emitFailed(tr("Failed to move unzipped Minecraft!"));
|
emitFailed(tr("Failed to move unzipped Minecraft!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -172,23 +150,20 @@ void PackInstallTask::install()
|
|||||||
|
|
||||||
bool fallback = true;
|
bool fallback = true;
|
||||||
|
|
||||||
//handle different versions
|
// handle different versions
|
||||||
QFile packJson(m_stagingPath + "/.minecraft/pack.json");
|
QFile packJson(m_stagingPath + "/.minecraft/pack.json");
|
||||||
QDir jarmodDir = QDir(m_stagingPath + "/unzip/instMods");
|
QDir jarmodDir = QDir(m_stagingPath + "/unzip/instMods");
|
||||||
if(packJson.exists())
|
if (packJson.exists()) {
|
||||||
{
|
|
||||||
packJson.open(QIODevice::ReadOnly | QIODevice::Text);
|
packJson.open(QIODevice::ReadOnly | QIODevice::Text);
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(packJson.readAll());
|
QJsonDocument doc = QJsonDocument::fromJson(packJson.readAll());
|
||||||
packJson.close();
|
packJson.close();
|
||||||
|
|
||||||
//we only care about the libs
|
// we only care about the libs
|
||||||
QJsonArray libs = doc.object().value("libraries").toArray();
|
QJsonArray libs = doc.object().value("libraries").toArray();
|
||||||
|
|
||||||
foreach (const QJsonValue &value, libs)
|
foreach (const QJsonValue& value, libs) {
|
||||||
{
|
|
||||||
QString nameValue = value.toObject().value("name").toString();
|
QString nameValue = value.toObject().value("name").toString();
|
||||||
if(!nameValue.startsWith("net.minecraftforge"))
|
if (!nameValue.startsWith("net.minecraftforge")) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,16 +174,13 @@ void PackInstallTask::install()
|
|||||||
fallback = false;
|
fallback = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(jarmodDir.exists())
|
if (jarmodDir.exists()) {
|
||||||
{
|
|
||||||
qDebug() << "Found jarmods, installing...";
|
qDebug() << "Found jarmods, installing...";
|
||||||
|
|
||||||
QStringList jarmods;
|
QStringList jarmods;
|
||||||
for (auto info: jarmodDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files))
|
for (auto info : jarmodDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files)) {
|
||||||
{
|
|
||||||
qDebug() << "Jarmod:" << info.fileName();
|
qDebug() << "Jarmod:" << info.fileName();
|
||||||
jarmods.push_back(info.absoluteFilePath());
|
jarmods.push_back(info.absoluteFilePath());
|
||||||
}
|
}
|
||||||
@ -217,12 +189,11 @@ void PackInstallTask::install()
|
|||||||
fallback = false;
|
fallback = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//just nuke unzip directory, it s not needed anymore
|
// just nuke unzip directory, it s not needed anymore
|
||||||
FS::deletePath(m_stagingPath + "/unzip");
|
FS::deletePath(m_stagingPath + "/unzip");
|
||||||
|
|
||||||
if(fallback)
|
if (fallback) {
|
||||||
{
|
// TODO: Some fallback mechanism... or just keep failing!
|
||||||
//TODO: Some fallback mechanism... or just keep failing!
|
|
||||||
emitFailed(tr("No installation method found!"));
|
emitFailed(tr("No installation method found!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -232,8 +203,7 @@ void PackInstallTask::install()
|
|||||||
progress(4, 4);
|
progress(4, 4);
|
||||||
|
|
||||||
instance.setName(name());
|
instance.setName(name());
|
||||||
if(m_instIcon == "default")
|
if (m_instIcon == "default") {
|
||||||
{
|
|
||||||
m_instIcon = "ftb_logo";
|
m_instIcon = "ftb_logo";
|
||||||
}
|
}
|
||||||
instance.setIconKey(m_instIcon);
|
instance.setIconKey(m_instIcon);
|
||||||
@ -252,4 +222,4 @@ bool PackInstallTask::abort()
|
|||||||
return InstanceTask::abort();
|
return InstanceTask::abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace LegacyFTB
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "InstanceTask.h"
|
|
||||||
#include "net/NetJob.h"
|
|
||||||
#include <quazip/quazip.h>
|
#include <quazip/quazip.h>
|
||||||
#include <quazip/quazipdir.h>
|
#include <quazip/quazipdir.h>
|
||||||
|
#include "InstanceTask.h"
|
||||||
|
#include "PackHelpers.h"
|
||||||
#include "meta/Index.h"
|
#include "meta/Index.h"
|
||||||
#include "meta/Version.h"
|
#include "meta/Version.h"
|
||||||
#include "meta/VersionList.h"
|
#include "meta/VersionList.h"
|
||||||
#include "PackHelpers.h"
|
#include "net/NetJob.h"
|
||||||
|
|
||||||
#include "net/NetJob.h"
|
#include "net/NetJob.h"
|
||||||
|
|
||||||
@ -14,36 +14,31 @@
|
|||||||
|
|
||||||
namespace LegacyFTB {
|
namespace LegacyFTB {
|
||||||
|
|
||||||
class PackInstallTask : public InstanceTask
|
class PackInstallTask : public InstanceTask {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit PackInstallTask(shared_qobject_ptr<QNetworkAccessManager> network, Modpack pack, QString version);
|
explicit PackInstallTask(shared_qobject_ptr<QNetworkAccessManager> network, Modpack pack, QString version);
|
||||||
virtual ~PackInstallTask(){}
|
virtual ~PackInstallTask() {}
|
||||||
|
|
||||||
bool canAbort() const override { return true; }
|
bool canAbort() const override { return true; }
|
||||||
bool abort() override;
|
bool abort() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! Entry point for tasks.
|
//! Entry point for tasks.
|
||||||
virtual void executeTask() override;
|
virtual void executeTask() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void downloadPack();
|
void downloadPack();
|
||||||
void unzip();
|
void unzip();
|
||||||
void install();
|
void install();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onDownloadSucceeded();
|
|
||||||
void onDownloadFailed(QString reason);
|
|
||||||
void onDownloadProgress(qint64 current, qint64 total);
|
|
||||||
void onDownloadAborted();
|
|
||||||
|
|
||||||
void onUnzipFinished();
|
void onUnzipFinished();
|
||||||
void onUnzipCanceled();
|
void onUnzipCanceled();
|
||||||
|
|
||||||
private: /* data */
|
private: /* data */
|
||||||
shared_qobject_ptr<QNetworkAccessManager> m_network;
|
shared_qobject_ptr<QNetworkAccessManager> m_network;
|
||||||
bool abortable = false;
|
bool abortable = false;
|
||||||
std::unique_ptr<QuaZip> m_packZip;
|
std::unique_ptr<QuaZip> m_packZip;
|
||||||
@ -56,4 +51,4 @@ private: /* data */
|
|||||||
QString m_version;
|
QString m_version;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace LegacyFTB
|
||||||
|
@ -38,7 +38,7 @@ class ModrinthAPI : public NetworkResourceAPI {
|
|||||||
static auto getModLoaderStrings(const ModLoaderTypes types) -> const QStringList
|
static auto getModLoaderStrings(const ModLoaderTypes types) -> const QStringList
|
||||||
{
|
{
|
||||||
QStringList l;
|
QStringList l;
|
||||||
for (auto loader : { Forge, Fabric, Quilt }) {
|
for (auto loader : { Forge, Fabric, Quilt, LiteLoader }) {
|
||||||
if (types & loader) {
|
if (types & loader) {
|
||||||
l << getModLoaderString(loader);
|
l << getModLoaderString(loader);
|
||||||
}
|
}
|
||||||
@ -92,7 +92,7 @@ class ModrinthAPI : public NetworkResourceAPI {
|
|||||||
{
|
{
|
||||||
if (args.loaders.has_value()) {
|
if (args.loaders.has_value()) {
|
||||||
if (!validateModLoaders(args.loaders.value())) {
|
if (!validateModLoaders(args.loaders.value())) {
|
||||||
qWarning() << "Modrinth only have Forge and Fabric-compatible mods!";
|
qWarning() << "Modrinth - or our interface - does not support any the provided mod loaders!";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -141,7 +141,7 @@ class ModrinthAPI : public NetworkResourceAPI {
|
|||||||
return s.isEmpty() ? QString() : s;
|
return s.isEmpty() ? QString() : s;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto validateModLoaders(ModLoaderTypes loaders) const -> bool { return loaders & (Forge | Fabric | Quilt); }
|
static inline auto validateModLoaders(ModLoaderTypes loaders) -> bool { return loaders & (Forge | Fabric | Quilt | LiteLoader); }
|
||||||
|
|
||||||
[[nodiscard]] std::optional<QString> getDependencyURL(DependencySearchArgs const& args) const override
|
[[nodiscard]] std::optional<QString> getDependencyURL(DependencySearchArgs const& args) const override
|
||||||
{
|
{
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QLibraryInfo>
|
#include <QLibraryInfo>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <locale>
|
||||||
|
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "net/NetJob.h"
|
#include "net/NetJob.h"
|
||||||
@ -527,34 +528,34 @@ Language * TranslationsModel::findLanguage(const QString& key)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TranslationsModel::setUseSystemLocale(bool useSystemLocale)
|
||||||
|
{
|
||||||
|
APPLICATION->settings()->set("UseSystemLocale", useSystemLocale);
|
||||||
|
QLocale::setDefault(QLocale(useSystemLocale ? QString::fromStdString(std::locale().name()) : defaultLangCode));
|
||||||
|
}
|
||||||
|
|
||||||
bool TranslationsModel::selectLanguage(QString key)
|
bool TranslationsModel::selectLanguage(QString key)
|
||||||
{
|
{
|
||||||
QString &langCode = key;
|
QString& langCode = key;
|
||||||
auto langPtr = findLanguage(key);
|
auto langPtr = findLanguage(key);
|
||||||
|
|
||||||
if (langCode.isEmpty())
|
if (langCode.isEmpty()) {
|
||||||
{
|
|
||||||
d->no_language_set = true;
|
d->no_language_set = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!langPtr)
|
if (!langPtr) {
|
||||||
{
|
|
||||||
qWarning() << "Selected invalid language" << key << ", defaulting to" << defaultLangCode;
|
qWarning() << "Selected invalid language" << key << ", defaulting to" << defaultLangCode;
|
||||||
langCode = defaultLangCode;
|
langCode = defaultLangCode;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
langCode = langPtr->key;
|
langCode = langPtr->key;
|
||||||
}
|
}
|
||||||
|
|
||||||
// uninstall existing translators if there are any
|
// uninstall existing translators if there are any
|
||||||
if (d->m_app_translator)
|
if (d->m_app_translator) {
|
||||||
{
|
|
||||||
QCoreApplication::removeTranslator(d->m_app_translator.get());
|
QCoreApplication::removeTranslator(d->m_app_translator.get());
|
||||||
d->m_app_translator.reset();
|
d->m_app_translator.reset();
|
||||||
}
|
}
|
||||||
if (d->m_qt_translator)
|
if (d->m_qt_translator) {
|
||||||
{
|
|
||||||
QCoreApplication::removeTranslator(d->m_qt_translator.get());
|
QCoreApplication::removeTranslator(d->m_qt_translator.get());
|
||||||
d->m_qt_translator.reset();
|
d->m_qt_translator.reset();
|
||||||
}
|
}
|
||||||
@ -564,8 +565,9 @@ bool TranslationsModel::selectLanguage(QString key)
|
|||||||
* In a multithreaded application, the default locale should be set at application startup, before any non-GUI threads are created.
|
* In a multithreaded application, the default locale should be set at application startup, before any non-GUI threads are created.
|
||||||
* This function is not reentrant.
|
* This function is not reentrant.
|
||||||
*/
|
*/
|
||||||
QLocale locale = QLocale(langCode);
|
QLocale::setDefault(
|
||||||
QLocale::setDefault(locale);
|
QLocale(APPLICATION->settings()->get("UseSystemLocale").toBool() ? QString::fromStdString(std::locale().name()) : langCode));
|
||||||
|
|
||||||
|
|
||||||
// if it's the default UI language, finish
|
// if it's the default UI language, finish
|
||||||
if(langCode == defaultLangCode)
|
if(langCode == defaultLangCode)
|
||||||
|
@ -20,17 +20,16 @@
|
|||||||
|
|
||||||
struct Language;
|
struct Language;
|
||||||
|
|
||||||
class TranslationsModel : public QAbstractListModel
|
class TranslationsModel : public QAbstractListModel {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit TranslationsModel(QString path, QObject *parent = 0);
|
explicit TranslationsModel(QString path, QObject* parent = 0);
|
||||||
virtual ~TranslationsModel();
|
virtual ~TranslationsModel();
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||||
int columnCount(const QModelIndex & parent) const override;
|
int columnCount(const QModelIndex& parent) const override;
|
||||||
|
|
||||||
bool selectLanguage(QString key);
|
bool selectLanguage(QString key);
|
||||||
void updateLanguage(QString key);
|
void updateLanguage(QString key);
|
||||||
@ -38,27 +37,27 @@ public:
|
|||||||
QString selectedLanguage();
|
QString selectedLanguage();
|
||||||
|
|
||||||
void downloadIndex();
|
void downloadIndex();
|
||||||
|
void setUseSystemLocale(bool useSystemLocale);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Language *findLanguage(const QString & key);
|
Language* findLanguage(const QString& key);
|
||||||
void reloadLocalFiles();
|
void reloadLocalFiles();
|
||||||
void downloadTranslation(QString key);
|
void downloadTranslation(QString key);
|
||||||
void downloadNext();
|
void downloadNext();
|
||||||
|
|
||||||
// hide copy constructor
|
// hide copy constructor
|
||||||
TranslationsModel(const TranslationsModel &) = delete;
|
TranslationsModel(const TranslationsModel&) = delete;
|
||||||
// hide assign op
|
// hide assign op
|
||||||
TranslationsModel &operator=(const TranslationsModel &) = delete;
|
TranslationsModel& operator=(const TranslationsModel&) = delete;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void indexReceived();
|
void indexReceived();
|
||||||
void indexFailed(QString reason);
|
void indexFailed(QString reason);
|
||||||
void dlFailed(QString reason);
|
void dlFailed(QString reason);
|
||||||
void dlGood();
|
void dlGood();
|
||||||
void translationDirChanged(const QString &path);
|
void translationDirChanged(const QString& path);
|
||||||
|
|
||||||
|
private: /* data */
|
||||||
private: /* data */
|
|
||||||
struct Private;
|
struct Private;
|
||||||
std::unique_ptr<Private> d;
|
std::unique_ptr<Private> d;
|
||||||
};
|
};
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
|
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
|
#include "ui/dialogs/ExportToModListDialog.h"
|
||||||
#include "ui_MainWindow.h"
|
#include "ui_MainWindow.h"
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
@ -202,6 +203,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi
|
|||||||
exportInstanceMenu->addAction(ui->actionExportInstanceZip);
|
exportInstanceMenu->addAction(ui->actionExportInstanceZip);
|
||||||
exportInstanceMenu->addAction(ui->actionExportInstanceMrPack);
|
exportInstanceMenu->addAction(ui->actionExportInstanceMrPack);
|
||||||
exportInstanceMenu->addAction(ui->actionExportInstanceFlamePack);
|
exportInstanceMenu->addAction(ui->actionExportInstanceFlamePack);
|
||||||
|
exportInstanceMenu->addAction(ui->actionExportInstanceToModList);
|
||||||
ui->actionExportInstance->setMenu(exportInstanceMenu);
|
ui->actionExportInstance->setMenu(exportInstanceMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1186,7 +1188,17 @@ void MainWindow::globalSettingsClosed()
|
|||||||
|
|
||||||
void MainWindow::on_actionEditInstance_triggered()
|
void MainWindow::on_actionEditInstance_triggered()
|
||||||
{
|
{
|
||||||
|
if (!m_selectedInstance)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_selectedInstance->canEdit()) {
|
||||||
APPLICATION->showInstanceWindow(m_selectedInstance);
|
APPLICATION->showInstanceWindow(m_selectedInstance);
|
||||||
|
} else {
|
||||||
|
CustomMessageBox::selectable(this, tr("Instance not editable"),
|
||||||
|
tr("This instance is not editable. It may be broken, invalid, or too old. Check logs for details."),
|
||||||
|
QMessageBox::Critical)
|
||||||
|
->show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionManageAccounts_triggered()
|
void MainWindow::on_actionManageAccounts_triggered()
|
||||||
@ -1317,6 +1329,14 @@ void MainWindow::on_actionExportInstanceMrPack_triggered()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionExportInstanceToModList_triggered()
|
||||||
|
{
|
||||||
|
if (m_selectedInstance) {
|
||||||
|
ExportToModListDialog dlg(m_selectedInstance, this);
|
||||||
|
dlg.exec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionExportInstanceFlamePack_triggered()
|
void MainWindow::on_actionExportInstanceFlamePack_triggered()
|
||||||
{
|
{
|
||||||
if (m_selectedInstance) {
|
if (m_selectedInstance) {
|
||||||
@ -1435,11 +1455,36 @@ void MainWindow::on_actionCreateInstanceShortcut_triggered()
|
|||||||
QString iconPath;
|
QString iconPath;
|
||||||
QStringList args;
|
QStringList args;
|
||||||
#if defined(Q_OS_MACOS)
|
#if defined(Q_OS_MACOS)
|
||||||
|
appPath = QApplication::applicationFilePath();
|
||||||
if (appPath.startsWith("/private/var/")) {
|
if (appPath.startsWith("/private/var/")) {
|
||||||
QMessageBox::critical(this, tr("Create instance shortcut"),
|
QMessageBox::critical(this, tr("Create instance shortcut"),
|
||||||
tr("The launcher is in the folder it was extracted from, therefore it cannot create shortcuts."));
|
tr("The launcher is in the folder it was extracted from, therefore it cannot create shortcuts."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto pIcon = APPLICATION->icons()->icon(m_selectedInstance->iconKey());
|
||||||
|
if (pIcon == nullptr) {
|
||||||
|
pIcon = APPLICATION->icons()->icon("grass");
|
||||||
|
}
|
||||||
|
|
||||||
|
iconPath = FS::PathCombine(m_selectedInstance->instanceRoot(), "Icon.icns");
|
||||||
|
|
||||||
|
QFile iconFile(iconPath);
|
||||||
|
if (!iconFile.open(QFile::WriteOnly)) {
|
||||||
|
QMessageBox::critical(this, tr("Create instance Application"), tr("Failed to create icon for Application."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon icon = pIcon->icon();
|
||||||
|
|
||||||
|
bool success = icon.pixmap(1024, 1024).save(iconPath, "ICNS");
|
||||||
|
iconFile.close();
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
iconFile.remove();
|
||||||
|
QMessageBox::critical(this, tr("Create instance Application"), tr("Failed to create icon for Application."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
||||||
if (appPath.startsWith("/tmp/.mount_")) {
|
if (appPath.startsWith("/tmp/.mount_")) {
|
||||||
// AppImage!
|
// AppImage!
|
||||||
@ -1522,7 +1567,11 @@ void MainWindow::on_actionCreateInstanceShortcut_triggered()
|
|||||||
#endif
|
#endif
|
||||||
args.append({ "--launch", m_selectedInstance->id() });
|
args.append({ "--launch", m_selectedInstance->id() });
|
||||||
if (FS::createShortcut(desktopFilePath, appPath, args, m_selectedInstance->name(), iconPath)) {
|
if (FS::createShortcut(desktopFilePath, appPath, args, m_selectedInstance->name(), iconPath)) {
|
||||||
|
#if not defined(Q_OS_MACOS)
|
||||||
QMessageBox::information(this, tr("Create instance shortcut"), tr("Created a shortcut to this instance on your desktop!"));
|
QMessageBox::information(this, tr("Create instance shortcut"), tr("Created a shortcut to this instance on your desktop!"));
|
||||||
|
#else
|
||||||
|
QMessageBox::information(this, tr("Create instance shortcut"), tr("Created a shortcut to this instance!"));
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
#if not defined(Q_OS_MACOS)
|
#if not defined(Q_OS_MACOS)
|
||||||
iconFile.remove();
|
iconFile.remove();
|
||||||
|
@ -158,6 +158,7 @@ private slots:
|
|||||||
void on_actionExportInstanceZip_triggered();
|
void on_actionExportInstanceZip_triggered();
|
||||||
void on_actionExportInstanceMrPack_triggered();
|
void on_actionExportInstanceMrPack_triggered();
|
||||||
void on_actionExportInstanceFlamePack_triggered();
|
void on_actionExportInstanceFlamePack_triggered();
|
||||||
|
void on_actionExportInstanceToModList_triggered();
|
||||||
|
|
||||||
void on_actionRenameInstance_triggered();
|
void on_actionRenameInstance_triggered();
|
||||||
|
|
||||||
|
@ -487,6 +487,14 @@
|
|||||||
<string>CurseForge (zip)</string>
|
<string>CurseForge (zip)</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionExportInstanceToModList">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="new"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Mod List</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
<action name="actionCreateInstanceShortcut">
|
<action name="actionCreateInstanceShortcut">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset theme="shortcut">
|
<iconset theme="shortcut">
|
||||||
|
223
launcher/ui/dialogs/ExportToModListDialog.cpp
Normal file
223
launcher/ui/dialogs/ExportToModListDialog.cpp
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ExportToModListDialog.h"
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QTextEdit>
|
||||||
|
#include "FileSystem.h"
|
||||||
|
#include "Markdown.h"
|
||||||
|
#include "minecraft/MinecraftInstance.h"
|
||||||
|
#include "minecraft/mod/ModFolderModel.h"
|
||||||
|
#include "modplatform/helpers/ExportToModList.h"
|
||||||
|
#include "ui_ExportToModListDialog.h"
|
||||||
|
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QFileSystemModel>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
|
const QHash<ExportToModList::Formats, QString> ExportToModListDialog::exampleLines = {
|
||||||
|
{ ExportToModList::HTML, "<li><a href=\"{url}\">{name}</a> [{version}] by {authors}</li>" },
|
||||||
|
{ ExportToModList::MARKDOWN, "[{name}]({url}) [{version}] by {authors}" },
|
||||||
|
{ ExportToModList::PLAINTXT, "{name} ({url}) [{version}] by {authors}" },
|
||||||
|
{ ExportToModList::JSON, "{\"name\":\"{name}\",\"url\":\"{url}\",\"version\":\"{version}\",\"authors\":\"{authors}\"}," },
|
||||||
|
{ ExportToModList::CSV, "{name},{url},{version},\"{authors}\"" },
|
||||||
|
};
|
||||||
|
|
||||||
|
ExportToModListDialog::ExportToModListDialog(InstancePtr instance, QWidget* parent)
|
||||||
|
: QDialog(parent), m_template_changed(false), name(instance->name()), ui(new Ui::ExportToModListDialog)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
enableCustom(false);
|
||||||
|
|
||||||
|
MinecraftInstance* mcInstance = dynamic_cast<MinecraftInstance*>(instance.get());
|
||||||
|
if (mcInstance) {
|
||||||
|
mcInstance->loaderModList()->update();
|
||||||
|
connect(mcInstance->loaderModList().get(), &ModFolderModel::updateFinished, this, [this, mcInstance]() {
|
||||||
|
m_allMods = mcInstance->loaderModList()->allMods();
|
||||||
|
triggerImp();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(ui->formatComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ExportToModListDialog::formatChanged);
|
||||||
|
connect(ui->authorsCheckBox, &QCheckBox::stateChanged, this, &ExportToModListDialog::trigger);
|
||||||
|
connect(ui->versionCheckBox, &QCheckBox::stateChanged, this, &ExportToModListDialog::trigger);
|
||||||
|
connect(ui->urlCheckBox, &QCheckBox::stateChanged, this, &ExportToModListDialog::trigger);
|
||||||
|
connect(ui->authorsButton, &QPushButton::clicked, this, [this](bool) { addExtra(ExportToModList::Authors); });
|
||||||
|
connect(ui->versionButton, &QPushButton::clicked, this, [this](bool) { addExtra(ExportToModList::Version); });
|
||||||
|
connect(ui->urlButton, &QPushButton::clicked, this, [this](bool) { addExtra(ExportToModList::Url); });
|
||||||
|
connect(ui->templateText, &QTextEdit::textChanged, this, [this] {
|
||||||
|
if (ui->templateText->toPlainText() != exampleLines[format])
|
||||||
|
ui->formatComboBox->setCurrentIndex(5);
|
||||||
|
else
|
||||||
|
triggerImp();
|
||||||
|
});
|
||||||
|
connect(ui->copyButton, &QPushButton::clicked, this, [this](bool) {
|
||||||
|
this->ui->finalText->selectAll();
|
||||||
|
this->ui->finalText->copy();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ExportToModListDialog::~ExportToModListDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExportToModListDialog::formatChanged(int index)
|
||||||
|
{
|
||||||
|
switch (index) {
|
||||||
|
case 0: {
|
||||||
|
enableCustom(false);
|
||||||
|
ui->resultText->show();
|
||||||
|
format = ExportToModList::HTML;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1: {
|
||||||
|
enableCustom(false);
|
||||||
|
ui->resultText->show();
|
||||||
|
format = ExportToModList::MARKDOWN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
enableCustom(false);
|
||||||
|
ui->resultText->hide();
|
||||||
|
format = ExportToModList::PLAINTXT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
enableCustom(false);
|
||||||
|
ui->resultText->hide();
|
||||||
|
format = ExportToModList::JSON;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 4: {
|
||||||
|
enableCustom(false);
|
||||||
|
ui->resultText->hide();
|
||||||
|
format = ExportToModList::CSV;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 5: {
|
||||||
|
m_template_changed = true;
|
||||||
|
enableCustom(true);
|
||||||
|
ui->resultText->hide();
|
||||||
|
format = ExportToModList::CUSTOM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
triggerImp();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExportToModListDialog::triggerImp()
|
||||||
|
{
|
||||||
|
if (format == ExportToModList::CUSTOM) {
|
||||||
|
ui->finalText->setPlainText(ExportToModList::exportToModList(m_allMods, ui->templateText->toPlainText()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto opt = 0;
|
||||||
|
if (ui->authorsCheckBox->isChecked())
|
||||||
|
opt |= ExportToModList::Authors;
|
||||||
|
if (ui->versionCheckBox->isChecked())
|
||||||
|
opt |= ExportToModList::Version;
|
||||||
|
if (ui->urlCheckBox->isChecked())
|
||||||
|
opt |= ExportToModList::Url;
|
||||||
|
auto txt = ExportToModList::exportToModList(m_allMods, format, static_cast<ExportToModList::OptionalData>(opt));
|
||||||
|
ui->finalText->setPlainText(txt);
|
||||||
|
switch (format) {
|
||||||
|
case ExportToModList::CUSTOM:
|
||||||
|
return;
|
||||||
|
case ExportToModList::HTML:
|
||||||
|
ui->resultText->setHtml(txt);
|
||||||
|
break;
|
||||||
|
case ExportToModList::MARKDOWN:
|
||||||
|
ui->resultText->setHtml(markdownToHTML(txt));
|
||||||
|
break;
|
||||||
|
case ExportToModList::PLAINTXT:
|
||||||
|
break;
|
||||||
|
case ExportToModList::JSON:
|
||||||
|
break;
|
||||||
|
case ExportToModList::CSV:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
auto exampleLine = exampleLines[format];
|
||||||
|
if (!m_template_changed && ui->templateText->toPlainText() != exampleLine)
|
||||||
|
ui->templateText->setPlainText(exampleLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExportToModListDialog::done(int result)
|
||||||
|
{
|
||||||
|
if (result == Accepted) {
|
||||||
|
const QString filename = FS::RemoveInvalidFilenameChars(name);
|
||||||
|
const QString output =
|
||||||
|
QFileDialog::getSaveFileName(this, tr("Export %1").arg(name), FS::PathCombine(QDir::homePath(), filename + extension()),
|
||||||
|
"File (*.txt *.html *.md *.json *.csv)", nullptr);
|
||||||
|
|
||||||
|
if (output.isEmpty())
|
||||||
|
return;
|
||||||
|
FS::write(output, ui->finalText->toPlainText().toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
|
QDialog::done(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ExportToModListDialog::extension()
|
||||||
|
{
|
||||||
|
switch (format) {
|
||||||
|
case ExportToModList::HTML:
|
||||||
|
return ".html";
|
||||||
|
case ExportToModList::MARKDOWN:
|
||||||
|
return ".md";
|
||||||
|
case ExportToModList::PLAINTXT:
|
||||||
|
return ".txt";
|
||||||
|
case ExportToModList::CUSTOM:
|
||||||
|
return ".txt";
|
||||||
|
case ExportToModList::JSON:
|
||||||
|
return ".json";
|
||||||
|
case ExportToModList::CSV:
|
||||||
|
return ".csv";
|
||||||
|
}
|
||||||
|
return ".txt";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExportToModListDialog::addExtra(ExportToModList::OptionalData option)
|
||||||
|
{
|
||||||
|
if (format != ExportToModList::CUSTOM)
|
||||||
|
return;
|
||||||
|
switch (option) {
|
||||||
|
case ExportToModList::Authors:
|
||||||
|
ui->templateText->insertPlainText("{authors}");
|
||||||
|
break;
|
||||||
|
case ExportToModList::Url:
|
||||||
|
ui->templateText->insertPlainText("{url}");
|
||||||
|
break;
|
||||||
|
case ExportToModList::Version:
|
||||||
|
ui->templateText->insertPlainText("{version}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void ExportToModListDialog::enableCustom(bool enabled)
|
||||||
|
{
|
||||||
|
ui->authorsCheckBox->setHidden(enabled);
|
||||||
|
ui->versionCheckBox->setHidden(enabled);
|
||||||
|
ui->urlCheckBox->setHidden(enabled);
|
||||||
|
|
||||||
|
ui->authorsButton->setHidden(!enabled);
|
||||||
|
ui->versionButton->setHidden(!enabled);
|
||||||
|
ui->urlButton->setHidden(!enabled);
|
||||||
|
}
|
55
launcher/ui/dialogs/ExportToModListDialog.h
Normal file
55
launcher/ui/dialogs/ExportToModListDialog.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QList>
|
||||||
|
#include "BaseInstance.h"
|
||||||
|
#include "minecraft/mod/Mod.h"
|
||||||
|
#include "modplatform/helpers/ExportToModList.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class ExportToModListDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExportToModListDialog : public QDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ExportToModListDialog(InstancePtr instance, QWidget* parent = nullptr);
|
||||||
|
~ExportToModListDialog();
|
||||||
|
|
||||||
|
void done(int result) override;
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
void formatChanged(int index);
|
||||||
|
void triggerImp();
|
||||||
|
void trigger(int) { triggerImp(); };
|
||||||
|
void addExtra(ExportToModList::OptionalData option);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString extension();
|
||||||
|
void enableCustom(bool enabled);
|
||||||
|
QList<Mod*> m_allMods;
|
||||||
|
bool m_template_changed;
|
||||||
|
QString name;
|
||||||
|
ExportToModList::Formats format = ExportToModList::Formats::HTML;
|
||||||
|
Ui::ExportToModListDialog* ui;
|
||||||
|
static const QHash<ExportToModList::Formats, QString> exampleLines;
|
||||||
|
};
|
240
launcher/ui/dialogs/ExportToModListDialog.ui
Normal file
240
launcher/ui/dialogs/ExportToModListDialog.ui
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>ExportToModListDialog</class>
|
||||||
|
<widget class="QDialog" name="ExportToModListDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>650</width>
|
||||||
|
<height>446</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Export Pack to ModList</string>
|
||||||
|
</property>
|
||||||
|
<property name="sizeGripEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_3">
|
||||||
|
<property name="title">
|
||||||
|
<string>Settings</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QComboBox" name="formatComboBox">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>HTML</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Markdown</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Plaintext</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>JSON</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>CSV</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Custom</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QGroupBox" name="templateGroup">
|
||||||
|
<property name="title">
|
||||||
|
<string>Template</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="templateText"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QGroupBox" name="optionsGroup">
|
||||||
|
<property name="title">
|
||||||
|
<string>Optional Info</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="versionCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Version</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="authorsCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Authors</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="urlCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>URL</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="versionButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Version</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="authorsButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Authors</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="urlButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>URL</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Plain</enum>
|
||||||
|
</property>
|
||||||
|
<property name="lineWidth">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Format</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_4">
|
||||||
|
<property name="title">
|
||||||
|
<string>Result</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPlainTextEdit" name="finalText">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>143</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextBrowser" name="resultText">
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="warningLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>This depends on the mods' metadata. To ensure it is available, run an update on the instance. Installing the updates isn't necessary.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="copyButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Copy</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>ExportToModListDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>334</x>
|
||||||
|
<y>435</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>324</x>
|
||||||
|
<y>206</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>ExportToModListDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>324</x>
|
||||||
|
<y>390</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>324</x>
|
||||||
|
<y>206</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
@ -43,6 +43,8 @@
|
|||||||
#include "ui/pages/modplatform/flame/FlameResourcePages.h"
|
#include "ui/pages/modplatform/flame/FlameResourcePages.h"
|
||||||
#include "ui/pages/modplatform/modrinth/ModrinthResourcePages.h"
|
#include "ui/pages/modplatform/modrinth/ModrinthResourcePages.h"
|
||||||
|
|
||||||
|
#include "modplatform/flame/FlameAPI.h"
|
||||||
|
#include "modplatform/modrinth/ModrinthAPI.h"
|
||||||
#include "ui/widgets/PageContainer.h"
|
#include "ui/widgets/PageContainer.h"
|
||||||
|
|
||||||
namespace ResourceDownload {
|
namespace ResourceDownload {
|
||||||
@ -281,8 +283,11 @@ QList<BasePage*> ModDownloadDialog::getPages()
|
|||||||
{
|
{
|
||||||
QList<BasePage*> pages;
|
QList<BasePage*> pages;
|
||||||
|
|
||||||
|
auto loaders = static_cast<MinecraftInstance*>(m_instance)->getPackProfile()->getModLoaders().value();
|
||||||
|
|
||||||
|
if (ModrinthAPI::validateModLoaders(loaders))
|
||||||
pages.append(ModrinthModPage::create(this, *m_instance));
|
pages.append(ModrinthModPage::create(this, *m_instance));
|
||||||
if (APPLICATION->capabilities() & Application::SupportsFlame)
|
if (APPLICATION->capabilities() & Application::SupportsFlame && FlameAPI::validateModLoaders(loaders))
|
||||||
pages.append(FlameModPage::create(this, *m_instance));
|
pages.append(FlameModPage::create(this, *m_instance));
|
||||||
|
|
||||||
m_selectedPage = dynamic_cast<ModPage*>(pages[0]);
|
m_selectedPage = dynamic_cast<ModPage*>(pages[0]);
|
||||||
|
@ -69,7 +69,6 @@ class NoBigComboBoxStyle : public QProxyStyle {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
NoBigComboBoxStyle(QStyle* style) : QProxyStyle(style) {}
|
NoBigComboBoxStyle(QStyle* style) : QProxyStyle(style) {}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ManagedPackPage* ManagedPackPage::createPage(BaseInstance* inst, QString type, QWidget* parent)
|
ManagedPackPage* ManagedPackPage::createPage(BaseInstance* inst, QString type, QWidget* parent)
|
||||||
@ -91,13 +90,13 @@ ManagedPackPage::ManagedPackPage(BaseInstance* inst, InstanceWindow* instance_wi
|
|||||||
|
|
||||||
// NOTE: GTK2 themes crash with the proxy style.
|
// NOTE: GTK2 themes crash with the proxy style.
|
||||||
// This seems like an upstream bug, so there's not much else that can be done.
|
// This seems like an upstream bug, so there's not much else that can be done.
|
||||||
if (!QStyleFactory::keys().contains("gtk2")){
|
if (!QStyleFactory::keys().contains("gtk2")) {
|
||||||
auto comboStyle = NoBigComboBoxStyle::getInstance(ui->versionsComboBox->style());
|
auto comboStyle = NoBigComboBoxStyle::getInstance(ui->versionsComboBox->style());
|
||||||
ui->versionsComboBox->setStyle(comboStyle);
|
ui->versionsComboBox->setStyle(comboStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->reloadButton->setVisible(false);
|
ui->reloadButton->setVisible(false);
|
||||||
connect(ui->reloadButton, &QPushButton::clicked, this, [this](bool){
|
connect(ui->reloadButton, &QPushButton::clicked, this, [this](bool) {
|
||||||
ui->reloadButton->setVisible(false);
|
ui->reloadButton->setVisible(false);
|
||||||
|
|
||||||
m_loaded = false;
|
m_loaded = false;
|
||||||
@ -226,7 +225,8 @@ void ModrinthManagedPackPage::parseManagedPack()
|
|||||||
|
|
||||||
QString id = m_inst->getManagedPackID();
|
QString id = m_inst->getManagedPackID();
|
||||||
|
|
||||||
m_fetch_job->addNetAction(Net::Download::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_PROD_URL, id), response));
|
m_fetch_job->addNetAction(
|
||||||
|
Net::Download::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_PROD_URL, id), response));
|
||||||
|
|
||||||
QObject::connect(m_fetch_job.get(), &NetJob::succeeded, this, [this, response, id] {
|
QObject::connect(m_fetch_job.get(), &NetJob::succeeded, this, [this, response, id] {
|
||||||
QJsonParseError parse_error{};
|
QJsonParseError parse_error{};
|
||||||
@ -267,7 +267,6 @@ void ModrinthManagedPackPage::parseManagedPack()
|
|||||||
if (version.version == m_inst->getManagedPackVersionName())
|
if (version.version == m_inst->getManagedPackVersionName())
|
||||||
name = tr("%1 (Current)").arg(name);
|
name = tr("%1 (Current)").arg(name);
|
||||||
|
|
||||||
|
|
||||||
ui->versionsComboBox->addItem(name, QVariant(version.id));
|
ui->versionsComboBox->addItem(name, QVariant(version.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,6 +290,10 @@ QString ModrinthManagedPackPage::url() const
|
|||||||
void ModrinthManagedPackPage::suggestVersion()
|
void ModrinthManagedPackPage::suggestVersion()
|
||||||
{
|
{
|
||||||
auto index = ui->versionsComboBox->currentIndex();
|
auto index = ui->versionsComboBox->currentIndex();
|
||||||
|
if (m_pack.versions.length() == 0) {
|
||||||
|
setFailState();
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto version = m_pack.versions.at(index);
|
auto version = m_pack.versions.at(index);
|
||||||
|
|
||||||
ui->changelogTextBrowser->setHtml(markdownToHTML(version.changelog.toUtf8()));
|
ui->changelogTextBrowser->setHtml(markdownToHTML(version.changelog.toUtf8()));
|
||||||
@ -301,6 +304,10 @@ void ModrinthManagedPackPage::suggestVersion()
|
|||||||
void ModrinthManagedPackPage::update()
|
void ModrinthManagedPackPage::update()
|
||||||
{
|
{
|
||||||
auto index = ui->versionsComboBox->currentIndex();
|
auto index = ui->versionsComboBox->currentIndex();
|
||||||
|
if (m_pack.versions.length() == 0) {
|
||||||
|
setFailState();
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto version = m_pack.versions.at(index);
|
auto version = m_pack.versions.at(index);
|
||||||
|
|
||||||
QMap<QString, QString> extra_info;
|
QMap<QString, QString> extra_info;
|
||||||
@ -429,6 +436,10 @@ QString FlameManagedPackPage::url() const
|
|||||||
void FlameManagedPackPage::suggestVersion()
|
void FlameManagedPackPage::suggestVersion()
|
||||||
{
|
{
|
||||||
auto index = ui->versionsComboBox->currentIndex();
|
auto index = ui->versionsComboBox->currentIndex();
|
||||||
|
if (m_pack.versions.length() == 0) {
|
||||||
|
setFailState();
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto version = m_pack.versions.at(index);
|
auto version = m_pack.versions.at(index);
|
||||||
|
|
||||||
ui->changelogTextBrowser->setHtml(m_api.getModFileChangelog(m_inst->getManagedPackID().toInt(), version.fileId));
|
ui->changelogTextBrowser->setHtml(m_api.getModFileChangelog(m_inst->getManagedPackID().toInt(), version.fileId));
|
||||||
@ -439,6 +450,10 @@ void FlameManagedPackPage::suggestVersion()
|
|||||||
void FlameManagedPackPage::update()
|
void FlameManagedPackPage::update()
|
||||||
{
|
{
|
||||||
auto index = ui->versionsComboBox->currentIndex();
|
auto index = ui->versionsComboBox->currentIndex();
|
||||||
|
if (m_pack.versions.length() == 0) {
|
||||||
|
setFailState();
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto version = m_pack.versions.at(index);
|
auto version = m_pack.versions.at(index);
|
||||||
|
|
||||||
QMap<QString, QString> extra_info;
|
QMap<QString, QString> extra_info;
|
||||||
|
@ -104,6 +104,7 @@ void ResourcePage::openedImpl()
|
|||||||
|
|
||||||
updateSelectionButton();
|
updateSelectionButton();
|
||||||
triggerSearch();
|
triggerSearch();
|
||||||
|
m_ui->searchEdit->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ResourcePage::eventFilter(QObject* watched, QEvent* event) -> bool
|
auto ResourcePage::eventFilter(QObject* watched, QEvent* event) -> bool
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
#include "LanguageSelectionWidget.h"
|
#include "LanguageSelectionWidget.h"
|
||||||
|
|
||||||
#include <QVBoxLayout>
|
#include <QCheckBox>
|
||||||
#include <QTreeView>
|
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
#include <QTreeView>
|
||||||
|
#include <QVBoxLayout>
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
#include "translations/TranslationsModel.h"
|
|
||||||
#include "settings/Setting.h"
|
#include "settings/Setting.h"
|
||||||
|
#include "translations/TranslationsModel.h"
|
||||||
|
|
||||||
LanguageSelectionWidget::LanguageSelectionWidget(QWidget *parent) :
|
LanguageSelectionWidget::LanguageSelectionWidget(QWidget* parent) : QWidget(parent)
|
||||||
QWidget(parent)
|
|
||||||
{
|
{
|
||||||
verticalLayout = new QVBoxLayout(this);
|
verticalLayout = new QVBoxLayout(this);
|
||||||
verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
|
verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
|
||||||
@ -31,6 +31,13 @@ LanguageSelectionWidget::LanguageSelectionWidget(QWidget *parent) :
|
|||||||
helpUsLabel->setWordWrap(true);
|
helpUsLabel->setWordWrap(true);
|
||||||
verticalLayout->addWidget(helpUsLabel);
|
verticalLayout->addWidget(helpUsLabel);
|
||||||
|
|
||||||
|
formatCheckbox = new QCheckBox(this);
|
||||||
|
formatCheckbox->setObjectName(QStringLiteral("formatCheckbox"));
|
||||||
|
formatCheckbox->setCheckState(APPLICATION->settings()->get("UseSystemLocale").toBool() ? Qt::Checked : Qt::Unchecked);
|
||||||
|
connect(formatCheckbox, &QCheckBox::stateChanged,
|
||||||
|
[this]() { APPLICATION->translations()->setUseSystemLocale(formatCheckbox->isChecked()); });
|
||||||
|
verticalLayout->addWidget(formatCheckbox);
|
||||||
|
|
||||||
auto translations = APPLICATION->translations();
|
auto translations = APPLICATION->translations();
|
||||||
auto index = translations->selectedIndex();
|
auto index = translations->selectedIndex();
|
||||||
languageView->setModel(translations.get());
|
languageView->setModel(translations.get());
|
||||||
@ -38,7 +45,7 @@ LanguageSelectionWidget::LanguageSelectionWidget(QWidget *parent) :
|
|||||||
languageView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
languageView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||||
languageView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
|
languageView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||||
connect(languageView->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &LanguageSelectionWidget::languageRowChanged);
|
connect(languageView->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &LanguageSelectionWidget::languageRowChanged);
|
||||||
verticalLayout->setContentsMargins(0,0,0,0);
|
verticalLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
auto language_setting = APPLICATION->settings()->getSetting("Language");
|
auto language_setting = APPLICATION->settings()->getSetting("Language");
|
||||||
connect(language_setting.get(), &Setting::SettingChanged, this, &LanguageSelectionWidget::languageSettingChanged);
|
connect(language_setting.get(), &Setting::SettingChanged, this, &LanguageSelectionWidget::languageSettingChanged);
|
||||||
@ -55,13 +62,12 @@ void LanguageSelectionWidget::retranslate()
|
|||||||
QString text = tr("Don't see your language or the quality is poor?<br/><a href=\"%1\">Help us with translations!</a>")
|
QString text = tr("Don't see your language or the quality is poor?<br/><a href=\"%1\">Help us with translations!</a>")
|
||||||
.arg(BuildConfig.TRANSLATIONS_URL);
|
.arg(BuildConfig.TRANSLATIONS_URL);
|
||||||
helpUsLabel->setText(text);
|
helpUsLabel->setText(text);
|
||||||
|
formatCheckbox->setText(tr("Use system locales"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LanguageSelectionWidget::languageRowChanged(const QModelIndex& current, const QModelIndex& previous)
|
void LanguageSelectionWidget::languageRowChanged(const QModelIndex& current, const QModelIndex& previous)
|
||||||
{
|
{
|
||||||
if (current == previous)
|
if (current == previous) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto translations = APPLICATION->translations();
|
auto translations = APPLICATION->translations();
|
||||||
@ -70,7 +76,7 @@ void LanguageSelectionWidget::languageRowChanged(const QModelIndex& current, con
|
|||||||
translations->updateLanguage(key);
|
translations->updateLanguage(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LanguageSelectionWidget::languageSettingChanged(const Setting &, const QVariant)
|
void LanguageSelectionWidget::languageSettingChanged(const Setting&, const QVariant)
|
||||||
{
|
{
|
||||||
auto translations = APPLICATION->translations();
|
auto translations = APPLICATION->translations();
|
||||||
auto index = translations->selectedIndex();
|
auto index = translations->selectedIndex();
|
||||||
|
@ -21,23 +21,24 @@ class QVBoxLayout;
|
|||||||
class QTreeView;
|
class QTreeView;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class Setting;
|
class Setting;
|
||||||
|
class QCheckBox;
|
||||||
|
|
||||||
class LanguageSelectionWidget: public QWidget
|
class LanguageSelectionWidget : public QWidget {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit LanguageSelectionWidget(QWidget *parent = 0);
|
explicit LanguageSelectionWidget(QWidget* parent = 0);
|
||||||
virtual ~LanguageSelectionWidget() { };
|
virtual ~LanguageSelectionWidget(){};
|
||||||
|
|
||||||
QString getSelectedLanguageKey() const;
|
QString getSelectedLanguageKey() const;
|
||||||
void retranslate();
|
void retranslate();
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void languageRowChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
void languageRowChanged(const QModelIndex& current, const QModelIndex& previous);
|
||||||
void languageSettingChanged(const Setting &, const QVariant);
|
void languageSettingChanged(const Setting&, const QVariant);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVBoxLayout *verticalLayout = nullptr;
|
QVBoxLayout* verticalLayout = nullptr;
|
||||||
QTreeView *languageView = nullptr;
|
QTreeView* languageView = nullptr;
|
||||||
QLabel *helpUsLabel = nullptr;
|
QLabel* helpUsLabel = nullptr;
|
||||||
|
QCheckBox* formatCheckbox = nullptr;
|
||||||
};
|
};
|
||||||
|
@ -42,6 +42,10 @@ class LinkTask : public Task {
|
|||||||
m_lnk->debug(true);
|
m_lnk->debug(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~LinkTask() {
|
||||||
|
delete m_lnk;
|
||||||
|
}
|
||||||
|
|
||||||
void matcher(const IPathMatcher *filter)
|
void matcher(const IPathMatcher *filter)
|
||||||
{
|
{
|
||||||
m_lnk->matcher(filter);
|
m_lnk->matcher(filter);
|
||||||
@ -219,7 +223,8 @@ slots:
|
|||||||
qDebug() << tempDir.path();
|
qDebug() << tempDir.path();
|
||||||
qDebug() << target_dir.path();
|
qDebug() << target_dir.path();
|
||||||
FS::copy c(folder, target_dir.path());
|
FS::copy c(folder, target_dir.path());
|
||||||
c.matcher(new RegexpMatcher("[.]?mcmeta"));
|
RegexpMatcher re("[.]?mcmeta");
|
||||||
|
c.matcher(&re);
|
||||||
c();
|
c();
|
||||||
|
|
||||||
for(auto entry: target_dir.entryList())
|
for(auto entry: target_dir.entryList())
|
||||||
@ -253,7 +258,8 @@ slots:
|
|||||||
qDebug() << tempDir.path();
|
qDebug() << tempDir.path();
|
||||||
qDebug() << target_dir.path();
|
qDebug() << target_dir.path();
|
||||||
FS::copy c(folder, target_dir.path());
|
FS::copy c(folder, target_dir.path());
|
||||||
c.matcher(new RegexpMatcher("[.]?mcmeta"));
|
RegexpMatcher re("[.]?mcmeta");
|
||||||
|
c.matcher(&re);
|
||||||
c.whitelist(true);
|
c.whitelist(true);
|
||||||
c();
|
c();
|
||||||
|
|
||||||
@ -460,7 +466,8 @@ slots:
|
|||||||
qDebug() << target_dir.path();
|
qDebug() << target_dir.path();
|
||||||
|
|
||||||
LinkTask lnk_tsk(folder, target_dir.path());
|
LinkTask lnk_tsk(folder, target_dir.path());
|
||||||
lnk_tsk.matcher(new RegexpMatcher("[.]?mcmeta"));
|
RegexpMatcher re("[.]?mcmeta");
|
||||||
|
lnk_tsk.matcher(&re);
|
||||||
lnk_tsk.linkRecursively(true);
|
lnk_tsk.linkRecursively(true);
|
||||||
QObject::connect(&lnk_tsk, &Task::finished, [&]{
|
QObject::connect(&lnk_tsk, &Task::finished, [&]{
|
||||||
QVERIFY2(lnk_tsk.wasSuccessful(), "Task finished but was not successful when it should have been.");
|
QVERIFY2(lnk_tsk.wasSuccessful(), "Task finished but was not successful when it should have been.");
|
||||||
@ -511,7 +518,8 @@ slots:
|
|||||||
qDebug() << target_dir.path();
|
qDebug() << target_dir.path();
|
||||||
|
|
||||||
LinkTask lnk_tsk(folder, target_dir.path());
|
LinkTask lnk_tsk(folder, target_dir.path());
|
||||||
lnk_tsk.matcher(new RegexpMatcher("[.]?mcmeta"));
|
RegexpMatcher re("[.]?mcmeta");
|
||||||
|
lnk_tsk.matcher(&re);
|
||||||
lnk_tsk.linkRecursively(true);
|
lnk_tsk.linkRecursively(true);
|
||||||
lnk_tsk.whitelist(true);
|
lnk_tsk.whitelist(true);
|
||||||
QObject::connect(&lnk_tsk, &Task::finished, [&]{
|
QObject::connect(&lnk_tsk, &Task::finished, [&]{
|
||||||
|
@ -38,6 +38,7 @@ class DummyResourceModel : public ResourceModel {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
DummyResourceModel() : ResourceModel(new DummyResourceAPI) {}
|
DummyResourceModel() : ResourceModel(new DummyResourceAPI) {}
|
||||||
|
~DummyResourceModel() {}
|
||||||
|
|
||||||
[[nodiscard]] auto metaEntryBase() const -> QString override { return ""; };
|
[[nodiscard]] auto metaEntryBase() const -> QString override { return ""; };
|
||||||
|
|
||||||
@ -58,7 +59,10 @@ class DummyResourceModel : public ResourceModel {
|
|||||||
class ResourceModelTest : public QObject {
|
class ResourceModelTest : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private slots:
|
private slots:
|
||||||
void test_abstract_item_model() { [[maybe_unused]] auto tester = new QAbstractItemModelTester(new DummyResourceModel); }
|
void test_abstract_item_model() {
|
||||||
|
auto dummy = DummyResourceModel();
|
||||||
|
auto tester = QAbstractItemModelTester(&dummy);
|
||||||
|
}
|
||||||
|
|
||||||
void test_search()
|
void test_search()
|
||||||
{
|
{
|
||||||
@ -78,6 +82,8 @@ class ResourceModelTest : public QObject {
|
|||||||
QVERIFY(processed_pack->addonId.toString() == Json::requireString(processed_response, "project_id"));
|
QVERIFY(processed_pack->addonId.toString() == Json::requireString(processed_response, "project_id"));
|
||||||
QVERIFY(processed_pack->description == Json::requireString(processed_response, "description"));
|
QVERIFY(processed_pack->description == Json::requireString(processed_response, "description"));
|
||||||
QVERIFY(processed_pack->authors.first().name == Json::requireString(processed_response, "author"));
|
QVERIFY(processed_pack->authors.first().name == Json::requireString(processed_response, "author"));
|
||||||
|
|
||||||
|
delete model;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include <QTest>
|
#include <QTest>
|
||||||
#include <QTimer>
|
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
#include <tasks/ConcurrentTask.h>
|
#include <tasks/ConcurrentTask.h>
|
||||||
#include <tasks/MultipleOptionsTask.h>
|
#include <tasks/MultipleOptionsTask.h>
|
||||||
@ -19,10 +19,7 @@ class BasicTask : public Task {
|
|||||||
BasicTask(bool show_debug_log = true) : Task(nullptr, show_debug_log) {}
|
BasicTask(bool show_debug_log = true) : Task(nullptr, show_debug_log) {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void executeTask() override
|
void executeTask() override { emitSucceeded(); };
|
||||||
{
|
|
||||||
emitSucceeded();
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Does nothing. Only used for testing. */
|
/* Does nothing. Only used for testing. */
|
||||||
@ -34,7 +31,7 @@ class BasicTask_MultiStep : public Task {
|
|||||||
private:
|
private:
|
||||||
auto isMultiStep() const -> bool override { return true; }
|
auto isMultiStep() const -> bool override { return true; }
|
||||||
|
|
||||||
void executeTask() override {};
|
void executeTask() override{};
|
||||||
};
|
};
|
||||||
|
|
||||||
class BigConcurrentTask : public ConcurrentTask {
|
class BigConcurrentTask : public ConcurrentTask {
|
||||||
@ -44,7 +41,7 @@ class BigConcurrentTask : public ConcurrentTask {
|
|||||||
{
|
{
|
||||||
// This is here only to help fill the stack a bit more quickly (if there's an issue, of course :^))
|
// This is here only to help fill the stack a bit more quickly (if there's an issue, of course :^))
|
||||||
// Each tasks thus adds 1024 * 4 bytes to the stack, at the very least.
|
// Each tasks thus adds 1024 * 4 bytes to the stack, at the very least.
|
||||||
[[maybe_unused]] volatile std::array<uint32_t, 1024> some_data_on_the_stack {};
|
[[maybe_unused]] volatile std::array<uint32_t, 1024> some_data_on_the_stack{};
|
||||||
|
|
||||||
ConcurrentTask::startNext();
|
ConcurrentTask::startNext();
|
||||||
}
|
}
|
||||||
@ -53,49 +50,42 @@ class BigConcurrentTask : public ConcurrentTask {
|
|||||||
class BigConcurrentTaskThread : public QThread {
|
class BigConcurrentTaskThread : public QThread {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
BigConcurrentTask big_task;
|
QTimer m_deadline;
|
||||||
|
|
||||||
void run() override
|
void run() override
|
||||||
{
|
{
|
||||||
QTimer deadline;
|
BigConcurrentTask big_task;
|
||||||
deadline.setInterval(10000);
|
m_deadline.setInterval(10000);
|
||||||
connect(&deadline, &QTimer::timeout, this, [this]{ passed_the_deadline = true; });
|
|
||||||
deadline.start();
|
|
||||||
|
|
||||||
// NOTE: Arbitrary value that manages to trigger a problem when there is one.
|
// NOTE: Arbitrary value that manages to trigger a problem when there is one.
|
||||||
// Considering each tasks, in a problematic state, adds 1024 * 4 bytes to the stack,
|
// Considering each tasks, in a problematic state, adds 1024 * 4 bytes to the stack,
|
||||||
// this number is enough to fill up 16 MiB of stack, more than enough to cause a problem.
|
// this number is enough to fill up 16 MiB of stack, more than enough to cause a problem.
|
||||||
static const unsigned s_num_tasks = 1 << 12;
|
static const unsigned s_num_tasks = 1 << 12;
|
||||||
auto sub_tasks = new BasicTask::Ptr[s_num_tasks];
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < s_num_tasks; i++) {
|
for (unsigned i = 0; i < s_num_tasks; i++) {
|
||||||
auto sub_task = makeShared<BasicTask>(false);
|
auto sub_task = makeShared<BasicTask>(false);
|
||||||
sub_tasks[i] = sub_task;
|
|
||||||
big_task.addTask(sub_task);
|
big_task.addTask(sub_task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connect(&big_task, &Task::finished, this, &QThread::quit);
|
||||||
|
connect(&m_deadline, &QTimer::timeout, this, [&] { passed_the_deadline = true; quit(); });
|
||||||
|
|
||||||
|
m_deadline.start();
|
||||||
big_task.run();
|
big_task.run();
|
||||||
|
|
||||||
while (!big_task.isFinished() && !passed_the_deadline)
|
exec();
|
||||||
QCoreApplication::processEvents();
|
|
||||||
|
|
||||||
emit finished();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool passed_the_deadline = false;
|
bool passed_the_deadline = false;
|
||||||
|
|
||||||
signals:
|
|
||||||
void finished();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class TaskTest : public QObject {
|
class TaskTest : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void test_SetStatus_NoMultiStep(){
|
void test_SetStatus_NoMultiStep()
|
||||||
|
{
|
||||||
BasicTask t;
|
BasicTask t;
|
||||||
QString status {"test status"};
|
QString status{ "test status" };
|
||||||
|
|
||||||
t.setStatus(status);
|
t.setStatus(status);
|
||||||
|
|
||||||
@ -103,9 +93,10 @@ class TaskTest : public QObject {
|
|||||||
QCOMPARE(t.getStepProgress().isEmpty(), TaskStepProgressList{}.isEmpty());
|
QCOMPARE(t.getStepProgress().isEmpty(), TaskStepProgressList{}.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_SetStatus_MultiStep(){
|
void test_SetStatus_MultiStep()
|
||||||
|
{
|
||||||
BasicTask_MultiStep t;
|
BasicTask_MultiStep t;
|
||||||
QString status {"test status"};
|
QString status{ "test status" };
|
||||||
|
|
||||||
t.setStatus(status);
|
t.setStatus(status);
|
||||||
|
|
||||||
@ -115,7 +106,8 @@ class TaskTest : public QObject {
|
|||||||
QCOMPARE(t.getStepProgress().isEmpty(), TaskStepProgressList{}.isEmpty());
|
QCOMPARE(t.getStepProgress().isEmpty(), TaskStepProgressList{}.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_SetProgress(){
|
void test_SetProgress()
|
||||||
|
{
|
||||||
BasicTask t;
|
BasicTask t;
|
||||||
int current = 42;
|
int current = 42;
|
||||||
int total = 207;
|
int total = 207;
|
||||||
@ -126,17 +118,18 @@ class TaskTest : public QObject {
|
|||||||
QCOMPARE(t.getTotalProgress(), total);
|
QCOMPARE(t.getTotalProgress(), total);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_basicRun(){
|
void test_basicRun()
|
||||||
|
{
|
||||||
BasicTask t;
|
BasicTask t;
|
||||||
QObject::connect(&t, &Task::finished, [&]{ QVERIFY2(t.wasSuccessful(), "Task finished but was not successful when it should have been."); });
|
QObject::connect(&t, &Task::finished,
|
||||||
|
[&] { QVERIFY2(t.wasSuccessful(), "Task finished but was not successful when it should have been."); });
|
||||||
t.start();
|
t.start();
|
||||||
|
|
||||||
QVERIFY2(QTest::qWaitFor([&]() {
|
QVERIFY2(QTest::qWaitFor([&]() { return t.isFinished(); }, 1000), "Task didn't finish as it should.");
|
||||||
return t.isFinished();
|
|
||||||
}, 1000), "Task didn't finish as it should.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_basicConcurrentRun(){
|
void test_basicConcurrentRun()
|
||||||
|
{
|
||||||
auto t1 = makeShared<BasicTask>();
|
auto t1 = makeShared<BasicTask>();
|
||||||
auto t2 = makeShared<BasicTask>();
|
auto t2 = makeShared<BasicTask>();
|
||||||
auto t3 = makeShared<BasicTask>();
|
auto t3 = makeShared<BasicTask>();
|
||||||
@ -147,7 +140,7 @@ class TaskTest : public QObject {
|
|||||||
t.addTask(t2);
|
t.addTask(t2);
|
||||||
t.addTask(t3);
|
t.addTask(t3);
|
||||||
|
|
||||||
QObject::connect(&t, &Task::finished, [&]{
|
QObject::connect(&t, &Task::finished, [&t, &t1, &t2, &t3] {
|
||||||
QVERIFY2(t.wasSuccessful(), "Task finished but was not successful when it should have been.");
|
QVERIFY2(t.wasSuccessful(), "Task finished but was not successful when it should have been.");
|
||||||
QVERIFY(t1->wasSuccessful());
|
QVERIFY(t1->wasSuccessful());
|
||||||
QVERIFY(t2->wasSuccessful());
|
QVERIFY(t2->wasSuccessful());
|
||||||
@ -155,13 +148,12 @@ class TaskTest : public QObject {
|
|||||||
});
|
});
|
||||||
|
|
||||||
t.start();
|
t.start();
|
||||||
QVERIFY2(QTest::qWaitFor([&]() {
|
QVERIFY2(QTest::qWaitFor([&]() { return t.isFinished(); }, 1000), "Task didn't finish as it should.");
|
||||||
return t.isFinished();
|
|
||||||
}, 1000), "Task didn't finish as it should.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests if starting new tasks after the 6 initial ones is working
|
// Tests if starting new tasks after the 6 initial ones is working
|
||||||
void test_moreConcurrentRun(){
|
void test_moreConcurrentRun()
|
||||||
|
{
|
||||||
auto t1 = makeShared<BasicTask>();
|
auto t1 = makeShared<BasicTask>();
|
||||||
auto t2 = makeShared<BasicTask>();
|
auto t2 = makeShared<BasicTask>();
|
||||||
auto t3 = makeShared<BasicTask>();
|
auto t3 = makeShared<BasicTask>();
|
||||||
@ -184,7 +176,7 @@ class TaskTest : public QObject {
|
|||||||
t.addTask(t8);
|
t.addTask(t8);
|
||||||
t.addTask(t9);
|
t.addTask(t9);
|
||||||
|
|
||||||
QObject::connect(&t, &Task::finished, [&]{
|
QObject::connect(&t, &Task::finished, [&t, &t1, &t2, &t3, &t4, &t5, &t6, &t7, &t8, &t9] {
|
||||||
QVERIFY2(t.wasSuccessful(), "Task finished but was not successful when it should have been.");
|
QVERIFY2(t.wasSuccessful(), "Task finished but was not successful when it should have been.");
|
||||||
QVERIFY(t1->wasSuccessful());
|
QVERIFY(t1->wasSuccessful());
|
||||||
QVERIFY(t2->wasSuccessful());
|
QVERIFY(t2->wasSuccessful());
|
||||||
@ -198,12 +190,11 @@ class TaskTest : public QObject {
|
|||||||
});
|
});
|
||||||
|
|
||||||
t.start();
|
t.start();
|
||||||
QVERIFY2(QTest::qWaitFor([&]() {
|
QVERIFY2(QTest::qWaitFor([&]() { return t.isFinished(); }, 1000), "Task didn't finish as it should.");
|
||||||
return t.isFinished();
|
|
||||||
}, 1000), "Task didn't finish as it should.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_basicSequentialRun(){
|
void test_basicSequentialRun()
|
||||||
|
{
|
||||||
auto t1 = makeShared<BasicTask>();
|
auto t1 = makeShared<BasicTask>();
|
||||||
auto t2 = makeShared<BasicTask>();
|
auto t2 = makeShared<BasicTask>();
|
||||||
auto t3 = makeShared<BasicTask>();
|
auto t3 = makeShared<BasicTask>();
|
||||||
@ -214,7 +205,7 @@ class TaskTest : public QObject {
|
|||||||
t.addTask(t2);
|
t.addTask(t2);
|
||||||
t.addTask(t3);
|
t.addTask(t3);
|
||||||
|
|
||||||
QObject::connect(&t, &Task::finished, [&]{
|
QObject::connect(&t, &Task::finished, [&t, &t1, &t2, &t3] {
|
||||||
QVERIFY2(t.wasSuccessful(), "Task finished but was not successful when it should have been.");
|
QVERIFY2(t.wasSuccessful(), "Task finished but was not successful when it should have been.");
|
||||||
QVERIFY(t1->wasSuccessful());
|
QVERIFY(t1->wasSuccessful());
|
||||||
QVERIFY(t2->wasSuccessful());
|
QVERIFY(t2->wasSuccessful());
|
||||||
@ -222,12 +213,11 @@ class TaskTest : public QObject {
|
|||||||
});
|
});
|
||||||
|
|
||||||
t.start();
|
t.start();
|
||||||
QVERIFY2(QTest::qWaitFor([&]() {
|
QVERIFY2(QTest::qWaitFor([&]() { return t.isFinished(); }, 1000), "Task didn't finish as it should.");
|
||||||
return t.isFinished();
|
|
||||||
}, 1000), "Task didn't finish as it should.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_basicMultipleOptionsRun(){
|
void test_basicMultipleOptionsRun()
|
||||||
|
{
|
||||||
auto t1 = makeShared<BasicTask>();
|
auto t1 = makeShared<BasicTask>();
|
||||||
auto t2 = makeShared<BasicTask>();
|
auto t2 = makeShared<BasicTask>();
|
||||||
auto t3 = makeShared<BasicTask>();
|
auto t3 = makeShared<BasicTask>();
|
||||||
@ -238,7 +228,7 @@ class TaskTest : public QObject {
|
|||||||
t.addTask(t2);
|
t.addTask(t2);
|
||||||
t.addTask(t3);
|
t.addTask(t3);
|
||||||
|
|
||||||
QObject::connect(&t, &Task::finished, [&]{
|
QObject::connect(&t, &Task::finished, [&t, &t1, &t2, &t3] {
|
||||||
QVERIFY2(t.wasSuccessful(), "Task finished but was not successful when it should have been.");
|
QVERIFY2(t.wasSuccessful(), "Task finished but was not successful when it should have been.");
|
||||||
QVERIFY(t1->wasSuccessful());
|
QVERIFY(t1->wasSuccessful());
|
||||||
QVERIFY(!t2->wasSuccessful());
|
QVERIFY(!t2->wasSuccessful());
|
||||||
@ -246,25 +236,22 @@ class TaskTest : public QObject {
|
|||||||
});
|
});
|
||||||
|
|
||||||
t.start();
|
t.start();
|
||||||
QVERIFY2(QTest::qWaitFor([&]() {
|
QVERIFY2(QTest::qWaitFor([&]() { return t.isFinished(); }, 1000), "Task didn't finish as it should.");
|
||||||
return t.isFinished();
|
|
||||||
}, 1000), "Task didn't finish as it should.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_stackOverflowInConcurrentTask()
|
void test_stackOverflowInConcurrentTask()
|
||||||
{
|
{
|
||||||
QEventLoop loop;
|
QEventLoop loop;
|
||||||
|
|
||||||
auto thread = new BigConcurrentTaskThread;
|
BigConcurrentTaskThread thread;
|
||||||
|
|
||||||
connect(thread, &BigConcurrentTaskThread::finished, &loop, &QEventLoop::quit);
|
connect(&thread, &BigConcurrentTaskThread::finished, &loop, &QEventLoop::quit);
|
||||||
|
|
||||||
thread->start();
|
thread.start();
|
||||||
|
|
||||||
loop.exec();
|
loop.exec();
|
||||||
|
|
||||||
QVERIFY(!thread->passed_the_deadline);
|
QVERIFY(!thread.passed_the_deadline);
|
||||||
thread->deleteLater();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
class VersionTest : public QObject {
|
class VersionTest : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
QStringList m_flex_test_names = {};
|
||||||
|
|
||||||
void addDataColumns()
|
void addDataColumns()
|
||||||
{
|
{
|
||||||
QTest::addColumn<QString>("first");
|
QTest::addColumn<QString>("first");
|
||||||
@ -101,8 +103,9 @@ class VersionTest : public QObject {
|
|||||||
QString first{split_line.first().simplified()};
|
QString first{split_line.first().simplified()};
|
||||||
QString second{split_line.last().simplified()};
|
QString second{split_line.last().simplified()};
|
||||||
|
|
||||||
auto new_test_name = test_name_template.arg(QString::number(test_number), "lessThan").toLatin1().data();
|
auto new_test_name = test_name_template.arg(QString::number(test_number), "lessThan");
|
||||||
QTest::newRow(new_test_name) << first << second << true << false;
|
m_flex_test_names.append(new_test_name);
|
||||||
|
QTest::newRow(m_flex_test_names.last().toLatin1().data()) << first << second << true << false;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -112,8 +115,9 @@ class VersionTest : public QObject {
|
|||||||
QString first{split_line.first().simplified()};
|
QString first{split_line.first().simplified()};
|
||||||
QString second{split_line.last().simplified()};
|
QString second{split_line.last().simplified()};
|
||||||
|
|
||||||
auto new_test_name = test_name_template.arg(QString::number(test_number), "equals").toLatin1().data();
|
auto new_test_name = test_name_template.arg(QString::number(test_number), "equals");
|
||||||
QTest::newRow(new_test_name) << first << second << false << true;
|
m_flex_test_names.append(new_test_name);
|
||||||
|
QTest::newRow(m_flex_test_names.last().toLatin1().data()) << first << second << false << true;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -123,8 +127,9 @@ class VersionTest : public QObject {
|
|||||||
QString first{split_line.first().simplified()};
|
QString first{split_line.first().simplified()};
|
||||||
QString second{split_line.last().simplified()};
|
QString second{split_line.last().simplified()};
|
||||||
|
|
||||||
auto new_test_name = test_name_template.arg(QString::number(test_number), "greaterThan").toLatin1().data();
|
auto new_test_name = test_name_template.arg(QString::number(test_number), "greaterThan");
|
||||||
QTest::newRow(new_test_name) << first << second << false << false;
|
m_flex_test_names.append(new_test_name);
|
||||||
|
QTest::newRow(m_flex_test_names.last().toLatin1().data()) << first << second << false << false;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user