mirror of
https://github.com/UltimMC/Launcher.git
synced 2025-12-13 20:22:13 +00:00
Compare commits
117 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce68efa174 | ||
|
|
8bb906bbd7 | ||
|
|
e7f67a73b3 | ||
|
|
3821569363 | ||
|
|
d8d6f5929b | ||
|
|
977cc1cfbb | ||
|
|
4c0dc51110 | ||
|
|
5c43842359 | ||
|
|
aba1f89e2a | ||
|
|
cc6968e9a3 | ||
|
|
d570037331 | ||
|
|
6a8984a21d | ||
|
|
0d4046de39 | ||
|
|
24698fe85f | ||
|
|
40c238442f | ||
|
|
ff06489fed | ||
|
|
08fbfa7434 | ||
|
|
6f75009a80 | ||
|
|
7c51cc475b | ||
|
|
fc911add58 | ||
|
|
6349800f07 | ||
|
|
9b3ae29a36 | ||
|
|
19278c853b | ||
|
|
b3cf19190f | ||
|
|
842328df8e | ||
|
|
f72a38b06c | ||
|
|
d934e64831 | ||
|
|
15775bd30a | ||
|
|
cc499488db | ||
|
|
a218d7b7f6 | ||
|
|
b5d6f50fb1 | ||
|
|
252f375454 | ||
|
|
a75e64dd18 | ||
|
|
18a342ef14 | ||
|
|
8b86306d48 | ||
|
|
dd0752e69f | ||
|
|
d166340097 | ||
|
|
eb5699c835 | ||
|
|
b9fb718822 | ||
|
|
1f498266d8 | ||
|
|
e241c3625c | ||
|
|
421a46e3d3 | ||
|
|
5179aed3a0 | ||
|
|
77de2d1e54 | ||
|
|
e422eff959 | ||
|
|
828254dd11 | ||
|
|
1f3a840f3c | ||
|
|
56d91fda3a | ||
|
|
e8731c5d01 | ||
|
|
30b1f5e5cf | ||
|
|
7f4073840a | ||
|
|
f0d850e1ee | ||
|
|
d6e5c472b5 | ||
|
|
c31dbf13cb | ||
|
|
affb2fdd6c | ||
|
|
c081cd8021 | ||
|
|
1194ec9a8e | ||
|
|
d911c9908c | ||
|
|
702e00e059 | ||
|
|
478815dae6 | ||
|
|
c08bfce5f2 | ||
|
|
9ec6deea84 | ||
|
|
0bccc94471 | ||
|
|
a0a805735b | ||
|
|
171325d427 | ||
|
|
be73eb3322 | ||
|
|
bf7b070508 | ||
|
|
223a7aba7b | ||
|
|
84ae67fff5 | ||
|
|
694067c603 | ||
|
|
6b3d1101cb | ||
|
|
f485885757 | ||
|
|
48d3052ac1 | ||
|
|
e118b1f990 | ||
|
|
55a0d110b6 | ||
|
|
f3900f2966 | ||
|
|
db8b47e7f6 | ||
|
|
439e17b149 | ||
|
|
8c71a5d61f | ||
|
|
6d34411f54 | ||
|
|
68ef451be5 | ||
|
|
e993adaf44 | ||
|
|
ad1f2c530c | ||
|
|
69c3e7111f | ||
|
|
92abe4c603 | ||
|
|
9860d5ee12 | ||
|
|
8a3a0f5a52 | ||
|
|
69a9ca39ad | ||
|
|
825d31bf1a | ||
|
|
2590c6be15 | ||
|
|
4c3bd416c6 | ||
|
|
aade36860c | ||
|
|
3a0cdf2d3d | ||
|
|
d2b2d55aa9 | ||
|
|
eb9661370b | ||
|
|
e1f542b5b0 | ||
|
|
15920aa9d0 | ||
|
|
e17364de6b | ||
|
|
b911a3834c | ||
|
|
94c2c363b2 | ||
|
|
df82d8fadb | ||
|
|
851a77d5bb | ||
|
|
41caf7976d | ||
|
|
fc3c0b0971 | ||
|
|
94cb5c7d77 | ||
|
|
911ac19a56 | ||
|
|
7f2a16917e | ||
|
|
8a8c4193e6 | ||
|
|
927217c7f0 | ||
|
|
e6ca58a89e | ||
|
|
aefa73ad11 | ||
|
|
4f6cd65c13 | ||
|
|
5099964c67 | ||
|
|
9e80ddb040 | ||
|
|
489cb4dbf5 | ||
|
|
e3b9b30302 | ||
|
|
93ae21abfc |
@@ -9,6 +9,7 @@ NamespaceIndentation: None
|
||||
|
||||
BreakBeforeBraces: Allman
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
ColumnLimit: 96
|
||||
MaxEmptyLinesToKeep: 1
|
||||
|
||||
|
||||
@@ -29,7 +29,9 @@ Config::Config()
|
||||
UPDATER_FORCE_LOCAL = @MultiMC_UPDATER_FORCE_LOCAL_value@;
|
||||
|
||||
GIT_COMMIT = "@MultiMC_GIT_COMMIT@";
|
||||
GIT_COMMIT_CSTR = "@MultiMC_GIT_COMMIT@";
|
||||
VERSION_STR = "@MultiMC_VERSION_STRING@";
|
||||
VERSION_CSTR = "@MultiMC_VERSION_STRING@";
|
||||
NEWS_RSS_URL = "@MultiMC_NEWS_RSS_URL@";
|
||||
}
|
||||
|
||||
|
||||
@@ -61,10 +61,14 @@ public:
|
||||
|
||||
/// The commit hash of this build
|
||||
QString GIT_COMMIT;
|
||||
const char* GIT_COMMIT_CSTR;
|
||||
|
||||
/// This is printed on start to standard output
|
||||
QString VERSION_STR;
|
||||
|
||||
/// Version string as a char string. Used by the crash handling system to avoid touching heap memory.
|
||||
const char* VERSION_CSTR;
|
||||
|
||||
/**
|
||||
* This is used to fetch the news RSS feed.
|
||||
* It defaults in CMakeLists.txt to "http://multimc.org/rss.xml"
|
||||
|
||||
364
CMakeLists.txt
364
CMakeLists.txt
@@ -35,7 +35,7 @@ set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${PROJECT_BINARY_DIR}/jars)
|
||||
######## Set compiler flags ########
|
||||
include(UseCXX11)
|
||||
include(Coverage)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||
set(CMAKE_CXX_FLAGS " -Wall ${CMAKE_CXX_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Werror=return-type")
|
||||
|
||||
################################ 3rd Party Libs ################################
|
||||
@@ -75,15 +75,36 @@ if(${BIGENDIAN})
|
||||
endif(${BIGENDIAN})
|
||||
|
||||
|
||||
######## Set URLs ########
|
||||
######## Dark magic crash reports ########
|
||||
option(MultiMC_HANDLE_SEGV "Handle fatal crashes and generate crash reports." OFF)
|
||||
set(CRASH_HANDLER_IMPL "")
|
||||
message(STATUS "Crash dumps are ${MultiMC_HANDLE_SEGV}")
|
||||
if (MultiMC_HANDLE_SEGV)
|
||||
add_definitions(-DHANDLE_SEGV)
|
||||
if (WIN32)
|
||||
find_package(DbgHelp)
|
||||
set(MultiMC_LINK_ADDITIONAL_LIBS "${MultiMC_LINK_ADDITIONAL_LIBS}dbghelp")
|
||||
set(MultiMC_CRASH_HANDLER_EXTRA_H "WinBacktrace.h")
|
||||
set(MultiMC_CRASH_HANDLER_EXTRA_CPP "WinBacktrace.cpp")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
option(MultiMC_TEST_SEGV "Intentionally segfault sometimes to test crash handling." OFF)
|
||||
if (MultiMC_TEST_SEGV)
|
||||
# TODO: Make this a unit test instead.
|
||||
message(WARNING "You have enabled crash handler testing. MULTIMC WILL INTENTIONALLY CRASH ITSELF. Crashes should occur on exit and when the new instance button is pressed.")
|
||||
add_definitions(-DTEST_SEGV)
|
||||
endif ()
|
||||
|
||||
|
||||
######## Set URLs ########
|
||||
set(MultiMC_NEWS_RSS_URL "http://multimc.org/rss.xml" CACHE STRING "URL to fetch MultiMC's news RSS feed from.")
|
||||
|
||||
|
||||
######## Set version numbers ########
|
||||
set(MultiMC_VERSION_MAJOR 0)
|
||||
set(MultiMC_VERSION_MINOR 3)
|
||||
set(MultiMC_VERSION_HOTFIX 5)
|
||||
set(MultiMC_VERSION_MINOR 4)
|
||||
set(MultiMC_VERSION_HOTFIX 0)
|
||||
|
||||
# Build number
|
||||
set(MultiMC_VERSION_BUILD -1 CACHE STRING "Build number. -1 for no build number.")
|
||||
@@ -231,11 +252,6 @@ add_definitions(-DLIBUTIL_STATIC)
|
||||
add_subdirectory(depends/util)
|
||||
include_directories(${LIBUTIL_INCLUDE_DIR})
|
||||
|
||||
# Add the settings library.
|
||||
add_definitions(-DLIBSETTINGS_STATIC)
|
||||
add_subdirectory(depends/settings)
|
||||
include_directories(${LIBSETTINGS_INCLUDE_DIR})
|
||||
|
||||
# Add the updater
|
||||
add_subdirectory(mmc_updater)
|
||||
|
||||
@@ -250,6 +266,12 @@ SET(MULTIMC_SOURCES
|
||||
BuildConfig.h
|
||||
${PROJECT_BINARY_DIR}/BuildConfig.cpp
|
||||
|
||||
# Crash handling
|
||||
HandleCrash.h
|
||||
HandleCrash.cpp
|
||||
${MultiMC_CRASH_HANDLER_EXTRA_H} # Extra platform specific stuff
|
||||
${MultiMC_CRASH_HANDLER_EXTRA_CPP}
|
||||
|
||||
# Logging
|
||||
logger/QsDebugOutput.cpp
|
||||
logger/QsDebugOutput.h
|
||||
@@ -258,101 +280,153 @@ SET(MULTIMC_SOURCES
|
||||
logger/QsLogDest.cpp
|
||||
logger/QsLogDest.h
|
||||
|
||||
# GUI - general utilities
|
||||
gui/GuiUtil.h
|
||||
gui/GuiUtil.cpp
|
||||
|
||||
# GUI - windows
|
||||
gui/MainWindow.h
|
||||
gui/MainWindow.cpp
|
||||
gui/ConsoleWindow.h
|
||||
gui/ConsoleWindow.cpp
|
||||
|
||||
# GUI - page dialog pages
|
||||
gui/pages/BasePage.h
|
||||
gui/pages/VersionPage.cpp
|
||||
gui/pages/VersionPage.h
|
||||
gui/pages/TexturePackPage.h
|
||||
gui/pages/ResourcePackPage.h
|
||||
gui/pages/ModFolderPage.cpp
|
||||
gui/pages/ModFolderPage.h
|
||||
gui/pages/NotesPage.cpp
|
||||
gui/pages/NotesPage.h
|
||||
gui/pages/LegacyUpgradePage.cpp
|
||||
gui/pages/LegacyUpgradePage.h
|
||||
gui/pages/LegacyJarModPage.cpp
|
||||
gui/pages/LegacyJarModPage.h
|
||||
gui/pages/LogPage.cpp
|
||||
gui/pages/LogPage.h
|
||||
gui/pages/InstanceSettingsPage.cpp
|
||||
gui/pages/InstanceSettingsPage.h
|
||||
gui/pages/ScreenshotsPage.cpp
|
||||
gui/pages/ScreenshotsPage.h
|
||||
gui/pages/OtherLogsPage.cpp
|
||||
gui/pages/OtherLogsPage.h
|
||||
|
||||
# GUI - dialogs
|
||||
gui/dialogs/SettingsDialog.h
|
||||
gui/dialogs/SettingsDialog.cpp
|
||||
gui/dialogs/CopyInstanceDialog.h
|
||||
gui/dialogs/CopyInstanceDialog.cpp
|
||||
gui/dialogs/NewInstanceDialog.cpp
|
||||
gui/dialogs/ProgressDialog.h
|
||||
gui/dialogs/ProgressDialog.cpp
|
||||
gui/dialogs/AboutDialog.h
|
||||
gui/dialogs/AboutDialog.cpp
|
||||
gui/dialogs/VersionSelectDialog.h
|
||||
gui/dialogs/VersionSelectDialog.cpp
|
||||
gui/dialogs/LwjglSelectDialog.h
|
||||
gui/dialogs/LwjglSelectDialog.cpp
|
||||
gui/dialogs/InstanceSettings.h
|
||||
gui/dialogs/InstanceSettings.cpp
|
||||
gui/dialogs/IconPickerDialog.h
|
||||
gui/dialogs/IconPickerDialog.cpp
|
||||
gui/dialogs/LegacyModEditDialog.h
|
||||
gui/dialogs/LegacyModEditDialog.cpp
|
||||
gui/dialogs/OneSixModEditDialog.h
|
||||
gui/dialogs/OneSixModEditDialog.cpp
|
||||
gui/dialogs/ModEditDialogCommon.h
|
||||
gui/dialogs/ModEditDialogCommon.cpp
|
||||
gui/dialogs/EditNotesDialog.h
|
||||
gui/dialogs/EditNotesDialog.cpp
|
||||
gui/dialogs/CustomMessageBox.h
|
||||
gui/dialogs/CustomMessageBox.cpp
|
||||
gui/dialogs/EditAccountDialog.h
|
||||
gui/dialogs/EditAccountDialog.cpp
|
||||
gui/dialogs/LoginDialog.h
|
||||
gui/dialogs/LoginDialog.cpp
|
||||
gui/dialogs/AccountListDialog.h
|
||||
gui/dialogs/AboutDialog.h
|
||||
gui/dialogs/AccountListDialog.cpp
|
||||
gui/dialogs/AccountSelectDialog.h
|
||||
gui/dialogs/AccountListDialog.h
|
||||
gui/dialogs/AccountSelectDialog.cpp
|
||||
gui/dialogs/UpdateDialog.h
|
||||
gui/dialogs/UpdateDialog.cpp
|
||||
gui/dialogs/ScreenshotDialog.h
|
||||
gui/dialogs/ScreenshotDialog.cpp
|
||||
gui/dialogs/NotificationDialog.h
|
||||
gui/dialogs/AccountSelectDialog.h
|
||||
gui/dialogs/CopyInstanceDialog.cpp
|
||||
gui/dialogs/CopyInstanceDialog.h
|
||||
gui/dialogs/CustomMessageBox.cpp
|
||||
gui/dialogs/CustomMessageBox.h
|
||||
gui/dialogs/EditAccountDialog.cpp
|
||||
gui/dialogs/EditAccountDialog.h
|
||||
gui/dialogs/IconPickerDialog.cpp
|
||||
gui/dialogs/IconPickerDialog.h
|
||||
gui/dialogs/LoginDialog.cpp
|
||||
gui/dialogs/LoginDialog.h
|
||||
gui/dialogs/LwjglSelectDialog.cpp
|
||||
gui/dialogs/LwjglSelectDialog.h
|
||||
gui/dialogs/ModEditDialogCommon.cpp
|
||||
gui/dialogs/ModEditDialogCommon.h
|
||||
gui/dialogs/NewInstanceDialog.cpp
|
||||
gui/dialogs/NewInstanceDialog.h
|
||||
gui/dialogs/NotificationDialog.cpp
|
||||
gui/dialogs/NotificationDialog.h
|
||||
gui/pagedialog/PageDialog.cpp
|
||||
gui/pagedialog/PageDialog.h
|
||||
gui/dialogs/ProgressDialog.cpp
|
||||
gui/dialogs/ProgressDialog.h
|
||||
gui/dialogs/SettingsDialog.cpp
|
||||
gui/dialogs/SettingsDialog.h
|
||||
gui/dialogs/UpdateDialog.cpp
|
||||
gui/dialogs/UpdateDialog.h
|
||||
gui/dialogs/VersionSelectDialog.cpp
|
||||
gui/dialogs/VersionSelectDialog.h
|
||||
|
||||
|
||||
# GUI - widgets
|
||||
gui/widgets/Common.h
|
||||
gui/widgets/Common.cpp
|
||||
gui/widgets/ModListView.h
|
||||
gui/widgets/ModListView.cpp
|
||||
gui/widgets/VersionListView.h
|
||||
gui/widgets/VersionListView.cpp
|
||||
gui/widgets/LabeledToolButton.h
|
||||
gui/widgets/Common.h
|
||||
gui/widgets/IconLabel.cpp
|
||||
gui/widgets/IconLabel.h
|
||||
gui/widgets/LabeledToolButton.cpp
|
||||
gui/widgets/MCModInfoFrame.h
|
||||
gui/widgets/LabeledToolButton.h
|
||||
gui/widgets/LineSeparator.cpp
|
||||
gui/widgets/LineSeparator.h
|
||||
gui/widgets/MCModInfoFrame.cpp
|
||||
gui/widgets/MCModInfoFrame.h
|
||||
gui/widgets/ModListView.cpp
|
||||
gui/widgets/ModListView.h
|
||||
gui/widgets/PageContainer.cpp
|
||||
gui/widgets/PageContainer.h
|
||||
gui/widgets/PageContainer_p.h
|
||||
gui/widgets/ServerStatus.cpp
|
||||
gui/widgets/ServerStatus.h
|
||||
gui/widgets/VersionListView.cpp
|
||||
gui/widgets/VersionListView.h
|
||||
|
||||
|
||||
# GUI - instance group view
|
||||
gui/groupview/Group.cpp
|
||||
gui/groupview/Group.h
|
||||
gui/groupview/GroupedProxyModel.cpp
|
||||
gui/groupview/GroupedProxyModel.h
|
||||
gui/groupview/GroupView.cpp
|
||||
gui/groupview/GroupView.h
|
||||
gui/groupview/InstanceDelegate.cpp
|
||||
gui/groupview/InstanceDelegate.h
|
||||
gui/groupview/VisualGroup.cpp
|
||||
gui/groupview/VisualGroup.h
|
||||
|
||||
# Base classes and infrastructure
|
||||
# LOGIC - Base classes and infrastructure
|
||||
logic/BaseVersion.h
|
||||
logic/MinecraftVersion.h
|
||||
logic/InstanceFactory.h
|
||||
logic/InstanceFactory.cpp
|
||||
logic/BaseInstance.h
|
||||
logic/BaseInstance.cpp
|
||||
logic/BaseInstance_p.h
|
||||
|
||||
logic/MinecraftProcess.h
|
||||
logic/MinecraftProcess.cpp
|
||||
logic/Mod.h
|
||||
logic/Mod.cpp
|
||||
logic/ModList.h
|
||||
logic/ModList.cpp
|
||||
|
||||
# sets and maps for deciding based on versions
|
||||
logic/VersionFilterData.h
|
||||
logic/VersionFilterData.cpp
|
||||
|
||||
# Basic instance launcher for starting from terminal
|
||||
# Instance launch
|
||||
logic/InstanceLauncher.h
|
||||
logic/InstanceLauncher.cpp
|
||||
logic/MinecraftProcess.h
|
||||
logic/MinecraftProcess.cpp
|
||||
|
||||
# URN parser/resolver
|
||||
logic/URNResolver.cpp
|
||||
logic/URNResolver.h
|
||||
|
||||
# Annoying nag screen logic
|
||||
logic/NagUtils.h
|
||||
logic/NagUtils.cpp
|
||||
|
||||
# Player skin utilities
|
||||
logic/SkinUtils.h
|
||||
logic/SkinUtils.cpp
|
||||
|
||||
# misc model filter
|
||||
logic/EnabledItemFilter.h
|
||||
logic/EnabledItemFilter.cpp
|
||||
|
||||
# JSON parsing helpers
|
||||
logic/MMCJson.h
|
||||
logic/MMCJson.cpp
|
||||
|
||||
# RW lock protected map
|
||||
logic/RWStorage.h
|
||||
|
||||
# network stuffs
|
||||
logic/net/NetAction.h
|
||||
logic/net/MD5EtagDownload.h
|
||||
@@ -361,10 +435,6 @@ SET(MULTIMC_SOURCES
|
||||
logic/net/ByteArrayDownload.cpp
|
||||
logic/net/CacheDownload.h
|
||||
logic/net/CacheDownload.cpp
|
||||
logic/net/ForgeMirrors.h
|
||||
logic/net/ForgeMirrors.cpp
|
||||
logic/net/ForgeXzDownload.h
|
||||
logic/net/ForgeXzDownload.cpp
|
||||
logic/net/NetJob.h
|
||||
logic/net/NetJob.cpp
|
||||
logic/net/HttpMetaCache.h
|
||||
@@ -415,9 +485,6 @@ SET(MULTIMC_SOURCES
|
||||
logic/LegacyUpdate.h
|
||||
logic/LegacyUpdate.cpp
|
||||
|
||||
logic/LegacyForge.h
|
||||
logic/LegacyForge.cpp
|
||||
|
||||
# OneSix instances
|
||||
logic/OneSixUpdate.h
|
||||
logic/OneSixUpdate.cpp
|
||||
@@ -426,30 +493,46 @@ SET(MULTIMC_SOURCES
|
||||
logic/OneSixInstance_p.h
|
||||
|
||||
# OneSix version json infrastructure
|
||||
logic/OneSixVersionBuilder.h
|
||||
logic/OneSixVersionBuilder.cpp
|
||||
logic/VersionFile.h
|
||||
logic/VersionFile.cpp
|
||||
logic/VersionFinal.h
|
||||
logic/VersionFinal.cpp
|
||||
logic/OneSixLibrary.h
|
||||
logic/OneSixLibrary.cpp
|
||||
logic/OneSixRule.h
|
||||
logic/OneSixRule.cpp
|
||||
logic/OpSys.h
|
||||
logic/OpSys.cpp
|
||||
logic/minecraft/InstanceVersion.cpp
|
||||
logic/minecraft/InstanceVersion.h
|
||||
logic/minecraft/JarMod.cpp
|
||||
logic/minecraft/JarMod.h
|
||||
logic/minecraft/MinecraftVersion.cpp
|
||||
logic/minecraft/MinecraftVersion.h
|
||||
logic/minecraft/MinecraftVersionList.cpp
|
||||
logic/minecraft/MinecraftVersionList.h
|
||||
logic/minecraft/OneSixLibrary.cpp
|
||||
logic/minecraft/OneSixLibrary.h
|
||||
logic/minecraft/OneSixRule.cpp
|
||||
logic/minecraft/OneSixRule.h
|
||||
logic/minecraft/OpSys.cpp
|
||||
logic/minecraft/OpSys.h
|
||||
logic/minecraft/ParseUtils.cpp
|
||||
logic/minecraft/ParseUtils.h
|
||||
logic/minecraft/RawLibrary.cpp
|
||||
logic/minecraft/RawLibrary.h
|
||||
logic/minecraft/VersionBuilder.cpp
|
||||
logic/minecraft/VersionBuilder.h
|
||||
logic/minecraft/VersionBuildError.h
|
||||
logic/minecraft/VersionFile.cpp
|
||||
logic/minecraft/VersionFile.h
|
||||
logic/minecraft/VersionPatch.h
|
||||
logic/minecraft/VersionSource.h
|
||||
|
||||
# Mod installers
|
||||
# A Recursive file system watcher
|
||||
logic/RecursiveFileSystemWatcher.h
|
||||
logic/RecursiveFileSystemWatcher.cpp
|
||||
|
||||
# Various base classes
|
||||
logic/BaseInstaller.h
|
||||
logic/BaseInstaller.cpp
|
||||
logic/ForgeInstaller.h
|
||||
logic/ForgeInstaller.cpp
|
||||
logic/LiteLoaderInstaller.h
|
||||
logic/LiteLoaderInstaller.cpp
|
||||
logic/BaseVersionList.h
|
||||
logic/BaseVersionList.cpp
|
||||
|
||||
# Nostalgia
|
||||
logic/NostalgiaInstance.h
|
||||
logic/NostalgiaInstance.cpp
|
||||
logic/InstanceList.h
|
||||
logic/InstanceList.cpp
|
||||
logic/LwjglVersionList.h
|
||||
logic/LwjglVersionList.cpp
|
||||
|
||||
# FTB
|
||||
logic/OneSixFTBInstance.h
|
||||
@@ -457,27 +540,8 @@ SET(MULTIMC_SOURCES
|
||||
logic/LegacyFTBInstance.h
|
||||
logic/LegacyFTBInstance.cpp
|
||||
|
||||
# Lists
|
||||
logic/lists/InstanceList.h
|
||||
logic/lists/InstanceList.cpp
|
||||
logic/lists/BaseVersionList.h
|
||||
logic/lists/BaseVersionList.cpp
|
||||
logic/lists/MinecraftVersionList.h
|
||||
logic/lists/MinecraftVersionList.cpp
|
||||
logic/lists/LwjglVersionList.h
|
||||
logic/lists/LwjglVersionList.cpp
|
||||
logic/lists/ForgeVersionList.h
|
||||
logic/lists/ForgeVersionList.cpp
|
||||
logic/lists/JavaVersionList.h
|
||||
logic/lists/JavaVersionList.cpp
|
||||
logic/lists/LiteLoaderVersionList.h
|
||||
logic/lists/LiteLoaderVersionList.cpp
|
||||
|
||||
# the screenshots feature
|
||||
logic/screenshots/Screenshot.h
|
||||
logic/screenshots/Screenshot.cpp
|
||||
logic/screenshots/ScreenshotList.h
|
||||
logic/screenshots/ScreenshotList.cpp
|
||||
logic/screenshots/ImgurUpload.h
|
||||
logic/screenshots/ImgurUpload.cpp
|
||||
logic/screenshots/ImgurAlbumCreation.h
|
||||
@@ -489,11 +553,6 @@ SET(MULTIMC_SOURCES
|
||||
logic/icons/IconList.h
|
||||
logic/icons/IconList.cpp
|
||||
|
||||
|
||||
# misc model/view
|
||||
logic/EnabledItemFilter.h
|
||||
logic/EnabledItemFilter.cpp
|
||||
|
||||
# Tasks
|
||||
logic/tasks/ProgressProvider.h
|
||||
logic/tasks/Task.h
|
||||
@@ -503,17 +562,27 @@ SET(MULTIMC_SOURCES
|
||||
logic/tasks/SequentialTask.h
|
||||
logic/tasks/SequentialTask.cpp
|
||||
|
||||
# Utilities
|
||||
logic/JavaChecker.h
|
||||
logic/JavaChecker.cpp
|
||||
logic/JavaUtils.h
|
||||
logic/JavaUtils.cpp
|
||||
logic/NagUtils.h
|
||||
logic/NagUtils.cpp
|
||||
logic/SkinUtils.h
|
||||
logic/SkinUtils.cpp
|
||||
logic/JavaCheckerJob.h
|
||||
logic/JavaCheckerJob.cpp
|
||||
# Settings
|
||||
logic/settings/INIFile.cpp
|
||||
logic/settings/INIFile.h
|
||||
logic/settings/INISettingsObject.cpp
|
||||
logic/settings/INISettingsObject.h
|
||||
logic/settings/OverrideSetting.cpp
|
||||
logic/settings/OverrideSetting.h
|
||||
logic/settings/Setting.cpp
|
||||
logic/settings/Setting.h
|
||||
logic/settings/SettingsObject.cpp
|
||||
logic/settings/SettingsObject.h
|
||||
|
||||
# Java related code
|
||||
logic/java/JavaChecker.h
|
||||
logic/java/JavaChecker.cpp
|
||||
logic/java/JavaUtils.h
|
||||
logic/java/JavaUtils.cpp
|
||||
logic/java/JavaVersionList.h
|
||||
logic/java/JavaVersionList.cpp
|
||||
logic/java/JavaCheckerJob.h
|
||||
logic/java/JavaCheckerJob.cpp
|
||||
|
||||
# Assets
|
||||
logic/assets/AssetsMigrateTask.h
|
||||
@@ -532,6 +601,27 @@ SET(MULTIMC_SOURCES
|
||||
logic/tools/JProfiler.cpp
|
||||
logic/tools/JVisualVM.h
|
||||
logic/tools/JVisualVM.cpp
|
||||
|
||||
# Forge and all things forge related
|
||||
logic/forge/ForgeVersion.h
|
||||
logic/forge/ForgeVersion.cpp
|
||||
logic/forge/ForgeVersionList.h
|
||||
logic/forge/ForgeVersionList.cpp
|
||||
logic/forge/ForgeMirror.h
|
||||
logic/forge/ForgeMirrors.h
|
||||
logic/forge/ForgeMirrors.cpp
|
||||
logic/forge/ForgeXzDownload.h
|
||||
logic/forge/ForgeXzDownload.cpp
|
||||
logic/forge/LegacyForge.h
|
||||
logic/forge/LegacyForge.cpp
|
||||
logic/forge/ForgeInstaller.h
|
||||
logic/forge/ForgeInstaller.cpp
|
||||
|
||||
# Liteloader and related things
|
||||
logic/liteloader/LiteLoaderInstaller.h
|
||||
logic/liteloader/LiteLoaderInstaller.cpp
|
||||
logic/liteloader/LiteLoaderVersionList.h
|
||||
logic/liteloader/LiteLoaderVersionList.cpp
|
||||
)
|
||||
|
||||
|
||||
@@ -539,7 +629,17 @@ SET(MULTIMC_SOURCES
|
||||
SET(MULTIMC_UIS
|
||||
# Windows
|
||||
gui/MainWindow.ui
|
||||
gui/ConsoleWindow.ui
|
||||
|
||||
# Option pages
|
||||
gui/pages/VersionPage.ui
|
||||
gui/pages/ModFolderPage.ui
|
||||
gui/pages/LegacyUpgradePage.ui
|
||||
gui/pages/LegacyJarModPage.ui
|
||||
gui/pages/LogPage.ui
|
||||
gui/pages/InstanceSettingsPage.ui
|
||||
gui/pages/NotesPage.ui
|
||||
gui/pages/ScreenshotsPage.ui
|
||||
gui/pages/OtherLogsPage.ui
|
||||
|
||||
# Dialogs
|
||||
gui/dialogs/SettingsDialog.ui
|
||||
@@ -548,18 +648,13 @@ SET(MULTIMC_UIS
|
||||
gui/dialogs/AboutDialog.ui
|
||||
gui/dialogs/VersionSelectDialog.ui
|
||||
gui/dialogs/LwjglSelectDialog.ui
|
||||
gui/dialogs/InstanceSettings.ui
|
||||
gui/dialogs/ProgressDialog.ui
|
||||
gui/dialogs/IconPickerDialog.ui
|
||||
gui/dialogs/LegacyModEditDialog.ui
|
||||
gui/dialogs/OneSixModEditDialog.ui
|
||||
gui/dialogs/EditNotesDialog.ui
|
||||
gui/dialogs/AccountListDialog.ui
|
||||
gui/dialogs/AccountSelectDialog.ui
|
||||
gui/dialogs/EditAccountDialog.ui
|
||||
gui/dialogs/LoginDialog.ui
|
||||
gui/dialogs/UpdateDialog.ui
|
||||
gui/dialogs/ScreenshotDialog.ui
|
||||
gui/dialogs/NotificationDialog.ui
|
||||
|
||||
# Widgets/other
|
||||
@@ -580,7 +675,10 @@ endforeach()
|
||||
set(MULTIMC_QRCS
|
||||
resources/backgrounds/backgrounds.qrc
|
||||
resources/multimc/multimc.qrc
|
||||
resources/pe_dark/pe_dark.qrc
|
||||
resources/pe_light/pe_light.qrc
|
||||
resources/instances/instances.qrc
|
||||
resources/versions/versions.qrc
|
||||
)
|
||||
|
||||
|
||||
@@ -622,7 +720,7 @@ add_executable(MultiMC MACOSX_BUNDLE WIN32 main.cpp ${MULTIMC_RCS})
|
||||
|
||||
# Link
|
||||
target_link_libraries(MultiMC MultiMC_common)
|
||||
target_link_libraries(MultiMC_common xz-embedded unpack200 quazip libUtil libSettings ${MultiMC_LINK_ADDITIONAL_LIBS})
|
||||
target_link_libraries(MultiMC_common xz-embedded unpack200 quazip libUtil ${MultiMC_LINK_ADDITIONAL_LIBS})
|
||||
qt5_use_modules(MultiMC Core Widgets Network Xml Concurrent ${MultiMC_QT_ADDITIONAL_MODULES})
|
||||
qt5_use_modules(MultiMC_common Core Widgets Network Xml Concurrent ${MultiMC_QT_ADDITIONAL_MODULES})
|
||||
|
||||
@@ -660,7 +758,7 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInf
|
||||
DIRECTORY "${QT_PLUGINS_DIR}/imageformats"
|
||||
DESTINATION ${PLUGIN_DEST_DIR}
|
||||
COMPONENT Runtime
|
||||
REGEX "tga|svg|tiff|mng" EXCLUDE
|
||||
REGEX "tga|tiff|mng" EXCLUDE
|
||||
)
|
||||
|
||||
# Platform plugins
|
||||
@@ -676,7 +774,7 @@ else()
|
||||
DIRECTORY "${QT_PLUGINS_DIR}/imageformats"
|
||||
DESTINATION ${PLUGIN_DEST_DIR}
|
||||
COMPONENT Runtime
|
||||
REGEX "tga|svg|tiff|mng" EXCLUDE
|
||||
REGEX "tga|tiff|mng" EXCLUDE
|
||||
REGEX "d\\." EXCLUDE
|
||||
REGEX "_debug\\." EXCLUDE
|
||||
)
|
||||
@@ -761,8 +859,6 @@ include(CPack)
|
||||
|
||||
include(Coverity)
|
||||
|
||||
include_directories(${PROJECT_BINARY_DIR}/include)
|
||||
|
||||
# Translations
|
||||
add_subdirectory(translations)
|
||||
|
||||
|
||||
375
HandleCrash.cpp
Normal file
375
HandleCrash.cpp
Normal file
@@ -0,0 +1,375 @@
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// This is the Unix implementation of MultiMC's crash handling system.
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <MultiMC.h>
|
||||
|
||||
#if defined Q_OS_UNIX
|
||||
#include <sys/utsname.h>
|
||||
#include <execinfo.h>
|
||||
#elif defined Q_OS_WIN32
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
#include <WinBacktrace.h>
|
||||
#endif
|
||||
|
||||
#include "BuildConfig.h"
|
||||
|
||||
#include "HandleCrash.h"
|
||||
|
||||
// The maximum number of frames to include in the backtrace.
|
||||
#define BT_SIZE 20
|
||||
|
||||
|
||||
#define DUMPF_NAME_FMT "mmc-crash-%X.bm" // Black magic? Bowel movement? Dump?
|
||||
// 1234567890 1234
|
||||
// The maximum number of digits in a unix timestamp when encoded in hexadecimal is about 17.
|
||||
// Our format string is ~14 characters long.
|
||||
// The maximum length of the dump file's filename should be well over both of these. 42 is a good number.
|
||||
#define DUMPF_NAME_LEN 42
|
||||
|
||||
// {{{ Platform hackery
|
||||
|
||||
#if defined Q_OS_UNIX
|
||||
|
||||
struct CrashData
|
||||
{
|
||||
int signal = 0;
|
||||
};
|
||||
|
||||
// This has to be declared here, after the CrashData struct, but before the function that uses it.
|
||||
void handleCrash(CrashData);
|
||||
|
||||
void handler(int sig)
|
||||
{
|
||||
CrashData cData;
|
||||
cData.signal = sig;
|
||||
handleCrash(cData);
|
||||
}
|
||||
|
||||
#elif defined Q_OS_WIN32
|
||||
|
||||
// Struct for storing platform specific crash information.
|
||||
// This gets passed into the generic handler, which will use
|
||||
// it to access platform specific information.
|
||||
struct CrashData
|
||||
{
|
||||
EXCEPTION_RECORD* exceptionInfo;
|
||||
CONTEXT* context;
|
||||
};
|
||||
|
||||
void handleCrash(CrashData);
|
||||
|
||||
LONG WINAPI ExceptionFilter(EXCEPTION_POINTERS* eInfo)
|
||||
{
|
||||
CrashData cData;
|
||||
cData.exceptionInfo = eInfo->ExceptionRecord;
|
||||
cData.context = eInfo->ContextRecord;
|
||||
handleCrash(cData);
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// }}}
|
||||
|
||||
// {{{ Handling
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
// #ThanksMicrosoft
|
||||
// Blame Microsoft for this atrocity.
|
||||
void dprintf(int fd, const char* fmt...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
char buffer[10240];
|
||||
// Just sprintf to a really long string and hope it works...
|
||||
// This is a hack, but I can't think of a better way to do it easily.
|
||||
int len = vsnprintf(buffer, 10240, fmt, args);
|
||||
printf(buffer, fmt, args);
|
||||
write(fd, buffer, len);
|
||||
va_end(args);
|
||||
}
|
||||
#endif
|
||||
|
||||
void getVsnType(char* out);
|
||||
void readFromTo(int from, int to);
|
||||
|
||||
void dumpErrorInfo(int dumpFile, CrashData crash)
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
// TODO: Moar unix
|
||||
dprintf(dumpFile, "Signal: %d\n", crash.signal);
|
||||
#elif defined Q_OS_WIN32
|
||||
EXCEPTION_RECORD* excInfo = crash.exceptionInfo;
|
||||
|
||||
dprintf(dumpFile, "Exception Code: %d\n", excInfo->ExceptionCode);
|
||||
dprintf(dumpFile, "Exception Address: 0x%0X\n", excInfo->ExceptionAddress);
|
||||
#endif
|
||||
}
|
||||
|
||||
void dumpMiscInfo(int dumpFile)
|
||||
{
|
||||
char vsnType[42]; // The version type. If it's more than 42 chars, the universe might implode...
|
||||
|
||||
// Get MMC info.
|
||||
getVsnType(vsnType);
|
||||
|
||||
// Get MMC info.
|
||||
getVsnType(vsnType);
|
||||
|
||||
dprintf(dumpFile, "MultiMC Version: %s\n", BuildConfig.VERSION_CSTR);
|
||||
dprintf(dumpFile, "MultiMC Version Type: %s\n", vsnType);
|
||||
}
|
||||
|
||||
void dumpBacktrace(int dumpFile, CrashData crash)
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
// Variables for storing crash info.
|
||||
void* trace[BT_SIZE]; // Backtrace frames
|
||||
size_t size; // The backtrace size
|
||||
|
||||
// Get the backtrace.
|
||||
size = backtrace(trace, BT_SIZE);
|
||||
|
||||
// Dump the backtrace
|
||||
dprintf(dumpFile, "---- BEGIN BACKTRACE ----\n");
|
||||
backtrace_symbols_fd(trace, size, dumpFile);
|
||||
dprintf(dumpFile, "---- END BACKTRACE ----\n");
|
||||
#elif defined Q_OS_WIN32
|
||||
dprintf(dumpFile, "---- BEGIN BACKTRACE ----\n");
|
||||
|
||||
StackFrame stack[BT_SIZE];
|
||||
size_t size;
|
||||
|
||||
SYMBOL_INFO *symbol;
|
||||
HANDLE process;
|
||||
|
||||
size = getBacktrace(stack, BT_SIZE, *crash.context);
|
||||
|
||||
// FIXME: Accessing heap memory is supposedly "dangerous",
|
||||
// but I can't find another way of doing this.
|
||||
|
||||
// Initialize
|
||||
process = GetCurrentProcess();
|
||||
if (!SymInitialize(process, NULL, true))
|
||||
{
|
||||
dprintf(dumpFile, "Failed to initialize symbol handler. Can't print stack trace.\n");
|
||||
dprintf(dumpFile, "Here's a list of addresses in the call stack instead:\n");
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
dprintf(dumpFile, "0x%0X\n", (DWORD64)stack[i].address);
|
||||
}
|
||||
} else {
|
||||
// Allocate memory... ._.
|
||||
symbol = (SYMBOL_INFO *) calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
|
||||
symbol->MaxNameLen = 255;
|
||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
|
||||
// Dump stacktrace
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
DWORD64 addr = (DWORD64)stack[i].address;
|
||||
if (!SymFromAddr(process, (DWORD64)(addr), 0, symbol))
|
||||
dprintf(dumpFile, "?? - 0x%0X\n", addr);
|
||||
else
|
||||
dprintf(dumpFile, "%s - 0x%0X\n", symbol->Name, symbol->Address);
|
||||
}
|
||||
|
||||
free(symbol);
|
||||
}
|
||||
|
||||
dprintf(dumpFile, "---- END BACKTRACE ----\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void dumpSysInfo(int dumpFile)
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
utsname sysinfo; // System information
|
||||
|
||||
// Dump system info
|
||||
if (uname(&sysinfo) >= 0)
|
||||
{
|
||||
dprintf(dumpFile, "OS System: %s\n", sysinfo.sysname);
|
||||
dprintf(dumpFile, "OS Machine: %s\n", sysinfo.machine);
|
||||
dprintf(dumpFile, "OS Release: %s\n", sysinfo.release);
|
||||
dprintf(dumpFile, "OS Version: %s\n", sysinfo.version);
|
||||
} else {
|
||||
dprintf(dumpFile, "OS System: Unknown Unix");
|
||||
}
|
||||
#else
|
||||
// TODO: Get more information here.
|
||||
dprintf(dumpFile, "OS System: Windows");
|
||||
#endif
|
||||
}
|
||||
|
||||
void dumpLogs(int dumpFile)
|
||||
{
|
||||
int otherFile;
|
||||
|
||||
// Attempt to attach the log file if the logger was initialized.
|
||||
dprintf(dumpFile, "---- BEGIN LOGS ----\n");
|
||||
if (loggerInitialized)
|
||||
{
|
||||
otherFile = open("MultiMC-0.log", O_RDONLY);
|
||||
readFromTo(otherFile, dumpFile);
|
||||
} else {
|
||||
dprintf(dumpFile, "Logger not initialized.\n");
|
||||
}
|
||||
dprintf(dumpFile, "---- END LOGS ----\n");
|
||||
}
|
||||
|
||||
// The signal handler. If this function is called, it means shit has probably collided with some sort of device one might use to keep oneself cool.
|
||||
// This is the generic part of the code that will be called after platform specific handling is finished.
|
||||
void handleCrash(CrashData crash)
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
fprintf(stderr, "Fatal error! Received signal %d\n", crash.signal);
|
||||
#endif
|
||||
|
||||
time_t unixTime = 0; // Unix timestamp. Used to give our crash dumps "unique" names.
|
||||
|
||||
char dumpFileName[DUMPF_NAME_LEN]; // The name of the file we're dumping to.
|
||||
int dumpFile; // File descriptor for our dump file.
|
||||
|
||||
// Determine what our dump file should be called.
|
||||
// We'll just call it "mmc-crash-<unixtime>.dump"
|
||||
// First, check the time.
|
||||
time(&unixTime);
|
||||
|
||||
// Now we get to do some !!FUN!! hackery to ensure we don't use the stack when we convert
|
||||
// the timestamp from an int to a string. To do this, we just allocate a fixed size array
|
||||
// of chars on the stack, and sprintf into it. We know the timestamp won't ever be longer
|
||||
// than a certain number of digits, so this should work just fine.
|
||||
// sprintf doesn't support writing signed values as hex, so this breaks on negative timestamps.
|
||||
// It really shouldn't matter, though...
|
||||
sprintf(dumpFileName, DUMPF_NAME_FMT, unixTime);
|
||||
|
||||
// Now, we need to open the file.
|
||||
// Fail if it already exists. This should never happen.
|
||||
dumpFile = open(dumpFileName, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
|
||||
|
||||
if (dumpFile >= 0)
|
||||
{
|
||||
// If we opened the dump file successfully.
|
||||
// Dump everything we can and GTFO.
|
||||
fprintf(stderr, "Dumping crash report to %s\n", dumpFileName);
|
||||
|
||||
// Dump misc info
|
||||
dprintf(dumpFile, "Unix Time: %d\n", unixTime);
|
||||
dumpErrorInfo(dumpFile, crash);
|
||||
dumpMiscInfo(dumpFile);
|
||||
|
||||
dprintf(dumpFile, "\n");
|
||||
|
||||
dumpSysInfo(dumpFile);
|
||||
|
||||
dprintf(dumpFile, "\n");
|
||||
|
||||
dumpBacktrace(dumpFile, crash);
|
||||
|
||||
dprintf(dumpFile, "\n");
|
||||
|
||||
// DIE DIE DIE!
|
||||
exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Failed to open dump file %s to write crash info (ERRNO: %d)\n", dumpFileName, errno);
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Reads data from the file descriptor on the first argument into the second argument.
|
||||
void readFromTo(int from, int to)
|
||||
{
|
||||
char buffer[1024];
|
||||
size_t lastread = 1;
|
||||
while (lastread > 0)
|
||||
{
|
||||
lastread = read(from, buffer, 1024);
|
||||
if (lastread > 0) write(to, buffer, lastread);
|
||||
}
|
||||
}
|
||||
|
||||
// Writes the current version type to the given char buffer.
|
||||
void getVsnType(char* out)
|
||||
{
|
||||
switch (BuildConfig.versionTypeEnum)
|
||||
{
|
||||
case Config::Release:
|
||||
sprintf(out, "Release");
|
||||
break;
|
||||
case Config::ReleaseCandidate:
|
||||
sprintf(out, "ReleaseCandidate");
|
||||
break;
|
||||
case Config::Development:
|
||||
sprintf(out, "Development");
|
||||
break;
|
||||
default:
|
||||
sprintf(out, "Unknown");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
// {{{ Misc
|
||||
|
||||
#if defined TEST_SEGV
|
||||
// Causes a crash. For testing.
|
||||
void testCrash()
|
||||
{
|
||||
char* lol = (char*)MMC->settings().get();
|
||||
lol -= 8;
|
||||
|
||||
// Throw shit at the fan.
|
||||
for (int i = 0; i < 8; i++)
|
||||
lol[i] = 'f';
|
||||
}
|
||||
#endif
|
||||
|
||||
// Initializes the Unix crash handler.
|
||||
void initBlackMagic()
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
// Register the handler.
|
||||
signal(SIGSEGV, handler);
|
||||
signal(SIGABRT, handler);
|
||||
#elif defined Q_OS_WIN32
|
||||
// I hate Windows
|
||||
SetUnhandledExceptionFilter(ExceptionFilter);
|
||||
#endif
|
||||
|
||||
#ifdef TEST_SEGV
|
||||
testCrash();
|
||||
#endif
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
18
HandleCrash.h
Normal file
18
HandleCrash.h
Normal file
@@ -0,0 +1,18 @@
|
||||
// This is a simple header file for the crash handling system. It exposes only one method,
|
||||
// initBlackMagic, which initializes the system, registering signal handlers, or doing
|
||||
// whatever stupid things need to be done on Windows.
|
||||
// The platform specific implementations for this system are in UnixCrash.cpp and
|
||||
// WinCrash.cpp.
|
||||
|
||||
#if defined Q_OS_WIN
|
||||
#warning Crash handling is not yet implemented on Windows.
|
||||
#elif defined Q_OS_UNIX
|
||||
#else
|
||||
#warning Crash handling is not supported on this platform.
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initializes the crash handling system.
|
||||
*/
|
||||
void initBlackMagic();
|
||||
|
||||
98
MultiMC.cpp
98
MultiMC.cpp
@@ -12,13 +12,14 @@
|
||||
#include <QDesktopServices>
|
||||
|
||||
#include "gui/dialogs/VersionSelectDialog.h"
|
||||
#include "logic/lists/InstanceList.h"
|
||||
#include "logic/InstanceList.h"
|
||||
#include "logic/auth/MojangAccountList.h"
|
||||
#include "logic/icons/IconList.h"
|
||||
#include "logic/lists/LwjglVersionList.h"
|
||||
#include "logic/lists/MinecraftVersionList.h"
|
||||
#include "logic/lists/ForgeVersionList.h"
|
||||
#include "logic/lists/LiteLoaderVersionList.h"
|
||||
#include "logic/LwjglVersionList.h"
|
||||
#include "logic/minecraft/MinecraftVersionList.h"
|
||||
#include "logic/liteloader/LiteLoaderVersionList.h"
|
||||
|
||||
#include "logic/forge/ForgeVersionList.h"
|
||||
|
||||
#include "logic/news/NewsChecker.h"
|
||||
|
||||
@@ -28,7 +29,7 @@
|
||||
#include "logic/net/HttpMetaCache.h"
|
||||
#include "logic/net/URLConstants.h"
|
||||
|
||||
#include "logic/JavaUtils.h"
|
||||
#include "logic/java/JavaUtils.h"
|
||||
|
||||
#include "logic/updater/UpdateChecker.h"
|
||||
#include "logic/updater/NotificationChecker.h"
|
||||
@@ -37,12 +38,14 @@
|
||||
#include "logic/tools/JVisualVM.h"
|
||||
#include "logic/tools/MCEditTool.h"
|
||||
|
||||
#include "logic/URNResolver.h"
|
||||
|
||||
#include "pathutils.h"
|
||||
#include "cmdutils.h"
|
||||
#include <inisettingsobject.h>
|
||||
#include <setting.h>
|
||||
#include "logic/settings/INISettingsObject.h"
|
||||
#include "logic/settings/Setting.h"
|
||||
#include "logger/QsLog.h"
|
||||
#include <logger/QsLogDest.h>
|
||||
#include "logger/QsLogDest.h"
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
#include <windows.h>
|
||||
@@ -86,6 +89,7 @@ MultiMC::MultiMC(int &argc, char **argv, bool root_override)
|
||||
parser.addShortOpt("launch", 'l');
|
||||
parser.addDocumentation("launch", "tries to launch the given instance", "<inst>");
|
||||
*/
|
||||
|
||||
// parse the arguments
|
||||
try
|
||||
{
|
||||
@@ -161,6 +165,17 @@ MultiMC::MultiMC(int &argc, char **argv, bool root_override)
|
||||
#endif
|
||||
}
|
||||
|
||||
// static data paths... mostly just for translations
|
||||
#ifdef Q_OS_LINUX
|
||||
QDir foo(PathCombine(binPath, ".."));
|
||||
staticDataPath = foo.absolutePath();
|
||||
#elif defined(Q_OS_WIN32)
|
||||
staticDataPath = binPath;
|
||||
#elif defined(Q_OS_MAC)
|
||||
QDir foo(PathCombine(rootPath, "Contents/Resources"));
|
||||
staticDataPath = foo.absolutePath();
|
||||
#endif
|
||||
|
||||
// init the logger
|
||||
initLogger();
|
||||
|
||||
@@ -179,6 +194,7 @@ MultiMC::MultiMC(int &argc, char **argv, bool root_override)
|
||||
}
|
||||
QLOG_INFO() << "Binary path : " << binPath;
|
||||
QLOG_INFO() << "Application root path : " << rootPath;
|
||||
QLOG_INFO() << "Static data path : " << staticDataPath;
|
||||
|
||||
// load settings
|
||||
initGlobalSettings();
|
||||
@@ -203,7 +219,7 @@ MultiMC::MultiMC(int &argc, char **argv, bool root_override)
|
||||
m_instances.reset(new InstanceList(InstDirSetting->get().toString(), this));
|
||||
QLOG_INFO() << "Loading Instances...";
|
||||
m_instances->loadList();
|
||||
connect(InstDirSetting.get(), SIGNAL(settingChanged(const Setting &, QVariant)),
|
||||
connect(InstDirSetting.get(), SIGNAL(SettingChanged(const Setting &, QVariant)),
|
||||
m_instances.get(), SLOT(on_InstFolderChanged(const Setting &, QVariant)));
|
||||
|
||||
// and accounts
|
||||
@@ -287,7 +303,8 @@ void MultiMC::initTranslations()
|
||||
}
|
||||
|
||||
m_mmc_translator.reset(new QTranslator());
|
||||
if (m_mmc_translator->load("mmc_" + locale.bcp47Name(), MMC->root() + "/translations"))
|
||||
if (m_mmc_translator->load("mmc_" + locale.bcp47Name(),
|
||||
MMC->staticData() + "/translations"))
|
||||
{
|
||||
QLOG_DEBUG() << "Loading MMC Language File for"
|
||||
<< locale.bcp47Name().toLocal8Bit().constData() << "...";
|
||||
@@ -322,50 +339,80 @@ void MultiMC::initLogger()
|
||||
QsLogging::Logger &logger = QsLogging::Logger::instance();
|
||||
logger.setLoggingLevel(QsLogging::TraceLevel);
|
||||
m_fileDestination = QsLogging::DestinationFactory::MakeFileDestination(logBase.arg(0));
|
||||
m_debugDestination = QsLogging::DestinationFactory::MakeQDebugDestination();
|
||||
m_debugDestination = QsLogging::DestinationFactory::MakeDebugOutputDestination();
|
||||
logger.addDestination(m_fileDestination.get());
|
||||
logger.addDestination(m_debugDestination.get());
|
||||
// log all the things
|
||||
logger.setLoggingLevel(QsLogging::TraceLevel);
|
||||
loggerInitialized = true;
|
||||
}
|
||||
|
||||
bool loggerInitialized = false;
|
||||
|
||||
void MultiMC::initGlobalSettings()
|
||||
{
|
||||
m_settings.reset(new INISettingsObject("multimc.cfg", this));
|
||||
// Updates
|
||||
m_settings->registerSetting("UpdateChannel", BuildConfig.VERSION_CHANNEL);
|
||||
m_settings->registerSetting("AutoUpdate", true);
|
||||
m_settings->registerSetting("IconTheme", QString("multimc"));
|
||||
|
||||
// Notifications
|
||||
m_settings->registerSetting("ShownNotifications", QString());
|
||||
|
||||
// FTB
|
||||
m_settings->registerSetting("TrackFTBInstances", false);
|
||||
QString ftbDataDefault;
|
||||
#ifdef Q_OS_LINUX
|
||||
QString ftbDefault = QDir::home().absoluteFilePath(".ftblauncher");
|
||||
QString ftbDefault = ftbDataDefault = QDir::home().absoluteFilePath(".ftblauncher");
|
||||
#elif defined(Q_OS_WIN32)
|
||||
wchar_t buf[APPDATA_BUFFER_SIZE];
|
||||
QString ftbDefault;
|
||||
if(!GetEnvironmentVariableW(L"APPDATA", buf, APPDATA_BUFFER_SIZE))
|
||||
wchar_t newBuf[APPDATA_BUFFER_SIZE];
|
||||
QString ftbDefault, newFtbDefault, oldFtbDefault;
|
||||
if (!GetEnvironmentVariableW(L"LOCALAPPDATA", newBuf, APPDATA_BUFFER_SIZE))
|
||||
{
|
||||
QLOG_FATAL() << "Your LOCALAPPDATA folder is missing! If you are on windows, this means your system is broken. If you aren't on windows, how the **** are you running the windows build????";
|
||||
}
|
||||
else
|
||||
{
|
||||
newFtbDefault = QDir(QString::fromWCharArray(newBuf)).absoluteFilePath("ftblauncher");
|
||||
}
|
||||
if (!GetEnvironmentVariableW(L"APPDATA", buf, APPDATA_BUFFER_SIZE))
|
||||
{
|
||||
QLOG_FATAL() << "Your APPDATA folder is missing! If you are on windows, this means your system is broken. If you aren't on windows, how the **** are you running the windows build????";
|
||||
}
|
||||
else
|
||||
{
|
||||
ftbDefault = PathCombine(QString::fromWCharArray(buf), "ftblauncher");
|
||||
oldFtbDefault = QDir(QString::fromWCharArray(buf)).absoluteFilePath("ftblauncher");
|
||||
}
|
||||
if (QFile::exists(QDir(newFtbDefault).absoluteFilePath("ftblaunch.cfg")))
|
||||
{
|
||||
QLOG_INFO() << "Old FTB setup";
|
||||
ftbDefault = ftbDataDefault = oldFtbDefault;
|
||||
}
|
||||
else
|
||||
{
|
||||
QLOG_INFO() << "New FTB setup";
|
||||
ftbDefault = oldFtbDefault;
|
||||
ftbDataDefault = newFtbDefault;
|
||||
}
|
||||
#elif defined(Q_OS_MAC)
|
||||
QString ftbDefault =
|
||||
PathCombine(QDir::homePath(), "Library/Application Support/ftblauncher");
|
||||
QString ftbDefault = ftbDataDefault =
|
||||
PathCombine(QDir::homePath(), "Library/Application Support/ftblauncher");
|
||||
#endif
|
||||
m_settings->registerSetting("FTBLauncherDataRoot", ftbDataDefault);
|
||||
m_settings->registerSetting("FTBLauncherRoot", ftbDefault);
|
||||
QLOG_INFO() << "FTB Launcher paths:"
|
||||
<< m_settings->get("FTBLauncherDataRoot").toString()
|
||||
<< "and"
|
||||
<< m_settings->get("FTBLauncherRoot").toString();
|
||||
|
||||
m_settings->registerSetting("FTBRoot");
|
||||
if (m_settings->get("FTBRoot").isNull())
|
||||
{
|
||||
QString ftbRoot;
|
||||
QFile f(QDir(m_settings->get("FTBLauncherRoot").toString())
|
||||
.absoluteFilePath("ftblaunch.cfg"));
|
||||
.absoluteFilePath("ftblaunch.cfg"));
|
||||
QLOG_INFO() << "Attempting to read" << f.fileName();
|
||||
if (f.open(QFile::ReadOnly))
|
||||
{
|
||||
@@ -441,6 +488,7 @@ void MultiMC::initGlobalSettings()
|
||||
// Java Settings
|
||||
m_settings->registerSetting("JavaPath", "");
|
||||
m_settings->registerSetting("LastHostname", "");
|
||||
m_settings->registerSetting("JavaDetectionHack", "");
|
||||
m_settings->registerSetting("JvmArgs", "");
|
||||
|
||||
// Custom Commands
|
||||
@@ -461,6 +509,8 @@ void MultiMC::initGlobalSettings()
|
||||
m_settings->registerSetting("ConsoleWindowGeometry", "");
|
||||
|
||||
m_settings->registerSetting("SettingsGeometry", "");
|
||||
|
||||
m_settings->registerSetting("PagedGeometry", "");
|
||||
}
|
||||
|
||||
void MultiMC::initHttpMetaCache()
|
||||
@@ -600,6 +650,16 @@ std::shared_ptr<JavaVersionList> MultiMC::javalist()
|
||||
return m_javalist;
|
||||
}
|
||||
|
||||
std::shared_ptr<URNResolver> MultiMC::resolver()
|
||||
{
|
||||
if (!m_resolver)
|
||||
{
|
||||
m_resolver.reset(new URNResolver());
|
||||
}
|
||||
return m_resolver;
|
||||
}
|
||||
|
||||
|
||||
void MultiMC::installUpdates(const QString updateFilesDir, UpdateFlags flags)
|
||||
{
|
||||
// if we are going to update on exit, save the params now
|
||||
|
||||
24
MultiMC.h
24
MultiMC.h
@@ -23,21 +23,13 @@ class NewsChecker;
|
||||
class StatusChecker;
|
||||
class BaseProfilerFactory;
|
||||
class BaseDetachedToolFactory;
|
||||
class URNResolver;
|
||||
|
||||
#if defined(MMC)
|
||||
#undef MMC
|
||||
#endif
|
||||
#define MMC (static_cast<MultiMC *>(QCoreApplication::instance()))
|
||||
|
||||
// FIXME: possibly move elsewhere
|
||||
enum InstSortMode
|
||||
{
|
||||
// Sort alphabetically by name.
|
||||
Sort_Name,
|
||||
// Sort by which instance was launched most recently.
|
||||
Sort_LastLaunch
|
||||
};
|
||||
|
||||
enum UpdateFlag
|
||||
{
|
||||
None = 0x0,
|
||||
@@ -48,6 +40,9 @@ enum UpdateFlag
|
||||
Q_DECLARE_FLAGS(UpdateFlags, UpdateFlag);
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(UpdateFlags);
|
||||
|
||||
// Global var used by the crash handling system to determine if a log file should be included in a crash report.
|
||||
extern bool loggerInitialized;
|
||||
|
||||
class MultiMC : public QApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -125,6 +120,8 @@ public:
|
||||
|
||||
std::shared_ptr<JavaVersionList> javalist();
|
||||
|
||||
std::shared_ptr<URNResolver> resolver();
|
||||
|
||||
QMap<QString, std::shared_ptr<BaseProfilerFactory>> profilers()
|
||||
{
|
||||
return m_profilers;
|
||||
@@ -147,6 +144,11 @@ public:
|
||||
*/
|
||||
bool openJsonEditor(const QString &filename);
|
||||
|
||||
/// this is the static data. it stores things that don't move.
|
||||
const QString &staticData()
|
||||
{
|
||||
return staticDataPath;
|
||||
}
|
||||
/// this is the root of the 'installation'. Used for automatic updates
|
||||
const QString &root()
|
||||
{
|
||||
@@ -206,8 +208,11 @@ private:
|
||||
std::shared_ptr<LiteLoaderVersionList> m_liteloaderlist;
|
||||
std::shared_ptr<MinecraftVersionList> m_minecraftlist;
|
||||
std::shared_ptr<JavaVersionList> m_javalist;
|
||||
std::shared_ptr<URNResolver> m_resolver;
|
||||
|
||||
QMap<QString, std::shared_ptr<BaseProfilerFactory>> m_profilers;
|
||||
QMap<QString, std::shared_ptr<BaseDetachedToolFactory>> m_tools;
|
||||
|
||||
QsLogging::DestinationPtr m_fileDestination;
|
||||
QsLogging::DestinationPtr m_debugDestination;
|
||||
|
||||
@@ -215,6 +220,7 @@ private:
|
||||
UpdateFlags m_updateOnExitFlags = None;
|
||||
|
||||
QString rootPath;
|
||||
QString staticDataPath;
|
||||
QString binPath;
|
||||
QString dataPath;
|
||||
QString origcwdPath;
|
||||
|
||||
77
WinBacktrace.cpp
Normal file
77
WinBacktrace.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// CAUTION:
|
||||
// This file contains all manner of hackery and insanity.
|
||||
// I will not be responsible for any loss of sanity due to reading this code.
|
||||
// Here be dragons!
|
||||
|
||||
#include "WinBacktrace.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#ifndef __i386__
|
||||
#error WinBacktrace is only supported on x86 architectures.
|
||||
#endif
|
||||
|
||||
// We need to do some crazy shit to walk through the stack.
|
||||
// Windows unwinds the stack when an exception is thrown, so we
|
||||
// need to examine the EXCEPTION_POINTERS's CONTEXT.
|
||||
size_t getBacktrace(StackFrame *stack, size_t size, CONTEXT ctx)
|
||||
{
|
||||
// Written using information and a bit of pseudocode from
|
||||
// http://www.eptacom.net/pubblicazioni/pub_eng/except.html
|
||||
// This is probably one of the most horrifying things I've ever written.
|
||||
|
||||
// This tracks whether the current EBP is valid.
|
||||
// When an invalid EBP is encountered, we stop walking the stack.
|
||||
bool validEBP = true;
|
||||
DWORD ebp = ctx.Ebp; // The current EBP (Extended Base Pointer)
|
||||
DWORD eip = ctx.Eip;
|
||||
int i;
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
if (ebp & 3)
|
||||
validEBP = false;
|
||||
// FIXME: This function is obsolete, according to MSDN.
|
||||
else if (IsBadReadPtr((void*) ebp, 8))
|
||||
validEBP = false;
|
||||
|
||||
if (!validEBP) break;
|
||||
|
||||
// Find the caller.
|
||||
// On the first iteration, the caller is whatever EIP points to.
|
||||
// On successive iterations, the caller is the byte after EBP.
|
||||
BYTE* caller = !i ? (BYTE*)eip : *((BYTE**) ebp + 1);
|
||||
// The first ebp is the EBP from the CONTEXT.
|
||||
// On successive iterations, the EBP is the DWORD that the previous EBP points to.
|
||||
ebp = !i ? ebp : *(DWORD*)ebp;
|
||||
|
||||
// Find the caller's module.
|
||||
// We'll use VirtualQuery to get information about the caller's address.
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
VirtualQuery(caller, &mbi, sizeof(mbi));
|
||||
|
||||
// We can get the instance handle from the allocation base.
|
||||
HINSTANCE hInst = (HINSTANCE)mbi.AllocationBase;
|
||||
|
||||
// If the handle is 0, then the EBP is invalid.
|
||||
if (hInst == 0) validEBP = false;
|
||||
// Otherwise, dump info about the caller.
|
||||
else stack[i].address = (void*)caller;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
44
WinBacktrace.h
Normal file
44
WinBacktrace.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#ifndef SF_STR_LEN
|
||||
// The max length of all strings in the StackFrame struct.
|
||||
// Because it must be stack allocated, this must be known at compile time.
|
||||
// Stuff longer than this will be truncated.
|
||||
// Defaults to 4096 (4kB)
|
||||
#define SF_STR_LEN 4096
|
||||
#endif
|
||||
|
||||
// Data structure for holding information about a stack frame.
|
||||
// There's some more hackery in here so it can be allocated on the stack.
|
||||
struct StackFrame
|
||||
{
|
||||
// The address of this stack frame.
|
||||
void* address;
|
||||
|
||||
// The name of the function at this address.
|
||||
char funcName[SF_STR_LEN];
|
||||
};
|
||||
|
||||
// This function walks through the given CONTEXT structure, extracting a
|
||||
// backtrace from it.
|
||||
// The backtrace will be put into the array given by the `stack` argument
|
||||
// with a maximum length of `size`.
|
||||
// This function returns the size of the backtrace retrieved.
|
||||
size_t getBacktrace(StackFrame* stack, size_t size, CONTEXT ctx);
|
||||
120
changelog.md
Normal file
120
changelog.md
Normal file
@@ -0,0 +1,120 @@
|
||||
#MultiMC Changelog
|
||||
|
||||
##0.4.0
|
||||
- Jar support in 1.6+
|
||||
- Deprecated legacy instances
|
||||
- Legacy instances can still be used but not created
|
||||
- All Minecraft versions are supported in the new instance format
|
||||
- All instance editing and settings dialogs were turned into pages
|
||||
- The edit instance dialog contains pages relevant to editing and settings
|
||||
- The console window contains pages useful when playing the game
|
||||
- Redone the screenshot management and upload (page)
|
||||
- Added a way to display and manage log files and crash reports generated by Minecraft (page)
|
||||
- Added measures to prevent corruption of version files
|
||||
- Minecraft version files are no longer part of the instances by default
|
||||
- Added help for the newly added dialog pages
|
||||
- Made logs uploaded to paste.ee expire after a month
|
||||
- Fixed a few bugs related to liteloader and forge (1.7.10 issues)
|
||||
- Icon themes. Two new themes where added (work in progress)
|
||||
- Changelog and update channel are now visible in the update dialog
|
||||
- Several performance improvements to the group view
|
||||
- Added keyboard navigation to the group view
|
||||
|
||||
##0.3.9
|
||||
- Workaround for 1.7.10 Forge
|
||||
|
||||
##0.3.8
|
||||
- Workaround for performance issues with Intel integrated graphics chips
|
||||
|
||||
##0.3.7
|
||||
- Fixed forge for 1.7.10-pre4 (and any future prereleases)
|
||||
|
||||
##0.3.6
|
||||
- New server status - now with more color
|
||||
- Fix for FTB tracking issues
|
||||
- Fix for translations on OSX not working
|
||||
- Screenshot dialog should be harder to lose track of when used from the console window
|
||||
- A crash handler implementation has been added.
|
||||
|
||||
##0.3.5
|
||||
- More versions are now selectable when changing instance versions
|
||||
- Fix for Forge/FML changing its mcmod.info metadata format
|
||||
|
||||
##0.3.4
|
||||
- Show a list of Patreon patrons in credits section of the about dialog
|
||||
- Make the console window raise itself after minecraft closes
|
||||
- Add Control/Command+q shortcut to quit from the main window
|
||||
- Add french translation
|
||||
- Download and cache FML libs for legacy versions
|
||||
- Update the OS X icon
|
||||
- Fix FTB libraries not being used properly
|
||||
|
||||
##0.3.3
|
||||
- Tweak context menu to prevent accidental clicks
|
||||
- Fix adding icons to custom icon directories
|
||||
- Added a Patreon button to the toolbar
|
||||
- Minecraft authentication tasks now provide better error reports
|
||||
|
||||
##0.3.2
|
||||
- Fix issues with libraries not getting replaced properly (fixes instance startup for new instances)
|
||||
- Fix april fools
|
||||
|
||||
##0.3.1
|
||||
- Fix copying of FTB instances (instance type is changed properly now)
|
||||
- Customizing FTB pack versions will remove the FTB pack patch file
|
||||
|
||||
##0.3
|
||||
- Improved instance view
|
||||
- Overhauled 1.6+ version loading
|
||||
- Added a patch system for instance modification
|
||||
- There is no longer a single custom.json file that overrides version.json
|
||||
- Instead there are now "patch" files in <instance>/patches/, one for each main tweaker (forge, liteloader etc.)
|
||||
- These patches are applied after version.json in a customisable order,
|
||||
- A list of these files is shown in the left most tab in the Edit Mods dialog, where a list of libraries was shown before.
|
||||
- custom.json can still be used for overriding everything.
|
||||
- Offline mode can be used even when online
|
||||
- Show an "empty" message in version selector dialogs
|
||||
- Fix FTB paths on windows
|
||||
- Tooling support
|
||||
- JProfiler
|
||||
- JVisualVM
|
||||
- MCEdit
|
||||
- Don't assume forge in FTB instances and allow other libraries (liteloader, mcpatcher, etc.) in FTB instances
|
||||
- Screenshot uploading/managing
|
||||
- Instance badges
|
||||
- Some pre/post command stuff (remove the timeout, variable substitution)
|
||||
- Fix logging when the system language is not en_US
|
||||
- Setting PermGen to 64 will now omit the java parameter because it is the default
|
||||
- Fix encoding of escape sequences (tabs and newlines) in config files
|
||||
|
||||
##0.2.1
|
||||
- Hotfix - move the native library extraction into the onesix launcher part.
|
||||
|
||||
##0.2
|
||||
- Java memory settings have MB added to the number to make the units obvious.
|
||||
- Complete rework of the launcher part. No more sensitive information in the process arguments.
|
||||
- Cached downloads now do not destroy files on failure.
|
||||
- Mojang service status is now on the MultiMC status bar.
|
||||
- Java checker is no longer needed/used on instance launch.
|
||||
- Support for private FTB packs.
|
||||
- Fixed instance ID issues related to copying FTB packs without changing the instance name.
|
||||
- Forge versions are better sorted (build numbers above 999 were sorted wrong).
|
||||
- Fixed crash related to the MultiMC update channel picker in offline mode.
|
||||
- Started using icon themes for the application icons, fixing many OSX graphical glitches.
|
||||
- Icon sources have been located, along with icon licenses.
|
||||
- Update to the German translation.
|
||||
|
||||
##0.1.1
|
||||
- Hotfix - Changed the issue tracker URL to [GitHub issues](https://github.com/MultiMC/MultiMC5/issues).
|
||||
|
||||
##0.1
|
||||
- Reworked the version numbering system to support our [new Git workflow](http://nvie.com/posts/a-successful-git-branching-model/).
|
||||
- Added a tray icon for the console window.
|
||||
- Fixed instances getting deselected after FTB instances are loaded (or whenever the model is reset).
|
||||
- Implemented proxy settings.
|
||||
- Fixed sorting of Java installations in the Java list.
|
||||
- Jar files are now distributed separately, rather than being extracted from the binary at runtime.
|
||||
- Added additional information to the about dialog.
|
||||
|
||||
##0.0
|
||||
- Initial release.
|
||||
@@ -1,78 +0,0 @@
|
||||
#
|
||||
# This is MultiMC's changelog. It is formatted in YAML.
|
||||
#
|
||||
# Each key below represents a release version name. Each release key has several string entries under it, each containing information about a single change. Each of these entries may contain Markdown for formatting.
|
||||
#
|
||||
|
||||
0.0:
|
||||
- Initial release.
|
||||
0.1:
|
||||
- Reworked the version numbering system to support our [new Git workflow](http://nvie.com/posts/a-successful-git-branching-model/).
|
||||
- Added a tray icon for the console window.
|
||||
- Fixed instances getting deselected after FTB instances are loaded (or whenever the model is reset).
|
||||
- Implemented proxy settings.
|
||||
- Fixed sorting of Java installations in the Java list.
|
||||
- Jar files are now distributed separately, rather than being extracted from the binary at runtime.
|
||||
- Added additional information to the about dialog.
|
||||
0.1.1:
|
||||
- Hotfix - Changed the issue tracker URL to [GitHub issues](https://github.com/MultiMC/MultiMC5/issues).
|
||||
0.2:
|
||||
- Java memory settings have MB added to the number to make the units obvious.
|
||||
- Complete rework of the launcher part. No more sensitive information in the process arguments.
|
||||
- Cached downloads now do not destroy files on failure.
|
||||
- Mojang service status is now on the MultiMC status bar.
|
||||
- Java checker is no longer needed/used on instance launch.
|
||||
- Support for private FTB packs.
|
||||
- Fixed instance ID issues related to copying FTB packs without changing the instance name.
|
||||
- Forge versions are better sorted (build numbers above 999 were sorted wrong).
|
||||
- Fixed crash related to the MultiMC update channel picker in offline mode.
|
||||
- Started using icon themes for the application icons, fixing many OSX graphical glitches.
|
||||
- Icon sources have been located, along with icon licenses.
|
||||
- Update to the German translation.
|
||||
0.2.1:
|
||||
- Hotfix - move the native library extraction into the onesix launcher part.
|
||||
0.3:
|
||||
- Improved instance view
|
||||
- Overhauled 1.6+ version loading
|
||||
- Added a patch system for instance modification
|
||||
- There is no longer a single custom.json file that overrides version.json
|
||||
- Instead there are now "patch" files in <instance>/patches/, one for each main tweaker (forge, liteloader etc.)
|
||||
- These patches are applied after version.json in a customisable order,
|
||||
- A list of these files is shown in the left most tab in the Edit Mods dialog, where a list of libraries was shown before.
|
||||
- custom.json can still be used for overriding everything.
|
||||
- Offline mode can be used even when online
|
||||
- Show an "empty" message in version selector dialogs
|
||||
- Fix FTB paths on windows
|
||||
- Tooling support
|
||||
- JProfiler
|
||||
- JVisualVM
|
||||
- MCEdit
|
||||
- Don't assume forge in FTB instances and allow other libraries (liteloader, mcpatcher, etc.) in FTB instances
|
||||
- Screenshot uploading/managing
|
||||
- Instance badges
|
||||
- Some pre/post command stuff (remove the timeout, variable substitution)
|
||||
- Fix logging when the system language is not en_US
|
||||
- Setting PermGen to 64 will now omit the java parameter because it is the default
|
||||
- Fix encoding of escape sequences (tabs and newlines) in config files
|
||||
0.3.1:
|
||||
- Fix copying of FTB instances (instance type is changed properly now)
|
||||
- Customizing FTB pack versions will remove the FTB pack patch file
|
||||
0.3.2:
|
||||
- Fix issues with libraries not getting replaced properly (fixes instance startup for new instances)
|
||||
- Fix april fools
|
||||
0.3.3:
|
||||
- Tweak context menu to prevent accidental clicks
|
||||
- Fix adding icons to custom icon directories
|
||||
- Added a Patreon button to the toolbar
|
||||
- Minecraft authentication tasks now provide better error reports
|
||||
0.3.4:
|
||||
- Show a list of Patreon patrons in credits section of the about dialog
|
||||
- Make the console window raise itself after minecraft closes
|
||||
- Add Control/Command+q shortcut to quit from the main window
|
||||
- Add french translation
|
||||
- Download and cache FML libs for legacy versions
|
||||
- Update the OS X icon
|
||||
- Fix FTB libraries not being used properly
|
||||
0.3.5
|
||||
- More versions are now selectable when changing instance versions
|
||||
- Fix for Forge/FML changing its mcmod.info metadata format
|
||||
@@ -18,7 +18,7 @@ set(SRC
|
||||
# The launcher has to be there for silly FML/Forge relauncher.
|
||||
net/minecraft/Launcher.java
|
||||
org/multimc/legacy/LegacyLauncher.java
|
||||
org/multimc/legacy/LegacyFrame.java
|
||||
org/multimc/LegacyFrame.java
|
||||
|
||||
# onesix launcher
|
||||
org/multimc/onesix/OneSixLauncher.java
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.awt.BorderLayout;
|
||||
import java.awt.Graphics;
|
||||
import java.applet.Applet;
|
||||
import java.applet.AppletStub;
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
public class Launcher extends Applet implements AppletStub
|
||||
{
|
||||
@@ -130,13 +131,23 @@ public class Launcher extends Applet implements AppletStub
|
||||
|
||||
@Override
|
||||
public URL getCodeBase() {
|
||||
return wrappedApplet.getCodeBase();
|
||||
try {
|
||||
return new URL("http://www.minecraft.net/game/");
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getDocumentBase()
|
||||
{
|
||||
return documentBase;
|
||||
try {
|
||||
return new URL("http://www.minecraft.net/game/");
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.multimc.legacy;/*
|
||||
package org.multimc;/*
|
||||
* Copyright 2012-2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,10 +14,7 @@ package org.multimc.legacy;/*
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import org.multimc.Launcher;
|
||||
import org.multimc.NotFoundException;
|
||||
import org.multimc.ParamBucket;
|
||||
import org.multimc.Utils;
|
||||
import org.multimc.*;
|
||||
|
||||
import java.applet.Applet;
|
||||
import java.awt.*;
|
||||
|
||||
@@ -17,128 +17,185 @@ package org.multimc.onesix;
|
||||
|
||||
import org.multimc.*;
|
||||
|
||||
import java.applet.Applet;
|
||||
import java.io.File;
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class OneSixLauncher implements Launcher
|
||||
{
|
||||
@Override
|
||||
public int launch(ParamBucket params)
|
||||
// parameters, separated from ParamBucket
|
||||
private List<String> libraries;
|
||||
private List<String> extlibs;
|
||||
private List<String> mcparams;
|
||||
private List<String> mods;
|
||||
private List<String> traits;
|
||||
private String appletClass;
|
||||
private String mainClass;
|
||||
private String natives;
|
||||
private String userName, sessionId;
|
||||
private String windowTitle;
|
||||
private String windowParams;
|
||||
|
||||
// secondary parameters
|
||||
private Dimension winSize;
|
||||
private boolean maximize;
|
||||
private String cwd;
|
||||
|
||||
// the much abused system classloader, for convenience (for further abuse)
|
||||
private ClassLoader cl;
|
||||
|
||||
private void processParams(ParamBucket params) throws NotFoundException
|
||||
{
|
||||
// get and process the launch script params
|
||||
List<String> libraries;
|
||||
List<String> extlibs;
|
||||
List<String> mcparams;
|
||||
List<String> mods;
|
||||
String mainClass;
|
||||
String natives;
|
||||
final String windowTitle;
|
||||
String windowParams;
|
||||
try
|
||||
{
|
||||
libraries = params.all("cp");
|
||||
extlibs = params.all("ext");
|
||||
mcparams = params.all("param");
|
||||
mainClass = params.first("mainClass");
|
||||
mods = params.allSafe("mods", new ArrayList<String>());
|
||||
natives = params.first("natives");
|
||||
libraries = params.all("cp");
|
||||
extlibs = params.all("ext");
|
||||
mcparams = params.allSafe("param", new ArrayList<String>() );
|
||||
mainClass = params.firstSafe("mainClass", "net.minecraft.client.Minecraft");
|
||||
appletClass = params.firstSafe("appletClass", "net.minecraft.client.MinecraftApplet");
|
||||
mods = params.allSafe("mods", new ArrayList<String>());
|
||||
traits = params.allSafe("traits", new ArrayList<String>());
|
||||
natives = params.first("natives");
|
||||
|
||||
windowTitle = params.first("windowTitle");
|
||||
// windowParams = params.first("windowParams");
|
||||
} catch (NotFoundException e)
|
||||
userName = params.first("userName");
|
||||
sessionId = params.first("sessionId");
|
||||
windowTitle = params.firstSafe("windowTitle", "Minecraft");
|
||||
windowParams = params.firstSafe("windowParams", "854x480");
|
||||
|
||||
cwd = System.getProperty("user.dir");
|
||||
winSize = new Dimension(854, 480);
|
||||
maximize = false;
|
||||
|
||||
String[] dimStrings = windowParams.split("x");
|
||||
|
||||
if (windowParams.equalsIgnoreCase("max"))
|
||||
{
|
||||
System.err.println("Not enough arguments.");
|
||||
e.printStackTrace(System.err);
|
||||
return -1;
|
||||
maximize = true;
|
||||
}
|
||||
|
||||
List<String> allJars = new ArrayList<String>();
|
||||
allJars.addAll(mods);
|
||||
allJars.addAll(libraries);
|
||||
|
||||
if(!Utils.addToClassPath(allJars))
|
||||
else if (dimStrings.length == 2)
|
||||
{
|
||||
System.err.println("Halting launch due to previous errors.");
|
||||
return -1;
|
||||
try
|
||||
{
|
||||
winSize = new Dimension(Integer.parseInt(dimStrings[0]), Integer.parseInt(dimStrings[1]));
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
private void printStats()
|
||||
{
|
||||
Utils.log("Main Class:");
|
||||
Utils.log(" " + mainClass);
|
||||
Utils.log();
|
||||
|
||||
// print the pretty things
|
||||
Utils.log("Native path:");
|
||||
Utils.log(" " + natives);
|
||||
Utils.log();
|
||||
|
||||
Utils.log("Traits:");
|
||||
Utils.log(" " + traits);
|
||||
Utils.log();
|
||||
|
||||
Utils.log("Libraries:");
|
||||
for (String s : libraries)
|
||||
{
|
||||
Utils.log("Main Class:");
|
||||
Utils.log(" " + mainClass);
|
||||
Utils.log();
|
||||
Utils.log(" " + s);
|
||||
}
|
||||
Utils.log();
|
||||
|
||||
Utils.log("Native path:");
|
||||
Utils.log(" " + natives);
|
||||
Utils.log();
|
||||
|
||||
Utils.log("Libraries:");
|
||||
for (String s : libraries)
|
||||
if(mods.size() > 0)
|
||||
{
|
||||
Utils.log("Class Path Mods:");
|
||||
for (String s : mods)
|
||||
{
|
||||
Utils.log(" " + s);
|
||||
}
|
||||
Utils.log();
|
||||
|
||||
if(mods.size() > 0)
|
||||
{
|
||||
Utils.log("Class Path Mods:");
|
||||
for (String s : mods)
|
||||
{
|
||||
Utils.log(" " + s);
|
||||
}
|
||||
Utils.log();
|
||||
}
|
||||
|
||||
Utils.log("Params:");
|
||||
Utils.log(" " + mcparams.toString());
|
||||
Utils.log();
|
||||
}
|
||||
|
||||
// set up the natives path(s).
|
||||
Utils.log("Preparing native libraries...");
|
||||
String property = System.getProperty("os.arch");
|
||||
boolean is_64 = property.equalsIgnoreCase("x86_64") || property.equalsIgnoreCase("amd64");
|
||||
for(String extlib: extlibs)
|
||||
{
|
||||
try
|
||||
{
|
||||
String cleanlib = extlib.replace("${arch}", is_64 ? "64" : "32");
|
||||
File cleanlibf = new File(cleanlib);
|
||||
Utils.log("Extracting " + cleanlibf.getName());
|
||||
Utils.unzip(cleanlibf, new File(natives));
|
||||
} catch (IOException e)
|
||||
{
|
||||
System.err.println("Failed to extract native library:");
|
||||
e.printStackTrace(System.err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
Utils.log("Params:");
|
||||
Utils.log(" " + mcparams.toString());
|
||||
Utils.log();
|
||||
|
||||
System.setProperty("java.library.path", natives);
|
||||
Field fieldSysPath;
|
||||
}
|
||||
|
||||
int legacyLaunch()
|
||||
{
|
||||
// Get the Minecraft Class and set the base folder
|
||||
Class<?> mc;
|
||||
try
|
||||
{
|
||||
fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
|
||||
fieldSysPath.setAccessible( true );
|
||||
fieldSysPath.set( null, null );
|
||||
mc = cl.loadClass(mainClass);
|
||||
|
||||
Field f = Utils.getMCPathField(mc);
|
||||
|
||||
if (f == null)
|
||||
{
|
||||
System.err.println("Could not find Minecraft path field.");
|
||||
}
|
||||
else
|
||||
{
|
||||
f.setAccessible(true);
|
||||
f.set(null, new File(cwd));
|
||||
}
|
||||
} catch (Exception e)
|
||||
{
|
||||
System.err.println("Failed to set the native library path:");
|
||||
System.err.println("Could not set base folder. Failed to find/access Minecraft main class:");
|
||||
e.printStackTrace(System.err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
System.setProperty("minecraft.applet.TargetDirectory", cwd);
|
||||
|
||||
String[] mcArgs = new String[2];
|
||||
mcArgs[0] = userName;
|
||||
mcArgs[1] = sessionId;
|
||||
|
||||
Utils.log("Launching with applet wrapper...");
|
||||
try
|
||||
{
|
||||
Class<?> MCAppletClass = cl.loadClass(appletClass);
|
||||
Applet mcappl = (Applet) MCAppletClass.newInstance();
|
||||
LegacyFrame mcWindow = new LegacyFrame(windowTitle);
|
||||
mcWindow.start(mcappl, userName, sessionId, winSize, maximize);
|
||||
} catch (Exception e)
|
||||
{
|
||||
Utils.log("Applet wrapper failed:", "Error");
|
||||
e.printStackTrace(System.err);
|
||||
Utils.log();
|
||||
Utils.log("Falling back to compatibility mode.");
|
||||
try
|
||||
{
|
||||
mc.getMethod("main", String[].class).invoke(null, (Object) mcArgs);
|
||||
} catch (Exception e1)
|
||||
{
|
||||
Utils.log("Failed to invoke the Minecraft main class:", "Fatal");
|
||||
e1.printStackTrace(System.err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int launchWithMainClass()
|
||||
{
|
||||
// window size, title and state, onesix
|
||||
if (maximize)
|
||||
{
|
||||
// FIXME: there is no good way to maximize the minecraft window in onesix.
|
||||
// the following often breaks linux screen setups
|
||||
// mcparams.add("--fullscreen");
|
||||
}
|
||||
else
|
||||
{
|
||||
mcparams.add("--width");
|
||||
mcparams.add(Integer.toString(winSize.width));
|
||||
mcparams.add("--height");
|
||||
mcparams.add(Integer.toString(winSize.height));
|
||||
}
|
||||
|
||||
// Get the Minecraft Class.
|
||||
final ClassLoader cl = ClassLoader.getSystemClassLoader();
|
||||
Class<?> mc;
|
||||
try
|
||||
{
|
||||
@@ -161,9 +218,7 @@ public class OneSixLauncher implements Launcher
|
||||
e.printStackTrace(System.err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// FIXME: works only on linux, we need a better solution
|
||||
/*
|
||||
/*
|
||||
final java.nio.ByteBuffer[] icons = IconLoader.load("icon.png");
|
||||
new Thread() {
|
||||
public void run() {
|
||||
@@ -174,18 +229,21 @@ public class OneSixLauncher implements Launcher
|
||||
Method isCreated;
|
||||
Method setTitle;
|
||||
Method setIcon;
|
||||
|
||||
Field fieldWindowCreated;
|
||||
Boolean created = false;
|
||||
Display = cl.loadClass("org.lwjgl.opengl.Display");
|
||||
isCreated = Display.getMethod("isCreated");
|
||||
fieldWindowCreated = Display.getDeclaredField("window_created");
|
||||
fieldWindowCreated.setAccessible( true );
|
||||
setTitle = Display.getMethod("setTitle", String.class);
|
||||
setIcon = Display.getMethod("setIcon", java.nio.ByteBuffer[].class);
|
||||
|
||||
created = (Boolean) fieldWindowCreated.get( null );
|
||||
// set the window title? Maybe?
|
||||
while(!(Boolean) isCreated.invoke(null))
|
||||
while(!created)
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(150);
|
||||
created = (Boolean) fieldWindowCreated.get( null );
|
||||
} catch (InterruptedException ignored) {}
|
||||
}
|
||||
// Give it a bit more time ;)
|
||||
@@ -206,12 +264,13 @@ public class OneSixLauncher implements Launcher
|
||||
}
|
||||
}
|
||||
.start();
|
||||
*/
|
||||
// start Minecraft
|
||||
String[] paramsArray = mcparams.toArray(new String[mcparams.size()]); // init params accordingly
|
||||
*/
|
||||
// init params for the main method to chomp on.
|
||||
String[] paramsArray = mcparams.toArray(new String[mcparams.size()]);
|
||||
try
|
||||
{
|
||||
meth.invoke(null, (Object) paramsArray); // static method doesn't have an instance
|
||||
// static method doesn't have an instance
|
||||
meth.invoke(null, (Object) paramsArray);
|
||||
} catch (Exception e)
|
||||
{
|
||||
System.err.println("Failed to start Minecraft:");
|
||||
@@ -220,4 +279,88 @@ public class OneSixLauncher implements Launcher
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int launch(ParamBucket params)
|
||||
{
|
||||
// get and process the launch script params
|
||||
try
|
||||
{
|
||||
processParams(params);
|
||||
} catch (NotFoundException e)
|
||||
{
|
||||
System.err.println("Not enough arguments.");
|
||||
e.printStackTrace(System.err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// do some horrible black magic with the classpath
|
||||
{
|
||||
List<String> allJars = new ArrayList<String>();
|
||||
allJars.addAll(mods);
|
||||
allJars.addAll(libraries);
|
||||
|
||||
if(!Utils.addToClassPath(allJars))
|
||||
{
|
||||
System.err.println("Halting launch due to previous errors.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// print the pretty things
|
||||
printStats();
|
||||
|
||||
// extract native libs (depending on platform here... java!)
|
||||
Utils.log("Preparing native libraries...");
|
||||
String property = System.getProperty("os.arch");
|
||||
boolean is_64 = property.equalsIgnoreCase("x86_64") || property.equalsIgnoreCase("amd64");
|
||||
for(String extlib: extlibs)
|
||||
{
|
||||
try
|
||||
{
|
||||
String cleanlib = extlib.replace("${arch}", is_64 ? "64" : "32");
|
||||
File cleanlibf = new File(cleanlib);
|
||||
Utils.log("Extracting " + cleanlibf.getName());
|
||||
Utils.unzip(cleanlibf, new File(natives));
|
||||
} catch (IOException e)
|
||||
{
|
||||
System.err.println("Failed to extract native library:");
|
||||
e.printStackTrace(System.err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
Utils.log();
|
||||
|
||||
// set the native libs path... the brute force way
|
||||
try
|
||||
{
|
||||
System.setProperty("java.library.path", natives);
|
||||
System.setProperty("org.lwjgl.librarypath", natives);
|
||||
System.setProperty("net.java.games.input.librarypath", natives);
|
||||
// by the power of reflection, initialize native libs again. DIRTY!
|
||||
// this is SO BAD. imagine doing that to ld
|
||||
Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
|
||||
fieldSysPath.setAccessible( true );
|
||||
fieldSysPath.set( null, null );
|
||||
} catch (Exception e)
|
||||
{
|
||||
System.err.println("Failed to set the native library path:");
|
||||
e.printStackTrace(System.err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// grab the system classloader and ...
|
||||
cl = ClassLoader.getSystemClassLoader();
|
||||
|
||||
if (traits.contains("legacyLaunch") || traits.contains("alphaLaunch") )
|
||||
{
|
||||
// legacy launch uses the applet wrapper
|
||||
return legacyLaunch();
|
||||
}
|
||||
else
|
||||
{
|
||||
// normal launch just calls main()
|
||||
return launchWithMainClass();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,9 @@
|
||||
|
||||
extern coding basic_codings[];
|
||||
|
||||
// CODING_PRIVATE causes a lot of them
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
|
||||
#define CODING_PRIVATE(spec) \
|
||||
int spec_ = spec; \
|
||||
int B = CODING_B(spec_); \
|
||||
|
||||
@@ -1245,7 +1245,7 @@ extern int ZEXPORT unzReadCurrentFile (file, buf, len)
|
||||
return UNZ_PARAMERROR;
|
||||
|
||||
|
||||
if ((pfile_in_zip_read_info->read_buffer == NULL))
|
||||
if (pfile_in_zip_read_info->read_buffer == NULL)
|
||||
return UNZ_END_OF_LIST_OF_FILE;
|
||||
if (len==0)
|
||||
return 0;
|
||||
|
||||
@@ -777,9 +777,9 @@ extern int ZEXPORT zipOpenNewFileInZip3 (file, filename, zipfi,
|
||||
zi->ci.flag = 0;
|
||||
if ((level==8) || (level==9))
|
||||
zi->ci.flag |= 2;
|
||||
if ((level==2))
|
||||
if (level==2)
|
||||
zi->ci.flag |= 4;
|
||||
if ((level==1))
|
||||
if (level==1)
|
||||
zi->ci.flag |= 6;
|
||||
if (password != NULL)
|
||||
{
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
project(libSettings)
|
||||
|
||||
# Find Qt
|
||||
find_package(Qt5Core REQUIRED)
|
||||
|
||||
# Include Qt headers.
|
||||
include_directories(${Qt5Base_INCLUDE_DIRS})
|
||||
|
||||
include(UseCXX11)
|
||||
include(Coverage)
|
||||
|
||||
set(LIBSETTINGS_SOURCES
|
||||
libsettings_config.h
|
||||
|
||||
inifile.h
|
||||
inifile.cpp
|
||||
|
||||
settingsobject.h
|
||||
settingsobject.cpp
|
||||
inisettingsobject.h
|
||||
inisettingsobject.cpp
|
||||
|
||||
setting.h
|
||||
setting.cpp
|
||||
overridesetting.h
|
||||
overridesetting.cpp
|
||||
)
|
||||
|
||||
# Set the include dir path.
|
||||
set(LIBSETTINGS_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE)
|
||||
|
||||
# Static link!
|
||||
add_definitions(-DLIBSETTINGS_STATIC)
|
||||
|
||||
add_definitions(-DLIBSETTINGS_LIBRARY)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
add_library(libSettings STATIC ${LIBSETTINGS_SOURCES})
|
||||
qt5_use_modules(libSettings Core)
|
||||
target_link_libraries(libSettings)
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <QDir>
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
#include <QDebug>
|
||||
|
||||
QString PathCombine(QString path1, QString path2)
|
||||
{
|
||||
@@ -138,10 +137,10 @@ void openDirInDefaultProgram(QString path, bool ensureExists)
|
||||
{
|
||||
parentPath.mkpath(dir.absolutePath());
|
||||
}
|
||||
QDesktopServices::openUrl("file:///" + dir.absolutePath());
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath()));
|
||||
}
|
||||
|
||||
void openFileInDefaultProgram(QString filename)
|
||||
{
|
||||
QDesktopServices::openUrl("file:///" + QFileInfo(filename).absolutePath());
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(filename));
|
||||
}
|
||||
|
||||
@@ -75,7 +75,6 @@ bool Util::createShortCut(QString location, QString dest, QStringList args, QStr
|
||||
{
|
||||
#if LINUX
|
||||
location = PathCombine(location, name + ".desktop");
|
||||
qDebug("location: %s", qPrintable(location));
|
||||
|
||||
QFile f(location);
|
||||
f.open(QIODevice::WriteOnly | QIODevice::Text);
|
||||
|
||||
@@ -14,64 +14,130 @@
|
||||
*/
|
||||
|
||||
#include "ConsoleWindow.h"
|
||||
#include "ui_ConsoleWindow.h"
|
||||
#include "MultiMC.h"
|
||||
|
||||
#include <QScrollBar>
|
||||
#include <QMessageBox>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <qlayoutitem.h>
|
||||
|
||||
#include <gui/Platform.h>
|
||||
#include <gui/dialogs/CustomMessageBox.h>
|
||||
#include <gui/dialogs/ProgressDialog.h>
|
||||
#include "widgets/PageContainer.h"
|
||||
#include "pages/LogPage.h"
|
||||
|
||||
#include "logic/net/PasteUpload.h"
|
||||
#include "logic/icons/IconList.h"
|
||||
|
||||
class LogPageProvider : public BasePageProvider
|
||||
{
|
||||
public:
|
||||
LogPageProvider(BasePageProviderPtr parent, BasePage * log_page)
|
||||
{
|
||||
m_parent = parent;
|
||||
m_log_page = log_page;
|
||||
}
|
||||
virtual QString dialogTitle() {return "Fake";};
|
||||
virtual QList<BasePage *> getPages()
|
||||
{
|
||||
auto pages = m_parent->getPages();
|
||||
pages.prepend(m_log_page);
|
||||
return pages;
|
||||
}
|
||||
private:
|
||||
BasePageProviderPtr m_parent;
|
||||
BasePage * m_log_page;
|
||||
};
|
||||
|
||||
ConsoleWindow::ConsoleWindow(MinecraftProcess *mcproc, QWidget *parent)
|
||||
: QMainWindow(parent), ui(new Ui::ConsoleWindow), proc(mcproc)
|
||||
: QMainWindow(parent), m_proc(mcproc)
|
||||
{
|
||||
MultiMCPlatform::fixWM_CLASS(this);
|
||||
ui->setupUi(this);
|
||||
connect(mcproc, SIGNAL(log(QString, MessageLevel::Enum)), this,
|
||||
SLOT(write(QString, MessageLevel::Enum)));
|
||||
connect(mcproc, SIGNAL(ended(BaseInstance *, int, QProcess::ExitStatus)), this,
|
||||
SLOT(onEnded(BaseInstance *, int, QProcess::ExitStatus)));
|
||||
connect(mcproc, SIGNAL(prelaunch_failed(BaseInstance *, int, QProcess::ExitStatus)), this,
|
||||
SLOT(onEnded(BaseInstance *, int, QProcess::ExitStatus)));
|
||||
connect(mcproc, SIGNAL(launch_failed(BaseInstance *)), this,
|
||||
SLOT(onLaunchFailed(BaseInstance *)));
|
||||
|
||||
connect(ui->btnScreenshots, &QPushButton::clicked, this, &ConsoleWindow::uploadScreenshots);
|
||||
auto instance = m_proc->instance();
|
||||
auto icon = MMC->icons()->getIcon(instance->iconKey());
|
||||
QString windowTitle = tr("Console window for ") + instance->name();
|
||||
|
||||
restoreState(
|
||||
QByteArray::fromBase64(MMC->settings()->get("ConsoleWindowState").toByteArray()));
|
||||
restoreGeometry(
|
||||
QByteArray::fromBase64(MMC->settings()->get("ConsoleWindowGeometry").toByteArray()));
|
||||
// Set window properties
|
||||
{
|
||||
setWindowIcon(icon);
|
||||
setWindowTitle(windowTitle);
|
||||
}
|
||||
|
||||
QString iconKey = proc->instance()->iconKey();
|
||||
QString name = proc->instance()->name();
|
||||
auto icon = MMC->icons()->getIcon(iconKey);
|
||||
setWindowIcon(icon);
|
||||
m_trayIcon = new QSystemTrayIcon(icon, this);
|
||||
// TODO add screenshot upload as a menu item in the tray icon
|
||||
QString consoleTitle = tr("Console window for ") + name;
|
||||
m_trayIcon->setToolTip(consoleTitle);
|
||||
setWindowTitle(consoleTitle);
|
||||
// Add page container
|
||||
{
|
||||
auto mainLayout = new QVBoxLayout;
|
||||
auto provider = std::dynamic_pointer_cast<BasePageProvider>(m_proc->instance());
|
||||
auto proxy_provider = std::make_shared<LogPageProvider>(provider, new LogPage(m_proc));
|
||||
m_container = new PageContainer(proxy_provider, "console", this);
|
||||
mainLayout->addWidget(m_container);
|
||||
mainLayout->setSpacing(0);
|
||||
mainLayout->setContentsMargins(0,0,0,0);
|
||||
setLayout(mainLayout);
|
||||
setCentralWidget(m_container);
|
||||
}
|
||||
|
||||
// Add custom buttons to the page container layout.
|
||||
{
|
||||
auto horizontalLayout = new QHBoxLayout();
|
||||
horizontalLayout->setObjectName(QStringLiteral("horizontalLayout"));
|
||||
horizontalLayout->setContentsMargins(6, -1, 6, -1);
|
||||
|
||||
auto btnHelp = new QPushButton();
|
||||
btnHelp->setText(tr("Help"));
|
||||
horizontalLayout->addWidget(btnHelp);
|
||||
connect(btnHelp, SIGNAL(clicked(bool)), m_container, SLOT(help()));
|
||||
|
||||
auto spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
horizontalLayout->addSpacerItem(spacer);
|
||||
|
||||
m_killButton = new QPushButton();
|
||||
m_killButton->setText(tr("Kill Minecraft"));
|
||||
horizontalLayout->addWidget(m_killButton);
|
||||
connect(m_killButton, SIGNAL(clicked(bool)), SLOT(on_btnKillMinecraft_clicked()));
|
||||
|
||||
m_closeButton = new QPushButton();
|
||||
m_closeButton->setText(tr("Close"));
|
||||
horizontalLayout->addWidget(m_closeButton);
|
||||
connect(m_closeButton, SIGNAL(clicked(bool)), SLOT(on_closeButton_clicked()));
|
||||
|
||||
m_container->addButtons(horizontalLayout);
|
||||
}
|
||||
|
||||
// restore window state
|
||||
{
|
||||
auto base64State = MMC->settings()->get("ConsoleWindowState").toByteArray();
|
||||
restoreState(QByteArray::fromBase64(base64State));
|
||||
auto base64Geometry = MMC->settings()->get("ConsoleWindowGeometry").toByteArray();
|
||||
restoreGeometry(QByteArray::fromBase64(base64Geometry));
|
||||
}
|
||||
|
||||
// Set up tray icon
|
||||
{
|
||||
m_trayIcon = new QSystemTrayIcon(icon, this);
|
||||
m_trayIcon->setToolTip(windowTitle);
|
||||
|
||||
connect(m_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
|
||||
SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
|
||||
m_trayIcon->show();
|
||||
}
|
||||
|
||||
// Set up signal connections
|
||||
connect(mcproc, SIGNAL(ended(InstancePtr, int, QProcess::ExitStatus)), this,
|
||||
SLOT(onEnded(InstancePtr, int, QProcess::ExitStatus)));
|
||||
connect(mcproc, SIGNAL(prelaunch_failed(InstancePtr, int, QProcess::ExitStatus)), this,
|
||||
SLOT(onEnded(InstancePtr, int, QProcess::ExitStatus)));
|
||||
connect(mcproc, SIGNAL(launch_failed(InstancePtr)), this,
|
||||
SLOT(onLaunchFailed(InstancePtr)));
|
||||
|
||||
setMayClose(false);
|
||||
|
||||
connect(m_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
|
||||
SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
|
||||
m_trayIcon->show();
|
||||
if (mcproc->instance()->settings().get("ShowConsole").toBool())
|
||||
{
|
||||
show();
|
||||
}
|
||||
setMayClose(false);
|
||||
}
|
||||
|
||||
ConsoleWindow::~ConsoleWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ConsoleWindow::iconActivated(QSystemTrayIcon::ActivationReason reason)
|
||||
@@ -87,86 +153,6 @@ void ConsoleWindow::iconActivated(QSystemTrayIcon::ActivationReason reason)
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleWindow::writeColor(QString text, const char *color, const char * background)
|
||||
{
|
||||
// append a paragraph
|
||||
QString newtext;
|
||||
newtext += "<span style=\"";
|
||||
{
|
||||
if (color)
|
||||
newtext += QString("color:") + color + ";";
|
||||
if (background)
|
||||
newtext += QString("background-color:") + background + ";";
|
||||
newtext += "font-family: monospace;";
|
||||
}
|
||||
newtext += "\">";
|
||||
newtext += text.toHtmlEscaped();
|
||||
newtext += "</span>";
|
||||
ui->text->appendHtml(newtext);
|
||||
}
|
||||
|
||||
void ConsoleWindow::write(QString data, MessageLevel::Enum mode)
|
||||
{
|
||||
QScrollBar *bar = ui->text->verticalScrollBar();
|
||||
int max_bar = bar->maximum();
|
||||
int val_bar = bar->value();
|
||||
if(isVisible())
|
||||
{
|
||||
if (m_scroll_active)
|
||||
{
|
||||
m_scroll_active = (max_bar - val_bar) <= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_scroll_active = val_bar == max_bar;
|
||||
}
|
||||
}
|
||||
if (data.endsWith('\n'))
|
||||
data = data.left(data.length() - 1);
|
||||
QStringList paragraphs = data.split('\n');
|
||||
for (QString ¶graph : paragraphs)
|
||||
{
|
||||
paragraph = paragraph.trimmed();
|
||||
}
|
||||
|
||||
QListIterator<QString> iter(paragraphs);
|
||||
if (mode == MessageLevel::MultiMC)
|
||||
while (iter.hasNext())
|
||||
writeColor(iter.next(), "blue", 0);
|
||||
else if (mode == MessageLevel::Error)
|
||||
while (iter.hasNext())
|
||||
writeColor(iter.next(), "red", 0);
|
||||
else if (mode == MessageLevel::Warning)
|
||||
while (iter.hasNext())
|
||||
writeColor(iter.next(), "orange", 0);
|
||||
else if (mode == MessageLevel::Fatal)
|
||||
while (iter.hasNext())
|
||||
writeColor(iter.next(), "red", "black");
|
||||
else if (mode == MessageLevel::Debug)
|
||||
while (iter.hasNext())
|
||||
writeColor(iter.next(), "green", 0);
|
||||
else if (mode == MessageLevel::PrePost)
|
||||
while (iter.hasNext())
|
||||
writeColor(iter.next(), "grey", 0);
|
||||
// TODO: implement other MessageLevels
|
||||
else
|
||||
while (iter.hasNext())
|
||||
writeColor(iter.next(), 0, 0);
|
||||
if(isVisible())
|
||||
{
|
||||
if (m_scroll_active)
|
||||
{
|
||||
bar->setValue(bar->maximum());
|
||||
}
|
||||
m_last_scroll_value = bar->value();
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleWindow::clear()
|
||||
{
|
||||
ui->text->clear();
|
||||
}
|
||||
|
||||
void ConsoleWindow::on_closeButton_clicked()
|
||||
{
|
||||
close();
|
||||
@@ -175,15 +161,15 @@ void ConsoleWindow::on_closeButton_clicked()
|
||||
void ConsoleWindow::setMayClose(bool mayclose)
|
||||
{
|
||||
if(mayclose)
|
||||
ui->closeButton->setText(tr("Close"));
|
||||
m_closeButton->setText(tr("Close"));
|
||||
else
|
||||
ui->closeButton->setText(tr("Hide"));
|
||||
m_closeButton->setText(tr("Hide"));
|
||||
m_mayclose = mayclose;
|
||||
}
|
||||
|
||||
void ConsoleWindow::toggleConsole()
|
||||
{
|
||||
QScrollBar *bar = ui->text->verticalScrollBar();
|
||||
//QScrollBar *bar = ui->text->verticalScrollBar();
|
||||
if (isVisible())
|
||||
{
|
||||
if(!isActiveWindow())
|
||||
@@ -191,15 +177,17 @@ void ConsoleWindow::toggleConsole()
|
||||
activateWindow();
|
||||
return;
|
||||
}
|
||||
/*
|
||||
int max_bar = bar->maximum();
|
||||
int val_bar = m_last_scroll_value = bar->value();
|
||||
m_scroll_active = (max_bar - val_bar) <= 1;
|
||||
*/
|
||||
hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
show();
|
||||
isTopLevel();
|
||||
/*
|
||||
if (m_scroll_active)
|
||||
{
|
||||
bar->setValue(bar->maximum());
|
||||
@@ -208,6 +196,7 @@ void ConsoleWindow::toggleConsole()
|
||||
{
|
||||
bar->setValue(m_last_scroll_value);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,7 +206,7 @@ void ConsoleWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
toggleConsole();
|
||||
}
|
||||
else
|
||||
else if(m_container->requestClose(event))
|
||||
{
|
||||
MMC->settings()->set("ConsoleWindowState", saveState().toBase64());
|
||||
MMC->settings()->set("ConsoleWindowGeometry", saveGeometry().toBase64());
|
||||
@@ -230,25 +219,23 @@ void ConsoleWindow::closeEvent(QCloseEvent *event)
|
||||
|
||||
void ConsoleWindow::on_btnKillMinecraft_clicked()
|
||||
{
|
||||
ui->btnKillMinecraft->setEnabled(false);
|
||||
m_killButton->setEnabled(false);
|
||||
auto response = CustomMessageBox::selectable(
|
||||
this, tr("Kill Minecraft?"),
|
||||
tr("This can cause the instance to get corrupted and should only be used if Minecraft "
|
||||
"is frozen for some reason"),
|
||||
QMessageBox::Question, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)->exec();
|
||||
if (response == QMessageBox::Yes)
|
||||
proc->killMinecraft();
|
||||
m_proc->killMinecraft();
|
||||
else
|
||||
ui->btnKillMinecraft->setEnabled(true);
|
||||
m_killButton->setEnabled(true);
|
||||
}
|
||||
|
||||
void ConsoleWindow::onEnded(BaseInstance *instance, int code, QProcess::ExitStatus status)
|
||||
void ConsoleWindow::onEnded(InstancePtr instance, int code, QProcess::ExitStatus status)
|
||||
{
|
||||
bool peacefulExit = code == 0 && status != QProcess::CrashExit;
|
||||
ui->btnKillMinecraft->setEnabled(false);
|
||||
|
||||
m_killButton->setEnabled(false);
|
||||
setMayClose(true);
|
||||
|
||||
if (instance->settings().get("AutoCloseConsole").toBool())
|
||||
{
|
||||
if (peacefulExit)
|
||||
@@ -257,15 +244,8 @@ void ConsoleWindow::onEnded(BaseInstance *instance, int code, QProcess::ExitStat
|
||||
return;
|
||||
}
|
||||
}
|
||||
/*
|
||||
if(!peacefulExit)
|
||||
{
|
||||
m_trayIcon->showMessage(tr("Oh no!"), tr("Minecraft crashed!"), QSystemTrayIcon::Critical);
|
||||
}
|
||||
*/
|
||||
if (!isVisible())
|
||||
show();
|
||||
|
||||
// Raise Window
|
||||
if (MMC->settings()->get("RaiseConsole").toBool())
|
||||
{
|
||||
@@ -274,25 +254,12 @@ void ConsoleWindow::onEnded(BaseInstance *instance, int code, QProcess::ExitStat
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleWindow::onLaunchFailed(BaseInstance *instance)
|
||||
void ConsoleWindow::onLaunchFailed(InstancePtr instance)
|
||||
{
|
||||
ui->btnKillMinecraft->setEnabled(false);
|
||||
m_killButton->setEnabled(false);
|
||||
|
||||
setMayClose(true);
|
||||
|
||||
if (!isVisible())
|
||||
show();
|
||||
}
|
||||
|
||||
void ConsoleWindow::on_btnPaste_clicked()
|
||||
{
|
||||
auto text = ui->text->toPlainText();
|
||||
ProgressDialog dialog(this);
|
||||
PasteUpload *paste = new PasteUpload(this, text);
|
||||
dialog.exec(paste);
|
||||
if (!paste->successful())
|
||||
{
|
||||
CustomMessageBox::selectable(this, "Upload failed", paste->failReason(),
|
||||
QMessageBox::Critical)->exec();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,18 +19,15 @@
|
||||
#include <QSystemTrayIcon>
|
||||
#include "logic/MinecraftProcess.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class ConsoleWindow;
|
||||
}
|
||||
|
||||
class QPushButton;
|
||||
class PageContainer;
|
||||
class ConsoleWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConsoleWindow(MinecraftProcess *proc, QWidget *parent = 0);
|
||||
~ConsoleWindow();
|
||||
virtual ~ConsoleWindow() {};
|
||||
|
||||
/**
|
||||
* @brief specify if the window is allowed to close
|
||||
@@ -39,57 +36,30 @@ public:
|
||||
*/
|
||||
void setMayClose(bool mayclose);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief write a colored paragraph
|
||||
* @param data the string
|
||||
* @param color the css color name
|
||||
* this will only insert a single paragraph.
|
||||
* \n are ignored. a real \n is always appended.
|
||||
*/
|
||||
void writeColor(QString text, const char *color, const char *background);
|
||||
|
||||
signals:
|
||||
void isClosing();
|
||||
void uploadScreenshots();
|
||||
|
||||
public
|
||||
slots:
|
||||
/**
|
||||
* @brief write a string
|
||||
* @param data the string
|
||||
* @param mode the WriteMode
|
||||
* lines have to be put through this as a whole!
|
||||
*/
|
||||
void write(QString data, MessageLevel::Enum level = MessageLevel::MultiMC);
|
||||
|
||||
/**
|
||||
* @brief clear the text widget
|
||||
*/
|
||||
void clear();
|
||||
|
||||
private
|
||||
slots:
|
||||
void on_closeButton_clicked();
|
||||
void on_btnKillMinecraft_clicked();
|
||||
void onEnded(BaseInstance *instance, int code, QProcess::ExitStatus status);
|
||||
void onLaunchFailed(BaseInstance *instance);
|
||||
|
||||
void onEnded(InstancePtr instance, int code, QProcess::ExitStatus status);
|
||||
void onLaunchFailed(InstancePtr instance);
|
||||
|
||||
// FIXME: add handlers for the other MinecraftProcess signals (pre/post launch command
|
||||
// failures)
|
||||
|
||||
void on_btnPaste_clicked();
|
||||
void iconActivated(QSystemTrayIcon::ActivationReason);
|
||||
void toggleConsole();
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *);
|
||||
|
||||
private:
|
||||
Ui::ConsoleWindow *ui = nullptr;
|
||||
MinecraftProcess *proc = nullptr;
|
||||
MinecraftProcess *m_proc = nullptr;
|
||||
bool m_mayclose = true;
|
||||
int m_last_scroll_value = 0;
|
||||
bool m_scroll_active = true;
|
||||
QSystemTrayIcon *m_trayIcon = nullptr;
|
||||
int m_saved_offset = 0;
|
||||
PageContainer *m_container = nullptr;
|
||||
QPushButton *m_closeButton = nullptr;
|
||||
QPushButton *m_killButton = nullptr;
|
||||
};
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ConsoleWindow</class>
|
||||
<widget class="QMainWindow" name="ConsoleWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>640</width>
|
||||
<height>440</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MultiMC Console</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="text">
|
||||
<property name="undoRedoEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="plainText">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
<property name="centerOnScroll">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnPaste">
|
||||
<property name="text">
|
||||
<string>Upload Log</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnScreenshots">
|
||||
<property name="text">
|
||||
<string>Manage Screenshots</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnKillMinecraft">
|
||||
<property name="text">
|
||||
<string>&Kill Minecraft</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="closeButton">
|
||||
<property name="text">
|
||||
<string>&Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
38
gui/GuiUtil.cpp
Normal file
38
gui/GuiUtil.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#include "GuiUtil.h"
|
||||
|
||||
#include <QClipboard>
|
||||
#include <QDesktopServices>
|
||||
#include <QApplication>
|
||||
|
||||
#include "dialogs/ProgressDialog.h"
|
||||
#include "logic/net/PasteUpload.h"
|
||||
#include "dialogs/CustomMessageBox.h"
|
||||
|
||||
void GuiUtil::uploadPaste(const QString &text, QWidget *parentWidget)
|
||||
{
|
||||
ProgressDialog dialog(parentWidget);
|
||||
PasteUpload *paste = new PasteUpload(parentWidget, text);
|
||||
dialog.exec(paste);
|
||||
if (!paste->successful())
|
||||
{
|
||||
CustomMessageBox::selectable(parentWidget, "Upload failed", paste->failReason(),
|
||||
QMessageBox::Critical)->exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
const QString link = paste->pasteLink();
|
||||
setClipboardText(link);
|
||||
QDesktopServices::openUrl(link);
|
||||
CustomMessageBox::selectable(
|
||||
parentWidget, QObject::tr("Upload finished"),
|
||||
QObject::tr("The <a href=\"%1\">link to the uploaded log</a> has been opened in the default "
|
||||
"browser and placed in your clipboard.").arg(link),
|
||||
QMessageBox::Information)->exec();
|
||||
}
|
||||
delete paste;
|
||||
}
|
||||
|
||||
void GuiUtil::setClipboardText(const QString &text)
|
||||
{
|
||||
QApplication::clipboard()->setText(text);
|
||||
}
|
||||
9
gui/GuiUtil.h
Normal file
9
gui/GuiUtil.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace GuiUtil
|
||||
{
|
||||
void uploadPaste(const QString &text, QWidget *parentWidget);
|
||||
void setClipboardText(const QString &text);
|
||||
}
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "gui/Platform.h"
|
||||
|
||||
#include "gui/widgets/LabeledToolButton.h"
|
||||
#include "widgets/ServerStatus.h"
|
||||
|
||||
#include "gui/dialogs/SettingsDialog.h"
|
||||
#include "gui/dialogs/NewInstanceDialog.h"
|
||||
@@ -55,24 +56,22 @@
|
||||
#include "gui/dialogs/VersionSelectDialog.h"
|
||||
#include "gui/dialogs/CustomMessageBox.h"
|
||||
#include "gui/dialogs/LwjglSelectDialog.h"
|
||||
#include "gui/dialogs/InstanceSettings.h"
|
||||
#include "gui/dialogs/IconPickerDialog.h"
|
||||
#include "gui/dialogs/EditNotesDialog.h"
|
||||
#include "gui/dialogs/CopyInstanceDialog.h"
|
||||
#include "gui/dialogs/AccountListDialog.h"
|
||||
#include "gui/dialogs/AccountSelectDialog.h"
|
||||
#include "gui/dialogs/UpdateDialog.h"
|
||||
#include "gui/dialogs/EditAccountDialog.h"
|
||||
#include "gui/dialogs/ScreenshotDialog.h"
|
||||
#include "gui/dialogs/NotificationDialog.h"
|
||||
|
||||
#include "gui/ConsoleWindow.h"
|
||||
#include "pagedialog/PageDialog.h"
|
||||
|
||||
#include "logic/lists/InstanceList.h"
|
||||
#include "logic/lists/MinecraftVersionList.h"
|
||||
#include "logic/lists/LwjglVersionList.h"
|
||||
#include "logic/InstanceList.h"
|
||||
#include "logic/minecraft/MinecraftVersionList.h"
|
||||
#include "logic/LwjglVersionList.h"
|
||||
#include "logic/icons/IconList.h"
|
||||
#include "logic/lists/JavaVersionList.h"
|
||||
#include "logic/java/JavaVersionList.h"
|
||||
|
||||
#include "logic/auth/flows/AuthenticateTask.h"
|
||||
#include "logic/auth/flows/RefreshTask.h"
|
||||
@@ -90,7 +89,7 @@
|
||||
#include "logic/InstanceFactory.h"
|
||||
#include "logic/MinecraftProcess.h"
|
||||
#include "logic/OneSixUpdate.h"
|
||||
#include "logic/JavaUtils.h"
|
||||
#include "logic/java/JavaUtils.h"
|
||||
#include "logic/NagUtils.h"
|
||||
#include "logic/SkinUtils.h"
|
||||
|
||||
@@ -109,7 +108,8 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
|
||||
MultiMCPlatform::fixWM_CLASS(this);
|
||||
ui->setupUi(this);
|
||||
|
||||
QString winTitle = QString("MultiMC 5 - Version %1").arg(BuildConfig.printableVersionString());
|
||||
QString winTitle =
|
||||
QString("MultiMC 5 - Version %1").arg(BuildConfig.printableVersionString());
|
||||
if (!BuildConfig.BUILD_PLATFORM.isEmpty())
|
||||
winTitle += " on " + BuildConfig.BUILD_PLATFORM;
|
||||
setWindowTitle(winTitle);
|
||||
@@ -119,7 +119,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
|
||||
|
||||
// Global shortcuts
|
||||
{
|
||||
//FIXME: This is kinda weird. and bad. We need some kind of managed shutdown.
|
||||
// FIXME: This is kinda weird. and bad. We need some kind of managed shutdown.
|
||||
auto q = new QShortcut(QKeySequence::Quit, this);
|
||||
connect(q, SIGNAL(activated()), qApp, SLOT(quit()));
|
||||
}
|
||||
@@ -216,29 +216,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
|
||||
connect(MMC->instances().get(), SIGNAL(dataIsInvalid()), SLOT(selectionBad()));
|
||||
|
||||
m_statusLeft = new QLabel(tr("No instance selected"), this);
|
||||
m_statusRight = new QLabel(tr("No status available"), this);
|
||||
m_statusRefresh = new QToolButton(this);
|
||||
m_statusRefresh->setCheckable(true);
|
||||
m_statusRefresh->setToolButtonStyle(Qt::ToolButtonIconOnly);
|
||||
m_statusRefresh->setIcon(QIcon::fromTheme("refresh"));
|
||||
|
||||
m_statusRight = new ServerStatus(this);
|
||||
statusBar()->addPermanentWidget(m_statusLeft, 1);
|
||||
statusBar()->addPermanentWidget(m_statusRight, 0);
|
||||
statusBar()->addPermanentWidget(m_statusRefresh, 0);
|
||||
|
||||
// Start status checker
|
||||
{
|
||||
connect(MMC->statusChecker().get(), &StatusChecker::statusLoaded, this,
|
||||
&MainWindow::updateStatusUI);
|
||||
connect(MMC->statusChecker().get(), &StatusChecker::statusLoadingFailed, this,
|
||||
&MainWindow::updateStatusFailedUI);
|
||||
|
||||
connect(m_statusRefresh, &QAbstractButton::clicked, this, &MainWindow::reloadStatus);
|
||||
connect(&statusTimer, &QTimer::timeout, this, &MainWindow::reloadStatus);
|
||||
statusTimer.setSingleShot(true);
|
||||
|
||||
reloadStatus();
|
||||
}
|
||||
|
||||
// Add "manage accounts" button, right align
|
||||
QWidget *spacer = new QWidget();
|
||||
@@ -278,7 +258,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
|
||||
|
||||
auto accounts = MMC->accounts();
|
||||
|
||||
QList<CacheDownloadPtr> skin_dls;
|
||||
QList<CacheDownloadPtr> skin_dls;
|
||||
for (int i = 0; i < accounts->count(); i++)
|
||||
{
|
||||
auto account = accounts->at(i);
|
||||
@@ -289,21 +269,21 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
|
||||
auto meta = MMC->metacache()->resolveEntry("skins", profile.name + ".png");
|
||||
auto action = CacheDownload::make(
|
||||
QUrl("http://" + URLConstants::SKINS_BASE + profile.name + ".png"), meta);
|
||||
skin_dls.append(action);
|
||||
skin_dls.append(action);
|
||||
meta->stale = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!skin_dls.isEmpty())
|
||||
{
|
||||
auto job = new NetJob("Startup player skins download");
|
||||
connect(job, SIGNAL(succeeded()), SLOT(skinJobFinished()));
|
||||
connect(job, SIGNAL(failed()), SLOT(skinJobFinished()));
|
||||
for(auto action: skin_dls)
|
||||
job->addNetAction(action);
|
||||
skin_download_job.reset(job);
|
||||
job->start();
|
||||
}
|
||||
if (!skin_dls.isEmpty())
|
||||
{
|
||||
auto job = new NetJob("Startup player skins download");
|
||||
connect(job, SIGNAL(succeeded()), SLOT(skinJobFinished()));
|
||||
connect(job, SIGNAL(failed()), SLOT(skinJobFinished()));
|
||||
for (auto action : skin_dls)
|
||||
job->addNetAction(action);
|
||||
skin_download_job.reset(job);
|
||||
job->start();
|
||||
}
|
||||
|
||||
// run the things that load and download other things... FIXME: this is NOT the place
|
||||
// FIXME: invisible actions in the background = NOPE.
|
||||
@@ -325,15 +305,14 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
|
||||
auto updater = MMC->updateChecker();
|
||||
connect(updater.get(), &UpdateChecker::updateAvailable, this,
|
||||
&MainWindow::updateAvailable);
|
||||
connect(updater.get(), &UpdateChecker::noUpdateFound, [this]()
|
||||
{
|
||||
CustomMessageBox::selectable(
|
||||
this, tr("No update found."),
|
||||
tr("No MultiMC update was found!\nYou are using the latest version."))->exec();
|
||||
});
|
||||
connect(updater.get(), &UpdateChecker::noUpdateFound, this,
|
||||
&MainWindow::updateNotAvailable);
|
||||
// if automatic update checks are allowed, start one.
|
||||
if (MMC->settings()->get("AutoUpdate").toBool())
|
||||
on_actionCheckUpdate_triggered();
|
||||
{
|
||||
auto updater = MMC->updateChecker();
|
||||
updater->checkForUpdate(false);
|
||||
}
|
||||
|
||||
connect(MMC->notificationChecker().get(),
|
||||
&NotificationChecker::notificationCheckFinished, this,
|
||||
@@ -354,11 +333,10 @@ MainWindow::~MainWindow()
|
||||
|
||||
void MainWindow::skinJobFinished()
|
||||
{
|
||||
activeAccountChanged();
|
||||
skin_download_job.reset();
|
||||
activeAccountChanged();
|
||||
skin_download_job.reset();
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::showInstanceContextMenu(const QPoint &pos)
|
||||
{
|
||||
QList<QAction *> actions;
|
||||
@@ -380,9 +358,10 @@ void MainWindow::showInstanceContextMenu(const QPoint &pos)
|
||||
QAction *actionCopyInstance = new QAction(tr("Copy instance"), this);
|
||||
actionCopyInstance->setToolTip(ui->actionCopyInstance->toolTip());
|
||||
|
||||
|
||||
connect(actionRename, SIGNAL(triggered(bool)), SLOT(on_actionRenameInstance_triggered()));
|
||||
connect(actionCopyInstance, SIGNAL(triggered(bool)), SLOT(on_actionCopyInstance_triggered()));
|
||||
connect(actionRename, SIGNAL(triggered(bool)),
|
||||
SLOT(on_actionRenameInstance_triggered()));
|
||||
connect(actionCopyInstance, SIGNAL(triggered(bool)),
|
||||
SLOT(on_actionCopyInstance_triggered()));
|
||||
|
||||
actions.replace(1, actionRename);
|
||||
actions.prepend(actionSep);
|
||||
@@ -397,7 +376,8 @@ void MainWindow::showInstanceContextMenu(const QPoint &pos)
|
||||
QAction *actionCreateInstance = new QAction(tr("Create instance"), this);
|
||||
actionCreateInstance->setToolTip(ui->actionAddInstance->toolTip());
|
||||
|
||||
connect(actionCreateInstance, SIGNAL(triggered(bool)), SLOT(on_actionAddInstance_triggered()));
|
||||
connect(actionCreateInstance, SIGNAL(triggered(bool)),
|
||||
SLOT(on_actionAddInstance_triggered()));
|
||||
|
||||
actions.prepend(actionSep);
|
||||
actions.prepend(actionVoid);
|
||||
@@ -405,7 +385,7 @@ void MainWindow::showInstanceContextMenu(const QPoint &pos)
|
||||
}
|
||||
QMenu myMenu;
|
||||
myMenu.addActions(actions);
|
||||
if(onInstance)
|
||||
if (onInstance)
|
||||
myMenu.setEnabled(m_selectedInstance->canLaunch());
|
||||
myMenu.exec(view->mapToGlobal(pos));
|
||||
}
|
||||
@@ -418,7 +398,8 @@ void MainWindow::updateToolsMenu()
|
||||
}
|
||||
QMenu *launchMenu = new QMenu(this);
|
||||
QAction *normalLaunch = launchMenu->addAction(tr("Launch"));
|
||||
connect(normalLaunch, &QAction::triggered, [this](){doLaunch();});
|
||||
connect(normalLaunch, &QAction::triggered, [this]()
|
||||
{ doLaunch(); });
|
||||
launchMenu->addSeparator()->setText(tr("Profilers"));
|
||||
for (auto profiler : MMC->profilers().values())
|
||||
{
|
||||
@@ -427,11 +408,13 @@ void MainWindow::updateToolsMenu()
|
||||
if (!profiler->check(&error))
|
||||
{
|
||||
profilerAction->setDisabled(true);
|
||||
profilerAction->setToolTip(tr("Profiler not setup correctly. Go into settings, \"External Tools\"."));
|
||||
profilerAction->setToolTip(
|
||||
tr("Profiler not setup correctly. Go into settings, \"External Tools\"."));
|
||||
}
|
||||
else
|
||||
{
|
||||
connect(profilerAction, &QAction::triggered, [this, profiler](){doLaunch(true, profiler.get());});
|
||||
connect(profilerAction, &QAction::triggered, [this, profiler]()
|
||||
{ doLaunch(true, profiler.get()); });
|
||||
}
|
||||
}
|
||||
launchMenu->addSeparator()->setText(tr("Tools"));
|
||||
@@ -442,14 +425,13 @@ void MainWindow::updateToolsMenu()
|
||||
if (!tool->check(&error))
|
||||
{
|
||||
toolAction->setDisabled(true);
|
||||
toolAction->setToolTip(tr("Tool not setup correctly. Go into settings, \"External Tools\"."));
|
||||
toolAction->setToolTip(
|
||||
tr("Tool not setup correctly. Go into settings, \"External Tools\"."));
|
||||
}
|
||||
else
|
||||
{
|
||||
connect(toolAction, &QAction::triggered, [this, tool]()
|
||||
{
|
||||
tool->createDetachedTool(m_selectedInstance, this)->run();
|
||||
});
|
||||
{ tool->createDetachedTool(m_selectedInstance, this)->run(); });
|
||||
}
|
||||
}
|
||||
ui->actionLaunchInstance->setMenu(launchMenu);
|
||||
@@ -620,60 +602,6 @@ void MainWindow::updateNewsLabel()
|
||||
}
|
||||
}
|
||||
|
||||
static QString convertStatus(const QString &status)
|
||||
{
|
||||
QString ret = "?";
|
||||
|
||||
if (status == "green")
|
||||
ret = "↑";
|
||||
else if (status == "yellow")
|
||||
ret = "-";
|
||||
else if (status == "red")
|
||||
ret = "↓";
|
||||
|
||||
return "<span style=\"font-size:11pt; font-weight:600;\">" + ret + "</span>";
|
||||
}
|
||||
|
||||
void MainWindow::reloadStatus()
|
||||
{
|
||||
m_statusRefresh->setChecked(true);
|
||||
MMC->statusChecker()->reloadStatus();
|
||||
// updateStatusUI();
|
||||
}
|
||||
|
||||
static QString makeStatusString(const QMap<QString, QString> statuses)
|
||||
{
|
||||
QString status = "";
|
||||
status += "Web: " + convertStatus(statuses["minecraft.net"]);
|
||||
status += " Account: " + convertStatus(statuses["account.mojang.com"]);
|
||||
status += " Skins: " + convertStatus(statuses["skins.minecraft.net"]);
|
||||
status += " Auth: " + convertStatus(statuses["authserver.mojang.com"]);
|
||||
status += " Session: " + convertStatus(statuses["sessionserver.mojang.com"]);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void MainWindow::updateStatusUI()
|
||||
{
|
||||
auto statusChecker = MMC->statusChecker();
|
||||
auto statuses = statusChecker->getStatusEntries();
|
||||
|
||||
QString status = makeStatusString(statuses);
|
||||
m_statusRefresh->setChecked(false);
|
||||
|
||||
m_statusRight->setText(status);
|
||||
|
||||
statusTimer.start(60 * 1000);
|
||||
}
|
||||
|
||||
void MainWindow::updateStatusFailedUI()
|
||||
{
|
||||
m_statusRight->setText(makeStatusString(QMap<QString, QString>()));
|
||||
m_statusRefresh->setChecked(false);
|
||||
|
||||
statusTimer.start(60 * 1000);
|
||||
}
|
||||
|
||||
void MainWindow::updateAvailable(QString repo, QString versionName, int versionId)
|
||||
{
|
||||
UpdateDialog dlg;
|
||||
@@ -692,6 +620,12 @@ void MainWindow::updateAvailable(QString repo, QString versionName, int versionI
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::updateNotAvailable()
|
||||
{
|
||||
UpdateDialog dlg(false);
|
||||
dlg.exec();
|
||||
}
|
||||
|
||||
QList<int> stringToIntList(const QString &string)
|
||||
{
|
||||
QStringList split = string.split(',', QString::SkipEmptyParts);
|
||||
@@ -745,7 +679,7 @@ void MainWindow::downloadUpdates(QString repo, int versionId, bool installOnExit
|
||||
if (updateDlg.exec(&updateTask))
|
||||
{
|
||||
UpdateFlags baseFlags = None;
|
||||
if(BuildConfig.UPDATER_DRY_RUN)
|
||||
if (BuildConfig.UPDATER_DRY_RUN)
|
||||
baseFlags |= DryRun;
|
||||
if (installOnExit)
|
||||
MMC->installUpdates(updateTask.updateFilesDir(), baseFlags | OnExit);
|
||||
@@ -782,6 +716,11 @@ void MainWindow::setCatBackground(bool enabled)
|
||||
|
||||
void MainWindow::on_actionAddInstance_triggered()
|
||||
{
|
||||
#ifdef TEST_SEGV
|
||||
// For further testing stuff.
|
||||
int v = *((int *)-1);
|
||||
#endif
|
||||
|
||||
if (!MMC->minecraftlist()->isLoaded() && m_versionLoadTask &&
|
||||
m_versionLoadTask->isRunning())
|
||||
{
|
||||
@@ -938,17 +877,14 @@ void MainWindow::updateInstanceToolIcon(QString new_icon)
|
||||
|
||||
void MainWindow::setSelectedInstanceById(const QString &id)
|
||||
{
|
||||
QModelIndex selectionIndex = proxymodel->index(0, 0);
|
||||
if (!id.isNull())
|
||||
if (id.isNull())
|
||||
return;
|
||||
const QModelIndex index = MMC->instances()->getInstanceIndexById(id);
|
||||
if (index.isValid())
|
||||
{
|
||||
const QModelIndex index = MMC->instances()->getInstanceIndexById(id);
|
||||
if (index.isValid())
|
||||
{
|
||||
selectionIndex = proxymodel->mapFromSource(index);
|
||||
}
|
||||
QModelIndex selectionIndex = proxymodel->mapFromSource(index);
|
||||
view->selectionModel()->setCurrentIndex(selectionIndex, QItemSelectionModel::ClearAndSelect);
|
||||
}
|
||||
view->selectionModel()->setCurrentIndex(selectionIndex,
|
||||
QItemSelectionModel::ClearAndSelect);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionChangeInstGroup_triggered()
|
||||
@@ -998,7 +934,6 @@ void MainWindow::on_actionConfig_Folder_triggered()
|
||||
void MainWindow::on_actionCheckUpdate_triggered()
|
||||
{
|
||||
auto updater = MMC->updateChecker();
|
||||
|
||||
updater->checkForUpdate(true);
|
||||
}
|
||||
|
||||
@@ -1012,6 +947,37 @@ void MainWindow::on_actionSettings_triggered()
|
||||
updateToolsMenu();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ShowPageDialog(T raw_provider, QWidget * parent, QString open_page = QString())
|
||||
{
|
||||
auto provider = std::dynamic_pointer_cast<BasePageProvider>(raw_provider);
|
||||
if(!provider)
|
||||
return;
|
||||
PageDialog dlg(provider, open_page, parent);
|
||||
dlg.exec();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionInstanceSettings_triggered()
|
||||
{
|
||||
ShowPageDialog(m_selectedInstance, this, "settings");
|
||||
}
|
||||
|
||||
void MainWindow::on_actionEditInstNotes_triggered()
|
||||
{
|
||||
ShowPageDialog(m_selectedInstance, this, "notes");
|
||||
}
|
||||
|
||||
void MainWindow::on_actionEditInstance_triggered()
|
||||
{
|
||||
ShowPageDialog(m_selectedInstance, this);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionScreenshots_triggered()
|
||||
{
|
||||
ShowPageDialog(m_selectedInstance, this, "screenshots");
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::on_actionManageAccounts_triggered()
|
||||
{
|
||||
AccountListDialog dialog(this);
|
||||
@@ -1100,17 +1066,6 @@ void MainWindow::on_actionViewSelectedInstFolder_triggered()
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionEditInstMods_triggered()
|
||||
{
|
||||
if (m_selectedInstance)
|
||||
{
|
||||
auto dialog = m_selectedInstance->createModEditDialog(this);
|
||||
if (dialog)
|
||||
dialog->exec();
|
||||
dialog->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
// Save the window state and geometry.
|
||||
@@ -1136,10 +1091,10 @@ void MainWindow::instanceActivated(QModelIndex index)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return;
|
||||
QString id = index.data(InstanceList::InstanceIDRole).toString();
|
||||
QString id = index.data(InstanceList::InstanceIDRole).toString();
|
||||
InstancePtr inst = MMC->instances()->getInstanceById(id);
|
||||
if(!inst)
|
||||
return;
|
||||
if (!inst)
|
||||
return;
|
||||
|
||||
NagUtils::checkJVMArgs(inst->settings().get("JvmArgs").toString(), this);
|
||||
|
||||
@@ -1292,7 +1247,8 @@ void MainWindow::doLaunch(bool online, BaseProfilerFactory *profiler)
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::updateInstance(InstancePtr instance, AuthSessionPtr session, BaseProfilerFactory *profiler)
|
||||
void MainWindow::updateInstance(InstancePtr instance, AuthSessionPtr session,
|
||||
BaseProfilerFactory *profiler)
|
||||
{
|
||||
auto updateTask = instance->doUpdate();
|
||||
if (!updateTask)
|
||||
@@ -1307,20 +1263,25 @@ void MainWindow::updateInstance(InstancePtr instance, AuthSessionPtr session, Ba
|
||||
tDialog.exec(updateTask.get());
|
||||
}
|
||||
|
||||
void MainWindow::launchInstance(InstancePtr instance, AuthSessionPtr session, BaseProfilerFactory *profiler)
|
||||
void MainWindow::launchInstance(InstancePtr instance, AuthSessionPtr session,
|
||||
BaseProfilerFactory *profiler)
|
||||
{
|
||||
Q_ASSERT_X(instance != NULL, "launchInstance", "instance is NULL");
|
||||
Q_ASSERT_X(session.get() != nullptr, "launchInstance", "session is NULL");
|
||||
|
||||
proc = instance->prepareForLaunch(session);
|
||||
if (!proc)
|
||||
QString launchScript;
|
||||
|
||||
if (!instance->prepareForLaunch(session, launchScript))
|
||||
return;
|
||||
|
||||
MinecraftProcess *proc = new MinecraftProcess(instance);
|
||||
proc->setLaunchScript(launchScript);
|
||||
proc->setWorkdir(instance->minecraftRoot());
|
||||
|
||||
this->hide();
|
||||
|
||||
console = new ConsoleWindow(proc);
|
||||
connect(console, SIGNAL(isClosing()), this, SLOT(instanceEnded()));
|
||||
connect(console, &ConsoleWindow::uploadScreenshots, this, &MainWindow::on_actionScreenshots_triggered);
|
||||
|
||||
proc->setLogin(session);
|
||||
proc->arm();
|
||||
@@ -1330,7 +1291,8 @@ void MainWindow::launchInstance(InstancePtr instance, AuthSessionPtr session, Ba
|
||||
QString error;
|
||||
if (!profiler->check(&error))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Couldn't start profiler: %1").arg(error));
|
||||
QMessageBox::critical(this, tr("Error"),
|
||||
tr("Couldn't start profiler: %1").arg(error));
|
||||
proc->abort();
|
||||
return;
|
||||
}
|
||||
@@ -1340,9 +1302,11 @@ void MainWindow::launchInstance(InstancePtr instance, AuthSessionPtr session, Ba
|
||||
dialog.setMaximum(0);
|
||||
dialog.setValue(0);
|
||||
dialog.setLabelText(tr("Waiting for profiler..."));
|
||||
connect(&dialog, &QProgressDialog::canceled, profilerInstance, &BaseProfiler::abortProfiling);
|
||||
connect(&dialog, &QProgressDialog::canceled, profilerInstance,
|
||||
&BaseProfiler::abortProfiling);
|
||||
dialog.show();
|
||||
connect(profilerInstance, &BaseProfiler::readyToLaunch, [&dialog, this](const QString &message)
|
||||
connect(profilerInstance, &BaseProfiler::readyToLaunch,
|
||||
[&dialog, this, proc](const QString & message)
|
||||
{
|
||||
dialog.accept();
|
||||
QMessageBox msg;
|
||||
@@ -1355,7 +1319,8 @@ void MainWindow::launchInstance(InstancePtr instance, AuthSessionPtr session, Ba
|
||||
msg.exec();
|
||||
proc->launch();
|
||||
});
|
||||
connect(profilerInstance, &BaseProfiler::abortLaunch, [&dialog, this](const QString &message)
|
||||
connect(profilerInstance, &BaseProfiler::abortLaunch,
|
||||
[&dialog, this, proc](const QString & message)
|
||||
{
|
||||
dialog.accept();
|
||||
QMessageBox msg;
|
||||
@@ -1403,119 +1368,26 @@ void MainWindow::startTask(Task *task)
|
||||
task->start();
|
||||
}
|
||||
|
||||
// Create A Desktop Shortcut
|
||||
void MainWindow::on_actionMakeDesktopShortcut_triggered()
|
||||
{
|
||||
QString name("Test");
|
||||
name = QInputDialog::getText(this, tr("MultiMC Shortcut"), tr("Enter a Shortcut Name."),
|
||||
QLineEdit::Normal, name);
|
||||
|
||||
Util::createShortCut(Util::getDesktopDir(), QApplication::instance()->applicationFilePath(),
|
||||
QStringList() << "-dl" << QDir::currentPath() << "test", name,
|
||||
"application-x-octet-stream");
|
||||
|
||||
CustomMessageBox::selectable(
|
||||
this, tr("Not useful"),
|
||||
tr("A Dummy Shortcut was created. it will not do anything productive"),
|
||||
QMessageBox::Warning)->show();
|
||||
}
|
||||
|
||||
// BrowserDialog
|
||||
void MainWindow::openWebPage(QUrl url)
|
||||
{
|
||||
QDesktopServices::openUrl(url);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionChangeInstMCVersion_triggered()
|
||||
{
|
||||
if (view->selectionModel()->selectedIndexes().count() < 1)
|
||||
return;
|
||||
|
||||
VersionSelectDialog vselect(m_selectedInstance->versionList().get(),
|
||||
tr("Change Minecraft version"), this);
|
||||
vselect.setFuzzyFilter(1, "*OneSix*");
|
||||
if (!vselect.exec() || !vselect.selectedVersion())
|
||||
return;
|
||||
|
||||
if (!MMC->accounts()->anyAccountIsValid())
|
||||
{
|
||||
CustomMessageBox::selectable(
|
||||
this, tr("Error"),
|
||||
tr("MultiMC cannot download Minecraft or update instances unless you have at least "
|
||||
"one account added.\nPlease add your Mojang or Minecraft account."),
|
||||
QMessageBox::Warning)->show();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_selectedInstance->versionIsCustom())
|
||||
{
|
||||
auto result = CustomMessageBox::selectable(
|
||||
this, tr("Are you sure?"),
|
||||
tr("This will remove any library/version customization you did previously. "
|
||||
"This includes things like Forge install and similar."),
|
||||
QMessageBox::Warning, QMessageBox::Ok | QMessageBox::Abort,
|
||||
QMessageBox::Abort)->exec();
|
||||
|
||||
if (result != QMessageBox::Ok)
|
||||
return;
|
||||
}
|
||||
m_selectedInstance->setIntendedVersionId(vselect.selectedVersion()->descriptor());
|
||||
|
||||
auto updateTask = m_selectedInstance->doUpdate();
|
||||
if (!updateTask)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ProgressDialog tDialog(this);
|
||||
connect(updateTask.get(), SIGNAL(failed(QString)), SLOT(onGameUpdateError(QString)));
|
||||
tDialog.exec(updateTask.get());
|
||||
}
|
||||
|
||||
void MainWindow::on_actionChangeInstLWJGLVersion_triggered()
|
||||
{
|
||||
if (!m_selectedInstance)
|
||||
return;
|
||||
|
||||
LWJGLSelectDialog lselect(this);
|
||||
lselect.exec();
|
||||
if (lselect.result() == QDialog::Accepted)
|
||||
{
|
||||
auto ptr = std::dynamic_pointer_cast<LegacyInstance>(m_selectedInstance);
|
||||
if(ptr)
|
||||
ptr->setLWJGLVersion(lselect.selectedVersion());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionInstanceSettings_triggered()
|
||||
{
|
||||
if (view->selectionModel()->selectedIndexes().count() < 1)
|
||||
return;
|
||||
|
||||
InstanceSettings settings(&m_selectedInstance->settings(), this);
|
||||
settings.setWindowTitle(tr("Instance settings"));
|
||||
settings.exec();
|
||||
}
|
||||
|
||||
void MainWindow::instanceChanged(const QModelIndex ¤t, const QModelIndex &previous)
|
||||
{
|
||||
if(!current.isValid())
|
||||
{
|
||||
selectionBad();
|
||||
MMC->settings()->set("SelectedInstance", QString());
|
||||
return;
|
||||
}
|
||||
QString id = current.data(InstanceList::InstanceIDRole).toString();
|
||||
m_selectedInstance = MMC->instances()->getInstanceById(id);
|
||||
if(!current.isValid())
|
||||
{
|
||||
MMC->settings()->set("SelectedInstance", QString());
|
||||
selectionBad();
|
||||
return;
|
||||
}
|
||||
QString id = current.data(InstanceList::InstanceIDRole).toString();
|
||||
m_selectedInstance = MMC->instances()->getInstanceById(id);
|
||||
if ( m_selectedInstance )
|
||||
{
|
||||
ui->instanceToolBar->setEnabled(m_selectedInstance->canLaunch());
|
||||
renameButton->setText(m_selectedInstance->name());
|
||||
ui->actionChangeInstLWJGLVersion->setEnabled(
|
||||
m_selectedInstance->menuActionEnabled("actionChangeInstLWJGLVersion"));
|
||||
ui->actionEditInstMods->setEnabled(
|
||||
m_selectedInstance->menuActionEnabled("actionEditInstMods"));
|
||||
ui->actionChangeInstMCVersion->setEnabled(
|
||||
m_selectedInstance->menuActionEnabled("actionChangeInstMCVersion"));
|
||||
m_statusLeft->setText(m_selectedInstance->getStatusbarDescription());
|
||||
updateInstanceToolIcon(m_selectedInstance->iconKey());
|
||||
|
||||
@@ -1525,9 +1397,9 @@ void MainWindow::instanceChanged(const QModelIndex ¤t, const QModelIndex &
|
||||
}
|
||||
else
|
||||
{
|
||||
selectionBad();
|
||||
MMC->settings()->set("SelectedInstance", QString());
|
||||
return;
|
||||
MMC->settings()->set("SelectedInstance", QString());
|
||||
selectionBad();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1545,20 +1417,6 @@ void MainWindow::selectionBad()
|
||||
setSelectedInstanceById(MMC->settings()->get("SelectedInstance").toString());
|
||||
}
|
||||
|
||||
void MainWindow::on_actionEditInstNotes_triggered()
|
||||
{
|
||||
if (!m_selectedInstance)
|
||||
return;
|
||||
|
||||
EditNotesDialog noteedit(m_selectedInstance->notes(), m_selectedInstance->name(), this);
|
||||
noteedit.exec();
|
||||
if (noteedit.result() == QDialog::Accepted)
|
||||
{
|
||||
|
||||
m_selectedInstance->setNotes(noteedit.getText());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::instanceEnded()
|
||||
{
|
||||
this->show();
|
||||
@@ -1592,7 +1450,9 @@ void MainWindow::checkMigrateLegacyAssets()
|
||||
|
||||
void MainWindow::checkSetDefaultJava()
|
||||
{
|
||||
const QString javaHack = "IntelHack";
|
||||
bool askForJava = false;
|
||||
do
|
||||
{
|
||||
QString currentHostName = QHostInfo::localHostName();
|
||||
QString oldHostName = MMC->settings()->get("LastHostname").toString();
|
||||
@@ -1600,16 +1460,30 @@ void MainWindow::checkSetDefaultJava()
|
||||
{
|
||||
MMC->settings()->set("LastHostname", currentHostName);
|
||||
askForJava = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
QString currentJavaPath = MMC->settings()->get("JavaPath").toString();
|
||||
if (currentJavaPath.isEmpty())
|
||||
{
|
||||
askForJava = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if defined Q_OS_WIN32
|
||||
QString currentHack = MMC->settings()->get("JavaDetectionHack").toString();
|
||||
if (currentHack != javaHack)
|
||||
{
|
||||
CustomMessageBox::selectable(
|
||||
this, tr("Java detection forced"),
|
||||
tr("Because of graphics performance issues caused by Intel drivers on Windows, "
|
||||
"MultiMC java detection was forced. Please select a Java "
|
||||
"version.<br/><br/>If you have custom java versions set for your instances, "
|
||||
"make sure you use the 'javaw.exe' executable."),
|
||||
QMessageBox::Warning)->exec();
|
||||
askForJava = true;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
} while (0);
|
||||
|
||||
if (askForJava)
|
||||
{
|
||||
@@ -1637,30 +1511,11 @@ void MainWindow::checkSetDefaultJava()
|
||||
java = ju.GetDefaultJava();
|
||||
}
|
||||
if (java)
|
||||
{
|
||||
MMC->settings()->set("JavaPath", java->path);
|
||||
MMC->settings()->set("JavaDetectionHack", javaHack);
|
||||
}
|
||||
else
|
||||
MMC->settings()->set("JavaPath", QString("java"));
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionScreenshots_triggered()
|
||||
{
|
||||
if (!m_selectedInstance)
|
||||
return;
|
||||
ScreenshotList *list = new ScreenshotList(m_selectedInstance);
|
||||
Task *task = list->load();
|
||||
ProgressDialog prog(this);
|
||||
prog.exec(task);
|
||||
if (!task->successful())
|
||||
{
|
||||
CustomMessageBox::selectable(this, tr("Failed to load screenshots!"),
|
||||
task->failReason(), QMessageBox::Warning)->exec();
|
||||
return;
|
||||
}
|
||||
ScreenshotDialog dialog(list, this);
|
||||
if (dialog.exec() == ScreenshotDialog::Accepted)
|
||||
{
|
||||
CustomMessageBox::selectable(this, tr("Done uploading!"), dialog.message(),
|
||||
QMessageBox::Information)->exec();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,11 +19,10 @@
|
||||
#include <QProcess>
|
||||
#include <QTimer>
|
||||
|
||||
#include "logic/lists/InstanceList.h"
|
||||
#include "logic/InstanceList.h"
|
||||
#include "logic/BaseInstance.h"
|
||||
|
||||
#include "logic/auth/MojangAccount.h"
|
||||
#include <logic/net/NetJob.h>
|
||||
#include "logic/net/NetJob.h"
|
||||
|
||||
class QToolButton;
|
||||
class LabeledToolButton;
|
||||
@@ -81,6 +80,8 @@ slots:
|
||||
|
||||
void on_actionSettings_triggered();
|
||||
|
||||
void on_actionInstanceSettings_triggered();
|
||||
|
||||
void on_actionManageAccounts_triggered();
|
||||
|
||||
void on_actionReportBug_triggered();
|
||||
@@ -103,14 +104,12 @@ slots:
|
||||
|
||||
void on_actionRenameInstance_triggered();
|
||||
|
||||
void on_actionMakeDesktopShortcut_triggered();
|
||||
|
||||
void on_actionChangeInstMCVersion_triggered();
|
||||
|
||||
void on_actionEditInstMods_triggered();
|
||||
void on_actionEditInstance_triggered();
|
||||
|
||||
void on_actionEditInstNotes_triggered();
|
||||
|
||||
void on_actionScreenshots_triggered();
|
||||
|
||||
/*!
|
||||
* Launches the currently selected instance with the default account.
|
||||
* If no default account is selected, prompts the user to pick an account.
|
||||
@@ -133,19 +132,13 @@ slots:
|
||||
void taskStart();
|
||||
void taskEnd();
|
||||
|
||||
void on_actionChangeInstLWJGLVersion_triggered();
|
||||
|
||||
void instanceEnded();
|
||||
|
||||
void on_actionInstanceSettings_triggered();
|
||||
|
||||
// called when an icon is changed in the icon model.
|
||||
void iconUpdated(QString);
|
||||
|
||||
void showInstanceContextMenu(const QPoint &);
|
||||
|
||||
void on_actionScreenshots_triggered();
|
||||
|
||||
void updateToolsMenu();
|
||||
|
||||
void skinJobFinished();
|
||||
@@ -161,6 +154,8 @@ slots:
|
||||
|
||||
void updateAvailable(QString repo, QString versionName, int versionId);
|
||||
|
||||
void updateNotAvailable();
|
||||
|
||||
void notificationsChanged();
|
||||
|
||||
void activeAccountChanged();
|
||||
@@ -171,12 +166,6 @@ slots:
|
||||
|
||||
void updateNewsLabel();
|
||||
|
||||
void updateStatusUI();
|
||||
|
||||
void updateStatusFailedUI();
|
||||
|
||||
void reloadStatus();
|
||||
|
||||
/*!
|
||||
* Runs the DownloadUpdateTask and installs updates.
|
||||
*/
|
||||
@@ -206,12 +195,9 @@ private:
|
||||
Task *m_versionLoadTask;
|
||||
|
||||
QLabel *m_statusLeft;
|
||||
QLabel *m_statusRight;
|
||||
QToolButton *m_statusRefresh;
|
||||
class ServerStatus *m_statusRight;
|
||||
|
||||
QMenu *accountMenu;
|
||||
QToolButton *accountMenuButton;
|
||||
QAction *manageAccountsAction;
|
||||
|
||||
QTimer statusTimer;
|
||||
};
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
<addaction name="actionReportBug"/>
|
||||
<addaction name="actionAbout"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionPatreon"/>
|
||||
<addaction name="actionPatreon"/>
|
||||
<addaction name="actionCAT"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar"/>
|
||||
@@ -109,16 +109,13 @@
|
||||
<addaction name="actionChangeInstIcon"/>
|
||||
<addaction name="actionLaunchInstance"/>
|
||||
<addaction name="actionLaunchInstanceOffline"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionEditInstNotes"/>
|
||||
<addaction name="actionChangeInstGroup"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionEditInstance"/>
|
||||
<addaction name="actionInstanceSettings"/>
|
||||
<addaction name="actionEditInstNotes"/>
|
||||
<addaction name="actionScreenshots"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionInstanceSettings"/>
|
||||
<addaction name="actionChangeInstMCVersion"/>
|
||||
<addaction name="actionChangeInstLWJGLVersion"/>
|
||||
<addaction name="actionEditInstMods"/>
|
||||
<addaction name="actionViewSelectedInstFolder"/>
|
||||
<addaction name="actionConfig_Folder"/>
|
||||
<addaction name="separator"/>
|
||||
@@ -284,7 +281,7 @@
|
||||
<property name="statusTip">
|
||||
<string>Open the MultiMC Patreon page.</string>
|
||||
</property>
|
||||
</action>
|
||||
</action>
|
||||
<action name="actionMoreNews">
|
||||
<property name="icon">
|
||||
<iconset theme="news">
|
||||
@@ -388,82 +385,18 @@
|
||||
<string>Edit the notes for the selected instance.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionInstanceSettings">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Settings</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Change settings for the selected instance.</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Change settings for the selected instance.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionMakeDesktopShortcut">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Make Shortcut</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Make a shortcut on the desktop for the selected instance.</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Make a shortcut on the desktop for the selected instance.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionManageInstSaves">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Manage Saves</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Manage saves for the selected instance.</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Manage saves for the selected instance.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionEditInstMods">
|
||||
<action name="actionEditInstance">
|
||||
<property name="text">
|
||||
<string>Edit Mods</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Edit the mods for the selected instance.</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Edit the mods for the selected instance.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionChangeInstMCVersion">
|
||||
<property name="text">
|
||||
<string>Change Version</string>
|
||||
<property name="iconText">
|
||||
<string>Edit Instance</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Change the selected instance's Minecraft version.</string>
|
||||
<string>Change the instance settings, mods and versions.</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Change the selected instance's Minecraft version.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionChangeInstLWJGLVersion">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Change LWJGL</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Change the version of LWJGL for the selected instance to use.</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Change the version of LWJGL for the selected instance to use.</string>
|
||||
<string>Change the instance settings, mods and versions.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionViewSelectedInstFolder">
|
||||
@@ -555,9 +488,19 @@
|
||||
<string><html><head/><body><p>View and upload screenshots for this instance</p></body></html></string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionInstanceSettings">
|
||||
<property name="text">
|
||||
<string>Instance Settings</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Change the settings specific to the instance</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources>
|
||||
<include location="../resources/pe_dark/pe_dark.qrc"/>
|
||||
<include location="../resources/pe_light/pe_light.qrc"/>
|
||||
<include location="../resources/multimc/multimc.qrc"/>
|
||||
<include location="../resources/instances/instances.qrc"/>
|
||||
</resources>
|
||||
|
||||
@@ -42,7 +42,7 @@ QString getCreditsHtml(QStringList patrons)
|
||||
"<h3>MultiMC Developers</h3>"
|
||||
"<p>Andrew Okin <<a href='mailto:forkk@forkk.net'>forkk@forkk.net</a>></p>"
|
||||
"<p>Petr Mrázek <<a href='mailto:peterix@gmail.com'>peterix@gmail.com</a>></p>"
|
||||
"<p>Sky <<a href='https://www.twitter.com/drayshak'>@drayshak</a>></p>"
|
||||
"<p>Sky Welch <<a href='mailto:multimc@bunnies.io'>multimc@bunnies.io</a>></p>"
|
||||
"<p>Jan (02JanDal) <<a href='mailto:02jandal@gmail.com'>02jandal@gmail.com</a>></p>"
|
||||
""
|
||||
"<h3>With thanks to</h3>"
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "logic/InstanceFactory.h"
|
||||
#include "logic/BaseVersion.h"
|
||||
#include "logic/icons/IconList.h"
|
||||
#include "logic/lists/MinecraftVersionList.h"
|
||||
#include "logic/tasks/Task.h"
|
||||
#include "logic/BaseInstance.h"
|
||||
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "EditNotesDialog.h"
|
||||
#include "ui_EditNotesDialog.h"
|
||||
#include "gui/Platform.h"
|
||||
|
||||
#include <QIcon>
|
||||
#include <QApplication>
|
||||
|
||||
EditNotesDialog::EditNotesDialog(QString notes, QString name, QWidget *parent)
|
||||
: QDialog(parent), ui(new Ui::EditNotesDialog), m_instance_name(name),
|
||||
m_instance_notes(notes)
|
||||
{
|
||||
MultiMCPlatform::fixWM_CLASS(this);
|
||||
ui->setupUi(this);
|
||||
ui->noteEditor->setText(notes);
|
||||
setWindowTitle(tr("Edit notes of %1").arg(m_instance_name));
|
||||
// connect(ui->closeButton, SIGNAL(clicked()), SLOT(close()));
|
||||
}
|
||||
|
||||
EditNotesDialog::~EditNotesDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
QString EditNotesDialog::getText()
|
||||
{
|
||||
QString test = ui->noteEditor->toPlainText();
|
||||
return test;
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditNotesDialog</class>
|
||||
<widget class="QDialog" name="EditNotesDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>459</width>
|
||||
<height>399</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Edit Notes</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTextEdit" name="noteEditor">
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
</property>
|
||||
<property name="acceptRichText">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextEditable|Qt::TextEditorInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>EditNotesDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>EditNotesDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -29,7 +29,10 @@ class IconPickerDialog : public QDialog
|
||||
public:
|
||||
explicit IconPickerDialog(QWidget *parent = 0);
|
||||
~IconPickerDialog();
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Woverloaded-virtual"
|
||||
int exec(QString selection);
|
||||
#pragma clang diagnostic pop
|
||||
QString selectedIconKey;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -1,243 +0,0 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Authors: Andrew Okin
|
||||
* Peterix
|
||||
* Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MultiMC.h"
|
||||
#include "InstanceSettings.h"
|
||||
#include "ui_InstanceSettings.h"
|
||||
#include "gui/Platform.h"
|
||||
#include "gui/dialogs/VersionSelectDialog.h"
|
||||
|
||||
#include "logic/JavaUtils.h"
|
||||
#include "logic/NagUtils.h"
|
||||
#include "logic/lists/JavaVersionList.h"
|
||||
#include "logic/JavaChecker.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
InstanceSettings::InstanceSettings(SettingsObject *obj, QWidget *parent)
|
||||
: QDialog(parent), ui(new Ui::InstanceSettings), m_obj(obj)
|
||||
{
|
||||
MultiMCPlatform::fixWM_CLASS(this);
|
||||
ui->setupUi(this);
|
||||
|
||||
restoreGeometry(QByteArray::fromBase64(MMC->settings()->get("SettingsGeometry").toByteArray()));
|
||||
|
||||
loadSettings();
|
||||
}
|
||||
|
||||
InstanceSettings::~InstanceSettings()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void InstanceSettings::showEvent(QShowEvent *ev)
|
||||
{
|
||||
QDialog::showEvent(ev);
|
||||
}
|
||||
|
||||
void InstanceSettings::closeEvent(QCloseEvent *ev)
|
||||
{
|
||||
MMC->settings()->set("SettingsGeometry", saveGeometry().toBase64());
|
||||
|
||||
QDialog::closeEvent(ev);
|
||||
}
|
||||
|
||||
void InstanceSettings::on_customCommandsGroupBox_toggled(bool state)
|
||||
{
|
||||
ui->labelCustomCmdsDescription->setEnabled(state);
|
||||
}
|
||||
|
||||
void InstanceSettings::on_buttonBox_accepted()
|
||||
{
|
||||
MMC->settings()->set("SettingsGeometry", saveGeometry().toBase64());
|
||||
|
||||
applySettings();
|
||||
accept();
|
||||
}
|
||||
|
||||
void InstanceSettings::on_buttonBox_rejected()
|
||||
{
|
||||
MMC->settings()->set("SettingsGeometry", saveGeometry().toBase64());
|
||||
|
||||
reject();
|
||||
}
|
||||
|
||||
void InstanceSettings::applySettings()
|
||||
{
|
||||
// Console
|
||||
bool console = ui->consoleSettingsBox->isChecked();
|
||||
m_obj->set("OverrideConsole", console);
|
||||
if (console)
|
||||
{
|
||||
m_obj->set("ShowConsole", ui->showConsoleCheck->isChecked());
|
||||
m_obj->set("AutoCloseConsole", ui->autoCloseConsoleCheck->isChecked());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_obj->reset("ShowConsole");
|
||||
m_obj->reset("AutoCloseConsole");
|
||||
}
|
||||
|
||||
// Window Size
|
||||
bool window = ui->windowSizeGroupBox->isChecked();
|
||||
m_obj->set("OverrideWindow", window);
|
||||
if (window)
|
||||
{
|
||||
m_obj->set("LaunchMaximized", ui->maximizedCheckBox->isChecked());
|
||||
m_obj->set("MinecraftWinWidth", ui->windowWidthSpinBox->value());
|
||||
m_obj->set("MinecraftWinHeight", ui->windowHeightSpinBox->value());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_obj->reset("LaunchMaximized");
|
||||
m_obj->reset("MinecraftWinWidth");
|
||||
m_obj->reset("MinecraftWinHeight");
|
||||
}
|
||||
|
||||
// Memory
|
||||
bool memory = ui->memoryGroupBox->isChecked();
|
||||
m_obj->set("OverrideMemory", memory);
|
||||
if (memory)
|
||||
{
|
||||
m_obj->set("MinMemAlloc", ui->minMemSpinBox->value());
|
||||
m_obj->set("MaxMemAlloc", ui->maxMemSpinBox->value());
|
||||
m_obj->set("PermGen", ui->permGenSpinBox->value());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_obj->reset("MinMemAlloc");
|
||||
m_obj->reset("MaxMemAlloc");
|
||||
m_obj->reset("PermGen");
|
||||
}
|
||||
|
||||
// Java Settings
|
||||
bool java = ui->javaSettingsGroupBox->isChecked();
|
||||
m_obj->set("OverrideJava", java);
|
||||
if (java)
|
||||
{
|
||||
m_obj->set("JavaPath", ui->javaPathTextBox->text());
|
||||
m_obj->set("JvmArgs", ui->jvmArgsTextBox->text());
|
||||
|
||||
NagUtils::checkJVMArgs(m_obj->get("JvmArgs").toString(), this->parentWidget());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_obj->reset("JavaPath");
|
||||
m_obj->reset("JvmArgs");
|
||||
}
|
||||
|
||||
// Custom Commands
|
||||
bool custcmd = ui->customCommandsGroupBox->isChecked();
|
||||
m_obj->set("OverrideCommands", custcmd);
|
||||
if (custcmd)
|
||||
{
|
||||
m_obj->set("PreLaunchCommand", ui->preLaunchCmdTextBox->text());
|
||||
m_obj->set("PostExitCommand", ui->postExitCmdTextBox->text());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_obj->reset("PreLaunchCommand");
|
||||
m_obj->reset("PostExitCommand");
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceSettings::loadSettings()
|
||||
{
|
||||
// Console
|
||||
ui->consoleSettingsBox->setChecked(m_obj->get("OverrideConsole").toBool());
|
||||
ui->showConsoleCheck->setChecked(m_obj->get("ShowConsole").toBool());
|
||||
ui->autoCloseConsoleCheck->setChecked(m_obj->get("AutoCloseConsole").toBool());
|
||||
|
||||
// Window Size
|
||||
ui->windowSizeGroupBox->setChecked(m_obj->get("OverrideWindow").toBool());
|
||||
ui->maximizedCheckBox->setChecked(m_obj->get("LaunchMaximized").toBool());
|
||||
ui->windowWidthSpinBox->setValue(m_obj->get("MinecraftWinWidth").toInt());
|
||||
ui->windowHeightSpinBox->setValue(m_obj->get("MinecraftWinHeight").toInt());
|
||||
|
||||
// Memory
|
||||
ui->memoryGroupBox->setChecked(m_obj->get("OverrideMemory").toBool());
|
||||
ui->minMemSpinBox->setValue(m_obj->get("MinMemAlloc").toInt());
|
||||
ui->maxMemSpinBox->setValue(m_obj->get("MaxMemAlloc").toInt());
|
||||
ui->permGenSpinBox->setValue(m_obj->get("PermGen").toInt());
|
||||
|
||||
// Java Settings
|
||||
ui->javaSettingsGroupBox->setChecked(m_obj->get("OverrideJava").toBool());
|
||||
ui->javaPathTextBox->setText(m_obj->get("JavaPath").toString());
|
||||
ui->jvmArgsTextBox->setText(m_obj->get("JvmArgs").toString());
|
||||
|
||||
// Custom Commands
|
||||
ui->customCommandsGroupBox->setChecked(m_obj->get("OverrideCommands").toBool());
|
||||
ui->preLaunchCmdTextBox->setText(m_obj->get("PreLaunchCommand").toString());
|
||||
ui->postExitCmdTextBox->setText(m_obj->get("PostExitCommand").toString());
|
||||
}
|
||||
|
||||
void InstanceSettings::on_javaDetectBtn_clicked()
|
||||
{
|
||||
JavaVersionPtr java;
|
||||
|
||||
VersionSelectDialog vselect(MMC->javalist().get(), tr("Select a Java version"), this, true);
|
||||
vselect.setResizeOn(2);
|
||||
vselect.exec();
|
||||
|
||||
if (vselect.result() == QDialog::Accepted && vselect.selectedVersion())
|
||||
{
|
||||
java = std::dynamic_pointer_cast<JavaVersion>(vselect.selectedVersion());
|
||||
ui->javaPathTextBox->setText(java->path);
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceSettings::on_javaBrowseBtn_clicked()
|
||||
{
|
||||
QString dir = QFileDialog::getOpenFileName(this, tr("Find Java executable"));
|
||||
if (!dir.isNull())
|
||||
{
|
||||
ui->javaPathTextBox->setText(dir);
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceSettings::on_javaTestBtn_clicked()
|
||||
{
|
||||
checker.reset(new JavaChecker());
|
||||
connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this,
|
||||
SLOT(checkFinished(JavaCheckResult)));
|
||||
checker->path = ui->javaPathTextBox->text();
|
||||
checker->performCheck();
|
||||
}
|
||||
|
||||
void InstanceSettings::checkFinished(JavaCheckResult result)
|
||||
{
|
||||
if (result.valid)
|
||||
{
|
||||
QString text;
|
||||
text += "Java test succeeded!\n";
|
||||
if (result.is_64bit)
|
||||
text += "Using 64bit java.\n";
|
||||
text += "\n";
|
||||
text += "Platform reported: " + result.realPlatform;
|
||||
QMessageBox::information(this, tr("Java test success"), text);
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(
|
||||
this, tr("Java test failure"),
|
||||
tr("The specified java binary didn't work. You should use the auto-detect feature, "
|
||||
"or set the path to the java executable."));
|
||||
}
|
||||
}
|
||||
@@ -1,393 +0,0 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MultiMC.h"
|
||||
#include "LegacyModEditDialog.h"
|
||||
#include "ModEditDialogCommon.h"
|
||||
#include "VersionSelectDialog.h"
|
||||
#include "ProgressDialog.h"
|
||||
#include "ui_LegacyModEditDialog.h"
|
||||
#include "logic/ModList.h"
|
||||
#include "logic/lists/ForgeVersionList.h"
|
||||
#include "gui/Platform.h"
|
||||
|
||||
#include <pathutils.h>
|
||||
#include <QFileDialog>
|
||||
//#include <QMessageBox>
|
||||
#include <QDebug>
|
||||
#include <QEvent>
|
||||
#include <QKeyEvent>
|
||||
|
||||
LegacyModEditDialog::LegacyModEditDialog(LegacyInstance *inst, QWidget *parent)
|
||||
: QDialog(parent), ui(new Ui::LegacyModEditDialog), m_inst(inst)
|
||||
{
|
||||
MultiMCPlatform::fixWM_CLASS(this);
|
||||
ui->setupUi(this);
|
||||
|
||||
// Jar mods
|
||||
{
|
||||
ensureFolderPathExists(m_inst->jarModsDir());
|
||||
m_jarmods = m_inst->jarModList();
|
||||
ui->jarModsTreeView->setModel(m_jarmods.get());
|
||||
#ifndef Q_OS_LINUX
|
||||
// FIXME: internal DnD causes segfaults later
|
||||
ui->jarModsTreeView->setDragDropMode(QAbstractItemView::DragDrop);
|
||||
// FIXME: DnD is glitched with contiguous (we move only first item in selection)
|
||||
ui->jarModsTreeView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
#endif
|
||||
ui->jarModsTreeView->installEventFilter(this);
|
||||
m_jarmods->startWatching();
|
||||
auto smodel = ui->jarModsTreeView->selectionModel();
|
||||
connect(smodel, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
|
||||
SLOT(jarCurrent(QModelIndex, QModelIndex)));
|
||||
}
|
||||
// Core mods
|
||||
{
|
||||
ensureFolderPathExists(m_inst->coreModsDir());
|
||||
m_coremods = m_inst->coreModList();
|
||||
ui->coreModsTreeView->setModel(m_coremods.get());
|
||||
ui->coreModsTreeView->installEventFilter(this);
|
||||
m_coremods->startWatching();
|
||||
auto smodel = ui->coreModsTreeView->selectionModel();
|
||||
connect(smodel, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
|
||||
SLOT(coreCurrent(QModelIndex, QModelIndex)));
|
||||
}
|
||||
// Loader mods
|
||||
{
|
||||
ensureFolderPathExists(m_inst->loaderModsDir());
|
||||
m_mods = m_inst->loaderModList();
|
||||
ui->loaderModTreeView->setModel(m_mods.get());
|
||||
ui->loaderModTreeView->installEventFilter(this);
|
||||
m_mods->startWatching();
|
||||
auto smodel = ui->loaderModTreeView->selectionModel();
|
||||
connect(smodel, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
|
||||
SLOT(loaderCurrent(QModelIndex, QModelIndex)));
|
||||
}
|
||||
// texture packs
|
||||
{
|
||||
ensureFolderPathExists(m_inst->texturePacksDir());
|
||||
m_texturepacks = m_inst->texturePackList();
|
||||
ui->texPackTreeView->setModel(m_texturepacks.get());
|
||||
ui->texPackTreeView->installEventFilter(this);
|
||||
m_texturepacks->startWatching();
|
||||
}
|
||||
}
|
||||
|
||||
LegacyModEditDialog::~LegacyModEditDialog()
|
||||
{
|
||||
m_mods->stopWatching();
|
||||
m_coremods->stopWatching();
|
||||
m_jarmods->stopWatching();
|
||||
m_texturepacks->stopWatching();
|
||||
delete ui;
|
||||
}
|
||||
|
||||
bool LegacyModEditDialog::coreListFilter(QKeyEvent *keyEvent)
|
||||
{
|
||||
switch (keyEvent->key())
|
||||
{
|
||||
case Qt::Key_Delete:
|
||||
on_rmCoreBtn_clicked();
|
||||
return true;
|
||||
case Qt::Key_Plus:
|
||||
on_addCoreBtn_clicked();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QDialog::eventFilter(ui->coreModsTreeView, keyEvent);
|
||||
}
|
||||
|
||||
bool LegacyModEditDialog::jarListFilter(QKeyEvent *keyEvent)
|
||||
{
|
||||
switch (keyEvent->key())
|
||||
{
|
||||
case Qt::Key_Up:
|
||||
{
|
||||
if (keyEvent->modifiers() & Qt::ControlModifier)
|
||||
{
|
||||
on_moveJarUpBtn_clicked();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Qt::Key_Down:
|
||||
{
|
||||
if (keyEvent->modifiers() & Qt::ControlModifier)
|
||||
{
|
||||
on_moveJarDownBtn_clicked();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Qt::Key_Delete:
|
||||
on_rmJarBtn_clicked();
|
||||
return true;
|
||||
case Qt::Key_Plus:
|
||||
on_addJarBtn_clicked();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QDialog::eventFilter(ui->jarModsTreeView, keyEvent);
|
||||
}
|
||||
|
||||
bool LegacyModEditDialog::loaderListFilter(QKeyEvent *keyEvent)
|
||||
{
|
||||
switch (keyEvent->key())
|
||||
{
|
||||
case Qt::Key_Delete:
|
||||
on_rmModBtn_clicked();
|
||||
return true;
|
||||
case Qt::Key_Plus:
|
||||
on_addModBtn_clicked();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QDialog::eventFilter(ui->loaderModTreeView, keyEvent);
|
||||
}
|
||||
|
||||
bool LegacyModEditDialog::texturePackListFilter(QKeyEvent *keyEvent)
|
||||
{
|
||||
switch (keyEvent->key())
|
||||
{
|
||||
case Qt::Key_Delete:
|
||||
on_rmTexPackBtn_clicked();
|
||||
return true;
|
||||
case Qt::Key_Plus:
|
||||
on_addTexPackBtn_clicked();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QDialog::eventFilter(ui->texPackTreeView, keyEvent);
|
||||
}
|
||||
|
||||
bool LegacyModEditDialog::eventFilter(QObject *obj, QEvent *ev)
|
||||
{
|
||||
if (ev->type() != QEvent::KeyPress)
|
||||
{
|
||||
return QDialog::eventFilter(obj, ev);
|
||||
}
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
|
||||
if (obj == ui->jarModsTreeView)
|
||||
return jarListFilter(keyEvent);
|
||||
if (obj == ui->coreModsTreeView)
|
||||
return coreListFilter(keyEvent);
|
||||
if (obj == ui->loaderModTreeView)
|
||||
return loaderListFilter(keyEvent);
|
||||
if (obj == ui->texPackTreeView)
|
||||
return texturePackListFilter(keyEvent);
|
||||
return QDialog::eventFilter(obj, ev);
|
||||
}
|
||||
|
||||
void LegacyModEditDialog::on_addCoreBtn_clicked()
|
||||
{
|
||||
//: Title of core mod selection dialog
|
||||
QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Select Core Mods"));
|
||||
for (auto filename : fileNames)
|
||||
{
|
||||
m_coremods->stopWatching();
|
||||
m_coremods->installMod(QFileInfo(filename));
|
||||
m_coremods->startWatching();
|
||||
}
|
||||
}
|
||||
void LegacyModEditDialog::on_addForgeBtn_clicked()
|
||||
{
|
||||
VersionSelectDialog vselect(MMC->forgelist().get(), tr("Select Forge version"), this);
|
||||
vselect.setExactFilter(1, m_inst->intendedVersionId());
|
||||
if (vselect.exec() && vselect.selectedVersion())
|
||||
{
|
||||
ForgeVersionPtr forge =
|
||||
std::dynamic_pointer_cast<ForgeVersion>(vselect.selectedVersion());
|
||||
if (!forge)
|
||||
return;
|
||||
auto entry = MMC->metacache()->resolveEntry("minecraftforge", forge->filename);
|
||||
if (entry->stale)
|
||||
{
|
||||
NetJob *fjob = new NetJob("Forge download");
|
||||
fjob->addNetAction(CacheDownload::make(forge->universal_url, entry));
|
||||
ProgressDialog dlg(this);
|
||||
dlg.exec(fjob);
|
||||
if (dlg.result() == QDialog::Accepted)
|
||||
{
|
||||
m_jarmods->stopWatching();
|
||||
m_jarmods->installMod(QFileInfo(entry->getFullPath()));
|
||||
m_jarmods->startWatching();
|
||||
}
|
||||
else
|
||||
{
|
||||
// failed to download forge :/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_jarmods->stopWatching();
|
||||
m_jarmods->installMod(QFileInfo(entry->getFullPath()));
|
||||
m_jarmods->startWatching();
|
||||
}
|
||||
}
|
||||
}
|
||||
void LegacyModEditDialog::on_addJarBtn_clicked()
|
||||
{
|
||||
//: Title of jar mod selection dialog
|
||||
QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Select Jar Mods"));
|
||||
for (auto filename : fileNames)
|
||||
{
|
||||
m_jarmods->stopWatching();
|
||||
m_jarmods->installMod(QFileInfo(filename));
|
||||
m_jarmods->startWatching();
|
||||
}
|
||||
}
|
||||
void LegacyModEditDialog::on_addModBtn_clicked()
|
||||
{
|
||||
//: Title of regular mod selection dialog
|
||||
QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Select Loader Mods"));
|
||||
for (auto filename : fileNames)
|
||||
{
|
||||
m_mods->stopWatching();
|
||||
m_mods->installMod(QFileInfo(filename));
|
||||
m_mods->startWatching();
|
||||
}
|
||||
}
|
||||
void LegacyModEditDialog::on_addTexPackBtn_clicked()
|
||||
{
|
||||
//: Title of texture pack selection dialog
|
||||
QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Select Texture Packs"));
|
||||
for (auto filename : fileNames)
|
||||
{
|
||||
m_texturepacks->stopWatching();
|
||||
m_texturepacks->installMod(QFileInfo(filename));
|
||||
m_texturepacks->startWatching();
|
||||
}
|
||||
}
|
||||
|
||||
void LegacyModEditDialog::on_moveJarDownBtn_clicked()
|
||||
{
|
||||
int first, last;
|
||||
auto list = ui->jarModsTreeView->selectionModel()->selectedRows();
|
||||
|
||||
if (!lastfirst(list, first, last))
|
||||
return;
|
||||
|
||||
m_jarmods->moveModsDown(first, last);
|
||||
}
|
||||
void LegacyModEditDialog::on_moveJarUpBtn_clicked()
|
||||
{
|
||||
int first, last;
|
||||
auto list = ui->jarModsTreeView->selectionModel()->selectedRows();
|
||||
|
||||
if (!lastfirst(list, first, last))
|
||||
return;
|
||||
m_jarmods->moveModsUp(first, last);
|
||||
}
|
||||
void LegacyModEditDialog::on_rmCoreBtn_clicked()
|
||||
{
|
||||
int first, last;
|
||||
auto list = ui->coreModsTreeView->selectionModel()->selectedRows();
|
||||
|
||||
if (!lastfirst(list, first, last))
|
||||
return;
|
||||
m_coremods->stopWatching();
|
||||
m_coremods->deleteMods(first, last);
|
||||
m_coremods->startWatching();
|
||||
}
|
||||
void LegacyModEditDialog::on_rmJarBtn_clicked()
|
||||
{
|
||||
int first, last;
|
||||
auto list = ui->jarModsTreeView->selectionModel()->selectedRows();
|
||||
|
||||
if (!lastfirst(list, first, last))
|
||||
return;
|
||||
m_jarmods->stopWatching();
|
||||
m_jarmods->deleteMods(first, last);
|
||||
m_jarmods->startWatching();
|
||||
}
|
||||
void LegacyModEditDialog::on_rmModBtn_clicked()
|
||||
{
|
||||
int first, last;
|
||||
auto list = ui->loaderModTreeView->selectionModel()->selectedRows();
|
||||
|
||||
if (!lastfirst(list, first, last))
|
||||
return;
|
||||
m_mods->stopWatching();
|
||||
m_mods->deleteMods(first, last);
|
||||
m_mods->startWatching();
|
||||
}
|
||||
void LegacyModEditDialog::on_rmTexPackBtn_clicked()
|
||||
{
|
||||
int first, last;
|
||||
auto list = ui->texPackTreeView->selectionModel()->selectedRows();
|
||||
|
||||
if (!lastfirst(list, first, last))
|
||||
return;
|
||||
m_texturepacks->stopWatching();
|
||||
m_texturepacks->deleteMods(first, last);
|
||||
m_texturepacks->startWatching();
|
||||
}
|
||||
void LegacyModEditDialog::on_viewCoreBtn_clicked()
|
||||
{
|
||||
openDirInDefaultProgram(m_inst->coreModsDir(), true);
|
||||
}
|
||||
void LegacyModEditDialog::on_viewModBtn_clicked()
|
||||
{
|
||||
openDirInDefaultProgram(m_inst->loaderModsDir(), true);
|
||||
}
|
||||
void LegacyModEditDialog::on_viewTexPackBtn_clicked()
|
||||
{
|
||||
openDirInDefaultProgram(m_inst->texturePacksDir(), true);
|
||||
}
|
||||
|
||||
void LegacyModEditDialog::on_buttonBox_rejected()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void LegacyModEditDialog::jarCurrent(QModelIndex current, QModelIndex previous)
|
||||
{
|
||||
if (!current.isValid())
|
||||
{
|
||||
ui->jarMIFrame->clear();
|
||||
return;
|
||||
}
|
||||
int row = current.row();
|
||||
Mod &m = m_jarmods->operator[](row);
|
||||
ui->jarMIFrame->updateWithMod(m);
|
||||
}
|
||||
|
||||
void LegacyModEditDialog::coreCurrent(QModelIndex current, QModelIndex previous)
|
||||
{
|
||||
if (!current.isValid())
|
||||
{
|
||||
ui->coreMIFrame->clear();
|
||||
return;
|
||||
}
|
||||
int row = current.row();
|
||||
Mod &m = m_coremods->operator[](row);
|
||||
ui->coreMIFrame->updateWithMod(m);
|
||||
}
|
||||
|
||||
void LegacyModEditDialog::loaderCurrent(QModelIndex current, QModelIndex previous)
|
||||
{
|
||||
if (!current.isValid())
|
||||
{
|
||||
ui->loaderMIFrame->clear();
|
||||
return;
|
||||
}
|
||||
int row = current.row();
|
||||
Mod &m = m_mods->operator[](row);
|
||||
ui->loaderMIFrame->updateWithMod(m);
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include "logic/LegacyInstance.h"
|
||||
#include <logic/net/NetJob.h>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class LegacyModEditDialog;
|
||||
}
|
||||
|
||||
class LegacyModEditDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit LegacyModEditDialog(LegacyInstance *inst, QWidget *parent = 0);
|
||||
~LegacyModEditDialog();
|
||||
|
||||
private
|
||||
slots:
|
||||
|
||||
void on_addJarBtn_clicked();
|
||||
void on_rmJarBtn_clicked();
|
||||
void on_addForgeBtn_clicked();
|
||||
void on_moveJarUpBtn_clicked();
|
||||
void on_moveJarDownBtn_clicked();
|
||||
|
||||
void on_addCoreBtn_clicked();
|
||||
void on_rmCoreBtn_clicked();
|
||||
void on_viewCoreBtn_clicked();
|
||||
|
||||
void on_addModBtn_clicked();
|
||||
void on_rmModBtn_clicked();
|
||||
void on_viewModBtn_clicked();
|
||||
|
||||
void on_addTexPackBtn_clicked();
|
||||
void on_rmTexPackBtn_clicked();
|
||||
void on_viewTexPackBtn_clicked();
|
||||
|
||||
// Questionable: SettingsDialog doesn't need this for some reason?
|
||||
void on_buttonBox_rejected();
|
||||
|
||||
void jarCurrent(QModelIndex current, QModelIndex previous);
|
||||
void coreCurrent(QModelIndex current, QModelIndex previous);
|
||||
void loaderCurrent(QModelIndex current, QModelIndex previous);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *ev);
|
||||
bool jarListFilter(QKeyEvent *ev);
|
||||
bool coreListFilter(QKeyEvent *ev);
|
||||
bool loaderListFilter(QKeyEvent *ev);
|
||||
bool texturePackListFilter(QKeyEvent *ev);
|
||||
|
||||
private:
|
||||
Ui::LegacyModEditDialog *ui;
|
||||
std::shared_ptr<ModList> m_mods;
|
||||
std::shared_ptr<ModList> m_coremods;
|
||||
std::shared_ptr<ModList> m_jarmods;
|
||||
std::shared_ptr<ModList> m_texturepacks;
|
||||
LegacyInstance *m_inst;
|
||||
NetJobPtr forgeJob;
|
||||
};
|
||||
@@ -1,321 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>LegacyModEditDialog</class>
|
||||
<widget class="QDialog" name="LegacyModEditDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>540</width>
|
||||
<height>420</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Edit Mods</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="jarTab">
|
||||
<attribute name="title">
|
||||
<string>Jar Mods</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="ModListView" name="jarModsTreeView">
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="jarModsButtonBox">
|
||||
<item>
|
||||
<widget class="QPushButton" name="addJarBtn">
|
||||
<property name="text">
|
||||
<string>&Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="rmJarBtn">
|
||||
<property name="text">
|
||||
<string>&Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="addForgeBtn">
|
||||
<property name="text">
|
||||
<string>MCForge</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="jarModsButtonSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="moveJarUpBtn">
|
||||
<property name="text">
|
||||
<string>Move &Up</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="moveJarDownBtn">
|
||||
<property name="text">
|
||||
<string>Move &Down</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="MCModInfoFrame" name="jarMIFrame">
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="coreTab">
|
||||
<attribute name="title">
|
||||
<string>Core Mods</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="ModListView" name="coreModsTreeView">
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DropOnly</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="coreModsButtonBox">
|
||||
<item>
|
||||
<widget class="QPushButton" name="addCoreBtn">
|
||||
<property name="text">
|
||||
<string>&Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="rmCoreBtn">
|
||||
<property name="text">
|
||||
<string>&Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="coreModsButtonSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="viewCoreBtn">
|
||||
<property name="text">
|
||||
<string>&View Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="MCModInfoFrame" name="coreMIFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="modTab">
|
||||
<attribute name="title">
|
||||
<string>Loader Mods</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="ModListView" name="loaderModTreeView">
|
||||
<property name="acceptDrops">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DropOnly</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="mlModsButtonBox">
|
||||
<item>
|
||||
<widget class="QPushButton" name="addModBtn">
|
||||
<property name="text">
|
||||
<string>&Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="rmModBtn">
|
||||
<property name="text">
|
||||
<string>&Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="mlModsButtonSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="viewModBtn">
|
||||
<property name="text">
|
||||
<string>&View Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="MCModInfoFrame" name="loaderMIFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="texPackTab">
|
||||
<property name="acceptDrops">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>Texture Packs</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="ModListView" name="texPackTreeView">
|
||||
<property name="acceptDrops">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DropOnly</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="texturePacksButtonBox">
|
||||
<item>
|
||||
<widget class="QPushButton" name="addTexPackBtn">
|
||||
<property name="text">
|
||||
<string>&Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="rmTexPackBtn">
|
||||
<property name="text">
|
||||
<string>&Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="texturePacksButtonSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="viewTexPackBtn">
|
||||
<property name="text">
|
||||
<string>&View Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ModListView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>gui/widgets/ModListView.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>MCModInfoFrame</class>
|
||||
<extends>QFrame</extends>
|
||||
<header>gui/widgets/MCModInfoFrame.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "ui_LwjglSelectDialog.h"
|
||||
#include "gui/Platform.h"
|
||||
|
||||
#include "logic/lists/LwjglVersionList.h"
|
||||
#include "logic/LwjglVersionList.h"
|
||||
|
||||
LWJGLSelectDialog::LWJGLSelectDialog(QWidget *parent)
|
||||
: QDialog(parent), ui(new Ui::LWJGLSelectDialog)
|
||||
|
||||
@@ -1,24 +1,7 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ModEditDialogCommon.h"
|
||||
#include "CustomMessageBox.h"
|
||||
#include <QDesktopServices>
|
||||
#include <QMessageBox>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
bool lastfirst(QModelIndexList &list, int &first, int &last)
|
||||
{
|
||||
if (!list.size())
|
||||
@@ -54,4 +37,4 @@ void showWebsiteForMod(QWidget *parentDlg, Mod &m)
|
||||
QObject::tr("The mod author didn't provide a website link for this mod."),
|
||||
QMessageBox::Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,9 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <QAbstractItemModel>
|
||||
#include <QModelIndex>
|
||||
#include <QDesktopServices>
|
||||
#include <QWidget>
|
||||
#include <logic/Mod.h>
|
||||
|
||||
bool lastfirst(QModelIndexList &list, int &first, int &last);
|
||||
|
||||
void showWebsiteForMod(QWidget *parentDlg, Mod &m);
|
||||
void showWebsiteForMod(QWidget *parentDlg, Mod &m);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "logic/InstanceFactory.h"
|
||||
#include "logic/BaseVersion.h"
|
||||
#include "logic/icons/IconList.h"
|
||||
#include "logic/lists/MinecraftVersionList.h"
|
||||
#include "logic/minecraft/MinecraftVersionList.h"
|
||||
#include "logic/tasks/Task.h"
|
||||
|
||||
#include "gui/Platform.h"
|
||||
@@ -47,7 +47,7 @@ NewInstanceDialog::NewInstanceDialog(QWidget *parent)
|
||||
taskDlg->exec(loadTask);
|
||||
}
|
||||
*/
|
||||
setSelectedVersion(MMC->minecraftlist()->getLatestStable());
|
||||
setSelectedVersion(MMC->minecraftlist()->getLatestStable(), true);
|
||||
InstIconKey = "infinity";
|
||||
ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
|
||||
}
|
||||
@@ -63,13 +63,17 @@ void NewInstanceDialog::updateDialogState()
|
||||
->setEnabled(!instName().isEmpty() && m_selectedVersion);
|
||||
}
|
||||
|
||||
void NewInstanceDialog::setSelectedVersion(BaseVersionPtr version)
|
||||
void NewInstanceDialog::setSelectedVersion(BaseVersionPtr version, bool initial)
|
||||
{
|
||||
m_selectedVersion = version;
|
||||
|
||||
if (m_selectedVersion)
|
||||
{
|
||||
ui->versionTextBox->setText(version->name());
|
||||
if(ui->instNameTextBox->text().isEmpty() && !initial)
|
||||
{
|
||||
ui->instNameTextBox->setText(version->name());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
|
||||
void updateDialogState();
|
||||
|
||||
void setSelectedVersion(BaseVersionPtr version);
|
||||
void setSelectedVersion(BaseVersionPtr version, bool initial = false);
|
||||
|
||||
void loadVersionList();
|
||||
|
||||
|
||||
@@ -1,399 +0,0 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MultiMC.h"
|
||||
|
||||
#include <pathutils.h>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QDebug>
|
||||
#include <QEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QDesktopServices>
|
||||
|
||||
#include "OneSixModEditDialog.h"
|
||||
#include "ModEditDialogCommon.h"
|
||||
#include "ui_OneSixModEditDialog.h"
|
||||
|
||||
#include "gui/Platform.h"
|
||||
#include "gui/dialogs/CustomMessageBox.h"
|
||||
#include "gui/dialogs/VersionSelectDialog.h"
|
||||
|
||||
#include "gui/dialogs/ProgressDialog.h"
|
||||
|
||||
#include "logic/ModList.h"
|
||||
#include "logic/VersionFinal.h"
|
||||
#include "logic/EnabledItemFilter.h"
|
||||
#include "logic/lists/ForgeVersionList.h"
|
||||
#include "logic/lists/LiteLoaderVersionList.h"
|
||||
#include "logic/ForgeInstaller.h"
|
||||
#include "logic/LiteLoaderInstaller.h"
|
||||
#include "logic/OneSixVersionBuilder.h"
|
||||
|
||||
OneSixModEditDialog::OneSixModEditDialog(OneSixInstance *inst, QWidget *parent)
|
||||
: QDialog(parent), ui(new Ui::OneSixModEditDialog), m_inst(inst)
|
||||
{
|
||||
MultiMCPlatform::fixWM_CLASS(this);
|
||||
ui->setupUi(this);
|
||||
// libraries!
|
||||
|
||||
m_version = m_inst->getFullVersion();
|
||||
if (m_version)
|
||||
{
|
||||
main_model = new EnabledItemFilter(this);
|
||||
main_model->setActive(true);
|
||||
main_model->setSourceModel(m_version.get());
|
||||
ui->libraryTreeView->setModel(main_model);
|
||||
ui->libraryTreeView->installEventFilter(this);
|
||||
connect(ui->libraryTreeView->selectionModel(), &QItemSelectionModel::currentChanged,
|
||||
this, &OneSixModEditDialog::versionCurrent);
|
||||
updateVersionControls();
|
||||
}
|
||||
else
|
||||
{
|
||||
disableVersionControls();
|
||||
}
|
||||
// Loader mods
|
||||
{
|
||||
ensureFolderPathExists(m_inst->loaderModsDir());
|
||||
m_mods = m_inst->loaderModList();
|
||||
ui->loaderModTreeView->setModel(m_mods.get());
|
||||
ui->loaderModTreeView->installEventFilter(this);
|
||||
m_mods->startWatching();
|
||||
auto smodel = ui->loaderModTreeView->selectionModel();
|
||||
connect(smodel, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
|
||||
SLOT(loaderCurrent(QModelIndex, QModelIndex)));
|
||||
}
|
||||
// resource packs
|
||||
{
|
||||
ensureFolderPathExists(m_inst->resourcePacksDir());
|
||||
m_resourcepacks = m_inst->resourcePackList();
|
||||
ui->resPackTreeView->setModel(m_resourcepacks.get());
|
||||
ui->resPackTreeView->installEventFilter(this);
|
||||
m_resourcepacks->startWatching();
|
||||
}
|
||||
|
||||
connect(m_inst, &OneSixInstance::versionReloaded, this,
|
||||
&OneSixModEditDialog::updateVersionControls);
|
||||
}
|
||||
|
||||
OneSixModEditDialog::~OneSixModEditDialog()
|
||||
{
|
||||
m_mods->stopWatching();
|
||||
m_resourcepacks->stopWatching();
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void OneSixModEditDialog::updateVersionControls()
|
||||
{
|
||||
ui->forgeBtn->setEnabled(true);
|
||||
ui->liteloaderBtn->setEnabled(true);
|
||||
}
|
||||
|
||||
void OneSixModEditDialog::disableVersionControls()
|
||||
{
|
||||
ui->forgeBtn->setEnabled(false);
|
||||
ui->liteloaderBtn->setEnabled(false);
|
||||
ui->reloadLibrariesBtn->setEnabled(false);
|
||||
ui->removeLibraryBtn->setEnabled(false);
|
||||
}
|
||||
|
||||
bool OneSixModEditDialog::reloadInstanceVersion()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_inst->reloadVersion();
|
||||
return true;
|
||||
}
|
||||
catch (MMCError &e)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), e.cause());
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
this, tr("Error"),
|
||||
tr("Failed to load the version description file for reasons unknown."));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void OneSixModEditDialog::on_reloadLibrariesBtn_clicked()
|
||||
{
|
||||
reloadInstanceVersion();
|
||||
}
|
||||
|
||||
void OneSixModEditDialog::on_removeLibraryBtn_clicked()
|
||||
{
|
||||
if (ui->libraryTreeView->currentIndex().isValid())
|
||||
{
|
||||
// FIXME: use actual model, not reloading.
|
||||
if (!m_version->remove(ui->libraryTreeView->currentIndex().row()))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Couldn't remove file"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OneSixModEditDialog::on_resetLibraryOrderBtn_clicked()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_version->resetOrder();
|
||||
}
|
||||
catch (MMCError &e)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), e.cause());
|
||||
}
|
||||
}
|
||||
|
||||
void OneSixModEditDialog::on_moveLibraryUpBtn_clicked()
|
||||
{
|
||||
if (ui->libraryTreeView->selectionModel()->selectedRows().isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
const int row = ui->libraryTreeView->selectionModel()->selectedRows().first().row();
|
||||
const int newRow = 0;m_version->move(row, VersionFinal::MoveUp);
|
||||
//ui->libraryTreeView->selectionModel()->setCurrentIndex(m_version->index(newRow), QItemSelectionModel::ClearAndSelect);
|
||||
}
|
||||
catch (MMCError &e)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), e.cause());
|
||||
}
|
||||
}
|
||||
|
||||
void OneSixModEditDialog::on_moveLibraryDownBtn_clicked()
|
||||
{
|
||||
if (ui->libraryTreeView->selectionModel()->selectedRows().isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
const int row = ui->libraryTreeView->selectionModel()->selectedRows().first().row();
|
||||
const int newRow = 0;m_version->move(row, VersionFinal::MoveDown);
|
||||
//ui->libraryTreeView->selectionModel()->setCurrentIndex(m_version->index(newRow), QItemSelectionModel::ClearAndSelect);
|
||||
}
|
||||
catch (MMCError &e)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), e.cause());
|
||||
}
|
||||
}
|
||||
|
||||
void OneSixModEditDialog::on_forgeBtn_clicked()
|
||||
{
|
||||
// FIXME: use actual model, not reloading. Move logic to model.
|
||||
if (m_version->hasFtbPack())
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Revert?"),
|
||||
tr("This action will remove the FTB pack version patch. Continue?")) !=
|
||||
QMessageBox::Yes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_version->removeFtbPack();
|
||||
reloadInstanceVersion();
|
||||
}
|
||||
if (m_version->isCustom())
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Revert?"),
|
||||
tr("This action will remove your custom.json. Continue?")) !=
|
||||
QMessageBox::Yes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_version->revertToBase();
|
||||
reloadInstanceVersion();
|
||||
}
|
||||
VersionSelectDialog vselect(MMC->forgelist().get(), tr("Select Forge version"), this);
|
||||
vselect.setExactFilter(1, m_inst->currentVersionId());
|
||||
vselect.setEmptyString(tr("No Forge versions are currently available for Minecraft ") +
|
||||
m_inst->currentVersionId());
|
||||
if (vselect.exec() && vselect.selectedVersion())
|
||||
{
|
||||
ProgressDialog dialog(this);
|
||||
dialog.exec(ForgeInstaller().createInstallTask(m_inst, vselect.selectedVersion(), this));
|
||||
}
|
||||
}
|
||||
|
||||
void OneSixModEditDialog::on_liteloaderBtn_clicked()
|
||||
{
|
||||
if (m_version->hasFtbPack())
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Revert?"),
|
||||
tr("This action will remove the FTB pack version patch. Continue?")) !=
|
||||
QMessageBox::Yes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_version->removeFtbPack();
|
||||
reloadInstanceVersion();
|
||||
}
|
||||
if (m_version->isCustom())
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Revert?"),
|
||||
tr("This action will remove your custom.json. Continue?")) !=
|
||||
QMessageBox::Yes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_version->revertToBase();
|
||||
reloadInstanceVersion();
|
||||
}
|
||||
VersionSelectDialog vselect(MMC->liteloaderlist().get(), tr("Select LiteLoader version"),
|
||||
this);
|
||||
vselect.setExactFilter(1, m_inst->currentVersionId());
|
||||
vselect.setEmptyString(tr("No LiteLoader versions are currently available for Minecraft ") +
|
||||
m_inst->currentVersionId());
|
||||
if (vselect.exec() && vselect.selectedVersion())
|
||||
{
|
||||
ProgressDialog dialog(this);
|
||||
dialog.exec(LiteLoaderInstaller().createInstallTask(m_inst, vselect.selectedVersion(), this));
|
||||
}
|
||||
}
|
||||
|
||||
bool OneSixModEditDialog::loaderListFilter(QKeyEvent *keyEvent)
|
||||
{
|
||||
switch (keyEvent->key())
|
||||
{
|
||||
case Qt::Key_Delete:
|
||||
on_rmModBtn_clicked();
|
||||
return true;
|
||||
case Qt::Key_Plus:
|
||||
on_addModBtn_clicked();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QDialog::eventFilter(ui->loaderModTreeView, keyEvent);
|
||||
}
|
||||
|
||||
bool OneSixModEditDialog::resourcePackListFilter(QKeyEvent *keyEvent)
|
||||
{
|
||||
switch (keyEvent->key())
|
||||
{
|
||||
case Qt::Key_Delete:
|
||||
on_rmResPackBtn_clicked();
|
||||
return true;
|
||||
case Qt::Key_Plus:
|
||||
on_addResPackBtn_clicked();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QDialog::eventFilter(ui->resPackTreeView, keyEvent);
|
||||
}
|
||||
|
||||
bool OneSixModEditDialog::eventFilter(QObject *obj, QEvent *ev)
|
||||
{
|
||||
if (ev->type() != QEvent::KeyPress)
|
||||
{
|
||||
return QDialog::eventFilter(obj, ev);
|
||||
}
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
|
||||
if (obj == ui->loaderModTreeView)
|
||||
return loaderListFilter(keyEvent);
|
||||
if (obj == ui->resPackTreeView)
|
||||
return resourcePackListFilter(keyEvent);
|
||||
return QDialog::eventFilter(obj, ev);
|
||||
}
|
||||
|
||||
void OneSixModEditDialog::on_buttonBox_rejected()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void OneSixModEditDialog::on_addModBtn_clicked()
|
||||
{
|
||||
QStringList fileNames = QFileDialog::getOpenFileNames(
|
||||
this, QApplication::translate("LegacyModEditDialog", "Select Loader Mods"));
|
||||
for (auto filename : fileNames)
|
||||
{
|
||||
m_mods->stopWatching();
|
||||
m_mods->installMod(QFileInfo(filename));
|
||||
m_mods->startWatching();
|
||||
}
|
||||
}
|
||||
void OneSixModEditDialog::on_rmModBtn_clicked()
|
||||
{
|
||||
int first, last;
|
||||
auto list = ui->loaderModTreeView->selectionModel()->selectedRows();
|
||||
|
||||
if (!lastfirst(list, first, last))
|
||||
return;
|
||||
m_mods->stopWatching();
|
||||
m_mods->deleteMods(first, last);
|
||||
m_mods->startWatching();
|
||||
}
|
||||
void OneSixModEditDialog::on_viewModBtn_clicked()
|
||||
{
|
||||
openDirInDefaultProgram(m_inst->loaderModsDir(), true);
|
||||
}
|
||||
|
||||
void OneSixModEditDialog::on_addResPackBtn_clicked()
|
||||
{
|
||||
QStringList fileNames = QFileDialog::getOpenFileNames(
|
||||
this, QApplication::translate("LegacyModEditDialog", "Select Resource Packs"));
|
||||
for (auto filename : fileNames)
|
||||
{
|
||||
m_resourcepacks->stopWatching();
|
||||
m_resourcepacks->installMod(QFileInfo(filename));
|
||||
m_resourcepacks->startWatching();
|
||||
}
|
||||
}
|
||||
void OneSixModEditDialog::on_rmResPackBtn_clicked()
|
||||
{
|
||||
int first, last;
|
||||
auto list = ui->resPackTreeView->selectionModel()->selectedRows();
|
||||
|
||||
if (!lastfirst(list, first, last))
|
||||
return;
|
||||
m_resourcepacks->stopWatching();
|
||||
m_resourcepacks->deleteMods(first, last);
|
||||
m_resourcepacks->startWatching();
|
||||
}
|
||||
void OneSixModEditDialog::on_viewResPackBtn_clicked()
|
||||
{
|
||||
openDirInDefaultProgram(m_inst->resourcePacksDir(), true);
|
||||
}
|
||||
|
||||
void OneSixModEditDialog::loaderCurrent(QModelIndex current, QModelIndex previous)
|
||||
{
|
||||
if (!current.isValid())
|
||||
{
|
||||
ui->frame->clear();
|
||||
return;
|
||||
}
|
||||
int row = current.row();
|
||||
Mod &m = m_mods->operator[](row);
|
||||
ui->frame->updateWithMod(m);
|
||||
}
|
||||
|
||||
void OneSixModEditDialog::versionCurrent(const QModelIndex ¤t,
|
||||
const QModelIndex &previous)
|
||||
{
|
||||
if (!current.isValid())
|
||||
{
|
||||
ui->removeLibraryBtn->setDisabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->removeLibraryBtn->setEnabled(m_version->canRemove(current.row()));
|
||||
}
|
||||
}
|
||||
@@ -1,310 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>OneSixModEditDialog</class>
|
||||
<widget class="QDialog" name="OneSixModEditDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>555</width>
|
||||
<height>463</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Manage Mods</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="libTab">
|
||||
<attribute name="title">
|
||||
<string>Version</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_10">
|
||||
<item>
|
||||
<widget class="ModListView" name="libraryTreeView">
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<attribute name="headerVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QPushButton" name="forgeBtn">
|
||||
<property name="toolTip">
|
||||
<string>Replace any current custom version with Minecraft Forge</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Install Forge</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="liteloaderBtn">
|
||||
<property name="text">
|
||||
<string>Install LiteLoader</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="reloadLibrariesBtn">
|
||||
<property name="text">
|
||||
<string>Reload</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="removeLibraryBtn">
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="moveLibraryUpBtn">
|
||||
<property name="toolTip">
|
||||
<string>This isn't implemented yet.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Move up</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="moveLibraryDownBtn">
|
||||
<property name="toolTip">
|
||||
<string>This isn't implemented yet.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Move down</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="resetLibraryOrderBtn">
|
||||
<property name="toolTip">
|
||||
<string>This isn't implemented yet.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reset order</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="modTab">
|
||||
<attribute name="title">
|
||||
<string>Loader Mods</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="ModListView" name="loaderModTreeView">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="acceptDrops">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DropOnly</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="addModBtn">
|
||||
<property name="text">
|
||||
<string>&Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="rmModBtn">
|
||||
<property name="text">
|
||||
<string>&Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="viewModBtn">
|
||||
<property name="text">
|
||||
<string>&View Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="MCModInfoFrame" name="frame">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="resPackTab">
|
||||
<attribute name="title">
|
||||
<string>Resource Packs</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="ModListView" name="resPackTreeView">
|
||||
<property name="acceptDrops">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DropOnly</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QPushButton" name="addResPackBtn">
|
||||
<property name="text">
|
||||
<string>&Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="rmResPackBtn">
|
||||
<property name="text">
|
||||
<string>&Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="viewResPackBtn">
|
||||
<property name="text">
|
||||
<string>&View Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ModListView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>gui/widgets/ModListView.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>MCModInfoFrame</class>
|
||||
<extends>QFrame</extends>
|
||||
<header>gui/widgets/MCModInfoFrame.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -34,7 +34,11 @@ public:
|
||||
|
||||
void updateSize();
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Woverloaded-virtual"
|
||||
int exec(ProgressProvider *task);
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
void setSkipButton(bool present, QString label = QString());
|
||||
|
||||
ProgressProvider *getTask();
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
#include "ScreenshotDialog.h"
|
||||
#include "ui_ScreenshotDialog.h"
|
||||
|
||||
#include <QModelIndex>
|
||||
#include <QMutableListIterator>
|
||||
|
||||
#include "ProgressDialog.h"
|
||||
#include "CustomMessageBox.h"
|
||||
#include "logic/net/NetJob.h"
|
||||
#include "logic/screenshots/ImgurUpload.h"
|
||||
#include "logic/screenshots/ImgurAlbumCreation.h"
|
||||
#include "logic/tasks/SequentialTask.h"
|
||||
|
||||
ScreenshotDialog::ScreenshotDialog(ScreenshotList *list, QWidget *parent)
|
||||
: QDialog(parent), ui(new Ui::ScreenshotDialog), m_list(list)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->listView->setModel(m_list);
|
||||
}
|
||||
|
||||
ScreenshotDialog::~ScreenshotDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
QString ScreenshotDialog::message() const
|
||||
{
|
||||
return tr("<a href=\"https://imgur.com/a/%1\">Visit album</a><br/>Delete hash: %2 (save "
|
||||
"this if you want to be able to edit/delete the album)")
|
||||
.arg(m_imgurAlbum->id(), m_imgurAlbum->deleteHash());
|
||||
}
|
||||
|
||||
QList<ScreenshotPtr> ScreenshotDialog::selected() const
|
||||
{
|
||||
QList<ScreenshotPtr> list;
|
||||
QList<ScreenshotPtr> first = m_list->screenshots();
|
||||
for (QModelIndex index : ui->listView->selectionModel()->selectedRows())
|
||||
{
|
||||
list.append(first.at(index.row()));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
void ScreenshotDialog::on_uploadBtn_clicked()
|
||||
{
|
||||
m_uploaded = selected();
|
||||
if (m_uploaded.isEmpty())
|
||||
{
|
||||
done(NothingDone);
|
||||
return;
|
||||
}
|
||||
SequentialTask *task = new SequentialTask(this);
|
||||
NetJob *job = new NetJob("Screenshot Upload");
|
||||
for (auto shot : m_uploaded)
|
||||
{
|
||||
job->addNetAction(ImgurUpload::make(shot));
|
||||
}
|
||||
NetJob *albumTask = new NetJob("Imgur Album Creation");
|
||||
albumTask->addNetAction(m_imgurAlbum = ImgurAlbumCreation::make(m_uploaded));
|
||||
task->addTask(NetJobPtr(job));
|
||||
task->addTask(NetJobPtr(albumTask));
|
||||
ProgressDialog prog(this);
|
||||
if (prog.exec(task) == QDialog::Accepted)
|
||||
{
|
||||
accept();
|
||||
}
|
||||
else
|
||||
{
|
||||
CustomMessageBox::selectable(this, tr("Failed to upload screenshots!"),
|
||||
tr("Unknown error"), QMessageBox::Warning)->exec();
|
||||
reject();
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenshotDialog::on_deleteBtn_clicked()
|
||||
{
|
||||
m_list->deleteSelected(this);
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include "logic/screenshots/ScreenshotList.h"
|
||||
|
||||
class ImgurAlbumCreation;
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class ScreenshotDialog;
|
||||
}
|
||||
|
||||
class ScreenshotDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ScreenshotDialog(ScreenshotList *list, QWidget *parent = 0);
|
||||
~ScreenshotDialog();
|
||||
|
||||
enum
|
||||
{
|
||||
NothingDone = 0x42
|
||||
};
|
||||
|
||||
QString message() const;
|
||||
QList<ScreenshotPtr> selected() const;
|
||||
|
||||
private
|
||||
slots:
|
||||
void on_uploadBtn_clicked();
|
||||
|
||||
void on_deleteBtn_clicked();
|
||||
|
||||
private:
|
||||
Ui::ScreenshotDialog *ui;
|
||||
ScreenshotList *m_list;
|
||||
QList<ScreenshotPtr> m_uploaded;
|
||||
std::shared_ptr<ImgurAlbumCreation> m_imgurAlbum;
|
||||
};
|
||||
@@ -1,110 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ScreenshotDialog</class>
|
||||
<widget class="QDialog" name="ScreenshotDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>470</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Screenshot Manager</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="../../resources/multimc/multimc.qrc">
|
||||
<normaloff>:/icons/multimc/scalable/apps/multimc.svg</normaloff>:/icons/multimc/scalable/apps/multimc.svg</iconset>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QListView" name="listView">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectItems</enum>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>90</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flow">
|
||||
<enum>QListView::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="isWrapping" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="resizeMode">
|
||||
<enum>QListView::Adjust</enum>
|
||||
</property>
|
||||
<property name="viewMode">
|
||||
<enum>QListView::IconMode</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="uploadBtn">
|
||||
<property name="text">
|
||||
<string>Upload</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="deleteBtn">
|
||||
<property name="text">
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="closeBtn">
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../../resources/multimc/multimc.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>closeBtn</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>ScreenshotDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>315</x>
|
||||
<y>272</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>271</x>
|
||||
<y>258</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -22,21 +22,31 @@
|
||||
#include "gui/dialogs/VersionSelectDialog.h"
|
||||
#include "gui/dialogs/CustomMessageBox.h"
|
||||
|
||||
#include "logic/JavaUtils.h"
|
||||
#include "logic/NagUtils.h"
|
||||
#include "logic/lists/JavaVersionList.h"
|
||||
#include <logic/JavaChecker.h>
|
||||
|
||||
#include "logic/java/JavaUtils.h"
|
||||
#include "logic/java/JavaVersionList.h"
|
||||
#include "logic/java/JavaChecker.h"
|
||||
|
||||
#include "logic/updater/UpdateChecker.h"
|
||||
|
||||
#include "logic/tools/BaseProfiler.h"
|
||||
|
||||
#include <settingsobject.h>
|
||||
#include "logic/settings/SettingsObject.h"
|
||||
#include <pathutils.h>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QDir>
|
||||
|
||||
// FIXME: possibly move elsewhere
|
||||
enum InstSortMode
|
||||
{
|
||||
// Sort alphabetically by name.
|
||||
Sort_Name,
|
||||
// Sort by which instance was launched most recently.
|
||||
Sort_LastLaunch
|
||||
};
|
||||
|
||||
SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent), ui(new Ui::SettingsDialog)
|
||||
{
|
||||
MultiMCPlatform::fixWM_CLASS(this);
|
||||
@@ -63,7 +73,7 @@ SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent), ui(new Ui::Se
|
||||
}
|
||||
else
|
||||
{
|
||||
MMC->updateChecker()->updateChanList();
|
||||
MMC->updateChecker()->updateChanList(false);
|
||||
}
|
||||
connect(ui->proxyGroup, SIGNAL(buttonClicked(int)), SLOT(proxyChanged(int)));
|
||||
ui->mceditLink->setOpenExternalLinks(true);
|
||||
@@ -316,7 +326,20 @@ void SettingsDialog::applySettings(SettingsObject *s)
|
||||
// Updates
|
||||
s->set("AutoUpdate", ui->autoUpdateCheckBox->isChecked());
|
||||
s->set("UpdateChannel", m_currentUpdateChannel);
|
||||
|
||||
//FIXME: make generic
|
||||
switch (ui->themeComboBox->currentIndex())
|
||||
{
|
||||
case 1:
|
||||
s->set("IconTheme", "pe_dark");
|
||||
break;
|
||||
case 2:
|
||||
s->set("IconTheme", "pe_light");
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
s->set("IconTheme", "multimc");
|
||||
break;
|
||||
}
|
||||
// FTB
|
||||
s->set("TrackFTBInstances", ui->trackFtbBox->isChecked());
|
||||
s->set("FTBLauncherRoot", ui->ftbLauncherBox->text());
|
||||
@@ -407,10 +430,10 @@ void SettingsDialog::loadSettings(SettingsObject *s)
|
||||
// Language
|
||||
ui->languageBox->clear();
|
||||
ui->languageBox->addItem(tr("English"), QLocale(QLocale::English));
|
||||
foreach(const QString & lang,
|
||||
QDir(MMC->root() + "/translations").entryList(QStringList() << "*.qm", QDir::Files))
|
||||
foreach(const QString & lang, QDir(MMC->staticData() + "/translations")
|
||||
.entryList(QStringList() << "*.qm", QDir::Files))
|
||||
{
|
||||
QLocale locale(lang.section(QRegExp("[_\.]"), 1));
|
||||
QLocale locale(lang.section(QRegExp("[_\\.]"), 1));
|
||||
ui->languageBox->addItem(QLocale::languageToString(locale.language()), locale);
|
||||
}
|
||||
ui->languageBox->setCurrentIndex(
|
||||
@@ -419,7 +442,20 @@ void SettingsDialog::loadSettings(SettingsObject *s)
|
||||
// Updates
|
||||
ui->autoUpdateCheckBox->setChecked(s->get("AutoUpdate").toBool());
|
||||
m_currentUpdateChannel = s->get("UpdateChannel").toString();
|
||||
|
||||
//FIXME: make generic
|
||||
auto theme = s->get("IconTheme").toString();
|
||||
if (theme == "pe_dark")
|
||||
{
|
||||
ui->themeComboBox->setCurrentIndex(1);
|
||||
}
|
||||
else if (theme == "pe_light")
|
||||
{
|
||||
ui->themeComboBox->setCurrentIndex(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->themeComboBox->setCurrentIndex(0);
|
||||
}
|
||||
// FTB
|
||||
ui->trackFtbBox->setChecked(s->get("TrackFTBInstances").toBool());
|
||||
ui->ftbLauncherBox->setText(s->get("FTBLauncherRoot").toString());
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <memory>
|
||||
#include <QDialog>
|
||||
|
||||
#include "logic/JavaChecker.h"
|
||||
#include "logic/java/JavaChecker.h"
|
||||
|
||||
class SettingsObject;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<string>Settings</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="../../graphics.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/icons/toolbar/settings</normaloff>:/icons/toolbar/settings</iconset>
|
||||
</property>
|
||||
<property name="modal">
|
||||
@@ -326,6 +326,43 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="themeBox">
|
||||
<property name="title">
|
||||
<string>Icon Theme</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="themeBoxLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="themeComboBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::StrongFocus</enum>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Default</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Simple</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Simple (Light Icons)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="editorsBox">
|
||||
<property name="title">
|
||||
|
||||
@@ -1,17 +1,175 @@
|
||||
#include "UpdateDialog.h"
|
||||
#include "ui_UpdateDialog.h"
|
||||
#include "gui/Platform.h"
|
||||
#include "logger/QsLog.h"
|
||||
#include "MultiMC.h"
|
||||
#include <logic/settings/SettingsObject.h>
|
||||
|
||||
UpdateDialog::UpdateDialog(QWidget *parent) : QDialog(parent), ui(new Ui::UpdateDialog)
|
||||
UpdateDialog::UpdateDialog(bool hasUpdate, QWidget *parent) : QDialog(parent), ui(new Ui::UpdateDialog)
|
||||
{
|
||||
MultiMCPlatform::fixWM_CLASS(this);
|
||||
ui->setupUi(this);
|
||||
auto channel = MMC->settings()->get("UpdateChannel").toString();
|
||||
if(hasUpdate)
|
||||
{
|
||||
ui->label->setText(tr("A new %1 update is available!").arg(channel));
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->label->setText(tr("No %1 updates found. You are running the latest version.").arg(channel));
|
||||
ui->btnUpdateNow->setDisabled(true);
|
||||
ui->btnUpdateOnExit->setDisabled(true);
|
||||
}
|
||||
loadChangelog();
|
||||
}
|
||||
|
||||
UpdateDialog::~UpdateDialog()
|
||||
{
|
||||
}
|
||||
|
||||
void UpdateDialog::loadChangelog()
|
||||
{
|
||||
auto channel = MMC->settings()->get("UpdateChannel").toString();
|
||||
dljob.reset(new NetJob("Changelog"));
|
||||
auto url = QString("https://raw.githubusercontent.com/MultiMC/MultiMC5/%1/changelog.md").arg(channel);
|
||||
changelogDownload = ByteArrayDownload::make(QUrl(url));
|
||||
dljob->addNetAction(changelogDownload);
|
||||
connect(dljob.get(), &NetJob::succeeded, this, &UpdateDialog::changelogLoaded);
|
||||
connect(dljob.get(), &NetJob::failed, this, &UpdateDialog::changelogFailed);
|
||||
dljob->start();
|
||||
}
|
||||
|
||||
// TODO: this will be replaced.
|
||||
QString reprocessMarkdown(QString markdown)
|
||||
{
|
||||
QString htmlData;
|
||||
QTextStream html(&htmlData);
|
||||
auto lines = markdown.split(QRegExp("[\r]?[\n]"),QString::KeepEmptyParts);
|
||||
enum
|
||||
{
|
||||
BASE,
|
||||
LIST1,
|
||||
LIST2
|
||||
}state = BASE;
|
||||
html << "<html>";
|
||||
int i = 0;
|
||||
auto procLine = [&](QString line) -> QString
|
||||
{
|
||||
// [GitHub issues](https://github.com/MultiMC/MultiMC5/issues)
|
||||
line.replace(QRegExp("\\[([^\\]]+)\\]\\(([^\\)]+)\\)"), "<a href=\"\\2\">\\1</a>");
|
||||
return line;
|
||||
};
|
||||
for(auto line: lines)
|
||||
{
|
||||
if(line.isEmpty())
|
||||
{
|
||||
// html << "<br />\n";
|
||||
}
|
||||
else switch (state)
|
||||
{
|
||||
case BASE:
|
||||
if(line.startsWith("##"))
|
||||
{
|
||||
html << "<h2>" << procLine(line.mid(2)) << "</h2>\n";
|
||||
}
|
||||
else if(line.startsWith("#"))
|
||||
{
|
||||
html << "<h1>" << procLine(line.mid(1)) << "</h1>\n";
|
||||
}
|
||||
else if(line.startsWith("- "))
|
||||
{
|
||||
state = LIST1;
|
||||
html << "<ul>\n";
|
||||
html << "<li>" << procLine(line.mid(2)) << "</li>\n";
|
||||
}
|
||||
else QLOG_ERROR() << "Invalid input on line " << i << ": " << line;
|
||||
break;
|
||||
case LIST1:
|
||||
if(line.startsWith("##"))
|
||||
{
|
||||
state = BASE;
|
||||
html << "</ul>\n";
|
||||
html << "<h2>" << procLine(line.mid(2)) << "</h2>\n";
|
||||
}
|
||||
else if(line.startsWith("#"))
|
||||
{
|
||||
state = BASE;
|
||||
html << "</ul>\n";
|
||||
html << "<h1>" << procLine(line.mid(1)) << "</h1>\n";
|
||||
}
|
||||
else if(line.startsWith("- "))
|
||||
{
|
||||
html << "<li>" << procLine(line.mid(2)) << "</li>\n";
|
||||
}
|
||||
else if(line.startsWith(" - "))
|
||||
{
|
||||
state = LIST2;
|
||||
html << "<ul>\n";
|
||||
html << "<li>" << procLine(line.mid(4)) << "</li>\n";
|
||||
}
|
||||
else QLOG_ERROR() << "Invalid input on line " << i << ": " << line;
|
||||
break;
|
||||
case LIST2:
|
||||
if(line.startsWith("##"))
|
||||
{
|
||||
state = BASE;
|
||||
html << "</ul>\n";
|
||||
html << "</ul>\n";
|
||||
html << "<h2>" << procLine(line.mid(2)) << "</h2>\n";
|
||||
}
|
||||
else if(line.startsWith("#"))
|
||||
{
|
||||
state = BASE;
|
||||
html << "</ul>\n";
|
||||
html << "</ul>\n";
|
||||
html << "<h1>" << procLine(line.mid(1)) << "</h1>\n";
|
||||
}
|
||||
else if(line.startsWith("- "))
|
||||
{
|
||||
state = LIST1;
|
||||
html << "</ul>\n";
|
||||
html << "<li>" << procLine(line.mid(2)) << "</li>\n";
|
||||
}
|
||||
else if(line.startsWith(" - "))
|
||||
{
|
||||
html << "<li>" << procLine(line.mid(4)) << "</li>\n";
|
||||
}
|
||||
else QLOG_ERROR() << "Invalid input on line " << i << ": " << line;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if(state == LIST2)
|
||||
{
|
||||
html << "</ul>\n";
|
||||
state = LIST1;
|
||||
}
|
||||
if(state == LIST1)
|
||||
{
|
||||
html << "</ul>\n";
|
||||
state = BASE;
|
||||
}
|
||||
if (state != BASE)
|
||||
{
|
||||
QLOG_ERROR() << "Reprocessing markdown didn't end in a final state!";
|
||||
}
|
||||
html << "</html>\n";
|
||||
QLOG_DEBUG() << htmlData;
|
||||
return htmlData;
|
||||
}
|
||||
|
||||
void UpdateDialog::changelogLoaded()
|
||||
{
|
||||
auto rawMarkdown = QString::fromUtf8(changelogDownload->m_data);
|
||||
auto html = reprocessMarkdown(rawMarkdown);
|
||||
ui->changelogBrowser->setHtml(html);
|
||||
}
|
||||
|
||||
void UpdateDialog::changelogFailed()
|
||||
{
|
||||
ui->changelogBrowser->setHtml(tr("<p align=\"center\" <span style=\"font-size:22pt;\">Failed to fetch changelog...</span></p>"));
|
||||
}
|
||||
|
||||
void UpdateDialog::on_btnUpdateLater_clicked()
|
||||
{
|
||||
reject();
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include "logic/net/ByteArrayDownload.h"
|
||||
#include "logic/net/NetJob.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
@@ -34,7 +36,7 @@ class UpdateDialog : public QDialog
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit UpdateDialog(QWidget *parent = 0);
|
||||
explicit UpdateDialog(bool hasUpdate = true, QWidget *parent = 0);
|
||||
~UpdateDialog();
|
||||
|
||||
private:
|
||||
@@ -43,4 +45,17 @@ public slots:
|
||||
void on_btnUpdateNow_clicked();
|
||||
void on_btnUpdateOnExit_clicked();
|
||||
void on_btnUpdateLater_clicked();
|
||||
|
||||
/// Starts loading the changelog
|
||||
void loadChangelog();
|
||||
|
||||
/// Slot for when the chengelog loads successfully.
|
||||
void changelogLoaded();
|
||||
|
||||
/// Slot for when the chengelog fails to load...
|
||||
void changelogFailed();
|
||||
|
||||
private:
|
||||
ByteArrayDownloadPtr changelogDownload;
|
||||
NetJobPtr dljob;
|
||||
};
|
||||
|
||||
@@ -6,65 +6,101 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>350</width>
|
||||
<height>260</height>
|
||||
<width>657</width>
|
||||
<height>673</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MultiMC Update</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="../../graphics.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/icons/toolbar/checkupdate</normaloff>:/icons/toolbar/checkupdate</iconset>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>A new MultiMC update is available!</string>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>14</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>changelogBrowser</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="changelogBrowser">
|
||||
<property name="html">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Bitstream Vera Sans'; font-size:11pt; font-weight:400; font-style:normal;">
|
||||
<p align="center" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:22pt;">Loading changelog...</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnUpdateNow">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Update now</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnUpdateOnExit">
|
||||
<property name="text">
|
||||
<string>Update after MultiMC closes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnUpdateLater">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Don't update yet</string>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnUpdateNow">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Update now</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnUpdateOnExit">
|
||||
<property name="text">
|
||||
<string>Update after MultiMC closes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnUpdateLater">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Don't update yet</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>changelogBrowser</tabstop>
|
||||
<tabstop>btnUpdateNow</tabstop>
|
||||
<tabstop>btnUpdateOnExit</tabstop>
|
||||
<tabstop>btnUpdateLater</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="../../graphics.qrc"/>
|
||||
<include location="../../resources/multimc/multimc.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
||||
@@ -18,13 +18,11 @@
|
||||
|
||||
#include <QHeaderView>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <gui/dialogs/ProgressDialog.h>
|
||||
#include "gui/Platform.h"
|
||||
|
||||
#include <logic/BaseVersion.h>
|
||||
#include <logic/lists/BaseVersionList.h>
|
||||
#include <logic/BaseVersionList.h>
|
||||
#include <logic/tasks/Task.h>
|
||||
|
||||
VersionSelectDialog::VersionSelectDialog(BaseVersionList *vlist, QString title, QWidget *parent,
|
||||
|
||||
@@ -3,15 +3,16 @@
|
||||
#include <QPainter>
|
||||
#include <QApplication>
|
||||
#include <QtMath>
|
||||
#include <QDebug>
|
||||
#include <QMouseEvent>
|
||||
#include <QListView>
|
||||
#include <QPersistentModelIndex>
|
||||
#include <QDrag>
|
||||
#include <QMimeData>
|
||||
#include <QCache>
|
||||
#include <QScrollBar>
|
||||
|
||||
#include "Group.h"
|
||||
#include "VisualGroup.h"
|
||||
#include "logger/QsLog.h"
|
||||
|
||||
template <typename T> bool listsIntersect(const QList<T> &l1, const QList<T> t2)
|
||||
{
|
||||
@@ -26,17 +27,12 @@ template <typename T> bool listsIntersect(const QList<T> &l1, const QList<T> t2)
|
||||
}
|
||||
|
||||
GroupView::GroupView(QWidget *parent)
|
||||
: QAbstractItemView(parent), m_leftMargin(5), m_rightMargin(5), m_bottomMargin(5),
|
||||
m_categoryMargin(5) //, m_updatesDisabled(false), m_categoryEditor(0), m_editedCategory(0)
|
||||
: QAbstractItemView(parent)
|
||||
{
|
||||
// setViewMode(IconMode);
|
||||
// setMovement(Snap);
|
||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
// setWordWrap(true);
|
||||
// setDragDropMode(QListView::InternalMove);
|
||||
setAcceptDrops(true);
|
||||
m_spacing = 5;
|
||||
setAutoScroll(true);
|
||||
}
|
||||
|
||||
GroupView::~GroupView()
|
||||
@@ -68,9 +64,10 @@ void GroupView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int e
|
||||
|
||||
void GroupView::updateGeometries()
|
||||
{
|
||||
geometryCache.clear();
|
||||
int previousScroll = verticalScrollBar()->value();
|
||||
|
||||
QMap<QString, Group *> cats;
|
||||
QMap<QString, VisualGroup *> cats;
|
||||
|
||||
for (int i = 0; i < model()->rowCount(); ++i)
|
||||
{
|
||||
@@ -78,14 +75,14 @@ void GroupView::updateGeometries()
|
||||
model()->index(i, 0).data(GroupViewRoles::GroupRole).toString();
|
||||
if (!cats.contains(groupName))
|
||||
{
|
||||
Group *old = this->category(groupName);
|
||||
VisualGroup *old = this->category(groupName);
|
||||
if (old)
|
||||
{
|
||||
cats.insert(groupName, new Group(old));
|
||||
cats.insert(groupName, new VisualGroup(old));
|
||||
}
|
||||
else
|
||||
{
|
||||
cats.insert(groupName, new Group(groupName, this));
|
||||
cats.insert(groupName, new VisualGroup(groupName, this));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,7 +144,7 @@ void GroupView::modelReset()
|
||||
|
||||
bool GroupView::isIndexHidden(const QModelIndex &index) const
|
||||
{
|
||||
Group *cat = category(index);
|
||||
VisualGroup *cat = category(index);
|
||||
if (cat)
|
||||
{
|
||||
return cat->collapsed;
|
||||
@@ -158,12 +155,12 @@ bool GroupView::isIndexHidden(const QModelIndex &index) const
|
||||
}
|
||||
}
|
||||
|
||||
Group *GroupView::category(const QModelIndex &index) const
|
||||
VisualGroup *GroupView::category(const QModelIndex &index) const
|
||||
{
|
||||
return category(index.data(GroupViewRoles::GroupRole).toString());
|
||||
}
|
||||
|
||||
Group *GroupView::category(const QString &cat) const
|
||||
VisualGroup *GroupView::category(const QString &cat) const
|
||||
{
|
||||
for (auto group : m_groups)
|
||||
{
|
||||
@@ -175,11 +172,11 @@ Group *GroupView::category(const QString &cat) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Group *GroupView::categoryAt(const QPoint &pos) const
|
||||
VisualGroup *GroupView::categoryAt(const QPoint &pos) const
|
||||
{
|
||||
for (auto group : m_groups)
|
||||
{
|
||||
if(group->hitScan(pos) & Group::CheckboxHit)
|
||||
if(group->hitScan(pos) & VisualGroup::CheckboxHit)
|
||||
{
|
||||
return group;
|
||||
}
|
||||
@@ -187,7 +184,7 @@ Group *GroupView::categoryAt(const QPoint &pos) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int GroupView::itemsPerRow() const
|
||||
int GroupView::calculateItemsPerRow() const
|
||||
{
|
||||
return qFloor((qreal)(contentWidth()) / (qreal)(itemWidth() + m_spacing));
|
||||
}
|
||||
@@ -199,77 +196,7 @@ int GroupView::contentWidth() const
|
||||
|
||||
int GroupView::itemWidth() const
|
||||
{
|
||||
return itemDelegate()
|
||||
->sizeHint(viewOptions(), model()->index(model()->rowCount() - 1, 0))
|
||||
.width();
|
||||
}
|
||||
|
||||
int GroupView::categoryRowHeight(const QModelIndex &index) const
|
||||
{
|
||||
QModelIndexList indices;
|
||||
int internalRow = categoryInternalPosition(index).second;
|
||||
for (auto &i : category(index)->items())
|
||||
{
|
||||
if (categoryInternalPosition(i).second == internalRow)
|
||||
{
|
||||
indices.append(i);
|
||||
}
|
||||
}
|
||||
|
||||
int largestHeight = 0;
|
||||
for (auto &i : indices)
|
||||
{
|
||||
largestHeight =
|
||||
qMax(largestHeight, itemDelegate()->sizeHint(viewOptions(), i).height());
|
||||
}
|
||||
return largestHeight + m_spacing;
|
||||
}
|
||||
|
||||
QPair<int, int> GroupView::categoryInternalPosition(const QModelIndex &index) const
|
||||
{
|
||||
QList<QModelIndex> indices = category(index)->items();
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
const int perRow = itemsPerRow();
|
||||
for (int i = 0; i < indices.size(); ++i)
|
||||
{
|
||||
if (indices.at(i) == index)
|
||||
{
|
||||
break;
|
||||
}
|
||||
++x;
|
||||
if (x == perRow)
|
||||
{
|
||||
x = 0;
|
||||
++y;
|
||||
}
|
||||
}
|
||||
return qMakePair(x, y);
|
||||
}
|
||||
|
||||
int GroupView::categoryInternalRowTop(const QModelIndex &index) const
|
||||
{
|
||||
Group *cat = category(index);
|
||||
int categoryInternalRow = categoryInternalPosition(index).second;
|
||||
int result = 0;
|
||||
for (int i = 0; i < categoryInternalRow; ++i)
|
||||
{
|
||||
result += cat->rowHeights.at(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int GroupView::itemHeightForCategoryRow(const Group *category, const int internalRow) const
|
||||
{
|
||||
for (auto &i : category->items())
|
||||
{
|
||||
QPair<int, int> pos = categoryInternalPosition(i);
|
||||
if (pos.second == internalRow)
|
||||
{
|
||||
return categoryRowHeight(i);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
return m_itemWidth;
|
||||
}
|
||||
|
||||
void GroupView::mousePressEvent(QMouseEvent *event)
|
||||
@@ -283,7 +210,6 @@ void GroupView::mousePressEvent(QMouseEvent *event)
|
||||
|
||||
m_pressedIndex = index;
|
||||
m_pressedAlreadySelected = selectionModel()->isSelected(m_pressedIndex);
|
||||
QItemSelectionModel::SelectionFlags selection_flags = selectionCommand(index, event);
|
||||
m_pressedPosition = geometryPos;
|
||||
|
||||
m_pressedCategory = categoryAt(geometryPos);
|
||||
@@ -296,13 +222,19 @@ void GroupView::mousePressEvent(QMouseEvent *event)
|
||||
|
||||
if (index.isValid() && (index.flags() & Qt::ItemIsEnabled))
|
||||
{
|
||||
if(index != currentIndex())
|
||||
{
|
||||
// FIXME: better!
|
||||
m_currentCursorColumn = -1;
|
||||
}
|
||||
// we disable scrollTo for mouse press so the item doesn't change position
|
||||
// when the user is interacting with it (ie. clicking on it)
|
||||
bool autoScroll = hasAutoScroll();
|
||||
setAutoScroll(false);
|
||||
selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
|
||||
|
||||
setAutoScroll(autoScroll);
|
||||
QRect rect(geometryPos, geometryPos);
|
||||
QRect rect(visualPos, visualPos);
|
||||
setSelection(rect, QItemSelectionModel::ClearAndSelect);
|
||||
|
||||
// signal handlers may change the model
|
||||
@@ -359,7 +291,7 @@ void GroupView::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
setState(DragSelectingState);
|
||||
|
||||
setSelection(QRect(geometryPos, geometryPos), QItemSelectionModel::ClearAndSelect);
|
||||
setSelection(QRect(visualPos, visualPos), QItemSelectionModel::ClearAndSelect);
|
||||
QModelIndex index = indexAt(visualPos);
|
||||
|
||||
// set at the end because it might scroll the view
|
||||
@@ -452,7 +384,7 @@ void GroupView::paintEvent(QPaintEvent *event)
|
||||
option.rect.setWidth(wpWidth);
|
||||
for (int i = 0; i < m_groups.size(); ++i)
|
||||
{
|
||||
Group *category = m_groups.at(i);
|
||||
VisualGroup *category = m_groups.at(i);
|
||||
int y = category->verticalPosition();
|
||||
y -= verticalOffset();
|
||||
QRect backup = option.rect;
|
||||
@@ -528,16 +460,13 @@ void GroupView::paintEvent(QPaintEvent *event)
|
||||
|
||||
void GroupView::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
// QListView::resizeEvent(event);
|
||||
|
||||
// if (m_categoryEditor)
|
||||
// {
|
||||
// m_categoryEditor->resize(qMax(contentWidth() / 2,
|
||||
// m_editedCategory->textRect.width()),
|
||||
// m_categoryEditor->height());
|
||||
// }
|
||||
|
||||
updateGeometries();
|
||||
int newItemsPerRow = calculateItemsPerRow();
|
||||
if(newItemsPerRow != m_currentItemsPerRow)
|
||||
{
|
||||
m_currentCursorColumn = -1;
|
||||
m_currentItemsPerRow = newItemsPerRow;
|
||||
updateGeometries();
|
||||
}
|
||||
}
|
||||
|
||||
void GroupView::dragEnterEvent(QDragEnterEvent *event)
|
||||
@@ -580,8 +509,8 @@ void GroupView::dropEvent(QDropEvent *event)
|
||||
return;
|
||||
}
|
||||
|
||||
QPair<Group *, int> dropPos = rowDropPos(event->pos() + offset());
|
||||
const Group *category = dropPos.first;
|
||||
QPair<VisualGroup *, int> dropPos = rowDropPos(event->pos() + offset());
|
||||
const VisualGroup *category = dropPos.first;
|
||||
const int row = dropPos.second;
|
||||
|
||||
if (row == -1)
|
||||
@@ -605,44 +534,44 @@ void GroupView::dropEvent(QDropEvent *event)
|
||||
void GroupView::startDrag(Qt::DropActions supportedActions)
|
||||
{
|
||||
QModelIndexList indexes = selectionModel()->selectedIndexes();
|
||||
if (indexes.count() > 0)
|
||||
{
|
||||
QMimeData *data = model()->mimeData(indexes);
|
||||
if (!data)
|
||||
{
|
||||
return;
|
||||
}
|
||||
QRect rect;
|
||||
QPixmap pixmap = renderToPixmap(indexes, &rect);
|
||||
//rect.translate(offset());
|
||||
// rect.adjust(horizontalOffset(), verticalOffset(), 0, 0);
|
||||
QDrag *drag = new QDrag(this);
|
||||
drag->setPixmap(pixmap);
|
||||
drag->setMimeData(data);
|
||||
Qt::DropAction defaultDropAction = Qt::IgnoreAction;
|
||||
if (this->defaultDropAction() != Qt::IgnoreAction &&
|
||||
(supportedActions & this->defaultDropAction()))
|
||||
{
|
||||
defaultDropAction = this->defaultDropAction();
|
||||
}
|
||||
if (drag->exec(supportedActions, defaultDropAction) == Qt::MoveAction)
|
||||
{
|
||||
const QItemSelection selection = selectionModel()->selection();
|
||||
if(indexes.count() == 0)
|
||||
return;
|
||||
|
||||
for (auto it = selection.constBegin(); it != selection.constEnd(); ++it)
|
||||
QMimeData *data = model()->mimeData(indexes);
|
||||
if (!data)
|
||||
{
|
||||
return;
|
||||
}
|
||||
QRect rect;
|
||||
QPixmap pixmap = renderToPixmap(indexes, &rect);
|
||||
//rect.translate(offset());
|
||||
// rect.adjust(horizontalOffset(), verticalOffset(), 0, 0);
|
||||
QDrag *drag = new QDrag(this);
|
||||
drag->setPixmap(pixmap);
|
||||
drag->setMimeData(data);
|
||||
Qt::DropAction defaultDropAction = Qt::IgnoreAction;
|
||||
if (this->defaultDropAction() != Qt::IgnoreAction &&
|
||||
(supportedActions & this->defaultDropAction()))
|
||||
{
|
||||
defaultDropAction = this->defaultDropAction();
|
||||
}
|
||||
if (drag->exec(supportedActions, defaultDropAction) == Qt::MoveAction)
|
||||
{
|
||||
const QItemSelection selection = selectionModel()->selection();
|
||||
|
||||
for (auto it = selection.constBegin(); it != selection.constEnd(); ++it)
|
||||
{
|
||||
QModelIndex parent = (*it).parent();
|
||||
if ((*it).left() != 0)
|
||||
{
|
||||
QModelIndex parent = (*it).parent();
|
||||
if ((*it).left() != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ((*it).right() != (model()->columnCount(parent) - 1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int count = (*it).bottom() - (*it).top() + 1;
|
||||
model()->removeRows((*it).top(), count, parent);
|
||||
continue;
|
||||
}
|
||||
if ((*it).right() != (model()->columnCount(parent) - 1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int count = (*it).bottom() - (*it).top() + 1;
|
||||
model()->removeRows((*it).top(), count, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -659,58 +588,25 @@ QRect GroupView::geometryRect(const QModelIndex &index) const
|
||||
return QRect();
|
||||
}
|
||||
|
||||
const Group *cat = category(index);
|
||||
QPair<int, int> pos = categoryInternalPosition(index);
|
||||
int row = index.row();
|
||||
if(geometryCache.contains(row))
|
||||
{
|
||||
return *geometryCache[row];
|
||||
}
|
||||
|
||||
const VisualGroup *cat = category(index);
|
||||
QPair<int, int> pos = cat->positionOf(index);
|
||||
int x = pos.first;
|
||||
// int y = pos.second;
|
||||
|
||||
QRect out;
|
||||
out.setTop(cat->verticalPosition() + cat->headerHeight() + 5 + categoryInternalRowTop(index));
|
||||
out.setTop(cat->verticalPosition() + cat->headerHeight() + 5 + cat->rowTopOf(index));
|
||||
out.setLeft(m_spacing + x * (itemWidth() + m_spacing));
|
||||
out.setSize(itemDelegate()->sizeHint(viewOptions(), index));
|
||||
|
||||
geometryCache.insert(row, new QRect(out));
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
void CategorizedView::startCategoryEditor(Category *category)
|
||||
{
|
||||
if (m_categoryEditor != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_editedCategory = category;
|
||||
m_categoryEditor = new QLineEdit(m_editedCategory->text, this);
|
||||
QRect rect = m_editedCategory->textRect;
|
||||
rect.setWidth(qMax(contentWidth() / 2, rect.width()));
|
||||
m_categoryEditor->setGeometry(rect);
|
||||
m_categoryEditor->show();
|
||||
m_categoryEditor->setFocus();
|
||||
connect(m_categoryEditor, &QLineEdit::returnPressed, this,
|
||||
&CategorizedView::endCategoryEditor);
|
||||
}
|
||||
|
||||
void CategorizedView::endCategoryEditor()
|
||||
{
|
||||
if (m_categoryEditor == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_editedCategory->text = m_categoryEditor->text();
|
||||
m_updatesDisabled = true;
|
||||
foreach (const QModelIndex &index, itemsForCategory(m_editedCategory))
|
||||
{
|
||||
const_cast<QAbstractItemModel *>(index.model())->setData(index,
|
||||
m_categoryEditor->text(), CategoryRole);
|
||||
}
|
||||
m_updatesDisabled = false;
|
||||
delete m_categoryEditor;
|
||||
m_categoryEditor = 0;
|
||||
m_editedCategory = 0;
|
||||
updateGeometries();
|
||||
}
|
||||
*/
|
||||
|
||||
QModelIndex GroupView::indexAt(const QPoint &point) const
|
||||
{
|
||||
for (int i = 0; i < model()->rowCount(); ++i)
|
||||
@@ -724,21 +620,19 @@ QModelIndex GroupView::indexAt(const QPoint &point) const
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
// FIXME: is rect supposed to be geometry or visual coords?
|
||||
void GroupView::setSelection(const QRect &rect,
|
||||
const QItemSelectionModel::SelectionFlags commands)
|
||||
{
|
||||
for (int i = 0; i < model()->rowCount(); ++i)
|
||||
{
|
||||
QModelIndex index = model()->index(i, 0);
|
||||
QRect itemRect = geometryRect(index);
|
||||
QRect itemRect = visualRect(index);
|
||||
if (itemRect.intersects(rect))
|
||||
{
|
||||
selectionModel()->select(index, commands);
|
||||
update(itemRect.translated(-offset()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QPixmap GroupView::renderToPixmap(const QModelIndexList &indices, QRect *r) const
|
||||
@@ -781,33 +675,23 @@ QList<QPair<QRect, QModelIndex>> GroupView::draggablePaintPairs(const QModelInde
|
||||
|
||||
bool GroupView::isDragEventAccepted(QDropEvent *event)
|
||||
{
|
||||
if (event->source() != this)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!listsIntersect(event->mimeData()->formats(), model()->mimeTypes()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!model()->canDropMimeData(event->mimeData(), event->dropAction(),
|
||||
rowDropPos(event->pos()).second, 0, QModelIndex()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
QPair<Group *, int> GroupView::rowDropPos(const QPoint &pos)
|
||||
QPair<VisualGroup *, int> GroupView::rowDropPos(const QPoint &pos)
|
||||
{
|
||||
return qMakePair<VisualGroup*, int>(nullptr, -1);
|
||||
// FIXME: PIXIE DUST.
|
||||
/*
|
||||
// check that we aren't on a category header and calculate which category we're in
|
||||
Group *category = 0;
|
||||
VisualGroup *category = 0;
|
||||
{
|
||||
int y = 0;
|
||||
for (auto cat : m_groups)
|
||||
{
|
||||
if (pos.y() > y && pos.y() < (y + cat->headerHeight()))
|
||||
{
|
||||
return qMakePair<Group*, int>(nullptr, -1);
|
||||
return qMakePair<VisualGroup*, int>(nullptr, -1);
|
||||
}
|
||||
y += cat->totalHeight() + m_categoryMargin;
|
||||
if (pos.y() < y)
|
||||
@@ -818,7 +702,7 @@ QPair<Group *, int> GroupView::rowDropPos(const QPoint &pos)
|
||||
}
|
||||
if (category == 0)
|
||||
{
|
||||
return qMakePair<Group*, int>(nullptr, -1);
|
||||
return qMakePair<VisualGroup*, int>(nullptr, -1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -834,7 +718,7 @@ QPair<Group *, int> GroupView::rowDropPos(const QPoint &pos)
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0, c = 0; i < contentWidth(); i += itemWidth + 10 /*spacing()*/, ++c)
|
||||
for (int i = 0, c = 0; i < contentWidth(); i += itemWidth + 10 , ++c)
|
||||
{
|
||||
if (pos.x() > (i - itemWidth / 2) && pos.x() <= (i + itemWidth / 2))
|
||||
{
|
||||
@@ -845,7 +729,7 @@ QPair<Group *, int> GroupView::rowDropPos(const QPoint &pos)
|
||||
}
|
||||
if (internalColumn == -1)
|
||||
{
|
||||
return qMakePair<Group*, int>(nullptr, -1);
|
||||
return qMakePair<VisualGroup*, int>(nullptr, -1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -865,13 +749,13 @@ QPair<Group *, int> GroupView::rowDropPos(const QPoint &pos)
|
||||
}
|
||||
if (internalRow == -1)
|
||||
{
|
||||
return qMakePair<Group*, int>(nullptr, -1);
|
||||
return qMakePair<VisualGroup*, int>(nullptr, -1);
|
||||
}
|
||||
// this happens if we're in the margin between a one category and another
|
||||
// categories header
|
||||
if (internalRow > (indices.size() / itemsPerRow()))
|
||||
{
|
||||
return qMakePair<Group*, int>(nullptr, -1);
|
||||
return qMakePair<VisualGroup*, int>(nullptr, -1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -885,6 +769,7 @@ QPair<Group *, int> GroupView::rowDropPos(const QPoint &pos)
|
||||
}
|
||||
|
||||
return qMakePair(category, indices.at(categoryRow).row());
|
||||
*/
|
||||
}
|
||||
|
||||
QPoint GroupView::offset() const
|
||||
@@ -912,34 +797,191 @@ QRegion GroupView::visualRegionForSelection(const QItemSelection &selection) con
|
||||
}
|
||||
return region;
|
||||
}
|
||||
|
||||
QModelIndex GroupView::moveCursor(QAbstractItemView::CursorAction cursorAction,
|
||||
Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
auto current = currentIndex();
|
||||
if(!current.isValid())
|
||||
{
|
||||
qDebug() << "model row: invalid";
|
||||
return current;
|
||||
}
|
||||
qDebug() << "model row: " << current.row();
|
||||
auto cat = category(current);
|
||||
int i = m_groups.indexOf(cat);
|
||||
if(i >= 0)
|
||||
int group_index = m_groups.indexOf(cat);
|
||||
if(group_index < 0)
|
||||
return current;
|
||||
|
||||
auto real_group = m_groups[group_index];
|
||||
int beginning_row = 0;
|
||||
for(auto group: m_groups)
|
||||
{
|
||||
// this is a pile of something foul
|
||||
auto real_group = m_groups[i];
|
||||
int beginning_row = 0;
|
||||
for(auto group: m_groups)
|
||||
if(group == real_group)
|
||||
break;
|
||||
beginning_row += group->numRows();
|
||||
}
|
||||
|
||||
QPair<int, int> pos = cat->positionOf(current);
|
||||
int column = pos.first;
|
||||
int row = pos.second;
|
||||
if(m_currentCursorColumn < 0)
|
||||
{
|
||||
m_currentCursorColumn = column;
|
||||
}
|
||||
switch(cursorAction)
|
||||
{
|
||||
case MoveUp:
|
||||
{
|
||||
if(group == real_group)
|
||||
break;
|
||||
beginning_row += group->numRows();
|
||||
if(row == 0)
|
||||
{
|
||||
int prevgroupindex = group_index-1;
|
||||
while(prevgroupindex >= 0)
|
||||
{
|
||||
auto prevgroup = m_groups[prevgroupindex];
|
||||
if(prevgroup->collapsed)
|
||||
{
|
||||
prevgroupindex--;
|
||||
continue;
|
||||
}
|
||||
int newRow = prevgroup->numRows() - 1;
|
||||
int newRowSize = prevgroup->rows[newRow].size();
|
||||
int newColumn = m_currentCursorColumn;
|
||||
if (m_currentCursorColumn >= newRowSize)
|
||||
{
|
||||
newColumn = newRowSize - 1;
|
||||
}
|
||||
return prevgroup->rows[newRow][newColumn];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int newRow = row - 1;
|
||||
int newRowSize = cat->rows[newRow].size();
|
||||
int newColumn = m_currentCursorColumn;
|
||||
if (m_currentCursorColumn >= newRowSize)
|
||||
{
|
||||
newColumn = newRowSize - 1;
|
||||
}
|
||||
return cat->rows[newRow][newColumn];
|
||||
}
|
||||
return current;
|
||||
}
|
||||
qDebug() << "category: " << real_group->text;
|
||||
QPair<int, int> pos = categoryInternalPosition(current);
|
||||
int row = beginning_row + pos.second;
|
||||
qDebug() << "row: " << row;
|
||||
qDebug() << "column: " << pos.first;
|
||||
case MoveDown:
|
||||
{
|
||||
if(row == cat->rows.size() - 1)
|
||||
{
|
||||
int nextgroupindex = group_index+1;
|
||||
while (nextgroupindex < m_groups.size())
|
||||
{
|
||||
auto nextgroup = m_groups[nextgroupindex];
|
||||
if(nextgroup->collapsed)
|
||||
{
|
||||
nextgroupindex++;
|
||||
continue;
|
||||
}
|
||||
int newRowSize = nextgroup->rows[0].size();
|
||||
int newColumn = m_currentCursorColumn;
|
||||
if (m_currentCursorColumn >= newRowSize)
|
||||
{
|
||||
newColumn = newRowSize - 1;
|
||||
}
|
||||
return nextgroup->rows[0][newColumn];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int newRow = row + 1;
|
||||
int newRowSize = cat->rows[newRow].size();
|
||||
int newColumn = m_currentCursorColumn;
|
||||
if (m_currentCursorColumn >= newRowSize)
|
||||
{
|
||||
newColumn = newRowSize - 1;
|
||||
}
|
||||
return cat->rows[newRow][newColumn];
|
||||
}
|
||||
return current;
|
||||
}
|
||||
case MoveLeft:
|
||||
{
|
||||
if(column > 0)
|
||||
{
|
||||
m_currentCursorColumn = column - 1;
|
||||
return cat->rows[row][column - 1];
|
||||
}
|
||||
// TODO: moving to previous line
|
||||
return current;
|
||||
}
|
||||
case MoveRight:
|
||||
{
|
||||
if(column < cat->rows[row].size() - 1)
|
||||
{
|
||||
m_currentCursorColumn = column + 1;
|
||||
return cat->rows[row][column + 1];
|
||||
}
|
||||
// TODO: moving to next line
|
||||
return current;
|
||||
}
|
||||
case MoveHome:
|
||||
{
|
||||
m_currentCursorColumn = 0;
|
||||
return cat->rows[row][0];
|
||||
}
|
||||
case MoveEnd:
|
||||
{
|
||||
auto last = cat->rows[row].size() - 1;
|
||||
m_currentCursorColumn = last;
|
||||
return cat->rows[row][last];
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
int GroupView::horizontalOffset() const
|
||||
{
|
||||
return horizontalScrollBar()->value();
|
||||
}
|
||||
|
||||
int GroupView::verticalOffset() const
|
||||
{
|
||||
return verticalScrollBar()->value();
|
||||
}
|
||||
|
||||
void GroupView::scrollContentsBy(int dx, int dy)
|
||||
{
|
||||
scrollDirtyRegion(dx, dy);
|
||||
viewport()->scroll(dx, dy);
|
||||
}
|
||||
|
||||
void GroupView::scrollTo(const QModelIndex &index, ScrollHint hint)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return;
|
||||
|
||||
const QRect rect = visualRect(index);
|
||||
if (hint == EnsureVisible && viewport()->rect().contains(rect))
|
||||
{
|
||||
viewport()->update(rect);
|
||||
return;
|
||||
}
|
||||
|
||||
verticalScrollBar()->setValue(verticalScrollToValue(index, rect, hint));
|
||||
}
|
||||
|
||||
int GroupView::verticalScrollToValue(const QModelIndex &index, const QRect &rect,
|
||||
QListView::ScrollHint hint) const
|
||||
{
|
||||
const QRect area = viewport()->rect();
|
||||
const bool above = (hint == QListView::EnsureVisible && rect.top() < area.top());
|
||||
const bool below = (hint == QListView::EnsureVisible && rect.bottom() > area.bottom());
|
||||
|
||||
int verticalValue = verticalScrollBar()->value();
|
||||
QRect adjusted = rect.adjusted(-spacing(), -spacing(), spacing(), spacing());
|
||||
if (hint == QListView::PositionAtTop || above)
|
||||
verticalValue += adjusted.top();
|
||||
else if (hint == QListView::PositionAtBottom || below)
|
||||
verticalValue += qMin(adjusted.top(), adjusted.bottom() - area.height() + 1);
|
||||
else if (hint == QListView::PositionAtCenter)
|
||||
verticalValue += adjusted.top() - ((area.height() - adjusted.height()) / 2);
|
||||
return verticalValue;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <QListView>
|
||||
#include <QLineEdit>
|
||||
#include <QScrollBar>
|
||||
#include <QCache>
|
||||
|
||||
struct GroupViewRoles
|
||||
{
|
||||
@@ -14,7 +15,7 @@ struct GroupViewRoles
|
||||
};
|
||||
};
|
||||
|
||||
struct Group;
|
||||
struct VisualGroup;
|
||||
|
||||
class GroupView : public QAbstractItemView
|
||||
{
|
||||
@@ -35,35 +36,20 @@ public:
|
||||
void setSelection(const QRect &rect,
|
||||
const QItemSelectionModel::SelectionFlags commands) override;
|
||||
|
||||
virtual int horizontalOffset() const override
|
||||
{
|
||||
return horizontalScrollBar()->value();
|
||||
}
|
||||
|
||||
virtual int verticalOffset() const override
|
||||
{
|
||||
return verticalScrollBar()->value();
|
||||
}
|
||||
|
||||
virtual void scrollContentsBy(int dx, int dy) override
|
||||
{
|
||||
scrollDirtyRegion(dx, dy);
|
||||
viewport()->scroll(dx, dy);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO!
|
||||
*/
|
||||
virtual void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) override
|
||||
{
|
||||
return;
|
||||
}
|
||||
virtual int horizontalOffset() const override;
|
||||
virtual int verticalOffset() const override;
|
||||
virtual void scrollContentsBy(int dx, int dy) override;
|
||||
virtual void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) override;
|
||||
|
||||
virtual QModelIndex moveCursor(CursorAction cursorAction,
|
||||
Qt::KeyboardModifiers modifiers) override;
|
||||
|
||||
virtual QRegion visualRegionForSelection(const QItemSelection &selection) const override;
|
||||
|
||||
int spacing() const
|
||||
{
|
||||
return m_spacing;
|
||||
};
|
||||
protected
|
||||
slots:
|
||||
virtual void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
|
||||
@@ -90,57 +76,50 @@ protected:
|
||||
void startDrag(Qt::DropActions supportedActions) override;
|
||||
|
||||
private:
|
||||
friend struct Group;
|
||||
friend struct VisualGroup;
|
||||
QList<VisualGroup *> m_groups;
|
||||
|
||||
QList<Group *> m_groups;
|
||||
// geometry
|
||||
int m_leftMargin = 5;
|
||||
int m_rightMargin = 5;
|
||||
int m_bottomMargin = 5;
|
||||
int m_categoryMargin = 5;
|
||||
int m_spacing = 5;
|
||||
int m_itemWidth = 100;
|
||||
int m_currentItemsPerRow = -1;
|
||||
int m_currentCursorColumn= -1;
|
||||
mutable QCache<int, QRect> geometryCache;
|
||||
|
||||
int m_leftMargin;
|
||||
int m_rightMargin;
|
||||
int m_bottomMargin;
|
||||
int m_categoryMargin;
|
||||
|
||||
// bool m_updatesDisabled;
|
||||
|
||||
Group *category(const QModelIndex &index) const;
|
||||
Group *category(const QString &cat) const;
|
||||
Group *categoryAt(const QPoint &pos) const;
|
||||
|
||||
int itemsPerRow() const;
|
||||
int contentWidth() const;
|
||||
|
||||
private:
|
||||
int itemWidth() const;
|
||||
int categoryRowHeight(const QModelIndex &index) const;
|
||||
|
||||
/*QLineEdit *m_categoryEditor;
|
||||
Category *m_editedCategory;
|
||||
void startCategoryEditor(Category *category);
|
||||
|
||||
private slots:
|
||||
void endCategoryEditor();*/
|
||||
|
||||
private: /* variables */
|
||||
/// point where the currently active mouse action started in geometry coordinates
|
||||
// point where the currently active mouse action started in geometry coordinates
|
||||
QPoint m_pressedPosition;
|
||||
QPersistentModelIndex m_pressedIndex;
|
||||
bool m_pressedAlreadySelected;
|
||||
Group *m_pressedCategory;
|
||||
VisualGroup *m_pressedCategory;
|
||||
QItemSelectionModel::SelectionFlag m_ctrlDragSelectionFlag;
|
||||
QPoint m_lastDragPosition;
|
||||
int m_spacing = 5;
|
||||
|
||||
VisualGroup *category(const QModelIndex &index) const;
|
||||
VisualGroup *category(const QString &cat) const;
|
||||
VisualGroup *categoryAt(const QPoint &pos) const;
|
||||
|
||||
int itemsPerRow() const
|
||||
{
|
||||
return m_currentItemsPerRow;
|
||||
};
|
||||
int contentWidth() const;
|
||||
|
||||
private: /* methods */
|
||||
QPair<int, int> categoryInternalPosition(const QModelIndex &index) const;
|
||||
int categoryInternalRowTop(const QModelIndex &index) const;
|
||||
int itemHeightForCategoryRow(const Group *category, const int internalRow) const;
|
||||
|
||||
int itemWidth() const;
|
||||
int calculateItemsPerRow() const;
|
||||
int verticalScrollToValue(const QModelIndex &index, const QRect &rect,
|
||||
QListView::ScrollHint hint) const;
|
||||
QPixmap renderToPixmap(const QModelIndexList &indices, QRect *r) const;
|
||||
QList<QPair<QRect, QModelIndex>> draggablePaintPairs(const QModelIndexList &indices,
|
||||
QRect *r) const;
|
||||
|
||||
bool isDragEventAccepted(QDropEvent *event);
|
||||
|
||||
QPair<Group *, int> rowDropPos(const QPoint &pos);
|
||||
QPair<VisualGroup *, int> rowDropPos(const QPoint &pos);
|
||||
|
||||
QPoint offset() const;
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
#include "GroupView.h"
|
||||
#include "logic/BaseInstance.h"
|
||||
#include "logic/lists/InstanceList.h"
|
||||
#include "logic/InstanceList.h"
|
||||
|
||||
QCache<QString, QPixmap> ListViewDelegate::m_pixmapCache;
|
||||
|
||||
@@ -120,6 +120,8 @@ void drawBadges(QPainter *painter, const QStyleOptionViewItemV4 &option, BaseIns
|
||||
case BaseInstance::VersionBrokenFlag:
|
||||
pixmaps.append("broken");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "Group.h"
|
||||
#include "VisualGroup.h"
|
||||
|
||||
#include <QModelIndex>
|
||||
#include <QPainter>
|
||||
@@ -7,30 +7,83 @@
|
||||
|
||||
#include "GroupView.h"
|
||||
|
||||
Group::Group(const QString &text, GroupView *view) : view(view), text(text), collapsed(false)
|
||||
VisualGroup::VisualGroup(const QString &text, GroupView *view) : view(view), text(text), collapsed(false)
|
||||
{
|
||||
}
|
||||
|
||||
Group::Group(const Group *other)
|
||||
VisualGroup::VisualGroup(const VisualGroup *other)
|
||||
: view(other->view), text(other->text), collapsed(other->collapsed)
|
||||
{
|
||||
}
|
||||
|
||||
void Group::update()
|
||||
void VisualGroup::update()
|
||||
{
|
||||
firstItemIndex = firstItem().row();
|
||||
auto temp_items = items();
|
||||
auto itemsPerRow = view->itemsPerRow();
|
||||
|
||||
rowHeights = QVector<int>(numRows());
|
||||
for (int i = 0; i < numRows(); ++i)
|
||||
int numRows = qMax(1, qCeil((qreal)temp_items.size() / (qreal)itemsPerRow));
|
||||
rows = QVector<VisualRow>(numRows);
|
||||
|
||||
int maxRowHeight = 0;
|
||||
int positionInRow = 0;
|
||||
int currentRow = 0;
|
||||
int offsetFromTop = 0;
|
||||
for (auto item: temp_items)
|
||||
{
|
||||
rowHeights[i] = view->categoryRowHeight(
|
||||
view->model()->index(i * view->itemsPerRow() + firstItemIndex, 0));
|
||||
if(positionInRow == itemsPerRow)
|
||||
{
|
||||
rows[currentRow].height = maxRowHeight;
|
||||
rows[currentRow].top = offsetFromTop;
|
||||
currentRow ++;
|
||||
offsetFromTop += maxRowHeight + 5;
|
||||
positionInRow = 0;
|
||||
maxRowHeight = 0;
|
||||
}
|
||||
auto itemHeight = view->itemDelegate()->sizeHint(view->viewOptions(), item).height();
|
||||
if(itemHeight > maxRowHeight)
|
||||
{
|
||||
maxRowHeight = itemHeight;
|
||||
}
|
||||
rows[currentRow].items.append(item);
|
||||
positionInRow++;
|
||||
}
|
||||
rows[currentRow].height = maxRowHeight;
|
||||
rows[currentRow].top = offsetFromTop;
|
||||
}
|
||||
|
||||
Group::HitResults Group::hitScan(const QPoint &pos) const
|
||||
QPair<int, int> VisualGroup::positionOf(const QModelIndex &index) const
|
||||
{
|
||||
Group::HitResults results = Group::NoHit;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
for (auto & row: rows)
|
||||
{
|
||||
for(auto x = 0; x < row.items.size(); x++)
|
||||
{
|
||||
if(row.items[x] == index)
|
||||
{
|
||||
return qMakePair(x,y);
|
||||
}
|
||||
}
|
||||
y++;
|
||||
}
|
||||
return qMakePair(x, y);
|
||||
}
|
||||
|
||||
int VisualGroup::rowTopOf(const QModelIndex &index) const
|
||||
{
|
||||
auto position = positionOf(index);
|
||||
return rows[position.second].top;
|
||||
}
|
||||
|
||||
int VisualGroup::rowHeightOf(const QModelIndex &index) const
|
||||
{
|
||||
auto position = positionOf(index);
|
||||
return rows[position.second].height;
|
||||
}
|
||||
|
||||
VisualGroup::HitResults VisualGroup::hitScan(const QPoint &pos) const
|
||||
{
|
||||
VisualGroup::HitResults results = VisualGroup::NoHit;
|
||||
int y_start = verticalPosition();
|
||||
int body_start = y_start + headerHeight();
|
||||
int body_end = body_start + contentHeight() + 5; // FIXME: wtf is this 5?
|
||||
@@ -38,28 +91,28 @@ Group::HitResults Group::hitScan(const QPoint &pos) const
|
||||
// int x = pos.x();
|
||||
if (y < y_start)
|
||||
{
|
||||
results = Group::NoHit;
|
||||
results = VisualGroup::NoHit;
|
||||
}
|
||||
else if (y < body_start)
|
||||
{
|
||||
results = Group::HeaderHit;
|
||||
results = VisualGroup::HeaderHit;
|
||||
int collapseSize = headerHeight() - 4;
|
||||
|
||||
// the icon
|
||||
QRect iconRect = QRect(view->m_leftMargin + 2, 2 + y_start, collapseSize, collapseSize);
|
||||
if (iconRect.contains(pos))
|
||||
{
|
||||
results |= Group::CheckboxHit;
|
||||
results |= VisualGroup::CheckboxHit;
|
||||
}
|
||||
}
|
||||
else if (y < body_end)
|
||||
{
|
||||
results |= Group::BodyHit;
|
||||
results |= VisualGroup::BodyHit;
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
void Group::drawHeader(QPainter *painter, const QStyleOptionViewItem &option)
|
||||
void VisualGroup::drawHeader(QPainter *painter, const QStyleOptionViewItem &option)
|
||||
{
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
@@ -190,12 +243,12 @@ void Group::drawHeader(QPainter *painter, const QStyleOptionViewItem &option)
|
||||
//END: text
|
||||
}
|
||||
|
||||
int Group::totalHeight() const
|
||||
int VisualGroup::totalHeight() const
|
||||
{
|
||||
return headerHeight() + 5 + contentHeight(); // FIXME: wtf is that '5'?
|
||||
}
|
||||
|
||||
int Group::headerHeight() const
|
||||
int VisualGroup::headerHeight() const
|
||||
{
|
||||
QFont font(QApplication::font());
|
||||
font.setBold(true);
|
||||
@@ -213,31 +266,27 @@ int Group::headerHeight() const
|
||||
*/
|
||||
}
|
||||
|
||||
int Group::contentHeight() const
|
||||
int VisualGroup::contentHeight() const
|
||||
{
|
||||
if (collapsed)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int result = 0;
|
||||
for (int i = 0; i < rowHeights.size(); ++i)
|
||||
{
|
||||
result += rowHeights[i];
|
||||
}
|
||||
return result;
|
||||
auto last = rows[numRows() - 1];
|
||||
return last.top + last.height;
|
||||
}
|
||||
|
||||
int Group::numRows() const
|
||||
int VisualGroup::numRows() const
|
||||
{
|
||||
return qMax(1, qCeil((qreal)numItems() / (qreal)view->itemsPerRow()));
|
||||
return rows.size();
|
||||
}
|
||||
|
||||
int Group::verticalPosition() const
|
||||
int VisualGroup::verticalPosition() const
|
||||
{
|
||||
return m_verticalPosition;
|
||||
}
|
||||
|
||||
QList<QModelIndex> Group::items() const
|
||||
QList<QModelIndex> VisualGroup::items() const
|
||||
{
|
||||
QList<QModelIndex> indices;
|
||||
for (int i = 0; i < view->model()->rowCount(); ++i)
|
||||
@@ -250,20 +299,3 @@ QList<QModelIndex> Group::items() const
|
||||
}
|
||||
return indices;
|
||||
}
|
||||
|
||||
int Group::numItems() const
|
||||
{
|
||||
return items().size();
|
||||
}
|
||||
|
||||
QModelIndex Group::firstItem() const
|
||||
{
|
||||
QList<QModelIndex> indices = items();
|
||||
return indices.isEmpty() ? QModelIndex() : indices.first();
|
||||
}
|
||||
|
||||
QModelIndex Group::lastItem() const
|
||||
{
|
||||
QList<QModelIndex> indices = items();
|
||||
return indices.isEmpty() ? QModelIndex() : indices.last();
|
||||
}
|
||||
@@ -9,22 +9,37 @@ class GroupView;
|
||||
class QPainter;
|
||||
class QModelIndex;
|
||||
|
||||
struct Group
|
||||
struct VisualRow
|
||||
{
|
||||
QList<QModelIndex> items;
|
||||
int height = 0;
|
||||
int top = 0;
|
||||
inline int size() const
|
||||
{
|
||||
return items.size();
|
||||
}
|
||||
inline QModelIndex &operator[](int i)
|
||||
{
|
||||
return items[i];
|
||||
}
|
||||
};
|
||||
|
||||
struct VisualGroup
|
||||
{
|
||||
/* constructors */
|
||||
Group(const QString &text, GroupView *view);
|
||||
Group(const Group *other);
|
||||
VisualGroup(const QString &text, GroupView *view);
|
||||
VisualGroup(const VisualGroup *other);
|
||||
|
||||
/* data */
|
||||
GroupView *view = nullptr;
|
||||
QString text;
|
||||
bool collapsed = false;
|
||||
QVector<int> rowHeights;
|
||||
QVector<VisualRow> rows;
|
||||
int firstItemIndex = 0;
|
||||
int m_verticalPosition = 0;
|
||||
|
||||
/* logic */
|
||||
/// do stuff. and things. TODO: redo.
|
||||
/// update the internal list of items and flow them into the rows.
|
||||
void update();
|
||||
|
||||
/// draw the header at y-position.
|
||||
@@ -42,9 +57,21 @@ struct Group
|
||||
/// the number of visual rows this group has
|
||||
int numRows() const;
|
||||
|
||||
/// actually calculate the above value
|
||||
int calculateNumRows() const;
|
||||
|
||||
/// the height at which this group starts, in pixels
|
||||
int verticalPosition() const;
|
||||
|
||||
/// relative geometry - top of the row of the given item
|
||||
int rowTopOf(const QModelIndex &index) const;
|
||||
|
||||
/// height of the row of the given item
|
||||
int rowHeightOf(const QModelIndex &index) const;
|
||||
|
||||
/// x/y position of the given item inside the group (in items!)
|
||||
QPair<int, int> positionOf(const QModelIndex &index) const;
|
||||
|
||||
enum HitResult
|
||||
{
|
||||
NoHit = 0x0,
|
||||
@@ -58,12 +85,7 @@ struct Group
|
||||
/// shoot! BANG! what did we hit?
|
||||
HitResults hitScan (const QPoint &pos) const;
|
||||
|
||||
/// super derpy thing.
|
||||
QList<QModelIndex> items() const;
|
||||
/// I don't even
|
||||
int numItems() const;
|
||||
QModelIndex firstItem() const;
|
||||
QModelIndex lastItem() const;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(Group::HitResults)
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(VisualGroup::HitResults)
|
||||
62
gui/pagedialog/PageDialog.cpp
Normal file
62
gui/pagedialog/PageDialog.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "PageDialog.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QKeyEvent>
|
||||
|
||||
#include "MultiMC.h"
|
||||
#include "logic/settings/SettingsObject.h"
|
||||
#include "gui/Platform.h"
|
||||
#include "gui/widgets/IconLabel.h"
|
||||
#include "gui/widgets/PageContainer.h"
|
||||
|
||||
PageDialog::PageDialog(BasePageProviderPtr pageProvider, QString defaultId, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
MultiMCPlatform::fixWM_CLASS(this);
|
||||
setWindowTitle(pageProvider->dialogTitle());
|
||||
m_container = new PageContainer(pageProvider, defaultId, this);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addWidget(m_container);
|
||||
mainLayout->setSpacing(0);
|
||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
setLayout(mainLayout);
|
||||
|
||||
QDialogButtonBox *buttons =
|
||||
new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Close);
|
||||
buttons->button(QDialogButtonBox::Close)->setDefault(true);
|
||||
m_container->addButtons(buttons);
|
||||
|
||||
connect(buttons->button(QDialogButtonBox::Close), SIGNAL(clicked()), this, SLOT(close()));
|
||||
connect(buttons->button(QDialogButtonBox::Help), SIGNAL(clicked()), m_container,
|
||||
SLOT(help()));
|
||||
|
||||
restoreGeometry(
|
||||
QByteArray::fromBase64(MMC->settings()->get("PagedGeometry").toByteArray()));
|
||||
}
|
||||
|
||||
void PageDialog::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
if (m_container->requestClose(event))
|
||||
{
|
||||
MMC->settings()->set("PagedGeometry", saveGeometry().toBase64());
|
||||
QDialog::closeEvent(event);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,23 +16,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include "gui/pages/BasePageProvider.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class EditNotesDialog;
|
||||
}
|
||||
|
||||
class EditNotesDialog : public QDialog
|
||||
class PageContainer;
|
||||
class PageDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit EditNotesDialog(QString notes, QString name, QWidget *parent = 0);
|
||||
~EditNotesDialog();
|
||||
QString getText();
|
||||
explicit PageDialog(BasePageProviderPtr pageProvider, QString defaultId = QString(),
|
||||
QWidget *parent = 0);
|
||||
virtual ~PageDialog() {}
|
||||
|
||||
private
|
||||
slots:
|
||||
virtual void closeEvent(QCloseEvent *event);
|
||||
|
||||
private:
|
||||
Ui::EditNotesDialog *ui;
|
||||
QString m_instance_name;
|
||||
QString m_instance_notes;
|
||||
PageContainer * m_container;
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,15 +15,24 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "OneSixInstance.h"
|
||||
#include <QString>
|
||||
#include <QIcon>
|
||||
#include <memory>
|
||||
|
||||
class NostalgiaInstance : public OneSixInstance
|
||||
class BasePage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit NostalgiaInstance(const QString &rootDir, SettingsObject *settings,
|
||||
QObject *parent = 0);
|
||||
virtual ~NostalgiaInstance() {};
|
||||
virtual QString getStatusbarDescription();
|
||||
virtual bool menuActionEnabled(QString action_name) const;
|
||||
virtual ~BasePage() {}
|
||||
virtual QString id() const = 0;
|
||||
virtual QString displayName() const = 0;
|
||||
virtual QIcon icon() const = 0;
|
||||
virtual bool apply() { return true; }
|
||||
virtual bool shouldDisplay() const { return true; }
|
||||
virtual QString helpPage() const { return QString(); }
|
||||
virtual void opened() {}
|
||||
virtual void closed() {}
|
||||
int stackIndex = -1;
|
||||
int listIndex = -1;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<BasePage> BasePagePtr;
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,15 +15,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
#include "BasePage.h"
|
||||
#include <memory>
|
||||
|
||||
#ifdef LIBSETTINGS_STATIC
|
||||
#define LIBSETTINGS_EXPORT
|
||||
#else
|
||||
#ifdef LIBSETTINGS_LIBRARY
|
||||
#define LIBSETTINGS_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
#define LIBSETTINGS_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
#endif
|
||||
class BasePageProvider
|
||||
{
|
||||
public:
|
||||
virtual QList<BasePage *> getPages() = 0;
|
||||
virtual QString dialogTitle() = 0;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<BasePageProvider> BasePageProviderPtr;
|
||||
216
gui/pages/InstanceSettingsPage.cpp
Normal file
216
gui/pages/InstanceSettingsPage.cpp
Normal file
@@ -0,0 +1,216 @@
|
||||
#include "InstanceSettingsPage.h"
|
||||
#include "ui_InstanceSettingsPage.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "gui/dialogs/VersionSelectDialog.h"
|
||||
#include "logic/NagUtils.h"
|
||||
#include "logic/java/JavaVersionList.h"
|
||||
#include "MultiMC.h"
|
||||
|
||||
InstanceSettingsPage::InstanceSettingsPage(BaseInstance *inst, QWidget *parent)
|
||||
: QWidget(parent), ui(new Ui::InstanceSettingsPage), m_instance(inst)
|
||||
{
|
||||
m_settings = &(inst->settings());
|
||||
ui->setupUi(this);
|
||||
loadSettings();
|
||||
}
|
||||
|
||||
bool InstanceSettingsPage::shouldDisplay() const
|
||||
{
|
||||
return !m_instance->isRunning();
|
||||
}
|
||||
|
||||
InstanceSettingsPage::~InstanceSettingsPage()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
bool InstanceSettingsPage::apply()
|
||||
{
|
||||
applySettings();
|
||||
return true;
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::applySettings()
|
||||
{
|
||||
// Console
|
||||
bool console = ui->consoleSettingsBox->isChecked();
|
||||
m_settings->set("OverrideConsole", console);
|
||||
if (console)
|
||||
{
|
||||
m_settings->set("ShowConsole", ui->showConsoleCheck->isChecked());
|
||||
m_settings->set("AutoCloseConsole", ui->autoCloseConsoleCheck->isChecked());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_settings->reset("ShowConsole");
|
||||
m_settings->reset("AutoCloseConsole");
|
||||
}
|
||||
|
||||
// Window Size
|
||||
bool window = ui->windowSizeGroupBox->isChecked();
|
||||
m_settings->set("OverrideWindow", window);
|
||||
if (window)
|
||||
{
|
||||
m_settings->set("LaunchMaximized", ui->maximizedCheckBox->isChecked());
|
||||
m_settings->set("MinecraftWinWidth", ui->windowWidthSpinBox->value());
|
||||
m_settings->set("MinecraftWinHeight", ui->windowHeightSpinBox->value());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_settings->reset("LaunchMaximized");
|
||||
m_settings->reset("MinecraftWinWidth");
|
||||
m_settings->reset("MinecraftWinHeight");
|
||||
}
|
||||
|
||||
// Memory
|
||||
bool memory = ui->memoryGroupBox->isChecked();
|
||||
m_settings->set("OverrideMemory", memory);
|
||||
if (memory)
|
||||
{
|
||||
m_settings->set("MinMemAlloc", ui->minMemSpinBox->value());
|
||||
m_settings->set("MaxMemAlloc", ui->maxMemSpinBox->value());
|
||||
m_settings->set("PermGen", ui->permGenSpinBox->value());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_settings->reset("MinMemAlloc");
|
||||
m_settings->reset("MaxMemAlloc");
|
||||
m_settings->reset("PermGen");
|
||||
}
|
||||
|
||||
// Java Install Settings
|
||||
bool javaInstall = ui->javaSettingsGroupBox->isChecked();
|
||||
m_settings->set("OverrideJavaLocation", javaInstall);
|
||||
if (javaInstall)
|
||||
{
|
||||
m_settings->set("JavaPath", ui->javaPathTextBox->text());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_settings->reset("JavaPath");
|
||||
}
|
||||
|
||||
// Java arguments
|
||||
bool javaArgs = ui->javaArgumentsGroupBox->isChecked();
|
||||
m_settings->set("OverrideJavaArgs", javaArgs);
|
||||
if(javaArgs)
|
||||
{
|
||||
m_settings->set("JvmArgs", ui->jvmArgsTextBox->toPlainText().replace("\n", " "));
|
||||
NagUtils::checkJVMArgs(m_settings->get("JvmArgs").toString(), this->parentWidget());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_settings->reset("JvmArgs");
|
||||
}
|
||||
|
||||
// old generic 'override both' is removed.
|
||||
m_settings->reset("OverrideJava");
|
||||
|
||||
// Custom Commands
|
||||
bool custcmd = ui->customCommandsGroupBox->isChecked();
|
||||
m_settings->set("OverrideCommands", custcmd);
|
||||
if (custcmd)
|
||||
{
|
||||
m_settings->set("PreLaunchCommand", ui->preLaunchCmdTextBox->text());
|
||||
m_settings->set("PostExitCommand", ui->postExitCmdTextBox->text());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_settings->reset("PreLaunchCommand");
|
||||
m_settings->reset("PostExitCommand");
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::loadSettings()
|
||||
{
|
||||
// Console
|
||||
ui->consoleSettingsBox->setChecked(m_settings->get("OverrideConsole").toBool());
|
||||
ui->showConsoleCheck->setChecked(m_settings->get("ShowConsole").toBool());
|
||||
ui->autoCloseConsoleCheck->setChecked(m_settings->get("AutoCloseConsole").toBool());
|
||||
|
||||
// Window Size
|
||||
ui->windowSizeGroupBox->setChecked(m_settings->get("OverrideWindow").toBool());
|
||||
ui->maximizedCheckBox->setChecked(m_settings->get("LaunchMaximized").toBool());
|
||||
ui->windowWidthSpinBox->setValue(m_settings->get("MinecraftWinWidth").toInt());
|
||||
ui->windowHeightSpinBox->setValue(m_settings->get("MinecraftWinHeight").toInt());
|
||||
|
||||
// Memory
|
||||
ui->memoryGroupBox->setChecked(m_settings->get("OverrideMemory").toBool());
|
||||
ui->minMemSpinBox->setValue(m_settings->get("MinMemAlloc").toInt());
|
||||
ui->maxMemSpinBox->setValue(m_settings->get("MaxMemAlloc").toInt());
|
||||
ui->permGenSpinBox->setValue(m_settings->get("PermGen").toInt());
|
||||
|
||||
// Java Settings
|
||||
bool overrideJava = m_settings->get("OverrideJava").toBool();
|
||||
bool overrideLocation = m_settings->get("OverrideJavaLocation").toBool() || overrideJava;
|
||||
bool overrideArgs = m_settings->get("OverrideJavaArgs").toBool() || overrideJava;
|
||||
|
||||
ui->javaSettingsGroupBox->setChecked(overrideLocation);
|
||||
ui->javaPathTextBox->setText(m_settings->get("JavaPath").toString());
|
||||
|
||||
ui->javaArgumentsGroupBox->setChecked(overrideArgs);
|
||||
ui->jvmArgsTextBox->setPlainText(m_settings->get("JvmArgs").toString());
|
||||
|
||||
// Custom Commands
|
||||
ui->customCommandsGroupBox->setChecked(m_settings->get("OverrideCommands").toBool());
|
||||
ui->preLaunchCmdTextBox->setText(m_settings->get("PreLaunchCommand").toString());
|
||||
ui->postExitCmdTextBox->setText(m_settings->get("PostExitCommand").toString());
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::on_javaDetectBtn_clicked()
|
||||
{
|
||||
JavaVersionPtr java;
|
||||
|
||||
VersionSelectDialog vselect(MMC->javalist().get(), tr("Select a Java version"), this, true);
|
||||
vselect.setResizeOn(2);
|
||||
vselect.exec();
|
||||
|
||||
if (vselect.result() == QDialog::Accepted && vselect.selectedVersion())
|
||||
{
|
||||
java = std::dynamic_pointer_cast<JavaVersion>(vselect.selectedVersion());
|
||||
ui->javaPathTextBox->setText(java->path);
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::on_javaBrowseBtn_clicked()
|
||||
{
|
||||
QString dir = QFileDialog::getOpenFileName(this, tr("Find Java executable"));
|
||||
if (!dir.isNull())
|
||||
{
|
||||
ui->javaPathTextBox->setText(dir);
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::on_javaTestBtn_clicked()
|
||||
{
|
||||
checker.reset(new JavaChecker());
|
||||
connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this,
|
||||
SLOT(checkFinished(JavaCheckResult)));
|
||||
checker->path = ui->javaPathTextBox->text();
|
||||
checker->performCheck();
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::checkFinished(JavaCheckResult result)
|
||||
{
|
||||
if (result.valid)
|
||||
{
|
||||
QString text;
|
||||
text += "Java test succeeded!\n";
|
||||
if (result.is_64bit)
|
||||
text += "Using 64bit java.\n";
|
||||
text += "\n";
|
||||
text += "Platform reported: " + result.realPlatform;
|
||||
QMessageBox::information(this, tr("Java test success"), text);
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(
|
||||
this, tr("Java test failure"),
|
||||
tr("The specified java binary didn't work. You should use the auto-detect feature, "
|
||||
"or set the path to the java executable."));
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,37 +15,45 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include "settingsobject.h"
|
||||
#include "logic/JavaChecker.h"
|
||||
#include <QWidget>
|
||||
|
||||
#include "logic/OneSixInstance.h"
|
||||
#include "logic/net/NetJob.h"
|
||||
#include "logic/java/JavaChecker.h"
|
||||
#include "BasePage.h"
|
||||
|
||||
class JavaChecker;
|
||||
namespace Ui
|
||||
{
|
||||
class InstanceSettings;
|
||||
class InstanceSettingsPage;
|
||||
}
|
||||
|
||||
class InstanceSettings : public QDialog
|
||||
class InstanceSettingsPage : public QWidget, public BasePage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit InstanceSettings(SettingsObject *s, QWidget *parent = 0);
|
||||
~InstanceSettings();
|
||||
|
||||
void updateCheckboxStuff();
|
||||
|
||||
void applySettings();
|
||||
void loadSettings();
|
||||
|
||||
protected:
|
||||
virtual void showEvent(QShowEvent *);
|
||||
virtual void closeEvent(QCloseEvent *);
|
||||
private
|
||||
slots:
|
||||
void on_customCommandsGroupBox_toggled(bool arg1);
|
||||
void on_buttonBox_accepted();
|
||||
void on_buttonBox_rejected();
|
||||
|
||||
explicit InstanceSettingsPage(BaseInstance *inst, QWidget *parent = 0);
|
||||
virtual ~InstanceSettingsPage();
|
||||
virtual QString displayName() const override
|
||||
{
|
||||
return tr("Settings");
|
||||
}
|
||||
virtual QIcon icon() const override
|
||||
{
|
||||
return QIcon::fromTheme("settings");
|
||||
}
|
||||
virtual QString id() const override
|
||||
{
|
||||
return "settings";
|
||||
}
|
||||
virtual bool apply();
|
||||
virtual QString helpPage() const override
|
||||
{
|
||||
return "Instance-settings";
|
||||
}
|
||||
virtual bool shouldDisplay() const;
|
||||
private slots:
|
||||
void on_javaDetectBtn_clicked();
|
||||
|
||||
void on_javaTestBtn_clicked();
|
||||
@@ -53,8 +61,13 @@ slots:
|
||||
void on_javaBrowseBtn_clicked();
|
||||
|
||||
void checkFinished(JavaCheckResult result);
|
||||
|
||||
void applySettings();
|
||||
void loadSettings();
|
||||
|
||||
private:
|
||||
Ui::InstanceSettings *ui;
|
||||
SettingsObject *m_obj;
|
||||
Ui::InstanceSettingsPage *ui;
|
||||
BaseInstance *m_instance;
|
||||
SettingsObject *m_settings;
|
||||
std::shared_ptr<JavaChecker> checker;
|
||||
};
|
||||
@@ -1,19 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>InstanceSettings</class>
|
||||
<widget class="QDialog" name="InstanceSettings">
|
||||
<class>InstanceSettingsPage</class>
|
||||
<widget class="QWidget" name="InstanceSettingsPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>526</width>
|
||||
<height>637</height>
|
||||
<width>458</width>
|
||||
<height>426</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Instance Settings</string>
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="settingsTabs">
|
||||
<property name="tabShape">
|
||||
@@ -23,134 +35,52 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="minecraftTab">
|
||||
<attribute name="title">
|
||||
<string>Minecraft</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="windowSizeGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Window Size</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="maximizedCheckBox">
|
||||
<property name="text">
|
||||
<string>Start Minecraft maximized?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayoutWindowSize">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelWindowHeight">
|
||||
<property name="text">
|
||||
<string>Window height:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelWindowWidth">
|
||||
<property name="text">
|
||||
<string>Window width:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="windowWidthSpinBox">
|
||||
<property name="minimum">
|
||||
<number>854</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65536</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>854</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="windowHeightSpinBox">
|
||||
<property name="minimum">
|
||||
<number>480</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65536</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>480</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="consoleSettingsBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Console Settings</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showConsoleCheck">
|
||||
<property name="text">
|
||||
<string>Show console while the game is running?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="autoCloseConsoleCheck">
|
||||
<property name="text">
|
||||
<string>Automatically close console when the game quits?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacerMinecraft">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="javaTab">
|
||||
<attribute name="title">
|
||||
<string>Java</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="javaSettingsGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Java installation</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QLineEdit" name="javaPathTextBox"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QPushButton" name="javaDetectBtn">
|
||||
<property name="text">
|
||||
<string>Auto-detect...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="javaBrowseBtn">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="javaTestBtn">
|
||||
<property name="text">
|
||||
<string>Test</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="memoryGroupBox">
|
||||
<property name="enabled">
|
||||
@@ -257,12 +187,12 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="javaSettingsGroupBox">
|
||||
<widget class="QGroupBox" name="javaArgumentsGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Java Settings</string>
|
||||
<string>Java arguments</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
@@ -270,51 +200,157 @@
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="2" column="4">
|
||||
<widget class="QPushButton" name="javaTestBtn">
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="1" column="1">
|
||||
<widget class="QPlainTextEdit" name="jvmArgsTextBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacerMinecraft">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="javaTab">
|
||||
<attribute name="title">
|
||||
<string>Game windows</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="windowSizeGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Game Window</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="maximizedCheckBox">
|
||||
<property name="text">
|
||||
<string>Test</string>
|
||||
<string>Start Minecraft maximized?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelJavaPath">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayoutWindowSize">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelWindowHeight">
|
||||
<property name="text">
|
||||
<string>Window height:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelWindowWidth">
|
||||
<property name="text">
|
||||
<string>Window width:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="windowWidthSpinBox">
|
||||
<property name="minimum">
|
||||
<number>854</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65536</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>854</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="windowHeightSpinBox">
|
||||
<property name="minimum">
|
||||
<number>480</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65536</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>480</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="consoleSettingsBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Console Settings</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showConsoleCheck">
|
||||
<property name="text">
|
||||
<string>Java path:</string>
|
||||
<string>Show console while the game is running?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="labelJVMArgs">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="autoCloseConsoleCheck">
|
||||
<property name="text">
|
||||
<string>JVM arguments:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2" colspan="3">
|
||||
<widget class="QLineEdit" name="jvmArgsTextBox"/>
|
||||
</item>
|
||||
<item row="0" column="2" colspan="3">
|
||||
<widget class="QLineEdit" name="javaPathTextBox"/>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QPushButton" name="javaBrowseBtn">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QPushButton" name="javaDetectBtn">
|
||||
<property name="text">
|
||||
<string>Auto-detect...</string>
|
||||
<string>Automatically close console when the game quits?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacerMinecraft_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>88</width>
|
||||
<height>125</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>Custom commands</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="customCommandsGroupBox">
|
||||
<property name="enabled">
|
||||
@@ -358,12 +394,6 @@
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Pre-launch command runs before the instance launches and post-exit command runs after it exits. Both will be run in MultiMC's working directory with INST_ID, INST_DIR, and INST_NAME as environment variables.</string>
|
||||
</property>
|
||||
@@ -378,42 +408,25 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacerMinecraft_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>88</width>
|
||||
<height>186</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>settingsTabs</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
<tabstop>windowSizeGroupBox</tabstop>
|
||||
<tabstop>maximizedCheckBox</tabstop>
|
||||
<tabstop>windowWidthSpinBox</tabstop>
|
||||
<tabstop>windowHeightSpinBox</tabstop>
|
||||
<tabstop>consoleSettingsBox</tabstop>
|
||||
<tabstop>showConsoleCheck</tabstop>
|
||||
<tabstop>autoCloseConsoleCheck</tabstop>
|
||||
<tabstop>memoryGroupBox</tabstop>
|
||||
<tabstop>minMemSpinBox</tabstop>
|
||||
<tabstop>maxMemSpinBox</tabstop>
|
||||
<tabstop>permGenSpinBox</tabstop>
|
||||
<tabstop>javaSettingsGroupBox</tabstop>
|
||||
<tabstop>jvmArgsTextBox</tabstop>
|
||||
<tabstop>customCommandsGroupBox</tabstop>
|
||||
<tabstop>preLaunchCmdTextBox</tabstop>
|
||||
<tabstop>postExitCmdTextBox</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
196
gui/pages/LegacyJarModPage.cpp
Normal file
196
gui/pages/LegacyJarModPage.cpp
Normal file
@@ -0,0 +1,196 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "LegacyJarModPage.h"
|
||||
#include "ui_LegacyJarModPage.h"
|
||||
|
||||
#include <QKeyEvent>
|
||||
#include <QFileDialog>
|
||||
#include <QKeyEvent>
|
||||
|
||||
#include <pathutils.h>
|
||||
|
||||
#include "gui/dialogs/VersionSelectDialog.h"
|
||||
#include "gui/dialogs/ProgressDialog.h"
|
||||
#include "gui/dialogs/ModEditDialogCommon.h"
|
||||
#include "logic/ModList.h"
|
||||
#include "logic/LegacyInstance.h"
|
||||
#include "logic/forge/ForgeVersion.h"
|
||||
#include "logic/forge/ForgeVersionList.h"
|
||||
#include "MultiMC.h"
|
||||
|
||||
LegacyJarModPage::LegacyJarModPage(LegacyInstance *inst, QWidget *parent)
|
||||
: QWidget(parent), ui(new Ui::LegacyJarModPage), m_inst(inst)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
m_jarmods = m_inst->jarModList();
|
||||
ui->jarModsTreeView->setModel(m_jarmods.get());
|
||||
ui->jarModsTreeView->setDragDropMode(QAbstractItemView::DragDrop);
|
||||
ui->jarModsTreeView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
ui->jarModsTreeView->installEventFilter(this);
|
||||
m_jarmods->startWatching();
|
||||
auto smodel = ui->jarModsTreeView->selectionModel();
|
||||
connect(smodel, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
|
||||
SLOT(jarCurrent(QModelIndex, QModelIndex)));
|
||||
}
|
||||
|
||||
LegacyJarModPage::~LegacyJarModPage()
|
||||
{
|
||||
m_jarmods->stopWatching();
|
||||
delete ui;
|
||||
}
|
||||
|
||||
bool LegacyJarModPage::shouldDisplay() const
|
||||
{
|
||||
return !m_inst->isRunning();
|
||||
}
|
||||
|
||||
bool LegacyJarModPage::eventFilter(QObject *obj, QEvent *ev)
|
||||
{
|
||||
if (ev->type() != QEvent::KeyPress || obj != ui->jarModsTreeView)
|
||||
{
|
||||
return QWidget::eventFilter(obj, ev);
|
||||
}
|
||||
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
|
||||
switch (keyEvent->key())
|
||||
{
|
||||
case Qt::Key_Up:
|
||||
{
|
||||
if (keyEvent->modifiers() & Qt::ControlModifier)
|
||||
{
|
||||
on_moveJarUpBtn_clicked();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Qt::Key_Down:
|
||||
{
|
||||
if (keyEvent->modifiers() & Qt::ControlModifier)
|
||||
{
|
||||
on_moveJarDownBtn_clicked();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Qt::Key_Delete:
|
||||
on_rmJarBtn_clicked();
|
||||
return true;
|
||||
case Qt::Key_Plus:
|
||||
on_addJarBtn_clicked();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QWidget::eventFilter(obj, ev);
|
||||
}
|
||||
|
||||
void LegacyJarModPage::on_addForgeBtn_clicked()
|
||||
{
|
||||
VersionSelectDialog vselect(MMC->forgelist().get(), tr("Select Forge version"), this);
|
||||
vselect.setExactFilter(1, m_inst->intendedVersionId());
|
||||
if (vselect.exec() && vselect.selectedVersion())
|
||||
{
|
||||
ForgeVersionPtr forge =
|
||||
std::dynamic_pointer_cast<ForgeVersion>(vselect.selectedVersion());
|
||||
if (!forge)
|
||||
return;
|
||||
auto entry = MMC->metacache()->resolveEntry("minecraftforge", forge->filename());
|
||||
if (entry->stale)
|
||||
{
|
||||
NetJob *fjob = new NetJob("Forge download");
|
||||
fjob->addNetAction(CacheDownload::make(forge->universal_url, entry));
|
||||
ProgressDialog dlg(this);
|
||||
dlg.exec(fjob);
|
||||
if (dlg.result() == QDialog::Accepted)
|
||||
{
|
||||
m_jarmods->stopWatching();
|
||||
m_jarmods->installMod(QFileInfo(entry->getFullPath()));
|
||||
m_jarmods->startWatching();
|
||||
}
|
||||
else
|
||||
{
|
||||
// failed to download forge :/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_jarmods->stopWatching();
|
||||
m_jarmods->installMod(QFileInfo(entry->getFullPath()));
|
||||
m_jarmods->startWatching();
|
||||
}
|
||||
}
|
||||
}
|
||||
void LegacyJarModPage::on_addJarBtn_clicked()
|
||||
{
|
||||
//: Title of jar mod selection dialog
|
||||
QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Select Jar Mods"));
|
||||
for (auto filename : fileNames)
|
||||
{
|
||||
m_jarmods->stopWatching();
|
||||
m_jarmods->installMod(QFileInfo(filename));
|
||||
m_jarmods->startWatching();
|
||||
}
|
||||
}
|
||||
|
||||
void LegacyJarModPage::on_moveJarDownBtn_clicked()
|
||||
{
|
||||
int first, last;
|
||||
auto list = ui->jarModsTreeView->selectionModel()->selectedRows();
|
||||
|
||||
if (!lastfirst(list, first, last))
|
||||
return;
|
||||
|
||||
m_jarmods->moveModsDown(first, last);
|
||||
}
|
||||
|
||||
void LegacyJarModPage::on_moveJarUpBtn_clicked()
|
||||
{
|
||||
int first, last;
|
||||
auto list = ui->jarModsTreeView->selectionModel()->selectedRows();
|
||||
|
||||
if (!lastfirst(list, first, last))
|
||||
return;
|
||||
m_jarmods->moveModsUp(first, last);
|
||||
}
|
||||
|
||||
void LegacyJarModPage::on_rmJarBtn_clicked()
|
||||
{
|
||||
int first, last;
|
||||
auto list = ui->jarModsTreeView->selectionModel()->selectedRows();
|
||||
|
||||
if (!lastfirst(list, first, last))
|
||||
return;
|
||||
m_jarmods->stopWatching();
|
||||
m_jarmods->deleteMods(first, last);
|
||||
m_jarmods->startWatching();
|
||||
}
|
||||
|
||||
void LegacyJarModPage::on_viewJarBtn_clicked()
|
||||
{
|
||||
openDirInDefaultProgram(m_inst->jarModsDir(), true);
|
||||
}
|
||||
|
||||
void LegacyJarModPage::jarCurrent(QModelIndex current, QModelIndex previous)
|
||||
{
|
||||
if (!current.isValid())
|
||||
{
|
||||
ui->jarMIFrame->clear();
|
||||
return;
|
||||
}
|
||||
int row = current.row();
|
||||
Mod &m = m_jarmods->operator[](row);
|
||||
ui->jarMIFrame->updateWithMod(m);
|
||||
}
|
||||
76
gui/pages/LegacyJarModPage.h
Normal file
76
gui/pages/LegacyJarModPage.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "logic/net/NetJob.h"
|
||||
#include "BasePage.h"
|
||||
|
||||
class ModList;
|
||||
class LegacyInstance;
|
||||
namespace Ui
|
||||
{
|
||||
class LegacyJarModPage;
|
||||
}
|
||||
|
||||
class LegacyJarModPage : public QWidget, public BasePage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit LegacyJarModPage(LegacyInstance *inst, QWidget *parent = 0);
|
||||
virtual ~LegacyJarModPage();
|
||||
|
||||
virtual QString displayName() const
|
||||
{
|
||||
return tr("Jar Mods");
|
||||
}
|
||||
virtual QIcon icon() const
|
||||
{
|
||||
return QIcon::fromTheme("plugin-red");
|
||||
}
|
||||
virtual QString id() const
|
||||
{
|
||||
return "jarmods";
|
||||
}
|
||||
virtual QString helpPage() const override
|
||||
{
|
||||
return "Legacy-jar-mods";
|
||||
}
|
||||
virtual bool shouldDisplay() const;
|
||||
|
||||
private
|
||||
slots:
|
||||
|
||||
void on_addJarBtn_clicked();
|
||||
void on_rmJarBtn_clicked();
|
||||
void on_addForgeBtn_clicked();
|
||||
void on_moveJarUpBtn_clicked();
|
||||
void on_moveJarDownBtn_clicked();
|
||||
void on_viewJarBtn_clicked();
|
||||
|
||||
void jarCurrent(QModelIndex current, QModelIndex previous);
|
||||
|
||||
protected:
|
||||
virtual bool eventFilter(QObject *obj, QEvent *ev) override;
|
||||
|
||||
private:
|
||||
Ui::LegacyJarModPage *ui;
|
||||
std::shared_ptr<ModList> m_jarmods;
|
||||
LegacyInstance *m_inst;
|
||||
NetJobPtr forgeJob;
|
||||
};
|
||||
158
gui/pages/LegacyJarModPage.ui
Normal file
158
gui/pages/LegacyJarModPage.ui
Normal file
@@ -0,0 +1,158 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>LegacyJarModPage</class>
|
||||
<widget class="QWidget" name="LegacyJarModPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>378</width>
|
||||
<height>324</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>LegacyJarModPage</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="ModListView" name="jarModsTreeView">
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="jarModsButtonBox">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Selection</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="rmJarBtn">
|
||||
<property name="text">
|
||||
<string>&Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="moveJarUpBtn">
|
||||
<property name="text">
|
||||
<string>Move &Up</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="moveJarDownBtn">
|
||||
<property name="text">
|
||||
<string>Move &Down</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LineSeparator" name="separator" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Install</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="addJarBtn">
|
||||
<property name="text">
|
||||
<string>&Add jar mod</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="addForgeBtn">
|
||||
<property name="text">
|
||||
<string>Install Forge</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="viewJarBtn">
|
||||
<property name="text">
|
||||
<string>&View Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="MCModInfoFrame" name="jarMIFrame">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ModListView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>gui/widgets/ModListView.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>MCModInfoFrame</class>
|
||||
<extends>QFrame</extends>
|
||||
<header>gui/widgets/MCModInfoFrame.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>LineSeparator</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>gui/widgets/LineSeparator.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
25
gui/pages/LegacyUpgradePage.cpp
Normal file
25
gui/pages/LegacyUpgradePage.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include "LegacyUpgradePage.h"
|
||||
#include "ui_LegacyUpgradePage.h"
|
||||
|
||||
#include "logic/LegacyInstance.h"
|
||||
|
||||
LegacyUpgradePage::LegacyUpgradePage(LegacyInstance *inst, QWidget *parent)
|
||||
: QWidget(parent), ui(new Ui::LegacyUpgradePage), m_inst(inst)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
LegacyUpgradePage::~LegacyUpgradePage()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void LegacyUpgradePage::on_upgradeButton_clicked()
|
||||
{
|
||||
// now what?
|
||||
}
|
||||
|
||||
bool LegacyUpgradePage::shouldDisplay() const
|
||||
{
|
||||
return !m_inst->isRunning();
|
||||
}
|
||||
61
gui/pages/LegacyUpgradePage.h
Normal file
61
gui/pages/LegacyUpgradePage.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "logic/OneSixInstance.h"
|
||||
#include "logic/net/NetJob.h"
|
||||
#include "BasePage.h"
|
||||
|
||||
class EnabledItemFilter;
|
||||
namespace Ui
|
||||
{
|
||||
class LegacyUpgradePage;
|
||||
}
|
||||
|
||||
class LegacyUpgradePage : public QWidget, public BasePage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit LegacyUpgradePage(LegacyInstance *inst, QWidget *parent = 0);
|
||||
virtual ~LegacyUpgradePage();
|
||||
virtual QString displayName() const override
|
||||
{
|
||||
return tr("Upgrade");
|
||||
}
|
||||
virtual QIcon icon() const override
|
||||
{
|
||||
return QIcon::fromTheme("checkupdate");
|
||||
}
|
||||
virtual QString id() const override
|
||||
{
|
||||
return "upgrade";
|
||||
}
|
||||
virtual QString helpPage() const override
|
||||
{
|
||||
return "Legacy-upgrade";
|
||||
}
|
||||
virtual bool shouldDisplay() const;
|
||||
private
|
||||
slots:
|
||||
void on_upgradeButton_clicked();
|
||||
|
||||
private:
|
||||
Ui::LegacyUpgradePage *ui;
|
||||
LegacyInstance *m_inst;
|
||||
};
|
||||
58
gui/pages/LegacyUpgradePage.ui
Normal file
58
gui/pages/LegacyUpgradePage.ui
Normal file
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>LegacyUpgradePage</class>
|
||||
<widget class="QWidget" name="LegacyUpgradePage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>546</width>
|
||||
<height>405</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Upgrade</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="textBrowser">
|
||||
<property name="html">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Bitstream Vera Sans'; font-size:11pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> </p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:18pt; font-weight:600;">New format is available</span> </p>
|
||||
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">MultiMC now supports old Minecraft versions in the new (OneSix) instance format. The old format won't be getting any new features and only the most critical bugfixes. As a consequence, you should upgrade this instance. </p>
|
||||
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The upgrade will create a new instance with the same contents as the current one, in the new format. The original instance will remain untouched, in case anything goes wrong in the process. </p>
|
||||
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Please report any issues on our <a href="https://github.com/MultiMC/MultiMC5/issues"><img src=":/icons/multimc/22x22/bug.png" /></a><a href="https://github.com/MultiMC/MultiMC5/issues"><span style=" text-decoration: underline; color:#68a0df;">github issues page</span></a>.</p></body></html></string>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCommandLinkButton" name="upgradeButton">
|
||||
<property name="text">
|
||||
<string>Start the upgrade! (Not Yet Implemented, Coming Soon™)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
124
gui/pages/LogPage.cpp
Normal file
124
gui/pages/LogPage.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
#include "LogPage.h"
|
||||
#include "ui_LogPage.h"
|
||||
|
||||
#include <QIcon>
|
||||
#include <QScrollBar>
|
||||
|
||||
#include "logic/MinecraftProcess.h"
|
||||
#include "gui/GuiUtil.h"
|
||||
|
||||
LogPage::LogPage(MinecraftProcess *proc, QWidget *parent)
|
||||
: QWidget(parent), ui(new Ui::LogPage), m_process(proc)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
connect(m_process, SIGNAL(log(QString, MessageLevel::Enum)), this,
|
||||
SLOT(write(QString, MessageLevel::Enum)));
|
||||
}
|
||||
|
||||
LogPage::~LogPage()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
bool LogPage::apply()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LogPage::shouldDisplay() const
|
||||
{
|
||||
return m_process->instance()->isRunning();
|
||||
}
|
||||
|
||||
void LogPage::on_btnPaste_clicked()
|
||||
{
|
||||
GuiUtil::uploadPaste(ui->text->toPlainText(), this);
|
||||
}
|
||||
|
||||
void LogPage::on_btnCopy_clicked()
|
||||
{
|
||||
GuiUtil::setClipboardText(ui->text->toPlainText());
|
||||
}
|
||||
|
||||
void LogPage::on_btnClear_clicked()
|
||||
{
|
||||
ui->text->clear();
|
||||
}
|
||||
|
||||
void LogPage::writeColor(QString text, const char *color, const char * background)
|
||||
{
|
||||
// append a paragraph
|
||||
QString newtext;
|
||||
newtext += "<span style=\"";
|
||||
{
|
||||
if (color)
|
||||
newtext += QString("color:") + color + ";";
|
||||
if (background)
|
||||
newtext += QString("background-color:") + background + ";";
|
||||
newtext += "font-family: monospace;";
|
||||
}
|
||||
newtext += "\">";
|
||||
newtext += text.toHtmlEscaped();
|
||||
newtext += "</span>";
|
||||
ui->text->appendHtml(newtext);
|
||||
}
|
||||
|
||||
void LogPage::write(QString data, MessageLevel::Enum mode)
|
||||
{
|
||||
QScrollBar *bar = ui->text->verticalScrollBar();
|
||||
int max_bar = bar->maximum();
|
||||
int val_bar = bar->value();
|
||||
if(isVisible())
|
||||
{
|
||||
if (m_scroll_active)
|
||||
{
|
||||
m_scroll_active = (max_bar - val_bar) <= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_scroll_active = val_bar == max_bar;
|
||||
}
|
||||
}
|
||||
if (data.endsWith('\n'))
|
||||
data = data.left(data.length() - 1);
|
||||
QStringList paragraphs = data.split('\n');
|
||||
QStringList filtered;
|
||||
for (QString ¶graph : paragraphs)
|
||||
{
|
||||
// Quick hack for
|
||||
if(paragraph.contains("Detected an attempt by a mod null to perform game activity during mod construction"))
|
||||
continue;
|
||||
filtered.append(paragraph.trimmed());
|
||||
}
|
||||
QListIterator<QString> iter(filtered);
|
||||
if (mode == MessageLevel::MultiMC)
|
||||
while (iter.hasNext())
|
||||
writeColor(iter.next(), "blue", 0);
|
||||
else if (mode == MessageLevel::Error)
|
||||
while (iter.hasNext())
|
||||
writeColor(iter.next(), "red", 0);
|
||||
else if (mode == MessageLevel::Warning)
|
||||
while (iter.hasNext())
|
||||
writeColor(iter.next(), "orange", 0);
|
||||
else if (mode == MessageLevel::Fatal)
|
||||
while (iter.hasNext())
|
||||
writeColor(iter.next(), "red", "black");
|
||||
else if (mode == MessageLevel::Debug)
|
||||
while (iter.hasNext())
|
||||
writeColor(iter.next(), "green", 0);
|
||||
else if (mode == MessageLevel::PrePost)
|
||||
while (iter.hasNext())
|
||||
writeColor(iter.next(), "grey", 0);
|
||||
// TODO: implement other MessageLevels
|
||||
else
|
||||
while (iter.hasNext())
|
||||
writeColor(iter.next(), 0, 0);
|
||||
if(isVisible())
|
||||
{
|
||||
if (m_scroll_active)
|
||||
{
|
||||
bar->setValue(bar->maximum());
|
||||
}
|
||||
m_last_scroll_value = bar->value();
|
||||
}
|
||||
}
|
||||
86
gui/pages/LogPage.h
Normal file
86
gui/pages/LogPage.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "logic/BaseInstance.h"
|
||||
#include "logic/net/NetJob.h"
|
||||
#include "logic/MinecraftProcess.h"
|
||||
#include "BasePage.h"
|
||||
|
||||
class EnabledItemFilter;
|
||||
class MinecraftProcess;
|
||||
namespace Ui
|
||||
{
|
||||
class LogPage;
|
||||
}
|
||||
|
||||
class LogPage : public QWidget, public BasePage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit LogPage(MinecraftProcess *proc, QWidget *parent = 0);
|
||||
virtual ~LogPage();
|
||||
virtual QString displayName() const override
|
||||
{
|
||||
return tr("Minecraft Log");
|
||||
}
|
||||
virtual QIcon icon() const override
|
||||
{
|
||||
return QIcon::fromTheme("log");
|
||||
}
|
||||
virtual QString id() const override
|
||||
{
|
||||
return "console";
|
||||
}
|
||||
virtual bool apply();
|
||||
virtual QString helpPage() const override
|
||||
{
|
||||
return "Minecraft-Log";
|
||||
}
|
||||
virtual bool shouldDisplay() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief write a colored paragraph
|
||||
* @param data the string
|
||||
* @param color the css color name
|
||||
* this will only insert a single paragraph.
|
||||
* \n are ignored. a real \n is always appended.
|
||||
*/
|
||||
void writeColor(QString text, const char *color, const char *background);
|
||||
|
||||
private slots:
|
||||
/**
|
||||
* @brief write a string
|
||||
* @param data the string
|
||||
* @param mode the WriteMode
|
||||
* lines have to be put through this as a whole!
|
||||
*/
|
||||
void write(QString data, MessageLevel::Enum level = MessageLevel::MultiMC);
|
||||
void on_btnPaste_clicked();
|
||||
void on_btnCopy_clicked();
|
||||
void on_btnClear_clicked();
|
||||
|
||||
private:
|
||||
Ui::LogPage *ui;
|
||||
MinecraftProcess *m_process;
|
||||
int m_last_scroll_value = 0;
|
||||
bool m_scroll_active = true;
|
||||
int m_saved_offset = 0;
|
||||
};
|
||||
139
gui/pages/LogPage.ui
Normal file
139
gui/pages/LogPage.ui
Normal file
@@ -0,0 +1,139 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>LogPage</class>
|
||||
<widget class="QWidget" name="LogPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>825</width>
|
||||
<height>782</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Log</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Search:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Find next</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="3">
|
||||
<widget class="QPlainTextEdit" name="text">
|
||||
<property name="undoRedoEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="plainText">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
<property name="centerOnScroll">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="3">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Keep updating</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnCopy">
|
||||
<property name="toolTip">
|
||||
<string>Copy the whole log into the clipboard</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Copy</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnPaste">
|
||||
<property name="toolTip">
|
||||
<string>Upload the log to paste.ee - it will stay online for a month</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Upload</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnClear">
|
||||
<property name="toolTip">
|
||||
<string>Clear the log</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clear</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
159
gui/pages/ModFolderPage.cpp
Normal file
159
gui/pages/ModFolderPage.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ModFolderPage.h"
|
||||
#include "ui_ModFolderPage.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QDesktopServices>
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
#include <pathutils.h>
|
||||
|
||||
#include "MultiMC.h"
|
||||
#include "gui/dialogs/CustomMessageBox.h"
|
||||
#include "gui/dialogs/ModEditDialogCommon.h"
|
||||
#include "logic/ModList.h"
|
||||
#include "logic/Mod.h"
|
||||
#include "logic/VersionFilterData.h"
|
||||
|
||||
ModFolderPage::ModFolderPage(BaseInstance *inst, std::shared_ptr<ModList> mods, QString id,
|
||||
QString iconName, QString displayName, QString helpPage,
|
||||
QWidget *parent)
|
||||
: QWidget(parent), ui(new Ui::ModFolderPage)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
m_inst = inst;
|
||||
m_mods = mods;
|
||||
m_id = id;
|
||||
m_displayName = displayName;
|
||||
m_iconName = iconName;
|
||||
m_helpName = helpPage;
|
||||
ui->modTreeView->setModel(m_mods.get());
|
||||
ui->modTreeView->installEventFilter(this);
|
||||
m_mods->startWatching();
|
||||
auto smodel = ui->modTreeView->selectionModel();
|
||||
connect(smodel, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
|
||||
SLOT(modCurrent(QModelIndex, QModelIndex)));
|
||||
}
|
||||
|
||||
CoreModFolderPage::CoreModFolderPage(BaseInstance *inst, std::shared_ptr<ModList> mods,
|
||||
QString id, QString iconName, QString displayName,
|
||||
QString helpPage, QWidget *parent)
|
||||
: ModFolderPage(inst, mods, id, iconName, displayName, helpPage, parent)
|
||||
{
|
||||
}
|
||||
|
||||
ModFolderPage::~ModFolderPage()
|
||||
{
|
||||
m_mods->stopWatching();
|
||||
delete ui;
|
||||
}
|
||||
|
||||
bool ModFolderPage::shouldDisplay() const
|
||||
{
|
||||
if (m_inst)
|
||||
return !m_inst->isRunning();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CoreModFolderPage::shouldDisplay() const
|
||||
{
|
||||
if (ModFolderPage::shouldDisplay())
|
||||
{
|
||||
auto inst = dynamic_cast<OneSixInstance *>(m_inst);
|
||||
if (!inst)
|
||||
return true;
|
||||
auto version = inst->getFullVersion();
|
||||
if (!version)
|
||||
return true;
|
||||
if (version->m_releaseTime < g_VersionFilterData.legacyCutoffDate)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ModFolderPage::modListFilter(QKeyEvent *keyEvent)
|
||||
{
|
||||
switch (keyEvent->key())
|
||||
{
|
||||
case Qt::Key_Delete:
|
||||
on_rmModBtn_clicked();
|
||||
return true;
|
||||
case Qt::Key_Plus:
|
||||
on_addModBtn_clicked();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QWidget::eventFilter(ui->modTreeView, keyEvent);
|
||||
}
|
||||
|
||||
bool ModFolderPage::eventFilter(QObject *obj, QEvent *ev)
|
||||
{
|
||||
if (ev->type() != QEvent::KeyPress)
|
||||
{
|
||||
return QWidget::eventFilter(obj, ev);
|
||||
}
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
|
||||
if (obj == ui->modTreeView)
|
||||
return modListFilter(keyEvent);
|
||||
return QWidget::eventFilter(obj, ev);
|
||||
}
|
||||
|
||||
void ModFolderPage::on_addModBtn_clicked()
|
||||
{
|
||||
QStringList fileNames = QFileDialog::getOpenFileNames(
|
||||
this, QApplication::translate("ModFolderPage", "Select Loader Mods"));
|
||||
for (auto filename : fileNames)
|
||||
{
|
||||
m_mods->stopWatching();
|
||||
m_mods->installMod(QFileInfo(filename));
|
||||
m_mods->startWatching();
|
||||
}
|
||||
}
|
||||
void ModFolderPage::on_rmModBtn_clicked()
|
||||
{
|
||||
int first, last;
|
||||
auto list = ui->modTreeView->selectionModel()->selectedRows();
|
||||
|
||||
if (!lastfirst(list, first, last))
|
||||
return;
|
||||
m_mods->stopWatching();
|
||||
m_mods->deleteMods(first, last);
|
||||
m_mods->startWatching();
|
||||
}
|
||||
|
||||
void ModFolderPage::on_viewModBtn_clicked()
|
||||
{
|
||||
openDirInDefaultProgram(m_mods->dir().absolutePath(), true);
|
||||
}
|
||||
|
||||
void ModFolderPage::modCurrent(const QModelIndex ¤t, const QModelIndex &previous)
|
||||
{
|
||||
if (!current.isValid())
|
||||
{
|
||||
ui->frame->clear();
|
||||
return;
|
||||
}
|
||||
int row = current.row();
|
||||
Mod &m = m_mods->operator[](row);
|
||||
ui->frame->updateWithMod(m);
|
||||
}
|
||||
94
gui/pages/ModFolderPage.h
Normal file
94
gui/pages/ModFolderPage.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "logic/OneSixInstance.h"
|
||||
#include "logic/net/NetJob.h"
|
||||
#include "BasePage.h"
|
||||
|
||||
class EnabledItemFilter;
|
||||
class ModList;
|
||||
namespace Ui
|
||||
{
|
||||
class ModFolderPage;
|
||||
}
|
||||
|
||||
class ModFolderPage : public QWidget, public BasePage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ModFolderPage(BaseInstance *inst, std::shared_ptr<ModList> mods, QString id,
|
||||
QString iconName, QString displayName, QString helpPage = "",
|
||||
QWidget *parent = 0);
|
||||
virtual ~ModFolderPage();
|
||||
virtual QString displayName() const override
|
||||
{
|
||||
return m_displayName;
|
||||
}
|
||||
virtual QIcon icon() const override
|
||||
{
|
||||
return QIcon::fromTheme(m_iconName);
|
||||
}
|
||||
virtual QString id() const override
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
virtual QString helpPage() const override
|
||||
{
|
||||
return m_helpName;
|
||||
}
|
||||
virtual bool shouldDisplay() const;
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *ev);
|
||||
bool modListFilter(QKeyEvent *ev);
|
||||
|
||||
protected:
|
||||
BaseInstance *m_inst;
|
||||
|
||||
private:
|
||||
Ui::ModFolderPage *ui;
|
||||
std::shared_ptr<ModList> m_mods;
|
||||
QString m_iconName;
|
||||
QString m_id;
|
||||
QString m_displayName;
|
||||
QString m_helpName;
|
||||
|
||||
public
|
||||
slots:
|
||||
void modCurrent(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
|
||||
private
|
||||
slots:
|
||||
void on_addModBtn_clicked();
|
||||
void on_rmModBtn_clicked();
|
||||
void on_viewModBtn_clicked();
|
||||
};
|
||||
|
||||
class CoreModFolderPage : public ModFolderPage
|
||||
{
|
||||
public:
|
||||
explicit CoreModFolderPage(BaseInstance *inst, std::shared_ptr<ModList> mods, QString id,
|
||||
QString iconName, QString displayName, QString helpPage = "",
|
||||
QWidget *parent = 0);
|
||||
virtual ~CoreModFolderPage()
|
||||
{
|
||||
}
|
||||
virtual bool shouldDisplay() const;
|
||||
};
|
||||
118
gui/pages/ModFolderPage.ui
Normal file
118
gui/pages/ModFolderPage.ui
Normal file
@@ -0,0 +1,118 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ModFolderPage</class>
|
||||
<widget class="QWidget" name="ModFolderPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>723</width>
|
||||
<height>532</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Mods</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="ModListView" name="modTreeView">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="acceptDrops">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DropOnly</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="addModBtn">
|
||||
<property name="text">
|
||||
<string>&Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="rmModBtn">
|
||||
<property name="text">
|
||||
<string>&Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="viewModBtn">
|
||||
<property name="text">
|
||||
<string>&View Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="MCModInfoFrame" name="frame">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ModListView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>gui/widgets/ModListView.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>MCModInfoFrame</class>
|
||||
<extends>QFrame</extends>
|
||||
<header>gui/widgets/MCModInfoFrame.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
20
gui/pages/NotesPage.cpp
Normal file
20
gui/pages/NotesPage.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "NotesPage.h"
|
||||
#include "ui_NotesPage.h"
|
||||
|
||||
NotesPage::NotesPage(BaseInstance *inst, QWidget *parent)
|
||||
: QWidget(parent), ui(new Ui::NotesPage), m_inst(inst)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->noteEditor->setText(m_inst->notes());
|
||||
}
|
||||
|
||||
NotesPage::~NotesPage()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
bool NotesPage::apply()
|
||||
{
|
||||
m_inst->setNotes(ui->noteEditor->toPlainText());
|
||||
return true;
|
||||
}
|
||||
58
gui/pages/NotesPage.h
Normal file
58
gui/pages/NotesPage.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "logic/BaseInstance.h"
|
||||
#include "logic/net/NetJob.h"
|
||||
#include "BasePage.h"
|
||||
|
||||
class EnabledItemFilter;
|
||||
namespace Ui
|
||||
{
|
||||
class NotesPage;
|
||||
}
|
||||
|
||||
class NotesPage : public QWidget, public BasePage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit NotesPage(BaseInstance *inst, QWidget *parent = 0);
|
||||
virtual ~NotesPage();
|
||||
virtual QString displayName() const override
|
||||
{
|
||||
return tr("Notes");
|
||||
}
|
||||
virtual QIcon icon() const override
|
||||
{
|
||||
return QIcon::fromTheme("news");
|
||||
}
|
||||
virtual QString id() const override
|
||||
{
|
||||
return "notes";
|
||||
}
|
||||
virtual bool apply();
|
||||
virtual QString helpPage() const override
|
||||
{
|
||||
return "Notes";
|
||||
}
|
||||
|
||||
private:
|
||||
Ui::NotesPage *ui;
|
||||
BaseInstance *m_inst;
|
||||
};
|
||||
46
gui/pages/NotesPage.ui
Normal file
46
gui/pages/NotesPage.ui
Normal file
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>NotesPage</class>
|
||||
<widget class="QWidget" name="NotesPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="noteEditor">
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
</property>
|
||||
<property name="acceptRichText">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextEditable|Qt::TextEditorInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
140
gui/pages/OtherLogsPage.cpp
Normal file
140
gui/pages/OtherLogsPage.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "OtherLogsPage.h"
|
||||
#include "ui_OtherLogsPage.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "gui/GuiUtil.h"
|
||||
#include "logic/RecursiveFileSystemWatcher.h"
|
||||
#include "logic/BaseInstance.h"
|
||||
|
||||
OtherLogsPage::OtherLogsPage(BaseInstance *instance, QWidget *parent)
|
||||
: QWidget(parent), ui(new Ui::OtherLogsPage), m_instance(instance),
|
||||
m_watcher(new RecursiveFileSystemWatcher(this))
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
m_watcher->setFileExpression("(.*\\.log(\\.[0-9]*)?$)|(crash-.*\\.txt)");
|
||||
m_watcher->setRootDir(QDir::current().absoluteFilePath(m_instance->minecraftRoot()));
|
||||
|
||||
connect(m_watcher, &RecursiveFileSystemWatcher::filesChanged, this,
|
||||
&OtherLogsPage::populateSelectLogBox);
|
||||
populateSelectLogBox();
|
||||
}
|
||||
|
||||
OtherLogsPage::~OtherLogsPage()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void OtherLogsPage::opened()
|
||||
{
|
||||
m_watcher->enable();
|
||||
}
|
||||
void OtherLogsPage::closed()
|
||||
{
|
||||
m_watcher->disable();
|
||||
}
|
||||
|
||||
void OtherLogsPage::populateSelectLogBox()
|
||||
{
|
||||
ui->selectLogBox->clear();
|
||||
ui->selectLogBox->addItems(m_watcher->files());
|
||||
if (m_currentFile.isNull())
|
||||
{
|
||||
ui->selectLogBox->setCurrentIndex(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
const int index = ui->selectLogBox->findText(m_currentFile);
|
||||
if(index != -1)
|
||||
ui->selectLogBox->setCurrentIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
void OtherLogsPage::on_selectLogBox_currentIndexChanged(const int index)
|
||||
{
|
||||
QString file;
|
||||
if (index != -1)
|
||||
{
|
||||
file = ui->selectLogBox->itemText(index);
|
||||
}
|
||||
|
||||
if (file.isEmpty() || !QFile::exists(m_instance->minecraftRoot() + "/" + file))
|
||||
{
|
||||
m_currentFile = QString();
|
||||
ui->text->clear();
|
||||
setControlsEnabled(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_currentFile = file;
|
||||
on_btnReload_clicked();
|
||||
setControlsEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void OtherLogsPage::on_btnReload_clicked()
|
||||
{
|
||||
QFile file(m_instance->minecraftRoot() + "/" + m_currentFile);
|
||||
if (!file.open(QFile::ReadOnly))
|
||||
{
|
||||
setControlsEnabled(false);
|
||||
ui->btnReload->setEnabled(true); // allow reload
|
||||
m_currentFile = QString();
|
||||
QMessageBox::critical(this, tr("Error"), tr("Unable to open %1 for reading: %2")
|
||||
.arg(m_currentFile, file.errorString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->text->setPlainText(QString::fromUtf8(file.readAll()));
|
||||
}
|
||||
}
|
||||
|
||||
void OtherLogsPage::on_btnPaste_clicked()
|
||||
{
|
||||
GuiUtil::uploadPaste(ui->text->toPlainText(), this);
|
||||
}
|
||||
void OtherLogsPage::on_btnCopy_clicked()
|
||||
{
|
||||
GuiUtil::setClipboardText(ui->text->toPlainText());
|
||||
}
|
||||
void OtherLogsPage::on_btnDelete_clicked()
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Delete"),
|
||||
tr("Do you really want to delete %1?").arg(m_currentFile),
|
||||
QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
|
||||
{
|
||||
return;
|
||||
}
|
||||
QFile file(m_instance->minecraftRoot() + "/" + m_currentFile);
|
||||
if (!file.remove())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Unable to delete %1: %2")
|
||||
.arg(m_currentFile, file.errorString()));
|
||||
}
|
||||
}
|
||||
|
||||
void OtherLogsPage::setControlsEnabled(const bool enabled)
|
||||
{
|
||||
ui->btnReload->setEnabled(enabled);
|
||||
ui->btnDelete->setEnabled(enabled);
|
||||
ui->btnCopy->setEnabled(enabled);
|
||||
ui->btnPaste->setEnabled(enabled);
|
||||
ui->text->setEnabled(enabled);
|
||||
}
|
||||
73
gui/pages/OtherLogsPage.h
Normal file
73
gui/pages/OtherLogsPage.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "BasePage.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class OtherLogsPage;
|
||||
}
|
||||
|
||||
class RecursiveFileSystemWatcher;
|
||||
|
||||
class BaseInstance;
|
||||
|
||||
class OtherLogsPage : public QWidget, public BasePage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit OtherLogsPage(BaseInstance *instance, QWidget *parent = 0);
|
||||
~OtherLogsPage();
|
||||
|
||||
QString id() const override
|
||||
{
|
||||
return "logs";
|
||||
}
|
||||
QString displayName() const override
|
||||
{
|
||||
return tr("Other logs");
|
||||
}
|
||||
QIcon icon() const override
|
||||
{
|
||||
return QIcon::fromTheme("log");
|
||||
}
|
||||
QString helpPage() const override
|
||||
{
|
||||
return "Minecraft-Logs";
|
||||
}
|
||||
void opened() override;
|
||||
void closed() override;
|
||||
|
||||
private slots:
|
||||
void populateSelectLogBox();
|
||||
void on_selectLogBox_currentIndexChanged(const int index);
|
||||
void on_btnReload_clicked();
|
||||
void on_btnPaste_clicked();
|
||||
void on_btnCopy_clicked();
|
||||
void on_btnDelete_clicked();
|
||||
|
||||
private:
|
||||
Ui::OtherLogsPage *ui;
|
||||
BaseInstance *m_instance;
|
||||
RecursiveFileSystemWatcher *m_watcher;
|
||||
QString m_currentFile;
|
||||
|
||||
void setControlsEnabled(const bool enabled);
|
||||
};
|
||||
103
gui/pages/OtherLogsPage.ui
Normal file
103
gui/pages/OtherLogsPage.ui
Normal file
@@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>OtherLogsPage</class>
|
||||
<widget class="QWidget" name="OtherLogsPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>657</width>
|
||||
<height>538</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="selectLogBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnReload">
|
||||
<property name="text">
|
||||
<string>Reload</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnCopy">
|
||||
<property name="toolTip">
|
||||
<string>Copy the whole log into the clipboard</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Copy</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnPaste">
|
||||
<property name="toolTip">
|
||||
<string>Upload the log to paste.ee - it will stay online for a month</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Upload</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnDelete">
|
||||
<property name="toolTip">
|
||||
<string>Clear the log</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="text">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>text</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
19
gui/pages/ResourcePackPage.h
Normal file
19
gui/pages/ResourcePackPage.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "ModFolderPage.h"
|
||||
|
||||
class ResourcePackPage : public ModFolderPage
|
||||
{
|
||||
public:
|
||||
explicit ResourcePackPage(BaseInstance *instance, QWidget *parent = 0)
|
||||
: ModFolderPage(instance, instance->resourcePackList(), "resourcepacks",
|
||||
"resourcepacks", tr("Resource packs"), "Resource-packs", parent)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~ResourcePackPage() {}
|
||||
virtual bool shouldDisplay() const override
|
||||
{
|
||||
return !m_inst->traits().contains("no-texturepacks") &&
|
||||
!m_inst->traits().contains("texturepacks");
|
||||
}
|
||||
};
|
||||
360
gui/pages/ScreenshotsPage.cpp
Normal file
360
gui/pages/ScreenshotsPage.cpp
Normal file
@@ -0,0 +1,360 @@
|
||||
#include "ScreenshotsPage.h"
|
||||
#include "ui_ScreenshotsPage.h"
|
||||
|
||||
#include <QModelIndex>
|
||||
#include <QMutableListIterator>
|
||||
#include <QMap>
|
||||
#include <QSet>
|
||||
#include <QFileIconProvider>
|
||||
#include <QFileSystemModel>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QLineEdit>
|
||||
#include <QEvent>
|
||||
#include <QPainter>
|
||||
#include <QClipboard>
|
||||
#include <QDesktopServices>
|
||||
#include <QKeyEvent>
|
||||
|
||||
#include <pathutils.h>
|
||||
|
||||
#include "gui/dialogs/ProgressDialog.h"
|
||||
#include "gui/dialogs/CustomMessageBox.h"
|
||||
#include "logic/net/NetJob.h"
|
||||
#include "logic/screenshots/ImgurUpload.h"
|
||||
#include "logic/screenshots/ImgurAlbumCreation.h"
|
||||
#include "logic/tasks/SequentialTask.h"
|
||||
|
||||
#include "logic/RWStorage.h"
|
||||
|
||||
typedef RWStorage<QString, QIcon> SharedIconCache;
|
||||
typedef std::shared_ptr<SharedIconCache> SharedIconCachePtr;
|
||||
|
||||
class ThumbnailingResult : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public slots:
|
||||
inline void emitResultsReady(const QString &path) { emit resultsReady(path); }
|
||||
inline void emitResultsFailed(const QString &path) { emit resultsFailed(path); }
|
||||
signals:
|
||||
void resultsReady(const QString &path);
|
||||
void resultsFailed(const QString &path);
|
||||
};
|
||||
|
||||
class ThumbnailRunnable : public QRunnable
|
||||
{
|
||||
public:
|
||||
ThumbnailRunnable(QString path, SharedIconCachePtr cache)
|
||||
{
|
||||
m_path = path;
|
||||
m_cache = cache;
|
||||
}
|
||||
void run()
|
||||
{
|
||||
QFileInfo info(m_path);
|
||||
if (info.isDir())
|
||||
return;
|
||||
if ((info.suffix().compare("png", Qt::CaseInsensitive) != 0))
|
||||
return;
|
||||
int tries = 5;
|
||||
while (tries)
|
||||
{
|
||||
if (!m_cache->stale(m_path))
|
||||
return;
|
||||
QImage image(m_path);
|
||||
if (image.isNull())
|
||||
{
|
||||
QThread::msleep(500);
|
||||
tries--;
|
||||
continue;
|
||||
}
|
||||
QImage small;
|
||||
if (image.width() > image.height())
|
||||
small = image.scaledToWidth(512).scaledToWidth(256, Qt::SmoothTransformation);
|
||||
else
|
||||
small = image.scaledToHeight(512).scaledToHeight(256, Qt::SmoothTransformation);
|
||||
auto smallSize = small.size();
|
||||
QPoint offset((256 - small.width()) / 2, (256 - small.height()) / 2);
|
||||
QImage square(QSize(256, 256), QImage::Format_ARGB32);
|
||||
square.fill(Qt::transparent);
|
||||
|
||||
QPainter painter(&square);
|
||||
painter.drawImage(offset, small);
|
||||
painter.end();
|
||||
|
||||
QIcon icon(QPixmap::fromImage(square));
|
||||
m_cache->add(m_path, icon);
|
||||
m_resultEmitter.emitResultsReady(m_path);
|
||||
return;
|
||||
}
|
||||
m_resultEmitter.emitResultsFailed(m_path);
|
||||
}
|
||||
QString m_path;
|
||||
SharedIconCachePtr m_cache;
|
||||
ThumbnailingResult m_resultEmitter;
|
||||
};
|
||||
|
||||
// this is about as elegant and well written as a bag of bricks with scribbles done by insane
|
||||
// asylum patients.
|
||||
class FilterModel : public QIdentityProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FilterModel(QObject *parent = 0) : QIdentityProxyModel(parent)
|
||||
{
|
||||
m_thumbnailingPool.setMaxThreadCount(4);
|
||||
m_thumbnailCache = std::make_shared<SharedIconCache>();
|
||||
m_thumbnailCache->add("placeholder", QIcon::fromTheme("screenshot-placeholder"));
|
||||
connect(&watcher, SIGNAL(fileChanged(QString)), SLOT(fileChanged(QString)));
|
||||
// FIXME: the watched file set is not updated when files are removed
|
||||
}
|
||||
virtual ~FilterModel() { m_thumbnailingPool.waitForDone(500); }
|
||||
virtual QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const
|
||||
{
|
||||
auto model = sourceModel();
|
||||
if (!model)
|
||||
return QVariant();
|
||||
if (role == Qt::DisplayRole || role == Qt::EditRole)
|
||||
{
|
||||
QVariant result = sourceModel()->data(mapToSource(proxyIndex), role);
|
||||
return result.toString().remove(QRegExp("\\.png$"));
|
||||
}
|
||||
if (role == Qt::DecorationRole)
|
||||
{
|
||||
QVariant result =
|
||||
sourceModel()->data(mapToSource(proxyIndex), QFileSystemModel::FilePathRole);
|
||||
QString filePath = result.toString();
|
||||
QIcon temp;
|
||||
if (!watched.contains(filePath))
|
||||
{
|
||||
((QFileSystemWatcher &)watcher).addPath(filePath);
|
||||
((QSet<QString> &)watched).insert(filePath);
|
||||
}
|
||||
if (m_thumbnailCache->get(filePath, temp))
|
||||
{
|
||||
return temp;
|
||||
}
|
||||
if (!m_failed.contains(filePath))
|
||||
{
|
||||
((FilterModel *)this)->thumbnailImage(filePath);
|
||||
}
|
||||
return (m_thumbnailCache->get("placeholder"));
|
||||
}
|
||||
return sourceModel()->data(mapToSource(proxyIndex), role);
|
||||
}
|
||||
virtual bool setData(const QModelIndex &index, const QVariant &value,
|
||||
int role = Qt::EditRole)
|
||||
{
|
||||
auto model = sourceModel();
|
||||
if (!model)
|
||||
return false;
|
||||
if (role != Qt::EditRole)
|
||||
return false;
|
||||
// FIXME: this is a workaround for a bug in QFileSystemModel, where it doesn't
|
||||
// sort after renames
|
||||
{
|
||||
((QFileSystemModel *)model)->setNameFilterDisables(true);
|
||||
((QFileSystemModel *)model)->setNameFilterDisables(false);
|
||||
}
|
||||
return model->setData(mapToSource(index), value.toString() + ".png", role);
|
||||
}
|
||||
|
||||
private:
|
||||
void thumbnailImage(QString path)
|
||||
{
|
||||
auto runnable = new ThumbnailRunnable(path, m_thumbnailCache);
|
||||
connect(&(runnable->m_resultEmitter), SIGNAL(resultsReady(QString)),
|
||||
SLOT(thumbnailReady(QString)));
|
||||
connect(&(runnable->m_resultEmitter), SIGNAL(resultsFailed(QString)),
|
||||
SLOT(thumbnailFailed(QString)));
|
||||
((QThreadPool &)m_thumbnailingPool).start(runnable);
|
||||
}
|
||||
private slots:
|
||||
void thumbnailReady(QString path) { emit layoutChanged(); }
|
||||
void thumbnailFailed(QString path) { m_failed.insert(path); }
|
||||
void fileChanged(QString filepath)
|
||||
{
|
||||
m_thumbnailCache->setStale(filepath);
|
||||
thumbnailImage(filepath);
|
||||
// reinsert the path...
|
||||
watcher.removePath(filepath);
|
||||
watcher.addPath(filepath);
|
||||
}
|
||||
|
||||
private:
|
||||
SharedIconCachePtr m_thumbnailCache;
|
||||
QThreadPool m_thumbnailingPool;
|
||||
QSet<QString> m_failed;
|
||||
QSet<QString> watched;
|
||||
QFileSystemWatcher watcher;
|
||||
};
|
||||
|
||||
class CenteredEditingDelegate : public QStyledItemDelegate
|
||||
{
|
||||
public:
|
||||
explicit CenteredEditingDelegate(QObject *parent = 0) : QStyledItemDelegate(parent) {}
|
||||
virtual ~CenteredEditingDelegate() {}
|
||||
virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
auto widget = QStyledItemDelegate::createEditor(parent, option, index);
|
||||
auto foo = dynamic_cast<QLineEdit *>(widget);
|
||||
if (foo)
|
||||
{
|
||||
foo->setAlignment(Qt::AlignHCenter);
|
||||
foo->setFrame(true);
|
||||
foo->setMaximumWidth(192);
|
||||
}
|
||||
return widget;
|
||||
}
|
||||
};
|
||||
|
||||
ScreenshotsPage::ScreenshotsPage(BaseInstance *instance, QWidget *parent)
|
||||
: QWidget(parent), ui(new Ui::ScreenshotsPage)
|
||||
{
|
||||
m_model.reset(new QFileSystemModel());
|
||||
m_filterModel.reset(new FilterModel());
|
||||
m_filterModel->setSourceModel(m_model.get());
|
||||
m_model->setFilter(QDir::Files | QDir::Writable | QDir::Readable);
|
||||
m_model->setReadOnly(false);
|
||||
m_model->setNameFilters({"*.png"});
|
||||
m_model->setNameFilterDisables(false);
|
||||
m_folder = PathCombine(instance->minecraftRoot(), "screenshots");
|
||||
m_valid = ensureFolderPathExists(m_folder);
|
||||
|
||||
ui->setupUi(this);
|
||||
ui->listView->setModel(m_filterModel.get());
|
||||
ui->listView->setIconSize(QSize(128, 128));
|
||||
ui->listView->setGridSize(QSize(192, 160));
|
||||
ui->listView->setSpacing(9);
|
||||
// ui->listView->setUniformItemSizes(true);
|
||||
ui->listView->setLayoutMode(QListView::Batched);
|
||||
ui->listView->setViewMode(QListView::IconMode);
|
||||
ui->listView->setResizeMode(QListView::Adjust);
|
||||
ui->listView->installEventFilter(this);
|
||||
ui->listView->setEditTriggers(0);
|
||||
ui->listView->setItemDelegate(new CenteredEditingDelegate(this));
|
||||
connect(ui->listView, SIGNAL(activated(QModelIndex)), SLOT(onItemActivated(QModelIndex)));
|
||||
}
|
||||
|
||||
bool ScreenshotsPage::eventFilter(QObject *obj, QEvent *evt)
|
||||
{
|
||||
if (obj != ui->listView)
|
||||
return QWidget::eventFilter(obj, evt);
|
||||
if (evt->type() != QEvent::KeyPress)
|
||||
{
|
||||
return QWidget::eventFilter(obj, evt);
|
||||
}
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(evt);
|
||||
switch (keyEvent->key())
|
||||
{
|
||||
case Qt::Key_Delete:
|
||||
on_deleteBtn_clicked();
|
||||
return true;
|
||||
case Qt::Key_F2:
|
||||
on_renameBtn_clicked();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QWidget::eventFilter(obj, evt);
|
||||
}
|
||||
|
||||
ScreenshotsPage::~ScreenshotsPage()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ScreenshotsPage::onItemActivated(QModelIndex index)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return;
|
||||
auto info = m_model->fileInfo(index);
|
||||
QString fileName = info.absoluteFilePath();
|
||||
openFileInDefaultProgram(info.absoluteFilePath());
|
||||
}
|
||||
|
||||
void ScreenshotsPage::on_viewFolderBtn_clicked()
|
||||
{
|
||||
openDirInDefaultProgram(m_folder, true);
|
||||
}
|
||||
|
||||
void ScreenshotsPage::on_uploadBtn_clicked()
|
||||
{
|
||||
auto selection = ui->listView->selectionModel()->selectedIndexes();
|
||||
if (selection.isEmpty())
|
||||
return;
|
||||
|
||||
QList<ScreenshotPtr> uploaded;
|
||||
auto job = std::make_shared<NetJob>("Screenshot Upload");
|
||||
for (auto item : selection)
|
||||
{
|
||||
auto info = m_model->fileInfo(item);
|
||||
auto screenshot = std::make_shared<ScreenShot>(info);
|
||||
uploaded.push_back(screenshot);
|
||||
job->addNetAction(ImgurUpload::make(screenshot));
|
||||
}
|
||||
SequentialTask task;
|
||||
auto albumTask = std::make_shared<NetJob>("Imgur Album Creation");
|
||||
auto imgurAlbum = ImgurAlbumCreation::make(uploaded);
|
||||
albumTask->addNetAction(imgurAlbum);
|
||||
task.addTask(job);
|
||||
task.addTask(albumTask);
|
||||
ProgressDialog prog(this);
|
||||
if (prog.exec(&task) != QDialog::Accepted)
|
||||
{
|
||||
CustomMessageBox::selectable(this, tr("Failed to upload screenshots!"),
|
||||
tr("Unknown error"), QMessageBox::Warning)->exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto link = QString("https://imgur.com/a/%1").arg(imgurAlbum->id());
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
clipboard->setText(link);
|
||||
QDesktopServices::openUrl(link);
|
||||
CustomMessageBox::selectable(
|
||||
this, tr("Upload finished"),
|
||||
tr("The <a href=\"%1\">link to the uploaded album</a> has been opened in the "
|
||||
"default browser and placed in your clipboard.<br/>Delete hash: %2 (save "
|
||||
"this if you want to be able to edit/delete the album)")
|
||||
.arg(link, imgurAlbum->deleteHash()),
|
||||
QMessageBox::Information)->exec();
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenshotsPage::on_deleteBtn_clicked()
|
||||
{
|
||||
auto mbox = CustomMessageBox::selectable(
|
||||
this, tr("Are you sure?"), tr("This will delete all selected screenshots."),
|
||||
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No);
|
||||
std::unique_ptr<QMessageBox> box(mbox);
|
||||
|
||||
if (box->exec() != QMessageBox::Yes)
|
||||
return;
|
||||
|
||||
auto selected = ui->listView->selectionModel()->selectedIndexes();
|
||||
for (auto item : selected)
|
||||
{
|
||||
m_model->remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenshotsPage::on_renameBtn_clicked()
|
||||
{
|
||||
auto selection = ui->listView->selectionModel()->selectedIndexes();
|
||||
if (selection.isEmpty())
|
||||
return;
|
||||
ui->listView->edit(selection[0]);
|
||||
// TODO: mass renaming
|
||||
}
|
||||
|
||||
void ScreenshotsPage::opened()
|
||||
{
|
||||
if (m_valid)
|
||||
{
|
||||
QString path = QDir(m_folder).absolutePath();
|
||||
m_model->setRootPath(path);
|
||||
ui->listView->setRootIndex(m_filterModel->mapFromSource(m_model->index(path)));
|
||||
}
|
||||
}
|
||||
|
||||
#include "ScreenshotsPage.moc"
|
||||
79
gui/pages/ScreenshotsPage.h
Normal file
79
gui/pages/ScreenshotsPage.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "logic/OneSixInstance.h"
|
||||
#include "BasePage.h"
|
||||
|
||||
class QFileSystemModel;
|
||||
class QIdentityProxyModel;
|
||||
namespace Ui
|
||||
{
|
||||
class ScreenshotsPage;
|
||||
}
|
||||
|
||||
struct ScreenShot;
|
||||
class ScreenshotList;
|
||||
class ImgurAlbumCreation;
|
||||
|
||||
class ScreenshotsPage : public QWidget, public BasePage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ScreenshotsPage(BaseInstance *instance, QWidget *parent = 0);
|
||||
virtual ~ScreenshotsPage();
|
||||
|
||||
virtual void opened() override;
|
||||
|
||||
enum
|
||||
{
|
||||
NothingDone = 0x42
|
||||
};
|
||||
|
||||
virtual bool eventFilter(QObject *, QEvent *);
|
||||
virtual QString displayName() const override
|
||||
{
|
||||
return tr("Screenshots");
|
||||
}
|
||||
virtual QIcon icon() const override
|
||||
{
|
||||
return QIcon::fromTheme("screenshots");
|
||||
}
|
||||
virtual QString id() const override
|
||||
{
|
||||
return "screenshots";
|
||||
}
|
||||
virtual QString helpPage() const override
|
||||
{
|
||||
return "Screenshots-management";
|
||||
}
|
||||
private slots:
|
||||
void on_uploadBtn_clicked();
|
||||
void on_deleteBtn_clicked();
|
||||
void on_renameBtn_clicked();
|
||||
void on_viewFolderBtn_clicked();
|
||||
void onItemActivated(QModelIndex);
|
||||
|
||||
private:
|
||||
Ui::ScreenshotsPage *ui;
|
||||
std::shared_ptr<QFileSystemModel> m_model;
|
||||
std::shared_ptr<QIdentityProxyModel> m_filterModel;
|
||||
QString m_folder;
|
||||
bool m_valid = false;
|
||||
};
|
||||
103
gui/pages/ScreenshotsPage.ui
Normal file
103
gui/pages/ScreenshotsPage.ui
Normal file
@@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ScreenshotsPage</class>
|
||||
<widget class="QWidget" name="ScreenshotsPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>723</width>
|
||||
<height>532</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Mods</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QListView" name="listView">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectItems</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="uploadBtn">
|
||||
<property name="text">
|
||||
<string>&Upload</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="deleteBtn">
|
||||
<property name="text">
|
||||
<string>&Delete</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="renameBtn">
|
||||
<property name="text">
|
||||
<string>&Rename</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="viewFolderBtn">
|
||||
<property name="text">
|
||||
<string>&View Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>listView</tabstop>
|
||||
<tabstop>uploadBtn</tabstop>
|
||||
<tabstop>deleteBtn</tabstop>
|
||||
<tabstop>renameBtn</tabstop>
|
||||
<tabstop>viewFolderBtn</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
17
gui/pages/TexturePackPage.h
Normal file
17
gui/pages/TexturePackPage.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "ModFolderPage.h"
|
||||
|
||||
class TexturePackPage : public ModFolderPage
|
||||
{
|
||||
public:
|
||||
explicit TexturePackPage(BaseInstance *instance, QWidget *parent = 0)
|
||||
: ModFolderPage(instance, instance->texturePackList(), "texturepacks", "resourcepacks",
|
||||
tr("Texture packs"), "Texture-packs", parent)
|
||||
{
|
||||
}
|
||||
virtual ~TexturePackPage() {}
|
||||
virtual bool shouldDisplay() const override
|
||||
{
|
||||
return m_inst->traits().contains("texturepacks");
|
||||
}
|
||||
};
|
||||
376
gui/pages/VersionPage.cpp
Normal file
376
gui/pages/VersionPage.cpp
Normal file
@@ -0,0 +1,376 @@
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MultiMC.h"
|
||||
|
||||
#include <pathutils.h>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QEvent>
|
||||
#include <QKeyEvent>
|
||||
|
||||
#include "VersionPage.h"
|
||||
#include "ui_VersionPage.h"
|
||||
|
||||
#include "gui/Platform.h"
|
||||
#include "gui/dialogs/CustomMessageBox.h"
|
||||
#include "gui/dialogs/VersionSelectDialog.h"
|
||||
#include "gui/dialogs/ModEditDialogCommon.h"
|
||||
|
||||
#include "gui/dialogs/ProgressDialog.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QMessageBox>
|
||||
#include <QListView>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
#include "logic/ModList.h"
|
||||
#include "logic/minecraft/InstanceVersion.h"
|
||||
#include "logic/EnabledItemFilter.h"
|
||||
#include "logic/forge/ForgeVersionList.h"
|
||||
#include "logic/forge/ForgeInstaller.h"
|
||||
#include "logic/liteloader/LiteLoaderVersionList.h"
|
||||
#include "logic/liteloader/LiteLoaderInstaller.h"
|
||||
#include "logic/minecraft/VersionBuilder.h"
|
||||
#include "logic/auth/MojangAccountList.h"
|
||||
#include "logic/Mod.h"
|
||||
#include "logic/icons/IconList.h"
|
||||
|
||||
|
||||
QIcon VersionPage::icon() const
|
||||
{
|
||||
return MMC->icons()->getIcon(m_inst->iconKey());
|
||||
}
|
||||
bool VersionPage::shouldDisplay() const
|
||||
{
|
||||
return !m_inst->isRunning();
|
||||
}
|
||||
|
||||
VersionPage::VersionPage(OneSixInstance *inst, QWidget *parent)
|
||||
: QWidget(parent), ui(new Ui::VersionPage), m_inst(inst)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
// libraries!
|
||||
|
||||
m_version = m_inst->getFullVersion();
|
||||
if (m_version)
|
||||
{
|
||||
main_model = new EnabledItemFilter(this);
|
||||
main_model->setActive(true);
|
||||
main_model->setSourceModel(m_version.get());
|
||||
ui->libraryTreeView->setModel(main_model);
|
||||
ui->libraryTreeView->installEventFilter(this);
|
||||
ui->libraryTreeView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
connect(ui->libraryTreeView->selectionModel(), &QItemSelectionModel::currentChanged,
|
||||
this, &VersionPage::versionCurrent);
|
||||
updateVersionControls();
|
||||
// select first item.
|
||||
auto index = main_model->index(0,0);
|
||||
if(index.isValid())
|
||||
ui->libraryTreeView->setCurrentIndex(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
disableVersionControls();
|
||||
}
|
||||
connect(m_inst, &OneSixInstance::versionReloaded, this,
|
||||
&VersionPage::updateVersionControls);
|
||||
}
|
||||
|
||||
VersionPage::~VersionPage()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void VersionPage::updateVersionControls()
|
||||
{
|
||||
ui->forgeBtn->setEnabled(true);
|
||||
ui->liteloaderBtn->setEnabled(true);
|
||||
}
|
||||
|
||||
void VersionPage::disableVersionControls()
|
||||
{
|
||||
ui->forgeBtn->setEnabled(false);
|
||||
ui->liteloaderBtn->setEnabled(false);
|
||||
ui->reloadLibrariesBtn->setEnabled(false);
|
||||
ui->removeLibraryBtn->setEnabled(false);
|
||||
}
|
||||
|
||||
bool VersionPage::reloadInstanceVersion()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_inst->reloadVersion();
|
||||
return true;
|
||||
}
|
||||
catch (MMCError &e)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), e.cause());
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
this, tr("Error"),
|
||||
tr("Failed to load the version description file for reasons unknown."));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void VersionPage::on_reloadLibrariesBtn_clicked()
|
||||
{
|
||||
reloadInstanceVersion();
|
||||
}
|
||||
|
||||
void VersionPage::on_removeLibraryBtn_clicked()
|
||||
{
|
||||
if (ui->libraryTreeView->currentIndex().isValid())
|
||||
{
|
||||
// FIXME: use actual model, not reloading.
|
||||
if (!m_version->remove(ui->libraryTreeView->currentIndex().row()))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Couldn't remove file"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VersionPage::on_jarmodBtn_clicked()
|
||||
{
|
||||
QFileDialog w;
|
||||
QSet<QString> locations;
|
||||
QString modsFolder = MMC->settings()->get("CentralModsDir").toString();
|
||||
auto f = [&](QStandardPaths::StandardLocation l)
|
||||
{
|
||||
QString location = QStandardPaths::writableLocation(l);
|
||||
QFileInfo finfo(location);
|
||||
if (!finfo.exists())
|
||||
return;
|
||||
locations.insert(location);
|
||||
};
|
||||
f(QStandardPaths::DesktopLocation);
|
||||
f(QStandardPaths::DocumentsLocation);
|
||||
f(QStandardPaths::DownloadLocation);
|
||||
f(QStandardPaths::HomeLocation);
|
||||
QList<QUrl> urls;
|
||||
for (auto location : locations)
|
||||
{
|
||||
urls.append(QUrl::fromLocalFile(location));
|
||||
}
|
||||
urls.append(QUrl::fromLocalFile(modsFolder));
|
||||
|
||||
w.setFileMode(QFileDialog::ExistingFiles);
|
||||
w.setAcceptMode(QFileDialog::AcceptOpen);
|
||||
w.setNameFilter(tr("Minecraft jar mods (*.zip *.jar)"));
|
||||
w.setDirectory(modsFolder);
|
||||
w.setSidebarUrls(urls);
|
||||
|
||||
if (w.exec())
|
||||
m_version->installJarMods(w.selectedFiles());
|
||||
}
|
||||
|
||||
void VersionPage::on_resetLibraryOrderBtn_clicked()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_version->resetOrder();
|
||||
}
|
||||
catch (MMCError &e)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), e.cause());
|
||||
}
|
||||
}
|
||||
|
||||
void VersionPage::on_moveLibraryUpBtn_clicked()
|
||||
{
|
||||
if (ui->libraryTreeView->selectionModel()->selectedRows().isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
const int row = ui->libraryTreeView->selectionModel()->selectedRows().first().row();
|
||||
m_version->move(row, InstanceVersion::MoveUp);
|
||||
}
|
||||
catch (MMCError &e)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), e.cause());
|
||||
}
|
||||
}
|
||||
|
||||
void VersionPage::on_moveLibraryDownBtn_clicked()
|
||||
{
|
||||
if (ui->libraryTreeView->selectionModel()->selectedRows().isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
const int row = ui->libraryTreeView->selectionModel()->selectedRows().first().row();
|
||||
m_version->move(row, InstanceVersion::MoveDown);
|
||||
}
|
||||
catch (MMCError &e)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), e.cause());
|
||||
}
|
||||
}
|
||||
|
||||
void VersionPage::on_changeMCVersionBtn_clicked()
|
||||
{
|
||||
VersionSelectDialog vselect(m_inst->versionList().get(), tr("Change Minecraft version"),
|
||||
this);
|
||||
if (!vselect.exec() || !vselect.selectedVersion())
|
||||
return;
|
||||
|
||||
if (!MMC->accounts()->anyAccountIsValid())
|
||||
{
|
||||
CustomMessageBox::selectable(
|
||||
this, tr("Error"),
|
||||
tr("MultiMC cannot download Minecraft or update instances unless you have at least "
|
||||
"one account added.\nPlease add your Mojang or Minecraft account."),
|
||||
QMessageBox::Warning)->show();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_inst->versionIsCustom())
|
||||
{
|
||||
auto result = CustomMessageBox::selectable(
|
||||
this, tr("Are you sure?"),
|
||||
tr("This will remove any library/version customization you did previously. "
|
||||
"This includes things like Forge install and similar."),
|
||||
QMessageBox::Warning, QMessageBox::Ok | QMessageBox::Abort,
|
||||
QMessageBox::Abort)->exec();
|
||||
|
||||
if (result != QMessageBox::Ok)
|
||||
return;
|
||||
m_version->revertToVanilla();
|
||||
reloadInstanceVersion();
|
||||
}
|
||||
m_inst->setIntendedVersionId(vselect.selectedVersion()->descriptor());
|
||||
|
||||
auto updateTask = m_inst->doUpdate();
|
||||
if (!updateTask)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ProgressDialog tDialog(this);
|
||||
connect(updateTask.get(), SIGNAL(failed(QString)), SLOT(onGameUpdateError(QString)));
|
||||
tDialog.exec(updateTask.get());
|
||||
}
|
||||
|
||||
void VersionPage::on_forgeBtn_clicked()
|
||||
{
|
||||
// FIXME: use actual model, not reloading. Move logic to model.
|
||||
if (m_version->hasFtbPack())
|
||||
{
|
||||
if (QMessageBox::question(
|
||||
this, tr("Revert?"),
|
||||
tr("This action will remove the FTB pack version patch. Continue?")) !=
|
||||
QMessageBox::Yes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_version->removeFtbPack();
|
||||
reloadInstanceVersion();
|
||||
}
|
||||
if (m_version->hasDeprecatedVersionFiles())
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Revert?"),
|
||||
tr("This action will remove deprecated version files "
|
||||
"(custom.json and version.json). Continue?")) !=
|
||||
QMessageBox::Yes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_version->removeDeprecatedVersionFiles();
|
||||
reloadInstanceVersion();
|
||||
}
|
||||
VersionSelectDialog vselect(MMC->forgelist().get(), tr("Select Forge version"), this);
|
||||
vselect.setExactFilter(1, m_inst->currentVersionId());
|
||||
vselect.setEmptyString(tr("No Forge versions are currently available for Minecraft ") +
|
||||
m_inst->currentVersionId());
|
||||
if (vselect.exec() && vselect.selectedVersion())
|
||||
{
|
||||
ProgressDialog dialog(this);
|
||||
dialog.exec(
|
||||
ForgeInstaller().createInstallTask(m_inst, vselect.selectedVersion(), this));
|
||||
}
|
||||
}
|
||||
|
||||
void VersionPage::on_liteloaderBtn_clicked()
|
||||
{
|
||||
if (m_version->hasFtbPack())
|
||||
{
|
||||
if (QMessageBox::question(
|
||||
this, tr("Revert?"),
|
||||
tr("This action will remove the FTB pack version patch. Continue?")) !=
|
||||
QMessageBox::Yes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_version->removeFtbPack();
|
||||
reloadInstanceVersion();
|
||||
}
|
||||
if (m_version->hasDeprecatedVersionFiles())
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Revert?"),
|
||||
tr("This action will remove deprecated version files "
|
||||
"(custom.json and version.json). Continue?")) !=
|
||||
QMessageBox::Yes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_version->removeDeprecatedVersionFiles();
|
||||
reloadInstanceVersion();
|
||||
}
|
||||
VersionSelectDialog vselect(MMC->liteloaderlist().get(), tr("Select LiteLoader version"),
|
||||
this);
|
||||
vselect.setExactFilter(1, m_inst->currentVersionId());
|
||||
vselect.setEmptyString(tr("No LiteLoader versions are currently available for Minecraft ") +
|
||||
m_inst->currentVersionId());
|
||||
if (vselect.exec() && vselect.selectedVersion())
|
||||
{
|
||||
ProgressDialog dialog(this);
|
||||
dialog.exec(
|
||||
LiteLoaderInstaller().createInstallTask(m_inst, vselect.selectedVersion(), this));
|
||||
}
|
||||
}
|
||||
|
||||
void VersionPage::versionCurrent(const QModelIndex ¤t, const QModelIndex &previous)
|
||||
{
|
||||
if (!current.isValid())
|
||||
{
|
||||
ui->removeLibraryBtn->setDisabled(true);
|
||||
ui->moveLibraryDownBtn->setDisabled(true);
|
||||
ui->moveLibraryUpBtn->setDisabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool enabled = m_version->canRemove(current.row());
|
||||
ui->removeLibraryBtn->setEnabled(enabled);
|
||||
ui->moveLibraryDownBtn->setEnabled(enabled);
|
||||
ui->moveLibraryUpBtn->setEnabled(enabled);
|
||||
}
|
||||
QString selectedId = m_version->versionFileId(current.row());
|
||||
if (selectedId == "net.minecraft" || selectedId == "org.multimc.custom.json" ||
|
||||
selectedId == "org.multimc.version.json")
|
||||
{
|
||||
ui->changeMCVersionBtn->setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->changeMCVersionBtn->setEnabled(false);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,35 +14,44 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <QDialog>
|
||||
|
||||
#include <logic/OneSixInstance.h>
|
||||
#include <QWidget>
|
||||
|
||||
#include "logic/OneSixInstance.h"
|
||||
#include "logic/net/NetJob.h"
|
||||
#include "BasePage.h"
|
||||
|
||||
class EnabledItemFilter;
|
||||
namespace Ui
|
||||
{
|
||||
class OneSixModEditDialog;
|
||||
class VersionPage;
|
||||
}
|
||||
|
||||
class OneSixModEditDialog : public QDialog
|
||||
class VersionPage : public QWidget, public BasePage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit OneSixModEditDialog(OneSixInstance *inst, QWidget *parent = 0);
|
||||
virtual ~OneSixModEditDialog();
|
||||
|
||||
explicit VersionPage(OneSixInstance *inst, QWidget *parent = 0);
|
||||
virtual ~VersionPage();
|
||||
virtual QString displayName() const override
|
||||
{
|
||||
return tr("Version");
|
||||
}
|
||||
virtual QIcon icon() const override;
|
||||
virtual QString id() const override
|
||||
{
|
||||
return "version";
|
||||
}
|
||||
virtual QString helpPage() const override
|
||||
{
|
||||
return "Instance-version";
|
||||
}
|
||||
virtual bool shouldDisplay() const;
|
||||
private
|
||||
slots:
|
||||
void on_addModBtn_clicked();
|
||||
void on_rmModBtn_clicked();
|
||||
void on_viewModBtn_clicked();
|
||||
|
||||
void on_addResPackBtn_clicked();
|
||||
void on_rmResPackBtn_clicked();
|
||||
void on_viewResPackBtn_clicked();
|
||||
// Questionable: SettingsDialog doesn't need this for some reason?
|
||||
void on_buttonBox_rejected();
|
||||
// version tab
|
||||
void on_forgeBtn_clicked();
|
||||
void on_liteloaderBtn_clicked();
|
||||
void on_reloadLibrariesBtn_clicked();
|
||||
@@ -50,26 +59,24 @@ slots:
|
||||
void on_resetLibraryOrderBtn_clicked();
|
||||
void on_moveLibraryUpBtn_clicked();
|
||||
void on_moveLibraryDownBtn_clicked();
|
||||
void on_jarmodBtn_clicked();
|
||||
|
||||
void updateVersionControls();
|
||||
void disableVersionControls();
|
||||
void on_changeMCVersionBtn_clicked();
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *ev);
|
||||
bool loaderListFilter(QKeyEvent *ev);
|
||||
bool resourcePackListFilter(QKeyEvent *ev);
|
||||
/// FIXME: this shouldn't be necessary!
|
||||
bool reloadInstanceVersion();
|
||||
|
||||
private:
|
||||
Ui::OneSixModEditDialog *ui;
|
||||
std::shared_ptr<VersionFinal> m_version;
|
||||
std::shared_ptr<ModList> m_mods;
|
||||
std::shared_ptr<ModList> m_resourcepacks;
|
||||
Ui::VersionPage *ui;
|
||||
std::shared_ptr<InstanceVersion> m_version;
|
||||
EnabledItemFilter *main_model;
|
||||
OneSixInstance *m_inst;
|
||||
NetJobPtr forgeJob;
|
||||
|
||||
public
|
||||
slots:
|
||||
void loaderCurrent(QModelIndex current, QModelIndex previous);
|
||||
void versionCurrent(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
};
|
||||
197
gui/pages/VersionPage.ui
Normal file
197
gui/pages/VersionPage.ui
Normal file
@@ -0,0 +1,197 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>VersionPage</class>
|
||||
<widget class="QWidget" name="VersionPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>475</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Version</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_10">
|
||||
<item>
|
||||
<widget class="ModListView" name="libraryTreeView">
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="headerHidden">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="headerVisible">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Selection</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="changeMCVersionBtn">
|
||||
<property name="text">
|
||||
<string>Change version</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="moveLibraryUpBtn">
|
||||
<property name="toolTip">
|
||||
<string>This isn't implemented yet.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Move up</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="moveLibraryDownBtn">
|
||||
<property name="toolTip">
|
||||
<string>This isn't implemented yet.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Move down</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="removeLibraryBtn">
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LineSeparator" name="separator" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Install</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="forgeBtn">
|
||||
<property name="toolTip">
|
||||
<string>Replace any current custom version with Minecraft Forge</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Install Forge</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="liteloaderBtn">
|
||||
<property name="text">
|
||||
<string>Install LiteLoader</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="jarmodBtn">
|
||||
<property name="text">
|
||||
<string>Add jar mod</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LineSeparator" name="widget" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>List</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="resetLibraryOrderBtn">
|
||||
<property name="toolTip">
|
||||
<string>This isn't implemented yet.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reset order</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="reloadLibrariesBtn">
|
||||
<property name="text">
|
||||
<string>Reload</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ModListView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>gui/widgets/ModListView.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>LineSeparator</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>gui/widgets/LineSeparator.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
30
gui/widgets/IconLabel.cpp
Normal file
30
gui/widgets/IconLabel.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "IconLabel.h"
|
||||
|
||||
#include <QStyle>
|
||||
#include <QStyleOption>
|
||||
#include <QLayout>
|
||||
#include <QPainter>
|
||||
#include <QRect>
|
||||
|
||||
IconLabel::IconLabel(QWidget *parent, QIcon icon, QSize size)
|
||||
: QWidget(parent), m_size(size), m_icon(icon)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
}
|
||||
|
||||
QSize IconLabel::sizeHint() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
void IconLabel::setIcon(QIcon icon)
|
||||
{
|
||||
m_icon = icon;
|
||||
update();
|
||||
}
|
||||
|
||||
void IconLabel::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter p(this);
|
||||
m_icon.paint(&p, contentsRect());
|
||||
}
|
||||
26
gui/widgets/IconLabel.h
Normal file
26
gui/widgets/IconLabel.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include <QWidget>
|
||||
#include <QIcon>
|
||||
|
||||
class QStyleOption;
|
||||
|
||||
/**
|
||||
* This is a trivial widget that paints a QIcon of the specified size.
|
||||
*/
|
||||
class IconLabel : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/// Create a line separator. orientation is the orientation of the line.
|
||||
explicit IconLabel(QWidget *parent, QIcon icon, QSize size);
|
||||
|
||||
virtual QSize sizeHint() const;
|
||||
virtual void paintEvent(QPaintEvent *);
|
||||
|
||||
void setIcon(QIcon icon);
|
||||
|
||||
private:
|
||||
QSize m_size;
|
||||
QIcon m_icon;
|
||||
};
|
||||
37
gui/widgets/LineSeparator.cpp
Normal file
37
gui/widgets/LineSeparator.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "LineSeparator.h"
|
||||
|
||||
#include <QStyle>
|
||||
#include <QStyleOption>
|
||||
#include <QLayout>
|
||||
#include <QPainter>
|
||||
|
||||
void LineSeparator::initStyleOption(QStyleOption *option) const
|
||||
{
|
||||
option->initFrom(this);
|
||||
// in a horizontal layout, the line is vertical (and vice versa)
|
||||
if (m_orientation == Qt::Vertical)
|
||||
option->state |= QStyle::State_Horizontal;
|
||||
}
|
||||
|
||||
LineSeparator::LineSeparator(QWidget *parent, Qt::Orientation orientation)
|
||||
: QWidget(parent), m_orientation(orientation)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
}
|
||||
|
||||
QSize LineSeparator::sizeHint() const
|
||||
{
|
||||
QStyleOption opt;
|
||||
initStyleOption(&opt);
|
||||
const int extent =
|
||||
style()->pixelMetric(QStyle::PM_ToolBarSeparatorExtent, &opt, parentWidget());
|
||||
return QSize(extent, extent);
|
||||
}
|
||||
|
||||
void LineSeparator::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter p(this);
|
||||
QStyleOption opt;
|
||||
initStyleOption(&opt);
|
||||
style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, &opt, &p, parentWidget());
|
||||
}
|
||||
18
gui/widgets/LineSeparator.h
Normal file
18
gui/widgets/LineSeparator.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include <QWidget>
|
||||
|
||||
class QStyleOption;
|
||||
|
||||
class LineSeparator : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/// Create a line separator. orientation is the orientation of the line.
|
||||
explicit LineSeparator(QWidget *parent, Qt::Orientation orientation = Qt::Horizontal);
|
||||
QSize sizeHint() const;
|
||||
void paintEvent(QPaintEvent *);
|
||||
void initStyleOption(QStyleOption *option) const;
|
||||
private:
|
||||
Qt::Orientation m_orientation = Qt::Horizontal;
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user