summaryrefslogtreecommitdiffstats
path: root/application
diff options
context:
space:
mode:
Diffstat (limited to 'application')
-rw-r--r--application/BuildConfig.cpp.in83
-rw-r--r--application/BuildConfig.h89
-rw-r--r--application/CMakeLists.txt654
-rw-r--r--application/ColorCache.cpp30
-rw-r--r--application/ColorCache.h178
-rw-r--r--application/ColumnResizer.cpp280
-rw-r--r--application/ColumnResizer.h20
-rw-r--r--application/GuiUtil.cpp192
-rw-r--r--application/HoeDown.h96
-rw-r--r--application/InstancePageProvider.h95
-rw-r--r--application/InstanceProxyModel.cpp36
-rw-r--r--application/InstanceProxyModel.h6
-rw-r--r--application/InstanceWindow.cpp280
-rw-r--r--application/InstanceWindow.h54
-rw-r--r--application/JavaCommon.cpp142
-rw-r--r--application/JavaCommon.h74
-rw-r--r--application/KonamiCode.cpp48
-rw-r--r--application/KonamiCode.h10
-rw-r--r--application/LaunchController.cpp483
-rw-r--r--application/LaunchController.h84
-rw-r--r--application/MainWindow.cpp2929
-rw-r--r--application/MainWindow.h219
-rw-r--r--application/MultiMC.cpp1913
-rw-r--r--application/MultiMC.h253
-rw-r--r--application/SettingsUI.h26
-rw-r--r--application/UpdateController.cpp736
-rw-r--r--application/UpdateController.h54
-rw-r--r--application/VersionProxyModel.cpp677
-rw-r--r--application/VersionProxyModel.h80
-rw-r--r--application/dialogs/AboutDialog.cpp158
-rw-r--r--application/dialogs/AboutDialog.h24
-rw-r--r--application/dialogs/AboutDialog.ui4
-rw-r--r--application/dialogs/CopyInstanceDialog.cpp104
-rw-r--r--application/dialogs/CopyInstanceDialog.h32
-rw-r--r--application/dialogs/CustomMessageBox.cpp24
-rw-r--r--application/dialogs/CustomMessageBox.h8
-rw-r--r--application/dialogs/EditAccountDialog.cpp26
-rw-r--r--application/dialogs/EditAccountDialog.h36
-rw-r--r--application/dialogs/ExportInstanceDialog.cpp806
-rw-r--r--application/dialogs/ExportInstanceDialog.h26
-rw-r--r--application/dialogs/IconPickerDialog.cpp189
-rw-r--r--application/dialogs/IconPickerDialog.h28
-rw-r--r--application/dialogs/LoginDialog.cpp84
-rw-r--r--application/dialogs/LoginDialog.h32
-rw-r--r--application/dialogs/ModEditDialogCommon.cpp40
-rw-r--r--application/dialogs/ModEditDialogCommon.h9
-rw-r--r--application/dialogs/NewComponentDialog.cpp88
-rw-r--r--application/dialogs/NewComponentDialog.h22
-rw-r--r--application/dialogs/NewComponentDialog.ui2
-rw-r--r--application/dialogs/NewInstanceDialog.cpp253
-rw-r--r--application/dialogs/NewInstanceDialog.h56
-rw-r--r--application/dialogs/NotificationDialog.cpp116
-rw-r--r--application/dialogs/NotificationDialog.h32
-rw-r--r--application/dialogs/ProfileSelectDialog.cpp126
-rw-r--r--application/dialogs/ProfileSelectDialog.h100
-rw-r--r--application/dialogs/ProgressDialog.cpp210
-rw-r--r--application/dialogs/ProgressDialog.h42
-rw-r--r--application/dialogs/SkinUploadDialog.cpp180
-rw-r--r--application/dialogs/SkinUploadDialog.h18
-rw-r--r--application/dialogs/UpdateDialog.cpp258
-rw-r--r--application/dialogs/UpdateDialog.h42
-rw-r--r--application/dialogs/VersionSelectDialog.cpp102
-rw-r--r--application/dialogs/VersionSelectDialog.h50
-rw-r--r--application/groupview/AccessibleGroupView.cpp774
-rw-r--r--application/groupview/AccessibleGroupView.h6
-rw-r--r--application/groupview/AccessibleGroupView_p.h116
-rw-r--r--application/groupview/GroupView.cpp1527
-rw-r--r--application/groupview/GroupView.h187
-rw-r--r--application/groupview/GroupedProxyModel.cpp36
-rw-r--r--application/groupview/GroupedProxyModel.h10
-rw-r--r--application/groupview/InstanceDelegate.cpp637
-rw-r--r--application/groupview/InstanceDelegate.h21
-rw-r--r--application/groupview/VisualGroup.cpp464
-rw-r--r--application/groupview/VisualGroup.h108
-rw-r--r--application/install_prereqs.cmake.in28
-rw-r--r--application/main.cpp63
-rwxr-xr-xapplication/package/linux/MultiMC116
-rwxr-xr-xapplication/package/linux/multimc.desktop1
-rw-r--r--application/package/ubuntu/multimc/DEBIAN/control12
-rwxr-xr-xapplication/package/ubuntu/multimc/DEBIAN/postrm3
-rw-r--r--application/package/ubuntu/multimc/opt/multimc/icon.svg353
-rwxr-xr-xapplication/package/ubuntu/multimc/opt/multimc/run.sh33
-rwxr-xr-xapplication/package/ubuntu/multimc/usr/share/applications/multimc.desktop16
-rw-r--r--application/package/ubuntu/readme.md12
-rw-r--r--application/pagedialog/PageDialog.cpp47
-rw-r--r--application/pagedialog/PageDialog.h12
-rw-r--r--application/pages/BasePage.h56
-rw-r--r--application/pages/BasePageContainer.h8
-rw-r--r--application/pages/BasePageProvider.h67
-rw-r--r--application/pages/global/AccountListPage.cpp194
-rw-r--r--application/pages/global/AccountListPage.h83
-rw-r--r--application/pages/global/AccountListPage.ui182
-rw-r--r--application/pages/global/CustomCommandsPage.cpp49
-rw-r--r--application/pages/global/CustomCommandsPage.h48
-rw-r--r--application/pages/global/ExternalToolsPage.cpp307
-rw-r--r--application/pages/global/ExternalToolsPage.h72
-rw-r--r--application/pages/global/ExternalToolsPage.ui4
-rw-r--r--application/pages/global/JavaPage.cpp167
-rw-r--r--application/pages/global/JavaPage.h58
-rw-r--r--application/pages/global/LanguagePage.cpp51
-rw-r--r--application/pages/global/LanguagePage.h60
-rw-r--r--application/pages/global/MinecraftPage.cpp45
-rw-r--r--application/pages/global/MinecraftPage.h52
-rw-r--r--application/pages/global/MultiMCPage.cpp565
-rw-r--r--application/pages/global/MultiMCPage.h100
-rw-r--r--application/pages/global/MultiMCPage.ui15
-rw-r--r--application/pages/global/PackagesPage.cpp288
-rw-r--r--application/pages/global/PackagesPage.h40
-rw-r--r--application/pages/global/PasteEEPage.cpp63
-rw-r--r--application/pages/global/PasteEEPage.h52
-rw-r--r--application/pages/global/ProxyPage.cpp97
-rw-r--r--application/pages/global/ProxyPage.h52
-rw-r--r--application/pages/instance/GameOptionsPage.cpp40
-rw-r--r--application/pages/instance/GameOptionsPage.h63
-rw-r--r--application/pages/instance/GameOptionsPage.ui88
-rw-r--r--application/pages/instance/InstanceSettingsPage.cpp422
-rw-r--r--application/pages/instance/InstanceSettingsPage.h66
-rw-r--r--application/pages/instance/InstanceSettingsPage.ui15
-rw-r--r--application/pages/instance/LegacyUpgradePage.cpp44
-rw-r--r--application/pages/instance/LegacyUpgradePage.h50
-rw-r--r--application/pages/instance/LogPage.cpp446
-rw-r--r--application/pages/instance/LogPage.h82
-rw-r--r--application/pages/instance/ModFolderPage.cpp377
-rw-r--r--application/pages/instance/ModFolderPage.h129
-rw-r--r--application/pages/instance/ModFolderPage.ui275
-rw-r--r--application/pages/instance/NotesPage.cpp13
-rw-r--r--application/pages/instance/NotesPage.h52
-rw-r--r--application/pages/instance/NotesPage.ui40
-rw-r--r--application/pages/instance/OtherLogsPage.cpp420
-rw-r--r--application/pages/instance/OtherLogsPage.h78
-rw-r--r--application/pages/instance/ResourcePackPage.h25
-rw-r--r--application/pages/instance/ScreenshotsPage.cpp608
-rw-r--r--application/pages/instance/ScreenshotsPage.h91
-rw-r--r--application/pages/instance/ScreenshotsPage.ui162
-rw-r--r--application/pages/instance/ServersPage.cpp760
-rw-r--r--application/pages/instance/ServersPage.h93
-rw-r--r--application/pages/instance/ServersPage.ui191
-rw-r--r--application/pages/instance/TexturePackPage.h23
-rw-r--r--application/pages/instance/VersionPage.cpp971
-rw-r--r--application/pages/instance/VersionPage.h108
-rw-r--r--application/pages/instance/VersionPage.ui516
-rw-r--r--application/pages/instance/WorldListPage.cpp432
-rw-r--r--application/pages/instance/WorldListPage.h105
-rw-r--r--application/pages/instance/WorldListPage.ui266
-rw-r--r--application/pages/modplatform/FTBPage.cpp434
-rw-r--r--application/pages/modplatform/FTBPage.h104
-rw-r--r--application/pages/modplatform/FTBPage.ui159
-rw-r--r--application/pages/modplatform/FtbListModel.cpp275
-rw-r--r--application/pages/modplatform/FtbListModel.h68
-rw-r--r--application/pages/modplatform/ImportPage.cpp161
-rw-r--r--application/pages/modplatform/ImportPage.h56
-rw-r--r--application/pages/modplatform/TechnicPage.cpp13
-rw-r--r--application/pages/modplatform/TechnicPage.h50
-rw-r--r--application/pages/modplatform/TwitchPage.cpp47
-rw-r--r--application/pages/modplatform/TwitchPage.h58
-rw-r--r--application/pages/modplatform/TwitchPage.ui33
-rw-r--r--application/pages/modplatform/VanillaPage.cpp94
-rw-r--r--application/pages/modplatform/VanillaPage.h64
-rw-r--r--application/pages/modplatform/VanillaPage.ui20
-rw-r--r--application/resources/OSX/OSX.qrc67
-rw-r--r--application/resources/OSX/scalable/language.svg40
-rw-r--r--application/resources/assets/assets.qrc2
-rw-r--r--application/resources/backgrounds/backgrounds.qrc1
-rw-r--r--application/resources/backgrounds/catbgrnd2.pngbin78285 -> 62973 bytes
-rw-r--r--application/resources/backgrounds/catmas.pngbin0 -> 72818 bytes
-rw-r--r--application/resources/documents/documents.qrc6
-rw-r--r--application/resources/flat/flat.qrc83
-rw-r--r--application/resources/flat/scalable/language.svg103
-rw-r--r--application/resources/iOS/iOS.qrc69
-rw-r--r--application/resources/iOS/scalable/language.svg32
-rw-r--r--application/resources/multimc/128x128/unknown_server.pngbin0 -> 11085 bytes
-rw-r--r--application/resources/multimc/index.theme12
-rw-r--r--application/resources/multimc/multimc.qrc560
-rw-r--r--application/resources/multimc/scalable/instances/fox.svg290
-rw-r--r--application/resources/multimc/scalable/language.svg109
-rw-r--r--application/resources/pe_blue/pe_blue.qrc69
-rw-r--r--application/resources/pe_blue/scalable/language.svg46
-rw-r--r--application/resources/pe_colored/pe_colored.qrc69
-rw-r--r--application/resources/pe_colored/scalable/language.svg44
-rw-r--r--application/resources/pe_dark/pe_dark.qrc69
-rw-r--r--application/resources/pe_dark/scalable/language.svg45
-rw-r--r--application/resources/pe_light/pe_light.qrc69
-rw-r--r--application/resources/pe_light/scalable/language.svg80
-rw-r--r--application/setupwizard/AnalyticsWizardPage.cpp70
-rw-r--r--application/setupwizard/AnalyticsWizardPage.h16
-rw-r--r--application/setupwizard/BaseWizardPage.h42
-rw-r--r--application/setupwizard/JavaWizardPage.cpp90
-rw-r--r--application/setupwizard/JavaWizardPage.h24
-rw-r--r--application/setupwizard/LanguageWizardPage.cpp54
-rw-r--r--application/setupwizard/LanguageWizardPage.h23
-rw-r--r--application/setupwizard/SetupWizard.cpp90
-rw-r--r--application/setupwizard/SetupWizard.h18
-rw-r--r--application/themes/BrightTheme.cpp44
-rw-r--r--application/themes/BrightTheme.h18
-rw-r--r--application/themes/CustomTheme.cpp368
-rw-r--r--application/themes/CustomTheme.h38
-rw-r--r--application/themes/DarkTheme.cpp44
-rw-r--r--application/themes/DarkTheme.h18
-rw-r--r--application/themes/FusionTheme.cpp2
-rw-r--r--application/themes/FusionTheme.h4
-rw-r--r--application/themes/ITheme.cpp68
-rw-r--r--application/themes/ITheme.h32
-rw-r--r--application/themes/SystemTheme.cpp62
-rw-r--r--application/themes/SystemTheme.h28
-rw-r--r--application/widgets/Common.cpp42
-rw-r--r--application/widgets/Common.h2
-rw-r--r--application/widgets/CustomCommands.cpp34
-rw-r--r--application/widgets/CustomCommands.h20
-rw-r--r--application/widgets/CustomCommands.ui12
-rw-r--r--application/widgets/FocusLineEdit.cpp22
-rw-r--r--application/widgets/FocusLineEdit.h16
-rw-r--r--application/widgets/IconLabel.cpp40
-rw-r--r--application/widgets/IconLabel.h16
-rw-r--r--application/widgets/JavaSettingsWidget.cpp654
-rw-r--r--application/widgets/JavaSettingsWidget.h122
-rw-r--r--application/widgets/LabeledToolButton.cpp104
-rw-r--r--application/widgets/LabeledToolButton.h22
-rw-r--r--application/widgets/LanguageSelectionWidget.cpp68
-rw-r--r--application/widgets/LanguageSelectionWidget.h41
-rw-r--r--application/widgets/LineSeparator.cpp30
-rw-r--r--application/widgets/LineSeparator.h14
-rw-r--r--application/widgets/LogView.cpp186
-rw-r--r--application/widgets/LogView.h38
-rw-r--r--application/widgets/MCModInfoFrame.cpp212
-rw-r--r--application/widgets/MCModInfoFrame.h30
-rw-r--r--application/widgets/ModListView.cpp76
-rw-r--r--application/widgets/ModListView.h10
-rw-r--r--application/widgets/PageContainer.cpp310
-rw-r--r--application/widgets/PageContainer.h81
-rw-r--r--application/widgets/PageContainer_p.h158
-rw-r--r--application/widgets/ProgressWidget.cpp80
-rw-r--r--application/widgets/ProgressWidget.h22
-rw-r--r--application/widgets/ServerStatus.cpp214
-rw-r--r--application/widgets/ServerStatus.h34
-rw-r--r--application/widgets/VersionListView.cpp185
-rw-r--r--application/widgets/VersionListView.h49
-rw-r--r--application/widgets/VersionSelectWidget.cpp213
-rw-r--r--application/widgets/VersionSelectWidget.h70
-rw-r--r--application/widgets/WideBar.cpp116
-rw-r--r--application/widgets/WideBar.h26
240 files changed, 20053 insertions, 15526 deletions
diff --git a/application/BuildConfig.cpp.in b/application/BuildConfig.cpp.in
index 0a28f074..4253afd0 100644
--- a/application/BuildConfig.cpp.in
+++ b/application/BuildConfig.cpp.in
@@ -5,50 +5,49 @@ Config BuildConfig;
Config::Config()
{
- // Version information
- VERSION_MAJOR = @MultiMC_VERSION_MAJOR@;
- VERSION_MINOR = @MultiMC_VERSION_MINOR@;
- VERSION_HOTFIX = @MultiMC_VERSION_HOTFIX@;
- VERSION_BUILD = @MultiMC_VERSION_BUILD@;
-
- BUILD_PLATFORM = "@MultiMC_BUILD_PLATFORM@";
- CHANLIST_URL = "@MultiMC_CHANLIST_URL@";
-/* ANALYTICS_ID = "@MultiMC_ANALYTICS_ID@"; */
- NOTIFICATION_URL = "@MultiMC_NOTIFICATION_URL@";
- FULL_VERSION_STR = "@MultiMC_VERSION_MAJOR@.@MultiMC_VERSION_MINOR@.@MultiMC_VERSION_BUILD@";
-
- GIT_COMMIT = "@MultiMC_GIT_COMMIT@";
- GIT_REFSPEC = "@MultiMC_GIT_REFSPEC@";
- if(GIT_REFSPEC.startsWith("refs/heads/") && !CHANLIST_URL.isEmpty() && VERSION_BUILD >= 0)
- {
- VERSION_CHANNEL = GIT_REFSPEC;
- VERSION_CHANNEL.remove("refs/heads/");
- UPDATER_ENABLED = true;
- }
- else
- {
- VERSION_CHANNEL = QObject::tr("custom");
- }
-
- VERSION_STR = "@MultiMC_VERSION_STRING@";
- NEWS_RSS_URL = "@MultiMC_NEWS_RSS_URL@";
- PASTE_EE_KEY = "@MultiMC_PASTE_EE_API_KEY@";
+ // Version information
+ VERSION_MAJOR = @MultiMC_VERSION_MAJOR@;
+ VERSION_MINOR = @MultiMC_VERSION_MINOR@;
+ VERSION_HOTFIX = @MultiMC_VERSION_HOTFIX@;
+ VERSION_BUILD = @MultiMC_VERSION_BUILD@;
+
+ BUILD_PLATFORM = "@MultiMC_BUILD_PLATFORM@";
+ CHANLIST_URL = "@MultiMC_CHANLIST_URL@";
+ NOTIFICATION_URL = "@MultiMC_NOTIFICATION_URL@";
+ FULL_VERSION_STR = "@MultiMC_VERSION_MAJOR@.@MultiMC_VERSION_MINOR@.@MultiMC_VERSION_BUILD@";
+
+ GIT_COMMIT = "@MultiMC_GIT_COMMIT@";
+ GIT_REFSPEC = "@MultiMC_GIT_REFSPEC@";
+ if(GIT_REFSPEC.startsWith("refs/heads/") && !CHANLIST_URL.isEmpty() && VERSION_BUILD >= 0)
+ {
+ VERSION_CHANNEL = GIT_REFSPEC;
+ VERSION_CHANNEL.remove("refs/heads/");
+ UPDATER_ENABLED = true;
+ }
+ else
+ {
+ VERSION_CHANNEL = QObject::tr("custom");
+ }
+
+ VERSION_STR = "@MultiMC_VERSION_STRING@";
+ NEWS_RSS_URL = "@MultiMC_NEWS_RSS_URL@";
+ PASTE_EE_KEY = "@MultiMC_PASTE_EE_API_KEY@";
}
QString Config::printableVersionString() const
{
- QString vstr = QString("%1.%2.%3").arg(QString::number(VERSION_MAJOR), QString::number(VERSION_MINOR), QString::number(VERSION_HOTFIX));
-
- // If the build is not a main release, append the channel
- if(VERSION_CHANNEL != "stable")
- {
- vstr += "-" + VERSION_CHANNEL;
- }
-
- // if a build number is set, also add it to the end
- if(VERSION_BUILD >= 0)
- {
- vstr += "-" + QString::number(VERSION_BUILD);
- }
- return vstr;
+ QString vstr = QString("%1.%2.%3").arg(QString::number(VERSION_MAJOR), QString::number(VERSION_MINOR), QString::number(VERSION_HOTFIX));
+
+ // If the build is not a main release, append the channel
+ if(VERSION_CHANNEL != "stable")
+ {
+ vstr += "-" + VERSION_CHANNEL;
+ }
+
+ // if a build number is set, also add it to the end
+ if(VERSION_BUILD >= 0)
+ {
+ vstr += "-" + QString::number(VERSION_BUILD);
+ }
+ return vstr;
}
diff --git a/application/BuildConfig.h b/application/BuildConfig.h
index e561cb52..b7965e10 100644
--- a/application/BuildConfig.h
+++ b/application/BuildConfig.h
@@ -7,64 +7,61 @@
class Config
{
public:
- Config();
- /// The major version number.
- int VERSION_MAJOR;
- /// The minor version number.
- int VERSION_MINOR;
- /// The hotfix number.
- int VERSION_HOTFIX;
- /// The build number.
- int VERSION_BUILD;
+ Config();
+ /// The major version number.
+ int VERSION_MAJOR;
+ /// The minor version number.
+ int VERSION_MINOR;
+ /// The hotfix number.
+ int VERSION_HOTFIX;
+ /// The build number.
+ int VERSION_BUILD;
- /**
- * The version channel
- * This is used by the updater to determine what channel the current version came from.
- */
- QString VERSION_CHANNEL;
+ /**
+ * The version channel
+ * This is used by the updater to determine what channel the current version came from.
+ */
+ QString VERSION_CHANNEL;
- bool UPDATER_ENABLED = false;
+ bool UPDATER_ENABLED = false;
- /// A short string identifying this build's platform. For example, "lin64" or "win32".
- QString BUILD_PLATFORM;
+ /// A short string identifying this build's platform. For example, "lin64" or "win32".
+ QString BUILD_PLATFORM;
- /// URL for the updater's channel
- QString CHANLIST_URL;
+ /// URL for the updater's channel
+ QString CHANLIST_URL;
-/* /// Google analytics ID
- QString ANALYTICS_ID;
-*/
- /// URL for notifications
- QString NOTIFICATION_URL;
+ /// URL for notifications
+ QString NOTIFICATION_URL;
- /// Used for matching notifications
- QString FULL_VERSION_STR;
+ /// Used for matching notifications
+ QString FULL_VERSION_STR;
- /// The git commit hash of this build
- QString GIT_COMMIT;
+ /// The git commit hash of this build
+ QString GIT_COMMIT;
- /// The git refspec of this build
- QString GIT_REFSPEC;
+ /// The git refspec of this build
+ QString GIT_REFSPEC;
- /// This is printed on start to standard output
- QString VERSION_STR;
+ /// This is printed on start to standard output
+ QString VERSION_STR;
- /**
- * This is used to fetch the news RSS feed.
- * It defaults in CMakeLists.txt to "http://multimc.org/rss.xml"
- */
- QString NEWS_RSS_URL;
+ /**
+ * This is used to fetch the news RSS feed.
+ * It defaults in CMakeLists.txt to "https://multimc.org/rss.xml"
+ */
+ QString NEWS_RSS_URL;
- /**
- * API key you can get from paste.ee when you register an account
- */
- QString PASTE_EE_KEY;
+ /**
+ * API key you can get from paste.ee when you register an account
+ */
+ QString PASTE_EE_KEY;
- /**
- * \brief Converts the Version to a string.
- * \return The version number in string format (major.minor.revision.build).
- */
- QString printableVersionString() const;
+ /**
+ * \brief Converts the Version to a string.
+ * \return The version number in string format (major.minor.revision.build).
+ */
+ QString printableVersionString() const;
};
extern Config BuildConfig;
diff --git a/application/CMakeLists.txt b/application/CMakeLists.txt
index a63167dc..8e73f2d0 100644
--- a/application/CMakeLists.txt
+++ b/application/CMakeLists.txt
@@ -7,286 +7,296 @@ configure_file("${PROJECT_SOURCE_DIR}/BuildConfig.cpp.in" "${PROJECT_BINARY_DIR}
######## Sources and headers ########
SET(MULTIMC_SOURCES
- # Application base
- main.cpp
- MultiMC.h
- MultiMC.cpp
- BuildConfig.h
- ${PROJECT_BINARY_DIR}/BuildConfig.cpp
- UpdateController.cpp
- UpdateController.h
+ # Application base
+ main.cpp
+ MultiMC.h
+ MultiMC.cpp
+ BuildConfig.h
+ ${PROJECT_BINARY_DIR}/BuildConfig.cpp
+ UpdateController.cpp
+ UpdateController.h
- # GUI - general utilities
- GuiUtil.h
- GuiUtil.cpp
- ColumnResizer.h
- ColumnResizer.cpp
- InstanceProxyModel.h
- InstanceProxyModel.cpp
- VersionProxyModel.h
- VersionProxyModel.cpp
- ColorCache.h
- ColorCache.cpp
- HoeDown.h
+ # GUI - general utilities
+ GuiUtil.h
+ GuiUtil.cpp
+ ColumnResizer.h
+ ColumnResizer.cpp
+ InstanceProxyModel.h
+ InstanceProxyModel.cpp
+ VersionProxyModel.h
+ VersionProxyModel.cpp
+ ColorCache.h
+ ColorCache.cpp
+ HoeDown.h
- # Super secret!
- KonamiCode.h
- KonamiCode.cpp
+ # Super secret!
+ KonamiCode.h
+ KonamiCode.cpp
- # GUI - windows
- MainWindow.h
- MainWindow.cpp
- InstanceWindow.h
- InstanceWindow.cpp
+ # GUI - windows
+ MainWindow.h
+ MainWindow.cpp
+ InstanceWindow.h
+ InstanceWindow.cpp
- # GUI - setup wizard
- setupwizard/SetupWizard.h
- setupwizard/SetupWizard.cpp
- setupwizard/AnalyticsWizardPage.cpp
- setupwizard/AnalyticsWizardPage.h
- setupwizard/BaseWizardPage.h
- setupwizard/JavaWizardPage.cpp
- setupwizard/JavaWizardPage.h
- setupwizard/LanguageWizardPage.cpp
- setupwizard/LanguageWizardPage.h
+ # GUI - setup wizard
+ setupwizard/SetupWizard.h
+ setupwizard/SetupWizard.cpp
+ setupwizard/AnalyticsWizardPage.cpp
+ setupwizard/AnalyticsWizardPage.h
+ setupwizard/BaseWizardPage.h
+ setupwizard/JavaWizardPage.cpp
+ setupwizard/JavaWizardPage.h
+ setupwizard/LanguageWizardPage.cpp
+ setupwizard/LanguageWizardPage.h
- # GUI - themes
- themes/FusionTheme.cpp
- themes/FusionTheme.h
- themes/BrightTheme.cpp
- themes/BrightTheme.h
- themes/CustomTheme.cpp
- themes/CustomTheme.h
- themes/DarkTheme.cpp
- themes/DarkTheme.h
- themes/ITheme.cpp
- themes/ITheme.h
- themes/SystemTheme.cpp
- themes/SystemTheme.h
+ # GUI - themes
+ themes/FusionTheme.cpp
+ themes/FusionTheme.h
+ themes/BrightTheme.cpp
+ themes/BrightTheme.h
+ themes/CustomTheme.cpp
+ themes/CustomTheme.h
+ themes/DarkTheme.cpp
+ themes/DarkTheme.h
+ themes/ITheme.cpp
+ themes/ITheme.h
+ themes/SystemTheme.cpp
+ themes/SystemTheme.h
- # GUI - settings-specific wrappers for paged dialog
- SettingsUI.h
+ # Processes
+ LaunchController.h
+ LaunchController.cpp
- # Processes
- LaunchController.h
- LaunchController.cpp
+ # page provider for instances
+ InstancePageProvider.h
- # page provider for instances
- InstancePageProvider.h
+ # Common java checking UI
+ JavaCommon.h
+ JavaCommon.cpp
- # Common java checking UI
- JavaCommon.h
- JavaCommon.cpp
+ # GUI - paged dialog base
+ pages/BasePage.h
+ pages/BasePageContainer.h
+ pages/BasePageProvider.h
- # GUI - paged dialog base
- pages/BasePage.h
- pages/BasePageContainer.h
- pages/BasePageProvider.h
+ # GUI - instance pages
+ pages/instance/GameOptionsPage.cpp
+ pages/instance/GameOptionsPage.h
+ pages/instance/VersionPage.cpp
+ pages/instance/VersionPage.h
+ pages/instance/TexturePackPage.h
+ pages/instance/ResourcePackPage.h
+ pages/instance/ModFolderPage.cpp
+ pages/instance/ModFolderPage.h
+ pages/instance/NotesPage.cpp
+ pages/instance/NotesPage.h
+ pages/instance/LogPage.cpp
+ pages/instance/LogPage.h
+ pages/instance/InstanceSettingsPage.cpp
+ pages/instance/InstanceSettingsPage.h
+ pages/instance/ScreenshotsPage.cpp
+ pages/instance/ScreenshotsPage.h
+ pages/instance/OtherLogsPage.cpp
+ pages/instance/OtherLogsPage.h
+ pages/instance/ServersPage.cpp
+ pages/instance/ServersPage.h
+ pages/instance/LegacyUpgradePage.cpp
+ pages/instance/LegacyUpgradePage.h
+ pages/instance/WorldListPage.cpp
+ pages/instance/WorldListPage.h
- # GUI - instance pages
- pages/instance/VersionPage.cpp
- pages/instance/VersionPage.h
- pages/instance/TexturePackPage.h
- pages/instance/ResourcePackPage.h
- pages/instance/ModFolderPage.cpp
- pages/instance/ModFolderPage.h
- pages/instance/NotesPage.cpp
- pages/instance/NotesPage.h
- pages/instance/LogPage.cpp
- pages/instance/LogPage.h
- pages/instance/InstanceSettingsPage.cpp
- pages/instance/InstanceSettingsPage.h
- pages/instance/ScreenshotsPage.cpp
- pages/instance/ScreenshotsPage.h
- pages/instance/OtherLogsPage.cpp
- pages/instance/OtherLogsPage.h
- pages/instance/LegacyUpgradePage.cpp
- pages/instance/LegacyUpgradePage.h
- pages/instance/WorldListPage.cpp
- pages/instance/WorldListPage.h
+ # GUI - global settings pages
+ pages/global/AccountListPage.cpp
+ pages/global/AccountListPage.h
+ pages/global/CustomCommandsPage.cpp
+ pages/global/CustomCommandsPage.h
+ pages/global/ExternalToolsPage.cpp
+ pages/global/ExternalToolsPage.h
+ pages/global/JavaPage.cpp
+ pages/global/JavaPage.h
+ pages/global/LanguagePage.cpp
+ pages/global/LanguagePage.h
+ pages/global/MinecraftPage.cpp
+ pages/global/MinecraftPage.h
+ pages/global/MultiMCPage.cpp
+ pages/global/MultiMCPage.h
+ pages/global/ProxyPage.cpp
+ pages/global/ProxyPage.h
+ pages/global/PasteEEPage.cpp
+ pages/global/PasteEEPage.h
+ pages/global/PackagesPage.cpp
+ pages/global/PackagesPage.h
- # GUI - global settings pages
- pages/global/AccountListPage.cpp
- pages/global/AccountListPage.h
- pages/global/CustomCommandsPage.cpp
- pages/global/CustomCommandsPage.h
- pages/global/ExternalToolsPage.cpp
- pages/global/ExternalToolsPage.h
- pages/global/JavaPage.cpp
- pages/global/JavaPage.h
- pages/global/MinecraftPage.cpp
- pages/global/MinecraftPage.h
- pages/global/MultiMCPage.cpp
- pages/global/MultiMCPage.h
- pages/global/ProxyPage.cpp
- pages/global/ProxyPage.h
- pages/global/PasteEEPage.cpp
- pages/global/PasteEEPage.h
- pages/global/PackagesPage.cpp
- pages/global/PackagesPage.h
+ # GUI - platform pages
+ pages/modplatform/VanillaPage.cpp
+ pages/modplatform/VanillaPage.h
+ pages/modplatform/FTBPage.cpp
+ pages/modplatform/FTBPage.h
+ pages/modplatform/FtbListModel.h
+ pages/modplatform/FtbListModel.cpp
+ pages/modplatform/TwitchPage.cpp
+ pages/modplatform/TwitchPage.h
+ pages/modplatform/TechnicPage.cpp
+ pages/modplatform/TechnicPage.h
+ pages/modplatform/ImportPage.cpp
+ pages/modplatform/ImportPage.h
- # GUI - platform pages
- pages/modplatform/VanillaPage.cpp
- pages/modplatform/VanillaPage.h
- pages/modplatform/FTBPage.cpp
- pages/modplatform/FTBPage.h
- pages/modplatform/FtbListModel.h
- pages/modplatform/FtbListModel.cpp
- pages/modplatform/TwitchPage.cpp
- pages/modplatform/TwitchPage.h
- pages/modplatform/TechnicPage.cpp
- pages/modplatform/TechnicPage.h
- pages/modplatform/ImportPage.cpp
- pages/modplatform/ImportPage.h
+ # GUI - dialogs
+ dialogs/AboutDialog.cpp
+ dialogs/AboutDialog.h
+ dialogs/ProfileSelectDialog.cpp
+ dialogs/ProfileSelectDialog.h
+ dialogs/CopyInstanceDialog.cpp
+ dialogs/CopyInstanceDialog.h
+ dialogs/CustomMessageBox.cpp
+ dialogs/CustomMessageBox.h
+ dialogs/EditAccountDialog.cpp
+ dialogs/EditAccountDialog.h
+ dialogs/ExportInstanceDialog.cpp
+ dialogs/ExportInstanceDialog.h
+ dialogs/IconPickerDialog.cpp
+ dialogs/IconPickerDialog.h
+ dialogs/LoginDialog.cpp
+ dialogs/LoginDialog.h
+ dialogs/NewComponentDialog.cpp
+ dialogs/NewComponentDialog.h
+ dialogs/NewInstanceDialog.cpp
+ dialogs/NewInstanceDialog.h
+ dialogs/NotificationDialog.cpp
+ dialogs/NotificationDialog.h
+ pagedialog/PageDialog.cpp
+ pagedialog/PageDialog.h
+ dialogs/ProgressDialog.cpp
+ dialogs/ProgressDialog.h
+ dialogs/UpdateDialog.cpp
+ dialogs/UpdateDialog.h
+ dialogs/VersionSelectDialog.cpp
+ dialogs/VersionSelectDialog.h
+ dialogs/SkinUploadDialog.cpp
+ dialogs/SkinUploadDialog.h
- # GUI - dialogs
- dialogs/AboutDialog.cpp
- dialogs/AboutDialog.h
- dialogs/ProfileSelectDialog.cpp
- dialogs/ProfileSelectDialog.h
- dialogs/CopyInstanceDialog.cpp
- dialogs/CopyInstanceDialog.h
- dialogs/CustomMessageBox.cpp
- dialogs/CustomMessageBox.h
- dialogs/EditAccountDialog.cpp
- dialogs/EditAccountDialog.h
- dialogs/ExportInstanceDialog.cpp
- dialogs/ExportInstanceDialog.h
- dialogs/IconPickerDialog.cpp
- dialogs/IconPickerDialog.h
- dialogs/LoginDialog.cpp
- dialogs/LoginDialog.h
- dialogs/ModEditDialogCommon.cpp
- dialogs/ModEditDialogCommon.h
- dialogs/NewComponentDialog.cpp
- dialogs/NewComponentDialog.h
- dialogs/NewInstanceDialog.cpp
- dialogs/NewInstanceDialog.h
- dialogs/NotificationDialog.cpp
- dialogs/NotificationDialog.h
- pagedialog/PageDialog.cpp
- pagedialog/PageDialog.h
- dialogs/ProgressDialog.cpp
- dialogs/ProgressDialog.h
- dialogs/UpdateDialog.cpp
- dialogs/UpdateDialog.h
- dialogs/VersionSelectDialog.cpp
- dialogs/VersionSelectDialog.h
- dialogs/SkinUploadDialog.cpp
- dialogs/SkinUploadDialog.h
+ # GUI - widgets
+ widgets/Common.cpp
+ widgets/Common.h
+ widgets/CustomCommands.cpp
+ widgets/CustomCommands.h
+ widgets/FocusLineEdit.cpp
+ widgets/FocusLineEdit.h
+ widgets/IconLabel.cpp
+ widgets/IconLabel.h
+ widgets/JavaSettingsWidget.cpp
+ widgets/JavaSettingsWidget.h
+ widgets/LabeledToolButton.cpp
+ widgets/LabeledToolButton.h
+ widgets/LanguageSelectionWidget.cpp
+ widgets/LanguageSelectionWidget.h
+ widgets/LineSeparator.cpp
+ widgets/LineSeparator.h
+ widgets/LogView.cpp
+ widgets/LogView.h
+ widgets/MCModInfoFrame.cpp
+ widgets/MCModInfoFrame.h
+ widgets/ModListView.cpp
+ widgets/ModListView.h
+ widgets/PageContainer.cpp
+ widgets/PageContainer.h
+ widgets/PageContainer_p.h
+ widgets/ServerStatus.cpp
+ widgets/ServerStatus.h
+ widgets/VersionListView.cpp
+ widgets/VersionListView.h
+ widgets/VersionSelectWidget.cpp
+ widgets/VersionSelectWidget.h
+ widgets/ProgressWidget.h
+ widgets/ProgressWidget.cpp
+ widgets/WideBar.h
+ widgets/WideBar.cpp
- # GUI - widgets
- widgets/Common.cpp
- widgets/Common.h
- widgets/CustomCommands.cpp
- widgets/CustomCommands.h
- widgets/FocusLineEdit.cpp
- widgets/FocusLineEdit.h
- widgets/IconLabel.cpp
- widgets/IconLabel.h
- widgets/JavaSettingsWidget.cpp
- widgets/JavaSettingsWidget.h
- widgets/LabeledToolButton.cpp
- widgets/LabeledToolButton.h
- widgets/LineSeparator.cpp
- widgets/LineSeparator.h
- widgets/LogView.cpp
- widgets/LogView.h
- widgets/MCModInfoFrame.cpp
- widgets/MCModInfoFrame.h
- widgets/ModListView.cpp
- widgets/ModListView.h
- widgets/PageContainer.cpp
- widgets/PageContainer.h
- widgets/PageContainer_p.h
- widgets/ServerStatus.cpp
- widgets/ServerStatus.h
- widgets/VersionListView.cpp
- widgets/VersionListView.h
- widgets/VersionSelectWidget.cpp
- widgets/VersionSelectWidget.h
- widgets/ProgressWidget.h
- widgets/ProgressWidget.cpp
-
- # GUI - instance group view
- groupview/GroupedProxyModel.cpp
- groupview/GroupedProxyModel.h
- groupview/GroupView.cpp
- groupview/GroupView.h
- groupview/InstanceDelegate.cpp
- groupview/InstanceDelegate.h
- groupview/VisualGroup.cpp
- groupview/VisualGroup.h
- )
+ # GUI - instance group view
+ groupview/GroupedProxyModel.cpp
+ groupview/GroupedProxyModel.h
+ groupview/AccessibleGroupView.cpp
+ groupview/AccessibleGroupView.h
+ groupview/AccessibleGroupView_p.h
+ groupview/GroupView.cpp
+ groupview/GroupView.h
+ groupview/InstanceDelegate.cpp
+ groupview/InstanceDelegate.h
+ groupview/VisualGroup.cpp
+ groupview/VisualGroup.h
+ )
######## UIs ########
SET(MULTIMC_UIS
- # Instance pages
- pages/instance/VersionPage.ui
- pages/instance/ModFolderPage.ui
- pages/instance/LogPage.ui
- pages/instance/InstanceSettingsPage.ui
- pages/instance/NotesPage.ui
- pages/instance/ScreenshotsPage.ui
- pages/instance/OtherLogsPage.ui
- pages/instance/LegacyUpgradePage.ui
- pages/instance/WorldListPage.ui
+ # Instance pages
+ pages/instance/GameOptionsPage.ui
+ pages/instance/VersionPage.ui
+ pages/instance/ModFolderPage.ui
+ pages/instance/LogPage.ui
+ pages/instance/InstanceSettingsPage.ui
+ pages/instance/NotesPage.ui
+ pages/instance/ScreenshotsPage.ui
+ pages/instance/OtherLogsPage.ui
+ pages/instance/LegacyUpgradePage.ui
+ pages/instance/ServersPage.ui
+ pages/instance/WorldListPage.ui
- # Global settings pages
- pages/global/AccountListPage.ui
- pages/global/ExternalToolsPage.ui
- pages/global/JavaPage.ui
- pages/global/MinecraftPage.ui
- pages/global/MultiMCPage.ui
- pages/global/ProxyPage.ui
- pages/global/PasteEEPage.ui
- pages/global/PackagesPage.ui
+ # Global settings pages
+ pages/global/AccountListPage.ui
+ pages/global/ExternalToolsPage.ui
+ pages/global/JavaPage.ui
+ pages/global/MinecraftPage.ui
+ pages/global/MultiMCPage.ui
+ pages/global/ProxyPage.ui
+ pages/global/PasteEEPage.ui
+ pages/global/PackagesPage.ui
- # Platform pages
- pages/modplatform/VanillaPage.ui
- pages/modplatform/FTBPage.ui
- pages/modplatform/TwitchPage.ui
- pages/modplatform/TechnicPage.ui
- pages/modplatform/ImportPage.ui
+ # Platform pages
+ pages/modplatform/VanillaPage.ui
+ pages/modplatform/FTBPage.ui
+ pages/modplatform/TwitchPage.ui
+ pages/modplatform/TechnicPage.ui
+ pages/modplatform/ImportPage.ui
- # Dialogs
- dialogs/CopyInstanceDialog.ui
- dialogs/NewComponentDialog.ui
- dialogs/NewInstanceDialog.ui
- dialogs/AboutDialog.ui
- dialogs/ProgressDialog.ui
- dialogs/IconPickerDialog.ui
- dialogs/ProfileSelectDialog.ui
- dialogs/EditAccountDialog.ui
- dialogs/ExportInstanceDialog.ui
- dialogs/LoginDialog.ui
- dialogs/UpdateDialog.ui
- dialogs/NotificationDialog.ui
- dialogs/SkinUploadDialog.ui
+ # Dialogs
+ dialogs/CopyInstanceDialog.ui
+ dialogs/NewComponentDialog.ui
+ dialogs/NewInstanceDialog.ui
+ dialogs/AboutDialog.ui
+ dialogs/ProgressDialog.ui
+ dialogs/IconPickerDialog.ui
+ dialogs/ProfileSelectDialog.ui
+ dialogs/EditAccountDialog.ui
+ dialogs/ExportInstanceDialog.ui
+ dialogs/LoginDialog.ui
+ dialogs/UpdateDialog.ui
+ dialogs/NotificationDialog.ui
+ dialogs/SkinUploadDialog.ui
- # Widgets/other
- widgets/CustomCommands.ui
- widgets/MCModInfoFrame.ui
+ # Widgets/other
+ widgets/CustomCommands.ui
+ widgets/MCModInfoFrame.ui
)
set(MULTIMC_QRCS
- resources/assets/assets.qrc
- resources/backgrounds/backgrounds.qrc
- resources/multimc/multimc.qrc
- resources/pe_dark/pe_dark.qrc
- resources/pe_light/pe_light.qrc
- resources/pe_colored/pe_colored.qrc
- resources/pe_blue/pe_blue.qrc
- resources/OSX/OSX.qrc
- resources/iOS/iOS.qrc
- resources/flat/flat.qrc
- resources/documents/documents.qrc
+ resources/assets/assets.qrc
+ resources/backgrounds/backgrounds.qrc
+ resources/multimc/multimc.qrc
+ resources/pe_dark/pe_dark.qrc
+ resources/pe_light/pe_light.qrc
+ resources/pe_colored/pe_colored.qrc
+ resources/pe_blue/pe_blue.qrc
+ resources/OSX/OSX.qrc
+ resources/iOS/iOS.qrc
+ resources/flat/flat.qrc
+ resources/documents/documents.qrc
)
######## Windows resource files ########
if(WIN32)
- set(MULTIMC_RCS resources/multimc.rc)
+ set(MULTIMC_RCS resources/multimc.rc)
endif()
# Qt 5 stuff
@@ -298,89 +308,89 @@ add_executable(MultiMC MACOSX_BUNDLE WIN32 ${MULTIMC_SOURCES} ${MULTIMC_UI} ${MU
#target_link_libraries(MultiMC MultiMC_gui ${QUAZIP_LIBRARIES} hoedown MultiMC_rainbow LocalPeer ganalytics)
target_link_libraries(MultiMC MultiMC_gui ${QUAZIP_LIBRARIES} hoedown MultiMC_rainbow LocalPeer)
if(DEFINED MultiMC_APP_BINARY_NAME)
- set_target_properties(MultiMC PROPERTIES OUTPUT_NAME "${MultiMC_APP_BINARY_NAME}")
+ set_target_properties(MultiMC PROPERTIES OUTPUT_NAME "${MultiMC_APP_BINARY_NAME}")
endif()
if(DEFINED MultiMC_BINARY_RPATH)
- SET_TARGET_PROPERTIES(MultiMC PROPERTIES INSTALL_RPATH "${MultiMC_BINARY_RPATH}")
+ SET_TARGET_PROPERTIES(MultiMC PROPERTIES INSTALL_RPATH "${MultiMC_BINARY_RPATH}")
endif()
if(DEFINED MultiMC_APP_BINARY_DEFS)
- target_compile_definitions(MultiMC PRIVATE ${MultiMC_APP_BINARY_DEFS})
+ target_compile_definitions(MultiMC PRIVATE ${MultiMC_APP_BINARY_DEFS})
endif()
install(TARGETS MultiMC
- BUNDLE DESTINATION ${BUNDLE_DEST_DIR} COMPONENT Runtime
- LIBRARY DESTINATION ${LIBRARY_DEST_DIR} COMPONENT Runtime
- RUNTIME DESTINATION ${BINARY_DEST_DIR} COMPONENT Runtime
+ BUNDLE DESTINATION ${BUNDLE_DEST_DIR} COMPONENT Runtime
+ LIBRARY DESTINATION ${LIBRARY_DEST_DIR} COMPONENT Runtime
+ RUNTIME DESTINATION ${BINARY_DEST_DIR} COMPONENT Runtime
)
#### The MultiMC bundle mess! ####
# Bundle utilities are used to complete the portable packages - they add all the libraries that would otherwise be missing on the target system.
# NOTE: it seems that this absolutely has to be here, and nowhere else.
if(INSTALL_BUNDLE STREQUAL "full")
- # Add qt.conf - this makes Qt stop looking for things outside the bundle
- install(
- CODE "file(WRITE \"\${CMAKE_INSTALL_PREFIX}/${RESOURCES_DEST_DIR}/qt.conf\" \" \")"
- COMPONENT Runtime
- )
- # Bundle plugins
- if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
- # Image formats
- install(
- DIRECTORY "${QT_PLUGINS_DIR}/imageformats"
- DESTINATION ${PLUGIN_DEST_DIR}
- COMPONENT Runtime
- REGEX "tga|tiff|mng|webp" EXCLUDE
- )
- # Icon engines
- install(
- DIRECTORY "${QT_PLUGINS_DIR}/iconengines"
- DESTINATION ${PLUGIN_DEST_DIR}
- COMPONENT Runtime
- REGEX "fontawesome" EXCLUDE
- )
- # Platform plugins
- install(
- DIRECTORY "${QT_PLUGINS_DIR}/platforms"
- DESTINATION ${PLUGIN_DEST_DIR}
- COMPONENT Runtime
- REGEX "minimal|linuxfb|offscreen" EXCLUDE
- )
- else()
- # Image formats
- install(
- DIRECTORY "${QT_PLUGINS_DIR}/imageformats"
- DESTINATION ${PLUGIN_DEST_DIR}
- COMPONENT Runtime
- REGEX "tga|tiff|mng|webp" EXCLUDE
- REGEX "d\\." EXCLUDE
- REGEX "_debug\\." EXCLUDE
- REGEX "\\.dSYM" EXCLUDE
- )
- # Icon engines
- install(
- DIRECTORY "${QT_PLUGINS_DIR}/iconengines"
- DESTINATION ${PLUGIN_DEST_DIR}
- COMPONENT Runtime
- REGEX "fontawesome" EXCLUDE
- REGEX "d\\." EXCLUDE
- REGEX "_debug\\." EXCLUDE
- REGEX "\\.dSYM" EXCLUDE
- )
- # Platform plugins
- install(
- DIRECTORY "${QT_PLUGINS_DIR}/platforms"
- DESTINATION ${PLUGIN_DEST_DIR}
- COMPONENT Runtime
- REGEX "minimal|linuxfb|offscreen" EXCLUDE
- REGEX "d\\." EXCLUDE
- REGEX "_debug\\." EXCLUDE
- REGEX "\\.dSYM" EXCLUDE
- )
- endif()
- configure_file(
- "${CMAKE_CURRENT_SOURCE_DIR}/install_prereqs.cmake.in"
- "${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake"
- @ONLY
- )
- install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake" COMPONENT Runtime)
+ # Add qt.conf - this makes Qt stop looking for things outside the bundle
+ install(
+ CODE "file(WRITE \"\${CMAKE_INSTALL_PREFIX}/${RESOURCES_DEST_DIR}/qt.conf\" \" \")"
+ COMPONENT Runtime
+ )
+ # Bundle plugins
+ if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
+ # Image formats
+ install(
+ DIRECTORY "${QT_PLUGINS_DIR}/imageformats"
+ DESTINATION ${PLUGIN_DEST_DIR}
+ COMPONENT Runtime
+ REGEX "tga|tiff|mng|webp" EXCLUDE
+ )
+ # Icon engines
+ install(
+ DIRECTORY "${QT_PLUGINS_DIR}/iconengines"
+ DESTINATION ${PLUGIN_DEST_DIR}
+ COMPONENT Runtime
+ REGEX "fontawesome" EXCLUDE
+ )
+ # Platform plugins
+ install(
+ DIRECTORY "${QT_PLUGINS_DIR}/platforms"
+ DESTINATION ${PLUGIN_DEST_DIR}
+ COMPONENT Runtime
+ REGEX "minimal|linuxfb|offscreen" EXCLUDE
+ )
+ else()
+ # Image formats
+ install(
+ DIRECTORY "${QT_PLUGINS_DIR}/imageformats"
+ DESTINATION ${PLUGIN_DEST_DIR}
+ COMPONENT Runtime
+ REGEX "tga|tiff|mng|webp" EXCLUDE
+ REGEX "d\\." EXCLUDE
+ REGEX "_debug\\." EXCLUDE
+ REGEX "\\.dSYM" EXCLUDE
+ )
+ # Icon engines
+ install(
+ DIRECTORY "${QT_PLUGINS_DIR}/iconengines"
+ DESTINATION ${PLUGIN_DEST_DIR}
+ COMPONENT Runtime
+ REGEX "fontawesome" EXCLUDE
+ REGEX "d\\." EXCLUDE
+ REGEX "_debug\\." EXCLUDE
+ REGEX "\\.dSYM" EXCLUDE
+ )
+ # Platform plugins
+ install(
+ DIRECTORY "${QT_PLUGINS_DIR}/platforms"
+ DESTINATION ${PLUGIN_DEST_DIR}
+ COMPONENT Runtime
+ REGEX "minimal|linuxfb|offscreen" EXCLUDE
+ REGEX "d\\." EXCLUDE
+ REGEX "_debug\\." EXCLUDE
+ REGEX "\\.dSYM" EXCLUDE
+ )
+ endif()
+ configure_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/install_prereqs.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake"
+ @ONLY
+ )
+ install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake" COMPONENT Runtime)
endif()
diff --git a/application/ColorCache.cpp b/application/ColorCache.cpp
index e216b597..ef268dd2 100644
--- a/application/ColorCache.cpp
+++ b/application/ColorCache.cpp
@@ -6,13 +6,13 @@
*/
QColor ColorCache::blend(QColor color)
{
- if (Rainbow::luma(m_front) > Rainbow::luma(m_back))
- {
- // for dark color schemes, produce a fitting color first
- color = Rainbow::tint(m_front, color, 0.5);
- }
- // adapt contrast
- return Rainbow::mix(m_front, color, m_bias);
+ if (Rainbow::luma(m_front) > Rainbow::luma(m_back))
+ {
+ // for dark color schemes, produce a fitting color first
+ color = Rainbow::tint(m_front, color, 0.5);
+ }
+ // adapt contrast
+ return Rainbow::mix(m_front, color, m_bias);
}
/**
@@ -20,16 +20,16 @@ QColor ColorCache::blend(QColor color)
*/
QColor ColorCache::blendBackground(QColor color)
{
- // adapt contrast
- return Rainbow::mix(m_back, color, m_bias);
+ // adapt contrast
+ return Rainbow::mix(m_back, color, m_bias);
}
void ColorCache::recolorAll()
{
- auto iter = m_colors.begin();
- while(iter != m_colors.end())
- {
- iter->front = blend(iter->original);
- iter->back = blendBackground(iter->original);
- }
+ auto iter = m_colors.begin();
+ while(iter != m_colors.end())
+ {
+ iter->front = blend(iter->original);
+ iter->back = blendBackground(iter->original);
+ }
}
diff --git a/application/ColorCache.h b/application/ColorCache.h
index 1ce1c211..6ae633b9 100644
--- a/application/ColorCache.h
+++ b/application/ColorCache.h
@@ -7,113 +7,113 @@
class ColorCache
{
public:
- ColorCache(QColor front, QColor back, qreal bias)
- {
- m_front = front;
- m_back = back;
- m_bias = bias;
- };
+ ColorCache(QColor front, QColor back, qreal bias)
+ {
+ m_front = front;
+ m_back = back;
+ m_bias = bias;
+ };
- void addColor(int key, QColor color)
- {
- m_colors[key] = {color, blend(color), blendBackground(color)};
- }
+ void addColor(int key, QColor color)
+ {
+ m_colors[key] = {color, blend(color), blendBackground(color)};
+ }
- void setForeground(QColor front)
- {
- if(m_front != front)
- {
- m_front = front;
- recolorAll();
- }
- }
+ void setForeground(QColor front)
+ {
+ if(m_front != front)
+ {
+ m_front = front;
+ recolorAll();
+ }
+ }
- void setBackground(QColor back)
- {
- if(m_back != back)
- {
- m_back = back;
- recolorAll();
- }
- }
+ void setBackground(QColor back)
+ {
+ if(m_back != back)
+ {
+ m_back = back;
+ recolorAll();
+ }
+ }
- QColor getFront(int key)
- {
- auto iter = m_colors.find(key);
- if(iter == m_colors.end())
- {
- return QColor();
- }
- return (*iter).front;
- }
+ QColor getFront(int key)
+ {
+ auto iter = m_colors.find(key);
+ if(iter == m_colors.end())
+ {
+ return QColor();
+ }
+ return (*iter).front;
+ }
- QColor getBack(int key)
- {
- auto iter = m_colors.find(key);
- if(iter == m_colors.end())
- {
- return QColor();
- }
- return (*iter).back;
- }
+ QColor getBack(int key)
+ {
+ auto iter = m_colors.find(key);
+ if(iter == m_colors.end())
+ {
+ return QColor();
+ }
+ return (*iter).back;
+ }
- /**
- * Blend the color with the front color, adapting to the back color
- */
- QColor blend(QColor color);
+ /**
+ * Blend the color with the front color, adapting to the back color
+ */
+ QColor blend(QColor color);
- /**
- * Blend the color with the back color
- */
- QColor blendBackground(QColor color);
+ /**
+ * Blend the color with the back color
+ */
+ QColor blendBackground(QColor color);
protected:
- void recolorAll();
+ void recolorAll();
protected:
- struct ColorEntry
- {
- QColor original;
- QColor front;
- QColor back;
- };
+ struct ColorEntry
+ {
+ QColor original;
+ QColor front;
+ QColor back;
+ };
protected:
- qreal m_bias;
- QColor m_front;
- QColor m_back;
- QMap<int, ColorEntry> m_colors;
+ qreal m_bias;
+ QColor m_front;
+ QColor m_back;
+ QMap<int, ColorEntry> m_colors;
};
class LogColorCache : public ColorCache
{
public:
- LogColorCache(QColor front, QColor back)
- : ColorCache(front, back, 1.0)
- {
- addColor((int)MessageLevel::MultiMC, QColor("purple"));
- addColor((int)MessageLevel::Debug, QColor("green"));
- addColor((int)MessageLevel::Warning, QColor("orange"));
- addColor((int)MessageLevel::Error, QColor("red"));
- addColor((int)MessageLevel::Fatal, QColor("red"));
- addColor((int)MessageLevel::Message, front);
- }
+ LogColorCache(QColor front, QColor back)
+ : ColorCache(front, back, 1.0)
+ {
+ addColor((int)MessageLevel::MultiMC, QColor("purple"));
+ addColor((int)MessageLevel::Debug, QColor("green"));
+ addColor((int)MessageLevel::Warning, QColor("orange"));
+ addColor((int)MessageLevel::Error, QColor("red"));
+ addColor((int)MessageLevel::Fatal, QColor("red"));
+ addColor((int)MessageLevel::Message, front);
+ }
- QColor getFront(MessageLevel::Enum level)
- {
- if(!m_colors.contains((int) level))
- {
- return ColorCache::getFront((int)MessageLevel::Message);
- }
- return ColorCache::getFront((int)level);
- }
+ QColor getFront(MessageLevel::Enum level)
+ {
+ if(!m_colors.contains((int) level))
+ {
+ return ColorCache::getFront((int)MessageLevel::Message);
+ }
+ return ColorCache::getFront((int)level);
+ }
- QColor getBack(MessageLevel::Enum level)
- {
- if(level == MessageLevel::Fatal)
- {
- return QColor(Qt::black);
- }
- return QColor(Qt::transparent);
- }
+ QColor getBack(MessageLevel::Enum level)
+ {
+ if(level == MessageLevel::Fatal)
+ {
+ return QColor(Qt::black);
+ }
+ return QColor(Qt::transparent);
+ }
};
diff --git a/application/ColumnResizer.cpp b/application/ColumnResizer.cpp
index ee99bf40..fe415067 100644
--- a/application/ColumnResizer.cpp
+++ b/application/ColumnResizer.cpp
@@ -14,67 +14,67 @@
class FormLayoutWidgetItem : public QWidgetItem
{
public:
- FormLayoutWidgetItem(QWidget* widget, QFormLayout* formLayout, QFormLayout::ItemRole itemRole)
- : QWidgetItem(widget)
- , m_width(-1)
- , m_formLayout(formLayout)
- , m_itemRole(itemRole)
- {}
-
- QSize sizeHint() const
- {
- QSize size = QWidgetItem::sizeHint();
- if (m_width != -1) {
- size.setWidth(m_width);
- }
- return size;
- }
-
- QSize minimumSize() const
- {
- QSize size = QWidgetItem::minimumSize();
- if (m_width != -1) {
- size.setWidth(m_width);
- }
- return size;
- }
-
- QSize maximumSize() const
- {
- QSize size = QWidgetItem::maximumSize();
- if (m_width != -1) {
- size.setWidth(m_width);
- }
- return size;
- }
-
- void setWidth(int width)
- {
- if (width != m_width) {
- m_width = width;
- invalidate();
- }
- }
-
- void setGeometry(const QRect& _rect)
- {
- QRect rect = _rect;
- int width = widget()->sizeHint().width();
- if (m_itemRole == QFormLayout::LabelRole && m_formLayout->labelAlignment() & Qt::AlignRight) {
- rect.setLeft(rect.right() - width);
- }
- QWidgetItem::setGeometry(rect);
- }
-
- QFormLayout* formLayout() const
- {
- return m_formLayout;
- }
+ FormLayoutWidgetItem(QWidget* widget, QFormLayout* formLayout, QFormLayout::ItemRole itemRole)
+ : QWidgetItem(widget)
+ , m_width(-1)
+ , m_formLayout(formLayout)
+ , m_itemRole(itemRole)
+ {}
+
+ QSize sizeHint() const
+ {
+ QSize size = QWidgetItem::sizeHint();
+ if (m_width != -1) {
+ size.setWidth(m_width);
+ }
+ return size;
+ }
+
+ QSize minimumSize() const
+ {
+ QSize size = QWidgetItem::minimumSize();
+ if (m_width != -1) {
+ size.setWidth(m_width);
+ }
+ return size;
+ }
+
+ QSize maximumSize() const
+ {
+ QSize size = QWidgetItem::maximumSize();
+ if (m_width != -1) {
+ size.setWidth(m_width);
+ }
+ return size;
+ }
+
+ void setWidth(int width)
+ {
+ if (width != m_width) {
+ m_width = width;
+ invalidate();
+ }
+ }
+
+ void setGeometry(const QRect& _rect)
+ {
+ QRect rect = _rect;
+ int width = widget()->sizeHint().width();
+ if (m_itemRole == QFormLayout::LabelRole && m_formLayout->labelAlignment() & Qt::AlignRight) {
+ rect.setLeft(rect.right() - width);
+ }
+ QWidgetItem::setGeometry(rect);
+ }
+
+ QFormLayout* formLayout() const
+ {
+ return m_formLayout;
+ }
private:
- int m_width;
- QFormLayout* m_formLayout;
- QFormLayout::ItemRole m_itemRole;
+ int m_width;
+ QFormLayout* m_formLayout;
+ QFormLayout::ItemRole m_itemRole;
};
typedef QPair<QGridLayout*, int> GridColumnInfo;
@@ -82,25 +82,25 @@ typedef QPair<QGridLayout*, int> GridColumnInfo;
class ColumnResizerPrivate
{
public:
- ColumnResizerPrivate(ColumnResizer* q_ptr)
- : q(q_ptr)
- , m_updateTimer(new QTimer(q))
- {
- m_updateTimer->setSingleShot(true);
- m_updateTimer->setInterval(0);
- QObject::connect(m_updateTimer, SIGNAL(timeout()), q, SLOT(updateWidth()));
- }
-
- void scheduleWidthUpdate()
- {
- m_updateTimer->start();
- }
-
- ColumnResizer* q;
- QTimer* m_updateTimer;
- QList<QWidget*> m_widgets;
- QList<FormLayoutWidgetItem*> m_wrWidgetItemList;
- QList<GridColumnInfo> m_gridColumnInfoList;
+ ColumnResizerPrivate(ColumnResizer* q_ptr)
+ : q(q_ptr)
+ , m_updateTimer(new QTimer(q))
+ {
+ m_updateTimer->setSingleShot(true);
+ m_updateTimer->setInterval(0);
+ QObject::connect(m_updateTimer, SIGNAL(timeout()), q, SLOT(updateWidth()));
+ }
+
+ void scheduleWidthUpdate()
+ {
+ m_updateTimer->start();
+ }
+
+ ColumnResizer* q;
+ QTimer* m_updateTimer;
+ QList<QWidget*> m_widgets;
+ QList<FormLayoutWidgetItem*> m_wrWidgetItemList;
+ QList<GridColumnInfo> m_gridColumnInfoList;
};
ColumnResizer::ColumnResizer(QObject* parent)
@@ -110,90 +110,90 @@ ColumnResizer::ColumnResizer(QObject* parent)
ColumnResizer::~ColumnResizer()
{
- delete d;
+ delete d;
}
void ColumnResizer::addWidget(QWidget* widget)
{
- d->m_widgets.append(widget);
- widget->installEventFilter(this);
- d->scheduleWidthUpdate();
+ d->m_widgets.append(widget);
+ widget->installEventFilter(this);
+ d->scheduleWidthUpdate();
}
void ColumnResizer::updateWidth()
{
- int width = 0;
- Q_FOREACH(QWidget* widget, d->m_widgets) {
- width = qMax(widget->sizeHint().width(), width);
- }
- Q_FOREACH(FormLayoutWidgetItem* item, d->m_wrWidgetItemList) {
- item->setWidth(width);
- item->formLayout()->update();
- }
- Q_FOREACH(GridColumnInfo info, d->m_gridColumnInfoList) {
- info.first->setColumnMinimumWidth(info.second, width);
- }
+ int width = 0;
+ Q_FOREACH(QWidget* widget, d->m_widgets) {
+ width = qMax(widget->sizeHint().width(), width);
+ }
+ Q_FOREACH(FormLayoutWidgetItem* item, d->m_wrWidgetItemList) {
+ item->setWidth(width);
+ item->formLayout()->update();
+ }
+ Q_FOREACH(GridColumnInfo info, d->m_gridColumnInfoList) {
+ info.first->setColumnMinimumWidth(info.second, width);
+ }
}
bool ColumnResizer::eventFilter(QObject*, QEvent* event)
{
- if (event->type() == QEvent::Resize) {
- d->scheduleWidthUpdate();
- }
- return false;
+ if (event->type() == QEvent::Resize) {
+ d->scheduleWidthUpdate();
+ }
+ return false;
}
void ColumnResizer::addWidgetsFromLayout(QLayout* layout, int column)
{
- Q_ASSERT(column >= 0);
- QGridLayout* gridLayout = qobject_cast<QGridLayout*>(layout);
- QFormLayout* formLayout = qobject_cast<QFormLayout*>(layout);
- if (gridLayout) {
- addWidgetsFromGridLayout(gridLayout, column);
- } else if (formLayout) {
- if (column > QFormLayout::SpanningRole) {
- qCritical() << "column should not be more than" << QFormLayout::SpanningRole << "for QFormLayout";
- return;
- }
- QFormLayout::ItemRole role = static_cast<QFormLayout::ItemRole>(column);
- addWidgetsFromFormLayout(formLayout, role);
- } else {
- qCritical() << "Don't know how to handle layout" << layout;
- }
+ Q_ASSERT(column >= 0);
+ QGridLayout* gridLayout = qobject_cast<QGridLayout*>(layout);
+ QFormLayout* formLayout = qobject_cast<QFormLayout*>(layout);
+ if (gridLayout) {
+ addWidgetsFromGridLayout(gridLayout, column);
+ } else if (formLayout) {
+ if (column > QFormLayout::SpanningRole) {
+ qCritical() << "column should not be more than" << QFormLayout::SpanningRole << "for QFormLayout";
+ return;
+ }
+ QFormLayout::ItemRole role = static_cast<QFormLayout::ItemRole>(column);
+ addWidgetsFromFormLayout(formLayout, role);
+ } else {
+ qCritical() << "Don't know how to handle layout" << layout;
+ }
}
void ColumnResizer::addWidgetsFromGridLayout(QGridLayout* layout, int column)
{
- for (int row = 0; row < layout->rowCount(); ++row) {
- QLayoutItem* item = layout->itemAtPosition(row, column);
- if (!item) {
- continue;
- }
- QWidget* widget = item->widget();
- if (!widget) {
- continue;
- }
- addWidget(widget);
- }
- d->m_gridColumnInfoList << GridColumnInfo(layout, column);
+ for (int row = 0; row < layout->rowCount(); ++row) {
+ QLayoutItem* item = layout->itemAtPosition(row, column);
+ if (!item) {
+ continue;
+ }
+ QWidget* widget = item->widget();
+ if (!widget) {
+ continue;
+ }
+ addWidget(widget);
+ }
+ d->m_gridColumnInfoList << GridColumnInfo(layout, column);
}
void ColumnResizer::addWidgetsFromFormLayout(QFormLayout* layout, QFormLayout::ItemRole role)
{
- for (int row = 0; row < layout->rowCount(); ++row) {
- QLayoutItem* item = layout->itemAt(row, role);
- if (!item) {
- continue;
- }
- QWidget* widget = item->widget();
- if (!widget) {
- continue;
- }
- layout->removeItem(item);
- delete item;
- FormLayoutWidgetItem* newItem = new FormLayoutWidgetItem(widget, layout, role);
- layout->setItem(row, role, newItem);
- addWidget(widget);
- d->m_wrWidgetItemList << newItem;
- }
+ for (int row = 0; row < layout->rowCount(); ++row) {
+ QLayoutItem* item = layout->itemAt(row, role);
+ if (!item) {
+ continue;
+ }
+ QWidget* widget = item->widget();
+ if (!widget) {
+ continue;
+ }
+ layout->removeItem(item);
+ delete item;
+ FormLayoutWidgetItem* newItem = new FormLayoutWidgetItem(widget, layout, role);
+ layout->setItem(row, role, newItem);
+ addWidget(widget);
+ d->m_wrWidgetItemList << newItem;
+ }
}
diff --git a/application/ColumnResizer.h b/application/ColumnResizer.h
index 78966a7e..8c920f01 100644
--- a/application/ColumnResizer.h
+++ b/application/ColumnResizer.h
@@ -18,24 +18,24 @@ class QWidget;
class ColumnResizerPrivate;
class ColumnResizer : public QObject
{
- Q_OBJECT
+ Q_OBJECT
public:
- ColumnResizer(QObject* parent = 0);
- ~ColumnResizer();
+ ColumnResizer(QObject* parent = 0);
+ ~ColumnResizer();
- void addWidget(QWidget* widget);
- void addWidgetsFromLayout(QLayout*, int column);
- void addWidgetsFromGridLayout(QGridLayout*, int column);
- void addWidgetsFromFormLayout(QFormLayout*, QFormLayout::ItemRole role);
+ void addWidget(QWidget* widget);
+ void addWidgetsFromLayout(QLayout*, int column);
+ void addWidgetsFromGridLayout(QGridLayout*, int column);
+ void addWidgetsFromFormLayout(QFormLayout*, QFormLayout::ItemRole role);
private Q_SLOTS:
- void updateWidth();
+ void updateWidth();
protected:
- bool eventFilter(QObject*, QEvent* event);
+ bool eventFilter(QObject*, QEvent* event);
private:
- ColumnResizerPrivate* const d;
+ ColumnResizerPrivate* const d;
};
#endif /* COLUMNRESIZER_H */
diff --git a/application/GuiUtil.cpp b/application/GuiUtil.cpp
index b05fc57c..302206f5 100644
--- a/application/GuiUtil.cpp
+++ b/application/GuiUtil.cpp
@@ -15,117 +15,117 @@
QString GuiUtil::uploadPaste(const QString &text, QWidget *parentWidget)
{
- ProgressDialog dialog(parentWidget);
- auto APIKeySetting = MMC->settings()->get("PasteEEAPIKey").toString();
- if(APIKeySetting == "multimc")
- {
- APIKeySetting = BuildConfig.PASTE_EE_KEY;
- }
- std::unique_ptr<PasteUpload> paste(new PasteUpload(parentWidget, text, APIKeySetting));
-
- if (!paste->validateText())
- {
- CustomMessageBox::selectable(
- parentWidget, QObject::tr("Upload failed"),
- QObject::tr("The log file is too big. You'll have to upload it manually."),
- QMessageBox::Warning)->exec();
- return QString();
- }
-
- dialog.execWithTask(paste.get());
- if (!paste->wasSuccessful())
- {
- CustomMessageBox::selectable(parentWidget, QObject::tr("Upload failed"),
- paste->failReason(), QMessageBox::Critical)->exec();
- return QString();
- }
- else
- {
- const QString link = paste->pasteLink();
- setClipboardText(link);
- CustomMessageBox::selectable(
- parentWidget, QObject::tr("Upload finished"),
- QObject::tr("The <a href=\"%1\">link to the uploaded log</a> has been placed in your clipboard.").arg(link),
- QMessageBox::Information)->exec();
- return link;
- }
+ ProgressDialog dialog(parentWidget);
+ auto APIKeySetting = MMC->settings()->get("PasteEEAPIKey").toString();
+ if(APIKeySetting == "multimc")
+ {
+ APIKeySetting = BuildConfig.PASTE_EE_KEY;
+ }
+ std::unique_ptr<PasteUpload> paste(new PasteUpload(parentWidget, text, APIKeySetting));
+
+ if (!paste->validateText())
+ {
+ CustomMessageBox::selectable(
+ parentWidget, QObject::tr("Upload failed"),
+ QObject::tr("The log file is too big. You'll have to upload it manually."),
+ QMessageBox::Warning)->exec();
+ return QString();
+ }
+
+ dialog.execWithTask(paste.get());
+ if (!paste->wasSuccessful())
+ {
+ CustomMessageBox::selectable(parentWidget, QObject::tr("Upload failed"),
+ paste->failReason(), QMessageBox::Critical)->exec();
+ return QString();
+ }
+ else
+ {
+ const QString link = paste->pasteLink();
+ setClipboardText(link);
+ CustomMessageBox::selectable(
+ parentWidget, QObject::tr("Upload finished"),
+ QObject::tr("The <a href=\"%1\">link to the uploaded log</a> has been placed in your clipboard.").arg(link),
+ QMessageBox::Information)->exec();
+ return link;
+ }
}
void GuiUtil::setClipboardText(const QString &text)
{
- QApplication::clipboard()->setText(text);
+ QApplication::clipboard()->setText(text);
}
static QStringList BrowseForFileInternal(QString context, QString caption, QString filter, QString defaultPath, QWidget *parentWidget, bool single)
{
- static QMap<QString, QString> savedPaths;
-
- QFileDialog w(parentWidget, caption);
- QSet<QString> locations;
- 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(defaultPath));
-
- w.setFileMode(single ? QFileDialog::ExistingFile : QFileDialog::ExistingFiles);
- w.setAcceptMode(QFileDialog::AcceptOpen);
- w.setNameFilter(filter);
-
- QString pathToOpen;
- if(savedPaths.contains(context))
- {
- pathToOpen = savedPaths[context];
- }
- else
- {
- pathToOpen = defaultPath;
- }
- if(!pathToOpen.isEmpty())
- {
- QFileInfo finfo(pathToOpen);
- if(finfo.exists() && finfo.isDir())
- {
- w.setDirectory(finfo.absoluteFilePath());
- }
- }
-
- w.setSidebarUrls(urls);
-
- if (w.exec())
- {
- savedPaths[context] = w.directory().absolutePath();
- return w.selectedFiles();
- }
- savedPaths[context] = w.directory().absolutePath();
- return {};
+ static QMap<QString, QString> savedPaths;
+
+ QFileDialog w(parentWidget, caption);
+ QSet<QString> locations;
+ 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(defaultPath));
+
+ w.setFileMode(single ? QFileDialog::ExistingFile : QFileDialog::ExistingFiles);
+ w.setAcceptMode(QFileDialog::AcceptOpen);
+ w.setNameFilter(filter);
+
+ QString pathToOpen;
+ if(savedPaths.contains(context))
+ {
+ pathToOpen = savedPaths[context];
+ }
+ else
+ {
+ pathToOpen = defaultPath;
+ }
+ if(!pathToOpen.isEmpty())
+ {
+ QFileInfo finfo(pathToOpen);
+ if(finfo.exists() && finfo.isDir())
+ {
+ w.setDirectory(finfo.absoluteFilePath());
+ }
+ }
+
+ w.setSidebarUrls(urls);
+
+ if (w.exec())
+ {
+ savedPaths[context] = w.directory().absolutePath();
+ return w.selectedFiles();
+ }
+ savedPaths[context] = w.directory().absolutePath();
+ return {};
}
QString GuiUtil::BrowseForFile(QString context, QString caption, QString filter, QString defaultPath, QWidget *parentWidget)
{
- auto resultList = BrowseForFileInternal(context, caption, filter, defaultPath, parentWidget, true);
- if(resultList.size())
- {
- return resultList[0];
- }
- return QString();
+ auto resultList = BrowseForFileInternal(context, caption, filter, defaultPath, parentWidget, true);
+ if(resultList.size())
+ {
+ return resultList[0];
+ }
+ return QString();
}
QStringList GuiUtil::BrowseForFiles(QString context, QString caption, QString filter, QString defaultPath, QWidget *parentWidget)
{
- return BrowseForFileInternal(context, caption, filter, defaultPath, parentWidget, false);
+ return BrowseForFileInternal(context, caption, filter, defaultPath, parentWidget, false);
}
diff --git a/application/HoeDown.h b/application/HoeDown.h
index 18c315c6..c94a312f 100644
--- a/application/HoeDown.h
+++ b/application/HoeDown.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,52 +25,52 @@
class HoeDown
{
public:
- class buffer
- {
- public:
- buffer(size_t unit = 4096)
- {
- buf = hoedown_buffer_new(unit);
- }
- ~buffer()
- {
- hoedown_buffer_free(buf);
- }
- const char * cstr()
- {
- return hoedown_buffer_cstr(buf);
- }
- void put(QByteArray input)
- {
- hoedown_buffer_put(buf, (uint8_t *) input.data(), input.size());
- }
- const uint8_t * data() const
- {
- return buf->data;
- }
- size_t size() const
- {
- return buf->size;
- }
- hoedown_buffer * buf;
- } ib, ob;
- HoeDown()
- {
- renderer = hoedown_html_renderer_new((hoedown_html_flags) 0,0);
- document = hoedown_document_new(renderer, (hoedown_extensions) 0, 8);
- }
- ~HoeDown()
- {
- hoedown_document_free(document);
- hoedown_html_renderer_free(renderer);
- }
- QString process(QByteArray input)
- {
- ib.put(input);
- hoedown_document_render(document, ob.buf, ib.data(), ib.size());
- return ob.cstr();
- }
+ class buffer
+ {
+ public:
+ buffer(size_t unit = 4096)
+ {
+ buf = hoedown_buffer_new(unit);
+ }
+ ~buffer()
+ {
+ hoedown_buffer_free(buf);
+ }
+ const char * cstr()
+ {
+ return hoedown_buffer_cstr(buf);
+ }
+ void put(QByteArray input)
+ {
+ hoedown_buffer_put(buf, (uint8_t *) input.data(), input.size());
+ }
+ const uint8_t * data() const
+ {
+ return buf->data;
+ }
+ size_t size() const
+ {
+ return buf->size;
+ }
+ hoedown_buffer * buf;
+ } ib, ob;
+ HoeDown()
+ {
+ renderer = hoedown_html_renderer_new((hoedown_html_flags) 0,0);
+ document = hoedown_document_new(renderer, (hoedown_extensions) 0, 8);
+ }
+ ~HoeDown()
+ {
+ hoedown_document_free(document);
+ hoedown_html_renderer_free(renderer);
+ }
+ QString process(QByteArray input)
+ {
+ ib.put(input);
+ hoedown_document_render(document, ob.buf, ib.data(), ib.size());
+ return ob.cstr();
+ }
private:
- hoedown_document * document;
- hoedown_renderer * renderer;
+ hoedown_document * document;
+ hoedown_renderer * renderer;
};
diff --git a/application/InstancePageProvider.h b/application/InstancePageProvider.h
index 9dda7859..dde36aef 100644
--- a/application/InstancePageProvider.h
+++ b/application/InstancePageProvider.h
@@ -15,57 +15,62 @@
#include "pages/instance/OtherLogsPage.h"
#include "pages/instance/LegacyUpgradePage.h"
#include "pages/instance/WorldListPage.h"
+#include "pages/instance/ServersPage.h"
+#include "pages/instance/GameOptionsPage.h"
+#include "Env.h"
class InstancePageProvider : public QObject, public BasePageProvider
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit InstancePageProvider(InstancePtr parent)
- {
- inst = parent;
- }
+ explicit InstancePageProvider(InstancePtr parent)
+ {
+ inst = parent;
+ }
- virtual ~InstancePageProvider() {};
- virtual QList<BasePage *> getPages() override
- {
- QList<BasePage *> values;
- values.append(new LogPage(inst));
- std::shared_ptr<MinecraftInstance> onesix = std::dynamic_pointer_cast<MinecraftInstance>(inst);
- if(onesix)
- {
- values.append(new VersionPage(onesix.get()));
- auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList(), "mods", "loadermods", tr("Loader mods"), "Loader-mods");
- modsPage->setFilter("%1 (*.zip *.jar *.litemod)");
- values.append(modsPage);
- values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList(), "coremods", "coremods", tr("Core mods"), "Core-mods"));
- values.append(new ResourcePackPage(onesix.get()));
- values.append(new TexturePackPage(onesix.get()));
- values.append(new NotesPage(onesix.get()));
- values.append(new WorldListPage(onesix.get(), onesix->worldList(), "worlds", "worlds", tr("Worlds"), "Worlds"));
- values.append(new ScreenshotsPage(FS::PathCombine(onesix->minecraftRoot(), "screenshots")));
- values.append(new InstanceSettingsPage(onesix.get()));
- }
- std::shared_ptr<LegacyInstance> legacy = std::dynamic_pointer_cast<LegacyInstance>(inst);
- if(legacy)
- {
- values.append(new LegacyUpgradePage(legacy));
- values.append(new NotesPage(legacy.get()));
- values.append(new WorldListPage(legacy.get(), legacy->worldList(), "worlds", "worlds", tr("Worlds"), "Worlds"));
- values.append(new ScreenshotsPage(FS::PathCombine(legacy->minecraftRoot(), "screenshots")));
- }
- auto logMatcher = inst->getLogFileMatcher();
- if(logMatcher)
- {
- values.append(new OtherLogsPage(inst->getLogFileRoot(), logMatcher));
- }
- return values;
- }
+ virtual ~InstancePageProvider() {};
+ virtual QList<BasePage *> getPages() override
+ {
+ QList<BasePage *> values;
+ values.append(new LogPage(inst));
+ std::shared_ptr<MinecraftInstance> onesix = std::dynamic_pointer_cast<MinecraftInstance>(inst);
+ if(onesix)
+ {
+ values.append(new VersionPage(onesix.get()));
+ auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList(), "mods", "loadermods", tr("Loader mods"), "Loader-mods");
+ modsPage->setFilter("%1 (*.zip *.jar *.litemod)");
+ values.append(modsPage);
+ values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList(), "coremods", "coremods", tr("Core mods"), "Core-mods"));
+ values.append(new ResourcePackPage(onesix.get()));
+ values.append(new TexturePackPage(onesix.get()));
+ values.append(new NotesPage(onesix.get()));
+ values.append(new WorldListPage(onesix.get(), onesix->worldList()));
+ values.append(new ServersPage(onesix.get()));
+ // values.append(new GameOptionsPage(onesix.get()));
+ values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots")));
+ values.append(new InstanceSettingsPage(onesix.get()));
+ }
+ std::shared_ptr<LegacyInstance> legacy = std::dynamic_pointer_cast<LegacyInstance>(inst);
+ if(legacy)
+ {
+ values.append(new LegacyUpgradePage(legacy));
+ values.append(new NotesPage(legacy.get()));
+ values.append(new WorldListPage(legacy.get(), legacy->worldList()));
+ values.append(new ScreenshotsPage(FS::PathCombine(legacy->gameRoot(), "screenshots")));
+ }
+ auto logMatcher = inst->getLogFileMatcher();
+ if(logMatcher)
+ {
+ values.append(new OtherLogsPage(inst->getLogFileRoot(), logMatcher));
+ }
+ return values;
+ }
- virtual QString dialogTitle() override
- {
- return tr("Edit Instance (%1)").arg(inst->name());
- }
+ virtual QString dialogTitle() override
+ {
+ return tr("Edit Instance (%1)").arg(inst->name());
+ }
protected:
- InstancePtr inst;
+ InstancePtr inst;
};
diff --git a/application/InstanceProxyModel.cpp b/application/InstanceProxyModel.cpp
index d0e9e10d..5317f60c 100644
--- a/application/InstanceProxyModel.cpp
+++ b/application/InstanceProxyModel.cpp
@@ -9,26 +9,26 @@ InstanceProxyModel::InstanceProxyModel(QObject *parent) : GroupedProxyModel(pare
QVariant InstanceProxyModel::data(const QModelIndex & index, int role) const
{
- QVariant data = QSortFilterProxyModel::data(index, role);
- if(role == Qt::DecorationRole)
- {
- return QVariant(MMC->icons()->getIcon(data.toString()));
- }
- return data;
+ QVariant data = QSortFilterProxyModel::data(index, role);
+ if(role == Qt::DecorationRole)
+ {
+ return QVariant(MMC->icons()->getIcon(data.toString()));
+ }
+ return data;
}
bool InstanceProxyModel::subSortLessThan(const QModelIndex &left,
- const QModelIndex &right) const
+ const QModelIndex &right) const
{
- BaseInstance *pdataLeft = static_cast<BaseInstance *>(left.internalPointer());
- BaseInstance *pdataRight = static_cast<BaseInstance *>(right.internalPointer());
- QString sortMode = MMC->settings()->get("InstSortMode").toString();
- if (sortMode == "LastLaunch")
- {
- return pdataLeft->lastLaunch() > pdataRight->lastLaunch();
- }
- else
- {
- return QString::localeAwareCompare(pdataLeft->name(), pdataRight->name()) < 0;
- }
+ BaseInstance *pdataLeft = static_cast<BaseInstance *>(left.internalPointer());
+ BaseInstance *pdataRight = static_cast<BaseInstance *>(right.internalPointer());
+ QString sortMode = MMC->settings()->get("InstSortMode").toString();
+ if (sortMode == "LastLaunch")
+ {
+ return pdataLeft->lastLaunch() > pdataRight->lastLaunch();
+ }
+ else
+ {
+ return QString::localeAwareCompare(pdataLeft->name(), pdataRight->name()) < 0;
+ }
}
diff --git a/application/InstanceProxyModel.h b/application/InstanceProxyModel.h
index c063f526..fab6f834 100644
--- a/application/InstanceProxyModel.h
+++ b/application/InstanceProxyModel.h
@@ -8,9 +8,9 @@
class InstanceProxyModel : public GroupedProxyModel
{
public:
- explicit InstanceProxyModel(QObject *parent = 0);
- QVariant data(const QModelIndex & index, int role) const override;
+ explicit InstanceProxyModel(QObject *parent = 0);
+ QVariant data(const QModelIndex & index, int role) const override;
protected:
- virtual bool subSortLessThan(const QModelIndex &left, const QModelIndex &right) const override;
+ virtual bool subSortLessThan(const QModelIndex &left, const QModelIndex &right) const override;
};
diff --git a/application/InstanceWindow.cpp b/application/InstanceWindow.cpp
index 5895ca3a..02c1bb23 100644
--- a/application/InstanceWindow.cpp
+++ b/application/InstanceWindow.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,184 +31,188 @@
#include "icons/IconList.h"
InstanceWindow::InstanceWindow(InstancePtr instance, QWidget *parent)
- : QMainWindow(parent), m_instance(instance)
+ : QMainWindow(parent), m_instance(instance)
{
- setAttribute(Qt::WA_DeleteOnClose);
-
- auto icon = MMC->icons()->getIcon(m_instance->iconKey());
- QString windowTitle = tr("Console window for ") + m_instance->name();
-
- // Set window properties
- {
- setWindowIcon(icon);
- setWindowTitle(windowTitle);
- }
-
- // Add page container
- {
- auto provider = std::make_shared<InstancePageProvider>(m_instance);
- m_container = new PageContainer(provider.get(), "console", this);
- m_container->setParentContainer(this);
- 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();
- horizontalLayout->addWidget(m_killButton);
- connect(m_killButton, SIGNAL(clicked(bool)), SLOT(on_btnKillMinecraft_clicked()));
-
- m_launchOfflineButton = new QPushButton();
- horizontalLayout->addWidget(m_launchOfflineButton);
- m_launchOfflineButton->setText(tr("Launch Offline"));
- updateLaunchButtons();
- connect(m_launchOfflineButton, SIGNAL(clicked(bool)), SLOT(on_btnLaunchMinecraftOffline_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 instance and launch process recognition
- {
- auto launchTask = m_instance->getLaunchTask();
- on_InstanceLaunchTask_changed(launchTask);
- connect(m_instance.get(), &BaseInstance::launchTaskChanged, this, &InstanceWindow::on_InstanceLaunchTask_changed);
- connect(m_instance.get(), &BaseInstance::runningStatusChanged, this, &InstanceWindow::on_RunningState_changed);
- }
-
- // set up instance destruction detection
- {
- connect(m_instance.get(), &BaseInstance::statusChanged, this, &InstanceWindow::on_instanceStatusChanged);
- }
- show();
+ setAttribute(Qt::WA_DeleteOnClose);
+
+ auto icon = MMC->icons()->getIcon(m_instance->iconKey());
+ QString windowTitle = tr("Console window for ") + m_instance->name();
+
+ // Set window properties
+ {
+ setWindowIcon(icon);
+ setWindowTitle(windowTitle);
+ }
+
+ // Add page container
+ {
+ auto provider = std::make_shared<InstancePageProvider>(m_instance);
+ m_container = new PageContainer(provider.get(), "console", this);
+ m_container->setParentContainer(this);
+ setCentralWidget(m_container);
+ setContentsMargins(0, 0, 0, 0);
+ }
+
+ // 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();
+ horizontalLayout->addWidget(m_killButton);
+ connect(m_killButton, SIGNAL(clicked(bool)), SLOT(on_btnKillMinecraft_clicked()));
+
+ m_launchOfflineButton = new QPushButton();
+ horizontalLayout->addWidget(m_launchOfflineButton);
+ m_launchOfflineButton->setText(tr("Launch Offline"));
+ updateLaunchButtons();
+ connect(m_launchOfflineButton, SIGNAL(clicked(bool)), SLOT(on_btnLaunchMinecraftOffline_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 instance and launch process recognition
+ {
+ auto launchTask = m_instance->getLaunchTask();
+ on_InstanceLaunchTask_changed(launchTask);
+ connect(m_instance.get(), &BaseInstance::launchTaskChanged, this, &InstanceWindow::on_InstanceLaunchTask_changed);
+ connect(m_instance.get(), &BaseInstance::runningStatusChanged, this, &InstanceWindow::on_RunningState_changed);
+ }
+
+ // set up instance destruction detection
+ {
+ connect(m_instance.get(), &BaseInstance::statusChanged, this, &InstanceWindow::on_instanceStatusChanged);
+ }
+ show();
}
void InstanceWindow::on_instanceStatusChanged(BaseInstance::Status, BaseInstance::Status newStatus)
{
- if(newStatus == BaseInstance::Status::Gone)
- {
- m_doNotSave = true;
- close();
- }
+ if(newStatus == BaseInstance::Status::Gone)
+ {
+ m_doNotSave = true;
+ close();
+ }
}
void InstanceWindow::updateLaunchButtons()
{
- if(m_instance->isRunning())
- {
- m_launchOfflineButton->setEnabled(false);
- m_killButton->setText(tr("Kill"));
- m_killButton->setToolTip(tr("Kill the running instance"));
- }
- else if(!m_instance->canLaunch())
- {
- m_launchOfflineButton->setEnabled(false);
- m_killButton->setText(tr("Launch"));
- m_killButton->setToolTip(tr("Launch the instance"));
- m_killButton->setEnabled(false);
- }
- else
- {
- m_launchOfflineButton->setEnabled(true);
- m_killButton->setText(tr("Launch"));
- m_killButton->setToolTip(tr("Launch the instance"));
- }
+ if(m_instance->isRunning())
+ {
+ m_launchOfflineButton->setEnabled(false);
+ m_killButton->setText(tr("Kill"));
+ m_killButton->setToolTip(tr("Kill the running instance"));
+ }
+ else if(!m_instance->canLaunch())
+ {
+ m_launchOfflineButton->setEnabled(false);
+ m_killButton->setText(tr("Launch"));
+ m_killButton->setToolTip(tr("Launch the instance"));
+ m_killButton->setEnabled(false);
+ }
+ else
+ {
+ m_launchOfflineButton->setEnabled(true);
+ m_killButton->setText(tr("Launch"));
+ m_killButton->setToolTip(tr("Launch the instance"));
+ }
}
void InstanceWindow::on_btnLaunchMinecraftOffline_clicked()
{
- MMC->launch(m_instance, false, nullptr);
+ MMC->launch(m_instance, false, nullptr);
}
-void InstanceWindow::on_InstanceLaunchTask_changed(std::shared_ptr<LaunchTask> proc)
+void InstanceWindow::on_InstanceLaunchTask_changed(shared_qobject_ptr<LaunchTask> proc)
{
- m_proc = proc;
+ m_proc = proc;
}
-void InstanceWindow::on_RunningState_changed(bool)
+void InstanceWindow::on_RunningState_changed(bool running)
{
- updateLaunchButtons();
- m_container->refreshContainer();
+ updateLaunchButtons();
+ m_container->refreshContainer();
+ if(running) {
+ selectPage("log");
+ }
}
void InstanceWindow::on_closeButton_clicked()
{
- close();
+ close();
}
void InstanceWindow::closeEvent(QCloseEvent *event)
{
- bool proceed = true;
- if(!m_doNotSave)
- {
- proceed &= m_container->prepareToClose();
- }
-
- if(!proceed)
- {
- return;
- }
-
- MMC->settings()->set("ConsoleWindowState", saveState().toBase64());
- MMC->settings()->set("ConsoleWindowGeometry", saveGeometry().toBase64());
- emit isClosing();
- event->accept();
+ bool proceed = true;
+ if(!m_doNotSave)
+ {
+ proceed &= m_container->prepareToClose();
+ }
+
+ if(!proceed)
+ {
+ return;
+ }
+
+ MMC->settings()->set("ConsoleWindowState", saveState().toBase64());
+ MMC->settings()->set("ConsoleWindowGeometry", saveGeometry().toBase64());
+ emit isClosing();
+ event->accept();
}
bool InstanceWindow::saveAll()
{
- return m_container->prepareToClose();
+ return m_container->saveAll();
}
void InstanceWindow::on_btnKillMinecraft_clicked()
{
- if(m_instance->isRunning())
- {
- MMC->kill(m_instance);
- }
- else
- {
- MMC->launch(m_instance, true, nullptr);
- }
+ if(m_instance->isRunning())
+ {
+ MMC->kill(m_instance);
+ }
+ else
+ {
+ MMC->launch(m_instance, true, nullptr);
+ }
}
QString InstanceWindow::instanceId()
{
- return m_instance->id();
+ return m_instance->id();
}
bool InstanceWindow::selectPage(QString pageId)
{
- return m_container->selectPage(pageId);
+ return m_container->selectPage(pageId);
}
void InstanceWindow::refreshContainer()
{
- m_container->refreshContainer();
+ m_container->refreshContainer();
}
InstanceWindow::~InstanceWindow()
@@ -217,10 +221,10 @@ InstanceWindow::~InstanceWindow()
bool InstanceWindow::requestClose()
{
- if(m_container->prepareToClose())
- {
- close();
- return true;
- }
- return false;
+ if(m_container->prepareToClose())
+ {
+ close();
+ return true;
+ }
+ return false;
}
diff --git a/application/InstanceWindow.h b/application/InstanceWindow.h
index 2b08644e..e5bd4464 100644
--- a/application/InstanceWindow.h
+++ b/application/InstanceWindow.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,48 +26,48 @@ class QPushButton;
class PageContainer;
class InstanceWindow : public QMainWindow, public BasePageContainer
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit InstanceWindow(InstancePtr proc, QWidget *parent = 0);
- virtual ~InstanceWindow();
+ explicit InstanceWindow(InstancePtr proc, QWidget *parent = 0);
+ virtual ~InstanceWindow();
- bool selectPage(QString pageId) override;
- void refreshContainer() override;
+ bool selectPage(QString pageId) override;
+ void refreshContainer() override;
- QString instanceId();
+ QString instanceId();
- // save all settings and changes (prepare for launch)
- bool saveAll();
+ // save all settings and changes (prepare for launch)
+ bool saveAll();
- // request closing the window (from a page)
- bool requestClose() override;
+ // request closing the window (from a page)
+ bool requestClose() override;
signals:
- void isClosing();
+ void isClosing();
private
slots:
- void on_closeButton_clicked();
- void on_btnKillMinecraft_clicked();
- void on_btnLaunchMinecraftOffline_clicked();
+ void on_closeButton_clicked();
+ void on_btnKillMinecraft_clicked();
+ void on_btnLaunchMinecraftOffline_clicked();
- void on_InstanceLaunchTask_changed(std::shared_ptr<LaunchTask> proc);
- void on_RunningState_changed(bool running);
- void on_instanceStatusChanged(BaseInstance::Status, BaseInstance::Status newStatus);
+ void on_InstanceLaunchTask_changed(shared_qobject_ptr<LaunchTask> proc);
+ void on_RunningState_changed(bool running);
+ void on_instanceStatusChanged(BaseInstance::Status, BaseInstance::Status newStatus);
protected:
- void closeEvent(QCloseEvent *) override;
+ void closeEvent(QCloseEvent *) override;
private:
- void updateLaunchButtons();
+ void updateLaunchButtons();
private:
- std::shared_ptr<LaunchTask> m_proc;
- InstancePtr m_instance;
- bool m_doNotSave = false;
- PageContainer *m_container = nullptr;
- QPushButton *m_closeButton = nullptr;
- QPushButton *m_killButton = nullptr;
- QPushButton *m_launchOfflineButton = nullptr;
+ shared_qobject_ptr<LaunchTask> m_proc;
+ InstancePtr m_instance;
+ bool m_doNotSave = false;
+ PageContainer *m_container = nullptr;
+ QPushButton *m_closeButton = nullptr;
+ QPushButton *m_killButton = nullptr;
+ QPushButton *m_launchOfflineButton = nullptr;
};
diff --git a/application/JavaCommon.cpp b/application/JavaCommon.cpp
index 0008fc04..563dfb35 100644
--- a/application/JavaCommon.cpp
+++ b/application/JavaCommon.cpp
@@ -4,100 +4,100 @@
bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget *parent)
{
- if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(QRegExp("-Xm[sx]"))
- || jvmargs.contains("-XX-MaxHeapSize") || jvmargs.contains("-XX:InitialHeapSize"))
- {
- auto warnStr = QObject::tr(
- "You tried to manually set a JVM memory option (using \"-XX:PermSize\", \"-XX-MaxHeapSize\", \"-XX:InitialHeapSize\", \"-Xmx\" or \"-Xms\").\n"
- "There are dedicated boxes for these in the settings (Java tab, in the Memory group at the top).\n"
- "This message will be displayed until you remove them from the JVM arguments.");
- CustomMessageBox::selectable(
- parent, QObject::tr("JVM arguments warning"),
- warnStr,
- QMessageBox::Warning)->exec();
- return false;
- }
- return true;
+ if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(QRegExp("-Xm[sx]"))
+ || jvmargs.contains("-XX-MaxHeapSize") || jvmargs.contains("-XX:InitialHeapSize"))
+ {
+ auto warnStr = QObject::tr(
+ "You tried to manually set a JVM memory option (using \"-XX:PermSize\", \"-XX-MaxHeapSize\", \"-XX:InitialHeapSize\", \"-Xmx\" or \"-Xms\").\n"
+ "There are dedicated boxes for these in the settings (Java tab, in the Memory group at the top).\n"
+ "This message will be displayed until you remove them from the JVM arguments.");
+ CustomMessageBox::selectable(
+ parent, QObject::tr("JVM arguments warning"),
+ warnStr,
+ QMessageBox::Warning)->exec();
+ return false;
+ }
+ return true;
}
void JavaCommon::javaWasOk(QWidget *parent, JavaCheckResult result)
{
- QString text;
- text += QObject::tr("Java test succeeded!<br />Platform reported: %1<br />Java version "
- "reported: %2<br />").arg(result.realPlatform, result.javaVersion.toString());
- if (result.errorLog.size())
- {
- auto htmlError = result.errorLog;
- htmlError.replace('\n', "<br />");
- text += QObject::tr("<br />Warnings:<br /><font color=\"orange\">%1</font>").arg(htmlError);
- }
- CustomMessageBox::selectable(parent, QObject::tr("Java test success"), text, QMessageBox::Information)->show();
+ QString text;
+ text += QObject::tr("Java test succeeded!<br />Platform reported: %1<br />Java version "
+ "reported: %2<br />").arg(result.realPlatform, result.javaVersion.toString());
+ if (result.errorLog.size())
+ {
+ auto htmlError = result.errorLog;
+ htmlError.replace('\n', "<br />");
+ text += QObject::tr("<br />Warnings:<br /><font color=\"orange\">%1</font>").arg(htmlError);
+ }
+ CustomMessageBox::selectable(parent, QObject::tr("Java test success"), text, QMessageBox::Information)->show();
}
void JavaCommon::javaArgsWereBad(QWidget *parent, JavaCheckResult result)
{
- auto htmlError = result.errorLog;
- QString text;
- htmlError.replace('\n', "<br />");
- text += QObject::tr("The specified java binary didn't work with the arguments you provided:<br />");
- text += QString("<font color=\"red\">%1</font>").arg(htmlError);
- CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
+ auto htmlError = result.errorLog;
+ QString text;
+ htmlError.replace('\n', "<br />");
+ text += QObject::tr("The specified java binary didn't work with the arguments you provided:<br />");
+ text += QString("<font color=\"red\">%1</font>").arg(htmlError);
+ CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
}
void JavaCommon::javaBinaryWasBad(QWidget *parent, JavaCheckResult result)
{
- QString text;
- text += QObject::tr(
- "The specified java binary didn't work.<br />You should use the auto-detect feature, "
- "or set the path to the java executable.<br />");
- CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
+ QString text;
+ text += QObject::tr(
+ "The specified java binary didn't work.<br />You should use the auto-detect feature, "
+ "or set the path to the java executable.<br />");
+ CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
}
void JavaCommon::TestCheck::run()
{
- if (!JavaCommon::checkJVMArgs(m_args, m_parent))
- {
- emit finished();
- return;
- }
- checker.reset(new JavaChecker());
- connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this,
- SLOT(checkFinished(JavaCheckResult)));
- checker->m_path = m_path;
- checker->performCheck();
+ if (!JavaCommon::checkJVMArgs(m_args, m_parent))
+ {
+ emit finished();
+ return;
+ }
+ checker.reset(new JavaChecker());
+ connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this,
+ SLOT(checkFinished(JavaCheckResult)));
+ checker->m_path = m_path;
+ checker->performCheck();
}
void JavaCommon::TestCheck::checkFinished(JavaCheckResult result)
{
- if (result.validity != JavaCheckResult::Validity::Valid)
- {
- javaBinaryWasBad(m_parent, result);
- emit finished();
- return;
- }
- checker.reset(new JavaChecker());
- connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this,
- SLOT(checkFinishedWithArgs(JavaCheckResult)));
- checker->m_path = m_path;
- checker->m_args = m_args;
- checker->m_minMem = m_minMem;
- checker->m_maxMem = m_maxMem;
- if (result.javaVersion.requiresPermGen())
- {
- checker->m_permGen = m_permGen;
- }
- checker->performCheck();
+ if (result.validity != JavaCheckResult::Validity::Valid)
+ {
+ javaBinaryWasBad(m_parent, result);
+ emit finished();
+ return;
+ }
+ checker.reset(new JavaChecker());
+ connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this,
+ SLOT(checkFinishedWithArgs(JavaCheckResult)));
+ checker->m_path = m_path;
+ checker->m_args = m_args;
+ checker->m_minMem = m_minMem;
+ checker->m_maxMem = m_maxMem;
+ if (result.javaVersion.requiresPermGen())
+ {
+ checker->m_permGen = m_permGen;
+ }
+ checker->performCheck();
}
void JavaCommon::TestCheck::checkFinishedWithArgs(JavaCheckResult result)
{
- if (result.validity == JavaCheckResult::Validity::Valid)
- {
- javaWasOk(m_parent, result);
- emit finished();
- return;
- }
- javaArgsWereBad(m_parent, result);
- emit finished();
+ if (result.validity == JavaCheckResult::Validity::Valid)
+ {
+ javaWasOk(m_parent, result);
+ emit finished();
+ return;
+ }
+ javaArgsWereBad(m_parent, result);
+ emit finished();
}
diff --git a/application/JavaCommon.h b/application/JavaCommon.h
index 4e4cd633..ca98145c 100644
--- a/application/JavaCommon.h
+++ b/application/JavaCommon.h
@@ -8,41 +8,41 @@ class QWidget;
*/
namespace JavaCommon
{
- bool checkJVMArgs(QString args, QWidget *parent);
-
- // Show a dialog saying that the Java binary was not usable
- void javaBinaryWasBad(QWidget *parent, JavaCheckResult result);
- // Show a dialog saying that the Java binary was not usable because of bad options
- void javaArgsWereBad(QWidget *parent, JavaCheckResult result);
- // Show a dialog saying that the Java binary was usable
- void javaWasOk(QWidget *parent, JavaCheckResult result);
-
- class TestCheck : public QObject
- {
- Q_OBJECT
- public:
- TestCheck(QWidget *parent, QString path, QString args, int minMem, int maxMem, int permGen)
- :m_parent(parent), m_path(path), m_args(args), m_minMem(minMem), m_maxMem(maxMem), m_permGen(permGen)
- {
- }
- virtual ~TestCheck() {};
-
- void run();
-
- signals:
- void finished();
-
- private slots:
- void checkFinished(JavaCheckResult result);
- void checkFinishedWithArgs(JavaCheckResult result);
-
- private:
- std::shared_ptr<JavaChecker> checker;
- QWidget *m_parent = nullptr;
- QString m_path;
- QString m_args;
- int m_minMem = 0;
- int m_maxMem = 0;
- int m_permGen = 64;
- };
+ bool checkJVMArgs(QString args, QWidget *parent);
+
+ // Show a dialog saying that the Java binary was not usable
+ void javaBinaryWasBad(QWidget *parent, JavaCheckResult result);
+ // Show a dialog saying that the Java binary was not usable because of bad options
+ void javaArgsWereBad(QWidget *parent, JavaCheckResult result);
+ // Show a dialog saying that the Java binary was usable
+ void javaWasOk(QWidget *parent, JavaCheckResult result);
+
+ class TestCheck : public QObject
+ {
+ Q_OBJECT
+ public:
+ TestCheck(QWidget *parent, QString path, QString args, int minMem, int maxMem, int permGen)
+ :m_parent(parent), m_path(path), m_args(args), m_minMem(minMem), m_maxMem(maxMem), m_permGen(permGen)
+ {
+ }
+ virtual ~TestCheck() {};
+
+ void run();
+
+ signals:
+ void finished();
+
+ private slots:
+ void checkFinished(JavaCheckResult result);
+ void checkFinishedWithArgs(JavaCheckResult result);
+
+ private:
+ std::shared_ptr<JavaChecker> checker;
+ QWidget *m_parent = nullptr;
+ QString m_path;
+ QString m_args;
+ int m_minMem = 0;
+ int m_maxMem = 0;
+ int m_permGen = 64;
+ };
}
diff --git a/application/KonamiCode.cpp b/application/KonamiCode.cpp
index 07c285bc..4c5af837 100644
--- a/application/KonamiCode.cpp
+++ b/application/KonamiCode.cpp
@@ -6,11 +6,13 @@
namespace {
const std::array<Qt::Key, 10> konamiCode =
{
- Qt::Key_Up, Qt::Key_Up,
- Qt::Key_Down, Qt::Key_Down,
- Qt::Key_Left, Qt::Key_Right,
- Qt::Key_Left, Qt::Key_Right,
- Qt::Key_B, Qt::Key_A
+ {
+ Qt::Key_Up, Qt::Key_Up,
+ Qt::Key_Down, Qt::Key_Down,
+ Qt::Key_Left, Qt::Key_Right,
+ Qt::Key_Left, Qt::Key_Right,
+ Qt::Key_B, Qt::Key_A
+ }
};
}
@@ -21,22 +23,22 @@ KonamiCode::KonamiCode(QObject* parent) : QObject(parent)
void KonamiCode::input(QEvent* event)
{
- if( event->type() == QEvent::KeyPress )
- {
- QKeyEvent *keyEvent = static_cast<QKeyEvent*>( event );
- auto key = Qt::Key(keyEvent->key());
- if(key == konamiCode[m_progress])
- {
- m_progress ++;
- }
- else
- {
- m_progress = 0;
- }
- if(m_progress == konamiCode.size())
- {
- m_progress = 0;
- emit triggered();
- }
- }
+ if( event->type() == QEvent::KeyPress )
+ {
+ QKeyEvent *keyEvent = static_cast<QKeyEvent*>( event );
+ auto key = Qt::Key(keyEvent->key());
+ if(key == konamiCode[m_progress])
+ {
+ m_progress ++;
+ }
+ else
+ {
+ m_progress = 0;
+ }
+ if(m_progress == konamiCode.size())
+ {
+ m_progress = 0;
+ emit triggered();
+ }
+ }
}
diff --git a/application/KonamiCode.h b/application/KonamiCode.h
index ad17f8be..3d320ae7 100644
--- a/application/KonamiCode.h
+++ b/application/KonamiCode.h
@@ -4,14 +4,14 @@
class KonamiCode : public QObject
{
- Q_OBJECT
+ Q_OBJECT
public:
- KonamiCode(QObject *parent = 0);
- void input(QEvent *event);
+ KonamiCode(QObject *parent = 0);
+ void input(QEvent *event);
signals:
- void triggered();
+ void triggered();
private:
- int m_progress = 0;
+ int m_progress = 0;
};
diff --git a/application/LaunchController.cpp b/application/LaunchController.cpp
index 2e711933..e39048f1 100644
--- a/application/LaunchController.cpp
+++ b/application/LaunchController.cpp
@@ -9,7 +9,6 @@
#include "InstanceWindow.h"
#include "BuildConfig.h"
#include "JavaCommon.h"
-#include "SettingsUI.h"
#include <QLineEdit>
#include <QInputDialog>
#include <tasks/Task.h>
@@ -23,291 +22,291 @@ LaunchController::LaunchController(QObject *parent) : Task(parent)
void LaunchController::executeTask()
{
- if (!m_instance)
- {
- emitFailed(tr("No instance specified"));
- return;
- }
+ if (!m_instance)
+ {
+ emitFailed(tr("No instance specified"));
+ return;
+ }
- login();
+ login();
}
// FIXME: minecraft specific
void LaunchController::login()
{
- JavaCommon::checkJVMArgs(m_instance->settings()->get("JvmArgs").toString(), m_parentWidget);
+ JavaCommon::checkJVMArgs(m_instance->settings()->get("JvmArgs").toString(), m_parentWidget);
- // Find an account to use.
- std::shared_ptr<MojangAccountList> accounts = MMC->accounts();
- MojangAccountPtr account = accounts->activeAccount();
- if (accounts->count() <= 0)
- {
- // Tell the user they need to log in at least one account in order to play.
- auto reply = CustomMessageBox::selectable(
- m_parentWidget, tr("No Accounts"),
- tr("In order to play Minecraft, you must have at least one Mojang or Minecraft "
- "account logged in to MultiMC."
- "Would you like to open the account manager to add an account now?"),
- QMessageBox::Information, QMessageBox::Yes | QMessageBox::No)->exec();
+ // Find an account to use.
+ std::shared_ptr<MojangAccountList> accounts = MMC->accounts();
+ MojangAccountPtr account = accounts->activeAccount();
+ if (accounts->count() <= 0)
+ {
+ // Tell the user they need to log in at least one account in order to play.
+ auto reply = CustomMessageBox::selectable(
+ m_parentWidget, tr("No Accounts"),
+ tr("In order to play Minecraft, you must have at least one Mojang or Minecraft "
+ "account logged in to MultiMC."
+ "Would you like to open the account manager to add an account now?"),
+ QMessageBox::Information, QMessageBox::Yes | QMessageBox::No)->exec();
- if (reply == QMessageBox::Yes)
- {
- // Open the account manager.
- SettingsUI::ShowPageDialog(MMC->globalSettingsPages(), m_parentWidget, "accounts");
- }
- }
- else if (account.get() == nullptr)
- {
- // If no default account is set, ask the user which one to use.
- ProfileSelectDialog selectDialog(tr("Which profile would you like to use?"),
- ProfileSelectDialog::GlobalDefaultCheckbox, m_parentWidget);
+ if (reply == QMessageBox::Yes)
+ {
+ // Open the account manager.
+ MMC->ShowGlobalSettings(m_parentWidget, "accounts");
+ }
+ }
+ else if (account.get() == nullptr)
+ {
+ // If no default account is set, ask the user which one to use.
+ ProfileSelectDialog selectDialog(tr("Which profile would you like to use?"),
+ ProfileSelectDialog::GlobalDefaultCheckbox, m_parentWidget);
- selectDialog.exec();
+ selectDialog.exec();
- // Launch the instance with the selected account.
- account = selectDialog.selectedAccount();
+ // Launch the instance with the selected account.
+ account = selectDialog.selectedAccount();
- // If the user said to use the account as default, do that.
- if (selectDialog.useAsGlobalDefault() && account.get() != nullptr)
- accounts->setActiveAccount(account->username());
- }
+ // If the user said to use the account as default, do that.
+ if (selectDialog.useAsGlobalDefault() && account.get() != nullptr)
+ accounts->setActiveAccount(account->username());
+ }
- // if no account is selected, we bail
- if (!account.get())
- {
- emitFailed(tr("No account selected for launch"));
- return;
- }
+ // if no account is selected, we bail
+ if (!account.get())
+ {
+ emitFailed(tr("No account selected for launch"));
+ return;
+ }
- // we try empty password first :)
- QString password;
- // we loop until the user succeeds in logging in or gives up
- bool tryagain = true;
- // the failure. the default failure.
- const QString needLoginAgain = tr("Your account is currently not logged in. Please enter "
- "your password to log in again.");
- QString failReason = needLoginAgain;
+ // we try empty password first :)
+ QString password;
+ // we loop until the user succeeds in logging in or gives up
+ bool tryagain = true;
+ // the failure. the default failure.
+ const QString needLoginAgain = tr("Your account is currently not logged in. Please enter "
+ "your password to log in again.");
+ QString failReason = needLoginAgain;
- while (tryagain)
- {
- m_session = std::make_shared<AuthSession>();
- m_session->wants_online = m_online;
- auto task = account->login(m_session, password);
- if (task)
- {
- // We'll need to validate the access token to make sure the account
- // is still logged in.
- ProgressDialog progDialog(m_parentWidget);
- if (m_online)
- {
- progDialog.setSkipButton(true, tr("Play Offline"));
- }
- progDialog.execWithTask(task.get());
- if (!task->wasSuccessful())
- {
- auto failReasonNew = task->failReason();
- if(failReasonNew == "Invalid token.")
- {
- account->invalidateClientToken();
- failReason = needLoginAgain;
- }
- else failReason = failReasonNew;
- }
- }
- switch (m_session->status)
- {
- case AuthSession::Undetermined:
- {
- qCritical() << "Received undetermined session status during login. Bye.";
- tryagain = false;
- emitFailed(tr("Received undetermined session status during login."));
- break;
- }
- case AuthSession::RequiresPassword:
- {
- EditAccountDialog passDialog(failReason, m_parentWidget, EditAccountDialog::PasswordField);
- auto username = m_session->username;
- auto chopN = [](QString toChop, int N) -> QString
- {
- if(toChop.size() > N)
- {
- auto left = toChop.left(N);
- left += QString("\u25CF").repeated(toChop.size() - N);
- return left;
- }
- return toChop;
- };
+ while (tryagain)
+ {
+ m_session = std::make_shared<AuthSession>();
+ m_session->wants_online = m_online;
+ auto task = account->login(m_session, password);
+ if (task)
+ {
+ // We'll need to validate the access token to make sure the account
+ // is still logged in.
+ ProgressDialog progDialog(m_parentWidget);
+ if (m_online)
+ {
+ progDialog.setSkipButton(true, tr("Play Offline"));
+ }
+ progDialog.execWithTask(task.get());
+ if (!task->wasSuccessful())
+ {
+ auto failReasonNew = task->failReason();
+ if(failReasonNew == "Invalid token.")
+ {
+ account->invalidateClientToken();
+ failReason = needLoginAgain;
+ }
+ else failReason = failReasonNew;
+ }
+ }
+ switch (m_session->status)
+ {
+ case AuthSession::Undetermined:
+ {
+ qCritical() << "Received undetermined session status during login. Bye.";
+ tryagain = false;
+ emitFailed(tr("Received undetermined session status during login."));
+ break;
+ }
+ case AuthSession::RequiresPassword:
+ {
+ EditAccountDialog passDialog(failReason, m_parentWidget, EditAccountDialog::PasswordField);
+ auto username = m_session->username;
+ auto chopN = [](QString toChop, int N) -> QString
+ {
+ if(toChop.size() > N)
+ {
+ auto left = toChop.left(N);
+ left += QString("\u25CF").repeated(toChop.size() - N);
+ return left;
+ }
+ return toChop;
+ };
- if(username.contains('@'))
- {
- auto parts = username.split('@');
- auto mailbox = chopN(parts[0],3);
- QString domain = chopN(parts[1], 3);
- username = mailbox + '@' + domain;
- }
- passDialog.setUsername(username);
- if (passDialog.exec() == QDialog::Accepted)
- {
- password = passDialog.password();
- }
- else
- {
- tryagain = false;
- }
- break;
- }
- case AuthSession::PlayableOffline:
- {
- // we ask the user for a player name
- bool ok = false;
- QString usedname = m_session->player_name;
- QString name = QInputDialog::getText(m_parentWidget, tr("Player name"),
- tr("Choose your offline mode player name."),
- QLineEdit::Normal, m_session->player_name, &ok);
- if (!ok)
- {
- tryagain = false;
- break;
- }
- if (name.length())
- {
- usedname = name;
- }
- m_session->MakeOffline(usedname);
- // offline flavored game from here :3
- }
- case AuthSession::PlayableOnline:
- {
- launchInstance();
- tryagain = false;
- return;
- }
- }
- }
- emitFailed(tr("Failed to launch."));
+ if(username.contains('@'))
+ {
+ auto parts = username.split('@');
+ auto mailbox = chopN(parts[0],3);
+ QString domain = chopN(parts[1], 3);
+ username = mailbox + '@' + domain;
+ }
+ passDialog.setUsername(username);
+ if (passDialog.exec() == QDialog::Accepted)
+ {
+ password = passDialog.password();
+ }
+ else
+ {
+ tryagain = false;
+ }
+ break;
+ }
+ case AuthSession::PlayableOffline:
+ {
+ // we ask the user for a player name
+ bool ok = false;
+ QString usedname = m_session->player_name;
+ QString name = QInputDialog::getText(m_parentWidget, tr("Player name"),
+ tr("Choose your offline mode player name."),
+ QLineEdit::Normal, m_session->player_name, &ok);
+ if (!ok)
+ {
+ tryagain = false;
+ break;
+ }
+ if (name.length())
+ {
+ usedname = name;
+ }
+ m_session->MakeOffline(usedname);
+ // offline flavored game from here :3
+ }
+ case AuthSession::PlayableOnline:
+ {
+ launchInstance();
+ tryagain = false;
+ return;
+ }
+ }
+ }
+ emitFailed(tr("Failed to launch."));
}
void LaunchController::launchInstance()
{
- Q_ASSERT_X(m_instance != NULL, "launchInstance", "instance is NULL");
- Q_ASSERT_X(m_session.get() != nullptr, "launchInstance", "session is NULL");
+ Q_ASSERT_X(m_instance != NULL, "launchInstance", "instance is NULL");
+ Q_ASSERT_X(m_session.get() != nullptr, "launchInstance", "session is NULL");
- if(!m_instance->reloadSettings())
- {
- QMessageBox::critical(m_parentWidget, tr("Error"), tr("Couldn't load the instance profile."));
- emitFailed(tr("Couldn't load the instance profile."));
- return;
- }
+ if(!m_instance->reloadSettings())
+ {
+ QMessageBox::critical(m_parentWidget, tr("Error"), tr("Couldn't load the instance profile."));
+ emitFailed(tr("Couldn't load the instance profile."));
+ return;
+ }
- m_launcher = m_instance->createLaunchTask(m_session);
- if (!m_launcher)
- {
- emitFailed(tr("Couldn't instantiate a launcher."));
- return;
- }
+ m_launcher = m_instance->createLaunchTask(m_session);
+ if (!m_launcher)
+ {
+ emitFailed(tr("Couldn't instantiate a launcher."));
+ return;
+ }
- auto console = qobject_cast<InstanceWindow *>(m_parentWidget);
- auto showConsole = m_instance->settings()->get("ShowConsole").toBool();
- if(!console && showConsole)
- {
- MMC->showInstanceWindow(m_instance);
- }
- connect(m_launcher.get(), &LaunchTask::readyForLaunch, this, &LaunchController::readyForLaunch);
- connect(m_launcher.get(), &LaunchTask::succeeded, this, &LaunchController::onSucceeded);
- connect(m_launcher.get(), &LaunchTask::failed, this, &LaunchController::onFailed);
- connect(m_launcher.get(), &LaunchTask::requestProgress, this, &LaunchController::onProgressRequested);
+ auto console = qobject_cast<InstanceWindow *>(m_parentWidget);
+ auto showConsole = m_instance->settings()->get("ShowConsole").toBool();
+ if(!console && showConsole)
+ {
+ MMC->showInstanceWindow(m_instance);
+ }
+ connect(m_launcher.get(), &LaunchTask::readyForLaunch, this, &LaunchController::readyForLaunch);
+ connect(m_launcher.get(), &LaunchTask::succeeded, this, &LaunchController::onSucceeded);
+ connect(m_launcher.get(), &LaunchTask::failed, this, &LaunchController::onFailed);
+ connect(m_launcher.get(), &LaunchTask::requestProgress, this, &LaunchController::onProgressRequested);
- m_launcher->prependStep(std::make_shared<TextPrint>(m_launcher.get(), "MultiMC version: " + BuildConfig.printableVersionString() + "\n\n", MessageLevel::MultiMC));
- m_launcher->start();
+ m_launcher->prependStep(new TextPrint(m_launcher.get(), "MultiMC version: " + BuildConfig.printableVersionString() + "\n\n", MessageLevel::MultiMC));
+ m_launcher->start();
}
void LaunchController::readyForLaunch()
{
- if (!m_profiler)
- {
- m_launcher->proceed();
- return;
- }
+ if (!m_profiler)
+ {
+ m_launcher->proceed();
+ return;
+ }
- QString error;
- if (!m_profiler->check(&error))
- {
- m_launcher->abort();
- QMessageBox::critical(m_parentWidget, tr("Error"), tr("Couldn't start profiler: %1").arg(error));
- emitFailed("Profiler startup failed");
- return;
- }
- BaseProfiler *profilerInstance = m_profiler->createProfiler(m_launcher->instance(), this);
+ QString error;
+ if (!m_profiler->check(&error))
+ {
+ m_launcher->abort();
+ QMessageBox::critical(m_parentWidget, tr("Error"), tr("Couldn't start profiler: %1").arg(error));
+ emitFailed("Profiler startup failed");
+ return;
+ }
+ BaseProfiler *profilerInstance = m_profiler->createProfiler(m_launcher->instance(), this);
- connect(profilerInstance, &BaseProfiler::readyToLaunch, [this](const QString & message)
- {
- QMessageBox msg;
- msg.setText(tr("The game launch is delayed until you press the "
- "button. This is the right time to setup the profiler, as the "
- "profiler server is running now.\n\n%1").arg(message));
- msg.setWindowTitle(tr("Waiting"));
- msg.setIcon(QMessageBox::Information);
- msg.addButton(tr("Launch"), QMessageBox::AcceptRole);
- msg.setModal(true);
- msg.exec();
- m_launcher->proceed();
- });
- connect(profilerInstance, &BaseProfiler::abortLaunch, [this](const QString & message)
- {
- QMessageBox msg;
- msg.setText(tr("Couldn't start the profiler: %1").arg(message));
- msg.setWindowTitle(tr("Error"));
- msg.setIcon(QMessageBox::Critical);
- msg.addButton(QMessageBox::Ok);
- msg.setModal(true);
- msg.exec();
- m_launcher->abort();
- emitFailed("Profiler startup failed");
- });
- profilerInstance->beginProfiling(m_launcher);
+ connect(profilerInstance, &BaseProfiler::readyToLaunch, [this](const QString & message)
+ {
+ QMessageBox msg;
+ msg.setText(tr("The game launch is delayed until you press the "
+ "button. This is the right time to setup the profiler, as the "
+ "profiler server is running now.\n\n%1").arg(message));
+ msg.setWindowTitle(tr("Waiting"));
+ msg.setIcon(QMessageBox::Information);
+ msg.addButton(tr("Launch"), QMessageBox::AcceptRole);
+ msg.setModal(true);
+ msg.exec();
+ m_launcher->proceed();
+ });
+ connect(profilerInstance, &BaseProfiler::abortLaunch, [this](const QString & message)
+ {
+ QMessageBox msg;
+ msg.setText(tr("Couldn't start the profiler: %1").arg(message));
+ msg.setWindowTitle(tr("Error"));
+ msg.setIcon(QMessageBox::Critical);
+ msg.addButton(QMessageBox::Ok);
+ msg.setModal(true);
+ msg.exec();
+ m_launcher->abort();
+ emitFailed("Profiler startup failed");
+ });
+ profilerInstance->beginProfiling(m_launcher);
}
void LaunchController::onSucceeded()
{
- emitSucceeded();
+ emitSucceeded();
}
void LaunchController::onFailed(QString reason)
{
- if(m_instance->settings()->get("ShowConsoleOnError").toBool())
- {
- MMC->showInstanceWindow(m_instance, "console");
- }
- emitFailed(reason);
+ if(m_instance->settings()->get("ShowConsoleOnError").toBool())
+ {
+ MMC->showInstanceWindow(m_instance, "console");
+ }
+ emitFailed(reason);
}
void LaunchController::onProgressRequested(Task* task)
{
- ProgressDialog progDialog(m_parentWidget);
- progDialog.setSkipButton(true, tr("Abort"));
- m_launcher->proceed();
- progDialog.execWithTask(task);
+ ProgressDialog progDialog(m_parentWidget);
+ progDialog.setSkipButton(true, tr("Abort"));
+ m_launcher->proceed();
+ progDialog.execWithTask(task);
}
bool LaunchController::abort()
{
- if(!m_launcher)
- {
- return true;
- }
- if(!m_launcher->canAbort())
- {
- return false;
- }
- auto response = CustomMessageBox::selectable(
- m_parentWidget, 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)
- {
- return m_launcher->abort();
- }
- return false;
+ if(!m_launcher)
+ {
+ return true;
+ }
+ if(!m_launcher->canAbort())
+ {
+ return false;
+ }
+ auto response = CustomMessageBox::selectable(
+ m_parentWidget, 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)
+ {
+ return m_launcher->abort();
+ }
+ return false;
}
diff --git a/application/LaunchController.h b/application/LaunchController.h
index 84c65743..1d879028 100644
--- a/application/LaunchController.h
+++ b/application/LaunchController.h
@@ -6,56 +6,56 @@
class InstanceWindow;
class LaunchController: public Task
{
- Q_OBJECT
+ Q_OBJECT
public:
- void executeTask() override;
+ void executeTask() override;
- LaunchController(QObject * parent = nullptr);
- virtual ~LaunchController(){};
+ LaunchController(QObject * parent = nullptr);
+ virtual ~LaunchController(){};
- void setInstance(InstancePtr instance)
- {
- m_instance = instance;
- }
- InstancePtr instance()
- {
- return m_instance;
- }
- void setOnline(bool online)
- {
- m_online = online;
- }
- void setProfiler(BaseProfilerFactory *profiler)
- {
- m_profiler = profiler;
- }
- void setParentWidget(QWidget * widget)
- {
- m_parentWidget = widget;
- }
- QString id()
- {
- return m_instance->id();
- }
- bool abort() override;
+ void setInstance(InstancePtr instance)
+ {
+ m_instance = instance;
+ }
+ InstancePtr instance()
+ {
+ return m_instance;
+ }
+ void setOnline(bool online)
+ {
+ m_online = online;
+ }
+ void setProfiler(BaseProfilerFactory *profiler)
+ {
+ m_profiler = profiler;
+ }
+ void setParentWidget(QWidget * widget)
+ {
+ m_parentWidget = widget;
+ }
+ QString id()
+ {
+ return m_instance->id();
+ }
+ bool abort() override;
private:
- void login();
- void launchInstance();
+ void login();
+ void launchInstance();
private slots:
- void readyForLaunch();
+ void readyForLaunch();
- void onSucceeded();
- void onFailed(QString reason);
- void onProgressRequested(Task *task);
+ void onSucceeded();
+ void onFailed(QString reason);
+ void onProgressRequested(Task *task);
private:
- BaseProfilerFactory *m_profiler = nullptr;
- bool m_online = true;
- InstancePtr m_instance;
- QWidget * m_parentWidget = nullptr;
- InstanceWindow *m_console = nullptr;
- AuthSessionPtr m_session;
- std::shared_ptr <LaunchTask> m_launcher;
+ BaseProfilerFactory *m_profiler = nullptr;
+ bool m_online = true;
+ InstancePtr m_instance;
+ QWidget * m_parentWidget = nullptr;
+ InstanceWindow *m_console = nullptr;
+ AuthSessionPtr m_session;
+ shared_qobject_ptr<LaunchTask> m_launcher;
};
diff --git a/application/MainWindow.cpp b/application/MainWindow.cpp
index 60742412..1db09c6c 100644
--- a/application/MainWindow.cpp
+++ b/application/MainWindow.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Authors: Andrew Okin
* Peterix
@@ -70,7 +70,6 @@
#include "InstanceProxyModel.h"
#include "JavaCommon.h"
#include "LaunchController.h"
-#include "SettingsUI.h"
#include "groupview/GroupView.h"
#include "groupview/InstanceDelegate.h"
#include "widgets/LabeledToolButton.h"
@@ -86,7 +85,6 @@
#include "dialogs/EditAccountDialog.h"
#include "dialogs/NotificationDialog.h"
#include "dialogs/ExportInstanceDialog.h"
-#include <FolderInstanceProvider.h>
#include <InstanceImportTask.h>
#include "UpdateController.h"
#include "KonamiCode.h"
@@ -97,42 +95,42 @@ template <typename T>
class Translated
{
public:
- Translated(){}
- Translated(QWidget *parent)
- {
- m_contained = new T(parent);
- }
- void setTooltipId(const char * tooltip)
- {
- m_tooltip = tooltip;
- }
- void setTextId(const char * text)
- {
- m_text = text;
- }
- operator T*()
- {
- return m_contained;
- }
- T * operator->()
- {
- return m_contained;
- }
- void retranslate()
- {
- if(m_text)
- {
- m_contained->setText(QApplication::translate("MainWindow", m_text));
- }
- if(m_tooltip)
- {
- m_contained->setToolTip(QApplication::translate("MainWindow", m_tooltip));
- }
- }
+ Translated(){}
+ Translated(QWidget *parent)
+ {
+ m_contained = new T(parent);
+ }
+ void setTooltipId(const char * tooltip)
+ {
+ m_tooltip = tooltip;
+ }
+ void setTextId(const char * text)
+ {
+ m_text = text;
+ }
+ operator T*()
+ {
+ return m_contained;
+ }
+ T * operator->()
+ {
+ return m_contained;
+ }
+ void retranslate()
+ {
+ if(m_text)
+ {
+ m_contained->setText(QApplication::translate("MainWindow", m_text));
+ }
+ if(m_tooltip)
+ {
+ m_contained->setToolTip(QApplication::translate("MainWindow", m_tooltip));
+ }
+ }
private:
- T * m_contained = nullptr;
- const char * m_text = nullptr;
- const char * m_tooltip = nullptr;
+ T * m_contained = nullptr;
+ const char * m_text = nullptr;
+ const char * m_tooltip = nullptr;
};
using TranslatedAction = Translated<QAction>;
using TranslatedToolButton = Translated<QToolButton>;
@@ -140,889 +138,944 @@ using TranslatedToolButton = Translated<QToolButton>;
class TranslatedToolbar
{
public:
- TranslatedToolbar(){}
- TranslatedToolbar(QWidget *parent)
- {
- m_contained = new QToolBar(parent);
- }
- void setWindowTitleId(const char * title)
- {
- m_title = title;
- }
- operator QToolBar*()
- {
- return m_contained;
- }
- QToolBar * operator->()
- {
- return m_contained;
- }
- void retranslate()
- {
- if(m_title)
- {
- m_contained->setWindowTitle(QApplication::translate("MainWindow", m_title));
- }
- }
+ TranslatedToolbar(){}
+ TranslatedToolbar(QWidget *parent)
+ {
+ m_contained = new QToolBar(parent);
+ }
+ void setWindowTitleId(const char * title)
+ {
+ m_title = title;
+ }
+ operator QToolBar*()
+ {
+ return m_contained;
+ }
+ QToolBar * operator->()
+ {
+ return m_contained;
+ }
+ void retranslate()
+ {
+ if(m_title)
+ {
+ m_contained->setWindowTitle(QApplication::translate("MainWindow", m_title));
+ }
+ }
private:
- QToolBar * m_contained = nullptr;
- const char * m_title = nullptr;
+ QToolBar * m_contained = nullptr;
+ const char * m_title = nullptr;
};
class MainWindow::Ui
{
public:
- TranslatedAction actionAddInstance;
- //TranslatedAction actionRefresh;
- TranslatedAction actionCheckUpdate;
- TranslatedAction actionSettings;
- TranslatedAction actionPatreon;
- TranslatedAction actionMoreNews;
- TranslatedAction actionManageAccounts;
- TranslatedAction actionLaunchInstance;
- TranslatedAction actionRenameInstance;
- TranslatedAction actionChangeInstGroup;
- TranslatedAction actionChangeInstIcon;
- TranslatedAction actionEditInstNotes;
- TranslatedAction actionEditInstance;
- TranslatedAction actionWorlds;
- TranslatedAction actionViewSelectedInstFolder;
- TranslatedAction actionDeleteInstance;
- TranslatedAction actionConfig_Folder;
- TranslatedAction actionCAT;
- TranslatedAction actionCopyInstance;
- TranslatedAction actionLaunchInstanceOffline;
- TranslatedAction actionScreenshots;
- TranslatedAction actionExportInstance;
- QVector<TranslatedAction *> all_actions;
-
- LabeledToolButton *renameButton = nullptr;
- LabeledToolButton *changeIconButton = nullptr;
-
- QMenu * foldersMenu = nullptr;
- TranslatedToolButton foldersMenuButton;
- TranslatedAction actionViewInstanceFolder;
- TranslatedAction actionViewCentralModsFolder;
-
- QMenu * helpMenu = nullptr;
- TranslatedToolButton helpMenuButton;
- TranslatedAction actionReportBug;
- TranslatedAction actionDISCORD;
- TranslatedAction actionREDDIT;
- TranslatedAction actionAbout;
-
- QVector<TranslatedToolButton *> all_toolbuttons;
-
- QWidget *centralWidget = nullptr;
- QHBoxLayout *horizontalLayout = nullptr;
- QStatusBar *statusBar = nullptr;
-
- TranslatedToolbar mainToolBar;
- TranslatedToolbar instanceToolBar;
- TranslatedToolbar newsToolBar;
- QVector<TranslatedToolbar *> all_toolbars;
- bool m_kill = false;
-
- void updateLaunchAction()
- {
- if(m_kill)
- {
- actionLaunchInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Kill"));
- actionLaunchInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Kill the running instance"));
- }
- else
- {
- actionLaunchInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Launch"));
- actionLaunchInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Launch the selected instance."));
- }
- actionLaunchInstance.retranslate();
- }
- void setLaunchAction(bool kill)
- {
- m_kill = kill;
- updateLaunchAction();
- }
-
- void createMainToolbar(QMainWindow *MainWindow)
- {
- mainToolBar = TranslatedToolbar(MainWindow);
- mainToolBar->setObjectName(QStringLiteral("mainToolBar"));
- mainToolBar->setMovable(false);
- mainToolBar->setAllowedAreas(Qt::TopToolBarArea);
- mainToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
- mainToolBar->setFloatable(false);
- mainToolBar.setWindowTitleId(QT_TRANSLATE_NOOP("MainWindow", "Main Toolbar"));
-
- actionAddInstance = TranslatedAction(MainWindow);
- actionAddInstance->setObjectName(QStringLiteral("actionAddInstance"));
- actionAddInstance->setIcon(MMC->getThemedIcon("new"));
- actionAddInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Add Instance"));
- actionAddInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Add a new instance."));
- all_actions.append(&actionAddInstance);
- mainToolBar->addAction(actionAddInstance);
-
- mainToolBar->addSeparator();
-
- foldersMenu = new QMenu(MainWindow);
- foldersMenu->setToolTipsVisible(true);
-
- actionViewInstanceFolder = TranslatedAction(MainWindow);
- actionViewInstanceFolder->setObjectName(QStringLiteral("actionViewInstanceFolder"));
- actionViewInstanceFolder->setIcon(MMC->getThemedIcon("viewfolder"));
- actionViewInstanceFolder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "View Instance Folder"));
- actionViewInstanceFolder.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the instance folder in a file browser."));
- all_actions.append(&actionViewInstanceFolder);
- foldersMenu->addAction(actionViewInstanceFolder);
-
- actionViewCentralModsFolder = TranslatedAction(MainWindow);
- actionViewCentralModsFolder->setObjectName(QStringLiteral("actionViewCentralModsFolder"));
- actionViewCentralModsFolder->setIcon(MMC->getThemedIcon("centralmods"));
- actionViewCentralModsFolder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "View Central Mods Folder"));
- actionViewCentralModsFolder.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the central mods folder in a file browser."));
- all_actions.append(&actionViewCentralModsFolder);
- foldersMenu->addAction(actionViewCentralModsFolder);
-
- foldersMenuButton = TranslatedToolButton(MainWindow);
- foldersMenuButton.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Folders"));
- foldersMenuButton.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open one of the folders shared between instances."));
- foldersMenuButton->setMenu(foldersMenu);
- foldersMenuButton->setPopupMode(QToolButton::InstantPopup);
- foldersMenuButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
- foldersMenuButton->setIcon(MMC->getThemedIcon("viewfolder"));
- all_toolbuttons.append(&foldersMenuButton);
- QWidgetAction* foldersButtonAction = new QWidgetAction(MainWindow);
- foldersButtonAction->setDefaultWidget(foldersMenuButton);
- mainToolBar->addAction(foldersButtonAction);
-
- actionSettings = TranslatedAction(MainWindow);
- actionSettings->setObjectName(QStringLiteral("actionSettings"));
- actionSettings->setIcon(MMC->getThemedIcon("settings"));
- actionSettings->setMenuRole(QAction::PreferencesRole);
- actionSettings.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Settings"));
- actionSettings.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Change settings."));
- all_actions.append(&actionSettings);
- mainToolBar->addAction(actionSettings);
-
- helpMenu = new QMenu(MainWindow);
- helpMenu->setToolTipsVisible(true);
-
- actionReportBug = TranslatedAction(MainWindow);
- actionReportBug->setObjectName(QStringLiteral("actionReportBug"));
- actionReportBug->setIcon(MMC->getThemedIcon("bug"));
- actionReportBug.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Report a Bug"));
- actionReportBug.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the bug tracker to report a bug with MultiMC."));
- all_actions.append(&actionReportBug);
- helpMenu->addAction(actionReportBug);
-
- actionDISCORD = TranslatedAction(MainWindow);
- actionDISCORD->setObjectName(QStringLiteral("actionDISCORD"));
- actionDISCORD->setIcon(MMC->getThemedIcon("discord"));
- actionDISCORD.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Discord"));
- actionDISCORD.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open MultiMC discord voice chat."));
- all_actions.append(&actionDISCORD);
- helpMenu->addAction(actionDISCORD);
-
- actionREDDIT = TranslatedAction(MainWindow);
- actionREDDIT->setObjectName(QStringLiteral("actionREDDIT"));
- actionREDDIT->setIcon(MMC->getThemedIcon("reddit-alien"));
- actionREDDIT.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Reddit"));
- actionREDDIT.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open MultiMC subreddit."));
- all_actions.append(&actionREDDIT);
- helpMenu->addAction(actionREDDIT);
-
- actionAbout = TranslatedAction(MainWindow);
- actionAbout->setObjectName(QStringLiteral("actionAbout"));
- actionAbout->setIcon(MMC->getThemedIcon("about"));
- actionAbout->setMenuRole(QAction::AboutRole);
- actionAbout.setTextId(QT_TRANSLATE_NOOP("MainWindow", "About MultiMC"));
- actionAbout.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "View information about MultiMC."));
- all_actions.append(&actionAbout);
- helpMenu->addAction(actionAbout);
-
- helpMenuButton = TranslatedToolButton(MainWindow);
- helpMenuButton.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Help"));
- helpMenuButton.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Get help with MultiMC or Minecraft."));
- helpMenuButton->setMenu(helpMenu);
- helpMenuButton->setPopupMode(QToolButton::InstantPopup);
- helpMenuButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
- helpMenuButton->setIcon(MMC->getThemedIcon("help"));
- all_toolbuttons.append(&helpMenuButton);
- QWidgetAction* helpButtonAction = new QWidgetAction(MainWindow);
- helpButtonAction->setDefaultWidget(helpMenuButton);
- mainToolBar->addAction(helpButtonAction);
-
- if(BuildConfig.UPDATER_ENABLED)
- {
- actionCheckUpdate = TranslatedAction(MainWindow);
- actionCheckUpdate->setObjectName(QStringLiteral("actionCheckUpdate"));
- actionCheckUpdate->setIcon(MMC->getThemedIcon("checkupdate"));
- actionCheckUpdate.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Update"));
- actionCheckUpdate.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Check for new updates for MultiMC."));
- all_actions.append(&actionCheckUpdate);
- mainToolBar->addAction(actionCheckUpdate);
- }
-
- mainToolBar->addSeparator();
-
- actionPatreon = TranslatedAction(MainWindow);
- actionPatreon->setObjectName(QStringLiteral("actionPatreon"));
- actionPatreon->setIcon(MMC->getThemedIcon("patreon"));
- actionPatreon.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Support MultiMC"));
- actionPatreon.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the MultiMC Patreon page."));
- all_actions.append(&actionPatreon);
- mainToolBar->addAction(actionPatreon);
-
- actionCAT = TranslatedAction(MainWindow);
- actionCAT->setObjectName(QStringLiteral("actionCAT"));
- actionCAT->setCheckable(true);
- actionCAT->setIcon(MMC->getThemedIcon("cat"));
- actionCAT.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Meow"));
- actionCAT.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "It's a fluffy kitty :3"));
- actionCAT->setPriority(QAction::LowPriority);
- all_actions.append(&actionCAT);
- mainToolBar->addAction(actionCAT);
-
- // profile menu and its actions
- actionManageAccounts = TranslatedAction(MainWindow);
- actionManageAccounts->setObjectName(QStringLiteral("actionManageAccounts"));
- actionManageAccounts.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Manage Accounts"));
- // FIXME: no tooltip!
- actionManageAccounts->setCheckable(false);
- actionManageAccounts->setIcon(MMC->getThemedIcon("accounts"));
- all_actions.append(&actionManageAccounts);
-
- all_toolbars.append(&mainToolBar);
- MainWindow->addToolBar(Qt::TopToolBarArea, mainToolBar);
- }
-
- void createStatusBar(QMainWindow *MainWindow)
- {
- statusBar = new QStatusBar(MainWindow);
- statusBar->setObjectName(QStringLiteral("statusBar"));
- MainWindow->setStatusBar(statusBar);
- }
-
- void createNewsToolbar(QMainWindow *MainWindow)
- {
- newsToolBar = TranslatedToolbar(MainWindow);
- newsToolBar->setObjectName(QStringLiteral("newsToolBar"));
- newsToolBar->setMovable(false);
- newsToolBar->setAllowedAreas(Qt::BottomToolBarArea);
- newsToolBar->setIconSize(QSize(16, 16));
- newsToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
- newsToolBar->setFloatable(false);
- newsToolBar->setWindowTitle(QT_TRANSLATE_NOOP("MainWindow", "News Toolbar"));
-
- actionMoreNews = TranslatedAction(MainWindow);
- actionMoreNews->setObjectName(QStringLiteral("actionMoreNews"));
- actionMoreNews->setIcon(MMC->getThemedIcon("news"));
- actionMoreNews.setTextId(QT_TRANSLATE_NOOP("MainWindow", "More news..."));
- actionMoreNews.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the MultiMC development blog to read more news about MultiMC."));
- all_actions.append(&actionMoreNews);
- newsToolBar->addAction(actionMoreNews);
-
- all_toolbars.append(&newsToolBar);
- MainWindow->addToolBar(Qt::BottomToolBarArea, newsToolBar);
- }
-
- void createInstanceToolbar(QMainWindow *MainWindow)
- {
- instanceToolBar = TranslatedToolbar(MainWindow);
- instanceToolBar->setObjectName(QStringLiteral("instanceToolBar"));
- // disabled until we have an instance selected
- instanceToolBar->setEnabled(false);
- instanceToolBar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);
- instanceToolBar->setToolButtonStyle(Qt::ToolButtonTextOnly);
- instanceToolBar->setFloatable(false);
- instanceToolBar->setWindowTitle(QT_TRANSLATE_NOOP("MainWindow", "Instance Toolbar"));
-
- // NOTE: not added to toolbar, but used for instance context menu (right click)
- actionChangeInstIcon = TranslatedAction(MainWindow);
- actionChangeInstIcon->setObjectName(QStringLiteral("actionChangeInstIcon"));
- actionChangeInstIcon->setIcon(QIcon(":/icons/instances/infinity"));
- actionChangeInstIcon->setIconVisibleInMenu(true);
- actionChangeInstIcon.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Change Icon"));
- actionChangeInstIcon.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Change the selected instance's icon."));
- all_actions.append(&actionChangeInstIcon);
-
- changeIconButton = new LabeledToolButton(MainWindow);
- changeIconButton->setObjectName(QStringLiteral("changeIconButton"));
- changeIconButton->setIcon(MMC->getThemedIcon("news"));
- changeIconButton->setToolTip(actionChangeInstIcon->toolTip());
- changeIconButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
- instanceToolBar->addWidget(changeIconButton);
-
- // NOTE: not added to toolbar, but used for instance context menu (right click)
- actionRenameInstance = TranslatedAction(MainWindow);
- actionRenameInstance->setObjectName(QStringLiteral("actionRenameInstance"));
- actionRenameInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Rename"));
- actionRenameInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Rename the selected instance."));
- all_actions.append(&actionRenameInstance);
-
- // the rename label is inside the rename tool button
- renameButton = new LabeledToolButton(MainWindow);
- renameButton->setObjectName(QStringLiteral("renameButton"));
- renameButton->setToolTip(actionRenameInstance->toolTip());
- renameButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
- instanceToolBar->addWidget(renameButton);
-
- instanceToolBar->addSeparator();
-
- actionLaunchInstance = TranslatedAction(MainWindow);
- actionLaunchInstance->setObjectName(QStringLiteral("actionLaunchInstance"));
- all_actions.append(&actionLaunchInstance);
- instanceToolBar->addAction(actionLaunchInstance);
-
- actionLaunchInstanceOffline = TranslatedAction(MainWindow);
- actionLaunchInstanceOffline->setObjectName(QStringLiteral("actionLaunchInstanceOffline"));
- actionLaunchInstanceOffline.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Launch Offline"));
- actionLaunchInstanceOffline.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Launch the selected instance in offline mode."));
- all_actions.append(&actionLaunchInstanceOffline);
- instanceToolBar->addAction(actionLaunchInstanceOffline);
-
- instanceToolBar->addSeparator();
-
- actionEditInstance = TranslatedAction(MainWindow);
- actionEditInstance->setObjectName(QStringLiteral("actionEditInstance"));
- actionEditInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Edit Instance"));
- actionEditInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Change the instance settings, mods and versions."));
- all_actions.append(&actionEditInstance);
- instanceToolBar->addAction(actionEditInstance);
-
- actionEditInstNotes = TranslatedAction(MainWindow);
- actionEditInstNotes->setObjectName(QStringLiteral("actionEditInstNotes"));
- actionEditInstNotes.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Edit Notes"));
- actionEditInstNotes.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Edit the notes for the selected instance."));
- all_actions.append(&actionEditInstNotes);
- instanceToolBar->addAction(actionEditInstNotes);
-
- actionWorlds = TranslatedAction(MainWindow);
- actionWorlds->setObjectName(QStringLiteral("actionWorlds"));
- actionWorlds.setTextId(QT_TRANSLATE_NOOP("MainWindow", "View Worlds"));
- actionWorlds.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "View the worlds of this instance."));
- all_actions.append(&actionWorlds);
- instanceToolBar->addAction(actionWorlds);
-
- actionScreenshots = TranslatedAction(MainWindow);
- actionScreenshots->setObjectName(QStringLiteral("actionScreenshots"));
- actionScreenshots.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Manage Screenshots"));
- actionScreenshots.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "View and upload screenshots for this instance."));
- all_actions.append(&actionScreenshots);
- instanceToolBar->addAction(actionScreenshots);
-
- actionChangeInstGroup = TranslatedAction(MainWindow);
- actionChangeInstGroup->setObjectName(QStringLiteral("actionChangeInstGroup"));
- actionChangeInstGroup.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Change Group"));
- actionChangeInstGroup.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Change the selected instance's group."));
- all_actions.append(&actionChangeInstGroup);
- instanceToolBar->addAction(actionChangeInstGroup);
-
- instanceToolBar->addSeparator();
-
- actionViewSelectedInstFolder = TranslatedAction(MainWindow);
- actionViewSelectedInstFolder->setObjectName(QStringLiteral("actionViewSelectedInstFolder"));
- actionViewSelectedInstFolder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Instance Folder"));
- actionViewSelectedInstFolder.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the selected instance's root folder in a file browser."));
- all_actions.append(&actionViewSelectedInstFolder);
- instanceToolBar->addAction(actionViewSelectedInstFolder);
-
- actionConfig_Folder = TranslatedAction(MainWindow);
- actionConfig_Folder->setObjectName(QStringLiteral("actionConfig_Folder"));
- actionConfig_Folder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Config Folder"));
- actionConfig_Folder.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the instance's config folder."));
- all_actions.append(&actionConfig_Folder);
- instanceToolBar->addAction(actionConfig_Folder);
-
- instanceToolBar->addSeparator();
-
- actionExportInstance = TranslatedAction(MainWindow);
- actionExportInstance->setObjectName(QStringLiteral("actionExportInstance"));
- actionExportInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Export Instance"));
- // FIXME: missing tooltip
- all_actions.append(&actionExportInstance);
- instanceToolBar->addAction(actionExportInstance);
-
- actionDeleteInstance = TranslatedAction(MainWindow);
- actionDeleteInstance->setObjectName(QStringLiteral("actionDeleteInstance"));
- actionDeleteInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Delete"));
- actionDeleteInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Delete the selected instance."));
- all_actions.append(&actionDeleteInstance);
- instanceToolBar->addAction(actionDeleteInstance);
-
- actionCopyInstance = TranslatedAction(MainWindow);
- actionCopyInstance->setObjectName(QStringLiteral("actionCopyInstance"));
- actionCopyInstance->setIcon(MMC->getThemedIcon("copy"));
- actionCopyInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Copy Instance"));
- actionCopyInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Copy the selected instance."));
- all_actions.append(&actionCopyInstance);
- instanceToolBar->addAction(actionCopyInstance);
-
- all_toolbars.append(&instanceToolBar);
- MainWindow->addToolBar(Qt::RightToolBarArea, instanceToolBar);
- }
-
- void setupUi(QMainWindow *MainWindow)
- {
- if (MainWindow->objectName().isEmpty())
- {
- MainWindow->setObjectName(QStringLiteral("MainWindow"));
- }
- MainWindow->resize(694, 563);
- MainWindow->setWindowIcon(MMC->getThemedIcon("logo"));
- MainWindow->setWindowTitle("MultiMC 5");
-
- createMainToolbar(MainWindow);
-
- centralWidget = new QWidget(MainWindow);
- centralWidget->setObjectName(QStringLiteral("centralWidget"));
- horizontalLayout = new QHBoxLayout(centralWidget);
- horizontalLayout->setSpacing(0);
- horizontalLayout->setContentsMargins(11, 11, 11, 11);
- horizontalLayout->setObjectName(QStringLiteral("horizontalLayout"));
- horizontalLayout->setSizeConstraint(QLayout::SetDefaultConstraint);
- horizontalLayout->setContentsMargins(0, 0, 0, 0);
- MainWindow->setCentralWidget(centralWidget);
-
- createStatusBar(MainWindow);
- createNewsToolbar(MainWindow);
- createInstanceToolbar(MainWindow);
-
- retranslateUi(MainWindow);
-
- QMetaObject::connectSlotsByName(MainWindow);
- } // setupUi
-
- void retranslateUi(QMainWindow *MainWindow)
- {
- QString winTitle = tr("MultiMC 5 - Version %1").arg(BuildConfig.printableVersionString());
- if (!BuildConfig.BUILD_PLATFORM.isEmpty())
- {
- winTitle += tr(" on %1", "on platform, as in operating system").arg(BuildConfig.BUILD_PLATFORM);
- }
- MainWindow->setWindowTitle(winTitle);
- // all the actions
- for(auto * item: all_actions)
- {
- item->retranslate();
- }
- for(auto * item: all_toolbars)
- {
- item->retranslate();
- }
- for(auto * item: all_toolbuttons)
- {
- item->retranslate();
- }
- // submenu buttons
- foldersMenuButton->setText(tr("Folders"));
- helpMenuButton->setText(tr("Help"));
- } // retranslateUi
+ TranslatedAction actionAddInstance;
+ //TranslatedAction actionRefresh;
+ TranslatedAction actionCheckUpdate;
+ TranslatedAction actionSettings;
+ TranslatedAction actionPatreon;
+ TranslatedAction actionMoreNews;
+ TranslatedAction actionManageAccounts;
+ TranslatedAction actionLaunchInstance;
+ TranslatedAction actionRenameInstance;
+ TranslatedAction actionChangeInstGroup;
+ TranslatedAction actionChangeInstIcon;
+ TranslatedAction actionEditInstNotes;
+ TranslatedAction actionEditInstance;
+ TranslatedAction actionWorlds;
+ TranslatedAction actionViewSelectedInstFolder;
+ TranslatedAction actionViewSelectedMCFolder;
+ TranslatedAction actionDeleteInstance;
+ TranslatedAction actionConfig_Folder;
+ TranslatedAction actionCAT;
+ TranslatedAction actionCopyInstance;
+ TranslatedAction actionLaunchInstanceOffline;
+ TranslatedAction actionScreenshots;
+ TranslatedAction actionExportInstance;
+ QVector<TranslatedAction *> all_actions;
+
+ LabeledToolButton *renameButton = nullptr;
+ LabeledToolButton *changeIconButton = nullptr;
+
+ QMenu * foldersMenu = nullptr;
+ TranslatedToolButton foldersMenuButton;
+ TranslatedAction actionViewInstanceFolder;
+ TranslatedAction actionViewCentralModsFolder;
+
+ QMenu * helpMenu = nullptr;
+ TranslatedToolButton helpMenuButton;
+ TranslatedAction actionReportBug;
+ TranslatedAction actionDISCORD;
+ TranslatedAction actionREDDIT;
+ TranslatedAction actionAbout;
+
+ QVector<TranslatedToolButton *> all_toolbuttons;
+
+ QWidget *centralWidget = nullptr;
+ QHBoxLayout *horizontalLayout = nullptr;
+ QStatusBar *statusBar = nullptr;
+
+ TranslatedToolbar mainToolBar;
+ TranslatedToolbar instanceToolBar;
+ TranslatedToolbar newsToolBar;
+ QVector<TranslatedToolbar *> all_toolbars;
+ bool m_kill = false;
+
+ void updateLaunchAction()
+ {
+ if(m_kill)
+ {
+ actionLaunchInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Kill"));
+ actionLaunchInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Kill the running instance"));
+ }
+ else
+ {
+ actionLaunchInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Launch"));
+ actionLaunchInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Launch the selected instance."));
+ }
+ actionLaunchInstance.retranslate();
+ }
+ void setLaunchAction(bool kill)
+ {
+ m_kill = kill;
+ updateLaunchAction();
+ }
+
+ void createMainToolbar(QMainWindow *MainWindow)
+ {
+ mainToolBar = TranslatedToolbar(MainWindow);
+ mainToolBar->setObjectName(QStringLiteral("mainToolBar"));
+ mainToolBar->setMovable(false);
+ mainToolBar->setAllowedAreas(Qt::TopToolBarArea);
+ mainToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+ mainToolBar->setFloatable(false);
+ mainToolBar.setWindowTitleId(QT_TRANSLATE_NOOP("MainWindow", "Main Toolbar"));
+
+ actionAddInstance = TranslatedAction(MainWindow);
+ actionAddInstance->setObjectName(QStringLiteral("actionAddInstance"));
+ actionAddInstance->setIcon(MMC->getThemedIcon("new"));
+ actionAddInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Add Instance"));
+ actionAddInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Add a new instance."));
+ all_actions.append(&actionAddInstance);
+ mainToolBar->addAction(actionAddInstance);
+
+ mainToolBar->addSeparator();
+
+ foldersMenu = new QMenu(MainWindow);
+ foldersMenu->setToolTipsVisible(true);
+
+ actionViewInstanceFolder = TranslatedAction(MainWindow);
+ actionViewInstanceFolder->setObjectName(QStringLiteral("actionViewInstanceFolder"));
+ actionViewInstanceFolder->setIcon(MMC->getThemedIcon("viewfolder"));
+ actionViewInstanceFolder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "View Instance Folder"));
+ actionViewInstanceFolder.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the instance folder in a file browser."));
+ all_actions.append(&actionViewInstanceFolder);
+ foldersMenu->addAction(actionViewInstanceFolder);
+
+ actionViewCentralModsFolder = TranslatedAction(MainWindow);
+ actionViewCentralModsFolder->setObjectName(QStringLiteral("actionViewCentralModsFolder"));
+ actionViewCentralModsFolder->setIcon(MMC->getThemedIcon("centralmods"));
+ actionViewCentralModsFolder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "View Central Mods Folder"));
+ actionViewCentralModsFolder.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the central mods folder in a file browser."));
+ all_actions.append(&actionViewCentralModsFolder);
+ foldersMenu->addAction(actionViewCentralModsFolder);
+
+ foldersMenuButton = TranslatedToolButton(MainWindow);
+ foldersMenuButton.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Folders"));
+ foldersMenuButton.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open one of the folders shared between instances."));
+ foldersMenuButton->setMenu(foldersMenu);
+ foldersMenuButton->setPopupMode(QToolButton::InstantPopup);
+ foldersMenuButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+ foldersMenuButton->setIcon(MMC->getThemedIcon("viewfolder"));
+ foldersMenuButton->setFocusPolicy(Qt::NoFocus);
+ all_toolbuttons.append(&foldersMenuButton);
+ QWidgetAction* foldersButtonAction = new QWidgetAction(MainWindow);
+ foldersButtonAction->setDefaultWidget(foldersMenuButton);
+ mainToolBar->addAction(foldersButtonAction);
+
+ actionSettings = TranslatedAction(MainWindow);
+ actionSettings->setObjectName(QStringLiteral("actionSettings"));
+ actionSettings->setIcon(MMC->getThemedIcon("settings"));
+ actionSettings->setMenuRole(QAction::PreferencesRole);
+ actionSettings.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Settings"));
+ actionSettings.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Change settings."));
+ all_actions.append(&actionSettings);
+ mainToolBar->addAction(actionSettings);
+
+ helpMenu = new QMenu(MainWindow);
+ helpMenu->setToolTipsVisible(true);
+
+ actionReportBug = TranslatedAction(MainWindow);
+ actionReportBug->setObjectName(QStringLiteral("actionReportBug"));
+ actionReportBug->setIcon(MMC->getThemedIcon("bug"));
+ actionReportBug.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Report a Bug"));
+ actionReportBug.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the bug tracker to report a bug with MultiMC."));
+ all_actions.append(&actionReportBug);
+ helpMenu->addAction(actionReportBug);
+
+ actionDISCORD = TranslatedAction(MainWindow);
+ actionDISCORD->setObjectName(QStringLiteral("actionDISCORD"));
+ actionDISCORD->setIcon(MMC->getThemedIcon("discord"));
+ actionDISCORD.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Discord"));
+ actionDISCORD.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open MultiMC discord voice chat."));
+ all_actions.append(&actionDISCORD);
+ helpMenu->addAction(actionDISCORD);
+
+ actionREDDIT = TranslatedAction(MainWindow);
+ actionREDDIT->setObjectName(QStringLiteral("actionREDDIT"));
+ actionREDDIT->setIcon(MMC->getThemedIcon("reddit-alien"));
+ actionREDDIT.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Reddit"));
+ actionREDDIT.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open MultiMC subreddit."));
+ all_actions.append(&actionREDDIT);
+ helpMenu->addAction(actionREDDIT);
+
+ actionAbout = TranslatedAction(MainWindow);
+ actionAbout->setObjectName(QStringLiteral("actionAbout"));
+ actionAbout->setIcon(MMC->getThemedIcon("about"));
+ actionAbout->setMenuRole(QAction::AboutRole);
+ actionAbout.setTextId(QT_TRANSLATE_NOOP("MainWindow", "About MultiMC"));
+ actionAbout.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "View information about MultiMC."));
+ all_actions.append(&actionAbout);
+ helpMenu->addAction(actionAbout);
+
+ helpMenuButton = TranslatedToolButton(MainWindow);
+ helpMenuButton.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Help"));
+ helpMenuButton.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Get help with MultiMC or Minecraft."));
+ helpMenuButton->setMenu(helpMenu);
+ helpMenuButton->setPopupMode(QToolButton::InstantPopup);
+ helpMenuButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+ helpMenuButton->setIcon(MMC->getThemedIcon("help"));
+ helpMenuButton->setFocusPolicy(Qt::NoFocus);
+ all_toolbuttons.append(&helpMenuButton);
+ QWidgetAction* helpButtonAction = new QWidgetAction(MainWindow);
+ helpButtonAction->setDefaultWidget(helpMenuButton);
+ mainToolBar->addAction(helpButtonAction);
+
+ if(BuildConfig.UPDATER_ENABLED)
+ {
+ actionCheckUpdate = TranslatedAction(MainWindow);
+ actionCheckUpdate->setObjectName(QStringLiteral("actionCheckUpdate"));
+ actionCheckUpdate->setIcon(MMC->getThemedIcon("checkupdate"));
+ actionCheckUpdate.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Update"));
+ actionCheckUpdate.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Check for new updates for MultiMC."));
+ all_actions.append(&actionCheckUpdate);
+ mainToolBar->addAction(actionCheckUpdate);
+ }
+
+ mainToolBar->addSeparator();
+
+ actionPatreon = TranslatedAction(MainWindow);
+ actionPatreon->setObjectName(QStringLiteral("actionPatreon"));
+ actionPatreon->setIcon(MMC->getThemedIcon("patreon"));
+ actionPatreon.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Support MultiMC"));
+ actionPatreon.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the MultiMC Patreon page."));
+ all_actions.append(&actionPatreon);
+ mainToolBar->addAction(actionPatreon);
+
+ actionCAT = TranslatedAction(MainWindow);
+ actionCAT->setObjectName(QStringLiteral("actionCAT"));
+ actionCAT->setCheckable(true);
+ actionCAT->setIcon(MMC->getThemedIcon("cat"));
+ actionCAT.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Meow"));
+ actionCAT.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "It's a fluffy kitty :3"));
+ actionCAT->setPriority(QAction::LowPriority);
+ all_actions.append(&actionCAT);
+ mainToolBar->addAction(actionCAT);
+
+ // profile menu and its actions
+ actionManageAccounts = TranslatedAction(MainWindow);
+ actionManageAccounts->setObjectName(QStringLiteral("actionManageAccounts"));
+ actionManageAccounts.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Manage Accounts"));
+ // FIXME: no tooltip!
+ actionManageAccounts->setCheckable(false);
+ actionManageAccounts->setIcon(MMC->getThemedIcon("accounts"));
+ all_actions.append(&actionManageAccounts);
+
+ all_toolbars.append(&mainToolBar);
+ MainWindow->addToolBar(Qt::TopToolBarArea, mainToolBar);
+ }
+
+ void createStatusBar(QMainWindow *MainWindow)
+ {
+ statusBar = new QStatusBar(MainWindow);
+ statusBar->setObjectName(QStringLiteral("statusBar"));
+ MainWindow->setStatusBar(statusBar);
+ }
+
+ void createNewsToolbar(QMainWindow *MainWindow)
+ {
+ newsToolBar = TranslatedToolbar(MainWindow);
+ newsToolBar->setObjectName(QStringLiteral("newsToolBar"));
+ newsToolBar->setMovable(false);
+ newsToolBar->setAllowedAreas(Qt::BottomToolBarArea);
+ newsToolBar->setIconSize(QSize(16, 16));
+ newsToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+ newsToolBar->setFloatable(false);
+ newsToolBar->setWindowTitle(QT_TRANSLATE_NOOP("MainWindow", "News Toolbar"));
+
+ actionMoreNews = TranslatedAction(MainWindow);
+ actionMoreNews->setObjectName(QStringLiteral("actionMoreNews"));
+ actionMoreNews->setIcon(MMC->getThemedIcon("news"));
+ actionMoreNews.setTextId(QT_TRANSLATE_NOOP("MainWindow", "More news..."));
+ actionMoreNews.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the MultiMC development blog to read more news about MultiMC."));
+ all_actions.append(&actionMoreNews);
+ newsToolBar->addAction(actionMoreNews);
+
+ all_toolbars.append(&newsToolBar);
+ MainWindow->addToolBar(Qt::BottomToolBarArea, newsToolBar);
+ }
+
+ void createInstanceToolbar(QMainWindow *MainWindow)
+ {
+ instanceToolBar = TranslatedToolbar(MainWindow);
+ instanceToolBar->setObjectName(QStringLiteral("instanceToolBar"));
+ // disabled until we have an instance selected
+ instanceToolBar->setEnabled(false);
+ instanceToolBar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);
+ instanceToolBar->setToolButtonStyle(Qt::ToolButtonTextOnly);
+ instanceToolBar->setFloatable(false);
+ instanceToolBar->setWindowTitle(QT_TRANSLATE_NOOP("MainWindow", "Instance Toolbar"));
+
+ // NOTE: not added to toolbar, but used for instance context menu (right click)
+ actionChangeInstIcon = TranslatedAction(MainWindow);
+ actionChangeInstIcon->setObjectName(QStringLiteral("actionChangeInstIcon"));
+ actionChangeInstIcon->setIcon(QIcon(":/icons/instances/infinity"));
+ actionChangeInstIcon->setIconVisibleInMenu(true);
+ actionChangeInstIcon.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Change Icon"));
+ actionChangeInstIcon.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Change the selected instance's icon."));
+ all_actions.append(&actionChangeInstIcon);
+
+ changeIconButton = new LabeledToolButton(MainWindow);
+ changeIconButton->setObjectName(QStringLiteral("changeIconButton"));
+ changeIconButton->setIcon(MMC->getThemedIcon("news"));
+ changeIconButton->setToolTip(actionChangeInstIcon->toolTip());
+ changeIconButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ instanceToolBar->addWidget(changeIconButton);
+
+ // NOTE: not added to toolbar, but used for instance context menu (right click)
+ actionRenameInstance = TranslatedAction(MainWindow);
+ actionRenameInstance->setObjectName(QStringLiteral("actionRenameInstance"));
+ actionRenameInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Rename"));
+ actionRenameInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Rename the selected instance."));
+ all_actions.append(&actionRenameInstance);
+
+ // the rename label is inside the rename tool button
+ renameButton = new LabeledToolButton(MainWindow);
+ renameButton->setObjectName(QStringLiteral("renameButton"));
+ renameButton->setToolTip(actionRenameInstance->toolTip());
+ renameButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ instanceToolBar->addWidget(renameButton);
+
+ instanceToolBar->addSeparator();
+
+ actionLaunchInstance = TranslatedAction(MainWindow);
+ actionLaunchInstance->setObjectName(QStringLiteral("actionLaunchInstance"));
+ all_actions.append(&actionLaunchInstance);
+ instanceToolBar->addAction(actionLaunchInstance);
+
+ actionLaunchInstanceOffline = TranslatedAction(MainWindow);
+ actionLaunchInstanceOffline->setObjectName(QStringLiteral("actionLaunchInstanceOffline"));
+ actionLaunchInstanceOffline.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Launch Offline"));
+ actionLaunchInstanceOffline.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Launch the selected instance in offline mode."));
+ all_actions.append(&actionLaunchInstanceOffline);
+ instanceToolBar->addAction(actionLaunchInstanceOffline);
+
+ instanceToolBar->addSeparator();
+
+ actionEditInstance = TranslatedAction(MainWindow);
+ actionEditInstance->setObjectName(QStringLiteral("actionEditInstance"));
+ actionEditInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Edit Instance"));
+ actionEditInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Change the instance settings, mods and versions."));
+ all_actions.append(&actionEditInstance);
+ instanceToolBar->addAction(actionEditInstance);
+
+ actionEditInstNotes = TranslatedAction(MainWindow);
+ actionEditInstNotes->setObjectName(QStringLiteral("actionEditInstNotes"));
+ actionEditInstNotes.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Edit Notes"));
+ actionEditInstNotes.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Edit the notes for the selected instance."));
+ all_actions.append(&actionEditInstNotes);
+ instanceToolBar->addAction(actionEditInstNotes);
+
+ actionWorlds = TranslatedAction(MainWindow);
+ actionWorlds->setObjectName(QStringLiteral("actionWorlds"));
+ actionWorlds.setTextId(QT_TRANSLATE_NOOP("MainWindow", "View Worlds"));
+ actionWorlds.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "View the worlds of this instance."));
+ all_actions.append(&actionWorlds);
+ instanceToolBar->addAction(actionWorlds);
+
+ actionScreenshots = TranslatedAction(MainWindow);
+ actionScreenshots->setObjectName(QStringLiteral("actionScreenshots"));
+ actionScreenshots.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Manage Screenshots"));
+ actionScreenshots.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "View and upload screenshots for this instance."));
+ all_actions.append(&actionScreenshots);
+ instanceToolBar->addAction(actionScreenshots);
+
+ actionChangeInstGroup = TranslatedAction(MainWindow);
+ actionChangeInstGroup->setObjectName(QStringLiteral("actionChangeInstGroup"));
+ actionChangeInstGroup.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Change Group"));
+ actionChangeInstGroup.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Change the selected instance's group."));
+ all_actions.append(&actionChangeInstGroup);
+ instanceToolBar->addAction(actionChangeInstGroup);
+
+ instanceToolBar->addSeparator();
+
+ actionViewSelectedMCFolder = TranslatedAction(MainWindow);
+ actionViewSelectedMCFolder->setObjectName(QStringLiteral("actionViewSelectedMCFolder"));
+ actionViewSelectedMCFolder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Minecraft Folder"));
+ actionViewSelectedMCFolder.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the selected instance's minecraft folder in a file browser."));
+ all_actions.append(&actionViewSelectedMCFolder);
+ instanceToolBar->addAction(actionViewSelectedMCFolder);
+
+ actionConfig_Folder = TranslatedAction(MainWindow);
+ actionConfig_Folder->setObjectName(QStringLiteral("actionConfig_Folder"));
+ actionConfig_Folder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Config Folder"));
+ actionConfig_Folder.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the instance's config folder."));
+ all_actions.append(&actionConfig_Folder);
+ instanceToolBar->addAction(actionConfig_Folder);
+
+ actionViewSelectedInstFolder = TranslatedAction(MainWindow);
+ actionViewSelectedInstFolder->setObjectName(QStringLiteral("actionViewSelectedInstFolder"));
+ actionViewSelectedInstFolder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Instance Folder"));
+ actionViewSelectedInstFolder.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the selected instance's root folder in a file browser."));
+ all_actions.append(&actionViewSelectedInstFolder);
+ instanceToolBar->addAction(actionViewSelectedInstFolder);
+
+ instanceToolBar->addSeparator();
+
+ actionExportInstance = TranslatedAction(MainWindow);
+ actionExportInstance->setObjectName(QStringLiteral("actionExportInstance"));
+ actionExportInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Export Instance"));
+ // FIXME: missing tooltip
+ all_actions.append(&actionExportInstance);
+ instanceToolBar->addAction(actionExportInstance);
+
+ actionDeleteInstance = TranslatedAction(MainWindow);
+ actionDeleteInstance->setObjectName(QStringLiteral("actionDeleteInstance"));
+ actionDeleteInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Delete"));
+ actionDeleteInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Delete the selected instance."));
+ all_actions.append(&actionDeleteInstance);
+ instanceToolBar->addAction(actionDeleteInstance);
+
+ actionCopyInstance = TranslatedAction(MainWindow);
+ actionCopyInstance->setObjectName(QStringLiteral("actionCopyInstance"));
+ actionCopyInstance->setIcon(MMC->getThemedIcon("copy"));
+ actionCopyInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Copy Instance"));
+ actionCopyInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Copy the selected instance."));
+ all_actions.append(&actionCopyInstance);
+ instanceToolBar->addAction(actionCopyInstance);
+
+ all_toolbars.append(&instanceToolBar);
+ MainWindow->addToolBar(Qt::RightToolBarArea, instanceToolBar);
+ }
+
+ void setupUi(QMainWindow *MainWindow)
+ {
+ if (MainWindow->objectName().isEmpty())
+ {
+ MainWindow->setObjectName(QStringLiteral("MainWindow"));
+ }
+ MainWindow->resize(694, 563);
+ MainWindow->setWindowIcon(MMC->getThemedIcon("logo"));
+ MainWindow->setWindowTitle("MultiMC 5");
+
+ createMainToolbar(MainWindow);
+
+ centralWidget = new QWidget(MainWindow);
+ centralWidget->setObjectName(QStringLiteral("centralWidget"));
+ horizontalLayout = new QHBoxLayout(centralWidget);
+ horizontalLayout->setSpacing(0);
+ horizontalLayout->setObjectName(QStringLiteral("horizontalLayout"));
+ horizontalLayout->setSizeConstraint(QLayout::SetDefaultConstraint);
+ horizontalLayout->setContentsMargins(0, 0, 0, 0);
+ MainWindow->setCentralWidget(centralWidget);
+
+ createStatusBar(MainWindow);
+ createNewsToolbar(MainWindow);
+ createInstanceToolbar(MainWindow);
+
+ retranslateUi(MainWindow);
+
+ QMetaObject::connectSlotsByName(MainWindow);
+ } // setupUi
+
+ void retranslateUi(QMainWindow *MainWindow)
+ {
+ QString winTitle = tr("MultiMC 5 - Version %1").arg(BuildConfig.printableVersionString());
+ if (!BuildConfig.BUILD_PLATFORM.isEmpty())
+ {
+ winTitle += tr(" on %1", "on platform, as in operating system").arg(BuildConfig.BUILD_PLATFORM);
+ }
+ MainWindow->setWindowTitle(winTitle);
+ // all the actions
+ for(auto * item: all_actions)
+ {
+ item->retranslate();
+ }
+ for(auto * item: all_toolbars)
+ {
+ item->retranslate();
+ }
+ for(auto * item: all_toolbuttons)
+ {
+ item->retranslate();
+ }
+ // submenu buttons
+ foldersMenuButton->setText(tr("Folders"));
+ helpMenuButton->setText(tr("Help"));
+ } // retranslateUi
};
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow::Ui)
{
- ui->setupUi(this);
-
- // OSX magic.
- setUnifiedTitleAndToolBarOnMac(true);
-
- // Global shortcuts
- {
- // 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()));
- }
-
- // Konami Code
- {
- secretEventFilter = new KonamiCode(this);
- connect(secretEventFilter, &KonamiCode::triggered, this, &MainWindow::konamiTriggered);
- }
-
- // Add the news label to the news toolbar.
- {
- m_newsChecker.reset(new NewsChecker(BuildConfig.NEWS_RSS_URL));
- newsLabel = new QToolButton();
- newsLabel->setIcon(MMC->getThemedIcon("news"));
- newsLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
- newsLabel->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
- ui->newsToolBar->insertWidget(ui->actionMoreNews, newsLabel);
- QObject::connect(newsLabel, &QAbstractButton::clicked, this, &MainWindow::newsButtonClicked);
- QObject::connect(m_newsChecker.get(), &NewsChecker::newsLoaded, this, &MainWindow::updateNewsLabel);
- updateNewsLabel();
- }
-
- // Create the instance list widget
- {
- view = new GroupView(ui->centralWidget);
-
- view->setSelectionMode(QAbstractItemView::SingleSelection);
- // FIXME: leaks ListViewDelegate
- view->setItemDelegate(new ListViewDelegate(this));
- view->setFrameShape(QFrame::NoFrame);
- // do not show ugly blue border on the mac
- view->setAttribute(Qt::WA_MacShowFocusRect, false);
-
- view->installEventFilter(this);
- view->setContextMenuPolicy(Qt::CustomContextMenu);
- connect(view, &QWidget::customContextMenuRequested, this, &MainWindow::showInstanceContextMenu);
- connect(view, &GroupView::droppedURLs, this, &MainWindow::droppedURLs);
-
- proxymodel = new InstanceProxyModel(this);
- proxymodel->setSourceModel(MMC->instances().get());
- proxymodel->sort(0);
- connect(proxymodel, &InstanceProxyModel::dataChanged, this, &MainWindow::instanceDataChanged);
-
- view->setModel(proxymodel);
- ui->horizontalLayout->addWidget(view);
- }
- // The cat background
- {
- bool cat_enable = MMC->settings()->get("TheCat").toBool();
- ui->actionCAT->setChecked(cat_enable);
- connect(ui->actionCAT, SIGNAL(toggled(bool)), SLOT(onCatToggled(bool)));
- setCatBackground(cat_enable);
- }
- // start instance when double-clicked
- connect(view, &GroupView::doubleClicked, this, &MainWindow::instanceActivated);
-
- // track the selection -- update the instance toolbar
- connect(view->selectionModel(), &QItemSelectionModel::currentChanged, this, &MainWindow::instanceChanged);
-
- // track icon changes and update the toolbar!
- connect(MMC->icons().get(), &IconList::iconUpdated, this, &MainWindow::iconUpdated);
-
- // model reset -> selection is invalid. All the instance pointers are wrong.
- connect(MMC->instances().get(), &InstanceList::dataIsInvalid, this, &MainWindow::selectionBad);
-
- m_statusLeft = new QLabel(tr("No instance selected"), this);
- m_statusRight = new ServerStatus(this);
- statusBar()->addPermanentWidget(m_statusLeft, 1);
- statusBar()->addPermanentWidget(m_statusRight, 0);
-
- // Add "manage accounts" button, right align
- QWidget *spacer = new QWidget();
- spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
- ui->mainToolBar->addWidget(spacer);
-
- accountMenu = new QMenu(this);
-
- repopulateAccountsMenu();
-
- accountMenuButton = new QToolButton(this);
- accountMenuButton->setText(tr("Profiles"));
- accountMenuButton->setMenu(accountMenu);
- accountMenuButton->setPopupMode(QToolButton::InstantPopup);
- accountMenuButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
- accountMenuButton->setIcon(MMC->getThemedIcon("noaccount"));
-
- QWidgetAction *accountMenuButtonAction = new QWidgetAction(this);
- accountMenuButtonAction->setDefaultWidget(accountMenuButton);
-
- ui->mainToolBar->addAction(accountMenuButtonAction);
-
- // Update the menu when the active account changes.
- // Shouldn't have to use lambdas here like this, but if I don't, the compiler throws a fit.
- // Template hell sucks...
- connect(MMC->accounts().get(), &MojangAccountList::activeAccountChanged, [this]
- {
- activeAccountChanged();
- });
- connect(MMC->accounts().get(), &MojangAccountList::listChanged, [this]
- {
- repopulateAccountsMenu();
- });
-
- // Show initial account
- activeAccountChanged();
-
- auto accounts = MMC->accounts();
-
- QList<Net::Download::Ptr> skin_dls;
- for (int i = 0; i < accounts->count(); i++)
- {
- auto account = accounts->at(i);
- if (!account)
- {
- qWarning() << "Null account at index" << i;
- continue;
- }
- for (auto profile : account->profiles())
- {
- auto meta = Env::getInstance().metacache()->resolveEntry("skins", profile.id + ".png");
- auto action = Net::Download::makeCached(QUrl("https://" + URLConstants::SKINS_BASE + profile.id + ".png"), meta);
- skin_dls.append(action);
- meta->setStale(true);
- }
- }
- if (!skin_dls.isEmpty())
- {
- auto job = new NetJob("Startup player skins download");
- connect(job, &NetJob::succeeded, this, &MainWindow::skinJobFinished);
- connect(job, &NetJob::failed, this, &MainWindow::skinJobFinished);
- for (auto action : skin_dls)
- {
- job->addNetAction(action);
- }
- skin_download_job.reset(job);
- job->start();
- }
-
- // load the news
- {
- m_newsChecker->reloadNews();
- updateNewsLabel();
- }
-
-
- if(BuildConfig.UPDATER_ENABLED)
- {
- bool updatesAllowed = MMC->updatesAreAllowed();
- updatesAllowedChanged(updatesAllowed);
-
- connect(ui->actionCheckUpdate, &QAction::triggered, this, &MainWindow::checkForUpdates);
-
- // set up the updater object.
- auto updater = MMC->updateChecker();
- connect(updater.get(), &UpdateChecker::updateAvailable, this, &MainWindow::updateAvailable);
- connect(updater.get(), &UpdateChecker::noUpdateFound, this, &MainWindow::updateNotAvailable);
- // if automatic update checks are allowed, start one.
- if (MMC->settings()->get("AutoUpdate").toBool() && updatesAllowed)
- {
- updater->checkForUpdate(MMC->settings()->get("UpdateChannel").toString(), false);
- }
- }
-
- {
- auto checker = new NotificationChecker();
- checker->setNotificationsUrl(QUrl(BuildConfig.NOTIFICATION_URL));
- checker->setApplicationChannel(BuildConfig.VERSION_CHANNEL);
- checker->setApplicationPlatform(BuildConfig.BUILD_PLATFORM);
- checker->setApplicationFullVersion(BuildConfig.FULL_VERSION_STR);
- m_notificationChecker.reset(checker);
- connect(m_notificationChecker.get(), &NotificationChecker::notificationCheckFinished, this, &MainWindow::notificationsChanged);
- checker->checkForNotifications();
- }
-
- setSelectedInstanceById(MMC->settings()->get("SelectedInstance").toString());
-
- // removing this looks stupid
- view->setFocus();
+ ui->setupUi(this);
+
+ // OSX magic.
+ setUnifiedTitleAndToolBarOnMac(true);
+
+ // Global shortcuts
+ {
+ // 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()));
+ }
+
+ // Konami Code
+ {
+ secretEventFilter = new KonamiCode(this);
+ connect(secretEventFilter, &KonamiCode::triggered, this, &MainWindow::konamiTriggered);
+ }
+
+ // Add the news label to the news toolbar.
+ {
+ m_newsChecker.reset(new NewsChecker(BuildConfig.NEWS_RSS_URL));
+ newsLabel = new QToolButton();
+ newsLabel->setIcon(MMC->getThemedIcon("news"));
+ newsLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ newsLabel->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+ newsLabel->setFocusPolicy(Qt::NoFocus);
+ ui->newsToolBar->insertWidget(ui->actionMoreNews, newsLabel);
+ QObject::connect(newsLabel, &QAbstractButton::clicked, this, &MainWindow::newsButtonClicked);
+ QObject::connect(m_newsChecker.get(), &NewsChecker::newsLoaded, this, &MainWindow::updateNewsLabel);
+ updateNewsLabel();
+ }
+
+ // Create the instance list widget
+ {
+ view = new GroupView(ui->centralWidget);
+
+ view->setSelectionMode(QAbstractItemView::SingleSelection);
+ // FIXME: leaks ListViewDelegate
+ view->setItemDelegate(new ListViewDelegate(this));
+ view->setFrameShape(QFrame::NoFrame);
+ // do not show ugly blue border on the mac
+ view->setAttribute(Qt::WA_MacShowFocusRect, false);
+
+ view->installEventFilter(this);
+ view->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(view, &QWidget::customContextMenuRequested, this, &MainWindow::showInstanceContextMenu);
+ connect(view, &GroupView::droppedURLs, this, &MainWindow::droppedURLs, Qt::QueuedConnection);
+
+ proxymodel = new InstanceProxyModel(this);
+ proxymodel->setSourceModel(MMC->instances().get());
+ proxymodel->sort(0);
+ connect(proxymodel, &InstanceProxyModel::dataChanged, this, &MainWindow::instanceDataChanged);
+
+ view->setModel(proxymodel);
+ ui->horizontalLayout->addWidget(view);
+ }
+ // The cat background
+ {
+ bool cat_enable = MMC->settings()->get("TheCat").toBool();
+ ui->actionCAT->setChecked(cat_enable);
+ // NOTE: calling the operator like that is an ugly hack to appease ancient gcc...
+ connect(ui->actionCAT.operator->(), SIGNAL(toggled(bool)), SLOT(onCatToggled(bool)));
+ setCatBackground(cat_enable);
+ }
+ // start instance when double-clicked
+ connect(view, &GroupView::activated, this, &MainWindow::instanceActivated);
+
+ // track the selection -- update the instance toolbar
+ connect(view->selectionModel(), &QItemSelectionModel::currentChanged, this, &MainWindow::instanceChanged);
+
+ // track icon changes and update the toolbar!
+ connect(MMC->icons().get(), &IconList::iconUpdated, this, &MainWindow::iconUpdated);
+
+ // model reset -> selection is invalid. All the instance pointers are wrong.
+ connect(MMC->instances().get(), &InstanceList::dataIsInvalid, this, &MainWindow::selectionBad);
+
+ // handle newly added instances
+ connect(MMC->instances().get(), &InstanceList::instanceSelectRequest, this, &MainWindow::instanceSelectRequest);
+
+ // When the global settings page closes, we want to know about it and update our state
+ connect(MMC, &MultiMC::globalSettingsClosed, this, &MainWindow::globalSettingsClosed);
+
+ m_statusLeft = new QLabel(tr("No instance selected"), this);
+ m_statusRight = new ServerStatus(this);
+ statusBar()->addPermanentWidget(m_statusLeft, 1);
+ statusBar()->addPermanentWidget(m_statusRight, 0);
+
+ // Add "manage accounts" button, right align
+ QWidget *spacer = new QWidget();
+ spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ ui->mainToolBar->addWidget(spacer);
+
+ accountMenu = new QMenu(this);
+
+ repopulateAccountsMenu();
+
+ accountMenuButton = new QToolButton(this);
+ accountMenuButton->setText(tr("Profiles"));
+ accountMenuButton->setMenu(accountMenu);
+ accountMenuButton->setPopupMode(QToolButton::InstantPopup);
+ accountMenuButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+ accountMenuButton->setIcon(MMC->getThemedIcon("noaccount"));
+
+ QWidgetAction *accountMenuButtonAction = new QWidgetAction(this);
+ accountMenuButtonAction->setDefaultWidget(accountMenuButton);
+
+ ui->mainToolBar->addAction(accountMenuButtonAction);
+
+ // Update the menu when the active account changes.
+ // Shouldn't have to use lambdas here like this, but if I don't, the compiler throws a fit.
+ // Template hell sucks...
+ connect(MMC->accounts().get(), &MojangAccountList::activeAccountChanged, [this]
+ {
+ activeAccountChanged();
+ });
+ connect(MMC->accounts().get(), &MojangAccountList::listChanged, [this]
+ {
+ repopulateAccountsMenu();
+ });
+
+ // Show initial account
+ activeAccountChanged();
+
+ auto accounts = MMC->accounts();
+
+ QList<Net::Download::Ptr> skin_dls;
+ for (int i = 0; i < accounts->count(); i++)
+ {
+ auto account = accounts->at(i);
+ if (!account)
+ {
+ qWarning() << "Null account at index" << i;
+ continue;
+ }
+ for (auto profile : account->profiles())
+ {
+ auto meta = Env::getInstance().metacache()->resolveEntry("skins", profile.id + ".png");
+ auto action = Net::Download::makeCached(QUrl(URLConstants::SKINS_BASE + profile.id + ".png"), meta);
+ skin_dls.append(action);
+ meta->setStale(true);
+ }
+ }
+ if (!skin_dls.isEmpty())
+ {
+ auto job = new NetJob("Startup player skins download");
+ connect(job, &NetJob::succeeded, this, &MainWindow::skinJobFinished);
+ connect(job, &NetJob::failed, this, &MainWindow::skinJobFinished);
+ for (auto action : skin_dls)
+ {
+ job->addNetAction(action);
+ }
+ skin_download_job.reset(job);
+ job->start();
+ }
+
+ // load the news
+ {
+ m_newsChecker->reloadNews();
+ updateNewsLabel();
+ }
+
+
+ if(BuildConfig.UPDATER_ENABLED)
+ {
+ bool updatesAllowed = MMC->updatesAreAllowed();
+ updatesAllowedChanged(updatesAllowed);
+
+ // NOTE: calling the operator like that is an ugly hack to appease ancient gcc...
+ connect(ui->actionCheckUpdate.operator->(), &QAction::triggered, this, &MainWindow::checkForUpdates);
+
+ // set up the updater object.
+ auto updater = MMC->updateChecker();
+ connect(updater.get(), &UpdateChecker::updateAvailable, this, &MainWindow::updateAvailable);
+ connect(updater.get(), &UpdateChecker::noUpdateFound, this, &MainWindow::updateNotAvailable);
+ // if automatic update checks are allowed, start one.
+ if (MMC->settings()->get("AutoUpdate").toBool() && updatesAllowed)
+ {
+ updater->checkForUpdate(MMC->settings()->get("UpdateChannel").toString(), false);
+ }
+ }
+
+ {
+ auto checker = new NotificationChecker();
+ checker->setNotificationsUrl(QUrl(BuildConfig.NOTIFICATION_URL));
+ checker->setApplicationChannel(BuildConfig.VERSION_CHANNEL);
+ checker->setApplicationPlatform(BuildConfig.BUILD_PLATFORM);
+ checker->setApplicationFullVersion(BuildConfig.FULL_VERSION_STR);
+ m_notificationChecker.reset(checker);
+ connect(m_notificationChecker.get(), &NotificationChecker::notificationCheckFinished, this, &MainWindow::notificationsChanged);
+ checker->checkForNotifications();
+ }
+
+ setSelectedInstanceById(MMC->settings()->get("SelectedInstance").toString());
+
+ // removing this looks stupid
+ view->setFocus();
}
MainWindow::~MainWindow()
{
}
+QMenu * MainWindow::createPopupMenu()
+{
+ QMenu* filteredMenu = QMainWindow::createPopupMenu();
+ filteredMenu->removeAction( ui->mainToolBar->toggleViewAction() );
+ return filteredMenu;
+}
+
void MainWindow::konamiTriggered()
{
- qDebug() << "Super Secret Mode ACTIVATED!";
+ // ENV.enableFeature("NewModsPage");
+ qDebug() << "Super Secret Mode ACTIVATED!";
}
void MainWindow::skinJobFinished()
{
- activeAccountChanged();
- skin_download_job.reset();
+ activeAccountChanged();
+ skin_download_job.reset();
}
void MainWindow::showInstanceContextMenu(const QPoint &pos)
{
- QList<QAction *> actions;
-
- QAction *actionSep = new QAction("", this);
- actionSep->setSeparator(true);
-
- bool onInstance = view->indexAt(pos).isValid();
- if (onInstance)
- {
- actions = ui->instanceToolBar->actions();
-
- // replace the change icon widget with an actual action
- actions.replace(0, ui->actionChangeInstIcon);
-
- // replace the rename widget with an actual action
- actions.replace(1, ui->actionRenameInstance);
-
- // add header
- actions.prepend(actionSep);
- QAction *actionVoid = new QAction(m_selectedInstance->name(), this);
- actionVoid->setEnabled(false);
- actions.prepend(actionVoid);
- }
- else
- {
- auto group = view->groupNameAt(pos);
-
- QAction *actionVoid = new QAction("MultiMC", this);
- actionVoid->setEnabled(false);
-
- QAction *actionCreateInstance = new QAction(tr("Create instance"), this);
- actionCreateInstance->setToolTip(ui->actionAddInstance->toolTip());
- if(!group.isNull())
- {
- QVariantMap data;
- data["group"] = group;
- actionCreateInstance->setData(data);
- }
-
- connect(actionCreateInstance, SIGNAL(triggered(bool)), SLOT(on_actionAddInstance_triggered()));
-
- actions.prepend(actionSep);
- actions.prepend(actionVoid);
- actions.append(actionCreateInstance);
- if(!group.isNull())
- {
- QAction *actionDeleteGroup = new QAction(tr("Delete group '%1'").arg(group), this);
- QVariantMap data;
- data["group"] = group;
- actionDeleteGroup->setData(data);
- connect(actionDeleteGroup, SIGNAL(triggered(bool)), SLOT(deleteGroup()));
- actions.append(actionDeleteGroup);
- }
- }
- QMenu myMenu;
- myMenu.addActions(actions);
- /*
- if (onInstance)
- myMenu.setEnabled(m_selectedInstance->canLaunch());
- */
- myMenu.exec(view->mapToGlobal(pos));
+ QList<QAction *> actions;
+
+ QAction *actionSep = new QAction("", this);
+ actionSep->setSeparator(true);
+
+ bool onInstance = view->indexAt(pos).isValid();
+ if (onInstance)
+ {
+ actions = ui->instanceToolBar->actions();
+
+ // replace the change icon widget with an actual action
+ actions.replace(0, ui->actionChangeInstIcon);
+
+ // replace the rename widget with an actual action
+ actions.replace(1, ui->actionRenameInstance);
+
+ // add header
+ actions.prepend(actionSep);
+ QAction *actionVoid = new QAction(m_selectedInstance->name(), this);
+ actionVoid->setEnabled(false);
+ actions.prepend(actionVoid);
+ }
+ else
+ {
+ auto group = view->groupNameAt(pos);
+
+ QAction *actionVoid = new QAction("MultiMC", this);
+ actionVoid->setEnabled(false);
+
+ QAction *actionCreateInstance = new QAction(tr("Create instance"), this);
+ actionCreateInstance->setToolTip(ui->actionAddInstance->toolTip());
+ if(!group.isNull())
+ {
+ QVariantMap data;
+ data["group"] = group;
+ actionCreateInstance->setData(data);
+ }
+
+ connect(actionCreateInstance, SIGNAL(triggered(bool)), SLOT(on_actionAddInstance_triggered()));
+
+ actions.prepend(actionSep);
+ actions.prepend(actionVoid);
+ actions.append(actionCreateInstance);
+ if(!group.isNull())
+ {
+ QAction *actionDeleteGroup = new QAction(tr("Delete group '%1'").arg(group), this);
+ QVariantMap data;
+ data["group"] = group;
+ actionDeleteGroup->setData(data);
+ connect(actionDeleteGroup, SIGNAL(triggered(bool)), SLOT(deleteGroup()));
+ actions.append(actionDeleteGroup);
+ }
+ }
+ QMenu myMenu;
+ myMenu.addActions(actions);
+ /*
+ if (onInstance)
+ myMenu.setEnabled(m_selectedInstance->canLaunch());
+ */
+ myMenu.exec(view->mapToGlobal(pos));
}
void MainWindow::updateToolsMenu()
{
- QToolButton *launchButton = dynamic_cast<QToolButton*>(ui->instanceToolBar->widgetForAction(ui->actionLaunchInstance));
- if(!m_selectedInstance || m_selectedInstance->isRunning())
- {
- ui->actionLaunchInstance->setMenu(nullptr);
- launchButton->setPopupMode(QToolButton::InstantPopup);
- return;
- }
-
- QMenu *launchMenu = ui->actionLaunchInstance->menu();
- launchButton->setPopupMode(QToolButton::MenuButtonPopup);
- if (launchMenu)
- {
- launchMenu->clear();
- }
- else
- {
- launchMenu = new QMenu(this);
- }
-
- QAction *normalLaunch = launchMenu->addAction(tr("Launch"));
- connect(normalLaunch, &QAction::triggered, [this]()
- {
- MMC->launch(m_selectedInstance);
- });
- launchMenu->addSeparator()->setText(tr("Profilers"));
- for (auto profiler : MMC->profilers().values())
- {
- QAction *profilerAction = launchMenu->addAction(profiler->name());
- QString error;
- if (!profiler->check(&error))
- {
- profilerAction->setDisabled(true);
- profilerAction->setToolTip(tr("Profiler not setup correctly. Go into settings, \"External Tools\"."));
- }
- else
- {
- connect(profilerAction, &QAction::triggered, [this, profiler]()
- {
- MMC->launch(m_selectedInstance, true, profiler.get());
- });
- }
- }
- ui->actionLaunchInstance->setMenu(launchMenu);
+ QToolButton *launchButton = dynamic_cast<QToolButton*>(ui->instanceToolBar->widgetForAction(ui->actionLaunchInstance));
+ QToolButton *launchOfflineButton = dynamic_cast<QToolButton*>(ui->instanceToolBar->widgetForAction(ui->actionLaunchInstanceOffline));
+
+ if(!m_selectedInstance || m_selectedInstance->isRunning())
+ {
+ ui->actionLaunchInstance->setMenu(nullptr);
+ ui->actionLaunchInstanceOffline->setMenu(nullptr);
+ launchButton->setPopupMode(QToolButton::InstantPopup);
+ launchOfflineButton->setPopupMode(QToolButton::InstantPopup);
+ return;
+ }
+
+ QMenu *launchMenu = ui->actionLaunchInstance->menu();
+ QMenu *launchOfflineMenu = ui->actionLaunchInstanceOffline->menu();
+ launchButton->setPopupMode(QToolButton::MenuButtonPopup);
+ launchOfflineButton->setPopupMode(QToolButton::MenuButtonPopup);
+ if (launchMenu)
+ {
+ launchMenu->clear();
+ }
+ else
+ {
+ launchMenu = new QMenu(this);
+ }
+ if (launchOfflineMenu) {
+ launchOfflineMenu->clear();
+ }
+ else
+ {
+ launchOfflineMenu = new QMenu(this);
+ }
+
+ QAction *normalLaunch = launchMenu->addAction(tr("Launch"));
+ QAction *normalLaunchOffline = launchOfflineMenu->addAction(tr("Launch Offline"));
+ connect(normalLaunch, &QAction::triggered, [this]()
+ {
+ MMC->launch(m_selectedInstance, true);
+ });
+ connect(normalLaunchOffline, &QAction::triggered, [this]()
+ {
+ MMC->launch(m_selectedInstance, false);
+ });
+ QString profilersTitle = tr("Profilers");
+ launchMenu->addSeparator()->setText(profilersTitle);
+ launchOfflineMenu->addSeparator()->setText(profilersTitle);
+ for (auto profiler : MMC->profilers().values())
+ {
+ QAction *profilerAction = launchMenu->addAction(profiler->name());
+ QAction *profilerOfflineAction = launchOfflineMenu->addAction(profiler->name());
+ QString error;
+ if (!profiler->check(&error))
+ {
+ profilerAction->setDisabled(true);
+ profilerOfflineAction->setDisabled(true);
+ QString profilerToolTip = tr("Profiler not setup correctly. Go into settings, \"External Tools\".");
+ profilerAction->setToolTip(profilerToolTip);
+ profilerOfflineAction->setToolTip(profilerToolTip);
+ }
+ else
+ {
+ connect(profilerAction, &QAction::triggered, [this, profiler]()
+ {
+ MMC->launch(m_selectedInstance, true, profiler.get());
+ });
+ connect(profilerOfflineAction, &QAction::triggered, [this, profiler]()
+ {
+ MMC->launch(m_selectedInstance, false, profiler.get());
+ });
+ }
+ }
+ ui->actionLaunchInstance->setMenu(launchMenu);
+ ui->actionLaunchInstanceOffline->setMenu(launchOfflineMenu);
}
QString profileInUseFilter(const QString & profile, bool used)
{
- if(used)
- {
- return profile + QObject::tr(" (in use)");
- }
- else
- {
- return profile;
- }
+ if(used)
+ {
+ return profile + QObject::tr(" (in use)");
+ }
+ else
+ {
+ return profile;
+ }
}
void MainWindow::repopulateAccountsMenu()
{
- accountMenu->clear();
-
- std::shared_ptr<MojangAccountList> accounts = MMC->accounts();
- MojangAccountPtr active_account = accounts->activeAccount();
-
- QString active_username = "";
- if (active_account != nullptr)
- {
- active_username = active_account->username();
- const AccountProfile *profile = active_account->currentProfile();
- // this can be called before accountMenuButton exists
- if (profile != nullptr && accountMenuButton)
- {
- auto profileLabel = profileInUseFilter(profile->name, active_account->isInUse());
- accountMenuButton->setText(profileLabel);
- }
- }
-
- if (accounts->count() <= 0)
- {
- QAction *action = new QAction(tr("No accounts added!"), this);
- action->setEnabled(false);
- accountMenu->addAction(action);
- }
- else
- {
- // TODO: Nicer way to iterate?
- for (int i = 0; i < accounts->count(); i++)
- {
- MojangAccountPtr account = accounts->at(i);
- for (auto profile : account->profiles())
- {
- auto profileLabel = profileInUseFilter(profile.name, account->isInUse());
- QAction *action = new QAction(profileLabel, this);
- action->setData(account->username());
- action->setCheckable(true);
- if (active_username == account->username())
- {
- action->setChecked(true);
- }
-
- action->setIcon(SkinUtils::getFaceFromCache(profile.id));
- accountMenu->addAction(action);
- connect(action, SIGNAL(triggered(bool)), SLOT(changeActiveAccount()));
- }
- }
- }
-
- accountMenu->addSeparator();
-
- QAction *action = new QAction(tr("No Default Account"), this);
- action->setCheckable(true);
- action->setIcon(MMC->getThemedIcon("noaccount"));
- action->setData("");
- if (active_username.isEmpty())
- {
- action->setChecked(true);
- }
-
- accountMenu->addAction(action);
- connect(action, SIGNAL(triggered(bool)), SLOT(changeActiveAccount()));
-
- accountMenu->addSeparator();
- accountMenu->addAction(ui->actionManageAccounts);
+ accountMenu->clear();
+
+ std::shared_ptr<MojangAccountList> accounts = MMC->accounts();
+ MojangAccountPtr active_account = accounts->activeAccount();
+
+ QString active_username = "";
+ if (active_account != nullptr)
+ {
+ active_username = active_account->username();
+ const AccountProfile *profile = active_account->currentProfile();
+ // this can be called before accountMenuButton exists
+ if (profile != nullptr && accountMenuButton)
+ {
+ auto profileLabel = profileInUseFilter(profile->name, active_account->isInUse());
+ accountMenuButton->setText(profileLabel);
+ }
+ }
+
+ if (accounts->count() <= 0)
+ {
+ QAction *action = new QAction(tr("No accounts added!"), this);
+ action->setEnabled(false);
+ accountMenu->addAction(action);
+ }
+ else
+ {
+ // TODO: Nicer way to iterate?
+ for (int i = 0; i < accounts->count(); i++)
+ {
+ MojangAccountPtr account = accounts->at(i);
+ for (auto profile : account->profiles())
+ {
+ auto profileLabel = profileInUseFilter(profile.name, account->isInUse());
+ QAction *action = new QAction(profileLabel, this);
+ action->setData(account->username());
+ action->setCheckable(true);
+ if (active_username == account->username())
+ {
+ action->setChecked(true);
+ }
+
+ action->setIcon(SkinUtils::getFaceFromCache(profile.id));
+ accountMenu->addAction(action);
+ connect(action, SIGNAL(triggered(bool)), SLOT(changeActiveAccount()));
+ }
+ }
+ }
+
+ accountMenu->addSeparator();
+
+ QAction *action = new QAction(tr("No Default Account"), this);
+ action->setCheckable(true);
+ action->setIcon(MMC->getThemedIcon("noaccount"));
+ action->setData("");
+ if (active_username.isEmpty())
+ {
+ action->setChecked(true);
+ }
+
+ accountMenu->addAction(action);
+ connect(action, SIGNAL(triggered(bool)), SLOT(changeActiveAccount()));
+
+ accountMenu->addSeparator();
+ accountMenu->addAction(ui->actionManageAccounts);
}
void MainWindow::updatesAllowedChanged(bool allowed)
{
- if(!BuildConfig.UPDATER_ENABLED)
- {
- return;
- }
- ui->actionCheckUpdate->setEnabled(allowed);
+ if(!BuildConfig.UPDATER_ENABLED)
+ {
+ return;
+ }
+ ui->actionCheckUpdate->setEnabled(allowed);
}
/*
@@ -1030,799 +1083,825 @@ void MainWindow::updatesAllowedChanged(bool allowed)
*/
void MainWindow::changeActiveAccount()
{
- QAction *sAction = (QAction *)sender();
- // Profile's associated Mojang username
- // Will need to change when profiles are properly implemented
- if (sAction->data().type() != QVariant::Type::String)
- return;
+ QAction *sAction = (QAction *)sender();
+ // Profile's associated Mojang username
+ // Will need to change when profiles are properly implemented
+ if (sAction->data().type() != QVariant::Type::String)
+ return;
- QVariant data = sAction->data();
- QString id = "";
- if (!data.isNull())
- {
- id = data.toString();
- }
+ QVariant data = sAction->data();
+ QString id = "";
+ if (!data.isNull())
+ {
+ id = data.toString();
+ }
- MMC->accounts()->setActiveAccount(id);
+ MMC->accounts()->setActiveAccount(id);
- activeAccountChanged();
+ activeAccountChanged();
}
void MainWindow::activeAccountChanged()
{
- repopulateAccountsMenu();
+ repopulateAccountsMenu();
- MojangAccountPtr account = MMC->accounts()->activeAccount();
+ MojangAccountPtr account = MMC->accounts()->activeAccount();
- if (account != nullptr && account->username() != "")
- {
- const AccountProfile *profile = account->currentProfile();
- if (profile != nullptr)
- {
- auto profileLabel = profileInUseFilter(profile->name, account->isInUse());
- accountMenuButton->setIcon(SkinUtils::getFaceFromCache(profile->id));
- accountMenuButton->setText(profileLabel);
- return;
- }
- }
+ if (account != nullptr && account->username() != "")
+ {
+ const AccountProfile *profile = account->currentProfile();
+ if (profile != nullptr)
+ {
+ auto profileLabel = profileInUseFilter(profile->name, account->isInUse());
+ accountMenuButton->setIcon(SkinUtils::getFaceFromCache(profile->id));
+ accountMenuButton->setText(profileLabel);
+ return;
+ }
+ }
- // Set the icon to the "no account" icon.
- accountMenuButton->setIcon(MMC->getThemedIcon("noaccount"));
- accountMenuButton->setText(tr("Profiles"));
+ // Set the icon to the "no account" icon.
+ accountMenuButton->setIcon(MMC->getThemedIcon("noaccount"));
+ accountMenuButton->setText(tr("Profiles"));
}
bool MainWindow::eventFilter(QObject *obj, QEvent *ev)
{
- if (obj == view)
- {
- if (ev->type() == QEvent::KeyPress)
- {
- secretEventFilter->input(ev);
- QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
- switch (keyEvent->key())
- {
- case Qt::Key_Enter:
- case Qt::Key_Return:
- activateInstance(m_selectedInstance);
- return true;
- case Qt::Key_Delete:
- on_actionDeleteInstance_triggered();
- return true;
- case Qt::Key_F5:
- refreshInstances();
- return true;
- case Qt::Key_F2:
- on_actionRenameInstance_triggered();
- return true;
- default:
- break;
- }
- }
- }
- return QMainWindow::eventFilter(obj, ev);
+ if (obj == view)
+ {
+ if (ev->type() == QEvent::KeyPress)
+ {
+ secretEventFilter->input(ev);
+ QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
+ switch (keyEvent->key())
+ {
+ /*
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ activateInstance(m_selectedInstance);
+ return true;
+ */
+ case Qt::Key_Delete:
+ on_actionDeleteInstance_triggered();
+ return true;
+ case Qt::Key_F5:
+ refreshInstances();
+ return true;
+ case Qt::Key_F2:
+ on_actionRenameInstance_triggered();
+ return true;
+ default:
+ break;
+ }
+ }
+ }
+ return QMainWindow::eventFilter(obj, ev);
}
void MainWindow::updateNewsLabel()
{
- if (m_newsChecker->isLoadingNews())
- {
- newsLabel->setText(tr("Loading news..."));
- newsLabel->setEnabled(false);
- }
- else
- {
- QList<NewsEntryPtr> entries = m_newsChecker->getNewsEntries();
- if (entries.length() > 0)
- {
- newsLabel->setText(entries[0]->title);
- newsLabel->setEnabled(true);
- }
- else
- {
- newsLabel->setText(tr("No news available."));
- newsLabel->setEnabled(false);
- }
- }
+ if (m_newsChecker->isLoadingNews())
+ {
+ newsLabel->setText(tr("Loading news..."));
+ newsLabel->setEnabled(false);
+ }
+ else
+ {
+ QList<NewsEntryPtr> entries = m_newsChecker->getNewsEntries();
+ if (entries.length() > 0)
+ {
+ newsLabel->setText(entries[0]->title);
+ newsLabel->setEnabled(true);
+ }
+ else
+ {
+ newsLabel->setText(tr("No news available."));
+ newsLabel->setEnabled(false);
+ }
+ }
}
void MainWindow::updateAvailable(GoUpdate::Status status)
{
- if(!MMC->updatesAreAllowed())
- {
- updateNotAvailable();
- return;
- }
- UpdateDialog dlg(true, this);
- UpdateAction action = (UpdateAction)dlg.exec();
- switch (action)
- {
- case UPDATE_LATER:
- qDebug() << "Update will be installed later.";
- break;
- case UPDATE_NOW:
- downloadUpdates(status);
- break;
- }
+ if(!MMC->updatesAreAllowed())
+ {
+ updateNotAvailable();
+ return;
+ }
+ UpdateDialog dlg(true, this);
+ UpdateAction action = (UpdateAction)dlg.exec();
+ switch (action)
+ {
+ case UPDATE_LATER:
+ qDebug() << "Update will be installed later.";
+ break;
+ case UPDATE_NOW:
+ downloadUpdates(status);
+ break;
+ }
}
void MainWindow::updateNotAvailable()
{
- UpdateDialog dlg(false, this);
- dlg.exec();
+ UpdateDialog dlg(false, this);
+ dlg.exec();
}
QList<int> stringToIntList(const QString &string)
{
- QStringList split = string.split(',', QString::SkipEmptyParts);
- QList<int> out;
- for (int i = 0; i < split.size(); ++i)
- {
- out.append(split.at(i).toInt());
- }
- return out;
+ QStringList split = string.split(',', QString::SkipEmptyParts);
+ QList<int> out;
+ for (int i = 0; i < split.size(); ++i)
+ {
+ out.append(split.at(i).toInt());
+ }
+ return out;
}
QString intListToString(const QList<int> &list)
{
- QStringList slist;
- for (int i = 0; i < list.size(); ++i)
- {
- slist.append(QString::number(list.at(i)));
- }
- return slist.join(',');
+ QStringList slist;
+ for (int i = 0; i < list.size(); ++i)
+ {
+ slist.append(QString::number(list.at(i)));
+ }
+ return slist.join(',');
}
void MainWindow::notificationsChanged()
{
- QList<NotificationChecker::NotificationEntry> entries = m_notificationChecker->notificationEntries();
- QList<int> shownNotifications = stringToIntList(MMC->settings()->get("ShownNotifications").toString());
- for (auto it = entries.begin(); it != entries.end(); ++it)
- {
- NotificationChecker::NotificationEntry entry = *it;
- if (!shownNotifications.contains(entry.id))
- {
- NotificationDialog dialog(entry, this);
- if (dialog.exec() == NotificationDialog::DontShowAgain)
- {
- shownNotifications.append(entry.id);
- }
- }
- }
- MMC->settings()->set("ShownNotifications", intListToString(shownNotifications));
+ QList<NotificationChecker::NotificationEntry> entries = m_notificationChecker->notificationEntries();
+ QList<int> shownNotifications = stringToIntList(MMC->settings()->get("ShownNotifications").toString());
+ for (auto it = entries.begin(); it != entries.end(); ++it)
+ {
+ NotificationChecker::NotificationEntry entry = *it;
+ if (!shownNotifications.contains(entry.id))
+ {
+ NotificationDialog dialog(entry, this);
+ if (dialog.exec() == NotificationDialog::DontShowAgain)
+ {
+ shownNotifications.append(entry.id);
+ }
+ }
+ }
+ MMC->settings()->set("ShownNotifications", intListToString(shownNotifications));
}
void MainWindow::downloadUpdates(GoUpdate::Status status)
{
- if(!MMC->updatesAreAllowed())
- {
- return;
- }
- qDebug() << "Downloading updates.";
- ProgressDialog updateDlg(this);
- status.rootPath = MMC->root();
-
- auto dlPath = FS::PathCombine(MMC->root(), "update", "XXXXXX");
- if (!FS::ensureFilePathExists(dlPath))
- {
- CustomMessageBox::selectable(this, tr("Error"), tr("Couldn't create folder for update downloads:\n%1").arg(dlPath), QMessageBox::Warning)->show();
- }
- GoUpdate::DownloadTask updateTask(status, dlPath, &updateDlg);
- // If the task succeeds, install the updates.
- if (updateDlg.execWithTask(&updateTask))
- {
- /**
- * NOTE: This disables launching instances until the update either succeeds (and this process exits)
- * or the update fails (and the control leaves this scope).
- */
- MMC->updateIsRunning(true);
- UpdateController update(this, MMC->root(), updateTask.updateFilesDir(), updateTask.operations());
- update.installUpdates();
- MMC->updateIsRunning(false);
- }
- else
- {
- CustomMessageBox::selectable(this, tr("Error"), updateTask.failReason(), QMessageBox::Warning)->show();
- }
+ if(!MMC->updatesAreAllowed())
+ {
+ return;
+ }
+ qDebug() << "Downloading updates.";
+ ProgressDialog updateDlg(this);
+ status.rootPath = MMC->root();
+
+ auto dlPath = FS::PathCombine(MMC->root(), "update", "XXXXXX");
+ if (!FS::ensureFilePathExists(dlPath))
+ {
+ CustomMessageBox::selectable(this, tr("Error"), tr("Couldn't create folder for update downloads:\n%1").arg(dlPath), QMessageBox::Warning)->show();
+ }
+ GoUpdate::DownloadTask updateTask(status, dlPath, &updateDlg);
+ // If the task succeeds, install the updates.
+ if (updateDlg.execWithTask(&updateTask))
+ {
+ /**
+ * NOTE: This disables launching instances until the update either succeeds (and this process exits)
+ * or the update fails (and the control leaves this scope).
+ */
+ MMC->updateIsRunning(true);
+ UpdateController update(this, MMC->root(), updateTask.updateFilesDir(), updateTask.operations());
+ update.installUpdates();
+ MMC->updateIsRunning(false);
+ }
+ else
+ {
+ CustomMessageBox::selectable(this, tr("Error"), updateTask.failReason(), QMessageBox::Warning)->show();
+ }
}
void MainWindow::onCatToggled(bool state)
{
- setCatBackground(state);
- MMC->settings()->set("TheCat", state);
+ setCatBackground(state);
+ MMC->settings()->set("TheCat", state);
+}
+
+namespace {
+template <typename T>
+T non_stupid_abs(T in)
+{
+ if (in < 0)
+ return -in;
+ return in;
+}
}
void MainWindow::setCatBackground(bool enabled)
{
- if (enabled)
- {
- view->setStyleSheet("GroupView"
- "{"
- "background-image: url(:/backgrounds/kitteh);"
- "background-attachment: fixed;"
- "background-clip: padding;"
- "background-position: top right;"
- "background-repeat: none;"
- "background-color:palette(base);"
- "}");
- }
- else
- {
- view->setStyleSheet(QString());
- }
+ if (enabled)
+ {
+ QDateTime now = QDateTime::currentDateTime();
+ QDateTime xmas(QDate(now.date().year(), 12, 25), QTime(0, 0));
+ ;
+ QString cat = (non_stupid_abs(now.daysTo(xmas)) <= 4) ? "catmas" : "kitteh";
+ view->setStyleSheet(QString(R"(
+GroupView
+{
+ background-image: url(:/backgrounds/%1);
+ background-attachment: fixed;
+ background-clip: padding;
+ background-position: top right;
+ background-repeat: none;
+ background-color:palette(base);
+})").arg(cat));
+ }
+ else
+ {
+ view->setStyleSheet(QString());
+ }
}
void MainWindow::runModalTask(Task *task)
{
- connect(task, &Task::failed, [this](QString reason)
- {
- CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
- });
- connect(task, &Task::succeeded, [this, task]()
- {
- QStringList warnings = task->warnings();
- if(warnings.count())
- {
- CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show();
- }
- });
- ProgressDialog loadDialog(this);
- loadDialog.setSkipButton(true, tr("Abort"));
- loadDialog.execWithTask(task);
+ connect(task, &Task::failed, [this](QString reason)
+ {
+ CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
+ });
+ connect(task, &Task::succeeded, [this, task]()
+ {
+ QStringList warnings = task->warnings();
+ if(warnings.count())
+ {
+ CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show();
+ }
+ });
+ ProgressDialog loadDialog(this);
+ loadDialog.setSkipButton(true, tr("Abort"));
+ loadDialog.execWithTask(task);
}
void MainWindow::instanceFromInstanceTask(InstanceTask *rawTask)
{
- std::unique_ptr<Task> task(MMC->folderProvider()->wrapInstanceTask(rawTask));
- runModalTask(task.get());
-
- // FIXME: handle instance selection after creation
- // finalizeInstance(newInstance);
+ unique_qobject_ptr<Task> task(MMC->instances()->wrapInstanceTask(rawTask));
+ runModalTask(task.get());
}
void MainWindow::on_actionCopyInstance_triggered()
{
- if (!m_selectedInstance)
- return;
+ if (!m_selectedInstance)
+ return;
- CopyInstanceDialog copyInstDlg(m_selectedInstance, this);
- if (!copyInstDlg.exec())
- return;
+ CopyInstanceDialog copyInstDlg(m_selectedInstance, this);
+ if (!copyInstDlg.exec())
+ return;
- auto copyTask = new InstanceCopyTask(m_selectedInstance, copyInstDlg.shouldCopySaves());
- copyTask->setName(copyInstDlg.instName());
- copyTask->setGroup(copyInstDlg.instGroup());
- copyTask->setIcon(copyInstDlg.iconKey());
- std::unique_ptr<Task> task(MMC->folderProvider()->wrapInstanceTask(copyTask));
- runModalTask(task.get());
-
- // FIXME: handle instance selection after creation
- // finalizeInstance(newInstance);
+ auto copyTask = new InstanceCopyTask(m_selectedInstance, copyInstDlg.shouldCopySaves());
+ copyTask->setName(copyInstDlg.instName());
+ copyTask->setGroup(copyInstDlg.instGroup());
+ copyTask->setIcon(copyInstDlg.iconKey());
+ unique_qobject_ptr<Task> task(MMC->instances()->wrapInstanceTask(copyTask));
+ runModalTask(task.get());
}
void MainWindow::finalizeInstance(InstancePtr inst)
{
- view->updateGeometries();
- setSelectedInstanceById(inst->id());
- if (MMC->accounts()->anyAccountIsValid())
- {
- ProgressDialog loadDialog(this);
- auto update = inst->createUpdateTask(Net::Mode::Online);
- connect(update.get(), &Task::failed, [this](QString reason)
- {
- QString error = QString("Instance load failed: %1").arg(reason);
- CustomMessageBox::selectable(this, tr("Error"), error, QMessageBox::Warning)->show();
- });
- if(update)
- {
- loadDialog.setSkipButton(true, tr("Abort"));
- loadDialog.execWithTask(update.get());
- }
- }
- else
- {
- 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();
- }
+ view->updateGeometries();
+ setSelectedInstanceById(inst->id());
+ if (MMC->accounts()->anyAccountIsValid())
+ {
+ ProgressDialog loadDialog(this);
+ auto update = inst->createUpdateTask(Net::Mode::Online);
+ connect(update.get(), &Task::failed, [this](QString reason)
+ {
+ QString error = QString("Instance load failed: %1").arg(reason);
+ CustomMessageBox::selectable(this, tr("Error"), error, QMessageBox::Warning)->show();
+ });
+ if(update)
+ {
+ loadDialog.setSkipButton(true, tr("Abort"));
+ loadDialog.execWithTask(update.get());
+ }
+ }
+ else
+ {
+ 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();
+ }
}
void MainWindow::addInstance(QString url)
{
- QString groupName;
- do
- {
- QObject* obj = sender();
- if(!obj)
- break;
- QAction *action = qobject_cast<QAction *>(obj);
- if(!action)
- break;
- auto map = action->data().toMap();
- if(!map.contains("group"))
- break;
- groupName = map["group"].toString();
- } while(0);
-
- if(groupName.isEmpty())
- {
- groupName = MMC->settings()->get("LastUsedGroupForNewInstance").toString();
- }
-
- NewInstanceDialog newInstDlg(groupName, url, this);
- if (!newInstDlg.exec())
- return;
-
- MMC->settings()->set("LastUsedGroupForNewInstance", newInstDlg.instGroup());
-
- InstanceTask * creationTask = newInstDlg.extractTask();
- if(creationTask)
- {
- instanceFromInstanceTask(creationTask);
- }
+ QString groupName;
+ do
+ {
+ QObject* obj = sender();
+ if(!obj)
+ break;
+ QAction *action = qobject_cast<QAction *>(obj);
+ if(!action)
+ break;
+ auto map = action->data().toMap();
+ if(!map.contains("group"))
+ break;
+ groupName = map["group"].toString();
+ } while(0);
+
+ if(groupName.isEmpty())
+ {
+ groupName = MMC->settings()->get("LastUsedGroupForNewInstance").toString();
+ }
+
+ NewInstanceDialog newInstDlg(groupName, url, this);
+ if (!newInstDlg.exec())
+ return;
+
+ MMC->settings()->set("LastUsedGroupForNewInstance", newInstDlg.instGroup());
+
+ InstanceTask * creationTask = newInstDlg.extractTask();
+ if(creationTask)
+ {
+ instanceFromInstanceTask(creationTask);
+ }
}
void MainWindow::on_actionAddInstance_triggered()
{
- addInstance();
+ addInstance();
}
void MainWindow::droppedURLs(QList<QUrl> urls)
{
- for(auto & url:urls)
- {
- if(url.isLocalFile())
- {
- addInstance(url.toLocalFile());
- }
- else
- {
- addInstance(url.toString());
- }
- // Only process one dropped file...
- break;
- }
+ for(auto & url:urls)
+ {
+ if(url.isLocalFile())
+ {
+ addInstance(url.toLocalFile());
+ }
+ else
+ {
+ addInstance(url.toString());
+ }
+ // Only process one dropped file...
+ break;
+ }
}
void MainWindow::on_actionREDDIT_triggered()
{
- DesktopServices::openUrl(QUrl("https://www.reddit.com/r/MultiMC/"));
+ DesktopServices::openUrl(QUrl("https://www.reddit.com/r/MultiMC/"));
}
void MainWindow::on_actionDISCORD_triggered()
{
- DesktopServices::openUrl(QUrl("https://discord.gg/0k2zsXGNHs0fE4Wm"));
+ DesktopServices::openUrl(QUrl("https://discord.gg/0k2zsXGNHs0fE4Wm"));
}
void MainWindow::on_actionChangeInstIcon_triggered()
{
- if (!m_selectedInstance)
- return;
+ if (!m_selectedInstance)
+ return;
- IconPickerDialog dlg(this);
- dlg.execWithSelection(m_selectedInstance->iconKey());
- if (dlg.result() == QDialog::Accepted)
- {
- m_selectedInstance->setIconKey(dlg.selectedIconKey);
- auto icon = MMC->icons()->getIcon(dlg.selectedIconKey);
- ui->actionChangeInstIcon->setIcon(icon);
- ui->changeIconButton->setIcon(icon);
- }
+ IconPickerDialog dlg(this);
+ dlg.execWithSelection(m_selectedInstance->iconKey());
+ if (dlg.result() == QDialog::Accepted)
+ {
+ m_selectedInstance->setIconKey(dlg.selectedIconKey);
+ auto icon = MMC->icons()->getIcon(dlg.selectedIconKey);
+ ui->actionChangeInstIcon->setIcon(icon);
+ ui->changeIconButton->setIcon(icon);
+ }
}
void MainWindow::iconUpdated(QString icon)
{
- if (icon == m_currentInstIcon)
- {
- auto icon = MMC->icons()->getIcon(m_currentInstIcon);
- ui->actionChangeInstIcon->setIcon(icon);
- ui->changeIconButton->setIcon(icon);
- }
+ if (icon == m_currentInstIcon)
+ {
+ auto icon = MMC->icons()->getIcon(m_currentInstIcon);
+ ui->actionChangeInstIcon->setIcon(icon);
+ ui->changeIconButton->setIcon(icon);
+ }
}
void MainWindow::updateInstanceToolIcon(QString new_icon)
{
- m_currentInstIcon = new_icon;
- auto icon = MMC->icons()->getIcon(m_currentInstIcon);
- ui->actionChangeInstIcon->setIcon(icon);
- ui->changeIconButton->setIcon(icon);
+ m_currentInstIcon = new_icon;
+ auto icon = MMC->icons()->getIcon(m_currentInstIcon);
+ ui->actionChangeInstIcon->setIcon(icon);
+ ui->changeIconButton->setIcon(icon);
}
void MainWindow::setSelectedInstanceById(const QString &id)
{
- if (id.isNull())
- return;
- const QModelIndex index = MMC->instances()->getInstanceIndexById(id);
- if (index.isValid())
- {
- QModelIndex selectionIndex = proxymodel->mapFromSource(index);
- view->selectionModel()->setCurrentIndex(selectionIndex, QItemSelectionModel::ClearAndSelect);
- }
+ if (id.isNull())
+ return;
+ const QModelIndex index = MMC->instances()->getInstanceIndexById(id);
+ if (index.isValid())
+ {
+ QModelIndex selectionIndex = proxymodel->mapFromSource(index);
+ view->selectionModel()->setCurrentIndex(selectionIndex, QItemSelectionModel::ClearAndSelect);
+ }
}
void MainWindow::on_actionChangeInstGroup_triggered()
{
- if (!m_selectedInstance)
- return;
+ if (!m_selectedInstance)
+ return;
- bool ok = false;
- QString name(m_selectedInstance->group());
- auto groups = MMC->instances()->getGroups();
- groups.insert(0, "");
- groups.sort(Qt::CaseInsensitive);
- int foo = groups.indexOf(name);
+ bool ok = false;
+ InstanceId instId = m_selectedInstance->id();
+ QString name(MMC->instances()->getInstanceGroup(instId));
+ auto groups = MMC->instances()->getGroups();
+ groups.insert(0, "");
+ groups.sort(Qt::CaseInsensitive);
+ int foo = groups.indexOf(name);
- name = QInputDialog::getItem(this, tr("Group name"), tr("Enter a new group name."), groups, foo, true, &ok);
- name = name.simplified();
- if (ok)
- m_selectedInstance->setGroupPost(name);
+ name = QInputDialog::getItem(this, tr("Group name"), tr("Enter a new group name."), groups, foo, true, &ok);
+ name = name.simplified();
+ if (ok)
+ {
+ MMC->instances()->setInstanceGroup(instId, name);
+ }
}
void MainWindow::deleteGroup()
{
- QObject* obj = sender();
- if(!obj)
- return;
- QAction *action = qobject_cast<QAction *>(obj);
- if(!action)
- return;
- auto map = action->data().toMap();
- if(!map.contains("group"))
- return;
- QString groupName = map["group"].toString();
- if(!groupName.isEmpty())
- {
- MMC->instances()->deleteGroup(groupName);
- }
+ QObject* obj = sender();
+ if(!obj)
+ return;
+ QAction *action = qobject_cast<QAction *>(obj);
+ if(!action)
+ return;
+ auto map = action->data().toMap();
+ if(!map.contains("group"))
+ return;
+ QString groupName = map["group"].toString();
+ if(!groupName.isEmpty())
+ {
+ auto reply = QMessageBox::question(this, tr("Delete group"), tr("Are you sure you want to delete the group %1")
+ .arg(groupName), QMessageBox::Yes | QMessageBox::No);
+ if(reply == QMessageBox::Yes)
+ {
+ MMC->instances()->deleteGroup(groupName);
+ }
+ }
}
void MainWindow::on_actionViewInstanceFolder_triggered()
{
- QString str = MMC->settings()->get("InstanceDir").toString();
- DesktopServices::openDirectory(str);
+ QString str = MMC->settings()->get("InstanceDir").toString();
+ DesktopServices::openDirectory(str);
}
void MainWindow::refreshInstances()
{
- MMC->instances()->loadList(true);
+ MMC->instances()->loadList();
}
void MainWindow::on_actionViewCentralModsFolder_triggered()
{
- DesktopServices::openDirectory(MMC->settings()->get("CentralModsDir").toString(), true);
+ DesktopServices::openDirectory(MMC->settings()->get("CentralModsDir").toString(), true);
}
void MainWindow::on_actionConfig_Folder_triggered()
{
- if (m_selectedInstance)
- {
- QString str = m_selectedInstance->instanceConfigFolder();
- DesktopServices::openDirectory(QDir(str).absolutePath());
- }
+ if (m_selectedInstance)
+ {
+ QString str = m_selectedInstance->instanceConfigFolder();
+ DesktopServices::openDirectory(QDir(str).absolutePath());
+ }
}
void MainWindow::checkForUpdates()
{
- if(BuildConfig.UPDATER_ENABLED)
- {
- auto updater = MMC->updateChecker();
- updater->checkForUpdate(MMC->settings()->get("UpdateChannel").toString(), true);
- }
- else
- {
- qWarning() << "Updater not set up. Cannot check for updates.";
- }
+ if(BuildConfig.UPDATER_ENABLED)
+ {
+ auto updater = MMC->updateChecker();
+ updater->checkForUpdate(MMC->settings()->get("UpdateChannel").toString(), true);
+ }
+ else
+ {
+ qWarning() << "Updater not set up. Cannot check for updates.";
+ }
}
void MainWindow::on_actionSettings_triggered()
{
- SettingsUI::ShowPageDialog(MMC->globalSettingsPages(), this, "global-settings");
- // FIXME: quick HACK to make this work. improve, optimize.
- MMC->instances()->loadList(true);
- proxymodel->invalidate();
- proxymodel->sort(0);
- updateToolsMenu();
- update();
+ MMC->ShowGlobalSettings(this, "global-settings");
+}
+
+void MainWindow::globalSettingsClosed()
+{
+ // FIXME: quick HACK to make this work. improve, optimize.
+ MMC->instances()->loadList();
+ proxymodel->invalidate();
+ proxymodel->sort(0);
+ updateToolsMenu();
+ update();
}
void MainWindow::on_actionInstanceSettings_triggered()
{
- MMC->showInstanceWindow(m_selectedInstance, "settings");
+ MMC->showInstanceWindow(m_selectedInstance, "settings");
}
void MainWindow::on_actionEditInstNotes_triggered()
{
- MMC->showInstanceWindow(m_selectedInstance, "notes");
+ MMC->showInstanceWindow(m_selectedInstance, "notes");
}
void MainWindow::on_actionWorlds_triggered()
{
- MMC->showInstanceWindow(m_selectedInstance, "worlds");
+ MMC->showInstanceWindow(m_selectedInstance, "worlds");
}
void MainWindow::on_actionEditInstance_triggered()
{
- MMC->showInstanceWindow(m_selectedInstance);
+ MMC->showInstanceWindow(m_selectedInstance);
}
void MainWindow::on_actionScreenshots_triggered()
{
- MMC->showInstanceWindow(m_selectedInstance, "screenshots");
+ MMC->showInstanceWindow(m_selectedInstance, "screenshots");
}
void MainWindow::on_actionManageAccounts_triggered()
{
- SettingsUI::ShowPageDialog(MMC->globalSettingsPages(), this, "accounts");
+ MMC->ShowGlobalSettings(this, "accounts");
}
void MainWindow::on_actionReportBug_triggered()
{
- DesktopServices::openUrl(QUrl("https://github.com/MultiMC/MultiMC5/issues"));
+ DesktopServices::openUrl(QUrl("https://github.com/MultiMC/MultiMC5/issues"));
}
void MainWindow::on_actionPatreon_triggered()
{
- DesktopServices::openUrl(QUrl("http://www.patreon.com/multimc"));
+ DesktopServices::openUrl(QUrl("https://www.patreon.com/multimc"));
}
void MainWindow::on_actionMoreNews_triggered()
{
- DesktopServices::openUrl(QUrl("http://multimc.org/posts.html"));
+ DesktopServices::openUrl(QUrl("https://multimc.org/posts.html"));
}
void MainWindow::newsButtonClicked()
{
- QList<NewsEntryPtr> entries = m_newsChecker->getNewsEntries();
- if (entries.count() > 0)
- {
- DesktopServices::openUrl(QUrl(entries[0]->link));
- }
- else
- {
- DesktopServices::openUrl(QUrl("http://multimc.org/posts.html"));
- }
+ QList<NewsEntryPtr> entries = m_newsChecker->getNewsEntries();
+ if (entries.count() > 0)
+ {
+ DesktopServices::openUrl(QUrl(entries[0]->link));
+ }
+ else
+ {
+ DesktopServices::openUrl(QUrl("https://multimc.org/posts.html"));
+ }
}
void MainWindow::on_actionAbout_triggered()
{
- AboutDialog dialog(this);
- dialog.exec();
-}
-
-void MainWindow::on_mainToolBar_visibilityChanged(bool)
-{
- // Don't allow hiding the main toolbar.
- // This is the only way I could find to prevent it... :/
- ui->mainToolBar->setVisible(true);
+ AboutDialog dialog(this);
+ dialog.exec();
}
void MainWindow::on_actionDeleteInstance_triggered()
{
- if (!m_selectedInstance)
- {
- return;
- }
- auto response = CustomMessageBox::selectable(
- this,
- tr("CAREFUL!"),
- tr("About to delete: %1\nThis is permanent and will completely delete the instance.\n\nAre you sure?").arg(m_selectedInstance->name()),
- QMessageBox::Warning,
- QMessageBox::Yes | QMessageBox::No
- )->exec();
- if (response == QMessageBox::Yes)
- {
- m_selectedInstance->nuke();
- }
+ if (!m_selectedInstance)
+ {
+ return;
+ }
+ auto id = m_selectedInstance->id();
+ auto response = CustomMessageBox::selectable(
+ this,
+ tr("CAREFUL!"),
+ tr("About to delete: %1\nThis is permanent and will completely delete the instance.\n\nAre you sure?").arg(m_selectedInstance->name()),
+ QMessageBox::Warning,
+ QMessageBox::Yes | QMessageBox::No,
+ QMessageBox::No
+ )->exec();
+ if (response == QMessageBox::Yes)
+ {
+ MMC->instances()->deleteInstance(id);
+ }
}
void MainWindow::on_actionExportInstance_triggered()
{
- if (m_selectedInstance)
- {
- ExportInstanceDialog dlg(m_selectedInstance, this);
- dlg.exec();
- }
+ if (m_selectedInstance)
+ {
+ ExportInstanceDialog dlg(m_selectedInstance, this);
+ dlg.exec();
+ }
}
void MainWindow::on_actionRenameInstance_triggered()
{
- if (m_selectedInstance)
- {
- bool ok = false;
- QString name(m_selectedInstance->name());
- name = QInputDialog::getText(this, tr("Instance name"), tr("Enter a new instance name."), QLineEdit::Normal, name, &ok);
-
- name = name.trimmed();
- if (name.length() > 0)
- {
- if (ok && name.length())
- {
- m_selectedInstance->setName(name);
- ui->renameButton->setText(name);
- }
- }
- }
+ if (m_selectedInstance)
+ {
+ view->edit(view->currentIndex());
+ }
}
void MainWindow::on_actionViewSelectedInstFolder_triggered()
{
- if (m_selectedInstance)
- {
- QString str = m_selectedInstance->instanceRoot();
- DesktopServices::openDirectory(QDir(str).absolutePath());
- }
+ if (m_selectedInstance)
+ {
+ QString str = m_selectedInstance->instanceRoot();
+ DesktopServices::openDirectory(QDir(str).absolutePath());
+ }
}
+void MainWindow::on_actionViewSelectedMCFolder_triggered()
+{
+ if (m_selectedInstance)
+ {
+ QString str = m_selectedInstance->gameRoot();
+ if (!FS::ensureFilePathExists(str))
+ {
+ // TODO: report error
+ return;
+ }
+ DesktopServices::openDirectory(QDir(str).absolutePath());
+ }
+}
+
+
void MainWindow::closeEvent(QCloseEvent *event)
{
- // Save the window state and geometry.
- MMC->settings()->set("MainWindowState", saveState().toBase64());
- MMC->settings()->set("MainWindowGeometry", saveGeometry().toBase64());
- event->accept();
- emit isClosing();
+ // Save the window state and geometry.
+ MMC->settings()->set("MainWindowState", saveState().toBase64());
+ MMC->settings()->set("MainWindowGeometry", saveGeometry().toBase64());
+ event->accept();
+ emit isClosing();
}
void MainWindow::changeEvent(QEvent* event)
{
- if (event->type() == QEvent::LanguageChange)
- {
- ui->retranslateUi(this);
- }
- QMainWindow::changeEvent(event);
+ if (event->type() == QEvent::LanguageChange)
+ {
+ ui->retranslateUi(this);
+ }
+ QMainWindow::changeEvent(event);
}
void MainWindow::instanceActivated(QModelIndex index)
{
- if (!index.isValid())
- return;
- QString id = index.data(InstanceList::InstanceIDRole).toString();
- InstancePtr inst = MMC->instances()->getInstanceById(id);
- if (!inst)
- return;
+ if (!index.isValid())
+ return;
+ QString id = index.data(InstanceList::InstanceIDRole).toString();
+ InstancePtr inst = MMC->instances()->getInstanceById(id);
+ if (!inst)
+ return;
- activateInstance(inst);
+ activateInstance(inst);
}
void MainWindow::on_actionLaunchInstance_triggered()
{
- if (!m_selectedInstance)
- {
- return;
- }
- if(m_selectedInstance->isRunning())
- {
- MMC->kill(m_selectedInstance);
- }
- else
- {
- MMC->launch(m_selectedInstance);
- }
+ if (!m_selectedInstance)
+ {
+ return;
+ }
+ if(m_selectedInstance->isRunning())
+ {
+ MMC->kill(m_selectedInstance);
+ }
+ else
+ {
+ MMC->launch(m_selectedInstance);
+ }
}
void MainWindow::activateInstance(InstancePtr instance)
{
- MMC->launch(instance);
+ MMC->launch(instance);
}
void MainWindow::on_actionLaunchInstanceOffline_triggered()
{
- if (m_selectedInstance)
- {
- MMC->launch(m_selectedInstance, false);
- }
+ if (m_selectedInstance)
+ {
+ MMC->launch(m_selectedInstance, false);
+ }
}
void MainWindow::taskEnd()
{
- QObject *sender = QObject::sender();
- if (sender == m_versionLoadTask)
- m_versionLoadTask = NULL;
+ QObject *sender = QObject::sender();
+ if (sender == m_versionLoadTask)
+ m_versionLoadTask = NULL;
- sender->deleteLater();
+ sender->deleteLater();
}
void MainWindow::startTask(Task *task)
{
- connect(task, SIGNAL(succeeded()), SLOT(taskEnd()));
- connect(task, SIGNAL(failed(QString)), SLOT(taskEnd()));
- task->start();
+ connect(task, SIGNAL(succeeded()), SLOT(taskEnd()));
+ connect(task, SIGNAL(failed(QString)), SLOT(taskEnd()));
+ task->start();
}
void MainWindow::instanceChanged(const QModelIndex &current, const QModelIndex &previous)
{
- 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(true);
- if(m_selectedInstance->isRunning())
- {
- ui->actionLaunchInstance->setEnabled(true);
- ui->setLaunchAction(true);
- }
- else
- {
- ui->actionLaunchInstance->setEnabled(m_selectedInstance->canLaunch());
- ui->setLaunchAction(false);
- }
- ui->actionLaunchInstanceOffline->setEnabled(m_selectedInstance->canLaunch());
- ui->actionExportInstance->setEnabled(m_selectedInstance->canExport());
- ui->renameButton->setText(m_selectedInstance->name());
- m_statusLeft->setText(m_selectedInstance->getStatusbarDescription());
- updateInstanceToolIcon(m_selectedInstance->iconKey());
-
- updateToolsMenu();
-
- MMC->settings()->set("SelectedInstance", m_selectedInstance->id());
- }
- else
- {
- ui->instanceToolBar->setEnabled(false);
- MMC->settings()->set("SelectedInstance", QString());
- selectionBad();
- return;
- }
+ 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(true);
+ if(m_selectedInstance->isRunning())
+ {
+ ui->actionLaunchInstance->setEnabled(true);
+ ui->setLaunchAction(true);
+ }
+ else
+ {
+ ui->actionLaunchInstance->setEnabled(m_selectedInstance->canLaunch());
+ ui->setLaunchAction(false);
+ }
+ ui->actionLaunchInstanceOffline->setEnabled(m_selectedInstance->canLaunch());
+ ui->actionExportInstance->setEnabled(m_selectedInstance->canExport());
+ ui->renameButton->setText(m_selectedInstance->name());
+ m_statusLeft->setText(m_selectedInstance->getStatusbarDescription());
+ updateInstanceToolIcon(m_selectedInstance->iconKey());
+
+ updateToolsMenu();
+
+ MMC->settings()->set("SelectedInstance", m_selectedInstance->id());
+ }
+ else
+ {
+ ui->instanceToolBar->setEnabled(false);
+ MMC->settings()->set("SelectedInstance", QString());
+ selectionBad();
+ return;
+ }
+}
+
+void MainWindow::instanceSelectRequest(QString id)
+{
+ setSelectedInstanceById(id);
}
void MainWindow::instanceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
- auto current = view->selectionModel()->currentIndex();
- QItemSelection test(topLeft, bottomRight);
- if (test.contains(current))
- {
- instanceChanged(current, current);
- }
+ auto current = view->selectionModel()->currentIndex();
+ QItemSelection test(topLeft, bottomRight);
+ if (test.contains(current))
+ {
+ instanceChanged(current, current);
+ }
}
void MainWindow::selectionBad()
{
- // start by reseting everything...
- m_selectedInstance = nullptr;
+ // start by reseting everything...
+ m_selectedInstance = nullptr;
- statusBar()->clearMessage();
- ui->instanceToolBar->setEnabled(false);
- ui->renameButton->setText(tr("Rename Instance"));
- updateInstanceToolIcon("infinity");
+ statusBar()->clearMessage();
+ ui->instanceToolBar->setEnabled(false);
+ ui->renameButton->setText(tr("Rename Instance"));
+ updateInstanceToolIcon("infinity");
- // ...and then see if we can enable the previously selected instance
- setSelectedInstanceById(MMC->settings()->get("SelectedInstance").toString());
+ // ...and then see if we can enable the previously selected instance
+ setSelectedInstanceById(MMC->settings()->get("SelectedInstance").toString());
}
void MainWindow::checkInstancePathForProblems()
{
- QString instanceFolder = MMC->settings()->get("InstanceDir").toString();
- if (FS::checkProblemticPathJava(QDir(instanceFolder)))
- {
- QMessageBox warning(this);
- warning.setText(tr("Your instance folder contains \'!\' and this is known to cause Java problems!"));
- warning.setInformativeText(tr("You have now two options: <br/>"
- " - change the instance folder in the settings <br/>"
- " - move this installation of MultiMC5 to a different folder"));
- warning.setDefaultButton(QMessageBox::Ok);
- warning.exec();
- }
- auto tempFolderText = tr("This is a problem: <br/>"
- " - MultiMC will likely be deleted without warning by the operating system <br/>"
- " - close MultiMC now and extract it to a real location, not a temporary folder");
- QString pathfoldername = QDir(instanceFolder).absolutePath();
- if (pathfoldername.contains("Rar$", Qt::CaseInsensitive))
- {
- QMessageBox warning(this);
- warning.setText(tr("Your instance folder contains \'Rar$\' - that means you haven't extracted the MultiMC zip!"));
- warning.setInformativeText(tempFolderText);
- warning.setDefaultButton(QMessageBox::Ok);
- warning.exec();
- }
- else if (pathfoldername.contains(QDir::tempPath()))
- {
- QMessageBox warning(this);
- warning.setText(tr("Your instance folder is in a temporary folder: \'%1\'!").arg(QDir::tempPath()));
- warning.setInformativeText(tempFolderText);
- warning.setDefaultButton(QMessageBox::Ok);
- warning.exec();
- }
+ QString instanceFolder = MMC->settings()->get("InstanceDir").toString();
+ if (FS::checkProblemticPathJava(QDir(instanceFolder)))
+ {
+ QMessageBox warning(this);
+ warning.setText(tr("Your instance folder contains \'!\' and this is known to cause Java problems!"));
+ warning.setInformativeText(tr("You have now two options: <br/>"
+ " - change the instance folder in the settings <br/>"
+ " - move this installation of MultiMC5 to a different folder"));
+ warning.setDefaultButton(QMessageBox::Ok);
+ warning.exec();
+ }
+ auto tempFolderText = tr("This is a problem: <br/>"
+ " - MultiMC will likely be deleted without warning by the operating system <br/>"
+ " - close MultiMC now and extract it to a real location, not a temporary folder");
+ QString pathfoldername = QDir(instanceFolder).absolutePath();
+ if (pathfoldername.contains("Rar$", Qt::CaseInsensitive))
+ {
+ QMessageBox warning(this);
+ warning.setText(tr("Your instance folder contains \'Rar$\' - that means you haven't extracted the MultiMC zip!"));
+ warning.setInformativeText(tempFolderText);
+ warning.setDefaultButton(QMessageBox::Ok);
+ warning.exec();
+ }
+ else if (pathfoldername.startsWith(QDir::tempPath()) || pathfoldername.contains("/TempState/"))
+ {
+ QMessageBox warning(this);
+ warning.setText(tr("Your instance folder is in a temporary folder: \'%1\'!").arg(QDir::tempPath()));
+ warning.setInformativeText(tempFolderText);
+ warning.setDefaultButton(QMessageBox::Ok);
+ warning.exec();
+ }
}
diff --git a/application/MainWindow.h b/application/MainWindow.h
index 8f756412..a415b5e8 100644
--- a/application/MainWindow.h
+++ b/application/MainWindow.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,174 +42,181 @@ class InstanceTask;
class MainWindow : public QMainWindow
{
- Q_OBJECT
+ Q_OBJECT
- class Ui;
+ class Ui;
public:
- explicit MainWindow(QWidget *parent = 0);
- ~MainWindow();
+ explicit MainWindow(QWidget *parent = 0);
+ ~MainWindow();
- bool eventFilter(QObject *obj, QEvent *ev) override;
- void closeEvent(QCloseEvent *event) override;
- void changeEvent(QEvent * event) override;
+ bool eventFilter(QObject *obj, QEvent *ev) override;
+ void closeEvent(QCloseEvent *event) override;
+ void changeEvent(QEvent * event) override;
- void checkInstancePathForProblems();
+ void checkInstancePathForProblems();
- void updatesAllowedChanged(bool allowed);
+ void updatesAllowedChanged(bool allowed);
signals:
- void isClosing();
+ void isClosing();
+
+protected:
+ QMenu * createPopupMenu() override;
private slots:
- void onCatToggled(bool);
+ void onCatToggled(bool);
+
+ void on_actionAbout_triggered();
+
+ void on_actionAddInstance_triggered();
- void on_actionAbout_triggered();
+ void on_actionREDDIT_triggered();
- void on_actionAddInstance_triggered();
+ void on_actionDISCORD_triggered();
- void on_actionREDDIT_triggered();
+ void on_actionCopyInstance_triggered();
- void on_actionDISCORD_triggered();
+ void on_actionChangeInstGroup_triggered();
- void on_actionCopyInstance_triggered();
+ void on_actionChangeInstIcon_triggered();
+ void on_changeIconButton_clicked(bool)
+ {
+ on_actionChangeInstIcon_triggered();
+ }
- void on_actionChangeInstGroup_triggered();
+ void on_actionViewInstanceFolder_triggered();
- void on_actionChangeInstIcon_triggered();
- void on_changeIconButton_clicked(bool)
- {
- on_actionChangeInstIcon_triggered();
- }
+ void on_actionConfig_Folder_triggered();
- void on_actionViewInstanceFolder_triggered();
+ void on_actionViewSelectedInstFolder_triggered();
- void on_actionConfig_Folder_triggered();
+ void on_actionViewSelectedMCFolder_triggered();
- void on_actionViewSelectedInstFolder_triggered();
+ void refreshInstances();
- void refreshInstances();
+ void on_actionViewCentralModsFolder_triggered();
- void on_actionViewCentralModsFolder_triggered();
+ void checkForUpdates();
- void checkForUpdates();
+ void on_actionSettings_triggered();
- void on_actionSettings_triggered();
+ void on_actionInstanceSettings_triggered();
- void on_actionInstanceSettings_triggered();
+ void on_actionManageAccounts_triggered();
- void on_actionManageAccounts_triggered();
+ void on_actionReportBug_triggered();
- void on_actionReportBug_triggered();
+ void on_actionPatreon_triggered();
- void on_actionPatreon_triggered();
+ void on_actionMoreNews_triggered();
- void on_actionMoreNews_triggered();
+ void newsButtonClicked();
- void newsButtonClicked();
+ void on_actionLaunchInstance_triggered();
- void on_mainToolBar_visibilityChanged(bool);
+ void on_actionLaunchInstanceOffline_triggered();
- void on_actionLaunchInstance_triggered();
+ void on_actionDeleteInstance_triggered();
- void on_actionLaunchInstanceOffline_triggered();
+ void deleteGroup();
- void on_actionDeleteInstance_triggered();
+ void on_actionExportInstance_triggered();
- void deleteGroup();
+ void on_actionRenameInstance_triggered();
+ void on_renameButton_clicked(bool)
+ {
+ on_actionRenameInstance_triggered();
+ }
- void on_actionExportInstance_triggered();
+ void on_actionEditInstance_triggered();
- void on_actionRenameInstance_triggered();
- void on_renameButton_clicked(bool)
- {
- on_actionRenameInstance_triggered();
- }
+ void on_actionEditInstNotes_triggered();
- void on_actionEditInstance_triggered();
+ void on_actionWorlds_triggered();
- void on_actionEditInstNotes_triggered();
+ void on_actionScreenshots_triggered();
- void on_actionWorlds_triggered();
+ void taskEnd();
- void on_actionScreenshots_triggered();
+ /**
+ * called when an icon is changed in the icon model.
+ */
+ void iconUpdated(QString);
- void taskEnd();
+ void showInstanceContextMenu(const QPoint &);
- /**
- * called when an icon is changed in the icon model.
- */
- void iconUpdated(QString);
+ void updateToolsMenu();
- void showInstanceContextMenu(const QPoint &);
+ void skinJobFinished();
- void updateToolsMenu();
+ void instanceActivated(QModelIndex);
- void skinJobFinished();
+ void instanceChanged(const QModelIndex &current, const QModelIndex &previous);
- void instanceActivated(QModelIndex);
+ void instanceSelectRequest(QString id);
- void instanceChanged(const QModelIndex &current, const QModelIndex &previous);
+ void instanceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
- void instanceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
+ void selectionBad();
- void selectionBad();
+ void startTask(Task *task);
- void startTask(Task *task);
+ void updateAvailable(GoUpdate::Status status);
- void updateAvailable(GoUpdate::Status status);
+ void updateNotAvailable();
- void updateNotAvailable();
+ void notificationsChanged();
- void notificationsChanged();
+ void activeAccountChanged();
- void activeAccountChanged();
+ void changeActiveAccount();
- void changeActiveAccount();
+ void repopulateAccountsMenu();
- void repopulateAccountsMenu();
+ void updateNewsLabel();
- void updateNewsLabel();
+ /*!
+ * Runs the DownloadTask and installs updates.
+ */
+ void downloadUpdates(GoUpdate::Status status);
- /*!
- * Runs the DownloadTask and installs updates.
- */
- void downloadUpdates(GoUpdate::Status status);
+ void droppedURLs(QList<QUrl> urls);
- void droppedURLs(QList<QUrl> urls);
+ void konamiTriggered();
- void konamiTriggered();
+ void globalSettingsClosed();
private:
- void addInstance(QString url = QString());
- void activateInstance(InstancePtr instance);
- void setCatBackground(bool enabled);
- void updateInstanceToolIcon(QString new_icon);
- void setSelectedInstanceById(const QString &id);
+ void addInstance(QString url = QString());
+ void activateInstance(InstancePtr instance);
+ void setCatBackground(bool enabled);
+ void updateInstanceToolIcon(QString new_icon);
+ void setSelectedInstanceById(const QString &id);
- void runModalTask(Task *task);
- void instanceFromInstanceTask(InstanceTask *task);
- void finalizeInstance(InstancePtr inst);
+ void runModalTask(Task *task);
+ void instanceFromInstanceTask(InstanceTask *task);
+ void finalizeInstance(InstancePtr inst);
private:
- std::unique_ptr<Ui> ui;
-
- // these are managed by Qt's memory management model!
- GroupView *view = nullptr;
- InstanceProxyModel *proxymodel = nullptr;
- QToolButton *newsLabel = nullptr;
- QLabel *m_statusLeft = nullptr;
- ServerStatus *m_statusRight = nullptr;
- QMenu *accountMenu = nullptr;
- QToolButton *accountMenuButton = nullptr;
- KonamiCode * secretEventFilter = nullptr;
-
- unique_qobject_ptr<NetJob> skin_download_job;
- unique_qobject_ptr<NewsChecker> m_newsChecker;
- unique_qobject_ptr<NotificationChecker> m_notificationChecker;
-
- InstancePtr m_selectedInstance;
- QString m_currentInstIcon;
-
- // managed by the application object
- Task *m_versionLoadTask = nullptr;
+ std::unique_ptr<Ui> ui;
+
+ // these are managed by Qt's memory management model!
+ GroupView *view = nullptr;
+ InstanceProxyModel *proxymodel = nullptr;
+ QToolButton *newsLabel = nullptr;
+ QLabel *m_statusLeft = nullptr;
+ ServerStatus *m_statusRight = nullptr;
+ QMenu *accountMenu = nullptr;
+ QToolButton *accountMenuButton = nullptr;
+ KonamiCode * secretEventFilter = nullptr;
+
+ unique_qobject_ptr<NetJob> skin_download_job;
+ unique_qobject_ptr<NewsChecker> m_newsChecker;
+ unique_qobject_ptr<NotificationChecker> m_notificationChecker;
+
+ InstancePtr m_selectedInstance;
+ QString m_currentInstIcon;
+
+ // managed by the application object
+ Task *m_versionLoadTask = nullptr;
};
diff --git a/application/MultiMC.cpp b/application/MultiMC.cpp
index 9e35717a..5626b672 100644
--- a/application/MultiMC.cpp
+++ b/application/MultiMC.cpp
@@ -2,10 +2,15 @@
#include "BuildConfig.h"
#include "MainWindow.h"
#include "InstanceWindow.h"
+
+#include "groupview/AccessibleGroupView.h"
+#include <QAccessible>
+
#include "pages/BasePageProvider.h"
#include "pages/global/MultiMCPage.h"
#include "pages/global/MinecraftPage.h"
#include "pages/global/JavaPage.h"
+#include "pages/global/LanguagePage.h"
#include "pages/global/ProxyPage.h"
#include "pages/global/ExternalToolsPage.h"
#include "pages/global/AccountListPage.h"
@@ -36,7 +41,6 @@
#include "dialogs/CustomMessageBox.h"
#include "InstanceList.h"
-#include "FolderInstanceProvider.h"
#include <minecraft/auth/MojangAccountList.h>
#include "icons/IconList.h"
@@ -65,6 +69,8 @@
#include <sys.h>
+#include "pagedialog/PageDialog.h"
+
#if defined Q_OS_WIN32
#ifndef WIN32_LEAN_AND_MEAN
@@ -82,1148 +88,1041 @@ static const QLatin1String liveCheckFile("live.check");
using namespace Commandline;
#define MACOS_HINT "If you are on macOS Sierra, you might have to move MultiMC.app to your /Applications or ~/Applications folder. "\
- "This usually fixes the problem and you can move the application elsewhere afterwards.\n"\
- "\n"
+ "This usually fixes the problem and you can move the application elsewhere afterwards.\n"\
+ "\n"
static void appDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
- const char *levels = "DWCFIS";
- const QString format("%1 %2 %3\n");
-
- qint64 msecstotal = MMC->timeSinceStart();
- qint64 seconds = msecstotal / 1000;
- qint64 msecs = msecstotal % 1000;
- QString foo;
- char buf[1025] = {0};
- ::snprintf(buf, 1024, "%5lld.%03lld", seconds, msecs);
-
- QString out = format.arg(buf).arg(levels[type]).arg(msg);
-
- MMC->logFile->write(out.toUtf8());
- MMC->logFile->flush();
- QTextStream(stderr) << out.toLocal8Bit();
- fflush(stderr);
+ const char *levels = "DWCFIS";
+ const QString format("%1 %2 %3\n");
+
+ qint64 msecstotal = MMC->timeSinceStart();
+ qint64 seconds = msecstotal / 1000;
+ qint64 msecs = msecstotal % 1000;
+ QString foo;
+ char buf[1025] = {0};
+ ::snprintf(buf, 1024, "%5lld.%03lld", seconds, msecs);
+
+ QString out = format.arg(buf).arg(levels[type]).arg(msg);
+
+ MMC->logFile->write(out.toUtf8());
+ MMC->logFile->flush();
+ QTextStream(stderr) << out.toLocal8Bit();
+ fflush(stderr);
}
MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv)
{
#if defined Q_OS_WIN32
- // attach the parent console
- if(AttachConsole(ATTACH_PARENT_PROCESS))
- {
- // if attach succeeds, reopen and sync all the i/o
- if(freopen("CON", "w", stdout))
- {
- std::cout.sync_with_stdio();
- }
- if(freopen("CON", "w", stderr))
- {
- std::cerr.sync_with_stdio();
- }
- if(freopen("CON", "r", stdin))
- {
- std::cin.sync_with_stdio();
- }
- auto out = GetStdHandle (STD_OUTPUT_HANDLE);
- DWORD written;
- const char * endline = "\n";
- WriteConsole(out, endline, strlen(endline), &written, NULL);
- consoleAttached = true;
- }
+ // attach the parent console
+ if(AttachConsole(ATTACH_PARENT_PROCESS))
+ {
+ // if attach succeeds, reopen and sync all the i/o
+ if(freopen("CON", "w", stdout))
+ {
+ std::cout.sync_with_stdio();
+ }
+ if(freopen("CON", "w", stderr))
+ {
+ std::cerr.sync_with_stdio();
+ }
+ if(freopen("CON", "r", stdin))
+ {
+ std::cin.sync_with_stdio();
+ }
+ auto out = GetStdHandle (STD_OUTPUT_HANDLE);
+ DWORD written;
+ const char * endline = "\n";
+ WriteConsole(out, endline, strlen(endline), &written, NULL);
+ consoleAttached = true;
+ }
#endif
- setOrganizationName("MultiMC");
- setOrganizationDomain("multimc.org");
- setApplicationName("MultiMC5");
- setApplicationDisplayName("MultiMC 5");
- setApplicationVersion(BuildConfig.printableVersionString());
-
- startTime = QDateTime::currentDateTime();
-
- // Don't quit on hiding the last window
- this->setQuitOnLastWindowClosed(false);
-
- // Commandline parsing
- QHash<QString, QVariant> args;
- {
- Parser parser(FlagStyle::GNU, ArgumentStyle::SpaceAndEquals);
-
- // --help
- parser.addSwitch("help");
- parser.addShortOpt("help", 'h');
- parser.addDocumentation("help", "display this help and exit.");
- // --version
- parser.addSwitch("version");
- parser.addShortOpt("version", 'V');
- parser.addDocumentation("version", "display program version and exit.");
- // --dir
- parser.addOption("dir");
- parser.addShortOpt("dir", 'd');
- parser.addDocumentation("dir", "use the supplied folder as MultiMC root instead of "
- "the binary location (use '.' for current)");
- // --launch
- parser.addOption("launch");
- parser.addShortOpt("launch", 'l');
- parser.addDocumentation("launch", "launch the specified instance (by instance ID)");
- // --alive
- parser.addSwitch("alive");
- parser.addDocumentation("alive", "write a small '" + liveCheckFile + "' file after MultiMC starts");
-
- // parse the arguments
- try
- {
- args = parser.parse(arguments());
- }
- catch (ParsingError e)
- {
- std::cerr << "CommandLineError: " << e.what() << std::endl;
- std::cerr << "Try '%1 -h' to get help on MultiMC's command line parameters."
- << std::endl;
- m_status = MultiMC::Failed;
- return;
- }
-
- // display help and exit
- if (args["help"].toBool())
- {
- std::cout << qPrintable(parser.compileHelp(arguments()[0]));
- m_status = MultiMC::Succeeded;
- return;
- }
-
- // display version and exit
- if (args["version"].toBool())
- {
- std::cout << "Version " << BuildConfig.printableVersionString().toStdString() << std::endl;
- std::cout << "Git " << BuildConfig.GIT_COMMIT.toStdString() << std::endl;
- m_status = MultiMC::Succeeded;
- return;
- }
- }
- m_instanceIdToLaunch = args["launch"].toString();
- m_liveCheck = args["alive"].toBool();
-
- QString origcwdPath = QDir::currentPath();
- QString binPath = applicationDirPath();
- QString adjustedBy;
- QString dataPath;
- // change folder
- QString dirParam = args["dir"].toString();
- if (!dirParam.isEmpty())
- {
- // the dir param. it makes multimc data path point to whatever the user specified
- // on command line
- adjustedBy += "Command line " + dirParam;
- dataPath = dirParam;
- }
- else
- {
+ setOrganizationName("MultiMC");
+ setOrganizationDomain("multimc.org");
+ setApplicationName("MultiMC5");
+ setApplicationDisplayName("MultiMC 5");
+ setApplicationVersion(BuildConfig.printableVersionString());
+
+ startTime = QDateTime::currentDateTime();
+
+ // Don't quit on hiding the last window
+ this->setQuitOnLastWindowClosed(false);
+
+ // Commandline parsing
+ QHash<QString, QVariant> args;
+ {
+ Parser parser(FlagStyle::GNU, ArgumentStyle::SpaceAndEquals);
+
+ // --help
+ parser.addSwitch("help");
+ parser.addShortOpt("help", 'h');
+ parser.addDocumentation("help", "display this help and exit.");
+ // --version
+ parser.addSwitch("version");
+ parser.addShortOpt("version", 'V');
+ parser.addDocumentation("version", "display program version and exit.");
+ // --dir
+ parser.addOption("dir");
+ parser.addShortOpt("dir", 'd');
+ parser.addDocumentation("dir", "use the supplied folder as MultiMC root instead of "
+ "the binary location (use '.' for current)");
+ // --launch
+ parser.addOption("launch");
+ parser.addShortOpt("launch", 'l');
+ parser.addDocumentation("launch", "launch the specified instance (by instance ID)");
+ // --alive
+ parser.addSwitch("alive");
+ parser.addDocumentation("alive", "write a small '" + liveCheckFile + "' file after MultiMC starts");
+
+ // parse the arguments
+ try
+ {
+ args = parser.parse(arguments());
+ }
+ catch (const ParsingError &e)
+ {
+ std::cerr << "CommandLineError: " << e.what() << std::endl;
+ std::cerr << "Try '%1 -h' to get help on MultiMC's command line parameters."
+ << std::endl;
+ m_status = MultiMC::Failed;
+ return;
+ }
+
+ // display help and exit
+ if (args["help"].toBool())
+ {
+ std::cout << qPrintable(parser.compileHelp(arguments()[0]));
+ m_status = MultiMC::Succeeded;
+ return;
+ }
+
+ // display version and exit
+ if (args["version"].toBool())
+ {
+ std::cout << "Version " << BuildConfig.printableVersionString().toStdString() << std::endl;
+ std::cout << "Git " << BuildConfig.GIT_COMMIT.toStdString() << std::endl;
+ m_status = MultiMC::Succeeded;
+ return;
+ }
+ }
+ m_instanceIdToLaunch = args["launch"].toString();
+ m_liveCheck = args["alive"].toBool();
+
+ QString origcwdPath = QDir::currentPath();
+ QString binPath = applicationDirPath();
+ QString adjustedBy;
+ QString dataPath;
+ // change folder
+ QString dirParam = args["dir"].toString();
+ if (!dirParam.isEmpty())
+ {
+ // the dir param. it makes multimc data path point to whatever the user specified
+ // on command line
+ adjustedBy += "Command line " + dirParam;
+ dataPath = dirParam;
+ }
+ else
+ {
#ifdef MULTIMC_LINUX_DATADIR
- QString xdgDataHome = QFile::decodeName(qgetenv("XDG_DATA_HOME"));
- if (xdgDataHome.isEmpty())
- xdgDataHome = QDir::homePath() + QLatin1String("/.local/share");
- dataPath = xdgDataHome + "/multimc";
- adjustedBy += "XDG standard " + dataPath;
+ QString xdgDataHome = QFile::decodeName(qgetenv("XDG_DATA_HOME"));
+ if (xdgDataHome.isEmpty())
+ xdgDataHome = QDir::homePath() + QLatin1String("/.local/share");
+ dataPath = xdgDataHome + "/multimc";
+ adjustedBy += "XDG standard " + dataPath;
#else
- dataPath = applicationDirPath();
- adjustedBy += "Fallback to binary path " + dataPath;
+ dataPath = applicationDirPath();
+ adjustedBy += "Fallback to binary path " + dataPath;
#endif
- }
-
- if (!FS::ensureFolderPathExists(dataPath))
- {
- showFatalErrorMessage(
- "MultiMC data folder could not be created.",
- "MultiMC data folder could not be created.\n"
- "\n"
+ }
+
+ if (!FS::ensureFolderPathExists(dataPath))
+ {
+ showFatalErrorMessage(
+ "MultiMC data folder could not be created.",
+ "MultiMC data folder could not be created.\n"
+ "\n"
#if defined(Q_OS_MAC)
- MACOS_HINT
+ MACOS_HINT
#endif
- "Make sure you have the right permissions to the MultiMC data folder and any folder needed to access it.\n"
- "\n"
- "MultiMC cannot continue until you fix this problem."
- );
- return;
- }
- if (!QDir::setCurrent(dataPath))
- {
- showFatalErrorMessage(
- "MultiMC data folder could not be opened.",
- "MultiMC data folder could not be opened.\n"
- "\n"
+ "Make sure you have the right permissions to the MultiMC data folder and any folder needed to access it.\n"
+ "\n"
+ "MultiMC cannot continue until you fix this problem."
+ );
+ return;
+ }
+ if (!QDir::setCurrent(dataPath))
+ {
+ showFatalErrorMessage(
+ "MultiMC data folder could not be opened.",
+ "MultiMC data folder could not be opened.\n"
+ "\n"
#if defined(Q_OS_MAC)
- MACOS_HINT
+ MACOS_HINT
#endif
- "Make sure you have the right permissions to the MultiMC data folder.\n"
- "\n"
- "MultiMC cannot continue until you fix this problem."
- );
- return;
- }
-
- /*
- * Establish the mechanism for communication with an already running MultiMC that uses the same data path.
- * If there is one, tell it what the user actually wanted to do and exit.
- * We want to initialize this before logging to avoid messing with the log of a potential already running copy.
- */
- auto appID = ApplicationId::fromPathAndVersion(QDir::currentPath(), BuildConfig.printableVersionString());
- {
- // FIXME: you can run the same binaries with multiple data dirs and they won't clash. This could cause issues for updates.
- m_peerInstance = new LocalPeer(this, appID);
- connect(m_peerInstance, &LocalPeer::messageReceived, this, &MultiMC::messageReceived);
- if(m_peerInstance->isClient())
- {
- if(m_instanceIdToLaunch.isEmpty())
- {
- m_peerInstance->sendMessage("activate", 2000);
- }
- else
- {
- m_peerInstance->sendMessage(m_instanceIdToLaunch, 2000);
- }
- m_status = MultiMC::Succeeded;
- return;
- }
- }
-
- // init the logger
- {
- static const QString logBase = "MultiMC-%0.log";
- auto moveFile = [](const QString &oldName, const QString &newName)
- {
- QFile::remove(newName);
- QFile::copy(oldName, newName);
- QFile::remove(oldName);
- };
-
- moveFile(logBase.arg(3), logBase.arg(4));
- moveFile(logBase.arg(2), logBase.arg(3));
- moveFile(logBase.arg(1), logBase.arg(2));
- moveFile(logBase.arg(0), logBase.arg(1));
-
- logFile = std::unique_ptr<QFile>(new QFile(logBase.arg(0)));
- if(!logFile->open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
- {
- showFatalErrorMessage(
- "MultiMC data folder is not writable!",
- "MultiMC couldn't create a log file - the MultiMC data folder is not writable.\n"
- "\n"
- #if defined(Q_OS_MAC)
- MACOS_HINT
- #endif
- "Make sure you have write permissions to the MultiMC data folder.\n"
- "\n"
- "MultiMC cannot continue until you fix this problem."
- );
- return;
- }
- qInstallMessageHandler(appDebugOutput);
- qDebug() << "<> Log initialized.";
- }
-
- // Set up paths
- {
- // Root path is used for updates.
+ "Make sure you have the right permissions to the MultiMC data folder.\n"
+ "\n"
+ "MultiMC cannot continue until you fix this problem."
+ );
+ return;
+ }
+
+ /*
+ * Establish the mechanism for communication with an already running MultiMC that uses the same data path.
+ * If there is one, tell it what the user actually wanted to do and exit.
+ * We want to initialize this before logging to avoid messing with the log of a potential already running copy.
+ */
+ auto appID = ApplicationId::fromPathAndVersion(QDir::currentPath(), BuildConfig.printableVersionString());
+ {
+ // FIXME: you can run the same binaries with multiple data dirs and they won't clash. This could cause issues for updates.
+ m_peerInstance = new LocalPeer(this, appID);
+ connect(m_peerInstance, &LocalPeer::messageReceived, this, &MultiMC::messageReceived);
+ if(m_peerInstance->isClient())
+ {
+ if(m_instanceIdToLaunch.isEmpty())
+ {
+ m_peerInstance->sendMessage("activate", 2000);
+ }
+ else
+ {
+ m_peerInstance->sendMessage(m_instanceIdToLaunch, 2000);
+ }
+ m_status = MultiMC::Succeeded;
+ return;
+ }
+ }
+
+ // init the logger
+ {
+ static const QString logBase = "MultiMC-%0.log";
+ auto moveFile = [](const QString &oldName, const QString &newName)
+ {
+ QFile::remove(newName);
+ QFile::copy(oldName, newName);
+ QFile::remove(oldName);
+ };
+
+ moveFile(logBase.arg(3), logBase.arg(4));
+ moveFile(logBase.arg(2), logBase.arg(3));
+ moveFile(logBase.arg(1), logBase.arg(2));
+ moveFile(logBase.arg(0), logBase.arg(1));
+
+ logFile = std::unique_ptr<QFile>(new QFile(logBase.arg(0)));
+ if(!logFile->open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
+ {
+ showFatalErrorMessage(
+ "MultiMC data folder is not writable!",
+ "MultiMC couldn't create a log file - the MultiMC data folder is not writable.\n"
+ "\n"
+ #if defined(Q_OS_MAC)
+ MACOS_HINT
+ #endif
+ "Make sure you have write permissions to the MultiMC data folder.\n"
+ "\n"
+ "MultiMC cannot continue until you fix this problem."
+ );
+ return;
+ }
+ qInstallMessageHandler(appDebugOutput);
+ qDebug() << "<> Log initialized.";
+ }
+
+ // Set up paths
+ {
+ // Root path is used for updates.
#ifdef Q_OS_LINUX
- QDir foo(FS::PathCombine(binPath, ".."));
- m_rootPath = foo.absolutePath();
+ QDir foo(FS::PathCombine(binPath, ".."));
+ m_rootPath = foo.absolutePath();
#elif defined(Q_OS_WIN32)
- m_rootPath = binPath;
+ m_rootPath = binPath;
#elif defined(Q_OS_MAC)
- QDir foo(FS::PathCombine(binPath, "../.."));
- m_rootPath = foo.absolutePath();
- // on macOS, touch the root to force Finder to reload the .app metadata (and fix any icon change issues)
- FS::updateTimestamp(m_rootPath);
+ QDir foo(FS::PathCombine(binPath, "../.."));
+ m_rootPath = foo.absolutePath();
+ // on macOS, touch the root to force Finder to reload the .app metadata (and fix any icon change issues)
+ FS::updateTimestamp(m_rootPath);
#endif
#ifdef MULTIMC_JARS_LOCATION
- ENV.setJarsPath( TOSTRING(MULTIMC_JARS_LOCATION) );
+ ENV.setJarsPath( TOSTRING(MULTIMC_JARS_LOCATION) );
#endif
- qDebug() << "MultiMC 5, (c) 2013-2018 MultiMC Contributors";
- qDebug() << "Version : " << BuildConfig.printableVersionString();
- qDebug() << "Git commit : " << BuildConfig.GIT_COMMIT;
- qDebug() << "Git refspec : " << BuildConfig.GIT_REFSPEC;
- if (adjustedBy.size())
- {
- qDebug() << "Work dir before adjustment : " << origcwdPath;
- qDebug() << "Work dir after adjustment : " << QDir::currentPath();
- qDebug() << "Adjusted by : " << adjustedBy;
- }
- else
- {
- qDebug() << "Work dir : " << QDir::currentPath();
- }
- qDebug() << "Binary path : " << binPath;
- qDebug() << "Application root path : " << m_rootPath;
- if(!m_instanceIdToLaunch.isEmpty())
- {
- qDebug() << "ID of instance to launch : " << m_instanceIdToLaunch;
- }
- qDebug() << "<> Paths set.";
- }
-
- do // once
- {
- if(m_liveCheck)
- {
- QFile check(liveCheckFile);
- if(!check.open(QIODevice::WriteOnly | QIODevice::Truncate))
- {
- qWarning() << "Could not open" << liveCheckFile << "for writing!";
- break;
- }
- auto payload = appID.toString().toUtf8();
- if(check.write(payload) != payload.size())
- {
- qWarning() << "Could not write into" << liveCheckFile;
- check.remove();
- break;
- }
- check.close();
- }
- } while(false);
-
- // Initialize application settings
- {
- m_settings.reset(new INISettingsObject("multimc.cfg", this));
- // Updates
- m_settings->registerSetting("UpdateChannel", BuildConfig.VERSION_CHANNEL);
- m_settings->registerSetting("AutoUpdate", true);
-
- // Theming
- m_settings->registerSetting("IconTheme", QString("multimc"));
- m_settings->registerSetting("ApplicationTheme", QString("system"));
-
- // Notifications
- m_settings->registerSetting("ShownNotifications", QString());
-
- // Remembered state
- m_settings->registerSetting("LastUsedGroupForNewInstance", QString());
-
- QString defaultMonospace;
- int defaultSize = 11;
+ qDebug() << "MultiMC 5, (c) 2013-2019 MultiMC Contributors";
+ qDebug() << "Version : " << BuildConfig.printableVersionString();
+ qDebug() << "Git commit : " << BuildConfig.GIT_COMMIT;
+ qDebug() << "Git refspec : " << BuildConfig.GIT_REFSPEC;
+ if (adjustedBy.size())
+ {
+ qDebug() << "Work dir before adjustment : " << origcwdPath;
+ qDebug() << "Work dir after adjustment : " << QDir::currentPath();
+ qDebug() << "Adjusted by : " << adjustedBy;
+ }
+ else
+ {
+ qDebug() << "Work dir : " << QDir::currentPath();
+ }
+ qDebug() << "Binary path : " << binPath;
+ qDebug() << "Application root path : " << m_rootPath;
+ if(!m_instanceIdToLaunch.isEmpty())
+ {
+ qDebug() << "ID of instance to launch : " << m_instanceIdToLaunch;
+ }
+ qDebug() << "<> Paths set.";
+ }
+
+ do // once
+ {
+ if(m_liveCheck)
+ {
+ QFile check(liveCheckFile);
+ if(!check.open(QIODevice::WriteOnly | QIODevice::Truncate))
+ {
+ qWarning() << "Could not open" << liveCheckFile << "for writing!";
+ break;
+ }
+ auto payload = appID.toString().toUtf8();
+ if(check.write(payload) != payload.size())
+ {
+ qWarning() << "Could not write into" << liveCheckFile;
+ check.remove();
+ break;
+ }
+ check.close();
+ }
+ } while(false);
+
+ // Initialize application settings
+ {
+ m_settings.reset(new INISettingsObject("multimc.cfg", this));
+ // Updates
+ m_settings->registerSetting("UpdateChannel", BuildConfig.VERSION_CHANNEL);
+ m_settings->registerSetting("AutoUpdate", true);
+
+ // Theming
+ m_settings->registerSetting("IconTheme", QString("multimc"));
+ m_settings->registerSetting("ApplicationTheme", QString("system"));
+
+ // Notifications
+ m_settings->registerSetting("ShownNotifications", QString());
+
+ // Remembered state
+ m_settings->registerSetting("LastUsedGroupForNewInstance", QString());
+
+ QString defaultMonospace;
+ int defaultSize = 11;
#ifdef Q_OS_WIN32
- defaultMonospace = "Courier";
- defaultSize = 10;
+ defaultMonospace = "Courier";
+ defaultSize = 10;
#elif defined(Q_OS_MAC)
- defaultMonospace = "Menlo";
+ defaultMonospace = "Menlo";
#else
- defaultMonospace = "Monospace";
+ defaultMonospace = "Monospace";
#endif
- // resolve the font so the default actually matches
- QFont consoleFont;
- consoleFont.setFamily(defaultMonospace);
- consoleFont.setStyleHint(QFont::Monospace);
- consoleFont.setFixedPitch(true);
- QFontInfo consoleFontInfo(consoleFont);
- QString resolvedDefaultMonospace = consoleFontInfo.family();
- QFont resolvedFont(resolvedDefaultMonospace);
- qDebug() << "Detected default console font:" << resolvedDefaultMonospace
- << ", substitutions:" << resolvedFont.substitutions().join(',');
-
- m_settings->registerSetting("ConsoleFont", resolvedDefaultMonospace);
- m_settings->registerSetting("ConsoleFontSize", defaultSize);
- m_settings->registerSetting("ConsoleMaxLines", 100000);
- m_settings->registerSetting("ConsoleOverflowStop", true);
-
- // Folders
- m_settings->registerSetting("InstanceDir", "instances");
- m_settings->registerSetting({"CentralModsDir", "ModsDir"}, "mods");
- m_settings->registerSetting("IconsDir", "icons");
-
- // Editors
- m_settings->registerSetting("JsonEditor", QString());
-
- // Language
- m_settings->registerSetting("Language", QString());
-
- // Console
- m_settings->registerSetting("ShowConsole", false);
- m_settings->registerSetting("AutoCloseConsole", false);
- m_settings->registerSetting("ShowConsoleOnError", true);
- m_settings->registerSetting("LogPrePostOutput", true);
-
- // Window Size
- m_settings->registerSetting({"LaunchMaximized", "MCWindowMaximize"}, false);
- m_settings->registerSetting({"MinecraftWinWidth", "MCWindowWidth"}, 854);
- m_settings->registerSetting({"MinecraftWinHeight", "MCWindowHeight"}, 480);
-
- // Proxy Settings
- m_settings->registerSetting("ProxyType", "None");
- m_settings->registerSetting({"ProxyAddr", "ProxyHostName"}, "127.0.0.1");
- m_settings->registerSetting("ProxyPort", 8080);
- m_settings->registerSetting({"ProxyUser", "ProxyUsername"}, "");
- m_settings->registerSetting({"ProxyPass", "ProxyPassword"}, "");
-
- // Memory
- m_settings->registerSetting({"MinMemAlloc", "MinMemoryAlloc"}, 512);
- m_settings->registerSetting({"MaxMemAlloc", "MaxMemoryAlloc"}, 1024);
- m_settings->registerSetting("PermGen", 128);
-
- // Java Settings
- m_settings->registerSetting("JavaPath", "");
- m_settings->registerSetting("JavaTimestamp", 0);
- m_settings->registerSetting("JavaArchitecture", "");
- m_settings->registerSetting("JavaVersion", "");
- m_settings->registerSetting("LastHostname", "");
- m_settings->registerSetting("JvmArgs", "");
-
- // Minecraft launch method
- m_settings->registerSetting("MCLaunchMethod", "LauncherPart");
-
- // Wrapper command for launch
- m_settings->registerSetting("WrapperCommand", "");
-
- // Custom Commands
- m_settings->registerSetting({"PreLaunchCommand", "PreLaunchCmd"}, "");
- m_settings->registerSetting({"PostExitCommand", "PostExitCmd"}, "");
-
- // The cat
- m_settings->registerSetting("TheCat", false);
-
- m_settings->registerSetting("InstSortMode", "Name");
- m_settings->registerSetting("SelectedInstance", QString());
-
- // Window state and geometry
- m_settings->registerSetting("MainWindowState", "");
- m_settings->registerSetting("MainWindowGeometry", "");
-
- m_settings->registerSetting("ConsoleWindowState", "");
- m_settings->registerSetting("ConsoleWindowGeometry", "");
-
- m_settings->registerSetting("SettingsGeometry", "");
-
- m_settings->registerSetting("PagedGeometry", "");
-
- m_settings->registerSetting("NewInstanceGeometry", "");
-
- m_settings->registerSetting("UpdateDialogGeometry", "");
-
- // paste.ee API key
- m_settings->registerSetting("PasteEEAPIKey", "multimc");
-
-/* if(!BuildConfig.ANALYTICS_ID.isEmpty())
- {
- // Analytics
- m_settings->registerSetting("Analytics", true);
- m_settings->registerSetting("AnalyticsSeen", 0);
- m_settings->registerSetting("AnalyticsClientID", QString());
- }
-*/
- // Init page provider
- {
- m_globalSettingsProvider = std::make_shared<GenericPageProvider>(tr("Settings"));
- m_globalSettingsProvider->addPage<MultiMCPage>();
- m_globalSettingsProvider->addPage<MinecraftPage>();
- m_globalSettingsProvider->addPage<JavaPage>();
- m_globalSettingsProvider->addPage<CustomCommandsPage>();
- m_globalSettingsProvider->addPage<ProxyPage>();
- // m_globalSettingsProvider->addPage<PackagesPage>();
- m_globalSettingsProvider->addPage<ExternalToolsPage>();
- m_globalSettingsProvider->addPage<AccountListPage>();
- m_globalSettingsProvider->addPage<PasteEEPage>();
- }
- qDebug() << "<> Settings loaded.";
- }
-
- // load translations
- {
- m_translations.reset(new TranslationsModel("translations"));
- auto bcp47Name = m_settings->get("Language").toString();
- m_translations->selectLanguage(bcp47Name);
- qDebug() << "Your language is" << bcp47Name;
- qDebug() << "<> Translations loaded.";
- }
-
- // initialize the updater
- if(BuildConfig.UPDATER_ENABLED)
- {
- m_updateChecker.reset(new UpdateChecker(BuildConfig.CHANLIST_URL, BuildConfig.VERSION_CHANNEL, BuildConfig.VERSION_BUILD));
- qDebug() << "<> Updater started.";
- }
-
- // Instance icons
- {
- auto setting = MMC->settings()->getSetting("IconsDir");
- QStringList instFolders =
- {
- ":/icons/multimc/32x32/instances/",
- ":/icons/multimc/50x50/instances/",
- ":/icons/multimc/128x128/instances/"
- };
- m_icons.reset(new IconList(instFolders, setting->get().toString()));
- connect(setting.get(), &Setting::SettingChanged,[&](const Setting &, QVariant value)
- {
- m_icons->directoryChanged(value.toString());
- });
- ENV.registerIconList(m_icons);
- qDebug() << "<> Instance icons intialized.";
- }
-
- // Icon themes
- {
- // TODO: icon themes and instance icons do not mesh well together. Rearrange and fix discrepancies!
- // set icon theme search path!
- auto searchPaths = QIcon::themeSearchPaths();
- searchPaths.append("iconthemes");
- QIcon::setThemeSearchPaths(searchPaths);
- qDebug() << "<> Icon themes initialized.";
- }
-
- // Initialize widget themes
- {
- auto insertTheme = [this](ITheme * theme)
- {
- m_themes.insert(std::make_pair(theme->id(), std::unique_ptr<ITheme>(theme)));
- };
- auto darkTheme = new DarkTheme();
- insertTheme(new SystemTheme());
- insertTheme(darkTheme);
- insertTheme(new BrightTheme());
- insertTheme(new CustomTheme(darkTheme, "custom"));
- qDebug() << "<> Widget themes initialized.";
- }
-
- // initialize and load all instances
- {
- auto InstDirSetting = m_settings->getSetting("InstanceDir");
- // instance path: check for problems with '!' in instance path and warn the user in the log
- // and rememer that we have to show him a dialog when the gui starts (if it does so)
- QString instDir = InstDirSetting->get().toString();
- qDebug() << "Instance path : " << instDir;
- if (FS::checkProblemticPathJava(QDir(instDir)))
- {
- qWarning() << "Your instance path contains \'!\' and this is known to cause java problems";
- }
- m_instances.reset(new InstanceList(this));
- m_instanceFolder = new FolderInstanceProvider(m_settings, instDir);
- connect(InstDirSetting.get(), &Setting::SettingChanged, m_instanceFolder, &FolderInstanceProvider::on_InstFolderChanged);
- m_instances->addInstanceProvider(m_instanceFolder);
- qDebug() << "Loading Instances...";
- m_instances->loadList(true);
- qDebug() << "<> Instances loaded.";
- }
-
- // and accounts
- {
- m_accounts.reset(new MojangAccountList(this));
- qDebug() << "Loading accounts...";
- m_accounts->setListFilePath("accounts.json", true);
- m_accounts->loadList();
- qDebug() << "<> Accounts loaded.";
- }
-
- // init the http meta cache
- {
- ENV.initHttpMetaCache();
- qDebug() << "<> Cache initialized.";
- }
-
- // init proxy settings
- {
- QString proxyTypeStr = settings()->get("ProxyType").toString();
- QString addr = settings()->get("ProxyAddr").toString();
- int port = settings()->get("ProxyPort").value<qint16>();
- QString user = settings()->get("ProxyUser").toString();
- QString pass = settings()->get("ProxyPass").toString();
- ENV.updateProxySettings(proxyTypeStr, addr, port, user, pass);
- qDebug() << "<> Proxy settings done.";
- }
-
- // now we have network, download translation updates
- m_translations->downloadIndex();
-
- //FIXME: what to do with these?
- m_profilers.insert("jprofiler", std::shared_ptr<BaseProfilerFactory>(new JProfilerFactory()));
- m_profilers.insert("jvisualvm", std::shared_ptr<BaseProfilerFactory>(new JVisualVMFactory()));
- for (auto profiler : m_profilers.values())
- {
- profiler->registerSettings(m_settings);
- }
-
- // Create the MCEdit thing... why is this here?
- {
- m_mcedit.reset(new MCEditTool(m_settings));
- }
-
- connect(this, &MultiMC::aboutToQuit, [this](){
- if(m_instances)
- {
- // save any remaining instance state
- m_instances->saveNow();
- }
- if(logFile)
- {
- logFile->flush();
- logFile->close();
- }
- });
-
- {
- setIconTheme(settings()->get("IconTheme").toString());
- qDebug() << "<> Icon theme set.";
- setApplicationTheme(settings()->get("ApplicationTheme").toString(), true);
- qDebug() << "<> Application theme set.";
- }
-
- // Initialize analytics
-/* [this]()
- {
- const int analyticsVersion = 2;
- if(BuildConfig.ANALYTICS_ID.isEmpty())
- {
- return;
- }
-
- auto analyticsSetting = m_settings->getSetting("Analytics");
- connect(analyticsSetting.get(), &Setting::SettingChanged, this, &MultiMC::analyticsSettingChanged);
- QString clientID = m_settings->get("AnalyticsClientID").toString();
- if(clientID.isEmpty())
- {
- clientID = QUuid::createUuid().toString();
- clientID.remove(QLatin1Char('{'));
- clientID.remove(QLatin1Char('}'));
- m_settings->set("AnalyticsClientID", clientID);
- }
- m_analytics = new GAnalytics(BuildConfig.ANALYTICS_ID, clientID, analyticsVersion, this);
- m_analytics->setLogLevel(GAnalytics::Debug);
- m_analytics->setAnonymizeIPs(true);
- m_analytics->setNetworkAccessManager(&ENV.qnam());
-
- if(m_settings->get("AnalyticsSeen").toInt() < m_analytics->version())
- {
- qDebug() << "Analytics info not seen by user yet (or old version).";
- return;
- }
- if(!m_settings->get("Analytics").toBool())
- {
- qDebug() << "Analytics disabled by user.";
- return;
- }
-
- m_analytics->enable();
- qDebug() << "<> Initialized analytics with tid" << BuildConfig.ANALYTICS_ID;
- }(); */
-
- if(createSetupWizard())
- {
- return;
- }
- performMainStartupAction();
+ // resolve the font so the default actually matches
+ QFont consoleFont;
+ consoleFont.setFamily(defaultMonospace);
+ consoleFont.setStyleHint(QFont::Monospace);
+ consoleFont.setFixedPitch(true);
+ QFontInfo consoleFontInfo(consoleFont);
+ QString resolvedDefaultMonospace = consoleFontInfo.family();
+ QFont resolvedFont(resolvedDefaultMonospace);
+ qDebug() << "Detected default console font:" << resolvedDefaultMonospace
+ << ", substitutions:" << resolvedFont.substitutions().join(',');
+
+ m_settings->registerSetting("ConsoleFont", resolvedDefaultMonospace);
+ m_settings->registerSetting("ConsoleFontSize", defaultSize);
+ m_settings->registerSetting("ConsoleMaxLines", 100000);
+ m_settings->registerSetting("ConsoleOverflowStop", true);
+
+ // Folders
+ m_settings->registerSetting("InstanceDir", "instances");
+ m_settings->registerSetting({"CentralModsDir", "ModsDir"}, "mods");
+ m_settings->registerSetting("IconsDir", "icons");
+
+ // Editors
+ m_settings->registerSetting("JsonEditor", QString());
+
+ // Language
+ m_settings->registerSetting("Language", QString());
+
+ // Console
+ m_settings->registerSetting("ShowConsole", false);
+ m_settings->registerSetting("AutoCloseConsole", false);
+ m_settings->registerSetting("ShowConsoleOnError", true);
+ m_settings->registerSetting("LogPrePostOutput", true);
+
+ // Window Size
+ m_settings->registerSetting({"LaunchMaximized", "MCWindowMaximize"}, false);
+ m_settings->registerSetting({"MinecraftWinWidth", "MCWindowWidth"}, 854);
+ m_settings->registerSetting({"MinecraftWinHeight", "MCWindowHeight"}, 480);
+
+ // Proxy Settings
+ m_settings->registerSetting("ProxyType", "None");
+ m_settings->registerSetting({"ProxyAddr", "ProxyHostName"}, "127.0.0.1");
+ m_settings->registerSetting("ProxyPort", 8080);
+ m_settings->registerSetting({"ProxyUser", "ProxyUsername"}, "");
+ m_settings->registerSetting({"ProxyPass", "ProxyPassword"}, "");
+
+ // Memory
+ m_settings->registerSetting({"MinMemAlloc", "MinMemoryAlloc"}, 512);
+ m_settings->registerSetting({"MaxMemAlloc", "MaxMemoryAlloc"}, 1024);
+ m_settings->registerSetting("PermGen", 128);
+
+ // Java Settings
+ m_settings->registerSetting("JavaPath", "");
+ m_settings->registerSetting("JavaTimestamp", 0);
+ m_settings->registerSetting("JavaArchitecture", "");
+ m_settings->registerSetting("JavaVersion", "");
+ m_settings->registerSetting("LastHostname", "");
+ m_settings->registerSetting("JvmArgs", "");
+
+ // Minecraft launch method
+ m_settings->registerSetting("MCLaunchMethod", "LauncherPart");
+
+ // Wrapper command for launch
+ m_settings->registerSetting("WrapperCommand", "");
+
+ // Custom Commands
+ m_settings->registerSetting({"PreLaunchCommand", "PreLaunchCmd"}, "");
+ m_settings->registerSetting({"PostExitCommand", "PostExitCmd"}, "");
+
+ // The cat
+ m_settings->registerSetting("TheCat", false);
+
+ m_settings->registerSetting("InstSortMode", "Name");
+ m_settings->registerSetting("SelectedInstance", QString());
+
+ // Window state and geometry
+ m_settings->registerSetting("MainWindowState", "");
+ m_settings->registerSetting("MainWindowGeometry", "");
+
+ m_settings->registerSetting("ConsoleWindowState", "");
+ m_settings->registerSetting("ConsoleWindowGeometry", "");
+
+ m_settings->registerSetting("SettingsGeometry", "");
+
+ m_settings->registerSetting("PagedGeometry", "");
+
+ m_settings->registerSetting("NewInstanceGeometry", "");
+
+ m_settings->registerSetting("UpdateDialogGeometry", "");
+
+ // paste.ee API key
+ m_settings->registerSetting("PasteEEAPIKey", "multimc");
+
+ // Init page provider
+ {
+ m_globalSettingsProvider = std::make_shared<GenericPageProvider>(tr("Settings"));
+ m_globalSettingsProvider->addPage<MultiMCPage>();
+ m_globalSettingsProvider->addPage<MinecraftPage>();
+ m_globalSettingsProvider->addPage<JavaPage>();
+ m_globalSettingsProvider->addPage<LanguagePage>();
+ m_globalSettingsProvider->addPage<CustomCommandsPage>();
+ m_globalSettingsProvider->addPage<ProxyPage>();
+ // m_globalSettingsProvider->addPage<PackagesPage>();
+ m_globalSettingsProvider->addPage<ExternalToolsPage>();
+ m_globalSettingsProvider->addPage<AccountListPage>();
+ m_globalSettingsProvider->addPage<PasteEEPage>();
+ }
+ qDebug() << "<> Settings loaded.";
+ }
+
+ QAccessible::installFactory(groupViewAccessibleFactory);
+
+ // load translations
+ {
+ m_translations.reset(new TranslationsModel("translations"));
+ auto bcp47Name = m_settings->get("Language").toString();
+ m_translations->selectLanguage(bcp47Name);
+ qDebug() << "Your language is" << bcp47Name;
+ qDebug() << "<> Translations loaded.";
+ }
+
+ // initialize the updater
+ if(BuildConfig.UPDATER_ENABLED)
+ {
+ m_updateChecker.reset(new UpdateChecker(BuildConfig.CHANLIST_URL, BuildConfig.VERSION_CHANNEL, BuildConfig.VERSION_BUILD));
+ qDebug() << "<> Updater started.";
+ }
+
+ // Instance icons
+ {
+ auto setting = MMC->settings()->getSetting("IconsDir");
+ QStringList instFolders =
+ {
+ ":/icons/multimc/32x32/instances/",
+ ":/icons/multimc/50x50/instances/",
+ ":/icons/multimc/128x128/instances/",
+ ":/icons/multimc/scalable/instances/"
+ };
+ m_icons.reset(new IconList(instFolders, setting->get().toString()));
+ connect(setting.get(), &Setting::SettingChanged,[&](const Setting &, QVariant value)
+ {
+ m_icons->directoryChanged(value.toString());
+ });
+ ENV.registerIconList(m_icons);
+ qDebug() << "<> Instance icons intialized.";
+ }
+
+ // Icon themes
+ {
+ // TODO: icon themes and instance icons do not mesh well together. Rearrange and fix discrepancies!
+ // set icon theme search path!
+ auto searchPaths = QIcon::themeSearchPaths();
+ searchPaths.append("iconthemes");
+ QIcon::setThemeSearchPaths(searchPaths);
+ qDebug() << "<> Icon themes initialized.";
+ }
+
+ // Initialize widget themes
+ {
+ auto insertTheme = [this](ITheme * theme)
+ {
+ m_themes.insert(std::make_pair(theme->id(), std::unique_ptr<ITheme>(theme)));
+ };
+ auto darkTheme = new DarkTheme();
+ insertTheme(new SystemTheme());
+ insertTheme(darkTheme);
+ insertTheme(new BrightTheme());
+ insertTheme(new CustomTheme(darkTheme, "custom"));
+ qDebug() << "<> Widget themes initialized.";
+ }
+
+ // initialize and load all instances
+ {
+ auto InstDirSetting = m_settings->getSetting("InstanceDir");
+ // instance path: check for problems with '!' in instance path and warn the user in the log
+ // and rememer that we have to show him a dialog when the gui starts (if it does so)
+ QString instDir = InstDirSetting->get().toString();
+ qDebug() << "Instance path : " << instDir;
+ if (FS::checkProblemticPathJava(QDir(instDir)))
+ {
+ qWarning() << "Your instance path contains \'!\' and this is known to cause java problems";
+ }
+ m_instances.reset(new InstanceList(m_settings, instDir, this));
+ connect(InstDirSetting.get(), &Setting::SettingChanged, m_instances.get(), &InstanceList::on_InstFolderChanged);
+ qDebug() << "Loading Instances...";
+ m_instances->loadList();
+ qDebug() << "<> Instances loaded.";
+ }
+
+ // and accounts
+ {
+ m_accounts.reset(new MojangAccountList(this));
+ qDebug() << "Loading accounts...";
+ m_accounts->setListFilePath("accounts.json", true);
+ m_accounts->loadList();
+ qDebug() << "<> Accounts loaded.";
+ }
+
+ // init the http meta cache
+ {
+ ENV.initHttpMetaCache();
+ qDebug() << "<> Cache initialized.";
+ }
+
+ // init proxy settings
+ {
+ QString proxyTypeStr = settings()->get("ProxyType").toString();
+ QString addr = settings()->get("ProxyAddr").toString();
+ int port = settings()->get("ProxyPort").value<qint16>();
+ QString user = settings()->get("ProxyUser").toString();
+ QString pass = settings()->get("ProxyPass").toString();
+ ENV.updateProxySettings(proxyTypeStr, addr, port, user, pass);
+ qDebug() << "<> Proxy settings done.";
+ }
+
+ // now we have network, download translation updates
+ m_translations->downloadIndex();
+
+ //FIXME: what to do with these?
+ m_profilers.insert("jprofiler", std::shared_ptr<BaseProfilerFactory>(new JProfilerFactory()));
+ m_profilers.insert("jvisualvm", std::shared_ptr<BaseProfilerFactory>(new JVisualVMFactory()));
+ for (auto profiler : m_profilers.values())
+ {
+ profiler->registerSettings(m_settings);
+ }
+
+ // Create the MCEdit thing... why is this here?
+ {
+ m_mcedit.reset(new MCEditTool(m_settings));
+ }
+
+ connect(this, &MultiMC::aboutToQuit, [this](){
+ if(m_instances)
+ {
+ // save any remaining instance state
+ m_instances->saveNow();
+ }
+ if(logFile)
+ {
+ logFile->flush();
+ logFile->close();
+ }
+ });
+
+ {
+ setIconTheme(settings()->get("IconTheme").toString());
+ qDebug() << "<> Icon theme set.";
+ setApplicationTheme(settings()->get("ApplicationTheme").toString(), true);
+ qDebug() << "<> Application theme set.";
+ }
+
+ if(createSetupWizard())
+ {
+ return;
+ }
+ performMainStartupAction();
}
bool MultiMC::createSetupWizard()
{
- bool javaRequired = [&]()
- {
- QString currentHostName = QHostInfo::localHostName();
- QString oldHostName = settings()->get("LastHostname").toString();
- if (currentHostName != oldHostName)
- {
- settings()->set("LastHostname", currentHostName);
- return true;
- }
- QString currentJavaPath = settings()->get("JavaPath").toString();
- QString actualPath = FS::ResolveExecutable(currentJavaPath);
- if (actualPath.isNull())
- {
- return true;
- }
- return false;
- }/*();
- bool analyticsRequired = [&]()
- {
- if(BuildConfig.ANALYTICS_ID.isEmpty())
- {
- return false;
- }
- if (!settings()->get("Analytics").toBool())
- {
- return false;
- }
- if (settings()->get("AnalyticsSeen").toInt() < analytics()->version())
- {
- return true;
- }
- return false;
- }*/();
- bool languageRequired = [&]()
- {
- if (settings()->get("Language").toString().isEmpty())
- return true;
- return false;
- }();
-/* bool wizardRequired = javaRequired || analyticsRequired || languageRequired;
-*/ bool wizardRequired = javaRequired || languageRequired;
-
- if(wizardRequired)
- {
- m_setupWizard = new SetupWizard(nullptr);
- if (languageRequired)
- {
- m_setupWizard->addPage(new LanguageWizardPage(m_setupWizard));
- }
- if (javaRequired)
- {
- m_setupWizard->addPage(new JavaWizardPage(m_setupWizard));
- }
-/* if(analyticsRequired)
- {
- m_setupWizard->addPage(new AnalyticsWizardPage(m_setupWizard));
- }
-*/ connect(m_setupWizard, &QDialog::finished, this, &MultiMC::setupWizardFinished);
- m_setupWizard->show();
- return true;
- }
- return false;
+ bool javaRequired = [&]()
+ {
+ QString currentHostName = QHostInfo::localHostName();
+ QString oldHostName = settings()->get("LastHostname").toString();
+ if (currentHostName != oldHostName)
+ {
+ settings()->set("LastHostname", currentHostName);
+ return true;
+ }
+ QString currentJavaPath = settings()->get("JavaPath").toString();
+ QString actualPath = FS::ResolveExecutable(currentJavaPath);
+ if (actualPath.isNull())
+ {
+ return true;
+ }
+ return false;
+ }();
+ bool languageRequired = [&]()
+ {
+ if (settings()->get("Language").toString().isEmpty())
+ return true;
+ return false;
+ }();
+ bool wizardRequired = javaRequired || languageRequired;
+
+ if(wizardRequired)
+ {
+ m_setupWizard = new SetupWizard(nullptr);
+ if (languageRequired)
+ {
+ m_setupWizard->addPage(new LanguageWizardPage(m_setupWizard));
+ }
+ if (javaRequired)
+ {
+ m_setupWizard->addPage(new JavaWizardPage(m_setupWizard));
+ }
+ connect(m_setupWizard, &QDialog::finished, this, &MultiMC::setupWizardFinished);
+ m_setupWizard->show();
+ return true;
+ }
+ return false;
}
void MultiMC::setupWizardFinished(int status)
{
- qDebug() << "Wizard result =" << status;
- performMainStartupAction();
+ qDebug() << "Wizard result =" << status;
+ performMainStartupAction();
}
void MultiMC::performMainStartupAction()
{
- m_status = MultiMC::Initialized;
- if(!m_instanceIdToLaunch.isEmpty())
- {
- auto inst = instances()->getInstanceById(m_instanceIdToLaunch);
- if(inst)
- {
- qDebug() << "<> Instance launching:" << m_instanceIdToLaunch;
- launch(inst, true, nullptr);
- return;
- }
- }
- if(!m_mainWindow)
- {
- // normal main window
- showMainWindow(false);
- qDebug() << "<> Main window shown.";
- }
+ m_status = MultiMC::Initialized;
+ if(!m_instanceIdToLaunch.isEmpty())
+ {
+ auto inst = instances()->getInstanceById(m_instanceIdToLaunch);
+ if(inst)
+ {
+ qDebug() << "<> Instance launching:" << m_instanceIdToLaunch;
+ launch(inst, true, nullptr);
+ return;
+ }
+ }
+ if(!m_mainWindow)
+ {
+ // normal main window
+ showMainWindow(false);
+ qDebug() << "<> Main window shown.";
+ }
}
void MultiMC::showFatalErrorMessage(const QString& title, const QString& content)
{
- m_status = MultiMC::Failed;
- auto dialog = CustomMessageBox::selectable(nullptr, title, content, QMessageBox::Critical);
- dialog->exec();
+ m_status = MultiMC::Failed;
+ auto dialog = CustomMessageBox::selectable(nullptr, title, content, QMessageBox::Critical);
+ dialog->exec();
}
MultiMC::~MultiMC()
{
- // kill the other globals.
- Env::dispose();
+ // kill the other globals.
+ Env::dispose();
- // Shut down logger by setting the logger function to nothing
- qInstallMessageHandler(nullptr);
+ // Shut down logger by setting the logger function to nothing
+ qInstallMessageHandler(nullptr);
#if defined Q_OS_WIN32
- // Detach from Windows console
- if(consoleAttached)
- {
- fclose(stdout);
- fclose(stdin);
- fclose(stderr);
- FreeConsole();
- }
+ // Detach from Windows console
+ if(consoleAttached)
+ {
+ fclose(stdout);
+ fclose(stdin);
+ fclose(stderr);
+ FreeConsole();
+ }
#endif
}
void MultiMC::messageReceived(const QString& message)
{
- if(status() != Initialized)
- {
- qDebug() << "Received message" << message << "while still initializing. It will be ignored.";
- return;
- }
- if(message == "activate")
- {
- showMainWindow();
- }
- else
- {
- auto inst = instances()->getInstanceById(message);
- if(inst)
- {
- launch(inst, true, nullptr);
- }
- }
+ if(status() != Initialized)
+ {
+ qDebug() << "Received message" << message << "while still initializing. It will be ignored.";
+ return;
+ }
+ if(message == "activate")
+ {
+ showMainWindow();
+ }
+ else
+ {
+ auto inst = instances()->getInstanceById(message);
+ if(inst)
+ {
+ launch(inst, true, nullptr);
+ }
+ }
}
/*
void MultiMC::analyticsSettingChanged(const Setting&, QVariant value)
{
- if(!m_analytics)
- return;
- bool enabled = value.toBool();
- if(enabled)
- {
- qDebug() << "Analytics enabled by user.";
- }
- else
- {
- qDebug() << "Analytics disabled by user.";
- }
- m_analytics->enable(enabled);
+ if(!m_analytics)
+ return;
+ bool enabled = value.toBool();
+ if(enabled)
+ {
+ qDebug() << "Analytics enabled by user.";
+ }
+ else
+ {
+ qDebug() << "Analytics disabled by user.";
+ }
+ m_analytics->enable(enabled);
}
*/
std::shared_ptr<TranslationsModel> MultiMC::translations()
{
- return m_translations;
+ return m_translations;
}
std::shared_ptr<JavaInstallList> MultiMC::javalist()
{
- if (!m_javalist)
- {
- m_javalist.reset(new JavaInstallList());
- }
- return m_javalist;
+ if (!m_javalist)
+ {
+ m_javalist.reset(new JavaInstallList());
+ }
+ return m_javalist;
}
std::vector<ITheme *> MultiMC::getValidApplicationThemes()
{
- std::vector<ITheme *> ret;
- auto iter = m_themes.cbegin();
- while (iter != m_themes.cend())
- {
- ret.push_back((*iter).second.get());
- iter++;
- }
- return ret;
+ std::vector<ITheme *> ret;
+ auto iter = m_themes.cbegin();
+ while (iter != m_themes.cend())
+ {
+ ret.push_back((*iter).second.get());
+ iter++;
+ }
+ return ret;
}
void MultiMC::setApplicationTheme(const QString& name, bool initial)
{
- auto systemPalette = qApp->palette();
- auto themeIter = m_themes.find(name);
- if(themeIter != m_themes.end())
- {
- auto & theme = (*themeIter).second;
- theme->apply(initial);
- }
- else
- {
- qWarning() << "Tried to set invalid theme:" << name;
- }
+ auto systemPalette = qApp->palette();
+ auto themeIter = m_themes.find(name);
+ if(themeIter != m_themes.end())
+ {
+ auto & theme = (*themeIter).second;
+ theme->apply(initial);
+ }
+ else
+ {
+ qWarning() << "Tried to set invalid theme:" << name;
+ }
}
void MultiMC::setIconTheme(const QString& name)
{
- XdgIcon::setThemeName(name);
+ XdgIcon::setThemeName(name);
}
QIcon MultiMC::getThemedIcon(const QString& name)
{
- return XdgIcon::fromTheme(name);
+ return XdgIcon::fromTheme(name);
}
bool MultiMC::openJsonEditor(const QString &filename)
{
- const QString file = QDir::current().absoluteFilePath(filename);
- if (m_settings->get("JsonEditor").toString().isEmpty())
- {
- return DesktopServices::openUrl(QUrl::fromLocalFile(file));
- }
- else
- {
- //return DesktopServices::openFile(m_settings->get("JsonEditor").toString(), file);
- return DesktopServices::run(m_settings->get("JsonEditor").toString(), {file});
- }
+ const QString file = QDir::current().absoluteFilePath(filename);
+ if (m_settings->get("JsonEditor").toString().isEmpty())
+ {
+ return DesktopServices::openUrl(QUrl::fromLocalFile(file));
+ }
+ else
+ {
+ //return DesktopServices::openFile(m_settings->get("JsonEditor").toString(), file);
+ return DesktopServices::run(m_settings->get("JsonEditor").toString(), {file});
+ }
}
bool MultiMC::launch(InstancePtr instance, bool online, BaseProfilerFactory *profiler)
{
- if(m_updateRunning)
- {
- qDebug() << "Cannot launch instances while an update is running.";
- }
- else if(instance->canLaunch())
- {
- auto & extras = m_instanceExtras[instance->id()];
- auto & window = extras.window;
- if(window)
- {
- if(!window->saveAll())
- {
- return false;
- }
- }
- auto & controller = extras.controller;
- controller.reset(new LaunchController());
- controller->setInstance(instance);
- controller->setOnline(online);
- controller->setProfiler(profiler);
- if(window)
- {
- controller->setParentWidget(window);
- }
- else if(m_mainWindow)
- {
- controller->setParentWidget(m_mainWindow);
- }
- connect(controller.get(), &LaunchController::succeeded, this, &MultiMC::controllerSucceeded);
- connect(controller.get(), &LaunchController::failed, this, &MultiMC::controllerFailed);
- addRunningInstance();
- controller->start();
- return true;
- }
- else if (instance->isRunning())
- {
- showInstanceWindow(instance, "console");
- return true;
- }
- else if (instance->canEdit())
- {
- showInstanceWindow(instance);
- return true;
- }
- return false;
+ if(m_updateRunning)
+ {
+ qDebug() << "Cannot launch instances while an update is running.";
+ }
+ else if(instance->canLaunch())
+ {
+ auto & extras = m_instanceExtras[instance->id()];
+ auto & window = extras.window;
+ if(window)
+ {
+ if(!window->saveAll())
+ {
+ return false;
+ }
+ }
+ auto & controller = extras.controller;
+ controller.reset(new LaunchController());
+ controller->setInstance(instance);
+ controller->setOnline(online);
+ controller->setProfiler(profiler);
+ if(window)
+ {
+ controller->setParentWidget(window);
+ }
+ else if(m_mainWindow)
+ {
+ controller->setParentWidget(m_mainWindow);
+ }
+ connect(controller.get(), &LaunchController::succeeded, this, &MultiMC::controllerSucceeded);
+ connect(controller.get(), &LaunchController::failed, this, &MultiMC::controllerFailed);
+ addRunningInstance();
+ controller->start();
+ return true;
+ }
+ else if (instance->isRunning())
+ {
+ showInstanceWindow(instance, "console");
+ return true;
+ }
+ else if (instance->canEdit())
+ {
+ showInstanceWindow(instance);
+ return true;
+ }
+ return false;
}
bool MultiMC::kill(InstancePtr instance)
{
- if (!instance->isRunning())
- {
- qWarning() << "Attempted to kill instance" << instance->id() << "which isn't running.";
- return false;
- }
- auto & extras = m_instanceExtras[instance->id()];
- // NOTE: copy of the shared pointer keeps it alive
- auto controller = extras.controller;
- if(controller)
- {
- return controller->abort();
- }
- return true;
+ if (!instance->isRunning())
+ {
+ qWarning() << "Attempted to kill instance" << instance->id() << "which isn't running.";
+ return false;
+ }
+ auto & extras = m_instanceExtras[instance->id()];
+ // NOTE: copy of the shared pointer keeps it alive
+ auto controller = extras.controller;
+ if(controller)
+ {
+ return controller->abort();
+ }
+ return true;
}
void MultiMC::addRunningInstance()
{
- m_runningInstances ++;
- if(m_runningInstances == 1)
- {
- emit updateAllowedChanged(false);
- }
+ m_runningInstances ++;
+ if(m_runningInstances == 1)
+ {
+ emit updateAllowedChanged(false);
+ }
}
void MultiMC::subRunningInstance()
{
- if(m_runningInstances == 0)
- {
- qCritical() << "Something went really wrong and we now have less than 0 running instances... WTF";
- return;
- }
- m_runningInstances --;
- if(m_runningInstances == 0)
- {
- emit updateAllowedChanged(true);
- }
+ if(m_runningInstances == 0)
+ {
+ qCritical() << "Something went really wrong and we now have less than 0 running instances... WTF";
+ return;
+ }
+ m_runningInstances --;
+ if(m_runningInstances == 0)
+ {
+ emit updateAllowedChanged(true);
+ }
}
bool MultiMC::shouldExitNow() const
{
- return m_runningInstances == 0 && m_openWindows == 0;
+ return m_runningInstances == 0 && m_openWindows == 0;
}
bool MultiMC::updatesAreAllowed()
{
- return m_runningInstances == 0;
+ return m_runningInstances == 0;
}
void MultiMC::updateIsRunning(bool running)
{
- m_updateRunning = running;
+ m_updateRunning = running;
}
void MultiMC::controllerSucceeded()
{
- auto controller = qobject_cast<LaunchController *>(QObject::sender());
- if(!controller)
- return;
- auto id = controller->id();
- auto & extras = m_instanceExtras[id];
-
- // on success, do...
- if (controller->instance()->settings()->get("AutoCloseConsole").toBool())
- {
- if(extras.window)
- {
- extras.window->close();
- }
- }
- extras.controller.reset();
- subRunningInstance();
-
- // quit when there are no more windows.
- if(shouldExitNow())
- {
- m_status = Status::Succeeded;
- exit(0);
- }
+ auto controller = qobject_cast<LaunchController *>(QObject::sender());
+ if(!controller)
+ return;
+ auto id = controller->id();
+ auto & extras = m_instanceExtras[id];
+
+ // on success, do...
+ if (controller->instance()->settings()->get("AutoCloseConsole").toBool())
+ {
+ if(extras.window)
+ {
+ extras.window->close();
+ }
+ }
+ extras.controller.reset();
+ subRunningInstance();
+
+ // quit when there are no more windows.
+ if(shouldExitNow())
+ {
+ m_status = Status::Succeeded;
+ exit(0);
+ }
}
void MultiMC::controllerFailed(const QString& error)
{
- Q_UNUSED(error);
- auto controller = qobject_cast<LaunchController *>(QObject::sender());
- if(!controller)
- return;
- auto id = controller->id();
- auto & extras = m_instanceExtras[id];
-
- // on failure, do... nothing
- extras.controller.reset();
- subRunningInstance();
-
- // quit when there are no more windows.
- if(shouldExitNow())
- {
- m_status = Status::Failed;
- exit(1);
- }
+ Q_UNUSED(error);
+ auto controller = qobject_cast<LaunchController *>(QObject::sender());
+ if(!controller)
+ return;
+ auto id = controller->id();
+ auto & extras = m_instanceExtras[id];
+
+ // on failure, do... nothing
+ extras.controller.reset();
+ subRunningInstance();
+
+ // quit when there are no more windows.
+ if(shouldExitNow())
+ {
+ m_status = Status::Failed;
+ exit(1);
+ }
+}
+
+void MultiMC::ShowGlobalSettings(class QWidget* parent, QString open_page)
+{
+ if(!m_globalSettingsProvider) {
+ return;
+ }
+ emit globalSettingsAboutToOpen();
+ {
+ SettingsObject::Lock lock(MMC->settings());
+ PageDialog dlg(m_globalSettingsProvider.get(), open_page, parent);
+ dlg.exec();
+ }
+ emit globalSettingsClosed();
}
MainWindow* MultiMC::showMainWindow(bool minimized)
{
- if(m_mainWindow)
- {
- m_mainWindow->setWindowState(m_mainWindow->windowState() & ~Qt::WindowMinimized);
- m_mainWindow->raise();
- m_mainWindow->activateWindow();
- }
- else
- {
- m_mainWindow = new MainWindow();
- m_mainWindow->restoreState(QByteArray::fromBase64(MMC->settings()->get("MainWindowState").toByteArray()));
- m_mainWindow->restoreGeometry(QByteArray::fromBase64(MMC->settings()->get("MainWindowGeometry").toByteArray()));
- if(minimized)
- {
- m_mainWindow->showMinimized();
- }
- else
- {
- m_mainWindow->show();
- }
-
- m_mainWindow->checkInstancePathForProblems();
- connect(this, &MultiMC::updateAllowedChanged, m_mainWindow, &MainWindow::updatesAllowedChanged);
- connect(m_mainWindow, &MainWindow::isClosing, this, &MultiMC::on_windowClose);
- m_openWindows++;
- }
-/* // FIXME: move this somewhere else...
- if(m_analytics)
- {
- auto windowSize = m_mainWindow->size();
- auto sizeString = QString("%1x%2").arg(windowSize.width()).arg(windowSize.height());
- qDebug() << "Viewport size" << sizeString;
- m_analytics->setViewportSize(sizeString);
-*/ /*
- * cm1 = java min heap [MB]
- * cm2 = java max heap [MB]
- * cm3 = system RAM [MB]
- *
- * cd1 = java version
- * cd2 = java architecture
- * cd3 = system architecture
- * cd4 = CPU architecture
- */
-/* QVariantMap customValues;
- int min = m_settings->get("MinMemAlloc").toInt();
- int max = m_settings->get("MaxMemAlloc").toInt();
- if(min < max)
- {
- customValues["cm1"] = min;
- customValues["cm2"] = max;
- }
- else
- {
- customValues["cm1"] = max;
- customValues["cm2"] = min;
- }
-
- constexpr uint64_t Mega = 1024ull * 1024ull;
- int ramSize = int(Sys::getSystemRam() / Mega);
- qDebug() << "RAM size is" << ramSize << "MB";
- customValues["cm3"] = ramSize;
-
- customValues["cd1"] = m_settings->get("JavaVersion");
- customValues["cd2"] = m_settings->get("JavaArchitecture");
- customValues["cd3"] = Sys::isSystem64bit() ? "64":"32";
- customValues["cd4"] = Sys::isCPU64bit() ? "64":"32";
- auto kernelInfo = Sys::getKernelInfo();
- customValues["cd5"] = kernelInfo.kernelName;
- customValues["cd6"] = kernelInfo.kernelVersion;
- auto distInfo = Sys::getDistributionInfo();
- if(!distInfo.distributionName.isEmpty())
- {
- customValues["cd7"] = distInfo.distributionName;
- }
- if(!distInfo.distributionVersion.isEmpty())
- {
- customValues["cd8"] = distInfo.distributionVersion;
- }
- m_analytics->sendScreenView("Main Window", customValues);
- }
-*/
- return m_mainWindow;
+ if(m_mainWindow)
+ {
+ m_mainWindow->setWindowState(m_mainWindow->windowState() & ~Qt::WindowMinimized);
+ m_mainWindow->raise();
+ m_mainWindow->activateWindow();
+ }
+ else
+ {
+ m_mainWindow = new MainWindow();
+ m_mainWindow->restoreState(QByteArray::fromBase64(MMC->settings()->get("MainWindowState").toByteArray()));
+ m_mainWindow->restoreGeometry(QByteArray::fromBase64(MMC->settings()->get("MainWindowGeometry").toByteArray()));
+ if(minimized)
+ {
+ m_mainWindow->showMinimized();
+ }
+ else
+ {
+ m_mainWindow->show();
+ }
+
+ m_mainWindow->checkInstancePathForProblems();
+ connect(this, &MultiMC::updateAllowedChanged, m_mainWindow, &MainWindow::updatesAllowedChanged);
+ connect(m_mainWindow, &MainWindow::isClosing, this, &MultiMC::on_windowClose);
+ m_openWindows++;
+ }
+ return m_mainWindow;
}
InstanceWindow *MultiMC::showInstanceWindow(InstancePtr instance, QString page)
{
- if(!instance)
- return nullptr;
- auto id = instance->id();
- auto & extras = m_instanceExtras[id];
- auto & window = extras.window;
-
- if(window)
- {
- window->raise();
- window->activateWindow();
- }
- else
- {
- window = new InstanceWindow(instance);
- m_openWindows ++;
- connect(window, &InstanceWindow::isClosing, this, &MultiMC::on_windowClose);
- }
- if(!page.isEmpty())
- {
- window->selectPage(page);
- }
- if(extras.controller)
- {
- extras.controller->setParentWidget(window);
- }
- return window;
+ if(!instance)
+ return nullptr;
+ auto id = instance->id();
+ auto & extras = m_instanceExtras[id];
+ auto & window = extras.window;
+
+ if(window)
+ {
+ window->raise();
+ window->activateWindow();
+ }
+ else
+ {
+ window = new InstanceWindow(instance);
+ m_openWindows ++;
+ connect(window, &InstanceWindow::isClosing, this, &MultiMC::on_windowClose);
+ }
+ if(!page.isEmpty())
+ {
+ window->selectPage(page);
+ }
+ if(extras.controller)
+ {
+ extras.controller->setParentWidget(window);
+ }
+ return window;
}
void MultiMC::on_windowClose()
{
- m_openWindows--;
- auto instWindow = qobject_cast<InstanceWindow *>(QObject::sender());
- if(instWindow)
- {
- auto & extras = m_instanceExtras[instWindow->instanceId()];
- extras.window = nullptr;
- if(extras.controller)
- {
- extras.controller->setParentWidget(m_mainWindow);
- }
- }
- auto mainWindow = qobject_cast<MainWindow *>(QObject::sender());
- if(mainWindow)
- {
- m_mainWindow = nullptr;
- }
- // quit when there are no more windows.
- if(shouldExitNow())
- {
- exit(0);
- }
+ m_openWindows--;
+ auto instWindow = qobject_cast<InstanceWindow *>(QObject::sender());
+ if(instWindow)
+ {
+ auto & extras = m_instanceExtras[instWindow->instanceId()];
+ extras.window = nullptr;
+ if(extras.controller)
+ {
+ extras.controller->setParentWidget(m_mainWindow);
+ }
+ }
+ auto mainWindow = qobject_cast<MainWindow *>(QObject::sender());
+ if(mainWindow)
+ {
+ m_mainWindow = nullptr;
+ }
+ // quit when there are no more windows.
+ if(shouldExitNow())
+ {
+ exit(0);
+ }
}
diff --git a/application/MultiMC.h b/application/MultiMC.h
index 9c91d06d..056fca88 100644
--- a/application/MultiMC.h
+++ b/application/MultiMC.h
@@ -39,182 +39,189 @@ class MCEditTool;
class MultiMC : public QApplication
{
- // friends for the purpose of limiting access to deprecated stuff
- Q_OBJECT
+ // friends for the purpose of limiting access to deprecated stuff
+ Q_OBJECT
public:
- enum Status
- {
- StartingUp,
- Failed,
- Succeeded,
- Initialized
- };
+ enum Status
+ {
+ StartingUp,
+ Failed,
+ Succeeded,
+ Initialized
+ };
public:
- MultiMC(int &argc, char **argv);
- virtual ~MultiMC();
+ MultiMC(int &argc, char **argv);
+ virtual ~MultiMC();
- std::shared_ptr<SettingsObject> settings() const
- {
- return m_settings;
- }
+ std::shared_ptr<SettingsObject> settings() const
+ {
+ return m_settings;
+ }
- std::shared_ptr<GenericPageProvider> globalSettingsPages() const
- {
- return m_globalSettingsProvider;
- }
+ qint64 timeSinceStart() const
+ {
+ return startTime.msecsTo(QDateTime::currentDateTime());
+ }
- qint64 timeSinceStart() const
- {
- return startTime.msecsTo(QDateTime::currentDateTime());
- }
+ QIcon getThemedIcon(const QString& name);
- QIcon getThemedIcon(const QString& name);
+ void setIconTheme(const QString& name);
- void setIconTheme(const QString& name);
+ std::vector<ITheme *> getValidApplicationThemes();
- std::vector<ITheme *> getValidApplicationThemes();
+ void setApplicationTheme(const QString& name, bool initial);
- void setApplicationTheme(const QString& name, bool initial);
+ // DownloadUpdateTask
+ std::shared_ptr<UpdateChecker> updateChecker()
+ {
+ return m_updateChecker;
+ }
- // DownloadUpdateTask
- std::shared_ptr<UpdateChecker> updateChecker()
- {
- return m_updateChecker;
- }
+ std::shared_ptr<TranslationsModel> translations();
- std::shared_ptr<TranslationsModel> translations();
+ std::shared_ptr<JavaInstallList> javalist();
- std::shared_ptr<JavaInstallList> javalist();
+ std::shared_ptr<InstanceList> instances() const
+ {
+ return m_instances;
+ }
- std::shared_ptr<InstanceList> instances() const
- {
- return m_instances;
- }
+ FolderInstanceProvider * folderProvider() const
+ {
+ return m_instanceFolder;
+ }
- FolderInstanceProvider * folderProvider() const
- {
- return m_instanceFolder;
- }
+ std::shared_ptr<IconList> icons() const
+ {
+ return m_icons;
+ }
- std::shared_ptr<IconList> icons() const
- {
- return m_icons;
- }
+ MCEditTool *mcedit() const
+ {
+ return m_mcedit.get();
+ }
- MCEditTool *mcedit() const
- {
- return m_mcedit.get();
- }
+ std::shared_ptr<MojangAccountList> accounts() const
+ {
+ return m_accounts;
+ }
- std::shared_ptr<MojangAccountList> accounts() const
- {
- return m_accounts;
- }
+ Status status() const
+ {
+ return m_status;
+ }
- Status status() const
- {
- return m_status;
- }
+ const QMap<QString, std::shared_ptr<BaseProfilerFactory>> &profilers() const
+ {
+ return m_profilers;
+ }
- const QMap<QString, std::shared_ptr<BaseProfilerFactory>> &profilers() const
- {
- return m_profilers;
- }
+ /// this is the root of the 'installation'. Used for automatic updates
+ const QString &root()
+ {
+ return m_rootPath;
+ }
- /// this is the root of the 'installation'. Used for automatic updates
- const QString &root()
- {
- return m_rootPath;
- }
+ /*!
+ * Opens a json file using either a system default editor, or, if not empty, the editor
+ * specified in the settings
+ */
+ bool openJsonEditor(const QString &filename);
- /*!
- * Opens a json file using either a system default editor, or, if not empty, the editor
- * specified in the settings
- */
- bool openJsonEditor(const QString &filename);
+ InstanceWindow *showInstanceWindow(InstancePtr instance, QString page = QString());
+ MainWindow *showMainWindow(bool minimized = false);
- InstanceWindow *showInstanceWindow(InstancePtr instance, QString page = QString());
- MainWindow *showMainWindow(bool minimized = false);
+ void updateIsRunning(bool running);
+ bool updatesAreAllowed();
- void updateIsRunning(bool running);
- bool updatesAreAllowed();
+ void ShowGlobalSettings(class QWidget * parent, QString open_page = QString());
signals:
- void updateAllowedChanged(bool status);
+ void updateAllowedChanged(bool status);
+ void globalSettingsAboutToOpen();
+ void globalSettingsClosed();
public slots:
- bool launch(InstancePtr instance, bool online = true, BaseProfilerFactory *profiler = nullptr);
- bool kill(InstancePtr instance);
+ bool launch(InstancePtr instance, bool online = true, BaseProfilerFactory *profiler = nullptr);
+ bool kill(InstancePtr instance);
private slots:
+<<<<<<< HEAD
void on_windowClose();
void messageReceived(const QString & message);
void controllerSucceeded();
void controllerFailed(const QString & error);
/* void analyticsSettingChanged(const Setting &setting, QVariant value);
*/ void setupWizardFinished(int status);
+=======
+ void on_windowClose();
+ void messageReceived(const QString & message);
+ void controllerSucceeded();
+ void controllerFailed(const QString & error);
+ void analyticsSettingChanged(const Setting &setting, QVariant value);
+ void setupWizardFinished(int status);
+>>>>>>> origin/stable
private:
- bool createSetupWizard();
- void performMainStartupAction();
+ bool createSetupWizard();
+ void performMainStartupAction();
- // sets the fatal error message and m_status to Failed.
- void showFatalErrorMessage(const QString & title, const QString & content);
+ // sets the fatal error message and m_status to Failed.
+ void showFatalErrorMessage(const QString & title, const QString & content);
private:
- void addRunningInstance();
- void subRunningInstance();
- bool shouldExitNow() const;
+ void addRunningInstance();
+ void subRunningInstance();
+ bool shouldExitNow() const;
private:
- QDateTime startTime;
+ QDateTime startTime;
- std::shared_ptr<SettingsObject> m_settings;
- std::shared_ptr<InstanceList> m_instances;
- FolderInstanceProvider * m_instanceFolder = nullptr;
- std::shared_ptr<IconList> m_icons;
- std::shared_ptr<UpdateChecker> m_updateChecker;
- std::shared_ptr<MojangAccountList> m_accounts;
- std::shared_ptr<JavaInstallList> m_javalist;
- std::shared_ptr<TranslationsModel> m_translations;
- std::shared_ptr<GenericPageProvider> m_globalSettingsProvider;
- std::map<QString, std::unique_ptr<ITheme>> m_themes;
- std::unique_ptr<MCEditTool> m_mcedit;
+ std::shared_ptr<SettingsObject> m_settings;
+ std::shared_ptr<InstanceList> m_instances;
+ FolderInstanceProvider * m_instanceFolder = nullptr;
+ std::shared_ptr<IconList> m_icons;
+ std::shared_ptr<UpdateChecker> m_updateChecker;
+ std::shared_ptr<MojangAccountList> m_accounts;
+ std::shared_ptr<JavaInstallList> m_javalist;
+ std::shared_ptr<TranslationsModel> m_translations;
+ std::shared_ptr<GenericPageProvider> m_globalSettingsProvider;
+ std::map<QString, std::unique_ptr<ITheme>> m_themes;
+ std::unique_ptr<MCEditTool> m_mcedit;
- QMap<QString, std::shared_ptr<BaseProfilerFactory>> m_profilers;
+ QMap<QString, std::shared_ptr<BaseProfilerFactory>> m_profilers;
- QString m_rootPath;
- Status m_status = MultiMC::StartingUp;
+ QString m_rootPath;
+ Status m_status = MultiMC::StartingUp;
#if defined Q_OS_WIN32
- // used on Windows to attach the standard IO streams
- bool consoleAttached = false;
+ // used on Windows to attach the standard IO streams
+ bool consoleAttached = false;
#endif
- // FIXME: attach to instances instead.
- struct InstanceXtras
- {
- InstanceWindow * window = nullptr;
- shared_qobject_ptr<LaunchController> controller;
- };
- std::map<QString, InstanceXtras> m_instanceExtras;
+ // FIXME: attach to instances instead.
+ struct InstanceXtras
+ {
+ InstanceWindow * window = nullptr;
+ shared_qobject_ptr<LaunchController> controller;
+ };
+ std::map<QString, InstanceXtras> m_instanceExtras;
- // main state variables
- size_t m_openWindows = 0;
- size_t m_runningInstances = 0;
- bool m_updateRunning = false;
+ // main state variables
+ size_t m_openWindows = 0;
+ size_t m_runningInstances = 0;
+ bool m_updateRunning = false;
- // main window, if any
- MainWindow * m_mainWindow = nullptr;
+ // main window, if any
+ MainWindow * m_mainWindow = nullptr;
- // peer MultiMC instance connector - used to implement single instance MultiMC and signalling
- LocalPeer * m_peerInstance = nullptr;
+ // peer MultiMC instance connector - used to implement single instance MultiMC and signalling
+ LocalPeer * m_peerInstance = nullptr;
-/* GAnalytics * m_analytics = nullptr; */
- SetupWizard * m_setupWizard = nullptr;
+ SetupWizard * m_setupWizard = nullptr;
public:
- QString m_instanceIdToLaunch;
- bool m_liveCheck = false;
- std::unique_ptr<QFile> logFile;
+ QString m_instanceIdToLaunch;
+ bool m_liveCheck = false;
+ std::unique_ptr<QFile> logFile;
};
diff --git a/application/SettingsUI.h b/application/SettingsUI.h
deleted file mode 100644
index 0d14fbee..00000000
--- a/application/SettingsUI.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#pragma once
-#include "pages/BasePageProvider.h"
-#include "MultiMC.h"
-#include "pagedialog/PageDialog.h"
-#include "InstancePageProvider.h"
-#include <settings/SettingsObject.h>
-#include <BaseInstance.h>
-
-/*
- * FIXME: this is a fragment. find a better place for it.
- */
-namespace SettingsUI
-{
-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;
- {
- SettingsObject::Lock lock(MMC->settings());
- PageDialog dlg(provider.get(), open_page, parent);
- dlg.exec();
- }
-}
-}
diff --git a/application/UpdateController.cpp b/application/UpdateController.cpp
index 8df5b3fc..0309ad93 100644
--- a/application/UpdateController.cpp
+++ b/application/UpdateController.cpp
@@ -27,423 +27,423 @@
#endif
static QFile::Permissions unixModeToPermissions(const int mode)
{
- QFile::Permissions perms;
+ QFile::Permissions perms;
- if (mode & S_IRUSR)
- {
- perms |= QFile::ReadUser;
- }
- if (mode & S_IWUSR)
- {
- perms |= QFile::WriteUser;
- }
- if (mode & S_IXUSR)
- {
- perms |= QFile::ExeUser;
- }
+ if (mode & S_IRUSR)
+ {
+ perms |= QFile::ReadUser;
+ }
+ if (mode & S_IWUSR)
+ {
+ perms |= QFile::WriteUser;
+ }
+ if (mode & S_IXUSR)
+ {
+ perms |= QFile::ExeUser;
+ }
- if (mode & S_IRGRP)
- {
- perms |= QFile::ReadGroup;
- }
- if (mode & S_IWGRP)
- {
- perms |= QFile::WriteGroup;
- }
- if (mode & S_IXGRP)
- {
- perms |= QFile::ExeGroup;
- }
+ if (mode & S_IRGRP)
+ {
+ perms |= QFile::ReadGroup;
+ }
+ if (mode & S_IWGRP)
+ {
+ perms |= QFile::WriteGroup;
+ }
+ if (mode & S_IXGRP)
+ {
+ perms |= QFile::ExeGroup;
+ }
- if (mode & S_IROTH)
- {
- perms |= QFile::ReadOther;
- }
- if (mode & S_IWOTH)
- {
- perms |= QFile::WriteOther;
- }
- if (mode & S_IXOTH)
- {
- perms |= QFile::ExeOther;
- }
- return perms;
+ if (mode & S_IROTH)
+ {
+ perms |= QFile::ReadOther;
+ }
+ if (mode & S_IWOTH)
+ {
+ perms |= QFile::WriteOther;
+ }
+ if (mode & S_IXOTH)
+ {
+ perms |= QFile::ExeOther;
+ }
+ return perms;
}
static const QLatin1String liveCheckFile("live.check");
UpdateController::UpdateController(QWidget * parent, const QString& root, const QString updateFilesDir, GoUpdate::OperationList operations)
{
- m_parent = parent;
- m_root = root;
- m_updateFilesDir = updateFilesDir;
- m_operations = operations;
+ m_parent = parent;
+ m_root = root;
+ m_updateFilesDir = updateFilesDir;
+ m_operations = operations;
}
void UpdateController::installUpdates()
{
- qint64 pid = -1;
- QStringList args;
- bool started = false;
+ qint64 pid = -1;
+ QStringList args;
+ bool started = false;
- qDebug() << "Installing updates.";
+ qDebug() << "Installing updates.";
#ifdef Q_OS_WIN
- QString finishCmd = QApplication::applicationFilePath();
+ QString finishCmd = QApplication::applicationFilePath();
#elif defined Q_OS_LINUX
- QString finishCmd = FS::PathCombine(m_root, "MultiMC");
+ QString finishCmd = FS::PathCombine(m_root, "MultiMC");
#elif defined Q_OS_MAC
- QString finishCmd = QApplication::applicationFilePath();
+ QString finishCmd = QApplication::applicationFilePath();
#else
#error Unsupported operating system.
#endif
- QString backupPath = FS::PathCombine(m_root, "update", "backup");
- QDir origin(m_root);
+ QString backupPath = FS::PathCombine(m_root, "update", "backup");
+ QDir origin(m_root);
- // clean up the backup folder. it should be empty before we start
- if(!FS::deletePath(backupPath))
- {
- qWarning() << "couldn't remove previous backup folder" << backupPath;
- }
- // and it should exist.
- if(!FS::ensureFolderPathExists(backupPath))
- {
- qWarning() << "couldn't create folder" << backupPath;
- return;
- }
+ // clean up the backup folder. it should be empty before we start
+ if(!FS::deletePath(backupPath))
+ {
+ qWarning() << "couldn't remove previous backup folder" << backupPath;
+ }
+ // and it should exist.
+ if(!FS::ensureFolderPathExists(backupPath))
+ {
+ qWarning() << "couldn't create folder" << backupPath;
+ return;
+ }
- bool useXPHack = false;
- QString exePath;
- QString exeOrigin;
- QString exeBackup;
+ bool useXPHack = false;
+ QString exePath;
+ QString exeOrigin;
+ QString exeBackup;
- // perform the update operations
- for(auto op: m_operations)
- {
- switch(op.type)
- {
- // replace = move original out to backup, if it exists, move the new file in its place
- case GoUpdate::Operation::OP_REPLACE:
- {
+ // perform the update operations
+ for(auto op: m_operations)
+ {
+ switch(op.type)
+ {
+ // replace = move original out to backup, if it exists, move the new file in its place
+ case GoUpdate::Operation::OP_REPLACE:
+ {
#ifdef Q_OS_WIN32
- // hack for people renaming the .exe because ... reasons :)
- if(op.destination == "MultiMC.exe")
- {
- op.destination = QFileInfo(QApplication::applicationFilePath()).fileName();
- }
+ // hack for people renaming the .exe because ... reasons :)
+ if(op.destination == "MultiMC.exe")
+ {
+ op.destination = QFileInfo(QApplication::applicationFilePath()).fileName();
+ }
#endif
- QFileInfo destination (FS::PathCombine(m_root, op.destination));
+ QFileInfo destination (FS::PathCombine(m_root, op.destination));
#ifdef Q_OS_WIN32
- if(QSysInfo::windowsVersion() < QSysInfo::WV_VISTA)
- {
- if(destination.fileName() == "MultiMC.exe")
- {
- QDir rootDir(m_root);
- exeOrigin = rootDir.relativeFilePath(op.source);
- exePath = rootDir.relativeFilePath(op.destination);
- exeBackup = rootDir.relativeFilePath(FS::PathCombine(backupPath, destination.fileName()));
- useXPHack = true;
- continue;
- }
- }
+ if(QSysInfo::windowsVersion() < QSysInfo::WV_VISTA)
+ {
+ if(destination.fileName() == "MultiMC.exe")
+ {
+ QDir rootDir(m_root);
+ exeOrigin = rootDir.relativeFilePath(op.source);
+ exePath = rootDir.relativeFilePath(op.destination);
+ exeBackup = rootDir.relativeFilePath(FS::PathCombine(backupPath, destination.fileName()));
+ useXPHack = true;
+ continue;
+ }
+ }
#endif
- if(destination.exists())
- {
- QString backupName = op.destination;
- backupName.replace('/', '_');
- QString backupFilePath = FS::PathCombine(backupPath, backupName);
- if(!QFile::rename(destination.absoluteFilePath(), backupFilePath))
- {
- qWarning() << "Couldn't move:" << destination.absoluteFilePath() << "to" << backupFilePath;
- m_failedOperationType = Replace;
- m_failedFile = op.destination;
- fail();
- return;
- }
- BackupEntry be;
- be.original = destination.absoluteFilePath();
- be.backup = backupFilePath;
- be.update = op.source;
- m_replace_backups.append(be);
- }
- // make sure the folder we are putting this into exists
- if(!FS::ensureFilePathExists(destination.absoluteFilePath()))
- {
- qWarning() << "REPLACE: Couldn't create folder:" << destination.absoluteFilePath();
- m_failedOperationType = Replace;
- m_failedFile = op.destination;
- fail();
- return;
- }
- // now move the new file in
- if(!QFile::rename(op.source, destination.absoluteFilePath()))
- {
- qWarning() << "REPLACE: Couldn't move:" << op.source << "to" << destination.absoluteFilePath();
- m_failedOperationType = Replace;
- m_failedFile = op.destination;
- fail();
- return;
- }
- QFile::setPermissions(destination.absoluteFilePath(), unixModeToPermissions(op.destinationMode));
- }
- break;
- // delete = move original to backup
- case GoUpdate::Operation::OP_DELETE:
- {
- QString destFilePath = FS::PathCombine(m_root, op.destination);
- if(QFile::exists(destFilePath))
- {
- QString backupName = op.destination;
- backupName.replace('/', '_');
- QString trashFilePath = FS::PathCombine(backupPath, backupName);
+ if(destination.exists())
+ {
+ QString backupName = op.destination;
+ backupName.replace('/', '_');
+ QString backupFilePath = FS::PathCombine(backupPath, backupName);
+ if(!QFile::rename(destination.absoluteFilePath(), backupFilePath))
+ {
+ qWarning() << "Couldn't move:" << destination.absoluteFilePath() << "to" << backupFilePath;
+ m_failedOperationType = Replace;
+ m_failedFile = op.destination;
+ fail();
+ return;
+ }
+ BackupEntry be;
+ be.original = destination.absoluteFilePath();
+ be.backup = backupFilePath;
+ be.update = op.source;
+ m_replace_backups.append(be);
+ }
+ // make sure the folder we are putting this into exists
+ if(!FS::ensureFilePathExists(destination.absoluteFilePath()))
+ {
+ qWarning() << "REPLACE: Couldn't create folder:" << destination.absoluteFilePath();
+ m_failedOperationType = Replace;
+ m_failedFile = op.destination;
+ fail();
+ return;
+ }
+ // now move the new file in
+ if(!QFile::rename(op.source, destination.absoluteFilePath()))
+ {
+ qWarning() << "REPLACE: Couldn't move:" << op.source << "to" << destination.absoluteFilePath();
+ m_failedOperationType = Replace;
+ m_failedFile = op.destination;
+ fail();
+ return;
+ }
+ QFile::setPermissions(destination.absoluteFilePath(), unixModeToPermissions(op.destinationMode));
+ }
+ break;
+ // delete = move original to backup
+ case GoUpdate::Operation::OP_DELETE:
+ {
+ QString destFilePath = FS::PathCombine(m_root, op.destination);
+ if(QFile::exists(destFilePath))
+ {
+ QString backupName = op.destination;
+ backupName.replace('/', '_');
+ QString trashFilePath = FS::PathCombine(backupPath, backupName);
- if(!QFile::rename(destFilePath, trashFilePath))
- {
- qWarning() << "DELETE: Couldn't move:" << op.destination << "to" << trashFilePath;
- m_failedFile = op.destination;
- m_failedOperationType = Delete;
- fail();
- return;
- }
- BackupEntry be;
- be.original = destFilePath;
- be.backup = trashFilePath;
- m_delete_backups.append(be);
- }
- }
- break;
- }
- }
+ if(!QFile::rename(destFilePath, trashFilePath))
+ {
+ qWarning() << "DELETE: Couldn't move:" << op.destination << "to" << trashFilePath;
+ m_failedFile = op.destination;
+ m_failedOperationType = Delete;
+ fail();
+ return;
+ }
+ BackupEntry be;
+ be.original = destFilePath;
+ be.backup = trashFilePath;
+ m_delete_backups.append(be);
+ }
+ }
+ break;
+ }
+ }
- // try to start the new binary
- args = qApp->arguments();
- args.removeFirst();
+ // try to start the new binary
+ args = qApp->arguments();
+ args.removeFirst();
- // on old Windows, do insane things... no error checking here, this is just to have something.
- if(useXPHack)
- {
- QString script;
- auto nativePath = QDir::toNativeSeparators(exePath);
- auto nativeOriginPath = QDir::toNativeSeparators(exeOrigin);
- auto nativeBackupPath = QDir::toNativeSeparators(exeBackup);
+ // on old Windows, do insane things... no error checking here, this is just to have something.
+ if(useXPHack)
+ {
+ QString script;
+ auto nativePath = QDir::toNativeSeparators(exePath);
+ auto nativeOriginPath = QDir::toNativeSeparators(exeOrigin);
+ auto nativeBackupPath = QDir::toNativeSeparators(exeBackup);
- // so we write this vbscript thing...
- QTextStream out(&script);
- out << "WScript.Sleep 1000\n";
- out << "Set fso=CreateObject(\"Scripting.FileSystemObject\")\n";
- out << "Set shell=CreateObject(\"WScript.Shell\")\n";
- out << "fso.MoveFile \"" << nativePath << "\", \"" << nativeBackupPath << "\"\n";
- out << "fso.MoveFile \"" << nativeOriginPath << "\", \"" << nativePath << "\"\n";
- out << "shell.Run \"" << nativePath << "\"\n";
+ // so we write this vbscript thing...
+ QTextStream out(&script);
+ out << "WScript.Sleep 1000\n";
+ out << "Set fso=CreateObject(\"Scripting.FileSystemObject\")\n";
+ out << "Set shell=CreateObject(\"WScript.Shell\")\n";
+ out << "fso.MoveFile \"" << nativePath << "\", \"" << nativeBackupPath << "\"\n";
+ out << "fso.MoveFile \"" << nativeOriginPath << "\", \"" << nativePath << "\"\n";
+ out << "shell.Run \"" << nativePath << "\"\n";
- QString scriptPath = FS::PathCombine(m_root, "update", "update.vbs");
+ QString scriptPath = FS::PathCombine(m_root, "update", "update.vbs");
- // we save it
- QFile scriptFile(scriptPath);
- scriptFile.open(QIODevice::WriteOnly);
- scriptFile.write(script.toLocal8Bit().replace("\n", "\r\n"));
- scriptFile.close();
+ // we save it
+ QFile scriptFile(scriptPath);
+ scriptFile.open(QIODevice::WriteOnly);
+ scriptFile.write(script.toLocal8Bit().replace("\n", "\r\n"));
+ scriptFile.close();
- // we run it
- started = QProcess::startDetached("wscript", {scriptPath}, m_root);
+ // we run it
+ started = QProcess::startDetached("wscript", {scriptPath}, m_root);
- // and we quit. conscious thought.
- qApp->quit();
- return;
- }
- bool doLiveCheck = true;
- bool startFailed = false;
+ // and we quit. conscious thought.
+ qApp->quit();
+ return;
+ }
+ bool doLiveCheck = true;
+ bool startFailed = false;
- // remove live check file, if any
- if(QFile::exists(liveCheckFile))
- {
- if(!QFile::remove(liveCheckFile))
- {
- qWarning() << "Couldn't remove the" << liveCheckFile << "file! We will proceed without :(";
- doLiveCheck = false;
- }
- }
+ // remove live check file, if any
+ if(QFile::exists(liveCheckFile))
+ {
+ if(!QFile::remove(liveCheckFile))
+ {
+ qWarning() << "Couldn't remove the" << liveCheckFile << "file! We will proceed without :(";
+ doLiveCheck = false;
+ }
+ }
- if(doLiveCheck)
- {
- if(!args.contains("--alive"))
- {
- args.append("--alive");
- }
- }
+ if(doLiveCheck)
+ {
+ if(!args.contains("--alive"))
+ {
+ args.append("--alive");
+ }
+ }
- // FIXME: reparse args and construct a safe variant from scratch. This is a workaround for GH-1874:
- QStringList realargs;
- int skip = 0;
- for(auto & arg: args)
- {
- if(skip)
- {
- skip--;
- continue;
- }
- if(arg == "-l")
- {
- skip = 1;
- continue;
- }
- realargs.append(arg);
- }
+ // FIXME: reparse args and construct a safe variant from scratch. This is a workaround for GH-1874:
+ QStringList realargs;
+ int skip = 0;
+ for(auto & arg: args)
+ {
+ if(skip)
+ {
+ skip--;
+ continue;
+ }
+ if(arg == "-l")
+ {
+ skip = 1;
+ continue;
+ }
+ realargs.append(arg);
+ }
- // start the updated application
- started = QProcess::startDetached(finishCmd, realargs, QDir::currentPath(), &pid);
- // much dumber check - just find out if the call
- if(!started || pid == -1)
- {
- qWarning() << "Couldn't start new process properly!";
- startFailed = true;
- }
- if(!startFailed && doLiveCheck)
- {
- int attempts = 0;
- while(attempts < 10)
- {
- attempts++;
- QString key;
- std::this_thread::sleep_for(std::chrono::milliseconds(250));
- if(!QFile::exists(liveCheckFile))
- {
- qWarning() << "Couldn't find the" << liveCheckFile << "file!";
- startFailed = true;
- continue;
- }
- try
- {
- key = QString::fromUtf8(FS::read(liveCheckFile));
- auto id = ApplicationId::fromRawString(key);
- LocalPeer peer(nullptr, id);
- if(peer.isClient())
- {
- startFailed = false;
- qDebug() << "Found process started with key " << key;
- break;
- }
- else
- {
- startFailed = true;
- qDebug() << "Process started with key " << key << "apparently died or is not reponding...";
- break;
- }
- }
- catch(Exception e)
- {
- qWarning() << "Couldn't read the" << liveCheckFile << "file!";
- startFailed = true;
- continue;
- }
- }
- }
- if(startFailed)
- {
- m_failedOperationType = Start;
- fail();
- return;
- }
- else
- {
- origin.rmdir(m_updateFilesDir);
- qApp->quit();
- return;
- }
+ // start the updated application
+ started = QProcess::startDetached(finishCmd, realargs, QDir::currentPath(), &pid);
+ // much dumber check - just find out if the call
+ if(!started || pid == -1)
+ {
+ qWarning() << "Couldn't start new process properly!";
+ startFailed = true;
+ }
+ if(!startFailed && doLiveCheck)
+ {
+ int attempts = 0;
+ while(attempts < 10)
+ {
+ attempts++;
+ QString key;
+ std::this_thread::sleep_for(std::chrono::milliseconds(250));
+ if(!QFile::exists(liveCheckFile))
+ {
+ qWarning() << "Couldn't find the" << liveCheckFile << "file!";
+ startFailed = true;
+ continue;
+ }
+ try
+ {
+ key = QString::fromUtf8(FS::read(liveCheckFile));
+ auto id = ApplicationId::fromRawString(key);
+ LocalPeer peer(nullptr, id);
+ if(peer.isClient())
+ {
+ startFailed = false;
+ qDebug() << "Found process started with key " << key;
+ break;
+ }
+ else
+ {
+ startFailed = true;
+ qDebug() << "Process started with key " << key << "apparently died or is not reponding...";
+ break;
+ }
+ }
+ catch (const Exception &e)
+ {
+ qWarning() << "Couldn't read the" << liveCheckFile << "file!";
+ startFailed = true;
+ continue;
+ }
+ }
+ }
+ if(startFailed)
+ {
+ m_failedOperationType = Start;
+ fail();
+ return;
+ }
+ else
+ {
+ origin.rmdir(m_updateFilesDir);
+ qApp->quit();
+ return;
+ }
}
void UpdateController::fail()
{
- qWarning() << "Update failed!";
+ qWarning() << "Update failed!";
- QString msg;
- bool doRollback = false;
- QString failTitle = QObject::tr("Update failed!");
- QString rollFailTitle = QObject::tr("Rollback failed!");
- switch (m_failedOperationType)
- {
- case Replace:
- {
- msg = QObject::tr("Couldn't replace file %1. Changes will be reverted.\n"
- "See the MultiMC log file for details.").arg(m_failedFile);
- doRollback = true;
- QMessageBox::critical(m_parent, failTitle, msg);
- break;
- }
- case Delete:
- {
- msg = QObject::tr("Couldn't remove file %1. Changes will be reverted.\n"
- "See the MultiMC log file for details.").arg(m_failedFile);
- doRollback = true;
- QMessageBox::critical(m_parent, failTitle, msg);
- break;
- }
- case Start:
- {
- msg = QObject::tr("The new version didn't start or is too old and doesn't respond to startup checks.\n"
- "\n"
- "Roll back to previous version?");
- auto result = QMessageBox::critical(
- m_parent,
- failTitle,
- msg,
- QMessageBox::Yes | QMessageBox::No,
- QMessageBox::Yes
- );
- doRollback = (result == QMessageBox::Yes);
- break;
- }
- case Nothing:
- default:
- return;
- }
- if(doRollback)
- {
- auto rollbackOK = rollback();
- if(!rollbackOK)
- {
- msg = QObject::tr("The rollback failed too.\n"
- "You will have to repair MultiMC manually.\n"
- "Please let us know why and how this happened.").arg(m_failedFile);
- QMessageBox::critical(m_parent, rollFailTitle, msg);
- qApp->quit();
- }
- }
- else
- {
- qApp->quit();
- }
+ QString msg;
+ bool doRollback = false;
+ QString failTitle = QObject::tr("Update failed!");
+ QString rollFailTitle = QObject::tr("Rollback failed!");
+ switch (m_failedOperationType)
+ {
+ case Replace:
+ {
+ msg = QObject::tr("Couldn't replace file %1. Changes will be reverted.\n"
+ "See the MultiMC log file for details.").arg(m_failedFile);
+ doRollback = true;
+ QMessageBox::critical(m_parent, failTitle, msg);
+ break;
+ }
+ case Delete:
+ {
+ msg = QObject::tr("Couldn't remove file %1. Changes will be reverted.\n"
+ "See the MultiMC log file for details.").arg(m_failedFile);
+ doRollback = true;
+ QMessageBox::critical(m_parent, failTitle, msg);
+ break;
+ }
+ case Start:
+ {
+ msg = QObject::tr("The new version didn't start or is too old and doesn't respond to startup checks.\n"
+ "\n"
+ "Roll back to previous version?");
+ auto result = QMessageBox::critical(
+ m_parent,
+ failTitle,
+ msg,
+ QMessageBox::Yes | QMessageBox::No,
+ QMessageBox::Yes
+ );
+ doRollback = (result == QMessageBox::Yes);
+ break;
+ }
+ case Nothing:
+ default:
+ return;
+ }
+ if(doRollback)
+ {
+ auto rollbackOK = rollback();
+ if(!rollbackOK)
+ {
+ msg = QObject::tr("The rollback failed too.\n"
+ "You will have to repair MultiMC manually.\n"
+ "Please let us know why and how this happened.").arg(m_failedFile);
+ QMessageBox::critical(m_parent, rollFailTitle, msg);
+ qApp->quit();
+ }
+ }
+ else
+ {
+ qApp->quit();
+ }
}
bool UpdateController::rollback()
{
- bool revertOK = true;
- // if the above failed, roll back changes
- for(auto backup:m_replace_backups)
- {
- qWarning() << "restoring" << backup.original << "from" << backup.backup;
- if(!QFile::rename(backup.original, backup.update))
- {
- revertOK = false;
- qWarning() << "moving new" << backup.original << "back to" << backup.update << "failed!";
- continue;
- }
+ bool revertOK = true;
+ // if the above failed, roll back changes
+ for(auto backup:m_replace_backups)
+ {
+ qWarning() << "restoring" << backup.original << "from" << backup.backup;
+ if(!QFile::rename(backup.original, backup.update))
+ {
+ revertOK = false;
+ qWarning() << "moving new" << backup.original << "back to" << backup.update << "failed!";
+ continue;
+ }
- if(!QFile::rename(backup.backup, backup.original))
- {
- revertOK = false;
- qWarning() << "restoring" << backup.original << "failed!";
- }
- }
- for(auto backup:m_delete_backups)
- {
- qWarning() << "restoring" << backup.original << "from" << backup.backup;
- if(!QFile::rename(backup.backup, backup.original))
- {
- revertOK = false;
- qWarning() << "restoring" << backup.original << "failed!";
- }
- }
- return revertOK;
+ if(!QFile::rename(backup.backup, backup.original))
+ {
+ revertOK = false;
+ qWarning() << "restoring" << backup.original << "failed!";
+ }
+ }
+ for(auto backup:m_delete_backups)
+ {
+ qWarning() << "restoring" << backup.original << "from" << backup.backup;
+ if(!QFile::rename(backup.backup, backup.original))
+ {
+ revertOK = false;
+ qWarning() << "restoring" << backup.original << "failed!";
+ }
+ }
+ return revertOK;
}
diff --git a/application/UpdateController.h b/application/UpdateController.h
index 2b258701..715554e5 100644
--- a/application/UpdateController.h
+++ b/application/UpdateController.h
@@ -9,36 +9,36 @@ class QWidget;
class UpdateController
{
public:
- UpdateController(QWidget * parent, const QString &root, const QString updateFilesDir, GoUpdate::OperationList operations);
- void installUpdates();
+ UpdateController(QWidget * parent, const QString &root, const QString updateFilesDir, GoUpdate::OperationList operations);
+ void installUpdates();
private:
- void fail();
- bool rollback();
+ void fail();
+ bool rollback();
private:
- QString m_root;
- QString m_updateFilesDir;
- GoUpdate::OperationList m_operations;
- QWidget * m_parent;
+ QString m_root;
+ QString m_updateFilesDir;
+ GoUpdate::OperationList m_operations;
+ QWidget * m_parent;
- struct BackupEntry
- {
- // path where we got the new file from
- QString update;
- // path of what is being actually updated
- QString original;
- // path where the backup of the updated file was placed
- QString backup;
- };
- QList <BackupEntry> m_replace_backups;
- QList <BackupEntry> m_delete_backups;
- enum Failure
- {
- Replace,
- Delete,
- Start,
- Nothing
- } m_failedOperationType = Nothing;
- QString m_failedFile;
+ struct BackupEntry
+ {
+ // path where we got the new file from
+ QString update;
+ // path of what is being actually updated
+ QString original;
+ // path where the backup of the updated file was placed
+ QString backup;
+ };
+ QList <BackupEntry> m_replace_backups;
+ QList <BackupEntry> m_delete_backups;
+ enum Failure
+ {
+ Replace,
+ Delete,
+ Start,
+ Nothing
+ } m_failedOperationType = Nothing;
+ QString m_failedFile;
};
diff --git a/application/VersionProxyModel.cpp b/application/VersionProxyModel.cpp
index d59fceee..5587136f 100644
--- a/application/VersionProxyModel.cpp
+++ b/application/VersionProxyModel.cpp
@@ -7,430 +7,441 @@
class VersionFilterModel : public QSortFilterProxyModel
{
- Q_OBJECT
+ Q_OBJECT
public:
- VersionFilterModel(VersionProxyModel *parent) : QSortFilterProxyModel(parent)
- {
- m_parent = parent;
- setSortRole(BaseVersionList::SortRole);
- sort(0, Qt::DescendingOrder);
- }
-
- bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
- {
- const auto &filters = m_parent->filters();
- for (auto it = filters.begin(); it != filters.end(); ++it)
- {
- auto idx = sourceModel()->index(source_row, 0, source_parent);
- auto data = sourceModel()->data(idx, it.key());
- auto match = data.toString();
- if(!it.value()->accepts(match))
- {
- return false;
- }
- }
- return true;
- }
-
- void filterChanged()
- {
- invalidateFilter();
- }
+ VersionFilterModel(VersionProxyModel *parent) : QSortFilterProxyModel(parent)
+ {
+ m_parent = parent;
+ setSortRole(BaseVersionList::SortRole);
+ sort(0, Qt::DescendingOrder);
+ }
+
+ bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
+ {
+ const auto &filters = m_parent->filters();
+ for (auto it = filters.begin(); it != filters.end(); ++it)
+ {
+ auto idx = sourceModel()->index(source_row, 0, source_parent);
+ auto data = sourceModel()->data(idx, it.key());
+ auto match = data.toString();
+ if(!it.value()->accepts(match))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void filterChanged()
+ {
+ invalidateFilter();
+ }
private:
- VersionProxyModel *m_parent;
+ VersionProxyModel *m_parent;
};
VersionProxyModel::VersionProxyModel(QObject *parent) : QAbstractProxyModel(parent)
{
- filterModel = new VersionFilterModel(this);
- connect(filterModel, &QAbstractItemModel::dataChanged, this, &VersionProxyModel::sourceDataChanged);
- connect(filterModel, &QAbstractItemModel::rowsAboutToBeInserted, this, &VersionProxyModel::sourceRowsAboutToBeInserted);
- connect(filterModel, &QAbstractItemModel::rowsInserted, this, &VersionProxyModel::sourceRowsInserted);
- connect(filterModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &VersionProxyModel::sourceRowsAboutToBeRemoved);
- connect(filterModel, &QAbstractItemModel::rowsRemoved, this, &VersionProxyModel::sourceRowsRemoved);
- // FIXME: implement when needed
- /*
- connect(replacing, &QAbstractItemModel::rowsAboutToBeMoved, this, &VersionProxyModel::sourceRowsAboutToBeMoved);
- connect(replacing, &QAbstractItemModel::rowsMoved, this, &VersionProxyModel::sourceRowsMoved);
- connect(replacing, &QAbstractItemModel::layoutAboutToBeChanged, this, &VersionProxyModel::sourceLayoutAboutToBeChanged);
- connect(replacing, &QAbstractItemModel::layoutChanged, this, &VersionProxyModel::sourceLayoutChanged);
- */
- connect(filterModel, &QAbstractItemModel::modelAboutToBeReset, this, &VersionProxyModel::sourceAboutToBeReset);
- connect(filterModel, &QAbstractItemModel::modelReset, this, &VersionProxyModel::sourceReset);
-
- QAbstractProxyModel::setSourceModel(filterModel);
+ filterModel = new VersionFilterModel(this);
+ connect(filterModel, &QAbstractItemModel::dataChanged, this, &VersionProxyModel::sourceDataChanged);
+ connect(filterModel, &QAbstractItemModel::rowsAboutToBeInserted, this, &VersionProxyModel::sourceRowsAboutToBeInserted);
+ connect(filterModel, &QAbstractItemModel::rowsInserted, this, &VersionProxyModel::sourceRowsInserted);
+ connect(filterModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &VersionProxyModel::sourceRowsAboutToBeRemoved);
+ connect(filterModel, &QAbstractItemModel::rowsRemoved, this, &VersionProxyModel::sourceRowsRemoved);
+ // FIXME: implement when needed
+ /*
+ connect(replacing, &QAbstractItemModel::rowsAboutToBeMoved, this, &VersionProxyModel::sourceRowsAboutToBeMoved);
+ connect(replacing, &QAbstractItemModel::rowsMoved, this, &VersionProxyModel::sourceRowsMoved);
+ connect(replacing, &QAbstractItemModel::layoutAboutToBeChanged, this, &VersionProxyModel::sourceLayoutAboutToBeChanged);
+ connect(replacing, &QAbstractItemModel::layoutChanged, this, &VersionProxyModel::sourceLayoutChanged);
+ */
+ connect(filterModel, &QAbstractItemModel::modelAboutToBeReset, this, &VersionProxyModel::sourceAboutToBeReset);
+ connect(filterModel, &QAbstractItemModel::modelReset, this, &VersionProxyModel::sourceReset);
+
+ QAbstractProxyModel::setSourceModel(filterModel);
}
QVariant VersionProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
{
- if(section < 0 || section >= m_columns.size())
- return QVariant();
- if(orientation != Qt::Horizontal)
- return QVariant();
- auto column = m_columns[section];
- if(role == Qt::DisplayRole)
- {
- switch(column)
- {
- case Name:
- return tr("Version");
- case ParentVersion:
- return tr("Minecraft"); //FIXME: this should come from metadata
- case Branch:
- return tr("Branch");
- case Type:
- return tr("Type");
- case Architecture:
- return tr("Architecture");
- case Path:
- return tr("Path");
- case Time:
- return tr("Released");
- }
- }
- else if(role == Qt::ToolTipRole)
- {
- switch(column)
- {
- case Name:
- return tr("The name of the version.");
- case ParentVersion:
- return tr("Minecraft version"); //FIXME: this should come from metadata
- case Branch:
- return tr("The version's branch");
- case Type:
- return tr("The version's type");
- case Architecture:
- return tr("CPU Architecture");
- case Path:
- return tr("Filesystem path to this version");
- case Time:
- return tr("Release date of this version");
- }
- }
- return QVariant();
+ if(section < 0 || section >= m_columns.size())
+ return QVariant();
+ if(orientation != Qt::Horizontal)
+ return QVariant();
+ auto column = m_columns[section];
+ if(role == Qt::DisplayRole)
+ {
+ switch(column)
+ {
+ case Name:
+ return tr("Version");
+ case ParentVersion:
+ return tr("Minecraft"); //FIXME: this should come from metadata
+ case Branch:
+ return tr("Branch");
+ case Type:
+ return tr("Type");
+ case Architecture:
+ return tr("Architecture");
+ case Path:
+ return tr("Path");
+ case Time:
+ return tr("Released");
+ }
+ }
+ else if(role == Qt::ToolTipRole)
+ {
+ switch(column)
+ {
+ case Name:
+ return tr("The name of the version.");
+ case ParentVersion:
+ return tr("Minecraft version"); //FIXME: this should come from metadata
+ case Branch:
+ return tr("The version's branch");
+ case Type:
+ return tr("The version's type");
+ case Architecture:
+ return tr("CPU Architecture");
+ case Path:
+ return tr("Filesystem path to this version");
+ case Time:
+ return tr("Release date of this version");
+ }
+ }
+ return QVariant();
}
QVariant VersionProxyModel::data(const QModelIndex &index, int role) const
{
- if(!index.isValid())
- {
- return QVariant();
- }
- auto column = m_columns[index.column()];
- auto parentIndex = mapToSource(index);
- switch(role)
- {
- case Qt::DisplayRole:
- {
- switch(column)
- {
- case Name:
- return sourceModel()->data(parentIndex, BaseVersionList::VersionRole);
- case ParentVersion:
- return sourceModel()->data(parentIndex, BaseVersionList::ParentVersionRole);
- case Branch:
- return sourceModel()->data(parentIndex, BaseVersionList::BranchRole);
- case Type:
- return sourceModel()->data(parentIndex, BaseVersionList::TypeRole);
- case Architecture:
- return sourceModel()->data(parentIndex, BaseVersionList::ArchitectureRole);
- case Path:
- return sourceModel()->data(parentIndex, BaseVersionList::PathRole);
- case Time:
- return sourceModel()->data(parentIndex, Meta::VersionList::TimeRole).toDate();
- default:
- return QVariant();
- }
- }
- case Qt::ToolTipRole:
- {
- switch(column)
- {
- case Name:
- {
- if(hasRecommended)
- {
- auto value = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole);
- if(value.toBool())
- {
- return tr("Recommended");
- }
- else if(hasLatest)
- {
- auto value = sourceModel()->data(parentIndex, BaseVersionList::LatestRole);
- if(value.toBool())
- {
- return tr("Latest");
- }
- }
- else if(index.row() == 0)
- {
- return tr("Latest");
- }
- }
- }
- default:
- {
- return sourceModel()->data(parentIndex, BaseVersionList::VersionIdRole);
- }
- }
- }
- case Qt::DecorationRole:
- {
- switch(column)
- {
- case Name:
- {
- if(hasRecommended)
- {
- auto value = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole);
- if(value.toBool())
- {
- return MMC->getThemedIcon("star");
- }
- else if(hasLatest)
- {
- auto value = sourceModel()->data(parentIndex, BaseVersionList::LatestRole);
- if(value.toBool())
- {
- return MMC->getThemedIcon("bug");
- }
- }
- else if(index.row() == 0)
- {
- return MMC->getThemedIcon("bug");
- }
- auto pixmap = QPixmapCache::find("placeholder");
- if(!pixmap)
- {
- QPixmap px(16,16);
- px.fill(Qt::transparent);
- QPixmapCache::insert("placeholder", px);
- return px;
- }
- return *pixmap;
- }
- }
- default:
- {
- return QVariant();
- }
- }
- }
- default:
- {
- if(roles.contains((BaseVersionList::ModelRoles)role))
- {
- return sourceModel()->data(parentIndex, role);
- }
- return QVariant();
- }
- }
-};
+ if(!index.isValid())
+ {
+ return QVariant();
+ }
+ auto column = m_columns[index.column()];
+ auto parentIndex = mapToSource(index);
+ switch(role)
+ {
+ case Qt::DisplayRole:
+ {
+ switch(column)
+ {
+ case Name:
+ {
+ QString version = sourceModel()->data(parentIndex, BaseVersionList::VersionRole).toString();
+ if(version == m_currentVersion)
+ {
+ return tr("%1 (installed)").arg(version);
+ }
+ return version;
+ }
+ case ParentVersion:
+ return sourceModel()->data(parentIndex, BaseVersionList::ParentVersionRole);
+ case Branch:
+ return sourceModel()->data(parentIndex, BaseVersionList::BranchRole);
+ case Type:
+ return sourceModel()->data(parentIndex, BaseVersionList::TypeRole);
+ case Architecture:
+ return sourceModel()->data(parentIndex, BaseVersionList::ArchitectureRole);
+ case Path:
+ return sourceModel()->data(parentIndex, BaseVersionList::PathRole);
+ case Time:
+ return sourceModel()->data(parentIndex, Meta::VersionList::TimeRole).toDate();
+ default:
+ return QVariant();
+ }
+ }
+ case Qt::ToolTipRole:
+ {
+ switch(column)
+ {
+ case Name:
+ {
+ if(hasRecommended)
+ {
+ auto value = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole);
+ if(value.toBool())
+ {
+ return tr("Recommended");
+ }
+ else if(hasLatest)
+ {
+ auto value = sourceModel()->data(parentIndex, BaseVersionList::LatestRole);
+ if(value.toBool())
+ {
+ return tr("Latest");
+ }
+ }
+ else if(index.row() == 0)
+ {
+ return tr("Latest");
+ }
+ }
+ }
+ default:
+ {
+ return sourceModel()->data(parentIndex, BaseVersionList::VersionIdRole);
+ }
+ }
+ }
+ case Qt::DecorationRole:
+ {
+ switch(column)
+ {
+ case Name:
+ {
+ if(hasRecommended)
+ {
+ auto value = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole);
+ if(value.toBool())
+ {
+ return MMC->getThemedIcon("star");
+ }
+ else if(hasLatest)
+ {
+ auto value = sourceModel()->data(parentIndex, BaseVersionList::LatestRole);
+ if(value.toBool())
+ {
+ return MMC->getThemedIcon("bug");
+ }
+ }
+ else if(index.row() == 0)
+ {
+ return MMC->getThemedIcon("bug");
+ }
+ auto pixmap = QPixmapCache::find("placeholder");
+ if(!pixmap)
+ {
+ QPixmap px(16,16);
+ px.fill(Qt::transparent);
+ QPixmapCache::insert("placeholder", px);
+ return px;
+ }
+ return *pixmap;
+ }
+ }
+ default:
+ {
+ return QVariant();
+ }
+ }
+ }
+ default:
+ {
+ if(roles.contains((BaseVersionList::ModelRoles)role))
+ {
+ return sourceModel()->data(parentIndex, role);
+ }
+ return QVariant();
+ }
+ }
+}
QModelIndex VersionProxyModel::parent(const QModelIndex &child) const
{
- return QModelIndex();
+ return QModelIndex();
}
QModelIndex VersionProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
{
- if(sourceIndex.isValid())
- {
- return index(sourceIndex.row(), 0);
- }
- return QModelIndex();
+ if(sourceIndex.isValid())
+ {
+ return index(sourceIndex.row(), 0);
+ }
+ return QModelIndex();
}
QModelIndex VersionProxyModel::mapToSource(const QModelIndex &proxyIndex) const
{
- if(proxyIndex.isValid())
- {
- return sourceModel()->index(proxyIndex.row(), 0);
- }
- return QModelIndex();
+ if(proxyIndex.isValid())
+ {
+ return sourceModel()->index(proxyIndex.row(), 0);
+ }
+ return QModelIndex();
}
QModelIndex VersionProxyModel::index(int row, int column, const QModelIndex &parent) const
{
- // no trees here... shoo
- if(parent.isValid())
- {
- return QModelIndex();
- }
- if(row < 0 || row >= sourceModel()->rowCount())
- return QModelIndex();
- if(column < 0 || column >= columnCount())
- return QModelIndex();
- return QAbstractItemModel::createIndex(row, column);
+ // no trees here... shoo
+ if(parent.isValid())
+ {
+ return QModelIndex();
+ }
+ if(row < 0 || row >= sourceModel()->rowCount())
+ return QModelIndex();
+ if(column < 0 || column >= columnCount())
+ return QModelIndex();
+ return QAbstractItemModel::createIndex(row, column);
}
int VersionProxyModel::columnCount(const QModelIndex &parent) const
{
- return m_columns.size();
+ return m_columns.size();
}
int VersionProxyModel::rowCount(const QModelIndex &parent) const
{
- if(sourceModel())
- {
- return sourceModel()->rowCount();
- }
- return 0;
+ if(sourceModel())
+ {
+ return sourceModel()->rowCount();
+ }
+ return 0;
}
void VersionProxyModel::sourceDataChanged(const QModelIndex &source_top_left,
- const QModelIndex &source_bottom_right)
+ const QModelIndex &source_bottom_right)
{
- if(source_top_left.parent() != source_bottom_right.parent())
- return;
+ if(source_top_left.parent() != source_bottom_right.parent())
+ return;
- // whole row is getting changed
- auto topLeft = createIndex(source_top_left.row(), 0);
- auto bottomRight = createIndex(source_bottom_right.row(), columnCount() - 1);
- emit dataChanged(topLeft, bottomRight);
+ // whole row is getting changed
+ auto topLeft = createIndex(source_top_left.row(), 0);
+ auto bottomRight = createIndex(source_bottom_right.row(), columnCount() - 1);
+ emit dataChanged(topLeft, bottomRight);
}
void VersionProxyModel::setSourceModel(QAbstractItemModel *replacingRaw)
{
- auto replacing = dynamic_cast<BaseVersionList *>(replacingRaw);
- beginResetModel();
-
- m_columns.clear();
- if(!replacing)
- {
- roles.clear();
- filterModel->setSourceModel(replacing);
- return;
- }
-
- roles = replacing->providesRoles();
- if(roles.contains(BaseVersionList::VersionRole))
- {
- m_columns.push_back(Name);
- }
- /*
- if(roles.contains(BaseVersionList::ParentVersionRole))
- {
- m_columns.push_back(ParentVersion);
- }
- */
- if(roles.contains(BaseVersionList::ArchitectureRole))
- {
- m_columns.push_back(Architecture);
- }
- if(roles.contains(BaseVersionList::PathRole))
- {
- m_columns.push_back(Path);
- }
- if(roles.contains(Meta::VersionList::TimeRole))
- {
- m_columns.push_back(Time);
- }
- if(roles.contains(BaseVersionList::BranchRole))
- {
- m_columns.push_back(Branch);
- }
- if(roles.contains(BaseVersionList::TypeRole))
- {
- m_columns.push_back(Type);
- }
- if(roles.contains(BaseVersionList::RecommendedRole))
- {
- hasRecommended = true;
- }
- if(roles.contains(BaseVersionList::LatestRole))
- {
- hasLatest = true;
- }
- filterModel->setSourceModel(replacing);
-
- endResetModel();
+ auto replacing = dynamic_cast<BaseVersionList *>(replacingRaw);
+ beginResetModel();
+
+ m_columns.clear();
+ if(!replacing)
+ {
+ roles.clear();
+ filterModel->setSourceModel(replacing);
+ return;
+ }
+
+ roles = replacing->providesRoles();
+ if(roles.contains(BaseVersionList::VersionRole))
+ {
+ m_columns.push_back(Name);
+ }
+ /*
+ if(roles.contains(BaseVersionList::ParentVersionRole))
+ {
+ m_columns.push_back(ParentVersion);
+ }
+ */
+ if(roles.contains(BaseVersionList::ArchitectureRole))
+ {
+ m_columns.push_back(Architecture);
+ }
+ if(roles.contains(BaseVersionList::PathRole))
+ {
+ m_columns.push_back(Path);
+ }
+ if(roles.contains(Meta::VersionList::TimeRole))
+ {
+ m_columns.push_back(Time);
+ }
+ if(roles.contains(BaseVersionList::BranchRole))
+ {
+ m_columns.push_back(Branch);
+ }
+ if(roles.contains(BaseVersionList::TypeRole))
+ {
+ m_columns.push_back(Type);
+ }
+ if(roles.contains(BaseVersionList::RecommendedRole))
+ {
+ hasRecommended = true;
+ }
+ if(roles.contains(BaseVersionList::LatestRole))
+ {
+ hasLatest = true;
+ }
+ filterModel->setSourceModel(replacing);
+
+ endResetModel();
}
QModelIndex VersionProxyModel::getRecommended() const
{
- if(!roles.contains(BaseVersionList::RecommendedRole))
- {
- return index(0, 0);
- }
- int recommended = 0;
- for (int i = 0; i < rowCount(); i++)
- {
- auto value = sourceModel()->data(mapToSource(index(i, 0)), BaseVersionList::RecommendedRole);
- if (value.toBool())
- {
- recommended = i;
- }
- }
- return index(recommended, 0);
+ if(!roles.contains(BaseVersionList::RecommendedRole))
+ {
+ return index(0, 0);
+ }
+ int recommended = 0;
+ for (int i = 0; i < rowCount(); i++)
+ {
+ auto value = sourceModel()->data(mapToSource(index(i, 0)), BaseVersionList::RecommendedRole);
+ if (value.toBool())
+ {
+ recommended = i;
+ }
+ }
+ return index(recommended, 0);
}
QModelIndex VersionProxyModel::getVersion(const QString& version) const
{
- int found = -1;
- for (int i = 0; i < rowCount(); i++)
- {
- auto value = sourceModel()->data(mapToSource(index(i, 0)), BaseVersionList::VersionRole);
- if (value.toString() == version)
- {
- found = i;
- }
- }
- if(found == -1)
- {
- return QModelIndex();
- }
- return index(found, 0);
+ int found = -1;
+ for (int i = 0; i < rowCount(); i++)
+ {
+ auto value = sourceModel()->data(mapToSource(index(i, 0)), BaseVersionList::VersionRole);
+ if (value.toString() == version)
+ {
+ found = i;
+ }
+ }
+ if(found == -1)
+ {
+ return QModelIndex();
+ }
+ return index(found, 0);
}
void VersionProxyModel::clearFilters()
{
- m_filters.clear();
- filterModel->filterChanged();
+ m_filters.clear();
+ filterModel->filterChanged();
}
void VersionProxyModel::setFilter(const BaseVersionList::ModelRoles column, Filter * f)
{
- m_filters[column].reset(f);
- filterModel->filterChanged();
+ m_filters[column].reset(f);
+ filterModel->filterChanged();
}
const VersionProxyModel::FilterMap &VersionProxyModel::filters() const
{
- return m_filters;
+ return m_filters;
}
void VersionProxyModel::sourceAboutToBeReset()
{
- beginResetModel();
+ beginResetModel();
}
void VersionProxyModel::sourceReset()
{
- endResetModel();
+ endResetModel();
}
void VersionProxyModel::sourceRowsAboutToBeInserted(const QModelIndex& parent, int first, int last)
{
- beginInsertRows(parent, first, last);
+ beginInsertRows(parent, first, last);
}
void VersionProxyModel::sourceRowsInserted(const QModelIndex& parent, int first, int last)
{
- endInsertRows();
+ endInsertRows();
}
void VersionProxyModel::sourceRowsAboutToBeRemoved(const QModelIndex& parent, int first, int last)
{
- beginRemoveRows(parent, first, last);
+ beginRemoveRows(parent, first, last);
}
void VersionProxyModel::sourceRowsRemoved(const QModelIndex& parent, int first, int last)
{
- endRemoveRows();
+ endRemoveRows();
}
+void VersionProxyModel::setCurrentVersion(const QString &version)
+{
+ m_currentVersion = version;
+}
#include "VersionProxyModel.moc"
diff --git a/application/VersionProxyModel.h b/application/VersionProxyModel.h
index 91d1ba23..8991c31b 100644
--- a/application/VersionProxyModel.h
+++ b/application/VersionProxyModel.h
@@ -8,58 +8,60 @@ class VersionFilterModel;
class VersionProxyModel: public QAbstractProxyModel
{
- Q_OBJECT
+ Q_OBJECT
public:
- enum Column
- {
- Name,
- ParentVersion,
- Branch,
- Type,
- Architecture,
- Path,
- Time
- };
- typedef QHash<BaseVersionList::ModelRoles, std::shared_ptr<Filter>> FilterMap;
+ enum Column
+ {
+ Name,
+ ParentVersion,
+ Branch,
+ Type,
+ Architecture,
+ Path,
+ Time
+ };
+ typedef QHash<BaseVersionList::ModelRoles, std::shared_ptr<Filter>> FilterMap;
public:
VersionProxyModel ( QObject* parent = 0 );
virtual ~VersionProxyModel() {};
- virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override;
- virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
- virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override;
- virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const override;
- virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
- virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
- virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
- virtual QModelIndex parent(const QModelIndex &child) const override;
- virtual void setSourceModel(QAbstractItemModel *sourceModel) override;
+ virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override;
+ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override;
+ virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const override;
+ virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
+ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
+ virtual QModelIndex parent(const QModelIndex &child) const override;
+ virtual void setSourceModel(QAbstractItemModel *sourceModel) override;
- const FilterMap &filters() const;
- void setFilter(const BaseVersionList::ModelRoles column, Filter * filter);
- void clearFilters();
- QModelIndex getRecommended() const;
- QModelIndex getVersion(const QString & version) const;
+ const FilterMap &filters() const;
+ void setFilter(const BaseVersionList::ModelRoles column, Filter * filter);
+ void clearFilters();
+ QModelIndex getRecommended() const;
+ QModelIndex getVersion(const QString & version) const;
+ void setCurrentVersion(const QString &version);
private slots:
- void sourceDataChanged(const QModelIndex &source_top_left,const QModelIndex &source_bottom_right);
+ void sourceDataChanged(const QModelIndex &source_top_left,const QModelIndex &source_bottom_right);
- void sourceAboutToBeReset();
- void sourceReset();
+ void sourceAboutToBeReset();
+ void sourceReset();
- void sourceRowsAboutToBeInserted(const QModelIndex &parent, int first, int last);
- void sourceRowsInserted(const QModelIndex &parent, int first, int last);
+ void sourceRowsAboutToBeInserted(const QModelIndex &parent, int first, int last);
+ void sourceRowsInserted(const QModelIndex &parent, int first, int last);
- void sourceRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last);
- void sourceRowsRemoved(const QModelIndex &parent, int first, int last);
+ void sourceRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last);
+ void sourceRowsRemoved(const QModelIndex &parent, int first, int last);
private:
- QList<Column> m_columns;
- FilterMap m_filters;
- BaseVersionList::RoleList roles;
- VersionFilterModel * filterModel;
- bool hasRecommended = false;
- bool hasLatest = false;
+ QList<Column> m_columns;
+ FilterMap m_filters;
+ BaseVersionList::RoleList roles;
+ VersionFilterModel * filterModel;
+ bool hasRecommended = false;
+ bool hasLatest = false;
+ QString m_currentVersion;
};
diff --git a/application/dialogs/AboutDialog.cpp b/application/dialogs/AboutDialog.cpp
index 8f2e72c2..ca1dfd94 100644
--- a/application/dialogs/AboutDialog.cpp
+++ b/application/dialogs/AboutDialog.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,113 +27,113 @@
// This is a hack, but I can't think of a better way to do this easily without screwing with QTextDocument...
static QString getCreditsHtml(QStringList patrons)
{
- QString creditsHtml = QObject::tr(
- "<!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 { white-space: pre-wrap; margin-top:2px; margin-bottom:2px; }"
- "</style>"
- "</head>"
- ""
- "<body style=' font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;'>"
- ""
- "<h3>MultiMC Developers</h3>"
- "<p>Andrew Okin &lt;<a href='mailto:forkk@forkk.net'>forkk@forkk.net</a>&gt;</p>"
- "<p>Petr Mrázek &lt;<a href='mailto:peterix@gmail.com'>peterix@gmail.com</a>&gt;</p>"
- "<p>Sky Welch &lt;<a href='mailto:multimc@bunnies.io'>multimc@bunnies.io</a>&gt;</p>"
- "<p>Jan (02JanDal) &lt;<a href='mailto:02jandal@gmail.com'>02jandal@gmail.com</a>&gt;</p>"
- "<p>RoboSky &lt;<a href='https://twitter.com/RoboSky_'>@RoboSky_</a>&gt;</p>"
- ""
- "<h3>With thanks to</h3>"
- "<p>Orochimarufan &lt;<a href='mailto:orochimarufan.x3@gmail.com'>orochimarufan.x3@gmail.com</a>&gt;</p>"
- "<p>TakSuyu &lt;<a href='mailto:taksuyu@gmail.com'>taksuyu@gmail.com</a>&gt;</p>"
- "<p>Kilobyte &lt;<a href='mailto:stiepen22@gmx.de'>stiepen22@gmx.de</a>&gt;</p>"
- "<p>Rootbear75 &lt;<a href='https://twitter.com/rootbear75'>@rootbear75</a>&gt;</p>"
- ""
- "<h3>Patrons</h3>"
- "%1"
- ""
- "</body>"
- "</html>");
- if (patrons.isEmpty())
- return creditsHtml.arg(QObject::tr("<p>Loading...</p>"));
- else
- {
- QString patronsStr;
- for (QString patron : patrons)
- {
- patronsStr.append(QString("<p>%1</p>").arg(patron));
- }
-
- return creditsHtml.arg(patronsStr);
- }
+ QString creditsHtml = QObject::tr(
+ "<!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 { white-space: pre-wrap; margin-top:2px; margin-bottom:2px; }"
+ "</style>"
+ "</head>"
+ ""
+ "<body style=' font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;'>"
+ ""
+ "<h3>MultiMC Developers</h3>"
+ "<p>Andrew Okin &lt;<a href='mailto:forkk@forkk.net'>forkk@forkk.net</a>&gt;</p>"
+ "<p>Petr Mrázek &lt;<a href='mailto:peterix@gmail.com'>peterix@gmail.com</a>&gt;</p>"
+ "<p>Sky Welch &lt;<a href='mailto:multimc@bunnies.io'>multimc@bunnies.io</a>&gt;</p>"
+ "<p>Jan (02JanDal) &lt;<a href='mailto:02jandal@gmail.com'>02jandal@gmail.com</a>&gt;</p>"
+ "<p>RoboSky &lt;<a href='https://twitter.com/RoboSky_'>@RoboSky_</a>&gt;</p>"
+ ""
+ "<h3>With thanks to</h3>"
+ "<p>Orochimarufan &lt;<a href='mailto:orochimarufan.x3@gmail.com'>orochimarufan.x3@gmail.com</a>&gt;</p>"
+ "<p>TakSuyu &lt;<a href='mailto:taksuyu@gmail.com'>taksuyu@gmail.com</a>&gt;</p>"
+ "<p>Kilobyte &lt;<a href='mailto:stiepen22@gmx.de'>stiepen22@gmx.de</a>&gt;</p>"
+ "<p>Rootbear75 &lt;<a href='https://twitter.com/rootbear75'>@rootbear75</a>&gt;</p>"
+ ""
+ "<h3>Patrons</h3>"
+ "%1"
+ ""
+ "</body>"
+ "</html>");
+ if (patrons.isEmpty())
+ return creditsHtml.arg(QObject::tr("<p>Loading...</p>"));
+ else
+ {
+ QString patronsStr;
+ for (QString patron : patrons)
+ {
+ patronsStr.append(QString("<p>%1</p>").arg(patron));
+ }
+
+ return creditsHtml.arg(patronsStr);
+ }
}
static QString getLicenseHtml()
{
- HoeDown hoedown;
- QFile dataFile(":/documents/COPYING.md");
- dataFile.open(QIODevice::ReadOnly);
- QString output = hoedown.process(dataFile.readAll());
- return output;
+ HoeDown hoedown;
+ QFile dataFile(":/documents/COPYING.md");
+ dataFile.open(QIODevice::ReadOnly);
+ QString output = hoedown.process(dataFile.readAll());
+ return output;
}
AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent), ui(new Ui::AboutDialog)
{
- ui->setupUi(this);
+ ui->setupUi(this);
- QString chtml = getCreditsHtml(QStringList());
- ui->creditsText->setHtml(chtml);
+ QString chtml = getCreditsHtml(QStringList());
+ ui->creditsText->setHtml(chtml);
- QString lhtml = getLicenseHtml();
- ui->licenseText->setHtml(lhtml);
+ QString lhtml = getLicenseHtml();
+ ui->licenseText->setHtml(lhtml);
- ui->urlLabel->setOpenExternalLinks(true);
+ ui->urlLabel->setOpenExternalLinks(true);
- ui->icon->setPixmap(MMC->getThemedIcon("logo").pixmap(64));
- ui->title->setText("MultiMC 5");
+ ui->icon->setPixmap(MMC->getThemedIcon("logo").pixmap(64));
+ ui->title->setText("MultiMC 5");
- ui->versionLabel->setText(tr("Version") +": " + BuildConfig.printableVersionString());
- ui->platformLabel->setText(tr("Platform") +": " + BuildConfig.BUILD_PLATFORM);
+ ui->versionLabel->setText(tr("Version") +": " + BuildConfig.printableVersionString());
+ ui->platformLabel->setText(tr("Platform") +": " + BuildConfig.BUILD_PLATFORM);
- if (BuildConfig.VERSION_BUILD >= 0)
- ui->buildNumLabel->setText(tr("Build Number") +": " + QString::number(BuildConfig.VERSION_BUILD));
- else
- ui->buildNumLabel->setVisible(false);
+ if (BuildConfig.VERSION_BUILD >= 0)
+ ui->buildNumLabel->setText(tr("Build Number") +": " + QString::number(BuildConfig.VERSION_BUILD));
+ else
+ ui->buildNumLabel->setVisible(false);
- if (!BuildConfig.VERSION_CHANNEL.isEmpty())
- ui->channelLabel->setText(tr("Channel") +": " + BuildConfig.VERSION_CHANNEL);
- else
- ui->channelLabel->setVisible(false);
+ if (!BuildConfig.VERSION_CHANNEL.isEmpty())
+ ui->channelLabel->setText(tr("Channel") +": " + BuildConfig.VERSION_CHANNEL);
+ else
+ ui->channelLabel->setVisible(false);
- connect(ui->closeButton, SIGNAL(clicked()), SLOT(close()));
+ connect(ui->closeButton, SIGNAL(clicked()), SLOT(close()));
- connect(ui->aboutQt, &QPushButton::clicked, &QApplication::aboutQt);
+ connect(ui->aboutQt, &QPushButton::clicked, &QApplication::aboutQt);
- loadPatronList();
+ loadPatronList();
}
AboutDialog::~AboutDialog()
{
- delete ui;
+ delete ui;
}
void AboutDialog::loadPatronList()
{
- netJob.reset(new NetJob("Patreon Patron List"));
- netJob->addNetAction(Net::Download::makeByteArray(QUrl("http://files.multimc.org/patrons.txt"), &dataSink));
- connect(netJob.get(), &NetJob::succeeded, this, &AboutDialog::patronListLoaded);
- netJob->start();
+ netJob.reset(new NetJob("Patreon Patron List"));
+ netJob->addNetAction(Net::Download::makeByteArray(QUrl("https://files.multimc.org/patrons.txt"), &dataSink));
+ connect(netJob.get(), &NetJob::succeeded, this, &AboutDialog::patronListLoaded);
+ netJob->start();
}
void AboutDialog::patronListLoaded()
{
- QString patronListStr(dataSink);
- dataSink.clear();
- QString html = getCreditsHtml(patronListStr.split("\n", QString::SkipEmptyParts));
- ui->creditsText->setHtml(html);
+ QString patronListStr(dataSink);
+ dataSink.clear();
+ QString html = getCreditsHtml(patronListStr.split("\n", QString::SkipEmptyParts));
+ ui->creditsText->setHtml(html);
}
diff --git a/application/dialogs/AboutDialog.h b/application/dialogs/AboutDialog.h
index 9768b866..21001c07 100644
--- a/application/dialogs/AboutDialog.h
+++ b/application/dialogs/AboutDialog.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,23 +25,23 @@ class AboutDialog;
class AboutDialog : public QDialog
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit AboutDialog(QWidget *parent = 0);
- ~AboutDialog();
+ explicit AboutDialog(QWidget *parent = 0);
+ ~AboutDialog();
public
slots:
- /// Starts loading a list of Patreon patrons.
- void loadPatronList();
-
- /// Slot for when the patron list loads successfully.
- void patronListLoaded();
+ /// Starts loading a list of Patreon patrons.
+ void loadPatronList();
+
+ /// Slot for when the patron list loads successfully.
+ void patronListLoaded();
private:
- Ui::AboutDialog *ui;
+ Ui::AboutDialog *ui;
- NetJobPtr netJob;
- QByteArray dataSink;
+ NetJobPtr netJob;
+ QByteArray dataSink;
};
diff --git a/application/dialogs/AboutDialog.ui b/application/dialogs/AboutDialog.ui
index 5e8e3e68..a312aa0c 100644
--- a/application/dialogs/AboutDialog.ui
+++ b/application/dialogs/AboutDialog.ui
@@ -165,7 +165,7 @@
</font>
</property>
<property name="text">
- <string>© 2012-2018 MultiMC Contributors</string>
+ <string>© 2012-2019 MultiMC Contributors</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
@@ -180,7 +180,7 @@
</font>
</property>
<property name="text">
- <string notr="true">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;http://github.com/MultiMC/MultiMC5&quot;&gt;http://github.com/MultiMC/MultiMC5&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ <string notr="true">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/MultiMC/MultiMC5&quot;&gt;https://github.com/MultiMC/MultiMC5&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
diff --git a/application/dialogs/CopyInstanceDialog.cpp b/application/dialogs/CopyInstanceDialog.cpp
index 72ef00fa..6100860c 100644
--- a/application/dialogs/CopyInstanceDialog.cpp
+++ b/application/dialogs/CopyInstanceDialog.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,87 +29,97 @@
#include "InstanceList.h"
CopyInstanceDialog::CopyInstanceDialog(InstancePtr original, QWidget *parent)
- :QDialog(parent), ui(new Ui::CopyInstanceDialog), m_original(original)
+ :QDialog(parent), ui(new Ui::CopyInstanceDialog), m_original(original)
{
- ui->setupUi(this);
- resize(minimumSizeHint());
- layout()->setSizeConstraint(QLayout::SetFixedSize);
-
- InstIconKey = original->iconKey();
- ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
- ui->instNameTextBox->setText(original->name());
- ui->instNameTextBox->setFocus();
- auto groups = MMC->instances()->getGroups().toSet();
- auto groupList = QStringList(groups.toList());
- groupList.sort(Qt::CaseInsensitive);
- groupList.removeOne("");
- groupList.push_front("");
- ui->groupBox->addItems(groupList);
- int index = groupList.indexOf(m_original->group());
- if(index == -1)
- {
- index = 0;
- }
- ui->groupBox->setCurrentIndex(index);
- ui->groupBox->lineEdit()->setPlaceholderText(tr("No group"));
- ui->copySavesCheckbox->setChecked(m_copySaves);
+ ui->setupUi(this);
+ resize(minimumSizeHint());
+ layout()->setSizeConstraint(QLayout::SetFixedSize);
+
+ InstIconKey = original->iconKey();
+ ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
+ ui->instNameTextBox->setText(original->name());
+ ui->instNameTextBox->setFocus();
+ auto groups = MMC->instances()->getGroups().toSet();
+ auto groupList = QStringList(groups.toList());
+ groupList.sort(Qt::CaseInsensitive);
+ groupList.removeOne("");
+ groupList.push_front("");
+ ui->groupBox->addItems(groupList);
+ int index = groupList.indexOf(MMC->instances()->getInstanceGroup(m_original->id()));
+ if(index == -1)
+ {
+ index = 0;
+ }
+ ui->groupBox->setCurrentIndex(index);
+ ui->groupBox->lineEdit()->setPlaceholderText(tr("No group"));
+ ui->copySavesCheckbox->setChecked(m_copySaves);
}
CopyInstanceDialog::~CopyInstanceDialog()
{
- delete ui;
+ delete ui;
}
void CopyInstanceDialog::updateDialogState()
{
- ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!instName().isEmpty());
+ auto allowOK = !instName().isEmpty();
+ auto OkButton = ui->buttonBox->button(QDialogButtonBox::Ok);
+ if(OkButton->isEnabled() != allowOK)
+ {
+ OkButton->setEnabled(allowOK);
+ }
}
QString CopyInstanceDialog::instName() const
{
- return ui->instNameTextBox->text();
+ auto result = ui->instNameTextBox->text().trimmed();
+ if(result.size())
+ {
+ return result;
+ }
+ return QString();
}
QString CopyInstanceDialog::iconKey() const
{
- return InstIconKey;
+ return InstIconKey;
}
QString CopyInstanceDialog::instGroup() const
{
- return ui->groupBox->currentText();
+ return ui->groupBox->currentText();
}
void CopyInstanceDialog::on_iconButton_clicked()
{
- IconPickerDialog dlg(this);
- dlg.execWithSelection(InstIconKey);
-
- if (dlg.result() == QDialog::Accepted)
- {
- InstIconKey = dlg.selectedIconKey;
- ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
- }
+ IconPickerDialog dlg(this);
+ dlg.execWithSelection(InstIconKey);
+
+ if (dlg.result() == QDialog::Accepted)
+ {
+ InstIconKey = dlg.selectedIconKey;
+ ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
+ }
}
void CopyInstanceDialog::on_instNameTextBox_textChanged(const QString &arg1)
{
- updateDialogState();
+ updateDialogState();
}
bool CopyInstanceDialog::shouldCopySaves() const
{
- return m_copySaves;
+ return m_copySaves;
}
void CopyInstanceDialog::on_copySavesCheckbox_stateChanged(int state)
{
- if(state == Qt::Unchecked)
- {
- m_copySaves = false;
- }
- else if(state == Qt::Checked)
- {
- m_copySaves = true;
- }
+ if(state == Qt::Unchecked)
+ {
+ m_copySaves = false;
+ }
+ else if(state == Qt::Checked)
+ {
+ m_copySaves = true;
+ }
}
diff --git a/application/dialogs/CopyInstanceDialog.h b/application/dialogs/CopyInstanceDialog.h
index 809552eb..d46e647c 100644
--- a/application/dialogs/CopyInstanceDialog.h
+++ b/application/dialogs/CopyInstanceDialog.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,28 +28,28 @@ class CopyInstanceDialog;
class CopyInstanceDialog : public QDialog
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit CopyInstanceDialog(InstancePtr original, QWidget *parent = 0);
- ~CopyInstanceDialog();
+ explicit CopyInstanceDialog(InstancePtr original, QWidget *parent = 0);
+ ~CopyInstanceDialog();
- void updateDialogState();
+ void updateDialogState();
- QString instName() const;
- QString instGroup() const;
- QString iconKey() const;
- bool shouldCopySaves() const;
+ QString instName() const;
+ QString instGroup() const;
+ QString iconKey() const;
+ bool shouldCopySaves() const;
private
slots:
- void on_iconButton_clicked();
- void on_instNameTextBox_textChanged(const QString &arg1);
- void on_copySavesCheckbox_stateChanged(int state);
+ void on_iconButton_clicked();
+ void on_instNameTextBox_textChanged(const QString &arg1);
+ void on_copySavesCheckbox_stateChanged(int state);
private:
- Ui::CopyInstanceDialog *ui;
- QString InstIconKey;
- InstancePtr m_original;
- bool m_copySaves = true;
+ Ui::CopyInstanceDialog *ui;
+ QString InstIconKey;
+ InstancePtr m_original;
+ bool m_copySaves = true;
};
diff --git a/application/dialogs/CustomMessageBox.cpp b/application/dialogs/CustomMessageBox.cpp
index a7d75263..db60b7f3 100644
--- a/application/dialogs/CustomMessageBox.cpp
+++ b/application/dialogs/CustomMessageBox.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,18 +18,18 @@
namespace CustomMessageBox
{
QMessageBox *selectable(QWidget *parent, const QString &title, const QString &text,
- QMessageBox::Icon icon, QMessageBox::StandardButtons buttons,
- QMessageBox::StandardButton defaultButton)
+ QMessageBox::Icon icon, QMessageBox::StandardButtons buttons,
+ QMessageBox::StandardButton defaultButton)
{
- QMessageBox *messageBox = new QMessageBox(parent);
- messageBox->setWindowTitle(title);
- messageBox->setText(text);
- messageBox->setStandardButtons(buttons);
- messageBox->setDefaultButton(defaultButton);
- messageBox->setTextInteractionFlags(Qt::TextSelectableByMouse);
- messageBox->setIcon(icon);
- messageBox->setTextInteractionFlags(Qt::TextBrowserInteraction);
+ QMessageBox *messageBox = new QMessageBox(parent);
+ messageBox->setWindowTitle(title);
+ messageBox->setText(text);
+ messageBox->setStandardButtons(buttons);
+ messageBox->setDefaultButton(defaultButton);
+ messageBox->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ messageBox->setIcon(icon);
+ messageBox->setTextInteractionFlags(Qt::TextBrowserInteraction);
- return messageBox;
+ return messageBox;
}
}
diff --git a/application/dialogs/CustomMessageBox.h b/application/dialogs/CustomMessageBox.h
index f9c0ad4e..92291e17 100644
--- a/application/dialogs/CustomMessageBox.h
+++ b/application/dialogs/CustomMessageBox.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@
namespace CustomMessageBox
{
QMessageBox *selectable(QWidget *parent, const QString &title, const QString &text,
- QMessageBox::Icon icon = QMessageBox::NoIcon,
- QMessageBox::StandardButtons buttons = QMessageBox::Ok,
- QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
+ QMessageBox::Icon icon = QMessageBox::NoIcon,
+ QMessageBox::StandardButtons buttons = QMessageBox::Ok,
+ QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
}
diff --git a/application/dialogs/EditAccountDialog.cpp b/application/dialogs/EditAccountDialog.cpp
index e43be1d8..9ae0c745 100644
--- a/application/dialogs/EditAccountDialog.cpp
+++ b/application/dialogs/EditAccountDialog.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,43 +19,43 @@
#include <QUrl>
EditAccountDialog::EditAccountDialog(const QString &text, QWidget *parent, int flags)
- : QDialog(parent), ui(new Ui::EditAccountDialog)
+ : QDialog(parent), ui(new Ui::EditAccountDialog)
{
- ui->setupUi(this);
+ ui->setupUi(this);
- ui->label->setText(text);
- ui->label->setVisible(!text.isEmpty());
+ ui->label->setText(text);
+ ui->label->setVisible(!text.isEmpty());
- ui->userTextBox->setEnabled(flags & UsernameField);
- ui->passTextBox->setEnabled(flags & PasswordField);
+ ui->userTextBox->setEnabled(flags & UsernameField);
+ ui->passTextBox->setEnabled(flags & PasswordField);
}
EditAccountDialog::~EditAccountDialog()
{
- delete ui;
+ delete ui;
}
void EditAccountDialog::on_label_linkActivated(const QString &link)
{
- DesktopServices::openUrl(QUrl(link));
+ DesktopServices::openUrl(QUrl(link));
}
void EditAccountDialog::setUsername(const QString & user) const
{
- ui->userTextBox->setText(user);
+ ui->userTextBox->setText(user);
}
QString EditAccountDialog::username() const
{
- return ui->userTextBox->text();
+ return ui->userTextBox->text();
}
void EditAccountDialog::setPassword(const QString & pass) const
{
- ui->passTextBox->setText(pass);
+ ui->passTextBox->setText(pass);
}
QString EditAccountDialog::password() const
{
- return ui->passTextBox->text();
+ return ui->passTextBox->text();
}
diff --git a/application/dialogs/EditAccountDialog.h b/application/dialogs/EditAccountDialog.h
index f121a111..4f80284a 100644
--- a/application/dialogs/EditAccountDialog.h
+++ b/application/dialogs/EditAccountDialog.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,33 +24,33 @@ class EditAccountDialog;
class EditAccountDialog : public QDialog
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit EditAccountDialog(const QString &text = "", QWidget *parent = 0,
- int flags = UsernameField | PasswordField);
- ~EditAccountDialog();
+ explicit EditAccountDialog(const QString &text = "", QWidget *parent = 0,
+ int flags = UsernameField | PasswordField);
+ ~EditAccountDialog();
- void setUsername(const QString & user) const;
- void setPassword(const QString & pass) const;
+ void setUsername(const QString & user) const;
+ void setPassword(const QString & pass) const;
- QString username() const;
- QString password() const;
+ QString username() const;
+ QString password() const;
- enum Flags
- {
- NoFlags = 0,
+ enum Flags
+ {
+ NoFlags = 0,
- //! Specifies that the dialog should have a username field.
- UsernameField,
+ //! Specifies that the dialog should have a username field.
+ UsernameField,
- //! Specifies that the dialog should have a password field.
- PasswordField,
- };
+ //! Specifies that the dialog should have a password field.
+ PasswordField,
+ };
private slots:
void on_label_linkActivated(const QString &link);
private:
- Ui::EditAccountDialog *ui;
+ Ui::EditAccountDialog *ui;
};
diff --git a/application/dialogs/ExportInstanceDialog.cpp b/application/dialogs/ExportInstanceDialog.cpp
index 0e19b758..49c082e9 100644
--- a/application/dialogs/ExportInstanceDialog.cpp
+++ b/application/dialogs/ExportInstanceDialog.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,456 +33,450 @@
class PackIgnoreProxy : public QSortFilterProxyModel
{
- Q_OBJECT
+ Q_OBJECT
public:
- PackIgnoreProxy(InstancePtr instance, QObject *parent) : QSortFilterProxyModel(parent)
- {
- m_instance = instance;
- }
- // NOTE: Sadly, we have to do sorting ourselves.
- bool lessThan(const QModelIndex &left, const QModelIndex &right) const
- {
- QFileSystemModel *fsm = qobject_cast<QFileSystemModel *>(sourceModel());
- if (!fsm)
- {
- return QSortFilterProxyModel::lessThan(left, right);
- }
- bool asc = sortOrder() == Qt::AscendingOrder ? true : false;
-
- QFileInfo leftFileInfo = fsm->fileInfo(left);
- QFileInfo rightFileInfo = fsm->fileInfo(right);
-
- if (!leftFileInfo.isDir() && rightFileInfo.isDir())
- {
- return !asc;
- }
- if (leftFileInfo.isDir() && !rightFileInfo.isDir())
- {
- return asc;
- }
-
- // sort and proxy model breaks the original model...
- if (sortColumn() == 0)
- {
- return Strings::naturalCompare(leftFileInfo.fileName(), rightFileInfo.fileName(),
- Qt::CaseInsensitive) < 0;
- }
- if (sortColumn() == 1)
- {
- auto leftSize = leftFileInfo.size();
- auto rightSize = rightFileInfo.size();
- if ((leftSize == rightSize) || (leftFileInfo.isDir() && rightFileInfo.isDir()))
- {
- return Strings::naturalCompare(leftFileInfo.fileName(),
- rightFileInfo.fileName(),
- Qt::CaseInsensitive) < 0
- ? asc
- : !asc;
- }
- return leftSize < rightSize;
- }
- return QSortFilterProxyModel::lessThan(left, right);
- }
-
- virtual Qt::ItemFlags flags(const QModelIndex &index) const
- {
- if (!index.isValid())
- return Qt::NoItemFlags;
-
- auto sourceIndex = mapToSource(index);
- Qt::ItemFlags flags = sourceIndex.flags();
- if (index.column() == 0)
- {
- flags |= Qt::ItemIsUserCheckable;
- if (sourceIndex.model()->hasChildren(sourceIndex))
- {
- flags |= Qt::ItemIsTristate;
- }
- }
-
- return flags;
- }
-
- virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
- {
- QModelIndex sourceIndex = mapToSource(index);
-
- if (index.column() == 0 && role == Qt::CheckStateRole)
- {
- QFileSystemModel *fsm = qobject_cast<QFileSystemModel *>(sourceModel());
- auto blockedPath = relPath(fsm->filePath(sourceIndex));
- auto cover = blocked.cover(blockedPath);
- if (!cover.isNull())
- {
- return QVariant(Qt::Unchecked);
- }
- else if (blocked.exists(blockedPath))
- {
- return QVariant(Qt::PartiallyChecked);
- }
- else
- {
- return QVariant(Qt::Checked);
- }
- }
-
- return sourceIndex.data(role);
- }
-
- virtual bool setData(const QModelIndex &index, const QVariant &value,
- int role = Qt::EditRole)
- {
- if (index.column() == 0 && role == Qt::CheckStateRole)
- {
- Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
- return setFilterState(index, state);
- }
-
- QModelIndex sourceIndex = mapToSource(index);
- return QSortFilterProxyModel::sourceModel()->setData(sourceIndex, value, role);
- }
-
- QString relPath(const QString &path) const
- {
- QString prefix = QDir().absoluteFilePath(m_instance->instanceRoot());
- prefix += '/';
- if (!path.startsWith(prefix))
- {
- return QString();
- }
- return path.mid(prefix.size());
- }
-
- bool setFilterState(QModelIndex index, Qt::CheckState state)
- {
- QFileSystemModel *fsm = qobject_cast<QFileSystemModel *>(sourceModel());
-
- if (!fsm)
- {
- return false;
- }
-
- QModelIndex sourceIndex = mapToSource(index);
- auto blockedPath = relPath(fsm->filePath(sourceIndex));
- bool changed = false;
- if (state == Qt::Unchecked)
- {
- // blocking a path
- auto &node = blocked.insert(blockedPath);
- // get rid of all blocked nodes below
- node.clear();
- changed = true;
- }
- else if (state == Qt::Checked || state == Qt::PartiallyChecked)
- {
- if (!blocked.remove(blockedPath))
- {
- auto cover = blocked.cover(blockedPath);
- qDebug() << "Blocked by cover" << cover;
- // uncover
- blocked.remove(cover);
- // block all contents, except for any cover
- QModelIndex rootIndex =
- fsm->index(FS::PathCombine(m_instance->instanceRoot(), cover));
- QModelIndex doing = rootIndex;
- int row = 0;
- QStack<QModelIndex> todo;
- while (1)
- {
- auto node = doing.child(row, 0);
- if (!node.isValid())
- {
- if (!todo.size())
- {
- break;
- }
- else
- {
- doing = todo.pop();
- row = 0;
- continue;
- }
- }
- auto relpath = relPath(fsm->filePath(node));
- if (blockedPath.startsWith(relpath)) // cover found?
- {
- // continue processing cover later
- todo.push(node);
- }
- else
- {
- // or just block this one.
- blocked.insert(relpath);
- }
- row++;
- }
- }
- changed = true;
- }
- if (changed)
- {
- // update the thing
- emit dataChanged(index, index, {Qt::CheckStateRole});
- // update everything above index
- QModelIndex up = index.parent();
- while (1)
- {
- if (!up.isValid())
- break;
- emit dataChanged(up, up, {Qt::CheckStateRole});
- up = up.parent();
- }
- // and everything below the index
- QModelIndex doing = index;
- int row = 0;
- QStack<QModelIndex> todo;
- while (1)
- {
- auto node = doing.child(row, 0);
- if (!node.isValid())
- {
- if (!todo.size())
- {
- break;
- }
- else
- {
- doing = todo.pop();
- row = 0;
- continue;
- }
- }
- emit dataChanged(node, node, {Qt::CheckStateRole});
- todo.push(node);
- row++;
- }
- // siblings and unrelated nodes are ignored
- }
- return true;
- }
-
- bool shouldExpand(QModelIndex index)
- {
- QModelIndex sourceIndex = mapToSource(index);
- QFileSystemModel *fsm = qobject_cast<QFileSystemModel *>(sourceModel());
- if (!fsm)
- {
- return false;
- }
- auto blockedPath = relPath(fsm->filePath(sourceIndex));
- auto found = blocked.find(blockedPath);
- if(found)
- {
- return !found->leaf();
- }
- return false;
- }
-
- void setBlockedPaths(QStringList paths)
- {
- beginResetModel();
- blocked.clear();
- blocked.insert(paths);
- endResetModel();
- }
-
- const SeparatorPrefixTree<'/'> & blockedPaths() const
- {
- return blocked;
- }
+ PackIgnoreProxy(InstancePtr instance, QObject *parent) : QSortFilterProxyModel(parent)
+ {
+ m_instance = instance;
+ }
+ // NOTE: Sadly, we have to do sorting ourselves.
+ bool lessThan(const QModelIndex &left, const QModelIndex &right) const
+ {
+ QFileSystemModel *fsm = qobject_cast<QFileSystemModel *>(sourceModel());
+ if (!fsm)
+ {
+ return QSortFilterProxyModel::lessThan(left, right);
+ }
+ bool asc = sortOrder() == Qt::AscendingOrder ? true : false;
+
+ QFileInfo leftFileInfo = fsm->fileInfo(left);
+ QFileInfo rightFileInfo = fsm->fileInfo(right);
+
+ if (!leftFileInfo.isDir() && rightFileInfo.isDir())
+ {
+ return !asc;
+ }
+ if (leftFileInfo.isDir() && !rightFileInfo.isDir())
+ {
+ return asc;
+ }
+
+ // sort and proxy model breaks the original model...
+ if (sortColumn() == 0)
+ {
+ return Strings::naturalCompare(leftFileInfo.fileName(), rightFileInfo.fileName(),
+ Qt::CaseInsensitive) < 0;
+ }
+ if (sortColumn() == 1)
+ {
+ auto leftSize = leftFileInfo.size();
+ auto rightSize = rightFileInfo.size();
+ if ((leftSize == rightSize) || (leftFileInfo.isDir() && rightFileInfo.isDir()))
+ {
+ return Strings::naturalCompare(leftFileInfo.fileName(),
+ rightFileInfo.fileName(),
+ Qt::CaseInsensitive) < 0
+ ? asc
+ : !asc;
+ }
+ return leftSize < rightSize;
+ }
+ return QSortFilterProxyModel::lessThan(left, right);
+ }
+
+ virtual Qt::ItemFlags flags(const QModelIndex &index) const
+ {
+ if (!index.isValid())
+ return Qt::NoItemFlags;
+
+ auto sourceIndex = mapToSource(index);
+ Qt::ItemFlags flags = sourceIndex.flags();
+ if (index.column() == 0)
+ {
+ flags |= Qt::ItemIsUserCheckable;
+ if (sourceIndex.model()->hasChildren(sourceIndex))
+ {
+ flags |= Qt::ItemIsTristate;
+ }
+ }
+
+ return flags;
+ }
+
+ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
+ {
+ QModelIndex sourceIndex = mapToSource(index);
+
+ if (index.column() == 0 && role == Qt::CheckStateRole)
+ {
+ QFileSystemModel *fsm = qobject_cast<QFileSystemModel *>(sourceModel());
+ auto blockedPath = relPath(fsm->filePath(sourceIndex));
+ auto cover = blocked.cover(blockedPath);
+ if (!cover.isNull())
+ {
+ return QVariant(Qt::Unchecked);
+ }
+ else if (blocked.exists(blockedPath))
+ {
+ return QVariant(Qt::PartiallyChecked);
+ }
+ else
+ {
+ return QVariant(Qt::Checked);
+ }
+ }
+
+ return sourceIndex.data(role);
+ }
+
+ virtual bool setData(const QModelIndex &index, const QVariant &value,
+ int role = Qt::EditRole)
+ {
+ if (index.column() == 0 && role == Qt::CheckStateRole)
+ {
+ Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
+ return setFilterState(index, state);
+ }
+
+ QModelIndex sourceIndex = mapToSource(index);
+ return QSortFilterProxyModel::sourceModel()->setData(sourceIndex, value, role);
+ }
+
+ QString relPath(const QString &path) const
+ {
+ QString prefix = QDir().absoluteFilePath(m_instance->instanceRoot());
+ prefix += '/';
+ if (!path.startsWith(prefix))
+ {
+ return QString();
+ }
+ return path.mid(prefix.size());
+ }
+
+ bool setFilterState(QModelIndex index, Qt::CheckState state)
+ {
+ QFileSystemModel *fsm = qobject_cast<QFileSystemModel *>(sourceModel());
+
+ if (!fsm)
+ {
+ return false;
+ }
+
+ QModelIndex sourceIndex = mapToSource(index);
+ auto blockedPath = relPath(fsm->filePath(sourceIndex));
+ bool changed = false;
+ if (state == Qt::Unchecked)
+ {
+ // blocking a path
+ auto &node = blocked.insert(blockedPath);
+ // get rid of all blocked nodes below
+ node.clear();
+ changed = true;
+ }
+ else if (state == Qt::Checked || state == Qt::PartiallyChecked)
+ {
+ if (!blocked.remove(blockedPath))
+ {
+ auto cover = blocked.cover(blockedPath);
+ qDebug() << "Blocked by cover" << cover;
+ // uncover
+ blocked.remove(cover);
+ // block all contents, except for any cover
+ QModelIndex rootIndex =
+ fsm->index(FS::PathCombine(m_instance->instanceRoot(), cover));
+ QModelIndex doing = rootIndex;
+ int row = 0;
+ QStack<QModelIndex> todo;
+ while (1)
+ {
+ auto node = doing.child(row, 0);
+ if (!node.isValid())
+ {
+ if (!todo.size())
+ {
+ break;
+ }
+ else
+ {
+ doing = todo.pop();
+ row = 0;
+ continue;
+ }
+ }
+ auto relpath = relPath(fsm->filePath(node));
+ if (blockedPath.startsWith(relpath)) // cover found?
+ {
+ // continue processing cover later
+ todo.push(node);
+ }
+ else
+ {
+ // or just block this one.
+ blocked.insert(relpath);
+ }
+ row++;
+ }
+ }
+ changed = true;
+ }
+ if (changed)
+ {
+ // update the thing
+ emit dataChanged(index, index, {Qt::CheckStateRole});
+ // update everything above index
+ QModelIndex up = index.parent();
+ while (1)
+ {
+ if (!up.isValid())
+ break;
+ emit dataChanged(up, up, {Qt::CheckStateRole});
+ up = up.parent();
+ }
+ // and everything below the index
+ QModelIndex doing = index;
+ int row = 0;
+ QStack<QModelIndex> todo;
+ while (1)
+ {
+ auto node = doing.child(row, 0);
+ if (!node.isValid())
+ {
+ if (!todo.size())
+ {
+ break;
+ }
+ else
+ {
+ doing = todo.pop();
+ row = 0;
+ continue;
+ }
+ }
+ emit dataChanged(node, node, {Qt::CheckStateRole});
+ todo.push(node);
+ row++;
+ }
+ // siblings and unrelated nodes are ignored
+ }
+ return true;
+ }
+
+ bool shouldExpand(QModelIndex index)
+ {
+ QModelIndex sourceIndex = mapToSource(index);
+ QFileSystemModel *fsm = qobject_cast<QFileSystemModel *>(sourceModel());
+ if (!fsm)
+ {
+ return false;
+ }
+ auto blockedPath = relPath(fsm->filePath(sourceIndex));
+ auto found = blocked.find(blockedPath);
+ if(found)
+ {
+ return !found->leaf();
+ }
+ return false;
+ }
+
+ void setBlockedPaths(QStringList paths)
+ {
+ beginResetModel();
+ blocked.clear();
+ blocked.insert(paths);
+ endResetModel();
+ }
+
+ const SeparatorPrefixTree<'/'> & blockedPaths() const
+ {
+ return blocked;
+ }
protected:
- bool filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const
- {
- Q_UNUSED(source_parent)
+ bool filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const
+ {
+ Q_UNUSED(source_parent)
- // adjust the columns you want to filter out here
- // return false for those that will be hidden
- if (source_column == 2 || source_column == 3)
- return false;
+ // adjust the columns you want to filter out here
+ // return false for those that will be hidden
+ if (source_column == 2 || source_column == 3)
+ return false;
- return true;
- }
+ return true;
+ }
private:
- InstancePtr m_instance;
- SeparatorPrefixTree<'/'> blocked;
+ InstancePtr m_instance;
+ SeparatorPrefixTree<'/'> blocked;
};
ExportInstanceDialog::ExportInstanceDialog(InstancePtr instance, QWidget *parent)
- : QDialog(parent), ui(new Ui::ExportInstanceDialog), m_instance(instance)
+ : QDialog(parent), ui(new Ui::ExportInstanceDialog), m_instance(instance)
{
- ui->setupUi(this);
- auto model = new QFileSystemModel(this);
- proxyModel = new PackIgnoreProxy(m_instance, this);
- loadPackIgnore();
- proxyModel->setSourceModel(model);
- auto root = instance->instanceRoot();
- ui->treeView->setModel(proxyModel);
- ui->treeView->setRootIndex(proxyModel->mapFromSource(model->index(root)));
- ui->treeView->sortByColumn(0, Qt::AscendingOrder);
-
- connect(proxyModel, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(rowsInserted(QModelIndex,int,int)));
-
- model->setFilter(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::AllDirs | QDir::Hidden);
- model->setRootPath(root);
- auto headerView = ui->treeView->header();
- headerView->setSectionResizeMode(QHeaderView::ResizeToContents);
- headerView->setSectionResizeMode(0, QHeaderView::Stretch);
+ ui->setupUi(this);
+ auto model = new QFileSystemModel(this);
+ proxyModel = new PackIgnoreProxy(m_instance, this);
+ loadPackIgnore();
+ proxyModel->setSourceModel(model);
+ auto root = instance->instanceRoot();
+ ui->treeView->setModel(proxyModel);
+ ui->treeView->setRootIndex(proxyModel->mapFromSource(model->index(root)));
+ ui->treeView->sortByColumn(0, Qt::AscendingOrder);
+
+ connect(proxyModel, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(rowsInserted(QModelIndex,int,int)));
+
+ model->setFilter(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::AllDirs | QDir::Hidden);
+ model->setRootPath(root);
+ auto headerView = ui->treeView->header();
+ headerView->setSectionResizeMode(QHeaderView::ResizeToContents);
+ headerView->setSectionResizeMode(0, QHeaderView::Stretch);
}
ExportInstanceDialog::~ExportInstanceDialog()
{
- delete ui;
+ delete ui;
}
/// Save icon to instance's folder is needed
void SaveIcon(InstancePtr m_instance)
{
- auto iconKey = m_instance->iconKey();
- auto iconList = MMC->icons();
- auto mmcIcon = iconList->icon(iconKey);
- if(mmcIcon)
- {
- bool saveIcon = false;
- switch(mmcIcon->type())
- {
- case IconType::FileBased:
- case IconType::Transient:
- saveIcon = true;
- default:
- break;
- }
- if(saveIcon)
- {
- auto & image = mmcIcon->m_images[mmcIcon->type()];
- auto & icon = image.icon;
- auto sizes = icon.availableSizes();
- if(sizes.size() == 0)
- {
- return;
- }
- auto areaOf = [](QSize size)
- {
- return size.width() * size.height();
- };
- QSize largest = sizes[0];
- // find variant with largest area
- for(auto size: sizes)
- {
- if(areaOf(largest) < areaOf(size))
- {
- largest = size;
- }
- }
- auto pixmap = icon.pixmap(largest);
- pixmap.save(FS::PathCombine(m_instance->instanceRoot(), iconKey + ".png"));
- }
- }
+ auto iconKey = m_instance->iconKey();
+ auto iconList = MMC->icons();
+ auto mmcIcon = iconList->icon(iconKey);
+ if(!mmcIcon || mmcIcon->isBuiltIn()) {
+ return;
+ }
+ auto path = mmcIcon->getFilePath();
+ if(!path.isNull()) {
+ QFileInfo inInfo (path);
+ FS::copy(path, FS::PathCombine(m_instance->instanceRoot(), inInfo.fileName())) ();
+ return;
+ }
+ auto & image = mmcIcon->m_images[mmcIcon->type()];
+ auto & icon = image.icon;
+ auto sizes = icon.availableSizes();
+ if(sizes.size() == 0)
+ {
+ return;
+ }
+ auto areaOf = [](QSize size)
+ {
+ return size.width() * size.height();
+ };
+ QSize largest = sizes[0];
+ // find variant with largest area
+ for(auto size: sizes)
+ {
+ if(areaOf(largest) < areaOf(size))
+ {
+ largest = size;
+ }
+ }
+ auto pixmap = icon.pixmap(largest);
+ pixmap.save(FS::PathCombine(m_instance->instanceRoot(), iconKey + ".png"));
}
bool ExportInstanceDialog::doExport()
{
- auto name = FS::RemoveInvalidFilenameChars(m_instance->name());
-
- const QString output = QFileDialog::getSaveFileName(
- this, tr("Export %1").arg(m_instance->name()),
- FS::PathCombine(QDir::homePath(), name + ".zip"), "Zip (*.zip)", nullptr, QFileDialog::DontConfirmOverwrite);
- if (output.isEmpty())
- {
- return false;
- }
- if (QFile::exists(output))
- {
- int ret =
- QMessageBox::question(this, tr("Overwrite?"),
- tr("This file already exists. Do you want to overwrite it?"),
- QMessageBox::No, QMessageBox::Yes);
- if (ret == QMessageBox::No)
- {
- return false;
- }
- }
-
- SaveIcon(m_instance);
-
- auto & blocked = proxyModel->blockedPaths();
- using std::placeholders::_1;
- if (!JlCompress::compressDir(output, m_instance->instanceRoot(), name, std::bind(&SeparatorPrefixTree<'/'>::covers, blocked, _1)))
- {
- QMessageBox::warning(this, tr("Error"), tr("Unable to export instance"));
- return false;
- }
- return true;
+ auto name = FS::RemoveInvalidFilenameChars(m_instance->name());
+
+ const QString output = QFileDialog::getSaveFileName(
+ this, tr("Export %1").arg(m_instance->name()),
+ FS::PathCombine(QDir::homePath(), name + ".zip"), "Zip (*.zip)", nullptr, QFileDialog::DontConfirmOverwrite);
+ if (output.isEmpty())
+ {
+ return false;
+ }
+ if (QFile::exists(output))
+ {
+ int ret =
+ QMessageBox::question(this, tr("Overwrite?"),
+ tr("This file already exists. Do you want to overwrite it?"),
+ QMessageBox::No, QMessageBox::Yes);
+ if (ret == QMessageBox::No)
+ {
+ return false;
+ }
+ }
+
+ SaveIcon(m_instance);
+
+ auto & blocked = proxyModel->blockedPaths();
+ using std::placeholders::_1;
+ if (!JlCompress::compressDir(output, m_instance->instanceRoot(), name, std::bind(&SeparatorPrefixTree<'/'>::covers, blocked, _1)))
+ {
+ QMessageBox::warning(this, tr("Error"), tr("Unable to export instance"));
+ return false;
+ }
+ return true;
}
void ExportInstanceDialog::done(int result)
{
- savePackIgnore();
- if (result == QDialog::Accepted)
- {
- if (doExport())
- {
- QDialog::done(QDialog::Accepted);
- return;
- }
- else
- {
- return;
- }
- }
- QDialog::done(result);
+ savePackIgnore();
+ if (result == QDialog::Accepted)
+ {
+ if (doExport())
+ {
+ QDialog::done(QDialog::Accepted);
+ return;
+ }
+ else
+ {
+ return;
+ }
+ }
+ QDialog::done(result);
}
void ExportInstanceDialog::rowsInserted(QModelIndex parent, int top, int bottom)
{
- //WARNING: possible off-by-one?
- for(int i = top; i < bottom; i++)
- {
- auto node = parent.child(i, 0);
- if(proxyModel->shouldExpand(node))
- {
- auto expNode = node.parent();
- if(!expNode.isValid())
- {
- continue;
- }
- ui->treeView->expand(node);
- }
- }
+ //WARNING: possible off-by-one?
+ for(int i = top; i < bottom; i++)
+ {
+ auto node = parent.child(i, 0);
+ if(proxyModel->shouldExpand(node))
+ {
+ auto expNode = node.parent();
+ if(!expNode.isValid())
+ {
+ continue;
+ }
+ ui->treeView->expand(node);
+ }
+ }
}
QString ExportInstanceDialog::ignoreFileName()
{
- return FS::PathCombine(m_instance->instanceRoot(), ".packignore");
+ return FS::PathCombine(m_instance->instanceRoot(), ".packignore");
}
void ExportInstanceDialog::loadPackIgnore()
{
- auto filename = ignoreFileName();
- QFile ignoreFile(filename);
- if(!ignoreFile.open(QIODevice::ReadOnly))
- {
- return;
- }
- auto data = ignoreFile.readAll();
- auto string = QString::fromUtf8(data);
- proxyModel->setBlockedPaths(string.split('\n', QString::SkipEmptyParts));
+ auto filename = ignoreFileName();
+ QFile ignoreFile(filename);
+ if(!ignoreFile.open(QIODevice::ReadOnly))
+ {
+ return;
+ }
+ auto data = ignoreFile.readAll();
+ auto string = QString::fromUtf8(data);
+ proxyModel->setBlockedPaths(string.split('\n', QString::SkipEmptyParts));
}
void ExportInstanceDialog::savePackIgnore()
{
- auto data = proxyModel->blockedPaths().toStringList().join('\n').toUtf8();
- auto filename = ignoreFileName();
- try
- {
- FS::write(filename, data);
- }
- catch (Exception & e)
- {
- qWarning() << e.cause();
- }
+ auto data = proxyModel->blockedPaths().toStringList().join('\n').toUtf8();
+ auto filename = ignoreFileName();
+ try
+ {
+ FS::write(filename, data);
+ }
+ catch (const Exception &e)
+ {
+ qWarning() << e.cause();
+ }
}
#include "ExportInstanceDialog.moc"
diff --git a/application/dialogs/ExportInstanceDialog.h b/application/dialogs/ExportInstanceDialog.h
index 7b9c6726..aec4cbfb 100644
--- a/application/dialogs/ExportInstanceDialog.h
+++ b/application/dialogs/ExportInstanceDialog.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,25 +30,25 @@ class ExportInstanceDialog;
class ExportInstanceDialog : public QDialog
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit ExportInstanceDialog(InstancePtr instance, QWidget *parent = 0);
- ~ExportInstanceDialog();
+ explicit ExportInstanceDialog(InstancePtr instance, QWidget *parent = 0);
+ ~ExportInstanceDialog();
- virtual void done(int result);
+ virtual void done(int result);
private:
- bool doExport();
- void loadPackIgnore();
- void savePackIgnore();
- QString ignoreFileName();
+ bool doExport();
+ void loadPackIgnore();
+ void savePackIgnore();
+ QString ignoreFileName();
private:
- Ui::ExportInstanceDialog *ui;
- InstancePtr m_instance;
- PackIgnoreProxy * proxyModel;
+ Ui::ExportInstanceDialog *ui;
+ InstancePtr m_instance;
+ PackIgnoreProxy * proxyModel;
private slots:
- void rowsInserted(QModelIndex parent, int top, int bottom);
+ void rowsInserted(QModelIndex parent, int top, int bottom);
};
diff --git a/application/dialogs/IconPickerDialog.cpp b/application/dialogs/IconPickerDialog.cpp
index 4ffd12bc..7f930717 100644
--- a/application/dialogs/IconPickerDialog.cpp
+++ b/application/dialogs/IconPickerDialog.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,138 +25,139 @@
#include "groupview/InstanceDelegate.h"
#include "icons/IconList.h"
+#include "icons/IconUtils.h"
#include <DesktopServices.h>
IconPickerDialog::IconPickerDialog(QWidget *parent)
- : QDialog(parent), ui(new Ui::IconPickerDialog)
+ : QDialog(parent), ui(new Ui::IconPickerDialog)
{
- ui->setupUi(this);
- setWindowModality(Qt::WindowModal);
-
- auto contentsWidget = ui->iconView;
- contentsWidget->setViewMode(QListView::IconMode);
- contentsWidget->setFlow(QListView::LeftToRight);
- contentsWidget->setIconSize(QSize(48, 48));
- contentsWidget->setMovement(QListView::Static);
- contentsWidget->setResizeMode(QListView::Adjust);
- contentsWidget->setSelectionMode(QAbstractItemView::SingleSelection);
- contentsWidget->setSpacing(5);
- contentsWidget->setWordWrap(false);
- contentsWidget->setWrapping(true);
- contentsWidget->setUniformItemSizes(true);
- contentsWidget->setTextElideMode(Qt::ElideRight);
- contentsWidget->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
- contentsWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
- contentsWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- contentsWidget->setItemDelegate(new ListViewDelegate());
-
- // contentsWidget->setAcceptDrops(true);
- contentsWidget->setDropIndicatorShown(true);
- contentsWidget->viewport()->setAcceptDrops(true);
- contentsWidget->setDragDropMode(QAbstractItemView::DropOnly);
- contentsWidget->setDefaultDropAction(Qt::CopyAction);
-
- contentsWidget->installEventFilter(this);
-
- contentsWidget->setModel(MMC->icons().get());
-
- // NOTE: ResetRole forces the button to be on the left, while the OK/Cancel ones are on the right. We win.
- auto buttonAdd = ui->buttonBox->addButton(tr("Add Icon"), QDialogButtonBox::ResetRole);
- auto buttonRemove = ui->buttonBox->addButton(tr("Remove Icon"), QDialogButtonBox::ResetRole);
-
- connect(buttonAdd, SIGNAL(clicked(bool)), SLOT(addNewIcon()));
- connect(buttonRemove, SIGNAL(clicked(bool)), SLOT(removeSelectedIcon()));
-
- connect(contentsWidget, SIGNAL(doubleClicked(QModelIndex)), SLOT(activated(QModelIndex)));
-
- connect(contentsWidget->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), SLOT(selectionChanged(QItemSelection, QItemSelection)));
-
- auto buttonFolder = ui->buttonBox->addButton(tr("Open Folder"), QDialogButtonBox::ResetRole);
- connect(buttonFolder, &QPushButton::clicked, this, &IconPickerDialog::openFolder);
+ ui->setupUi(this);
+ setWindowModality(Qt::WindowModal);
+
+ auto contentsWidget = ui->iconView;
+ contentsWidget->setViewMode(QListView::IconMode);
+ contentsWidget->setFlow(QListView::LeftToRight);
+ contentsWidget->setIconSize(QSize(48, 48));
+ contentsWidget->setMovement(QListView::Static);
+ contentsWidget->setResizeMode(QListView::Adjust);
+ contentsWidget->setSelectionMode(QAbstractItemView::SingleSelection);
+ contentsWidget->setSpacing(5);
+ contentsWidget->setWordWrap(false);
+ contentsWidget->setWrapping(true);
+ contentsWidget->setUniformItemSizes(true);
+ contentsWidget->setTextElideMode(Qt::ElideRight);
+ contentsWidget->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
+ contentsWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+ contentsWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ contentsWidget->setItemDelegate(new ListViewDelegate());
+
+ // contentsWidget->setAcceptDrops(true);
+ contentsWidget->setDropIndicatorShown(true);
+ contentsWidget->viewport()->setAcceptDrops(true);
+ contentsWidget->setDragDropMode(QAbstractItemView::DropOnly);
+ contentsWidget->setDefaultDropAction(Qt::CopyAction);
+
+ contentsWidget->installEventFilter(this);
+
+ contentsWidget->setModel(MMC->icons().get());
+
+ // NOTE: ResetRole forces the button to be on the left, while the OK/Cancel ones are on the right. We win.
+ auto buttonAdd = ui->buttonBox->addButton(tr("Add Icon"), QDialogButtonBox::ResetRole);
+ auto buttonRemove = ui->buttonBox->addButton(tr("Remove Icon"), QDialogButtonBox::ResetRole);
+
+ connect(buttonAdd, SIGNAL(clicked(bool)), SLOT(addNewIcon()));
+ connect(buttonRemove, SIGNAL(clicked(bool)), SLOT(removeSelectedIcon()));
+
+ connect(contentsWidget, SIGNAL(doubleClicked(QModelIndex)), SLOT(activated(QModelIndex)));
+
+ connect(contentsWidget->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), SLOT(selectionChanged(QItemSelection, QItemSelection)));
+
+ auto buttonFolder = ui->buttonBox->addButton(tr("Open Folder"), QDialogButtonBox::ResetRole);
+ connect(buttonFolder, &QPushButton::clicked, this, &IconPickerDialog::openFolder);
}
bool IconPickerDialog::eventFilter(QObject *obj, QEvent *evt)
{
- if (obj != ui->iconView)
- return QDialog::eventFilter(obj, evt);
- if (evt->type() != QEvent::KeyPress)
- {
- return QDialog::eventFilter(obj, evt);
- }
- QKeyEvent *keyEvent = static_cast<QKeyEvent *>(evt);
- switch (keyEvent->key())
- {
- case Qt::Key_Delete:
- removeSelectedIcon();
- return true;
- case Qt::Key_Plus:
- addNewIcon();
- return true;
- default:
- break;
- }
- return QDialog::eventFilter(obj, evt);
+ if (obj != ui->iconView)
+ return QDialog::eventFilter(obj, evt);
+ if (evt->type() != QEvent::KeyPress)
+ {
+ return QDialog::eventFilter(obj, evt);
+ }
+ QKeyEvent *keyEvent = static_cast<QKeyEvent *>(evt);
+ switch (keyEvent->key())
+ {
+ case Qt::Key_Delete:
+ removeSelectedIcon();
+ return true;
+ case Qt::Key_Plus:
+ addNewIcon();
+ return true;
+ default:
+ break;
+ }
+ return QDialog::eventFilter(obj, evt);
}
void IconPickerDialog::addNewIcon()
{
- //: The title of the select icons open file dialog
- QString selectIcons = tr("Select Icons");
- //: The type of icon files
- QStringList fileNames = QFileDialog::getOpenFileNames(this, selectIcons, QString(),
- tr("Icons") + "(*.png *.jpg *.jpeg *.ico *.svg)");
- MMC->icons()->installIcons(fileNames);
+ //: The title of the select icons open file dialog
+ QString selectIcons = tr("Select Icons");
+ //: The type of icon files
+ auto filter = IconUtils::getIconFilter();
+ QStringList fileNames = QFileDialog::getOpenFileNames(this, selectIcons, QString(), tr("Icons %1").arg(filter));
+ MMC->icons()->installIcons(fileNames);
}
void IconPickerDialog::removeSelectedIcon()
{
- MMC->icons()->deleteIcon(selectedIconKey);
+ MMC->icons()->deleteIcon(selectedIconKey);
}
void IconPickerDialog::activated(QModelIndex index)
{
- selectedIconKey = index.data(Qt::UserRole).toString();
- accept();
+ selectedIconKey = index.data(Qt::UserRole).toString();
+ accept();
}
void IconPickerDialog::selectionChanged(QItemSelection selected, QItemSelection deselected)
{
- if (selected.empty())
- return;
+ if (selected.empty())
+ return;
- QString key = selected.first().indexes().first().data(Qt::UserRole).toString();
- if (!key.isEmpty())
- selectedIconKey = key;
+ QString key = selected.first().indexes().first().data(Qt::UserRole).toString();
+ if (!key.isEmpty())
+ selectedIconKey = key;
}
int IconPickerDialog::execWithSelection(QString selection)
{
- auto list = MMC->icons();
- auto contentsWidget = ui->iconView;
- selectedIconKey = selection;
-
- int index_nr = list->getIconIndex(selection);
- auto model_index = list->index(index_nr);
- contentsWidget->selectionModel()->select(
- model_index, QItemSelectionModel::Current | QItemSelectionModel::Select);
-
- QMetaObject::invokeMethod(this, "delayed_scroll", Qt::QueuedConnection,
- Q_ARG(QModelIndex, model_index));
- return QDialog::exec();
+ auto list = MMC->icons();
+ auto contentsWidget = ui->iconView;
+ selectedIconKey = selection;
+
+ int index_nr = list->getIconIndex(selection);
+ auto model_index = list->index(index_nr);
+ contentsWidget->selectionModel()->select(
+ model_index, QItemSelectionModel::Current | QItemSelectionModel::Select);
+
+ QMetaObject::invokeMethod(this, "delayed_scroll", Qt::QueuedConnection,
+ Q_ARG(QModelIndex, model_index));
+ return QDialog::exec();
}
void IconPickerDialog::delayed_scroll(QModelIndex model_index)
{
- auto contentsWidget = ui->iconView;
- contentsWidget->scrollTo(model_index);
+ auto contentsWidget = ui->iconView;
+ contentsWidget->scrollTo(model_index);
}
IconPickerDialog::~IconPickerDialog()
{
- delete ui;
+ delete ui;
}
void IconPickerDialog::openFolder()
{
- DesktopServices::openDirectory(MMC->icons()->getDirectory(), true);
+ DesktopServices::openDirectory(MMC->icons()->getDirectory(), true);
}
diff --git a/application/dialogs/IconPickerDialog.h b/application/dialogs/IconPickerDialog.h
index 9053ec61..cb870f44 100644
--- a/application/dialogs/IconPickerDialog.h
+++ b/application/dialogs/IconPickerDialog.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,26 +24,26 @@ class IconPickerDialog;
class IconPickerDialog : public QDialog
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit IconPickerDialog(QWidget *parent = 0);
- ~IconPickerDialog();
- int execWithSelection(QString selection);
- QString selectedIconKey;
+ explicit IconPickerDialog(QWidget *parent = 0);
+ ~IconPickerDialog();
+ int execWithSelection(QString selection);
+ QString selectedIconKey;
protected:
- virtual bool eventFilter(QObject *, QEvent *);
+ virtual bool eventFilter(QObject *, QEvent *);
private:
- Ui::IconPickerDialog *ui;
+ Ui::IconPickerDialog *ui;
private
slots:
- void selectionChanged(QItemSelection, QItemSelection);
- void activated(QModelIndex);
- void delayed_scroll(QModelIndex);
- void addNewIcon();
- void removeSelectedIcon();
- void openFolder();
+ void selectionChanged(QItemSelection, QItemSelection);
+ void activated(QModelIndex);
+ void delayed_scroll(QModelIndex);
+ void addNewIcon();
+ void removeSelectedIcon();
+ void openFolder();
};
diff --git a/application/dialogs/LoginDialog.cpp b/application/dialogs/LoginDialog.cpp
index b2020372..484cb8e2 100644
--- a/application/dialogs/LoginDialog.cpp
+++ b/application/dialogs/LoginDialog.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,89 +22,89 @@
LoginDialog::LoginDialog(QWidget *parent) : QDialog(parent), ui(new Ui::LoginDialog)
{
- ui->setupUi(this);
- ui->progressBar->setVisible(false);
- ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
+ ui->setupUi(this);
+ ui->progressBar->setVisible(false);
+ ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
- connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
- connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
+ connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
+ connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
}
LoginDialog::~LoginDialog()
{
- delete ui;
+ delete ui;
}
// Stage 1: User interaction
void LoginDialog::accept()
{
- setUserInputsEnabled(false);
- ui->progressBar->setVisible(true);
-
- // Setup the login task and start it
- m_account = MojangAccount::createFromUsername(ui->userTextBox->text());
- m_loginTask = m_account->login(nullptr, ui->passTextBox->text());
- connect(m_loginTask.get(), &Task::failed, this, &LoginDialog::onTaskFailed);
- connect(m_loginTask.get(), &Task::succeeded, this,
- &LoginDialog::onTaskSucceeded);
- connect(m_loginTask.get(), &Task::status, this, &LoginDialog::onTaskStatus);
- connect(m_loginTask.get(), &Task::progress, this, &LoginDialog::onTaskProgress);
- m_loginTask->start();
+ setUserInputsEnabled(false);
+ ui->progressBar->setVisible(true);
+
+ // Setup the login task and start it
+ m_account = MojangAccount::createFromUsername(ui->userTextBox->text());
+ m_loginTask = m_account->login(nullptr, ui->passTextBox->text());
+ connect(m_loginTask.get(), &Task::failed, this, &LoginDialog::onTaskFailed);
+ connect(m_loginTask.get(), &Task::succeeded, this,
+ &LoginDialog::onTaskSucceeded);
+ connect(m_loginTask.get(), &Task::status, this, &LoginDialog::onTaskStatus);
+ connect(m_loginTask.get(), &Task::progress, this, &LoginDialog::onTaskProgress);
+ m_loginTask->start();
}
void LoginDialog::setUserInputsEnabled(bool enable)
{
- ui->userTextBox->setEnabled(enable);
- ui->passTextBox->setEnabled(enable);
- ui->buttonBox->setEnabled(enable);
+ ui->userTextBox->setEnabled(enable);
+ ui->passTextBox->setEnabled(enable);
+ ui->buttonBox->setEnabled(enable);
}
// Enable the OK button only when both textboxes contain something.
void LoginDialog::on_userTextBox_textEdited(const QString &newText)
{
- ui->buttonBox->button(QDialogButtonBox::Ok)
- ->setEnabled(!newText.isEmpty() && !ui->passTextBox->text().isEmpty());
+ ui->buttonBox->button(QDialogButtonBox::Ok)
+ ->setEnabled(!newText.isEmpty() && !ui->passTextBox->text().isEmpty());
}
void LoginDialog::on_passTextBox_textEdited(const QString &newText)
{
- ui->buttonBox->button(QDialogButtonBox::Ok)
- ->setEnabled(!newText.isEmpty() && !ui->userTextBox->text().isEmpty());
+ ui->buttonBox->button(QDialogButtonBox::Ok)
+ ->setEnabled(!newText.isEmpty() && !ui->userTextBox->text().isEmpty());
}
void LoginDialog::onTaskFailed(const QString &reason)
{
- // Set message
- ui->label->setText("<span style='color:red'>" + reason + "</span>");
+ // Set message
+ ui->label->setText("<span style='color:red'>" + reason + "</span>");
- // Re-enable user-interaction
- setUserInputsEnabled(true);
- ui->progressBar->setVisible(false);
+ // Re-enable user-interaction
+ setUserInputsEnabled(true);
+ ui->progressBar->setVisible(false);
}
void LoginDialog::onTaskSucceeded()
{
- QDialog::accept();
+ QDialog::accept();
}
void LoginDialog::onTaskStatus(const QString &status)
{
- ui->label->setText(status);
+ ui->label->setText(status);
}
void LoginDialog::onTaskProgress(qint64 current, qint64 total)
{
- ui->progressBar->setMaximum(total);
- ui->progressBar->setValue(current);
+ ui->progressBar->setMaximum(total);
+ ui->progressBar->setValue(current);
}
// Public interface
MojangAccountPtr LoginDialog::newAccount(QWidget *parent, QString msg)
{
- LoginDialog dlg(parent);
- dlg.ui->label->setText(msg);
- if (dlg.exec() == QDialog::Accepted)
- {
- return dlg.m_account;
- }
- return 0;
+ LoginDialog dlg(parent);
+ dlg.ui->label->setText(msg);
+ if (dlg.exec() == QDialog::Accepted)
+ {
+ return dlg.m_account;
+ }
+ return 0;
}
diff --git a/application/dialogs/LoginDialog.h b/application/dialogs/LoginDialog.h
index 27b97cb0..30fcb760 100644
--- a/application/dialogs/LoginDialog.h
+++ b/application/dialogs/LoginDialog.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,32 +27,32 @@ class LoginDialog;
class LoginDialog : public QDialog
{
- Q_OBJECT
+ Q_OBJECT
public:
- ~LoginDialog();
+ ~LoginDialog();
- static MojangAccountPtr newAccount(QWidget *parent, QString message);
+ static MojangAccountPtr newAccount(QWidget *parent, QString message);
private:
- explicit LoginDialog(QWidget *parent = 0);
+ explicit LoginDialog(QWidget *parent = 0);
- void setUserInputsEnabled(bool enable);
+ void setUserInputsEnabled(bool enable);
protected
slots:
- void accept();
+ void accept();
- void onTaskFailed(const QString &reason);
- void onTaskSucceeded();
- void onTaskStatus(const QString &status);
- void onTaskProgress(qint64 current, qint64 total);
+ void onTaskFailed(const QString &reason);
+ void onTaskSucceeded();
+ void onTaskStatus(const QString &status);
+ void onTaskProgress(qint64 current, qint64 total);
- void on_userTextBox_textEdited(const QString &newText);
- void on_passTextBox_textEdited(const QString &newText);
+ void on_userTextBox_textEdited(const QString &newText);
+ void on_passTextBox_textEdited(const QString &newText);
private:
- Ui::LoginDialog *ui;
- MojangAccountPtr m_account;
- std::shared_ptr<Task> m_loginTask;
+ Ui::LoginDialog *ui;
+ MojangAccountPtr m_account;
+ std::shared_ptr<Task> m_loginTask;
};
diff --git a/application/dialogs/ModEditDialogCommon.cpp b/application/dialogs/ModEditDialogCommon.cpp
deleted file mode 100644
index 4201bdad..00000000
--- a/application/dialogs/ModEditDialogCommon.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#include "ModEditDialogCommon.h"
-#include "CustomMessageBox.h"
-#include <QUrl>
-
-bool lastfirst(QModelIndexList &list, int &first, int &last)
-{
- if (list.isEmpty())
- return false;
- first = last = list[0].row();
- for (auto item : list)
- {
- int row = item.row();
- if (row < first)
- first = row;
- if (row > last)
- last = row;
- }
- return true;
-}
-
-void showWebsiteForMod(QWidget *parentDlg, Mod &m)
-{
- QString url = m.homeurl();
- if (url.size())
- {
- // catch the cases where the protocol is missing
- if (!url.startsWith("http"))
- {
- url = "http://" + url;
- }
- DesktopServices::openUrl(url);
- }
- else
- {
- CustomMessageBox::selectable(
- parentDlg, QObject::tr("How sad!"),
- QObject::tr("The mod author didn't provide a website link for this mod."),
- QMessageBox::Warning);
- }
-}
diff --git a/application/dialogs/ModEditDialogCommon.h b/application/dialogs/ModEditDialogCommon.h
deleted file mode 100644
index fc5e3c2b..00000000
--- a/application/dialogs/ModEditDialogCommon.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-#include <QModelIndex>
-#include <DesktopServices.h>
-#include <QWidget>
-#include <minecraft/Mod.h>
-
-bool lastfirst(QModelIndexList &list, int &first, int &last);
-
-void showWebsiteForMod(QWidget *parentDlg, Mod &m);
diff --git a/application/dialogs/NewComponentDialog.cpp b/application/dialogs/NewComponentDialog.cpp
index 514aa938..d0d1d24b 100644
--- a/application/dialogs/NewComponentDialog.cpp
+++ b/application/dialogs/NewComponentDialog.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,72 +35,72 @@
#include <meta/VersionList.h>
NewComponentDialog::NewComponentDialog(const QString & initialName, const QString & initialUid, QWidget *parent)
- : QDialog(parent), ui(new Ui::NewComponentDialog)
+ : QDialog(parent), ui(new Ui::NewComponentDialog)
{
- ui->setupUi(this);
- resize(minimumSizeHint());
+ ui->setupUi(this);
+ resize(minimumSizeHint());
- ui->nameTextBox->setText(initialName);
- ui->uidTextBox->setText(initialUid);
+ ui->nameTextBox->setText(initialName);
+ ui->uidTextBox->setText(initialUid);
- connect(ui->nameTextBox, &QLineEdit::textChanged, this, &NewComponentDialog::updateDialogState);
- connect(ui->uidTextBox, &QLineEdit::textChanged, this, &NewComponentDialog::updateDialogState);
+ connect(ui->nameTextBox, &QLineEdit::textChanged, this, &NewComponentDialog::updateDialogState);
+ connect(ui->uidTextBox, &QLineEdit::textChanged, this, &NewComponentDialog::updateDialogState);
- auto groups = MMC->instances()->getGroups().toSet();
- ui->nameTextBox->setFocus();
+ auto groups = MMC->instances()->getGroups().toSet();
+ ui->nameTextBox->setFocus();
- originalPlaceholderText = ui->uidTextBox->placeholderText();
- updateDialogState();
+ originalPlaceholderText = ui->uidTextBox->placeholderText();
+ updateDialogState();
}
NewComponentDialog::~NewComponentDialog()
{
- delete ui;
+ delete ui;
}
void NewComponentDialog::updateDialogState()
{
- auto protoUid = ui->nameTextBox->text().toLower();
- protoUid.remove(QRegularExpression("[^a-z]"));
- if(protoUid.isEmpty())
- {
- ui->uidTextBox->setPlaceholderText(originalPlaceholderText);
- }
- else
- {
- QString suggestedUid = "org.multimc.custom." + protoUid;
- ui->uidTextBox->setPlaceholderText(suggestedUid);
- }
- bool allowOK = !name().isEmpty() && !uid().isEmpty() && !uidBlacklist.contains(uid());
- ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(allowOK);
+ auto protoUid = ui->nameTextBox->text().toLower();
+ protoUid.remove(QRegularExpression("[^a-z]"));
+ if(protoUid.isEmpty())
+ {
+ ui->uidTextBox->setPlaceholderText(originalPlaceholderText);
+ }
+ else
+ {
+ QString suggestedUid = "org.multimc.custom." + protoUid;
+ ui->uidTextBox->setPlaceholderText(suggestedUid);
+ }
+ bool allowOK = !name().isEmpty() && !uid().isEmpty() && !uidBlacklist.contains(uid());
+ ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(allowOK);
}
QString NewComponentDialog::name() const
{
- auto result = ui->nameTextBox->text();
- if(result.size())
- {
- return result.trimmed();
- }
- return QString();
+ auto result = ui->nameTextBox->text();
+ if(result.size())
+ {
+ return result.trimmed();
+ }
+ return QString();
}
QString NewComponentDialog::uid() const
{
- auto result = ui->uidTextBox->text();
- if(result.size())
- {
- return result.trimmed();
- }
- result = ui->uidTextBox->placeholderText();
- if(result.size() && result != originalPlaceholderText)
- {
- return result.trimmed();
- }
- return QString();
+ auto result = ui->uidTextBox->text();
+ if(result.size())
+ {
+ return result.trimmed();
+ }
+ result = ui->uidTextBox->placeholderText();
+ if(result.size() && result != originalPlaceholderText)
+ {
+ return result.trimmed();
+ }
+ return QString();
}
void NewComponentDialog::setBlacklist(QStringList badUids)
{
- uidBlacklist = badUids;
+ uidBlacklist = badUids;
}
diff --git a/application/dialogs/NewComponentDialog.h b/application/dialogs/NewComponentDialog.h
index 70caec0f..518f342d 100644
--- a/application/dialogs/NewComponentDialog.h
+++ b/application/dialogs/NewComponentDialog.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,22 +27,22 @@ class NewComponentDialog;
class NewComponentDialog : public QDialog
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit NewComponentDialog(const QString & initialName = QString(), const QString & initialUid = QString(), QWidget *parent = 0);
- virtual ~NewComponentDialog();
- void setBlacklist(QStringList badUids);
+ explicit NewComponentDialog(const QString & initialName = QString(), const QString & initialUid = QString(), QWidget *parent = 0);
+ virtual ~NewComponentDialog();
+ void setBlacklist(QStringList badUids);
- QString name() const;
- QString uid() const;
+ QString name() const;
+ QString uid() const;
private slots:
- void updateDialogState();
+ void updateDialogState();
private:
- Ui::NewComponentDialog *ui;
+ Ui::NewComponentDialog *ui;
- QString originalPlaceholderText;
- QStringList uidBlacklist;
+ QString originalPlaceholderText;
+ QStringList uidBlacklist;
};
diff --git a/application/dialogs/NewComponentDialog.ui b/application/dialogs/NewComponentDialog.ui
index b30c2431..03b0d222 100644
--- a/application/dialogs/NewComponentDialog.ui
+++ b/application/dialogs/NewComponentDialog.ui
@@ -14,7 +14,7 @@
</rect>
</property>
<property name="windowTitle">
- <string>Copy Instance</string>
+ <string>Add Empty Component</string>
</property>
<property name="windowIcon">
<iconset>
diff --git a/application/dialogs/NewInstanceDialog.cpp b/application/dialogs/NewInstanceDialog.cpp
index b3ce5c6c..3533763d 100644
--- a/application/dialogs/NewInstanceDialog.cpp
+++ b/application/dialogs/NewInstanceDialog.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,178 +39,209 @@
#include <pages/modplatform/ImportPage.h>
#include <pages/modplatform/TechnicPage.h>
-NewInstanceDialog::NewInstanceDialog(const QString & initialGroup, const QString & url, QWidget *parent)
- : QDialog(parent), ui(new Ui::NewInstanceDialog)
-{
- ui->setupUi(this);
-
- setWindowIcon(MMC->getThemedIcon("new"));
-
- InstIconKey = "default";
- ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
-
- auto groups = MMC->instances()->getGroups().toSet();
- auto groupList = QStringList(groups.toList());
- groupList.sort(Qt::CaseInsensitive);
- groupList.removeOne("");
- groupList.push_front(initialGroup);
- groupList.push_front("");
- ui->groupBox->addItems(groupList);
- int index = groupList.indexOf(initialGroup);
- if(index == -1)
- {
- index = 0;
- }
- ui->groupBox->setCurrentIndex(index);
- ui->groupBox->lineEdit()->setPlaceholderText(tr("No group"));
-
- m_buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Ok);
- m_buttons->button(QDialogButtonBox::Ok)->setDefault(true);
-
- m_container = new PageContainer(this);
- m_container->setSizePolicy(QSizePolicy::Policy::Preferred, QSizePolicy::Policy::Expanding);
- m_container->layout()->setContentsMargins(0, 0, 0, 0);
- ui->verticalLayout->insertWidget(2, m_container);
-
- m_container->addButtons(m_buttons);
- m_buttons->setFocus();
-
- if(!url.isEmpty())
- {
- m_container->selectPage("import");
- importPage->setUrl(url);
- }
-
- connect(m_buttons->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &NewInstanceDialog::accept);
- connect(m_buttons->button(QDialogButtonBox::Help), &QPushButton::clicked, m_container, &PageContainer::help);
-
- updateDialogState();
-
- restoreGeometry(QByteArray::fromBase64(MMC->settings()->get("NewInstanceGeometry").toByteArray()));
+NewInstanceDialog::NewInstanceDialog(const QString & initialGroup, const QString & url, QWidget *parent)
+ : QDialog(parent), ui(new Ui::NewInstanceDialog)
+{
+ ui->setupUi(this);
+
+ setWindowIcon(MMC->getThemedIcon("new"));
+
+ InstIconKey = "default";
+ ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
+
+ auto groups = MMC->instances()->getGroups().toSet();
+ auto groupList = QStringList(groups.toList());
+ groupList.sort(Qt::CaseInsensitive);
+ groupList.removeOne("");
+ groupList.push_front(initialGroup);
+ groupList.push_front("");
+ ui->groupBox->addItems(groupList);
+ int index = groupList.indexOf(initialGroup);
+ if(index == -1)
+ {
+ index = 0;
+ }
+ ui->groupBox->setCurrentIndex(index);
+ ui->groupBox->lineEdit()->setPlaceholderText(tr("No group"));
+
+
+ // NOTE: m_buttons must be initialized before PageContainer, because it indirectly accesses m_buttons through setSuggestedPack! Do not move this below.
+ m_buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+
+ m_container = new PageContainer(this);
+ m_container->setSizePolicy(QSizePolicy::Policy::Preferred, QSizePolicy::Policy::Expanding);
+ m_container->layout()->setContentsMargins(0, 0, 0, 0);
+ ui->verticalLayout->insertWidget(2, m_container);
+
+ m_container->addButtons(m_buttons);
+
+ // Bonk Qt over its stupid head and make sure it understands which button is the default one...
+ // See: https://stackoverflow.com/questions/24556831/qbuttonbox-set-default-button
+ auto OkButton = m_buttons->button(QDialogButtonBox::Ok);
+ OkButton->setDefault(true);
+ OkButton->setAutoDefault(true);
+ connect(OkButton, &QPushButton::clicked, this, &NewInstanceDialog::accept);
+
+ auto CancelButton = m_buttons->button(QDialogButtonBox::Cancel);
+ CancelButton->setDefault(false);
+ CancelButton->setAutoDefault(false);
+ connect(CancelButton, &QPushButton::clicked, this, &NewInstanceDialog::reject);
+
+ auto HelpButton = m_buttons->button(QDialogButtonBox::Help);
+ HelpButton->setDefault(false);
+ HelpButton->setAutoDefault(false);
+ connect(HelpButton, &QPushButton::clicked, m_container, &PageContainer::help);
+
+ if(!url.isEmpty())
+ {
+ QUrl actualUrl(url);
+ if(actualUrl.host() == "www.curseforge.com") {
+ m_container->selectPage("twitch");
+ twitchPage->setUrl(url);
+ }
+ else {
+ m_container->selectPage("import");
+ importPage->setUrl(url);
+ }
+ }
+
+ updateDialogState();
+
+ restoreGeometry(QByteArray::fromBase64(MMC->settings()->get("NewInstanceGeometry").toByteArray()));
}
void NewInstanceDialog::reject()
{
- MMC->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
- QDialog::reject();
+ MMC->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
+ QDialog::reject();
}
void NewInstanceDialog::accept()
{
- MMC->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
- importIconNow();
- QDialog::accept();
+ MMC->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
+ importIconNow();
+ QDialog::accept();
}
QList<BasePage *> NewInstanceDialog::getPages()
{
- importPage = new ImportPage(this);
- return
- {
- new VanillaPage(this),
- new FTBPage(this),
- importPage,
- new TwitchPage(this),
- new TechnicPage(this)
- };
+ importPage = new ImportPage(this);
+ twitchPage = new TwitchPage(this);
+ return
+ {
+ new VanillaPage(this),
+ importPage,
+ twitchPage,
+ new FTBPage(this)
+ };
}
QString NewInstanceDialog::dialogTitle()
{
- return tr("New Instance");
+ return tr("New Instance");
}
NewInstanceDialog::~NewInstanceDialog()
{
- delete ui;
+ delete ui;
}
void NewInstanceDialog::setSuggestedPack(const QString& name, InstanceTask* task)
{
- creationTask.reset(task);
- ui->instNameTextBox->setPlaceholderText(name);
+ creationTask.reset(task);
+ ui->instNameTextBox->setPlaceholderText(name);
+
+ if(!task)
+ {
+ ui->iconButton->setIcon(MMC->icons()->getIcon("default"));
+ importIcon = false;
+ }
- auto allowOK = task && !instName().isEmpty();
- m_buttons->button(QDialogButtonBox::Ok)->setEnabled(allowOK);
+ auto allowOK = task && !instName().isEmpty();
+ m_buttons->button(QDialogButtonBox::Ok)->setEnabled(allowOK);
}
void NewInstanceDialog::setSuggestedIconFromFile(const QString &path, const QString &name)
{
- importIcon = true;
- importIconPath = path;
- importIconName = name;
+ importIcon = true;
+ importIconPath = path;
+ importIconName = name;
- //Hmm, for some reason they can be to small
- ui->iconButton->setIcon(QIcon(path));
+ //Hmm, for some reason they can be to small
+ ui->iconButton->setIcon(QIcon(path));
}
InstanceTask * NewInstanceDialog::extractTask()
{
- InstanceTask * extracted = creationTask.get();
- creationTask.release();
- extracted->setName(instName());
- extracted->setGroup(instGroup());
- extracted->setIcon(iconKey());
- return extracted;
+ InstanceTask * extracted = creationTask.get();
+ creationTask.release();
+ extracted->setName(instName());
+ extracted->setGroup(instGroup());
+ extracted->setIcon(iconKey());
+ return extracted;
}
void NewInstanceDialog::updateDialogState()
{
- auto allowOK = creationTask && !instName().isEmpty();
- m_buttons->button(QDialogButtonBox::Ok)->setEnabled(allowOK);
+ auto allowOK = creationTask && !instName().isEmpty();
+ auto OkButton = m_buttons->button(QDialogButtonBox::Ok);
+ if(OkButton->isEnabled() != allowOK)
+ {
+ OkButton->setEnabled(allowOK);
+ }
}
QString NewInstanceDialog::instName() const
{
- auto result = ui->instNameTextBox->text();
- if(result.size())
- {
- return result.trimmed();
- }
- result = ui->instNameTextBox->placeholderText();
- if(result.size())
- {
- return result.trimmed();
- }
- return QString();
+ auto result = ui->instNameTextBox->text().trimmed();
+ if(result.size())
+ {
+ return result;
+ }
+ result = ui->instNameTextBox->placeholderText().trimmed();
+ if(result.size())
+ {
+ return result;
+ }
+ return QString();
}
QString NewInstanceDialog::instGroup() const
{
- return ui->groupBox->currentText();
+ return ui->groupBox->currentText();
}
QString NewInstanceDialog::iconKey() const
{
- return InstIconKey;
+ return InstIconKey;
}
void NewInstanceDialog::on_iconButton_clicked()
{
- importIconNow(); //so the user can switch back
- IconPickerDialog dlg(this);
- dlg.execWithSelection(InstIconKey);
+ importIconNow(); //so the user can switch back
+ IconPickerDialog dlg(this);
+ dlg.execWithSelection(InstIconKey);
- if (dlg.result() == QDialog::Accepted)
- {
- InstIconKey = dlg.selectedIconKey;
- ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
- importIcon = false;
- }
+ if (dlg.result() == QDialog::Accepted)
+ {
+ InstIconKey = dlg.selectedIconKey;
+ ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
+ importIcon = false;
+ }
}
void NewInstanceDialog::on_instNameTextBox_textChanged(const QString &arg1)
{
- updateDialogState();
+ updateDialogState();
}
void NewInstanceDialog::importIconNow()
{
- if(importIcon) {
- MMC->icons()->installIcon(importIconPath, importIconName);
- InstIconKey = importIconName;
- importIcon = false;
- }
- MMC->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
+ if(importIcon) {
+ MMC->icons()->installIcon(importIconPath, importIconName);
+ InstIconKey = importIconName;
+ importIcon = false;
+ }
+ MMC->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
}
diff --git a/application/dialogs/NewInstanceDialog.h b/application/dialogs/NewInstanceDialog.h
index 1448d225..0b8b2fb8 100644
--- a/application/dialogs/NewInstanceDialog.h
+++ b/application/dialogs/NewInstanceDialog.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,49 +29,51 @@ class NewInstanceDialog;
class PageContainer;
class QDialogButtonBox;
class ImportPage;
+class TwitchPage;
class NewInstanceDialog : public QDialog, public BasePageProvider
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit NewInstanceDialog(const QString & initialGroup, const QString & url = QString(), QWidget *parent = 0);
- ~NewInstanceDialog();
+ explicit NewInstanceDialog(const QString & initialGroup, const QString & url = QString(), QWidget *parent = 0);
+ ~NewInstanceDialog();
- void updateDialogState();
+ void updateDialogState();
- void setSuggestedPack(const QString & name = QString(), InstanceTask * task = nullptr);
- void setSuggestedIconFromFile(const QString &path, const QString &name);
+ void setSuggestedPack(const QString & name = QString(), InstanceTask * task = nullptr);
+ void setSuggestedIconFromFile(const QString &path, const QString &name);
- InstanceTask * extractTask();
+ InstanceTask * extractTask();
- QString dialogTitle() override;
- QList<BasePage *> getPages() override;
+ QString dialogTitle() override;
+ QList<BasePage *> getPages() override;
- QString instName() const;
- QString instGroup() const;
- QString iconKey() const;
+ QString instName() const;
+ QString instGroup() const;
+ QString iconKey() const;
public slots:
- void accept() override;
- void reject() override;
+ void accept() override;
+ void reject() override;
private slots:
- void on_iconButton_clicked();
- void on_instNameTextBox_textChanged(const QString &arg1);
+ void on_iconButton_clicked();
+ void on_instNameTextBox_textChanged(const QString &arg1);
private:
- Ui::NewInstanceDialog *ui = nullptr;
- PageContainer * m_container = nullptr;
- QDialogButtonBox * m_buttons = nullptr;
+ Ui::NewInstanceDialog *ui = nullptr;
+ PageContainer * m_container = nullptr;
+ QDialogButtonBox * m_buttons = nullptr;
- QString InstIconKey;
- ImportPage *importPage = nullptr;
- std::unique_ptr<InstanceTask> creationTask;
+ QString InstIconKey;
+ ImportPage *importPage = nullptr;
+ TwitchPage *twitchPage = nullptr;
+ std::unique_ptr<InstanceTask> creationTask;
- bool importIcon = false;
- QString importIconPath;
- QString importIconName;
+ bool importIcon = false;
+ QString importIconPath;
+ QString importIconName;
- void importIconNow();
+ void importIconNow();
};
diff --git a/application/dialogs/NotificationDialog.cpp b/application/dialogs/NotificationDialog.cpp
index 86b03bda..f2a35ae2 100644
--- a/application/dialogs/NotificationDialog.cpp
+++ b/application/dialogs/NotificationDialog.cpp
@@ -2,85 +2,85 @@
#include "ui_NotificationDialog.h"
#include <QTimerEvent>
-#include <QStyle>
+#include <QStyle>
NotificationDialog::NotificationDialog(const NotificationChecker::NotificationEntry &entry, QWidget *parent) :
- QDialog(parent, Qt::MSWindowsFixedSizeDialogHint | Qt::WindowTitleHint | Qt::CustomizeWindowHint),
- ui(new Ui::NotificationDialog)
+ QDialog(parent, Qt::MSWindowsFixedSizeDialogHint | Qt::WindowTitleHint | Qt::CustomizeWindowHint),
+ ui(new Ui::NotificationDialog)
{
- ui->setupUi(this);
+ ui->setupUi(this);
- QStyle::StandardPixmap icon;
- switch (entry.type)
- {
- case NotificationChecker::NotificationEntry::Critical:
- icon = QStyle::SP_MessageBoxCritical;
- break;
- case NotificationChecker::NotificationEntry::Warning:
- icon = QStyle::SP_MessageBoxWarning;
- break;
- default:
- case NotificationChecker::NotificationEntry::Information:
- icon = QStyle::SP_MessageBoxInformation;
- break;
- }
- ui->iconLabel->setPixmap(style()->standardPixmap(icon, 0, this));
- ui->messageLabel->setText(entry.message);
+ QStyle::StandardPixmap icon;
+ switch (entry.type)
+ {
+ case NotificationChecker::NotificationEntry::Critical:
+ icon = QStyle::SP_MessageBoxCritical;
+ break;
+ case NotificationChecker::NotificationEntry::Warning:
+ icon = QStyle::SP_MessageBoxWarning;
+ break;
+ default:
+ case NotificationChecker::NotificationEntry::Information:
+ icon = QStyle::SP_MessageBoxInformation;
+ break;
+ }
+ ui->iconLabel->setPixmap(style()->standardPixmap(icon, 0, this));
+ ui->messageLabel->setText(entry.message);
- m_dontShowAgainText = tr("Don't show again");
- m_closeText = tr("Close");
+ m_dontShowAgainText = tr("Don't show again");
+ m_closeText = tr("Close");
- ui->dontShowAgainBtn->setText(m_dontShowAgainText + QString(" (%1)").arg(m_dontShowAgainTime));
- ui->closeBtn->setText(m_closeText + QString(" (%1)").arg(m_closeTime));
+ ui->dontShowAgainBtn->setText(m_dontShowAgainText + QString(" (%1)").arg(m_dontShowAgainTime));
+ ui->closeBtn->setText(m_closeText + QString(" (%1)").arg(m_closeTime));
- startTimer(1000);
+ startTimer(1000);
}
NotificationDialog::~NotificationDialog()
{
- delete ui;
+ delete ui;
}
void NotificationDialog::timerEvent(QTimerEvent *event)
{
- if (m_dontShowAgainTime > 0)
- {
- m_dontShowAgainTime--;
- if (m_dontShowAgainTime == 0)
- {
- ui->dontShowAgainBtn->setText(m_dontShowAgainText);
- ui->dontShowAgainBtn->setEnabled(true);
- }
- else
- {
- ui->dontShowAgainBtn->setText(m_dontShowAgainText + QString(" (%1)").arg(m_dontShowAgainTime));
- }
- }
- if (m_closeTime > 0)
- {
- m_closeTime--;
- if (m_closeTime == 0)
- {
- ui->closeBtn->setText(m_closeText);
- ui->closeBtn->setEnabled(true);
- }
- else
- {
- ui->closeBtn->setText(m_closeText + QString(" (%1)").arg(m_closeTime));
- }
- }
+ if (m_dontShowAgainTime > 0)
+ {
+ m_dontShowAgainTime--;
+ if (m_dontShowAgainTime == 0)
+ {
+ ui->dontShowAgainBtn->setText(m_dontShowAgainText);
+ ui->dontShowAgainBtn->setEnabled(true);
+ }
+ else
+ {
+ ui->dontShowAgainBtn->setText(m_dontShowAgainText + QString(" (%1)").arg(m_dontShowAgainTime));
+ }
+ }
+ if (m_closeTime > 0)
+ {
+ m_closeTime--;
+ if (m_closeTime == 0)
+ {
+ ui->closeBtn->setText(m_closeText);
+ ui->closeBtn->setEnabled(true);
+ }
+ else
+ {
+ ui->closeBtn->setText(m_closeText + QString(" (%1)").arg(m_closeTime));
+ }
+ }
- if (m_closeTime == 0 && m_dontShowAgainTime == 0)
- {
- killTimer(event->timerId());
- }
+ if (m_closeTime == 0 && m_dontShowAgainTime == 0)
+ {
+ killTimer(event->timerId());
+ }
}
void NotificationDialog::on_dontShowAgainBtn_clicked()
{
- done(DontShowAgain);
+ done(DontShowAgain);
}
void NotificationDialog::on_closeBtn_clicked()
{
- done(Normal);
+ done(Normal);
}
diff --git a/application/dialogs/NotificationDialog.h b/application/dialogs/NotificationDialog.h
index 27b9e853..e1cbb9fa 100644
--- a/application/dialogs/NotificationDialog.h
+++ b/application/dialogs/NotificationDialog.h
@@ -11,34 +11,34 @@ class NotificationDialog;
class NotificationDialog : public QDialog
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit NotificationDialog(const NotificationChecker::NotificationEntry &entry, QWidget *parent = 0);
- ~NotificationDialog();
+ explicit NotificationDialog(const NotificationChecker::NotificationEntry &entry, QWidget *parent = 0);
+ ~NotificationDialog();
- enum ExitCode
- {
- Normal,
- DontShowAgain
- };
+ enum ExitCode
+ {
+ Normal,
+ DontShowAgain
+ };
protected:
- void timerEvent(QTimerEvent *event);
+ void timerEvent(QTimerEvent *event);
private:
- Ui::NotificationDialog *ui;
+ Ui::NotificationDialog *ui;
- int m_dontShowAgainTime = 10;
- int m_closeTime = 5;
+ int m_dontShowAgainTime = 10;
+ int m_closeTime = 5;
- QString m_dontShowAgainText;
- QString m_closeText;
+ QString m_dontShowAgainText;
+ QString m_closeText;
private
slots:
- void on_dontShowAgainBtn_clicked();
- void on_closeBtn_clicked();
+ void on_dontShowAgainBtn_clicked();
+ void on_closeBtn_clicked();
};
#endif // NOTIFICATIONDIALOG_H
diff --git a/application/dialogs/ProfileSelectDialog.cpp b/application/dialogs/ProfileSelectDialog.cpp
index f1b335f9..b64de01a 100644
--- a/application/dialogs/ProfileSelectDialog.cpp
+++ b/application/dialogs/ProfileSelectDialog.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,91 +26,91 @@
#include <MultiMC.h>
ProfileSelectDialog::ProfileSelectDialog(const QString &message, int flags, QWidget *parent)
- : QDialog(parent), ui(new Ui::ProfileSelectDialog)
+ : QDialog(parent), ui(new Ui::ProfileSelectDialog)
{
- ui->setupUi(this);
-
- m_accounts = MMC->accounts();
- auto view = ui->listView;
- //view->setModel(m_accounts.get());
- //view->hideColumn(MojangAccountList::ActiveColumn);
- view->setColumnCount(1);
- view->setRootIsDecorated(false);
- if(QTreeWidgetItem* header = view->headerItem())
- {
- header->setText(0, tr("Name"));
- }
- else
- {
- view->setHeaderLabel(tr("Name"));
- }
- QList <QTreeWidgetItem *> items;
- for (int i = 0; i < m_accounts->count(); i++)
- {
- MojangAccountPtr account = m_accounts->at(i);
- for (auto profile : account->profiles())
- {
- auto profileLabel = profile.name;
- if(account->isInUse())
- {
- profileLabel += tr(" (in use)");
- }
- auto item = new QTreeWidgetItem(view);
- item->setText(0, profileLabel);
- item->setIcon(0, SkinUtils::getFaceFromCache(profile.id));
- item->setData(0, MojangAccountList::PointerRole, QVariant::fromValue(account));
- items.append(item);
- }
- }
- view->addTopLevelItems(items);
-
- // Set the message label.
- ui->msgLabel->setVisible(!message.isEmpty());
- ui->msgLabel->setText(message);
-
- // Flags...
- ui->globalDefaultCheck->setVisible(flags & GlobalDefaultCheckbox);
- ui->instDefaultCheck->setVisible(flags & InstanceDefaultCheckbox);
- qDebug() << flags;
-
- // Select the first entry in the list.
- ui->listView->setCurrentIndex(ui->listView->model()->index(0, 0));
-
- connect(ui->listView, SIGNAL(doubleClicked(QModelIndex)), SLOT(on_buttonBox_accepted()));
+ ui->setupUi(this);
+
+ m_accounts = MMC->accounts();
+ auto view = ui->listView;
+ //view->setModel(m_accounts.get());
+ //view->hideColumn(MojangAccountList::ActiveColumn);
+ view->setColumnCount(1);
+ view->setRootIsDecorated(false);
+ if(QTreeWidgetItem* header = view->headerItem())
+ {
+ header->setText(0, tr("Name"));
+ }
+ else
+ {
+ view->setHeaderLabel(tr("Name"));
+ }
+ QList <QTreeWidgetItem *> items;
+ for (int i = 0; i < m_accounts->count(); i++)
+ {
+ MojangAccountPtr account = m_accounts->at(i);
+ for (auto profile : account->profiles())
+ {
+ auto profileLabel = profile.name;
+ if(account->isInUse())
+ {
+ profileLabel += tr(" (in use)");
+ }
+ auto item = new QTreeWidgetItem(view);
+ item->setText(0, profileLabel);
+ item->setIcon(0, SkinUtils::getFaceFromCache(profile.id));
+ item->setData(0, MojangAccountList::PointerRole, QVariant::fromValue(account));
+ items.append(item);
+ }
+ }
+ view->addTopLevelItems(items);
+
+ // Set the message label.
+ ui->msgLabel->setVisible(!message.isEmpty());
+ ui->msgLabel->setText(message);
+
+ // Flags...
+ ui->globalDefaultCheck->setVisible(flags & GlobalDefaultCheckbox);
+ ui->instDefaultCheck->setVisible(flags & InstanceDefaultCheckbox);
+ qDebug() << flags;
+
+ // Select the first entry in the list.
+ ui->listView->setCurrentIndex(ui->listView->model()->index(0, 0));
+
+ connect(ui->listView, SIGNAL(doubleClicked(QModelIndex)), SLOT(on_buttonBox_accepted()));
}
ProfileSelectDialog::~ProfileSelectDialog()
{
- delete ui;
+ delete ui;
}
MojangAccountPtr ProfileSelectDialog::selectedAccount() const
{
- return m_selected;
+ return m_selected;
}
bool ProfileSelectDialog::useAsGlobalDefault() const
{
- return ui->globalDefaultCheck->isChecked();
+ return ui->globalDefaultCheck->isChecked();
}
bool ProfileSelectDialog::useAsInstDefaullt() const
{
- return ui->instDefaultCheck->isChecked();
+ return ui->instDefaultCheck->isChecked();
}
void ProfileSelectDialog::on_buttonBox_accepted()
{
- QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
- if (selection.size() > 0)
- {
- QModelIndex selected = selection.first();
- m_selected = selected.data(MojangAccountList::PointerRole).value<MojangAccountPtr>();
- }
- close();
+ QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
+ if (selection.size() > 0)
+ {
+ QModelIndex selected = selection.first();
+ m_selected = selected.data(MojangAccountList::PointerRole).value<MojangAccountPtr>();
+ }
+ close();
}
void ProfileSelectDialog::on_buttonBox_rejected()
{
- close();
+ close();
}
diff --git a/application/dialogs/ProfileSelectDialog.h b/application/dialogs/ProfileSelectDialog.h
index b1268743..40fa0843 100644
--- a/application/dialogs/ProfileSelectDialog.h
+++ b/application/dialogs/ProfileSelectDialog.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,63 +28,63 @@ class ProfileSelectDialog;
class ProfileSelectDialog : public QDialog
{
- Q_OBJECT
+ Q_OBJECT
public:
- enum Flags
- {
- NoFlags = 0,
-
- /*!
- * Shows a check box on the dialog that allows the user to specify that the account
- * they've selected should be used as the global default for all instances.
- */
- GlobalDefaultCheckbox,
-
- /*!
- * Shows a check box on the dialog that allows the user to specify that the account
- * they've selected should be used as the default for the instance they are currently launching.
- * This is not currently implemented.
- */
- InstanceDefaultCheckbox,
- };
-
- /*!
- * Constructs a new account select dialog with the given parent and message.
- * The message will be shown at the top of the dialog. It is an empty string by default.
- */
- explicit ProfileSelectDialog(const QString& message="", int flags=0, QWidget *parent = 0);
- ~ProfileSelectDialog();
-
- /*!
- * Gets a pointer to the account that the user selected.
- * This is null if the user clicked cancel or hasn't clicked OK yet.
- */
- MojangAccountPtr selectedAccount() const;
-
- /*!
- * Returns true if the user checked the "use as global default" checkbox.
- * If the checkbox wasn't shown, this function returns false.
- */
- bool useAsGlobalDefault() const;
-
- /*!
- * Returns true if the user checked the "use as instance default" checkbox.
- * If the checkbox wasn't shown, this function returns false.
- */
- bool useAsInstDefaullt() const;
+ enum Flags
+ {
+ NoFlags = 0,
+
+ /*!
+ * Shows a check box on the dialog that allows the user to specify that the account
+ * they've selected should be used as the global default for all instances.
+ */
+ GlobalDefaultCheckbox,
+
+ /*!
+ * Shows a check box on the dialog that allows the user to specify that the account
+ * they've selected should be used as the default for the instance they are currently launching.
+ * This is not currently implemented.
+ */
+ InstanceDefaultCheckbox,
+ };
+
+ /*!
+ * Constructs a new account select dialog with the given parent and message.
+ * The message will be shown at the top of the dialog. It is an empty string by default.
+ */
+ explicit ProfileSelectDialog(const QString& message="", int flags=0, QWidget *parent = 0);
+ ~ProfileSelectDialog();
+
+ /*!
+ * Gets a pointer to the account that the user selected.
+ * This is null if the user clicked cancel or hasn't clicked OK yet.
+ */
+ MojangAccountPtr selectedAccount() const;
+
+ /*!
+ * Returns true if the user checked the "use as global default" checkbox.
+ * If the checkbox wasn't shown, this function returns false.
+ */
+ bool useAsGlobalDefault() const;
+
+ /*!
+ * Returns true if the user checked the "use as instance default" checkbox.
+ * If the checkbox wasn't shown, this function returns false.
+ */
+ bool useAsInstDefaullt() const;
public
slots:
- void on_buttonBox_accepted();
+ void on_buttonBox_accepted();
- void on_buttonBox_rejected();
+ void on_buttonBox_rejected();
protected:
- std::shared_ptr<MojangAccountList> m_accounts;
+ std::shared_ptr<MojangAccountList> m_accounts;
- //! The account that was selected when the user clicked OK.
- MojangAccountPtr m_selected;
+ //! The account that was selected when the user clicked OK.
+ MojangAccountPtr m_selected;
private:
- Ui::ProfileSelectDialog *ui;
+ Ui::ProfileSelectDialog *ui;
};
diff --git a/application/dialogs/ProgressDialog.cpp b/application/dialogs/ProgressDialog.cpp
index 056a0ffb..0e186fc2 100644
--- a/application/dialogs/ProgressDialog.cpp
+++ b/application/dialogs/ProgressDialog.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,117 +23,117 @@
ProgressDialog::ProgressDialog(QWidget *parent) : QDialog(parent), ui(new Ui::ProgressDialog)
{
- ui->setupUi(this);
- this->setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
- setSkipButton(false);
- changeProgress(0, 100);
+ ui->setupUi(this);
+ this->setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ setSkipButton(false);
+ changeProgress(0, 100);
}
void ProgressDialog::setSkipButton(bool present, QString label)
{
- ui->skipButton->setAutoDefault(false);
- ui->skipButton->setDefault(false);
- ui->skipButton->setFocusPolicy(Qt::ClickFocus);
- ui->skipButton->setEnabled(present);
- ui->skipButton->setVisible(present);
- ui->skipButton->setText(label);
- updateSize();
+ ui->skipButton->setAutoDefault(false);
+ ui->skipButton->setDefault(false);
+ ui->skipButton->setFocusPolicy(Qt::ClickFocus);
+ ui->skipButton->setEnabled(present);
+ ui->skipButton->setVisible(present);
+ ui->skipButton->setText(label);
+ updateSize();
}
void ProgressDialog::on_skipButton_clicked(bool checked)
{
- Q_UNUSED(checked);
- task->abort();
+ Q_UNUSED(checked);
+ task->abort();
}
ProgressDialog::~ProgressDialog()
{
- delete ui;
+ delete ui;
}
void ProgressDialog::updateSize()
{
QSize qSize = QSize(480, minimumSizeHint().height());
- resize(qSize);
+ resize(qSize);
setFixedSize(qSize);
}
int ProgressDialog::execWithTask(Task *task)
{
- this->task = task;
- QDialog::DialogCode result;
-
- if(!task)
- {
- qDebug() << "Programmer error: progress dialog created with null task.";
- return Accepted;
- }
-
- if(handleImmediateResult(result))
- {
- return result;
- }
-
- // Connect signals.
- connect(task, SIGNAL(started()), SLOT(onTaskStarted()));
- connect(task, SIGNAL(failed(QString)), SLOT(onTaskFailed(QString)));
- connect(task, SIGNAL(succeeded()), SLOT(onTaskSucceeded()));
- connect(task, SIGNAL(status(QString)), SLOT(changeStatus(const QString &)));
- connect(task, SIGNAL(progress(qint64, qint64)), SLOT(changeProgress(qint64, qint64)));
-
- // if this didn't connect to an already running task, invoke start
- if(!task->isRunning())
- {
- task->start();
- }
- if(task->isRunning())
- {
- changeProgress(task->getProgress(), task->getTotalProgress());
- changeStatus(task->getStatus());
- return QDialog::exec();
- }
- else if(handleImmediateResult(result))
- {
- return result;
- }
- else
- {
- return QDialog::Rejected;
- }
+ this->task = task;
+ QDialog::DialogCode result;
+
+ if(!task)
+ {
+ qDebug() << "Programmer error: progress dialog created with null task.";
+ return Accepted;
+ }
+
+ if(handleImmediateResult(result))
+ {
+ return result;
+ }
+
+ // Connect signals.
+ connect(task, SIGNAL(started()), SLOT(onTaskStarted()));
+ connect(task, SIGNAL(failed(QString)), SLOT(onTaskFailed(QString)));
+ connect(task, SIGNAL(succeeded()), SLOT(onTaskSucceeded()));
+ connect(task, SIGNAL(status(QString)), SLOT(changeStatus(const QString &)));
+ connect(task, SIGNAL(progress(qint64, qint64)), SLOT(changeProgress(qint64, qint64)));
+
+ // if this didn't connect to an already running task, invoke start
+ if(!task->isRunning())
+ {
+ task->start();
+ }
+ if(task->isRunning())
+ {
+ changeProgress(task->getProgress(), task->getTotalProgress());
+ changeStatus(task->getStatus());
+ return QDialog::exec();
+ }
+ else if(handleImmediateResult(result))
+ {
+ return result;
+ }
+ else
+ {
+ return QDialog::Rejected;
+ }
}
// TODO: only provide the unique_ptr overloads
int ProgressDialog::execWithTask(std::unique_ptr<Task> &&task)
{
- connect(this, &ProgressDialog::destroyed, task.get(), &Task::deleteLater);
- return execWithTask(task.release());
+ connect(this, &ProgressDialog::destroyed, task.get(), &Task::deleteLater);
+ return execWithTask(task.release());
}
int ProgressDialog::execWithTask(std::unique_ptr<Task> &task)
{
- connect(this, &ProgressDialog::destroyed, task.get(), &Task::deleteLater);
- return execWithTask(task.release());
+ connect(this, &ProgressDialog::destroyed, task.get(), &Task::deleteLater);
+ return execWithTask(task.release());
}
bool ProgressDialog::handleImmediateResult(QDialog::DialogCode &result)
{
- if(task->isFinished())
- {
- if(task->wasSuccessful())
- {
- result = QDialog::Accepted;
- }
- else
- {
- result = QDialog::Rejected;
- }
- return true;
- }
- return false;
+ if(task->isFinished())
+ {
+ if(task->wasSuccessful())
+ {
+ result = QDialog::Accepted;
+ }
+ else
+ {
+ result = QDialog::Rejected;
+ }
+ return true;
+ }
+ return false;
}
Task *ProgressDialog::getTask()
{
- return task;
+ return task;
}
void ProgressDialog::onTaskStarted()
@@ -142,55 +142,55 @@ void ProgressDialog::onTaskStarted()
void ProgressDialog::onTaskFailed(QString failure)
{
- reject();
+ reject();
}
void ProgressDialog::onTaskSucceeded()
{
- accept();
+ accept();
}
void ProgressDialog::changeStatus(const QString &status)
{
- ui->statusLabel->setText(status);
- updateSize();
+ ui->statusLabel->setText(status);
+ updateSize();
}
void ProgressDialog::changeProgress(qint64 current, qint64 total)
{
- ui->taskProgressBar->setMaximum(total);
- ui->taskProgressBar->setValue(current);
+ ui->taskProgressBar->setMaximum(total);
+ ui->taskProgressBar->setValue(current);
}
void ProgressDialog::keyPressEvent(QKeyEvent *e)
{
- if(ui->skipButton->isVisible())
- {
- if (e->key() == Qt::Key_Escape)
- {
- on_skipButton_clicked(true);
- return;
- }
- else if(e->key() == Qt::Key_Tab)
- {
- ui->skipButton->setFocusPolicy(Qt::StrongFocus);
- ui->skipButton->setFocus();
- ui->skipButton->setAutoDefault(true);
- ui->skipButton->setDefault(true);
- return;
- }
- }
- QDialog::keyPressEvent(e);
+ if(ui->skipButton->isVisible())
+ {
+ if (e->key() == Qt::Key_Escape)
+ {
+ on_skipButton_clicked(true);
+ return;
+ }
+ else if(e->key() == Qt::Key_Tab)
+ {
+ ui->skipButton->setFocusPolicy(Qt::StrongFocus);
+ ui->skipButton->setFocus();
+ ui->skipButton->setAutoDefault(true);
+ ui->skipButton->setDefault(true);
+ return;
+ }
+ }
+ QDialog::keyPressEvent(e);
}
void ProgressDialog::closeEvent(QCloseEvent *e)
{
- if (task && task->isRunning())
- {
- e->ignore();
- }
- else
- {
- QDialog::closeEvent(e);
- }
+ if (task && task->isRunning())
+ {
+ e->ignore();
+ }
+ else
+ {
+ QDialog::closeEvent(e);
+ }
}
diff --git a/application/dialogs/ProgressDialog.h b/application/dialogs/ProgressDialog.h
index f27b71e1..a3779e3f 100644
--- a/application/dialogs/ProgressDialog.h
+++ b/application/dialogs/ProgressDialog.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,45 +27,45 @@ class ProgressDialog;
class ProgressDialog : public QDialog
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit ProgressDialog(QWidget *parent = 0);
- ~ProgressDialog();
+ explicit ProgressDialog(QWidget *parent = 0);
+ ~ProgressDialog();
- void updateSize();
+ void updateSize();
- int execWithTask(Task *task);
- int execWithTask(std::unique_ptr<Task> &&task);
- int execWithTask(std::unique_ptr<Task> &task);
+ int execWithTask(Task *task);
+ int execWithTask(std::unique_ptr<Task> &&task);
+ int execWithTask(std::unique_ptr<Task> &task);
- void setSkipButton(bool present, QString label = QString());
+ void setSkipButton(bool present, QString label = QString());
- Task *getTask();
+ Task *getTask();
public
slots:
- void onTaskStarted();
- void onTaskFailed(QString failure);
- void onTaskSucceeded();
+ void onTaskStarted();
+ void onTaskFailed(QString failure);
+ void onTaskSucceeded();
- void changeStatus(const QString &status);
- void changeProgress(qint64 current, qint64 total);
+ void changeStatus(const QString &status);
+ void changeProgress(qint64 current, qint64 total);
private
slots:
- void on_skipButton_clicked(bool checked);
+ void on_skipButton_clicked(bool checked);
protected:
- virtual void keyPressEvent(QKeyEvent *e);
- virtual void closeEvent(QCloseEvent *e);
+ virtual void keyPressEvent(QKeyEvent *e);
+ virtual void closeEvent(QCloseEvent *e);
private:
- bool handleImmediateResult(QDialog::DialogCode &result);
+ bool handleImmediateResult(QDialog::DialogCode &result);
private:
- Ui::ProgressDialog *ui;
+ Ui::ProgressDialog *ui;
- Task *task;
+ Task *task;
};
diff --git a/application/dialogs/SkinUploadDialog.cpp b/application/dialogs/SkinUploadDialog.cpp
index 93414c6e..7d2ff829 100644
--- a/application/dialogs/SkinUploadDialog.cpp
+++ b/application/dialogs/SkinUploadDialog.cpp
@@ -9,106 +9,106 @@
void SkinUploadDialog::on_buttonBox_rejected()
{
- close();
+ close();
}
void SkinUploadDialog::on_buttonBox_accepted()
{
- AuthSessionPtr session = std::make_shared<AuthSession>();
- auto login = m_acct->login(session);
- ProgressDialog prog(this);
- if (prog.execWithTask((Task*)login.get()) != QDialog::Accepted)
- {
- //FIXME: recover with password prompt
- CustomMessageBox::selectable(this, tr("Skin Upload"), tr("Failed to login!"), QMessageBox::Warning)->exec();
- close();
- return;
- }
- QString fileName;
- QString input = ui->skinPathTextBox->text();
- QRegExp urlPrefixMatcher("^([a-z]+)://.+$");
- bool isLocalFile = false;
- // it has an URL prefix -> it is an URL
- if(urlPrefixMatcher.exactMatch(input))
- {
- QUrl fileURL = input;
- if(fileURL.isValid())
- {
- // local?
- if(fileURL.isLocalFile())
- {
- isLocalFile = true;
- fileName = fileURL.toLocalFile();
- }
- else
- {
- CustomMessageBox::selectable(
- this,
- tr("Skin Upload"),
- tr("Using remote URLs for setting skins is not implemented yet."),
- QMessageBox::Warning
- )->exec();
- close();
- return;
- }
- }
- else
- {
- CustomMessageBox::selectable(
- this,
- tr("Skin Upload"),
- tr("You cannot use an invalid URL for uploading skins."),
- QMessageBox::Warning
- )->exec();
- close();
- return;
- }
- }
- else
- {
- // just assume it's a path then
- isLocalFile = true;
- fileName = ui->skinPathTextBox->text();
- }
- if (isLocalFile && !QFile::exists(fileName))
- {
- CustomMessageBox::selectable(this, tr("Skin Upload"), tr("Skin file does not exist!"), QMessageBox::Warning)->exec();
- close();
- return;
- }
- SkinUpload::Model model = SkinUpload::STEVE;
- if (ui->steveBtn->isChecked())
- {
- model = SkinUpload::STEVE;
- }
- else if (ui->alexBtn->isChecked())
- {
- model = SkinUpload::ALEX;
- }
- SkinUploadPtr upload = std::make_shared<SkinUpload>(this, session, FS::read(fileName), model);
- if (prog.execWithTask((Task*)upload.get()) != QDialog::Accepted)
- {
- CustomMessageBox::selectable(this, tr("Skin Upload"), tr("Failed to upload skin!"), QMessageBox::Warning)->exec();
- close();
- return;
- }
- CustomMessageBox::selectable(this, tr("Skin Upload"), tr("Success"), QMessageBox::Information)->exec();
- close();
+ AuthSessionPtr session = std::make_shared<AuthSession>();
+ auto login = m_acct->login(session);
+ ProgressDialog prog(this);
+ if (prog.execWithTask((Task*)login.get()) != QDialog::Accepted)
+ {
+ //FIXME: recover with password prompt
+ CustomMessageBox::selectable(this, tr("Skin Upload"), tr("Failed to login!"), QMessageBox::Warning)->exec();
+ close();
+ return;
+ }
+ QString fileName;
+ QString input = ui->skinPathTextBox->text();
+ QRegExp urlPrefixMatcher("^([a-z]+)://.+$");
+ bool isLocalFile = false;
+ // it has an URL prefix -> it is an URL
+ if(urlPrefixMatcher.exactMatch(input))
+ {
+ QUrl fileURL = input;
+ if(fileURL.isValid())
+ {
+ // local?
+ if(fileURL.isLocalFile())
+ {
+ isLocalFile = true;
+ fileName = fileURL.toLocalFile();
+ }
+ else
+ {
+ CustomMessageBox::selectable(
+ this,
+ tr("Skin Upload"),
+ tr("Using remote URLs for setting skins is not implemented yet."),
+ QMessageBox::Warning
+ )->exec();
+ close();
+ return;
+ }
+ }
+ else
+ {
+ CustomMessageBox::selectable(
+ this,
+ tr("Skin Upload"),
+ tr("You cannot use an invalid URL for uploading skins."),
+ QMessageBox::Warning
+ )->exec();
+ close();
+ return;
+ }
+ }
+ else
+ {
+ // just assume it's a path then
+ isLocalFile = true;
+ fileName = ui->skinPathTextBox->text();
+ }
+ if (isLocalFile && !QFile::exists(fileName))
+ {
+ CustomMessageBox::selectable(this, tr("Skin Upload"), tr("Skin file does not exist!"), QMessageBox::Warning)->exec();
+ close();
+ return;
+ }
+ SkinUpload::Model model = SkinUpload::STEVE;
+ if (ui->steveBtn->isChecked())
+ {
+ model = SkinUpload::STEVE;
+ }
+ else if (ui->alexBtn->isChecked())
+ {
+ model = SkinUpload::ALEX;
+ }
+ SkinUploadPtr upload = std::make_shared<SkinUpload>(this, session, FS::read(fileName), model);
+ if (prog.execWithTask((Task*)upload.get()) != QDialog::Accepted)
+ {
+ CustomMessageBox::selectable(this, tr("Skin Upload"), tr("Failed to upload skin!"), QMessageBox::Warning)->exec();
+ close();
+ return;
+ }
+ CustomMessageBox::selectable(this, tr("Skin Upload"), tr("Success"), QMessageBox::Information)->exec();
+ close();
}
void SkinUploadDialog::on_skinBrowseBtn_clicked()
{
- QString raw_path = QFileDialog::getOpenFileName(this, tr("Select Skin Texture"), QString(), "*.png");
- if (raw_path.isEmpty() || !QFileInfo::exists(raw_path))
- {
- return;
- }
- QString cooked_path = FS::NormalizePath(raw_path);
- ui->skinPathTextBox->setText(cooked_path);
+ QString raw_path = QFileDialog::getOpenFileName(this, tr("Select Skin Texture"), QString(), "*.png");
+ if (raw_path.isEmpty() || !QFileInfo::exists(raw_path))
+ {
+ return;
+ }
+ QString cooked_path = FS::NormalizePath(raw_path);
+ ui->skinPathTextBox->setText(cooked_path);
}
SkinUploadDialog::SkinUploadDialog(MojangAccountPtr acct, QWidget *parent)
- :QDialog(parent), m_acct(acct), ui(new Ui::SkinUploadDialog)
+ :QDialog(parent), m_acct(acct), ui(new Ui::SkinUploadDialog)
{
- ui->setupUi(this);
+ ui->setupUi(this);
}
diff --git a/application/dialogs/SkinUploadDialog.h b/application/dialogs/SkinUploadDialog.h
index 514eabc8..deb44eac 100644
--- a/application/dialogs/SkinUploadDialog.h
+++ b/application/dialogs/SkinUploadDialog.h
@@ -5,25 +5,25 @@
namespace Ui
{
- class SkinUploadDialog;
+ class SkinUploadDialog;
}
class SkinUploadDialog : public QDialog {
- Q_OBJECT
+ Q_OBJECT
public:
- explicit SkinUploadDialog(MojangAccountPtr acct, QWidget *parent = 0);
- virtual ~SkinUploadDialog() {};
+ explicit SkinUploadDialog(MojangAccountPtr acct, QWidget *parent = 0);
+ virtual ~SkinUploadDialog() {};
public slots:
- void on_buttonBox_accepted();
+ void on_buttonBox_accepted();
- void on_buttonBox_rejected();
+ void on_buttonBox_rejected();
- void on_skinBrowseBtn_clicked();
+ void on_skinBrowseBtn_clicked();
protected:
- MojangAccountPtr m_acct;
+ MojangAccountPtr m_acct;
private:
- Ui::SkinUploadDialog *ui;
+ Ui::SkinUploadDialog *ui;
};
diff --git a/application/dialogs/UpdateDialog.cpp b/application/dialogs/UpdateDialog.cpp
index 30c7173d..242a5b70 100644
--- a/application/dialogs/UpdateDialog.cpp
+++ b/application/dialogs/UpdateDialog.cpp
@@ -10,20 +10,20 @@
UpdateDialog::UpdateDialog(bool hasUpdate, QWidget *parent) : QDialog(parent), ui(new Ui::UpdateDialog)
{
- 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->setHidden(true);
- ui->btnUpdateLater->setText(tr("Close"));
- }
- loadChangelog();
- restoreGeometry(QByteArray::fromBase64(MMC->settings()->get("UpdateDialogGeometry").toByteArray()));
+ 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->setHidden(true);
+ ui->btnUpdateLater->setText(tr("Close"));
+ }
+ loadChangelog();
+ restoreGeometry(QByteArray::fromBase64(MMC->settings()->get("UpdateDialogGeometry").toByteArray()));
}
UpdateDialog::~UpdateDialog()
@@ -32,150 +32,150 @@ UpdateDialog::~UpdateDialog()
void UpdateDialog::loadChangelog()
{
- auto channel = MMC->settings()->get("UpdateChannel").toString();
- dljob.reset(new NetJob("Changelog"));
- QString url;
- if(channel == "stable")
- {
- url = QString("https://raw.githubusercontent.com/MultiMC/MultiMC5/%1/changelog.md").arg(channel);
- m_changelogType = CHANGELOG_MARKDOWN;
- }
- else
- {
- url = QString("https://api.github.com/repos/MultiMC/MultiMC5/compare/%1...%2").arg(BuildConfig.GIT_COMMIT, channel);
- m_changelogType = CHANGELOG_COMMITS;
- }
- dljob->addNetAction(Net::Download::makeByteArray(QUrl(url), &changelogData));
- connect(dljob.get(), &NetJob::succeeded, this, &UpdateDialog::changelogLoaded);
- connect(dljob.get(), &NetJob::failed, this, &UpdateDialog::changelogFailed);
- dljob->start();
+ auto channel = MMC->settings()->get("UpdateChannel").toString();
+ dljob.reset(new NetJob("Changelog"));
+ QString url;
+ if(channel == "stable")
+ {
+ url = QString("https://raw.githubusercontent.com/MultiMC/MultiMC5/%1/changelog.md").arg(channel);
+ m_changelogType = CHANGELOG_MARKDOWN;
+ }
+ else
+ {
+ url = QString("https://api.github.com/repos/MultiMC/MultiMC5/compare/%1...%2").arg(BuildConfig.GIT_COMMIT, channel);
+ m_changelogType = CHANGELOG_COMMITS;
+ }
+ dljob->addNetAction(Net::Download::makeByteArray(QUrl(url), &changelogData));
+ connect(dljob.get(), &NetJob::succeeded, this, &UpdateDialog::changelogLoaded);
+ connect(dljob.get(), &NetJob::failed, this, &UpdateDialog::changelogFailed);
+ dljob->start();
}
QString reprocessMarkdown(QByteArray markdown)
{
- HoeDown hoedown;
- QString output = hoedown.process(markdown);
+ HoeDown hoedown;
+ QString output = hoedown.process(markdown);
- // HACK: easier than customizing hoedown
- output.replace(QRegExp("GH-([0-9]+)"), "<a href=\"https://github.com/MultiMC/MultiMC5/issues/\\1\">GH-\\1</a>");
- qDebug() << output;
- return output;
+ // HACK: easier than customizing hoedown
+ output.replace(QRegExp("GH-([0-9]+)"), "<a href=\"https://github.com/MultiMC/MultiMC5/issues/\\1\">GH-\\1</a>");
+ qDebug() << output;
+ return output;
}
QString reprocessCommits(QByteArray json)
{
- auto channel = MMC->settings()->get("UpdateChannel").toString();
- try
- {
- QString result;
- auto document = Json::requireDocument(json);
- auto rootobject = Json::requireObject(document);
- auto status = Json::requireString(rootobject, "status");
- auto diff_url = Json::requireString(rootobject, "html_url");
+ auto channel = MMC->settings()->get("UpdateChannel").toString();
+ try
+ {
+ QString result;
+ auto document = Json::requireDocument(json);
+ auto rootobject = Json::requireObject(document);
+ auto status = Json::requireString(rootobject, "status");
+ auto diff_url = Json::requireString(rootobject, "html_url");
- auto print_commits = [&]()
- {
- result += "<table cellspacing=0 cellpadding=2 style='border-width: 1px; border-style: solid'>";
- auto commitarray = Json::requireArray(rootobject, "commits");
- for(int i = commitarray.size() - 1; i >= 0; i--)
- {
- const auto & commitval = commitarray[i];
- auto commitobj = Json::requireObject(commitval);
- auto parents_info = Json::ensureArray(commitobj, "parents");
- // NOTE: this ignores merge commits, because they have more than one parent
- if(parents_info.size() > 1)
- {
- continue;
- }
- auto commit_url = Json::requireString(commitobj, "html_url");
- auto commit_info = Json::requireObject(commitobj, "commit");
- auto commit_message = Json::requireString(commit_info, "message");
- auto lines = commit_message.split('\n');
- QRegularExpression regexp("(?<prefix>(GH-(?<issuenr>[0-9]+))|(NOISSUE)|(SCRATCH))? *(?<rest>.*) *");
- auto match = regexp.match(lines.takeFirst(), 0, QRegularExpression::NormalMatch);
- auto issuenr = match.captured("issuenr");
- auto prefix = match.captured("prefix");
- auto rest = match.captured("rest");
- result += "<tr><td>";
- if(issuenr.length())
- {
- result += QString("<a href=\"https://github.com/MultiMC/MultiMC5/issues/%1\">GH-%2</a>").arg(issuenr, issuenr);
- }
- else if(prefix.length())
- {
- result += QString("<a href=\"%1\">%2</a>").arg(commit_url, prefix);
- }
- else
- {
- result += QString("<a href=\"%1\">NOISSUE</a>").arg(commit_url);
- }
- result += "</td>";
- lines.prepend(rest);
- result += "<td><p>" + lines.join("<br />") + "</p></td></tr>";
- }
- result += "</table>";
- };
+ auto print_commits = [&]()
+ {
+ result += "<table cellspacing=0 cellpadding=2 style='border-width: 1px; border-style: solid'>";
+ auto commitarray = Json::requireArray(rootobject, "commits");
+ for(int i = commitarray.size() - 1; i >= 0; i--)
+ {
+ const auto & commitval = commitarray[i];
+ auto commitobj = Json::requireObject(commitval);
+ auto parents_info = Json::ensureArray(commitobj, "parents");
+ // NOTE: this ignores merge commits, because they have more than one parent
+ if(parents_info.size() > 1)
+ {
+ continue;
+ }
+ auto commit_url = Json::requireString(commitobj, "html_url");
+ auto commit_info = Json::requireObject(commitobj, "commit");
+ auto commit_message = Json::requireString(commit_info, "message");
+ auto lines = commit_message.split('\n');
+ QRegularExpression regexp("(?<prefix>(GH-(?<issuenr>[0-9]+))|(NOISSUE)|(SCRATCH))? *(?<rest>.*) *");
+ auto match = regexp.match(lines.takeFirst(), 0, QRegularExpression::NormalMatch);
+ auto issuenr = match.captured("issuenr");
+ auto prefix = match.captured("prefix");
+ auto rest = match.captured("rest");
+ result += "<tr><td>";
+ if(issuenr.length())
+ {
+ result += QString("<a href=\"https://github.com/MultiMC/MultiMC5/issues/%1\">GH-%2</a>").arg(issuenr, issuenr);
+ }
+ else if(prefix.length())
+ {
+ result += QString("<a href=\"%1\">%2</a>").arg(commit_url, prefix);
+ }
+ else
+ {
+ result += QString("<a href=\"%1\">NOISSUE</a>").arg(commit_url);
+ }
+ result += "</td>";
+ lines.prepend(rest);
+ result += "<td><p>" + lines.join("<br />") + "</p></td></tr>";
+ }
+ result += "</table>";
+ };
- if(status == "identical")
- {
- return QObject::tr("<p>There are no code changes between your current version and latest %1.</p>").arg(channel);
- }
- else if(status == "ahead")
- {
- result += QObject::tr("<p>Following commits were added since last update:</p>");
- print_commits();
- }
- else if(status == "diverged")
- {
- auto commit_ahead = Json::requireInteger(rootobject, "ahead_by");
- auto commit_behind = Json::requireInteger(rootobject, "behind_by");
- result += QObject::tr("<p>The update removes %1 commits and adds the following %2:</p>").arg(commit_behind).arg(commit_ahead);
- print_commits();
- }
- result += QObject::tr("<p>You can <a href=\"%1\">look at the changes on github</a>.</p>").arg(diff_url);
- return result;
- }
- catch (JSONValidationError & e)
- {
- qWarning() << "Got an unparseable commit log from github:" << e.what();
- qDebug() << json;
- }
- return QString();
+ if(status == "identical")
+ {
+ return QObject::tr("<p>There are no code changes between your current version and latest %1.</p>").arg(channel);
+ }
+ else if(status == "ahead")
+ {
+ result += QObject::tr("<p>Following commits were added since last update:</p>");
+ print_commits();
+ }
+ else if(status == "diverged")
+ {
+ auto commit_ahead = Json::requireInteger(rootobject, "ahead_by");
+ auto commit_behind = Json::requireInteger(rootobject, "behind_by");
+ result += QObject::tr("<p>The update removes %1 commits and adds the following %2:</p>").arg(commit_behind).arg(commit_ahead);
+ print_commits();
+ }
+ result += QObject::tr("<p>You can <a href=\"%1\">look at the changes on github</a>.</p>").arg(diff_url);
+ return result;
+ }
+ catch (const JSONValidationError &e)
+ {
+ qWarning() << "Got an unparseable commit log from github:" << e.what();
+ qDebug() << json;
+ }
+ return QString();
}
void UpdateDialog::changelogLoaded()
{
- QString result;
- switch(m_changelogType)
- {
- case CHANGELOG_COMMITS:
- result = reprocessCommits(changelogData);
- break;
- case CHANGELOG_MARKDOWN:
- result = reprocessMarkdown(changelogData);
- break;
- }
- changelogData.clear();
- ui->changelogBrowser->setHtml(result);
+ QString result;
+ switch(m_changelogType)
+ {
+ case CHANGELOG_COMMITS:
+ result = reprocessCommits(changelogData);
+ break;
+ case CHANGELOG_MARKDOWN:
+ result = reprocessMarkdown(changelogData);
+ break;
+ }
+ changelogData.clear();
+ ui->changelogBrowser->setHtml(result);
}
void UpdateDialog::changelogFailed(QString reason)
{
- ui->changelogBrowser->setHtml(tr("<p align=\"center\" <span style=\"font-size:22pt;\">Failed to fetch changelog... Error: %1</span></p>").arg(reason));
+ ui->changelogBrowser->setHtml(tr("<p align=\"center\" <span style=\"font-size:22pt;\">Failed to fetch changelog... Error: %1</span></p>").arg(reason));
}
void UpdateDialog::on_btnUpdateLater_clicked()
{
- reject();
+ reject();
}
void UpdateDialog::on_btnUpdateNow_clicked()
{
- done(UPDATE_NOW);
+ done(UPDATE_NOW);
}
void UpdateDialog::closeEvent(QCloseEvent* evt)
{
- MMC->settings()->set("UpdateDialogGeometry", saveGeometry().toBase64());
- QDialog::closeEvent(evt);
+ MMC->settings()->set("UpdateDialogGeometry", saveGeometry().toBase64());
+ QDialog::closeEvent(evt);
}
diff --git a/application/dialogs/UpdateDialog.h b/application/dialogs/UpdateDialog.h
index 78960c99..6a871b1c 100644
--- a/application/dialogs/UpdateDialog.h
+++ b/application/dialogs/UpdateDialog.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,43 +25,43 @@ class UpdateDialog;
enum UpdateAction
{
- UPDATE_LATER = QDialog::Rejected,
- UPDATE_NOW = QDialog::Accepted,
+ UPDATE_LATER = QDialog::Rejected,
+ UPDATE_NOW = QDialog::Accepted,
};
enum ChangelogType
{
- CHANGELOG_MARKDOWN,
- CHANGELOG_COMMITS
+ CHANGELOG_MARKDOWN,
+ CHANGELOG_COMMITS
};
class UpdateDialog : public QDialog
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit UpdateDialog(bool hasUpdate = true, QWidget *parent = 0);
- ~UpdateDialog();
+ explicit UpdateDialog(bool hasUpdate = true, QWidget *parent = 0);
+ ~UpdateDialog();
public slots:
- void on_btnUpdateNow_clicked();
- void on_btnUpdateLater_clicked();
+ void on_btnUpdateNow_clicked();
+ void on_btnUpdateLater_clicked();
- /// Starts loading the changelog
- void loadChangelog();
+ /// Starts loading the changelog
+ void loadChangelog();
- /// Slot for when the chengelog loads successfully.
- void changelogLoaded();
+ /// Slot for when the chengelog loads successfully.
+ void changelogLoaded();
- /// Slot for when the chengelog fails to load...
- void changelogFailed(QString reason);
+ /// Slot for when the chengelog fails to load...
+ void changelogFailed(QString reason);
protected:
- void closeEvent(QCloseEvent * ) override;
+ void closeEvent(QCloseEvent * ) override;
private:
- Ui::UpdateDialog *ui;
- QByteArray changelogData;
- NetJobPtr dljob;
- ChangelogType m_changelogType = CHANGELOG_MARKDOWN;
+ Ui::UpdateDialog *ui;
+ QByteArray changelogData;
+ NetJobPtr dljob;
+ ChangelogType m_changelogType = CHANGELOG_MARKDOWN;
};
diff --git a/application/dialogs/VersionSelectDialog.cpp b/application/dialogs/VersionSelectDialog.cpp
index c7009497..0b6ba87e 100644
--- a/application/dialogs/VersionSelectDialog.cpp
+++ b/application/dialogs/VersionSelectDialog.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,109 +33,109 @@
#include <widgets/VersionSelectWidget.h>
VersionSelectDialog::VersionSelectDialog(BaseVersionList *vlist, QString title, QWidget *parent, bool cancelable)
- : QDialog(parent)
+ : QDialog(parent)
{
- setObjectName(QStringLiteral("VersionSelectDialog"));
- resize(400, 347);
- m_verticalLayout = new QVBoxLayout(this);
- m_verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
+ setObjectName(QStringLiteral("VersionSelectDialog"));
+ resize(400, 347);
+ m_verticalLayout = new QVBoxLayout(this);
+ m_verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
- m_versionWidget = new VersionSelectWidget(parent);
- m_verticalLayout->addWidget(m_versionWidget);
+ m_versionWidget = new VersionSelectWidget(parent);
+ m_verticalLayout->addWidget(m_versionWidget);
- m_horizontalLayout = new QHBoxLayout();
- m_horizontalLayout->setObjectName(QStringLiteral("horizontalLayout"));
+ m_horizontalLayout = new QHBoxLayout();
+ m_horizontalLayout->setObjectName(QStringLiteral("horizontalLayout"));
- m_refreshButton = new QPushButton(this);
- m_refreshButton->setObjectName(QStringLiteral("refreshButton"));
- m_horizontalLayout->addWidget(m_refreshButton);
+ m_refreshButton = new QPushButton(this);
+ m_refreshButton->setObjectName(QStringLiteral("refreshButton"));
+ m_horizontalLayout->addWidget(m_refreshButton);
- m_buttonBox = new QDialogButtonBox(this);
- m_buttonBox->setObjectName(QStringLiteral("buttonBox"));
- m_buttonBox->setOrientation(Qt::Horizontal);
- m_buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
- m_horizontalLayout->addWidget(m_buttonBox);
+ m_buttonBox = new QDialogButtonBox(this);
+ m_buttonBox->setObjectName(QStringLiteral("buttonBox"));
+ m_buttonBox->setOrientation(Qt::Horizontal);
+ m_buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
+ m_horizontalLayout->addWidget(m_buttonBox);
- m_verticalLayout->addLayout(m_horizontalLayout);
+ m_verticalLayout->addLayout(m_horizontalLayout);
- retranslate();
+ retranslate();
- QObject::connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
- QObject::connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+ QObject::connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ QObject::connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
- QMetaObject::connectSlotsByName(this);
- setWindowModality(Qt::WindowModal);
- setWindowTitle(title);
+ QMetaObject::connectSlotsByName(this);
+ setWindowModality(Qt::WindowModal);
+ setWindowTitle(title);
- m_vlist = vlist;
+ m_vlist = vlist;
- if (!cancelable)
- {
- m_buttonBox->button(QDialogButtonBox::Cancel)->setEnabled(false);
- }
+ if (!cancelable)
+ {
+ m_buttonBox->button(QDialogButtonBox::Cancel)->setEnabled(false);
+ }
}
void VersionSelectDialog::retranslate()
{
- // FIXME: overrides custom title given in constructor!
- setWindowTitle(tr("Choose Version"));
- m_refreshButton->setToolTip(tr("Reloads the version list."));
- m_refreshButton->setText(tr("&Refresh"));
+ // FIXME: overrides custom title given in constructor!
+ setWindowTitle(tr("Choose Version"));
+ m_refreshButton->setToolTip(tr("Reloads the version list."));
+ m_refreshButton->setText(tr("&Refresh"));
}
void VersionSelectDialog::setCurrentVersion(const QString& version)
{
- m_currentVersion = version;
- m_versionWidget->setCurrentVersion(version);
+ m_currentVersion = version;
+ m_versionWidget->setCurrentVersion(version);
}
void VersionSelectDialog::setEmptyString(QString emptyString)
{
- m_versionWidget->setEmptyString(emptyString);
+ m_versionWidget->setEmptyString(emptyString);
}
void VersionSelectDialog::setEmptyErrorString(QString emptyErrorString)
{
- m_versionWidget->setEmptyErrorString(emptyErrorString);
+ m_versionWidget->setEmptyErrorString(emptyErrorString);
}
void VersionSelectDialog::setResizeOn(int column)
{
- resizeOnColumn = column;
+ resizeOnColumn = column;
}
int VersionSelectDialog::exec()
{
- QDialog::open();
- m_versionWidget->initialize(m_vlist);
- if(resizeOnColumn != -1)
- {
- m_versionWidget->setResizeOn(resizeOnColumn);
- }
- return QDialog::exec();
+ QDialog::open();
+ m_versionWidget->initialize(m_vlist);
+ if(resizeOnColumn != -1)
+ {
+ m_versionWidget->setResizeOn(resizeOnColumn);
+ }
+ return QDialog::exec();
}
void VersionSelectDialog::selectRecommended()
{
- m_versionWidget->selectRecommended();
+ m_versionWidget->selectRecommended();
}
BaseVersionPtr VersionSelectDialog::selectedVersion() const
{
- return m_versionWidget->selectedVersion();
+ return m_versionWidget->selectedVersion();
}
void VersionSelectDialog::on_refreshButton_clicked()
{
- m_versionWidget->loadList();
+ m_versionWidget->loadList();
}
void VersionSelectDialog::setExactFilter(BaseVersionList::ModelRoles role, QString filter)
{
- m_versionWidget->setExactFilter(role, filter);
+ m_versionWidget->setExactFilter(role, filter);
}
void VersionSelectDialog::setFuzzyFilter(BaseVersionList::ModelRoles role, QString filter)
{
- m_versionWidget->setFuzzyFilter(role, filter);
+ m_versionWidget->setFuzzyFilter(role, filter);
}
diff --git a/application/dialogs/VersionSelectDialog.h b/application/dialogs/VersionSelectDialog.h
index 127a0ee9..14bc4d76 100644
--- a/application/dialogs/VersionSelectDialog.h
+++ b/application/dialogs/VersionSelectDialog.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,43 +36,43 @@ class VersionProxyModel;
class VersionSelectDialog : public QDialog
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit VersionSelectDialog(BaseVersionList *vlist, QString title, QWidget *parent = 0, bool cancelable = true);
- virtual ~VersionSelectDialog() {};
+ explicit VersionSelectDialog(BaseVersionList *vlist, QString title, QWidget *parent = 0, bool cancelable = true);
+ virtual ~VersionSelectDialog() {};
- int exec() override;
+ int exec() override;
- BaseVersionPtr selectedVersion() const;
+ BaseVersionPtr selectedVersion() const;
- void setCurrentVersion(const QString & version);
- void setFuzzyFilter(BaseVersionList::ModelRoles role, QString filter);
- void setExactFilter(BaseVersionList::ModelRoles role, QString filter);
- void setEmptyString(QString emptyString);
- void setEmptyErrorString(QString emptyErrorString);
- void setResizeOn(int column);
+ void setCurrentVersion(const QString & version);
+ void setFuzzyFilter(BaseVersionList::ModelRoles role, QString filter);
+ void setExactFilter(BaseVersionList::ModelRoles role, QString filter);
+ void setEmptyString(QString emptyString);
+ void setEmptyErrorString(QString emptyErrorString);
+ void setResizeOn(int column);
private slots:
- void on_refreshButton_clicked();
+ void on_refreshButton_clicked();
private:
- void retranslate();
- void selectRecommended();
+ void retranslate();
+ void selectRecommended();
private:
- QString m_currentVersion;
- VersionSelectWidget *m_versionWidget = nullptr;
- QVBoxLayout *m_verticalLayout = nullptr;
- QHBoxLayout *m_horizontalLayout = nullptr;
- QPushButton *m_refreshButton = nullptr;
- QDialogButtonBox *m_buttonBox = nullptr;
+ QString m_currentVersion;
+ VersionSelectWidget *m_versionWidget = nullptr;
+ QVBoxLayout *m_verticalLayout = nullptr;
+ QHBoxLayout *m_horizontalLayout = nullptr;
+ QPushButton *m_refreshButton = nullptr;
+ QDialogButtonBox *m_buttonBox = nullptr;
- BaseVersionList *m_vlist = nullptr;
+ BaseVersionList *m_vlist = nullptr;
- VersionProxyModel *m_proxyModel = nullptr;
+ VersionProxyModel *m_proxyModel = nullptr;
- int resizeOnColumn = -1;
+ int resizeOnColumn = -1;
- Task * loadTask = nullptr;
+ Task * loadTask = nullptr;
};
diff --git a/application/groupview/AccessibleGroupView.cpp b/application/groupview/AccessibleGroupView.cpp
new file mode 100644
index 00000000..9a1bb821
--- /dev/null
+++ b/application/groupview/AccessibleGroupView.cpp
@@ -0,0 +1,774 @@
+#include "GroupView.h"
+#include "AccessibleGroupView.h"
+#include "AccessibleGroupView_p.h"
+
+#include <qvariant.h>
+#include <qaccessible.h>
+#include <qheaderview.h>
+
+QAccessibleInterface *groupViewAccessibleFactory(const QString &classname, QObject *object)
+{
+ QAccessibleInterface *iface = 0;
+ if (!object || !object->isWidgetType())
+ return iface;
+
+ QWidget *widget = static_cast<QWidget*>(object);
+
+ if (classname == QLatin1String("GroupView")) {
+ iface = new AccessibleGroupView((GroupView *)widget);
+ }
+ return iface;
+}
+
+
+QAbstractItemView *AccessibleGroupView::view() const
+{
+ return qobject_cast<QAbstractItemView*>(object());
+}
+
+int AccessibleGroupView::logicalIndex(const QModelIndex &index) const
+{
+ if (!view()->model() || !index.isValid())
+ return -1;
+ return index.row() * (index.model()->columnCount()) + index.column();
+}
+
+AccessibleGroupView::AccessibleGroupView(QWidget *w)
+ : QAccessibleObject(w)
+{
+ Q_ASSERT(view());
+}
+
+bool AccessibleGroupView::isValid() const
+{
+ return view();
+}
+
+AccessibleGroupView::~AccessibleGroupView()
+{
+ for (QAccessible::Id id : childToId) {
+ QAccessible::deleteAccessibleInterface(id);
+ }
+}
+
+QAccessibleInterface *AccessibleGroupView::cellAt(int row, int column) const
+{
+ if (!view()->model()) {
+ return 0;
+ }
+
+ QModelIndex index = view()->model()->index(row, column, view()->rootIndex());
+ if (Q_UNLIKELY(!index.isValid())) {
+ qWarning() << "AccessibleGroupView::cellAt: invalid index: " << index << " for " << view();
+ return 0;
+ }
+
+ return child(logicalIndex(index));
+}
+
+QAccessibleInterface *AccessibleGroupView::caption() const
+{
+ return 0;
+}
+
+QString AccessibleGroupView::columnDescription(int column) const
+{
+ if (!view()->model())
+ return QString();
+
+ return view()->model()->headerData(column, Qt::Horizontal).toString();
+}
+
+int AccessibleGroupView::columnCount() const
+{
+ if (!view()->model())
+ return 0;
+ return 1;
+}
+
+int AccessibleGroupView::rowCount() const
+{
+ if (!view()->model())
+ return 0;
+ return view()->model()->rowCount();
+}
+
+int AccessibleGroupView::selectedCellCount() const
+{
+ if (!view()->selectionModel())
+ return 0;
+ return view()->selectionModel()->selectedIndexes().count();
+}
+
+int AccessibleGroupView::selectedColumnCount() const
+{
+ if (!view()->selectionModel())
+ return 0;
+ return view()->selectionModel()->selectedColumns().count();
+}
+
+int AccessibleGroupView::selectedRowCount() const
+{
+ if (!view()->selectionModel())
+ return 0;
+ return view()->selectionModel()->selectedRows().count();
+}
+
+QString AccessibleGroupView::rowDescription(int row) const
+{
+ if (!view()->model())
+ return QString();
+ return view()->model()->headerData(row, Qt::Vertical).toString();
+}
+
+QList<QAccessibleInterface *> AccessibleGroupView::selectedCells() const
+{
+ QList<QAccessibleInterface*> cells;
+ if (!view()->selectionModel())
+ return cells;
+ const QModelIndexList selectedIndexes = view()->selectionModel()->selectedIndexes();
+ cells.reserve(selectedIndexes.size());
+ for (const QModelIndex &index : selectedIndexes)
+ cells.append(child(logicalIndex(index)));
+ return cells;
+}
+
+QList<int> AccessibleGroupView::selectedColumns() const
+{
+ if (!view()->selectionModel()) {
+ return QList<int>();
+ }
+
+ const QModelIndexList selectedColumns = view()->selectionModel()->selectedColumns();
+
+ QList<int> columns;
+ columns.reserve(selectedColumns.size());
+ for (const QModelIndex &index : selectedColumns) {
+ columns.append(index.column());
+ }
+
+ return columns;
+}
+
+QList<int> AccessibleGroupView::selectedRows() const
+{
+ if (!view()->selectionModel()) {
+ return QList<int>();
+ }
+
+ QList<int> rows;
+
+ const QModelIndexList selectedRows = view()->selectionModel()->selectedRows();
+
+ rows.reserve(selectedRows.size());
+ for (const QModelIndex &index : selectedRows) {
+ rows.append(index.row());
+ }
+
+ return rows;
+}
+
+QAccessibleInterface *AccessibleGroupView::summary() const
+{
+ return 0;
+}
+
+bool AccessibleGroupView::isColumnSelected(int column) const
+{
+ if (!view()->selectionModel()) {
+ return false;
+ }
+
+ return view()->selectionModel()->isColumnSelected(column, QModelIndex());
+}
+
+bool AccessibleGroupView::isRowSelected(int row) const
+{
+ if (!view()->selectionModel()) {
+ return false;
+ }
+
+ return view()->selectionModel()->isRowSelected(row, QModelIndex());
+}
+
+bool AccessibleGroupView::selectRow(int row)
+{
+ if (!view()->model() || !view()->selectionModel()) {
+ return false;
+ }
+ QModelIndex index = view()->model()->index(row, 0, view()->rootIndex());
+
+ if (!index.isValid() || view()->selectionBehavior() == QAbstractItemView::SelectColumns) {
+ return false;
+ }
+
+ switch (view()->selectionMode()) {
+ case QAbstractItemView::NoSelection: {
+ return false;
+ }
+ case QAbstractItemView::SingleSelection: {
+ if (view()->selectionBehavior() != QAbstractItemView::SelectRows && columnCount() > 1 )
+ return false;
+ view()->clearSelection();
+ break;
+ }
+ case QAbstractItemView::ContiguousSelection: {
+ if ((!row || !view()->selectionModel()->isRowSelected(row - 1, view()->rootIndex())) && !view()->selectionModel()->isRowSelected(row + 1, view()->rootIndex())) {
+ view()->clearSelection();
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ view()->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ return true;
+}
+
+bool AccessibleGroupView::selectColumn(int column)
+{
+ if (!view()->model() || !view()->selectionModel()) {
+ return false;
+ }
+ QModelIndex index = view()->model()->index(0, column, view()->rootIndex());
+
+ if (!index.isValid() || view()->selectionBehavior() == QAbstractItemView::SelectRows) {
+ return false;
+ }
+
+ switch (view()->selectionMode()) {
+ case QAbstractItemView::NoSelection: {
+ return false;
+ }
+ case QAbstractItemView::SingleSelection: {
+ if (view()->selectionBehavior() != QAbstractItemView::SelectColumns && rowCount() > 1) {
+ return false;
+ }
+ // fallthrough intentional
+ }
+ case QAbstractItemView::ContiguousSelection: {
+ if ((!column || !view()->selectionModel()->isColumnSelected(column - 1, view()->rootIndex())) && !view()->selectionModel()->isColumnSelected(column + 1, view()->rootIndex())) {
+ view()->clearSelection();
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ view()->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Columns);
+ return true;
+}
+
+bool AccessibleGroupView::unselectRow(int row)
+{
+ if (!view()->model() || !view()->selectionModel()) {
+ return false;
+ }
+
+ QModelIndex index = view()->model()->index(row, 0, view()->rootIndex());
+ if (!index.isValid()) {
+ return false;
+ }
+
+ QItemSelection selection(index, index);
+ auto selectionModel = view()->selectionModel();
+
+ switch (view()->selectionMode()) {
+ case QAbstractItemView::SingleSelection:
+ // no unselect
+ if (selectedRowCount() == 1) {
+ return false;
+ }
+ break;
+ case QAbstractItemView::ContiguousSelection: {
+ // no unselect
+ if (selectedRowCount() == 1) {
+ return false;
+ }
+
+
+ if ((!row || selectionModel->isRowSelected(row - 1, view()->rootIndex())) && selectionModel->isRowSelected(row + 1, view()->rootIndex())) {
+ //If there are rows selected both up the current row and down the current rown,
+ //the ones which are down the current row will be deselected
+ selection = QItemSelection(index, view()->model()->index(rowCount() - 1, 0, view()->rootIndex()));
+ }
+ }
+ default: {
+ break;
+ }
+ }
+
+ selectionModel->select(selection, QItemSelectionModel::Deselect | QItemSelectionModel::Rows);
+ return true;
+}
+
+bool AccessibleGroupView::unselectColumn(int column)
+{
+ auto model = view()->model();
+ if (!model || !view()->selectionModel()) {
+ return false;
+ }
+
+ QModelIndex index = model->index(0, column, view()->rootIndex());
+ if (!index.isValid()) {
+ return false;
+ }
+
+ QItemSelection selection(index, index);
+
+ switch (view()->selectionMode()) {
+ case QAbstractItemView::SingleSelection: {
+ //In SingleSelection and ContiguousSelection once an item
+ //is selected, there's no way for the user to unselect all items
+ if (selectedColumnCount() == 1) {
+ return false;
+ }
+ break;
+ }
+ case QAbstractItemView::ContiguousSelection:
+ if (selectedColumnCount() == 1) {
+ return false;
+ }
+
+ if ((!column || view()->selectionModel()->isColumnSelected(column - 1, view()->rootIndex()))
+ && view()->selectionModel()->isColumnSelected(column + 1, view()->rootIndex())) {
+ //If there are columns selected both at the left of the current row and at the right
+ //of the current row, the ones which are at the right will be deselected
+ selection = QItemSelection(index, model->index(0, columnCount() - 1, view()->rootIndex()));
+ }
+ default:
+ break;
+ }
+
+ view()->selectionModel()->select(selection, QItemSelectionModel::Deselect | QItemSelectionModel::Columns);
+ return true;
+}
+
+QAccessible::Role AccessibleGroupView::role() const
+{
+ return QAccessible::List;
+}
+
+QAccessible::State AccessibleGroupView::state() const
+{
+ return QAccessible::State();
+}
+
+QAccessibleInterface *AccessibleGroupView::childAt(int x, int y) const
+{
+ QPoint viewportOffset = view()->viewport()->mapTo(view(), QPoint(0,0));
+ QPoint indexPosition = view()->mapFromGlobal(QPoint(x, y) - viewportOffset);
+ // FIXME: if indexPosition < 0 in one coordinate, return header
+
+ QModelIndex index = view()->indexAt(indexPosition);
+ if (index.isValid()) {
+ return child(logicalIndex(index));
+ }
+ return 0;
+}
+
+int AccessibleGroupView::childCount() const
+{
+ if (!view()->model()) {
+ return 0;
+ }
+ return (view()->model()->rowCount()) * (view()->model()->columnCount());
+}
+
+int AccessibleGroupView::indexOfChild(const QAccessibleInterface *iface) const
+{
+ if (!view()->model())
+ return -1;
+ QAccessibleInterface *parent = iface->parent();
+ if (parent->object() != view())
+ return -1;
+
+ Q_ASSERT(iface->role() != QAccessible::TreeItem); // should be handled by tree class
+ if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) {
+ const AccessibleGroupViewItem* cell = static_cast<const AccessibleGroupViewItem*>(iface);
+ return logicalIndex(cell->m_index);
+ } else if (iface->role() == QAccessible::Pane) {
+ return 0; // corner button
+ } else {
+ qWarning() << "AccessibleGroupView::indexOfChild has a child with unknown role..." << iface->role() << iface->text(QAccessible::Name);
+ }
+ // FIXME: we are in denial of our children. this should stop.
+ return -1;
+}
+
+QString AccessibleGroupView::text(QAccessible::Text t) const
+{
+ if (t == QAccessible::Description)
+ return view()->accessibleDescription();
+ return view()->accessibleName();
+}
+
+QRect AccessibleGroupView::rect() const
+{
+ if (!view()->isVisible())
+ return QRect();
+ QPoint pos = view()->mapToGlobal(QPoint(0, 0));
+ return QRect(pos.x(), pos.y(), view()->width(), view()->height());
+}
+
+QAccessibleInterface *AccessibleGroupView::parent() const
+{
+ if (view() && view()->parent()) {
+ if (qstrcmp("QComboBoxPrivateContainer", view()->parent()->metaObject()->className()) == 0) {
+ return QAccessible::queryAccessibleInterface(view()->parent()->parent());
+ }
+ return QAccessible::queryAccessibleInterface(view()->parent());
+ }
+ return 0;
+}
+
+QAccessibleInterface *AccessibleGroupView::child(int logicalIndex) const
+{
+ if (!view()->model())
+ return 0;
+
+ auto id = childToId.constFind(logicalIndex);
+ if (id != childToId.constEnd())
+ return QAccessible::accessibleInterface(id.value());
+
+ int columns = view()->model()->columnCount();
+
+ int row = logicalIndex / columns;
+ int column = logicalIndex % columns;
+
+ QAccessibleInterface *iface = 0;
+
+ QModelIndex index = view()->model()->index(row, column, view()->rootIndex());
+ if (Q_UNLIKELY(!index.isValid())) {
+ qWarning("AccessibleGroupView::child: Invalid index at: %d %d", row, column);
+ return 0;
+ }
+ iface = new AccessibleGroupViewItem(view(), index);
+
+ QAccessible::registerAccessibleInterface(iface);
+ childToId.insert(logicalIndex, QAccessible::uniqueId(iface));
+ return iface;
+}
+
+void *AccessibleGroupView::interface_cast(QAccessible::InterfaceType t)
+{
+ if (t == QAccessible::TableInterface)
+ return static_cast<QAccessibleTableInterface*>(this);
+ return 0;
+}
+
+void AccessibleGroupView::modelChange(QAccessibleTableModelChangeEvent *event)
+{
+ // if there is no cache yet, we don't update anything
+ if (childToId.isEmpty())
+ return;
+
+ switch (event->modelChangeType()) {
+ case QAccessibleTableModelChangeEvent::ModelReset:
+ for (QAccessible::Id id : childToId)
+ QAccessible::deleteAccessibleInterface(id);
+ childToId.clear();
+ break;
+
+ // rows are inserted: move every row after that
+ case QAccessibleTableModelChangeEvent::RowsInserted:
+ case QAccessibleTableModelChangeEvent::ColumnsInserted: {
+
+ ChildCache newCache;
+ ChildCache::ConstIterator iter = childToId.constBegin();
+
+ while (iter != childToId.constEnd()) {
+ QAccessible::Id id = iter.value();
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(id);
+ Q_ASSERT(iface);
+ if (indexOfChild(iface) >= 0) {
+ newCache.insert(indexOfChild(iface), id);
+ } else {
+ // ### This should really not happen,
+ // but it might if the view has a root index set.
+ // This needs to be fixed.
+ QAccessible::deleteAccessibleInterface(id);
+ }
+ ++iter;
+ }
+ childToId = newCache;
+ break;
+ }
+
+ case QAccessibleTableModelChangeEvent::ColumnsRemoved:
+ case QAccessibleTableModelChangeEvent::RowsRemoved: {
+ ChildCache newCache;
+ ChildCache::ConstIterator iter = childToId.constBegin();
+ while (iter != childToId.constEnd()) {
+ QAccessible::Id id = iter.value();
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(id);
+ Q_ASSERT(iface);
+ if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) {
+ Q_ASSERT(iface->tableCellInterface());
+ AccessibleGroupViewItem *cell = static_cast<AccessibleGroupViewItem*>(iface->tableCellInterface());
+ // Since it is a QPersistentModelIndex, we only need to check if it is valid
+ if (cell->m_index.isValid())
+ newCache.insert(indexOfChild(cell), id);
+ else
+ QAccessible::deleteAccessibleInterface(id);
+ }
+ ++iter;
+ }
+ childToId = newCache;
+ break;
+ }
+
+ case QAccessibleTableModelChangeEvent::DataChanged:
+ // nothing to do in this case
+ break;
+ }
+}
+
+// TABLE CELL
+
+AccessibleGroupViewItem::AccessibleGroupViewItem(QAbstractItemView *view_, const QModelIndex &index_)
+ : view(view_), m_index(index_)
+{
+ if (Q_UNLIKELY(!index_.isValid()))
+ qWarning() << "AccessibleGroupViewItem::AccessibleGroupViewItem with invalid index: " << index_;
+}
+
+void *AccessibleGroupViewItem::interface_cast(QAccessible::InterfaceType t)
+{
+ if (t == QAccessible::TableCellInterface)
+ return static_cast<QAccessibleTableCellInterface*>(this);
+ if (t == QAccessible::ActionInterface)
+ return static_cast<QAccessibleActionInterface*>(this);
+ return 0;
+}
+
+int AccessibleGroupViewItem::columnExtent() const { return 1; }
+int AccessibleGroupViewItem::rowExtent() const { return 1; }
+
+QList<QAccessibleInterface*> AccessibleGroupViewItem::rowHeaderCells() const
+{
+ return {};
+}
+
+QList<QAccessibleInterface*> AccessibleGroupViewItem::columnHeaderCells() const
+{
+ return {};
+}
+
+int AccessibleGroupViewItem::columnIndex() const
+{
+ if (!isValid()) {
+ return -1;
+ }
+
+ return m_index.column();
+}
+
+int AccessibleGroupViewItem::rowIndex() const
+{
+ if (!isValid()) {
+ return -1;
+ }
+
+ return m_index.row();
+}
+
+bool AccessibleGroupViewItem::isSelected() const
+{
+ if (!isValid()) {
+ return false;
+ }
+
+ return view->selectionModel()->isSelected(m_index);
+}
+
+QStringList AccessibleGroupViewItem::actionNames() const
+{
+ QStringList names;
+ names << toggleAction();
+ return names;
+}
+
+void AccessibleGroupViewItem::doAction(const QString& actionName)
+{
+ if (actionName == toggleAction()) {
+ if (isSelected()) {
+ unselectCell();
+ }
+ else {
+ selectCell();
+ }
+ }
+}
+
+QStringList AccessibleGroupViewItem::keyBindingsForAction(const QString &) const
+{
+ return QStringList();
+}
+
+
+void AccessibleGroupViewItem::selectCell()
+{
+ if (!isValid()) {
+ return;
+ }
+ QAbstractItemView::SelectionMode selectionMode = view->selectionMode();
+ if (selectionMode == QAbstractItemView::NoSelection) {
+ return;
+ }
+
+ Q_ASSERT(table());
+ QAccessibleTableInterface *cellTable = table()->tableInterface();
+
+ switch (view->selectionBehavior()) {
+ case QAbstractItemView::SelectItems:
+ break;
+ case QAbstractItemView::SelectColumns:
+ if (cellTable)
+ cellTable->selectColumn(m_index.column());
+ return;
+ case QAbstractItemView::SelectRows:
+ if (cellTable)
+ cellTable->selectRow(m_index.row());
+ return;
+ }
+
+ if (selectionMode == QAbstractItemView::SingleSelection) {
+ view->clearSelection();
+ }
+
+ view->selectionModel()->select(m_index, QItemSelectionModel::Select);
+}
+
+void AccessibleGroupViewItem::unselectCell()
+{
+ if (!isValid())
+ return;
+ QAbstractItemView::SelectionMode selectionMode = view->selectionMode();
+ if (selectionMode == QAbstractItemView::NoSelection)
+ return;
+
+ QAccessibleTableInterface *cellTable = table()->tableInterface();
+
+ switch (view->selectionBehavior()) {
+ case QAbstractItemView::SelectItems:
+ break;
+ case QAbstractItemView::SelectColumns:
+ if (cellTable)
+ cellTable->unselectColumn(m_index.column());
+ return;
+ case QAbstractItemView::SelectRows:
+ if (cellTable)
+ cellTable->unselectRow(m_index.row());
+ return;
+ }
+
+ //If the mode is not MultiSelection or ExtendedSelection and only
+ //one cell is selected it cannot be unselected by the user
+ if ((selectionMode != QAbstractItemView::MultiSelection) && (selectionMode != QAbstractItemView::ExtendedSelection) && (view->selectionModel()->selectedIndexes().count() <= 1))
+ return;
+
+ view->selectionModel()->select(m_index, QItemSelectionModel::Deselect);
+}
+
+QAccessibleInterface *AccessibleGroupViewItem::table() const
+{
+ return QAccessible::queryAccessibleInterface(view);
+}
+
+QAccessible::Role AccessibleGroupViewItem::role() const
+{
+ return QAccessible::ListItem;
+}
+
+QAccessible::State AccessibleGroupViewItem::state() const
+{
+ QAccessible::State st;
+ if (!isValid())
+ return st;
+
+ QRect globalRect = view->rect();
+ globalRect.translate(view->mapToGlobal(QPoint(0,0)));
+ if (!globalRect.intersects(rect()))
+ st.invisible = true;
+
+ if (view->selectionModel()->isSelected(m_index))
+ st.selected = true;
+ if (view->selectionModel()->currentIndex() == m_index)
+ st.focused = true;
+ if (m_index.model()->data(m_index, Qt::CheckStateRole).toInt() == Qt::Checked)
+ st.checked = true;
+
+ Qt::ItemFlags flags = m_index.flags();
+ if (flags & Qt::ItemIsSelectable) {
+ st.selectable = true;
+ st.focusable = true;
+ if (view->selectionMode() == QAbstractItemView::MultiSelection)
+ st.multiSelectable = true;
+ if (view->selectionMode() == QAbstractItemView::ExtendedSelection)
+ st.extSelectable = true;
+ }
+ return st;
+}
+
+
+QRect AccessibleGroupViewItem::rect() const
+{
+ QRect r;
+ if (!isValid())
+ return r;
+ r = view->visualRect(m_index);
+
+ if (!r.isNull()) {
+ r.translate(view->viewport()->mapTo(view, QPoint(0,0)));
+ r.translate(view->mapToGlobal(QPoint(0, 0)));
+ }
+ return r;
+}
+
+QString AccessibleGroupViewItem::text(QAccessible::Text t) const
+{
+ QString value;
+ if (!isValid())
+ return value;
+ QAbstractItemModel *model = view->model();
+ switch (t) {
+ case QAccessible::Name:
+ value = model->data(m_index, Qt::AccessibleTextRole).toString();
+ if (value.isEmpty())
+ value = model->data(m_index, Qt::DisplayRole).toString();
+ break;
+ case QAccessible::Description:
+ value = model->data(m_index, Qt::AccessibleDescriptionRole).toString();
+ break;
+ default:
+ break;
+ }
+ return value;
+}
+
+void AccessibleGroupViewItem::setText(QAccessible::Text /*t*/, const QString &text)
+{
+ if (!isValid() || !(m_index.flags() & Qt::ItemIsEditable))
+ return;
+ view->model()->setData(m_index, text);
+}
+
+bool AccessibleGroupViewItem::isValid() const
+{
+ return view && view->model() && m_index.isValid();
+}
+
+QAccessibleInterface *AccessibleGroupViewItem::parent() const
+{
+ return QAccessible::queryAccessibleInterface(view);
+}
+
+QAccessibleInterface *AccessibleGroupViewItem::child(int) const
+{
+ return 0;
+}
diff --git a/application/groupview/AccessibleGroupView.h b/application/groupview/AccessibleGroupView.h
new file mode 100644
index 00000000..9bfd1745
--- /dev/null
+++ b/application/groupview/AccessibleGroupView.h
@@ -0,0 +1,6 @@
+#pragma once
+
+#include <QString>
+class QAccessibleInterface;
+
+QAccessibleInterface *groupViewAccessibleFactory(const QString &classname, QObject *object);
diff --git a/application/groupview/AccessibleGroupView_p.h b/application/groupview/AccessibleGroupView_p.h
new file mode 100644
index 00000000..cdec1c0a
--- /dev/null
+++ b/application/groupview/AccessibleGroupView_p.h
@@ -0,0 +1,116 @@
+#pragma once
+
+#include "GroupView.h"
+#include "QtCore/qpointer.h"
+#include <QtGui/qaccessible.h>
+#include <QAccessibleWidget>
+#include <QAbstractItemView>
+// #include <QHeaderView>
+
+class QAccessibleTableCell;
+class QAccessibleTableHeaderCell;
+
+class AccessibleGroupView :public QAccessibleTableInterface, public QAccessibleObject
+{
+public:
+ explicit AccessibleGroupView(QWidget *w);
+ bool isValid() const override;
+
+ QAccessible::Role role() const override;
+ QAccessible::State state() const override;
+ QString text(QAccessible::Text t) const override;
+ QRect rect() const override;
+
+ QAccessibleInterface *childAt(int x, int y) const override;
+ int childCount() const override;
+ int indexOfChild(const QAccessibleInterface *) const override;
+
+ QAccessibleInterface *parent() const override;
+ QAccessibleInterface *child(int index) const override;
+
+ void *interface_cast(QAccessible::InterfaceType t) override;
+
+ // table interface
+ QAccessibleInterface *cellAt(int row, int column) const override;
+ QAccessibleInterface *caption() const override;
+ QAccessibleInterface *summary() const override;
+ QString columnDescription(int column) const override;
+ QString rowDescription(int row) const override;
+ int columnCount() const override;
+ int rowCount() const override;
+
+ // selection
+ int selectedCellCount() const override;
+ int selectedColumnCount() const override;
+ int selectedRowCount() const override;
+ QList<QAccessibleInterface*> selectedCells() const override;
+ QList<int> selectedColumns() const override;
+ QList<int> selectedRows() const override;
+ bool isColumnSelected(int column) const override;
+ bool isRowSelected(int row) const override;
+ bool selectRow(int row) override;
+ bool selectColumn(int column) override;
+ bool unselectRow(int row) override;
+ bool unselectColumn(int column) override;
+
+ QAbstractItemView *view() const;
+
+ void modelChange(QAccessibleTableModelChangeEvent *event) override;
+
+protected:
+ // maybe vector
+ typedef QHash<int, QAccessible::Id> ChildCache;
+ mutable ChildCache childToId;
+
+ virtual ~AccessibleGroupView();
+
+private:
+ inline int logicalIndex(const QModelIndex &index) const;
+};
+
+class AccessibleGroupViewItem: public QAccessibleInterface, public QAccessibleTableCellInterface, public QAccessibleActionInterface
+{
+public:
+ AccessibleGroupViewItem(QAbstractItemView *view, const QModelIndex &m_index);
+
+ void *interface_cast(QAccessible::InterfaceType t) override;
+ QObject *object() const override { return nullptr; }
+ QAccessible::Role role() const override;
+ QAccessible::State state() const override;
+ QRect rect() const override;
+ bool isValid() const override;
+
+ QAccessibleInterface *childAt(int, int) const override { return nullptr; }
+ int childCount() const override { return 0; }
+ int indexOfChild(const QAccessibleInterface *) const override { return -1; }
+
+ QString text(QAccessible::Text t) const override;
+ void setText(QAccessible::Text t, const QString &text) override;
+
+ QAccessibleInterface *parent() const override;
+ QAccessibleInterface *child(int) const override;
+
+ // cell interface
+ int columnExtent() const override;
+ QList<QAccessibleInterface*> columnHeaderCells() const override;
+ int columnIndex() const override;
+ int rowExtent() const override;
+ QList<QAccessibleInterface*> rowHeaderCells() const override;
+ int rowIndex() const override;
+ bool isSelected() const override;
+ QAccessibleInterface* table() const override;
+
+ //action interface
+ QStringList actionNames() const override;
+ void doAction(const QString &actionName) override;
+ QStringList keyBindingsForAction(const QString &actionName) const override;
+
+private:
+ QPointer<QAbstractItemView > view;
+ QPersistentModelIndex m_index;
+
+ void selectCell();
+ void unselectCell();
+
+ friend class AccessibleGroupView;
+};
diff --git a/application/groupview/GroupView.cpp b/application/groupview/GroupView.cpp
index 0d6aa49e..bc7ef6c0 100644
--- a/application/groupview/GroupView.cpp
+++ b/application/groupview/GroupView.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,943 +25,984 @@
#include <QMimeData>
#include <QCache>
#include <QScrollBar>
+#include <QAccessible>
#include "VisualGroup.h"
#include <QDebug>
template <typename T> bool listsIntersect(const QList<T> &l1, const QList<T> t2)
{
- for (auto &item : l1)
- {
- if (t2.contains(item))
- {
- return true;
- }
- }
- return false;
+ for (auto &item : l1)
+ {
+ if (t2.contains(item))
+ {
+ return true;
+ }
+ }
+ return false;
}
GroupView::GroupView(QWidget *parent)
- : QAbstractItemView(parent)
+ : QAbstractItemView(parent)
{
- setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
- setAcceptDrops(true);
- setAutoScroll(true);
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ setAcceptDrops(true);
+ setAutoScroll(true);
}
GroupView::~GroupView()
{
- qDeleteAll(m_groups);
- m_groups.clear();
+ qDeleteAll(m_groups);
+ m_groups.clear();
}
void GroupView::setModel(QAbstractItemModel *model)
{
- QAbstractItemView::setModel(model);
- connect(model, &QAbstractItemModel::modelReset, this, &GroupView::modelReset);
- connect(model, &QAbstractItemModel::rowsRemoved, this, &GroupView::rowsRemoved);
+ QAbstractItemView::setModel(model);
+ connect(model, &QAbstractItemModel::modelReset, this, &GroupView::modelReset);
+ connect(model, &QAbstractItemModel::rowsRemoved, this, &GroupView::rowsRemoved);
}
void GroupView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
- const QVector<int> &roles)
+ const QVector<int> &roles)
{
- scheduleDelayedItemsLayout();
+ scheduleDelayedItemsLayout();
}
void GroupView::rowsInserted(const QModelIndex &parent, int start, int end)
{
- scheduleDelayedItemsLayout();
+ scheduleDelayedItemsLayout();
}
void GroupView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
{
- scheduleDelayedItemsLayout();
+ scheduleDelayedItemsLayout();
}
void GroupView::modelReset()
{
- scheduleDelayedItemsLayout();
+ scheduleDelayedItemsLayout();
}
void GroupView::rowsRemoved()
{
- scheduleDelayedItemsLayout();
+ scheduleDelayedItemsLayout();
}
+void GroupView::currentChanged(const QModelIndex& current, const QModelIndex& previous)
+{
+ QAbstractItemView::currentChanged(current, previous);
+ // TODO: for accessibility support, implement+register a factory, steal QAccessibleTable from Qt and return an instance of it for GroupView.
+ if (QAccessible::isActive() && current.isValid()) {
+ QAccessibleEvent event(this, QAccessible::Focus);
+ event.setChild(current.row());
+ QAccessible::updateAccessibility(&event);
+ }
+}
+
+
class LocaleString : public QString
{
public:
- LocaleString(const char *s) : QString(s)
- {
- }
- LocaleString(const QString &s) : QString(s)
- {
- }
+ LocaleString(const char *s) : QString(s)
+ {
+ }
+ LocaleString(const QString &s) : QString(s)
+ {
+ }
};
inline bool operator<(const LocaleString &lhs, const LocaleString &rhs)
{
- return (QString::localeAwareCompare(lhs, rhs) < 0);
+ return (QString::localeAwareCompare(lhs, rhs) < 0);
}
void GroupView::updateScrollbar()
{
- int previousScroll = verticalScrollBar()->value();
- if (m_groups.isEmpty())
- {
- verticalScrollBar()->setRange(0, 0);
- }
- else
- {
- int totalHeight = 0;
- // top margin
- totalHeight += m_categoryMargin;
- int itemScroll = 0;
- for (auto category : m_groups)
- {
- category->m_verticalPosition = totalHeight;
- totalHeight += category->totalHeight() + m_categoryMargin;
- if(!itemScroll && category->totalHeight() != 0)
- {
- itemScroll = category->contentHeight() / category->numRows();
- }
- }
- // do not divide by zero
- if(itemScroll == 0)
- itemScroll = 64;
-
- totalHeight += m_bottomMargin;
- verticalScrollBar()->setSingleStep ( itemScroll );
- const int rowsPerPage = qMax ( viewport()->height() / itemScroll, 1 );
- verticalScrollBar()->setPageStep ( rowsPerPage * itemScroll );
-
- verticalScrollBar()->setRange(0, totalHeight - height());
- }
-
- verticalScrollBar()->setValue(qMin(previousScroll, verticalScrollBar()->maximum()));
+ int previousScroll = verticalScrollBar()->value();
+ if (m_groups.isEmpty())
+ {
+ verticalScrollBar()->setRange(0, 0);
+ }
+ else
+ {
+ int totalHeight = 0;
+ // top margin
+ totalHeight += m_categoryMargin;
+ int itemScroll = 0;
+ for (auto category : m_groups)
+ {
+ category->m_verticalPosition = totalHeight;
+ totalHeight += category->totalHeight() + m_categoryMargin;
+ if(!itemScroll && category->totalHeight() != 0)
+ {
+ itemScroll = category->contentHeight() / category->numRows();
+ }
+ }
+ // do not divide by zero
+ if(itemScroll == 0)
+ itemScroll = 64;
+
+ totalHeight += m_bottomMargin;
+ verticalScrollBar()->setSingleStep ( itemScroll );
+ const int rowsPerPage = qMax ( viewport()->height() / itemScroll, 1 );
+ verticalScrollBar()->setPageStep ( rowsPerPage * itemScroll );
+
+ verticalScrollBar()->setRange(0, totalHeight - height());
+ }
+
+ verticalScrollBar()->setValue(qMin(previousScroll, verticalScrollBar()->maximum()));
}
void GroupView::updateGeometries()
{
- geometryCache.clear();
-
- QMap<LocaleString, VisualGroup *> cats;
-
- for (int i = 0; i < model()->rowCount(); ++i)
- {
- const QString groupName = model()->index(i, 0).data(GroupViewRoles::GroupRole).toString();
- if (!cats.contains(groupName))
- {
- VisualGroup *old = this->category(groupName);
- if (old)
- {
- auto cat = new VisualGroup(old);
- cats.insert(groupName, cat);
- cat->update();
- }
- else
- {
- auto cat = new VisualGroup(groupName, this);
- cats.insert(groupName, cat);
- cat->update();
- }
- }
- }
-
- qDeleteAll(m_groups);
- m_groups = cats.values();
- updateScrollbar();
- viewport()->update();
+ geometryCache.clear();
+
+ QMap<LocaleString, VisualGroup *> cats;
+
+ for (int i = 0; i < model()->rowCount(); ++i)
+ {
+ const QString groupName = model()->index(i, 0).data(GroupViewRoles::GroupRole).toString();
+ if (!cats.contains(groupName))
+ {
+ VisualGroup *old = this->category(groupName);
+ if (old)
+ {
+ auto cat = new VisualGroup(old);
+ cats.insert(groupName, cat);
+ cat->update();
+ }
+ else
+ {
+ auto cat = new VisualGroup(groupName, this);
+ cats.insert(groupName, cat);
+ cat->update();
+ }
+ }
+ }
+
+ qDeleteAll(m_groups);
+ m_groups = cats.values();
+ updateScrollbar();
+ viewport()->update();
}
bool GroupView::isIndexHidden(const QModelIndex &index) const
{
- VisualGroup *cat = category(index);
- if (cat)
- {
- return cat->collapsed;
- }
- else
- {
- return false;
- }
+ VisualGroup *cat = category(index);
+ if (cat)
+ {
+ return cat->collapsed;
+ }
+ else
+ {
+ return false;
+ }
}
VisualGroup *GroupView::category(const QModelIndex &index) const
{
- return category(index.data(GroupViewRoles::GroupRole).toString());
+ return category(index.data(GroupViewRoles::GroupRole).toString());
}
VisualGroup *GroupView::category(const QString &cat) const
{
- for (auto group : m_groups)
- {
- if (group->text == cat)
- {
- return group;
- }
- }
- return nullptr;
+ for (auto group : m_groups)
+ {
+ if (group->text == cat)
+ {
+ return group;
+ }
+ }
+ return nullptr;
}
VisualGroup *GroupView::categoryAt(const QPoint &pos, VisualGroup::HitResults & result) const
{
- for (auto group : m_groups)
- {
- result = group->hitScan(pos);
- if(result != VisualGroup::NoHit)
- {
- return group;
- }
- }
- result = VisualGroup::NoHit;
- return nullptr;
+ for (auto group : m_groups)
+ {
+ result = group->hitScan(pos);
+ if(result != VisualGroup::NoHit)
+ {
+ return group;
+ }
+ }
+ result = VisualGroup::NoHit;
+ return nullptr;
}
QString GroupView::groupNameAt(const QPoint &point)
{
- VisualGroup::HitResults hitresult;
- auto group = categoryAt(point + offset(), hitresult);
- if(group && (hitresult & (VisualGroup::HeaderHit | VisualGroup::BodyHit)))
- {
- return group->text;
- }
- return QString();
+ executeDelayedItemsLayout();
+
+ VisualGroup::HitResults hitresult;
+ auto group = categoryAt(point + offset(), hitresult);
+ if(group && (hitresult & (VisualGroup::HeaderHit | VisualGroup::BodyHit)))
+ {
+ return group->text;
+ }
+ return QString();
}
int GroupView::calculateItemsPerRow() const
{
- return qFloor((qreal)(contentWidth()) / (qreal)(itemWidth() + m_spacing));
+ return qFloor((qreal)(contentWidth()) / (qreal)(itemWidth() + m_spacing));
}
int GroupView::contentWidth() const
{
- return width() - m_leftMargin - m_rightMargin;
+ return width() - m_leftMargin - m_rightMargin;
}
int GroupView::itemWidth() const
{
- return m_itemWidth;
+ return m_itemWidth;
}
void GroupView::mousePressEvent(QMouseEvent *event)
{
- // endCategoryEditor();
-
- QPoint visualPos = event->pos();
- QPoint geometryPos = event->pos() + offset();
-
- QPersistentModelIndex index = indexAt(visualPos);
-
- m_pressedIndex = index;
- m_pressedAlreadySelected = selectionModel()->isSelected(m_pressedIndex);
- m_pressedPosition = geometryPos;
-
- VisualGroup::HitResults hitresult;
- m_pressedCategory = categoryAt(geometryPos, hitresult);
- if (m_pressedCategory && hitresult & VisualGroup::CheckboxHit)
- {
- setState(m_pressedCategory->collapsed ? ExpandingState : CollapsingState);
- event->accept();
- return;
- }
-
- 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(visualPos, visualPos);
- setSelection(rect, QItemSelectionModel::ClearAndSelect);
-
- // signal handlers may change the model
- emit pressed(index);
- }
- else
- {
- // Forces a finalize() even if mouse is pressed, but not on a item
- selectionModel()->select(QModelIndex(), QItemSelectionModel::Select);
- }
+ executeDelayedItemsLayout();
+
+ QPoint visualPos = event->pos();
+ QPoint geometryPos = event->pos() + offset();
+
+ QPersistentModelIndex index = indexAt(visualPos);
+
+ m_pressedIndex = index;
+ m_pressedAlreadySelected = selectionModel()->isSelected(m_pressedIndex);
+ m_pressedPosition = geometryPos;
+
+ VisualGroup::HitResults hitresult;
+ m_pressedCategory = categoryAt(geometryPos, hitresult);
+ if (m_pressedCategory && hitresult & VisualGroup::CheckboxHit)
+ {
+ setState(m_pressedCategory->collapsed ? ExpandingState : CollapsingState);
+ event->accept();
+ return;
+ }
+
+ 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(visualPos, visualPos);
+ setSelection(rect, QItemSelectionModel::ClearAndSelect);
+
+ // signal handlers may change the model
+ emit pressed(index);
+ }
+ else
+ {
+ // Forces a finalize() even if mouse is pressed, but not on a item
+ selectionModel()->select(QModelIndex(), QItemSelectionModel::Select);
+ }
}
void GroupView::mouseMoveEvent(QMouseEvent *event)
{
- QPoint topLeft;
- QPoint visualPos = event->pos();
- QPoint geometryPos = event->pos() + offset();
-
- if (state() == ExpandingState || state() == CollapsingState)
- {
- return;
- }
-
- if (state() == DraggingState)
- {
- topLeft = m_pressedPosition - offset();
- if ((topLeft - event->pos()).manhattanLength() > QApplication::startDragDistance())
- {
- m_pressedIndex = QModelIndex();
- startDrag(model()->supportedDragActions());
- setState(NoState);
- stopAutoScroll();
- }
- return;
- }
-
- if (selectionMode() != SingleSelection)
- {
- topLeft = m_pressedPosition - offset();
- }
- else
- {
- topLeft = geometryPos;
- }
-
- if (m_pressedIndex.isValid() && (state() != DragSelectingState) &&
- (event->buttons() != Qt::NoButton) && !selectedIndexes().isEmpty())
- {
- setState(DraggingState);
- return;
- }
-
- if ((event->buttons() & Qt::LeftButton) && selectionModel())
- {
- setState(DragSelectingState);
-
- setSelection(QRect(visualPos, visualPos), QItemSelectionModel::ClearAndSelect);
- QModelIndex index = indexAt(visualPos);
-
- // set at the end because it might scroll the view
- if (index.isValid() && (index != selectionModel()->currentIndex()) &&
- (index.flags() & Qt::ItemIsEnabled))
- {
- selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
- }
- }
+ executeDelayedItemsLayout();
+
+ QPoint topLeft;
+ QPoint visualPos = event->pos();
+ QPoint geometryPos = event->pos() + offset();
+
+ if (state() == ExpandingState || state() == CollapsingState)
+ {
+ return;
+ }
+
+ if (state() == DraggingState)
+ {
+ topLeft = m_pressedPosition - offset();
+ if ((topLeft - event->pos()).manhattanLength() > QApplication::startDragDistance())
+ {
+ m_pressedIndex = QModelIndex();
+ startDrag(model()->supportedDragActions());
+ setState(NoState);
+ stopAutoScroll();
+ }
+ return;
+ }
+
+ if (selectionMode() != SingleSelection)
+ {
+ topLeft = m_pressedPosition - offset();
+ }
+ else
+ {
+ topLeft = geometryPos;
+ }
+
+ if (m_pressedIndex.isValid() && (state() != DragSelectingState) &&
+ (event->buttons() != Qt::NoButton) && !selectedIndexes().isEmpty())
+ {
+ setState(DraggingState);
+ return;
+ }
+
+ if ((event->buttons() & Qt::LeftButton) && selectionModel())
+ {
+ setState(DragSelectingState);
+
+ setSelection(QRect(visualPos, visualPos), QItemSelectionModel::ClearAndSelect);
+ QModelIndex index = indexAt(visualPos);
+
+ // set at the end because it might scroll the view
+ if (index.isValid() && (index != selectionModel()->currentIndex()) &&
+ (index.flags() & Qt::ItemIsEnabled))
+ {
+ selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
+ }
+ }
}
void GroupView::mouseReleaseEvent(QMouseEvent *event)
{
- QPoint visualPos = event->pos();
- QPoint geometryPos = event->pos() + offset();
- QPersistentModelIndex index = indexAt(visualPos);
-
- VisualGroup::HitResults hitresult;
-
- bool click = (index == m_pressedIndex && index.isValid()) ||
- (m_pressedCategory && m_pressedCategory == categoryAt(geometryPos, hitresult));
-
- if (click && m_pressedCategory)
- {
- if (state() == ExpandingState)
- {
- m_pressedCategory->collapsed = false;
- updateGeometries();
- viewport()->update();
- event->accept();
- return;
- }
- else if (state() == CollapsingState)
- {
- m_pressedCategory->collapsed = true;
- updateGeometries();
- viewport()->update();
- event->accept();
- return;
- }
- }
-
- m_ctrlDragSelectionFlag = QItemSelectionModel::NoUpdate;
-
- setState(NoState);
-
- if (click)
- {
- if (event->button() == Qt::LeftButton)
- {
- emit clicked(index);
- }
- QStyleOptionViewItem option = viewOptions();
- if (m_pressedAlreadySelected)
- {
- option.state |= QStyle::State_Selected;
- }
- if ((model()->flags(index) & Qt::ItemIsEnabled) &&
- style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, &option, this))
- {
- emit activated(index);
- }
- }
+ executeDelayedItemsLayout();
+
+ QPoint visualPos = event->pos();
+ QPoint geometryPos = event->pos() + offset();
+ QPersistentModelIndex index = indexAt(visualPos);
+
+ VisualGroup::HitResults hitresult;
+
+ bool click = (index == m_pressedIndex && index.isValid()) ||
+ (m_pressedCategory && m_pressedCategory == categoryAt(geometryPos, hitresult));
+
+ if (click && m_pressedCategory)
+ {
+ if (state() == ExpandingState)
+ {
+ m_pressedCategory->collapsed = false;
+ updateGeometries();
+ viewport()->update();
+ event->accept();
+ return;
+ }
+ else if (state() == CollapsingState)
+ {
+ m_pressedCategory->collapsed = true;
+ updateGeometries();
+ viewport()->update();
+ event->accept();
+ return;
+ }
+ }
+
+ m_ctrlDragSelectionFlag = QItemSelectionModel::NoUpdate;
+
+ setState(NoState);
+
+ if (click)
+ {
+ if (event->button() == Qt::LeftButton)
+ {
+ emit clicked(index);
+ }
+ QStyleOptionViewItem option = viewOptions();
+ if (m_pressedAlreadySelected)
+ {
+ option.state |= QStyle::State_Selected;
+ }
+ if ((model()->flags(index) & Qt::ItemIsEnabled) &&
+ style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, &option, this))
+ {
+ emit activated(index);
+ }
+ }
}
void GroupView::mouseDoubleClickEvent(QMouseEvent *event)
{
- QModelIndex index = indexAt(event->pos());
- if (!index.isValid() || !(index.flags() & Qt::ItemIsEnabled) || (m_pressedIndex != index))
- {
- QMouseEvent me(QEvent::MouseButtonPress, event->localPos(), event->windowPos(),
- event->screenPos(), event->button(), event->buttons(),
- event->modifiers());
- mousePressEvent(&me);
- return;
- }
- // signal handlers may change the model
- QPersistentModelIndex persistent = index;
- emit doubleClicked(persistent);
+ executeDelayedItemsLayout();
+
+ QModelIndex index = indexAt(event->pos());
+ if (!index.isValid() || !(index.flags() & Qt::ItemIsEnabled) || (m_pressedIndex != index))
+ {
+ QMouseEvent me(QEvent::MouseButtonPress, event->localPos(), event->windowPos(),
+ event->screenPos(), event->button(), event->buttons(),
+ event->modifiers());
+ mousePressEvent(&me);
+ return;
+ }
+ // signal handlers may change the model
+ QPersistentModelIndex persistent = index;
+ emit doubleClicked(persistent);
+
+ QStyleOptionViewItem option = viewOptions();
+ if ((model()->flags(index) & Qt::ItemIsEnabled) && !style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, &option, this))
+ {
+ emit activated(index);
+ }
}
void GroupView::paintEvent(QPaintEvent *event)
{
- executeDelayedItemsLayout();
-
- QPainter painter(this->viewport());
-
- QStyleOptionViewItem option(viewOptions());
- option.widget = this;
-
- int wpWidth = viewport()->width();
- option.rect.setWidth(wpWidth);
- for (int i = 0; i < m_groups.size(); ++i)
- {
- VisualGroup *category = m_groups.at(i);
- int y = category->verticalPosition();
- y -= verticalOffset();
- QRect backup = option.rect;
- int height = category->totalHeight();
- option.rect.setTop(y);
- option.rect.setHeight(height);
- option.rect.setLeft(m_leftMargin);
- option.rect.setRight(wpWidth - m_rightMargin);
- category->drawHeader(&painter, option);
- y += category->totalHeight() + m_categoryMargin;
- option.rect = backup;
- }
-
- for (int i = 0; i < model()->rowCount(); ++i)
- {
- const QModelIndex index = model()->index(i, 0);
- if (isIndexHidden(index))
- {
- continue;
- }
- Qt::ItemFlags flags = index.flags();
- option.rect = visualRect(index);
- option.features |= QStyleOptionViewItem::WrapText;
- if (flags & Qt::ItemIsSelectable && selectionModel()->isSelected(index))
- {
- option.state |= selectionModel()->isSelected(index) ? QStyle::State_Selected
- : QStyle::State_None;
- }
- else
- {
- option.state &= ~QStyle::State_Selected;
- }
- option.state |= (index == currentIndex()) ? QStyle::State_HasFocus : QStyle::State_None;
- if (!(flags & Qt::ItemIsEnabled))
- {
- option.state &= ~QStyle::State_Enabled;
- }
- itemDelegate()->paint(&painter, option, index);
- }
-
- /*
- * Drop indicators for manual reordering...
- */
+ executeDelayedItemsLayout();
+
+ QPainter painter(this->viewport());
+
+ QStyleOptionViewItem option(viewOptions());
+ option.widget = this;
+
+ int wpWidth = viewport()->width();
+ option.rect.setWidth(wpWidth);
+ for (int i = 0; i < m_groups.size(); ++i)
+ {
+ VisualGroup *category = m_groups.at(i);
+ int y = category->verticalPosition();
+ y -= verticalOffset();
+ QRect backup = option.rect;
+ int height = category->totalHeight();
+ option.rect.setTop(y);
+ option.rect.setHeight(height);
+ option.rect.setLeft(m_leftMargin);
+ option.rect.setRight(wpWidth - m_rightMargin);
+ category->drawHeader(&painter, option);
+ y += category->totalHeight() + m_categoryMargin;
+ option.rect = backup;
+ }
+
+ for (int i = 0; i < model()->rowCount(); ++i)
+ {
+ const QModelIndex index = model()->index(i, 0);
+ if (isIndexHidden(index))
+ {
+ continue;
+ }
+ Qt::ItemFlags flags = index.flags();
+ option.rect = visualRect(index);
+ option.features |= QStyleOptionViewItem::WrapText;
+ if (flags & Qt::ItemIsSelectable && selectionModel()->isSelected(index))
+ {
+ option.state |= selectionModel()->isSelected(index) ? QStyle::State_Selected
+ : QStyle::State_None;
+ }
+ else
+ {
+ option.state &= ~QStyle::State_Selected;
+ }
+ option.state |= (index == currentIndex()) ? QStyle::State_HasFocus : QStyle::State_None;
+ if (!(flags & Qt::ItemIsEnabled))
+ {
+ option.state &= ~QStyle::State_Enabled;
+ }
+ itemDelegate()->paint(&painter, option, index);
+ }
+
+ /*
+ * Drop indicators for manual reordering...
+ */
#if 0
- if (!m_lastDragPosition.isNull())
- {
- QPair<Group *, int> pair = rowDropPos(m_lastDragPosition);
- Group *category = pair.first;
- int row = pair.second;
- if (category)
- {
- int internalRow = row - category->firstItemIndex;
- QLine line;
- if (internalRow >= category->numItems())
- {
- QRect toTheRightOfRect = visualRect(category->lastItem());
- line = QLine(toTheRightOfRect.topRight(), toTheRightOfRect.bottomRight());
- }
- else
- {
- QRect toTheLeftOfRect = visualRect(model()->index(row, 0));
- line = QLine(toTheLeftOfRect.topLeft(), toTheLeftOfRect.bottomLeft());
- }
- painter.save();
- painter.setPen(QPen(Qt::black, 3));
- painter.drawLine(line);
- painter.restore();
- }
- }
+ if (!m_lastDragPosition.isNull())
+ {
+ QPair<Group *, int> pair = rowDropPos(m_lastDragPosition);
+ Group *category = pair.first;
+ int row = pair.second;
+ if (category)
+ {
+ int internalRow = row - category->firstItemIndex;
+ QLine line;
+ if (internalRow >= category->numItems())
+ {
+ QRect toTheRightOfRect = visualRect(category->lastItem());
+ line = QLine(toTheRightOfRect.topRight(), toTheRightOfRect.bottomRight());
+ }
+ else
+ {
+ QRect toTheLeftOfRect = visualRect(model()->index(row, 0));
+ line = QLine(toTheLeftOfRect.topLeft(), toTheLeftOfRect.bottomLeft());
+ }
+ painter.save();
+ painter.setPen(QPen(Qt::black, 3));
+ painter.drawLine(line);
+ painter.restore();
+ }
+ }
#endif
}
void GroupView::resizeEvent(QResizeEvent *event)
{
- int newItemsPerRow = calculateItemsPerRow();
- if(newItemsPerRow != m_currentItemsPerRow)
- {
- m_currentCursorColumn = -1;
- m_currentItemsPerRow = newItemsPerRow;
- updateGeometries();
- }
- else
- {
- updateScrollbar();
- }
+ int newItemsPerRow = calculateItemsPerRow();
+ if(newItemsPerRow != m_currentItemsPerRow)
+ {
+ m_currentCursorColumn = -1;
+ m_currentItemsPerRow = newItemsPerRow;
+ updateGeometries();
+ }
+ else
+ {
+ updateScrollbar();
+ }
}
void GroupView::dragEnterEvent(QDragEnterEvent *event)
{
- if (!isDragEventAccepted(event))
- {
- return;
- }
- m_lastDragPosition = event->pos() + offset();
- viewport()->update();
- event->accept();
+ executeDelayedItemsLayout();
+
+ if (!isDragEventAccepted(event))
+ {
+ return;
+ }
+ m_lastDragPosition = event->pos() + offset();
+ viewport()->update();
+ event->accept();
}
void GroupView::dragMoveEvent(QDragMoveEvent *event)
{
- if (!isDragEventAccepted(event))
- {
- return;
- }
- m_lastDragPosition = event->pos() + offset();
- viewport()->update();
- event->accept();
+ executeDelayedItemsLayout();
+
+ if (!isDragEventAccepted(event))
+ {
+ return;
+ }
+ m_lastDragPosition = event->pos() + offset();
+ viewport()->update();
+ event->accept();
}
void GroupView::dragLeaveEvent(QDragLeaveEvent *event)
{
- m_lastDragPosition = QPoint();
- viewport()->update();
+ executeDelayedItemsLayout();
+
+ m_lastDragPosition = QPoint();
+ viewport()->update();
}
void GroupView::dropEvent(QDropEvent *event)
{
- m_lastDragPosition = QPoint();
-
- stopAutoScroll();
- setState(NoState);
-
- if (event->source() == this)
- {
- if(event->possibleActions() & Qt::MoveAction)
- {
- QPair<VisualGroup *, int> dropPos = rowDropPos(event->pos() + offset());
- const VisualGroup *category = dropPos.first;
- const int row = dropPos.second;
-
- if (row == -1)
- {
- viewport()->update();
- return;
- }
-
- const QString categoryText = category->text;
- if (model()->dropMimeData(event->mimeData(), Qt::MoveAction, row, 0, QModelIndex()))
- {
- model()->setData(model()->index(row, 0), categoryText,
- GroupViewRoles::GroupRole);
- event->setDropAction(Qt::MoveAction);
- event->accept();
- }
- updateGeometries();
- viewport()->update();
- }
- }
- auto mimedata = event->mimeData();
-
- // check if the action is supported
- if (!mimedata)
- {
- return;
- }
-
- // files dropped from outside?
- if (mimedata->hasUrls())
- {
- auto urls = mimedata->urls();
- event->accept();
- emit droppedURLs(urls);
- }
+ executeDelayedItemsLayout();
+
+ m_lastDragPosition = QPoint();
+
+ stopAutoScroll();
+ setState(NoState);
+
+ if (event->source() == this)
+ {
+ if(event->possibleActions() & Qt::MoveAction)
+ {
+ QPair<VisualGroup *, int> dropPos = rowDropPos(event->pos() + offset());
+ const VisualGroup *category = dropPos.first;
+ const int row = dropPos.second;
+
+ if (row == -1)
+ {
+ viewport()->update();
+ return;
+ }
+
+ const QString categoryText = category->text;
+ if (model()->dropMimeData(event->mimeData(), Qt::MoveAction, row, 0, QModelIndex()))
+ {
+ model()->setData(model()->index(row, 0), categoryText,
+ GroupViewRoles::GroupRole);
+ event->setDropAction(Qt::MoveAction);
+ event->accept();
+ }
+ updateGeometries();
+ viewport()->update();
+ }
+ }
+ auto mimedata = event->mimeData();
+
+ // check if the action is supported
+ if (!mimedata)
+ {
+ return;
+ }
+
+ // files dropped from outside?
+ if (mimedata->hasUrls())
+ {
+ auto urls = mimedata->urls();
+ event->accept();
+ emit droppedURLs(urls);
+ }
}
void GroupView::startDrag(Qt::DropActions supportedActions)
{
- QModelIndexList indexes = selectionModel()->selectedIndexes();
- if(indexes.count() == 0)
- return;
-
- 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)
- {
- continue;
- }
- if ((*it).right() != (model()->columnCount(parent) - 1))
- {
- continue;
- }
- int count = (*it).bottom() - (*it).top() + 1;
- model()->removeRows((*it).top(), count, parent);
- }
- }
+ executeDelayedItemsLayout();
+
+ QModelIndexList indexes = selectionModel()->selectedIndexes();
+ if(indexes.count() == 0)
+ return;
+
+ 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)
+ {
+ continue;
+ }
+ if ((*it).right() != (model()->columnCount(parent) - 1))
+ {
+ continue;
+ }
+ int count = (*it).bottom() - (*it).top() + 1;
+ model()->removeRows((*it).top(), count, parent);
+ }
+ }
}
QRect GroupView::visualRect(const QModelIndex &index) const
{
- return geometryRect(index).translated(-offset());
+ const_cast<GroupView*>(this)->executeDelayedItemsLayout();
+
+ return geometryRect(index).translated(-offset());
}
QRect GroupView::geometryRect(const QModelIndex &index) const
{
- if (!index.isValid() || isIndexHidden(index) || index.column() > 0)
- {
- return QRect();
- }
+ const_cast<GroupView*>(this)->executeDelayedItemsLayout();
+
+ if (!index.isValid() || isIndexHidden(index) || index.column() > 0)
+ {
+ return QRect();
+ }
- int row = index.row();
- if(geometryCache.contains(row))
- {
- return *geometryCache[row];
- }
+ 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;
+ 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 + 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;
+ QRect out;
+ 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;
}
QModelIndex GroupView::indexAt(const QPoint &point) const
{
- const_cast<GroupView*>(this)->executeDelayedItemsLayout();
+ const_cast<GroupView*>(this)->executeDelayedItemsLayout();
- for (int i = 0; i < model()->rowCount(); ++i)
- {
- QModelIndex index = model()->index(i, 0);
- if (visualRect(index).contains(point))
- {
- return index;
- }
- }
- return QModelIndex();
+ for (int i = 0; i < model()->rowCount(); ++i)
+ {
+ QModelIndex index = model()->index(i, 0);
+ if (visualRect(index).contains(point))
+ {
+ return index;
+ }
+ }
+ return QModelIndex();
}
-void GroupView::setSelection(const QRect &rect,
- const QItemSelectionModel::SelectionFlags commands)
+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 = visualRect(index);
- if (itemRect.intersects(rect))
- {
- selectionModel()->select(index, commands);
- update(itemRect.translated(-offset()));
- }
- }
+ executeDelayedItemsLayout();
+
+ for (int i = 0; i < model()->rowCount(); ++i)
+ {
+ QModelIndex index = model()->index(i, 0);
+ 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
{
- Q_ASSERT(r);
- auto paintPairs = draggablePaintPairs(indices, r);
- if (paintPairs.isEmpty())
- {
- return QPixmap();
- }
- QPixmap pixmap(r->size());
- pixmap.fill(Qt::transparent);
- QPainter painter(&pixmap);
- QStyleOptionViewItem option = viewOptions();
- option.state |= QStyle::State_Selected;
- for (int j = 0; j < paintPairs.count(); ++j)
- {
- option.rect = paintPairs.at(j).first.translated(-r->topLeft());
- const QModelIndex &current = paintPairs.at(j).second;
- itemDelegate()->paint(&painter, option, current);
- }
- return pixmap;
-}
-
-QList<QPair<QRect, QModelIndex>> GroupView::draggablePaintPairs(const QModelIndexList &indices,
- QRect *r) const
-{
- Q_ASSERT(r);
- QRect &rect = *r;
- QList<QPair<QRect, QModelIndex>> ret;
- for (int i = 0; i < indices.count(); ++i)
- {
- const QModelIndex &index = indices.at(i);
- const QRect current = geometryRect(index);
- ret += qMakePair(current, index);
- rect |= current;
- }
- return ret;
+ Q_ASSERT(r);
+ auto paintPairs = draggablePaintPairs(indices, r);
+ if (paintPairs.isEmpty())
+ {
+ return QPixmap();
+ }
+ QPixmap pixmap(r->size());
+ pixmap.fill(Qt::transparent);
+ QPainter painter(&pixmap);
+ QStyleOptionViewItem option = viewOptions();
+ option.state |= QStyle::State_Selected;
+ for (int j = 0; j < paintPairs.count(); ++j)
+ {
+ option.rect = paintPairs.at(j).first.translated(-r->topLeft());
+ const QModelIndex &current = paintPairs.at(j).second;
+ itemDelegate()->paint(&painter, option, current);
+ }
+ return pixmap;
+}
+
+QList<QPair<QRect, QModelIndex>> GroupView::draggablePaintPairs(const QModelIndexList &indices, QRect *r) const
+{
+ Q_ASSERT(r);
+ QRect &rect = *r;
+ QList<QPair<QRect, QModelIndex>> ret;
+ for (int i = 0; i < indices.count(); ++i)
+ {
+ const QModelIndex &index = indices.at(i);
+ const QRect current = geometryRect(index);
+ ret += qMakePair(current, index);
+ rect |= current;
+ }
+ return ret;
}
bool GroupView::isDragEventAccepted(QDropEvent *event)
{
- return true;
+ return true;
}
QPair<VisualGroup *, int> GroupView::rowDropPos(const QPoint &pos)
{
- return qMakePair<VisualGroup*, int>(nullptr, -1);
+ return qMakePair<VisualGroup*, int>(nullptr, -1);
}
QPoint GroupView::offset() const
{
- return QPoint(horizontalOffset(), verticalOffset());
+ return QPoint(horizontalOffset(), verticalOffset());
}
QRegion GroupView::visualRegionForSelection(const QItemSelection &selection) const
{
- QRegion region;
- for (auto &range : selection)
- {
- int start_row = range.top();
- int end_row = range.bottom();
- for (int row = start_row; row <= end_row; ++row)
- {
- int start_column = range.left();
- int end_column = range.right();
- for (int column = start_column; column <= end_column; ++column)
- {
- QModelIndex index = model()->index(row, column, rootIndex());
- region += visualRect(index); // OK
- }
- }
- }
- return region;
+ QRegion region;
+ for (auto &range : selection)
+ {
+ int start_row = range.top();
+ int end_row = range.bottom();
+ for (int row = start_row; row <= end_row; ++row)
+ {
+ int start_column = range.left();
+ int end_column = range.right();
+ for (int column = start_column; column <= end_column; ++column)
+ {
+ QModelIndex index = model()->index(row, column, rootIndex());
+ region += visualRect(index); // OK
+ }
+ }
+ }
+ return region;
}
QModelIndex GroupView::moveCursor(QAbstractItemView::CursorAction cursorAction,
- Qt::KeyboardModifiers modifiers)
-{
- auto current = currentIndex();
- if(!current.isValid())
- {
- return current;
- }
- auto cat = category(current);
- 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)
- {
- 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(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;
- }
- 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;
+ Qt::KeyboardModifiers modifiers)
+{
+ auto current = currentIndex();
+ if(!current.isValid())
+ {
+ return current;
+ }
+ auto cat = category(current);
+ 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)
+ {
+ 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(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;
+ }
+ 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();
+ return horizontalScrollBar()->value();
}
int GroupView::verticalOffset() const
{
- return verticalScrollBar()->value();
+ return verticalScrollBar()->value();
}
void GroupView::scrollContentsBy(int dx, int dy)
{
- scrollDirtyRegion(dx, dy);
- viewport()->scroll(dx, dy);
+ scrollDirtyRegion(dx, dy);
+ viewport()->scroll(dx, dy);
}
void GroupView::scrollTo(const QModelIndex &index, ScrollHint hint)
{
- if (!index.isValid())
- return;
+ if (!index.isValid())
+ return;
- const QRect rect = visualRect(index);
- if (hint == EnsureVisible && viewport()->rect().contains(rect))
- {
- viewport()->update(rect);
- return;
- }
+ const QRect rect = visualRect(index);
+ if (hint == EnsureVisible && viewport()->rect().contains(rect))
+ {
+ viewport()->update(rect);
+ return;
+ }
- verticalScrollBar()->setValue(verticalScrollToValue(index, rect, hint));
+ 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;
+ 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;
}
diff --git a/application/groupview/GroupView.h b/application/groupview/GroupView.h
index 07c65bb5..db29a0d4 100644
--- a/application/groupview/GroupView.h
+++ b/application/groupview/GroupView.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,126 +23,127 @@
struct GroupViewRoles
{
- enum
- {
- GroupRole = Qt::UserRole,
- ProgressValueRole,
- ProgressMaximumRole
- };
+ enum
+ {
+ GroupRole = Qt::UserRole,
+ ProgressValueRole,
+ ProgressMaximumRole
+ };
};
class GroupView : public QAbstractItemView
{
- Q_OBJECT
+ Q_OBJECT
public:
- GroupView(QWidget *parent = 0);
- ~GroupView();
+ GroupView(QWidget *parent = 0);
+ ~GroupView();
- void setModel(QAbstractItemModel *model) override;
+ void setModel(QAbstractItemModel *model) override;
- /// return geometry rectangle occupied by the specified model item
- QRect geometryRect(const QModelIndex &index) const;
- /// return visual rectangle occupied by the specified model item
- virtual QRect visualRect(const QModelIndex &index) const override;
- /// get the model index at the specified visual point
- virtual QModelIndex indexAt(const QPoint &point) const override;
- QString groupNameAt(const QPoint &point);
- void setSelection(const QRect &rect,
- const QItemSelectionModel::SelectionFlags commands) override;
+ /// return geometry rectangle occupied by the specified model item
+ QRect geometryRect(const QModelIndex &index) const;
+ /// return visual rectangle occupied by the specified model item
+ virtual QRect visualRect(const QModelIndex &index) const override;
+ /// get the model index at the specified visual point
+ virtual QModelIndex indexAt(const QPoint &point) const override;
+ QString groupNameAt(const QPoint &point);
+ void setSelection(const QRect &rect,
+ const QItemSelectionModel::SelectionFlags commands) override;
- 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 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 QModelIndex moveCursor(CursorAction cursorAction,
+ Qt::KeyboardModifiers modifiers) override;
- virtual QRegion visualRegionForSelection(const QItemSelection &selection) const override;
+ virtual QRegion visualRegionForSelection(const QItemSelection &selection) const override;
- int spacing() const
- {
- return m_spacing;
- };
+ int spacing() const
+ {
+ return m_spacing;
+ };
public slots:
- virtual void updateGeometries() override;
+ virtual void updateGeometries() override;
protected slots:
- virtual void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
- const QVector<int> &roles) override;
- virtual void rowsInserted(const QModelIndex &parent, int start, int end) override;
- virtual void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) override;
- void modelReset();
- void rowsRemoved();
+ virtual void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
+ const QVector<int> &roles) override;
+ virtual void rowsInserted(const QModelIndex &parent, int start, int end) override;
+ virtual void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) override;
+ void modelReset();
+ void rowsRemoved();
+ void currentChanged(const QModelIndex &current, const QModelIndex &previous) override;
signals:
- void droppedURLs(QList<QUrl> urls);
+ void droppedURLs(QList<QUrl> urls);
protected:
- virtual bool isIndexHidden(const QModelIndex &index) const override;
- void mousePressEvent(QMouseEvent *event) override;
- void mouseMoveEvent(QMouseEvent *event) override;
- void mouseReleaseEvent(QMouseEvent *event) override;
- void mouseDoubleClickEvent(QMouseEvent *event) override;
- void paintEvent(QPaintEvent *event) override;
- void resizeEvent(QResizeEvent *event) override;
+ virtual bool isIndexHidden(const QModelIndex &index) const override;
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
+ void mouseDoubleClickEvent(QMouseEvent *event) override;
+ void paintEvent(QPaintEvent *event) override;
+ void resizeEvent(QResizeEvent *event) override;
- void dragEnterEvent(QDragEnterEvent *event) override;
- void dragMoveEvent(QDragMoveEvent *event) override;
- void dragLeaveEvent(QDragLeaveEvent *event) override;
- void dropEvent(QDropEvent *event) override;
+ void dragEnterEvent(QDragEnterEvent *event) override;
+ void dragMoveEvent(QDragMoveEvent *event) override;
+ void dragLeaveEvent(QDragLeaveEvent *event) override;
+ void dropEvent(QDropEvent *event) override;
- void startDrag(Qt::DropActions supportedActions) override;
+ void startDrag(Qt::DropActions supportedActions) override;
- void updateScrollbar();
+ void updateScrollbar();
private:
- friend struct VisualGroup;
- QList<VisualGroup *> 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;
-
- // point where the currently active mouse action started in geometry coordinates
- QPoint m_pressedPosition;
- QPersistentModelIndex m_pressedIndex;
- bool m_pressedAlreadySelected;
- VisualGroup *m_pressedCategory;
- QItemSelectionModel::SelectionFlag m_ctrlDragSelectionFlag;
- QPoint m_lastDragPosition;
-
- VisualGroup *category(const QModelIndex &index) const;
- VisualGroup *category(const QString &cat) const;
- VisualGroup *categoryAt(const QPoint &pos, VisualGroup::HitResults & result) const;
-
- int itemsPerRow() const
- {
- return m_currentItemsPerRow;
- };
- int contentWidth() const;
+ friend struct VisualGroup;
+ QList<VisualGroup *> 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;
+
+ // point where the currently active mouse action started in geometry coordinates
+ QPoint m_pressedPosition;
+ QPersistentModelIndex m_pressedIndex;
+ bool m_pressedAlreadySelected;
+ VisualGroup *m_pressedCategory;
+ QItemSelectionModel::SelectionFlag m_ctrlDragSelectionFlag;
+ QPoint m_lastDragPosition;
+
+ VisualGroup *category(const QModelIndex &index) const;
+ VisualGroup *category(const QString &cat) const;
+ VisualGroup *categoryAt(const QPoint &pos, VisualGroup::HitResults & result) const;
+
+ int itemsPerRow() const
+ {
+ return m_currentItemsPerRow;
+ };
+ int contentWidth() const;
private: /* methods */
- 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;
+ 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);
+ bool isDragEventAccepted(QDropEvent *event);
- QPair<VisualGroup *, int> rowDropPos(const QPoint &pos);
+ QPair<VisualGroup *, int> rowDropPos(const QPoint &pos);
- QPoint offset() const;
+ QPoint offset() const;
};
diff --git a/application/groupview/GroupedProxyModel.cpp b/application/groupview/GroupedProxyModel.cpp
index c13f2411..d5fbd93c 100644
--- a/application/groupview/GroupedProxyModel.cpp
+++ b/application/groupview/GroupedProxyModel.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,25 +24,25 @@ GroupedProxyModel::GroupedProxyModel(QObject *parent) : QSortFilterProxyModel(pa
bool GroupedProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
- const QString leftCategory = left.data(GroupViewRoles::GroupRole).toString();
- const QString rightCategory = right.data(GroupViewRoles::GroupRole).toString();
- if (leftCategory == rightCategory)
- {
- return subSortLessThan(left, right);
- }
- else
- {
- // FIXME: real group sorting happens in GroupView::updateGeometries(), see LocaleString
- auto result = leftCategory.localeAwareCompare(rightCategory);
- if(result == 0)
- {
- return subSortLessThan(left, right);
- }
- return result < 0;
- }
+ const QString leftCategory = left.data(GroupViewRoles::GroupRole).toString();
+ const QString rightCategory = right.data(GroupViewRoles::GroupRole).toString();
+ if (leftCategory == rightCategory)
+ {
+ return subSortLessThan(left, right);
+ }
+ else
+ {
+ // FIXME: real group sorting happens in GroupView::updateGeometries(), see LocaleString
+ auto result = leftCategory.localeAwareCompare(rightCategory);
+ if(result == 0)
+ {
+ return subSortLessThan(left, right);
+ }
+ return result < 0;
+ }
}
bool GroupedProxyModel::subSortLessThan(const QModelIndex &left, const QModelIndex &right) const
{
- return left.row() < right.row();
+ return left.row() < right.row();
}
diff --git a/application/groupview/GroupedProxyModel.h b/application/groupview/GroupedProxyModel.h
index babeb308..810657e7 100644
--- a/application/groupview/GroupedProxyModel.h
+++ b/application/groupview/GroupedProxyModel.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,12 +19,12 @@
class GroupedProxyModel : public QSortFilterProxyModel
{
- Q_OBJECT
+ Q_OBJECT
public:
- GroupedProxyModel(QObject *parent = 0);
+ GroupedProxyModel(QObject *parent = 0);
protected:
- virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
- virtual bool subSortLessThan(const QModelIndex &left, const QModelIndex &right) const;
+ virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
+ virtual bool subSortLessThan(const QModelIndex &left, const QModelIndex &right) const;
};
diff --git a/application/groupview/InstanceDelegate.cpp b/application/groupview/InstanceDelegate.cpp
index 0855c04a..39830d1a 100644
--- a/application/groupview/InstanceDelegate.cpp
+++ b/application/groupview/InstanceDelegate.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,33 +19,35 @@
#include <QTextLayout>
#include <QApplication>
#include <QtMath>
+#include <QDebug>
#include "GroupView.h"
#include "BaseInstance.h"
#include "InstanceList.h"
#include <xdgicon.h>
+#include <QTextEdit>
// Origin: Qt
static void viewItemTextLayout(QTextLayout &textLayout, int lineWidth, qreal &height,
- qreal &widthUsed)
+ qreal &widthUsed)
{
- height = 0;
- widthUsed = 0;
- textLayout.beginLayout();
- QString str = textLayout.text();
- while (true)
- {
- QTextLine line = textLayout.createLine();
- if (!line.isValid())
- break;
- if (line.textLength() == 0)
- break;
- line.setLineWidth(lineWidth);
- line.setPosition(QPointF(0, height));
- height += line.height();
- widthUsed = qMax(widthUsed, line.naturalTextWidth());
- }
- textLayout.endLayout();
+ height = 0;
+ widthUsed = 0;
+ textLayout.beginLayout();
+ QString str = textLayout.text();
+ while (true)
+ {
+ QTextLine line = textLayout.createLine();
+ if (!line.isValid())
+ break;
+ if (line.textLength() == 0)
+ break;
+ line.setLineWidth(lineWidth);
+ line.setPosition(QPointF(0, height));
+ height += line.height();
+ widthUsed = qMax(widthUsed, line.naturalTextWidth());
+ }
+ textLayout.endLayout();
}
ListViewDelegate::ListViewDelegate(QObject *parent) : QStyledItemDelegate(parent)
@@ -53,291 +55,374 @@ ListViewDelegate::ListViewDelegate(QObject *parent) : QStyledItemDelegate(parent
}
void drawSelectionRect(QPainter *painter, const QStyleOptionViewItem &option,
- const QRect &rect)
+ const QRect &rect)
{
- if ((option.state & QStyle::State_Selected))
- painter->fillRect(rect, option.palette.brush(QPalette::Highlight));
- else
- {
- QColor backgroundColor = option.palette.color(QPalette::Background);
- backgroundColor.setAlpha(160);
- painter->fillRect(rect, QBrush(backgroundColor));
- }
+ if ((option.state & QStyle::State_Selected))
+ painter->fillRect(rect, option.palette.brush(QPalette::Highlight));
+ else
+ {
+ QColor backgroundColor = option.palette.color(QPalette::Background);
+ backgroundColor.setAlpha(160);
+ painter->fillRect(rect, QBrush(backgroundColor));
+ }
}
void drawFocusRect(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect)
{
- if (!(option.state & QStyle::State_HasFocus))
- return;
- QStyleOptionFocusRect opt;
- opt.direction = option.direction;
- opt.fontMetrics = option.fontMetrics;
- opt.palette = option.palette;
- opt.rect = rect;
- // opt.state = option.state | QStyle::State_KeyboardFocusChange |
- // QStyle::State_Item;
- auto col = option.state & QStyle::State_Selected ? QPalette::Highlight : QPalette::Base;
- opt.backgroundColor = option.palette.color(col);
- // Apparently some widget styles expect this hint to not be set
- painter->setRenderHint(QPainter::Antialiasing, false);
-
- QStyle *style = option.widget ? option.widget->style() : QApplication::style();
-
- style->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, painter, option.widget);
-
- painter->setRenderHint(QPainter::Antialiasing);
+ if (!(option.state & QStyle::State_HasFocus))
+ return;
+ QStyleOptionFocusRect opt;
+ opt.direction = option.direction;
+ opt.fontMetrics = option.fontMetrics;
+ opt.palette = option.palette;
+ opt.rect = rect;
+ // opt.state = option.state | QStyle::State_KeyboardFocusChange |
+ // QStyle::State_Item;
+ auto col = option.state & QStyle::State_Selected ? QPalette::Highlight : QPalette::Base;
+ opt.backgroundColor = option.palette.color(col);
+ // Apparently some widget styles expect this hint to not be set
+ painter->setRenderHint(QPainter::Antialiasing, false);
+
+ QStyle *style = option.widget ? option.widget->style() : QApplication::style();
+
+ style->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, painter, option.widget);
+
+ painter->setRenderHint(QPainter::Antialiasing);
}
// TODO this can be made a lot prettier
void drawProgressOverlay(QPainter *painter, const QStyleOptionViewItem &option,
- const int value, const int maximum)
+ const int value, const int maximum)
{
- if (maximum == 0 || value == maximum)
- {
- return;
- }
+ if (maximum == 0 || value == maximum)
+ {
+ return;
+ }
- painter->save();
+ painter->save();
- qreal percent = (qreal)value / (qreal)maximum;
- QColor color = option.palette.color(QPalette::Dark);
- color.setAlphaF(0.70f);
- painter->setBrush(color);
- painter->setPen(QPen(QBrush(), 0));
- painter->drawPie(option.rect, 90 * 16, -percent * 360 * 16);
+ qreal percent = (qreal)value / (qreal)maximum;
+ QColor color = option.palette.color(QPalette::Dark);
+ color.setAlphaF(0.70f);
+ painter->setBrush(color);
+ painter->setPen(QPen(QBrush(), 0));
+ painter->drawPie(option.rect, 90 * 16, -percent * 360 * 16);
- painter->restore();
+ painter->restore();
}
void drawBadges(QPainter *painter, const QStyleOptionViewItem &option, BaseInstance *instance, QIcon::Mode mode, QIcon::State state)
{
- QList<QString> pixmaps;
- if (instance->isRunning())
- {
- pixmaps.append("status-running");
- }
- else if (instance->hasCrashed() || instance->hasVersionBroken())
- {
- pixmaps.append("status-bad");
- }
- if (instance->hasUpdateAvailable())
- {
- pixmaps.append("checkupdate");
- }
-
- static const int itemSide = 24;
- static const int spacing = 1;
- const int itemsPerRow = qMax(1, qFloor(double(option.rect.width() + spacing) / double(itemSide + spacing)));
- const int rows = qCeil((double)pixmaps.size() / (double)itemsPerRow);
- QListIterator<QString> it(pixmaps);
- painter->translate(option.rect.topLeft());
- for (int y = 0; y < rows; ++y)
- {
- for (int x = 0; x < itemsPerRow; ++x)
- {
- if (!it.hasNext())
- {
- return;
- }
- // FIXME: inject this.
- auto icon = XdgIcon::fromTheme(it.next());
- // opt.icon.paint(painter, iconbox, Qt::AlignCenter, mode, state);
- const QPixmap pixmap;
- // itemSide
- QRect badgeRect(
- option.rect.width() - x * itemSide + qMax(x - 1, 0) * spacing - itemSide,
- y * itemSide + qMax(y - 1, 0) * spacing,
- itemSide,
- itemSide
- );
- icon.paint(painter, badgeRect, Qt::AlignCenter, mode, state);
- }
- }
- painter->translate(-option.rect.topLeft());
+ QList<QString> pixmaps;
+ if (instance->isRunning())
+ {
+ pixmaps.append("status-running");
+ }
+ else if (instance->hasCrashed() || instance->hasVersionBroken())
+ {
+ pixmaps.append("status-bad");
+ }
+ if (instance->hasUpdateAvailable())
+ {
+ pixmaps.append("checkupdate");
+ }
+
+ static const int itemSide = 24;
+ static const int spacing = 1;
+ const int itemsPerRow = qMax(1, qFloor(double(option.rect.width() + spacing) / double(itemSide + spacing)));
+ const int rows = qCeil((double)pixmaps.size() / (double)itemsPerRow);
+ QListIterator<QString> it(pixmaps);
+ painter->translate(option.rect.topLeft());
+ for (int y = 0; y < rows; ++y)
+ {
+ for (int x = 0; x < itemsPerRow; ++x)
+ {
+ if (!it.hasNext())
+ {
+ return;
+ }
+ // FIXME: inject this.
+ auto icon = XdgIcon::fromTheme(it.next());
+ // opt.icon.paint(painter, iconbox, Qt::AlignCenter, mode, state);
+ const QPixmap pixmap;
+ // itemSide
+ QRect badgeRect(
+ option.rect.width() - x * itemSide + qMax(x - 1, 0) * spacing - itemSide,
+ y * itemSide + qMax(y - 1, 0) * spacing,
+ itemSide,
+ itemSide
+ );
+ icon.paint(painter, badgeRect, Qt::AlignCenter, mode, state);
+ }
+ }
+ painter->translate(-option.rect.topLeft());
}
static QSize viewItemTextSize(const QStyleOptionViewItem *option)
{
- QStyle *style = option->widget ? option->widget->style() : QApplication::style();
- QTextOption textOption;
- textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
- QTextLayout textLayout;
- textLayout.setTextOption(textOption);
- textLayout.setFont(option->font);
- textLayout.setText(option->text);
- const int textMargin =
- style->pixelMetric(QStyle::PM_FocusFrameHMargin, option, option->widget) + 1;
- QRect bounds(0, 0, 100 - 2 * textMargin, 600);
- qreal height = 0, widthUsed = 0;
- viewItemTextLayout(textLayout, bounds.width(), height, widthUsed);
- const QSize size(qCeil(widthUsed), qCeil(height));
- return QSize(size.width() + 2 * textMargin, size.height());
+ QStyle *style = option->widget ? option->widget->style() : QApplication::style();
+ QTextOption textOption;
+ textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
+ QTextLayout textLayout;
+ textLayout.setTextOption(textOption);
+ textLayout.setFont(option->font);
+ textLayout.setText(option->text);
+ const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, option, option->widget) + 1;
+ QRect bounds(0, 0, 100 - 2 * textMargin, 600);
+ qreal height = 0, widthUsed = 0;
+ viewItemTextLayout(textLayout, bounds.width(), height, widthUsed);
+ const QSize size(qCeil(widthUsed), qCeil(height));
+ return QSize(size.width() + 2 * textMargin, size.height());
}
void ListViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
- const QModelIndex &index) const
+ const QModelIndex &index) const
{
- QStyleOptionViewItem opt = option;
- initStyleOption(&opt, index);
- painter->save();
- painter->setClipRect(opt.rect);
-
- opt.features |= QStyleOptionViewItem::WrapText;
- opt.text = index.data().toString();
- opt.textElideMode = Qt::ElideRight;
- opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter;
-
- QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
-
- // const int iconSize = style->pixelMetric(QStyle::PM_IconViewIconSize);
- const int iconSize = 48;
- QRect iconbox = opt.rect;
- const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, opt.widget) + 1;
- QRect textRect = opt.rect;
- QRect textHighlightRect = textRect;
- // clip the decoration on top, remove width padding
- textRect.adjust(textMargin, iconSize + textMargin + 5, -textMargin, 0);
-
- textHighlightRect.adjust(0, iconSize + 5, 0, 0);
-
- // draw background
- {
- // FIXME: unused
- // QSize textSize = viewItemTextSize ( &opt );
- QPalette::ColorGroup cg;
- QStyleOptionViewItem opt2(opt);
-
- if ((opt.widget && opt.widget->isEnabled()) || (opt.state & QStyle::State_Enabled))
- {
- if (!(opt.state & QStyle::State_Active))
- cg = QPalette::Inactive;
- else
- cg = QPalette::Normal;
- }
- else
- {
- cg = QPalette::Disabled;
- }
- opt2.palette.setCurrentColorGroup(cg);
-
- // fill in background, if any
-
- if (opt.backgroundBrush.style() != Qt::NoBrush)
- {
- QPointF oldBO = painter->brushOrigin();
- painter->setBrushOrigin(opt.rect.topLeft());
- painter->fillRect(opt.rect, opt.backgroundBrush);
- painter->setBrushOrigin(oldBO);
- }
-
- drawSelectionRect(painter, opt2, textHighlightRect);
-
- /*
- if (opt.showDecorationSelected)
- {
- drawSelectionRect(painter, opt2, opt.rect);
- drawFocusRect(painter, opt2, opt.rect);
- // painter->fillRect ( opt.rect, opt.palette.brush ( cg, QPalette::Highlight ) );
- }
- else
- {
-
- // if ( opt.state & QStyle::State_Selected )
- {
- // QRect textRect = subElementRect ( QStyle::SE_ItemViewItemText, opt,
- // opt.widget );
- // painter->fillRect ( textHighlightRect, opt.palette.brush ( cg,
- // QPalette::Highlight ) );
- drawSelectionRect(painter, opt2, textHighlightRect);
- drawFocusRect(painter, opt2, textHighlightRect);
- }
- }
- */
- }
-
- // icon mode and state, also used for badges
- QIcon::Mode mode = QIcon::Normal;
- if (!(opt.state & QStyle::State_Enabled))
- mode = QIcon::Disabled;
- else if (opt.state & QStyle::State_Selected)
- mode = QIcon::Selected;
- QIcon::State state = opt.state & QStyle::State_Open ? QIcon::On : QIcon::Off;
-
- // draw the icon
- {
- iconbox.setHeight(iconSize);
- opt.icon.paint(painter, iconbox, Qt::AlignCenter, mode, state);
- }
- // set the text colors
- QPalette::ColorGroup cg =
- opt.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled;
- if (cg == QPalette::Normal && !(opt.state & QStyle::State_Active))
- cg = QPalette::Inactive;
- if (opt.state & QStyle::State_Selected)
- {
- painter->setPen(opt.palette.color(cg, QPalette::HighlightedText));
- }
- else
- {
- painter->setPen(opt.palette.color(cg, QPalette::Text));
- }
-
- // draw the text
- QTextOption textOption;
- textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
- textOption.setTextDirection(opt.direction);
- textOption.setAlignment(QStyle::visualAlignment(opt.direction, opt.displayAlignment));
- QTextLayout textLayout;
- textLayout.setTextOption(textOption);
- textLayout.setFont(opt.font);
- textLayout.setText(opt.text);
-
- qreal width, height;
- viewItemTextLayout(textLayout, textRect.width(), height, width);
-
- const int lineCount = textLayout.lineCount();
-
- const QRect layoutRect = QStyle::alignedRect(
- opt.direction, opt.displayAlignment, QSize(textRect.width(), int(height)), textRect);
- const QPointF position = layoutRect.topLeft();
- for (int i = 0; i < lineCount; ++i)
- {
- const QTextLine line = textLayout.lineAt(i);
- line.draw(painter, position);
- }
-
- // FIXME: this really has no business of being here. Make generic.
- auto instance = (BaseInstance*)index.data(InstanceList::InstancePointerRole)
- .value<void *>();
- if (instance)
- {
- drawBadges(painter, opt, instance, mode, state);
- }
-
- drawProgressOverlay(painter, opt, index.data(GroupViewRoles::ProgressValueRole).toInt(),
- index.data(GroupViewRoles::ProgressMaximumRole).toInt());
-
- painter->restore();
+ QStyleOptionViewItem opt = option;
+ initStyleOption(&opt, index);
+ painter->save();
+ painter->setClipRect(opt.rect);
+
+ opt.features |= QStyleOptionViewItem::WrapText;
+ opt.text = index.data().toString();
+ opt.textElideMode = Qt::ElideRight;
+ opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter;
+
+ QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
+
+ // const int iconSize = style->pixelMetric(QStyle::PM_IconViewIconSize);
+ const int iconSize = 48;
+ QRect iconbox = opt.rect;
+ const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, opt.widget) + 1;
+ QRect textRect = opt.rect;
+ QRect textHighlightRect = textRect;
+ // clip the decoration on top, remove width padding
+ textRect.adjust(textMargin, iconSize + textMargin + 5, -textMargin, 0);
+
+ textHighlightRect.adjust(0, iconSize + 5, 0, 0);
+
+ // draw background
+ {
+ // FIXME: unused
+ // QSize textSize = viewItemTextSize ( &opt );
+ drawSelectionRect(painter, opt, textHighlightRect);
+ /*
+ QPalette::ColorGroup cg;
+ QStyleOptionViewItem opt2(opt);
+
+ if ((opt.widget && opt.widget->isEnabled()) || (opt.state & QStyle::State_Enabled))
+ {
+ if (!(opt.state & QStyle::State_Active))
+ cg = QPalette::Inactive;
+ else
+ cg = QPalette::Normal;
+ }
+ else
+ {
+ cg = QPalette::Disabled;
+ }
+ */
+ /*
+ opt2.palette.setCurrentColorGroup(cg);
+
+ // fill in background, if any
+
+
+ if (opt.backgroundBrush.style() != Qt::NoBrush)
+ {
+ QPointF oldBO = painter->brushOrigin();
+ painter->setBrushOrigin(opt.rect.topLeft());
+ painter->fillRect(opt.rect, opt.backgroundBrush);
+ painter->setBrushOrigin(oldBO);
+ }
+
+ drawSelectionRect(painter, opt2, textHighlightRect);
+ */
+
+ /*
+ if (opt.showDecorationSelected)
+ {
+ drawSelectionRect(painter, opt2, opt.rect);
+ drawFocusRect(painter, opt2, opt.rect);
+ // painter->fillRect ( opt.rect, opt.palette.brush ( cg, QPalette::Highlight ) );
+ }
+ else
+ {
+
+ // if ( opt.state & QStyle::State_Selected )
+ {
+ // QRect textRect = subElementRect ( QStyle::SE_ItemViewItemText, opt,
+ // opt.widget );
+ // painter->fillRect ( textHighlightRect, opt.palette.brush ( cg,
+ // QPalette::Highlight ) );
+ drawSelectionRect(painter, opt2, textHighlightRect);
+ drawFocusRect(painter, opt2, textHighlightRect);
+ }
+ }
+ */
+ }
+
+ // icon mode and state, also used for badges
+ QIcon::Mode mode = QIcon::Normal;
+ if (!(opt.state & QStyle::State_Enabled))
+ mode = QIcon::Disabled;
+ else if (opt.state & QStyle::State_Selected)
+ mode = QIcon::Selected;
+ QIcon::State state = opt.state & QStyle::State_Open ? QIcon::On : QIcon::Off;
+
+ // draw the icon
+ {
+ iconbox.setHeight(iconSize);
+ opt.icon.paint(painter, iconbox, Qt::AlignCenter, mode, state);
+ }
+ // set the text colors
+ QPalette::ColorGroup cg =
+ opt.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled;
+ if (cg == QPalette::Normal && !(opt.state & QStyle::State_Active))
+ cg = QPalette::Inactive;
+ if (opt.state & QStyle::State_Selected)
+ {
+ painter->setPen(opt.palette.color(cg, QPalette::HighlightedText));
+ }
+ else
+ {
+ painter->setPen(opt.palette.color(cg, QPalette::Text));
+ }
+
+ // draw the text
+ QTextOption textOption;
+ textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
+ textOption.setTextDirection(opt.direction);
+ textOption.setAlignment(QStyle::visualAlignment(opt.direction, opt.displayAlignment));
+ QTextLayout textLayout;
+ textLayout.setTextOption(textOption);
+ textLayout.setFont(opt.font);
+ textLayout.setText(opt.text);
+
+ qreal width, height;
+ viewItemTextLayout(textLayout, textRect.width(), height, width);
+
+ const int lineCount = textLayout.lineCount();
+
+ const QRect layoutRect = QStyle::alignedRect(
+ opt.direction, opt.displayAlignment, QSize(textRect.width(), int(height)), textRect);
+ const QPointF position = layoutRect.topLeft();
+ for (int i = 0; i < lineCount; ++i)
+ {
+ const QTextLine line = textLayout.lineAt(i);
+ line.draw(painter, position);
+ }
+
+ // FIXME: this really has no business of being here. Make generic.
+ auto instance = (BaseInstance*)index.data(InstanceList::InstancePointerRole)
+ .value<void *>();
+ if (instance)
+ {
+ drawBadges(painter, opt, instance, mode, state);
+ }
+
+ drawProgressOverlay(painter, opt, index.data(GroupViewRoles::ProgressValueRole).toInt(),
+ index.data(GroupViewRoles::ProgressMaximumRole).toInt());
+
+ painter->restore();
}
QSize ListViewDelegate::sizeHint(const QStyleOptionViewItem &option,
- const QModelIndex &index) const
+ const QModelIndex &index) const
{
- QStyleOptionViewItem opt = option;
- initStyleOption(&opt, index);
- opt.features |= QStyleOptionViewItem::WrapText;
- opt.text = index.data().toString();
- opt.textElideMode = Qt::ElideRight;
- opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter;
-
- QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
- const int textMargin =
- style->pixelMetric(QStyle::PM_FocusFrameHMargin, &option, opt.widget) + 1;
- int height = 48 + textMargin * 2 + 5; // TODO: turn constants into variables
- QSize szz = viewItemTextSize(&opt);
- height += szz.height();
- // FIXME: maybe the icon items could scale and keep proportions?
- QSize sz(100, height);
- return sz;
+ QStyleOptionViewItem opt = option;
+ initStyleOption(&opt, index);
+ opt.features |= QStyleOptionViewItem::WrapText;
+ opt.text = index.data().toString();
+ opt.textElideMode = Qt::ElideRight;
+ opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter;
+
+ QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
+ const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, &option, opt.widget) + 1;
+ int height = 48 + textMargin * 2 + 5; // TODO: turn constants into variables
+ QSize szz = viewItemTextSize(&opt);
+ height += szz.height();
+ // FIXME: maybe the icon items could scale and keep proportions?
+ QSize sz(100, height);
+ return sz;
}
+class NoReturnTextEdit: public QTextEdit
+{
+ Q_OBJECT
+public:
+ explicit NoReturnTextEdit(QWidget *parent) : QTextEdit(parent)
+ {
+ setTextInteractionFlags(Qt::TextEditorInteraction);
+ setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
+ setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
+ }
+ bool event(QEvent * event) override
+ {
+ auto eventType = event->type();
+ if(eventType == QEvent::KeyPress || eventType == QEvent::KeyRelease)
+ {
+ QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
+ auto key = keyEvent->key();
+ if (key == Qt::Key_Return || key == Qt::Key_Enter)
+ {
+ emit editingDone();
+ return true;
+ }
+ if(key == Qt::Key_Tab)
+ {
+ return true;
+ }
+ }
+ return QTextEdit::event(event);
+ }
+signals:
+ void editingDone();
+};
+
+void ListViewDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const
+{
+ const int iconSize = 48;
+ QRect textRect = option.rect;
+ // QStyle *style = option.widget ? option.widget->style() : QApplication::style();
+ textRect.adjust(0, iconSize + 5, 0, 0);
+ editor->setGeometry(textRect);
+}
+
+void ListViewDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
+{
+ auto text = index.data(Qt::EditRole).toString();
+ QTextEdit * realeditor = qobject_cast<NoReturnTextEdit *>(editor);
+ realeditor->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
+ realeditor->append(text);
+ realeditor->selectAll();
+ realeditor->document()->clearUndoRedoStacks();
+}
+
+void ListViewDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
+{
+ QTextEdit * realeditor = qobject_cast<NoReturnTextEdit *>(editor);
+ QString text = realeditor->toPlainText();
+ text.replace(QChar('\n'), QChar(' '));
+ text = text.trimmed();
+ if(text.size() != 0)
+ {
+ model->setData(index, text);
+ }
+}
+
+QWidget * ListViewDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
+{
+ auto editor = new NoReturnTextEdit(parent);
+ connect(editor, &NoReturnTextEdit::editingDone, this, &ListViewDelegate::editingDone);
+ return editor;
+}
+
+void ListViewDelegate::editingDone()
+{
+ NoReturnTextEdit *editor = qobject_cast<NoReturnTextEdit *>(sender());
+ emit commitData(editor);
+ emit closeEditor(editor);
+}
+
+#include "InstanceDelegate.moc"
diff --git a/application/groupview/InstanceDelegate.h b/application/groupview/InstanceDelegate.h
index c0148570..be49f943 100644
--- a/application/groupview/InstanceDelegate.h
+++ b/application/groupview/InstanceDelegate.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,11 +20,20 @@
class ListViewDelegate : public QStyledItemDelegate
{
+ Q_OBJECT
+
public:
- explicit ListViewDelegate(QObject *parent = 0);
+ explicit ListViewDelegate(QObject *parent = 0);
+ virtual ~ListViewDelegate() {}
+
+ void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
+ QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
+ void updateEditorGeometry(QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & index) const override;
+ QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const override;
+
+ void setEditorData(QWidget * editor, const QModelIndex & index) const override;
+ void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const override;
-protected:
- void paint(QPainter *painter, const QStyleOptionViewItem &option,
- const QModelIndex &index) const;
- QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
+private slots:
+ void editingDone();
};
diff --git a/application/groupview/VisualGroup.cpp b/application/groupview/VisualGroup.cpp
index 940c7a8b..f3e6751d 100644
--- a/application/groupview/VisualGroup.cpp
+++ b/application/groupview/VisualGroup.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,290 +28,290 @@ VisualGroup::VisualGroup(const QString &text, GroupView *view) : view(view), tex
}
VisualGroup::VisualGroup(const VisualGroup *other)
- : view(other->view), text(other->text), collapsed(other->collapsed)
+ : view(other->view), text(other->text), collapsed(other->collapsed)
{
}
void VisualGroup::update()
{
- auto temp_items = items();
- auto itemsPerRow = view->itemsPerRow();
-
- 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)
- {
- 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;
+ auto temp_items = items();
+ auto itemsPerRow = view->itemsPerRow();
+
+ 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)
+ {
+ 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;
}
QPair<int, int> VisualGroup::positionOf(const QModelIndex &index) const
{
- 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++;
- }
- qWarning() << "Item" << index.row() << index.data(Qt::DisplayRole).toString() << "not found in visual group" << text;
- return qMakePair(0, 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++;
+ }
+ qWarning() << "Item" << index.row() << index.data(Qt::DisplayRole).toString() << "not found in visual group" << text;
+ return qMakePair(0, 0);
}
int VisualGroup::rowTopOf(const QModelIndex &index) const
{
- auto position = positionOf(index);
- return rows[position.second].top;
+ 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;
+ 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?
- int y = pos.y();
- // int x = pos.x();
- if (y < y_start)
- {
- results = VisualGroup::NoHit;
- }
- else if (y < body_start)
- {
- 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 |= VisualGroup::CheckboxHit;
- }
- }
- else if (y < body_end)
- {
- results |= VisualGroup::BodyHit;
- }
- return results;
+ 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?
+ int y = pos.y();
+ // int x = pos.x();
+ if (y < y_start)
+ {
+ results = VisualGroup::NoHit;
+ }
+ else if (y < body_start)
+ {
+ 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 |= VisualGroup::CheckboxHit;
+ }
+ }
+ else if (y < body_end)
+ {
+ results |= VisualGroup::BodyHit;
+ }
+ return results;
}
void VisualGroup::drawHeader(QPainter *painter, const QStyleOptionViewItem &option)
{
- painter->setRenderHint(QPainter::Antialiasing);
-
- const QRect optRect = option.rect;
- QFont font(QApplication::font());
- font.setBold(true);
- const QFontMetrics fontMetrics = QFontMetrics(font);
-
- QColor outlineColor = option.palette.text().color();
- outlineColor.setAlphaF(0.35);
-
- //BEGIN: top left corner
- {
- painter->save();
- painter->setPen(outlineColor);
- const QPointF topLeft(optRect.topLeft());
- QRectF arc(topLeft, QSizeF(4, 4));
- arc.translate(0.5, 0.5);
- painter->drawArc(arc, 1440, 1440);
- painter->restore();
- }
- //END: top left corner
-
- //BEGIN: left vertical line
- {
- QPoint start(optRect.topLeft());
- start.ry() += 3;
- QPoint verticalGradBottom(optRect.topLeft());
- verticalGradBottom.ry() += fontMetrics.height() + 5;
- QLinearGradient gradient(start, verticalGradBottom);
- gradient.setColorAt(0, outlineColor);
- gradient.setColorAt(1, Qt::transparent);
- painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient);
- }
- //END: left vertical line
-
- //BEGIN: horizontal line
- {
- QPoint start(optRect.topLeft());
- start.rx() += 3;
- QPoint horizontalGradTop(optRect.topLeft());
- horizontalGradTop.rx() += optRect.width() - 6;
- painter->fillRect(QRect(start, QSize(optRect.width() - 6, 1)), outlineColor);
- }
- //END: horizontal line
-
- //BEGIN: top right corner
- {
- painter->save();
- painter->setPen(outlineColor);
- QPointF topRight(optRect.topRight());
- topRight.rx() -= 4;
- QRectF arc(topRight, QSizeF(4, 4));
- arc.translate(0.5, 0.5);
- painter->drawArc(arc, 0, 1440);
- painter->restore();
- }
- //END: top right corner
-
- //BEGIN: right vertical line
- {
- QPoint start(optRect.topRight());
- start.ry() += 3;
- QPoint verticalGradBottom(optRect.topRight());
- verticalGradBottom.ry() += fontMetrics.height() + 5;
- QLinearGradient gradient(start, verticalGradBottom);
- gradient.setColorAt(0, outlineColor);
- gradient.setColorAt(1, Qt::transparent);
- painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient);
- }
- //END: right vertical line
-
- //BEGIN: checkboxy thing
- {
- painter->save();
- painter->setRenderHint(QPainter::Antialiasing, false);
- painter->setFont(font);
- QColor penColor(option.palette.text().color());
- penColor.setAlphaF(0.6);
- painter->setPen(penColor);
- QRect iconSubRect(option.rect);
- iconSubRect.setTop(iconSubRect.top() + 7);
- iconSubRect.setLeft(iconSubRect.left() + 7);
-
- int sizing = fontMetrics.height();
- int even = ( (sizing - 1) % 2 );
-
- iconSubRect.setHeight(sizing - even);
- iconSubRect.setWidth(sizing - even);
- painter->drawRect(iconSubRect);
-
-
- /*
- if(collapsed)
- painter->drawText(iconSubRect, Qt::AlignHCenter | Qt::AlignVCenter, "+");
- else
- painter->drawText(iconSubRect, Qt::AlignHCenter | Qt::AlignVCenter, "-");
- */
- painter->setBrush(option.palette.text());
- painter->fillRect(iconSubRect.x(), iconSubRect.y() + iconSubRect.height() / 2,
- iconSubRect.width(), 2, penColor);
- if (collapsed)
- {
- painter->fillRect(iconSubRect.x() + iconSubRect.width() / 2, iconSubRect.y(), 2,
- iconSubRect.height(), penColor);
- }
-
- painter->restore();
- }
- //END: checkboxy thing
-
- //BEGIN: text
- {
- QRect textRect(option.rect);
- textRect.setTop(textRect.top() + 7);
- textRect.setLeft(textRect.left() + 7 + fontMetrics.height() + 7);
- textRect.setHeight(fontMetrics.height());
- textRect.setRight(textRect.right() - 7);
-
- painter->save();
- painter->setFont(font);
- QColor penColor(option.palette.text().color());
- penColor.setAlphaF(0.6);
- painter->setPen(penColor);
- painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text);
- painter->restore();
- }
- //END: text
+ painter->setRenderHint(QPainter::Antialiasing);
+
+ const QRect optRect = option.rect;
+ QFont font(QApplication::font());
+ font.setBold(true);
+ const QFontMetrics fontMetrics = QFontMetrics(font);
+
+ QColor outlineColor = option.palette.text().color();
+ outlineColor.setAlphaF(0.35);
+
+ //BEGIN: top left corner
+ {
+ painter->save();
+ painter->setPen(outlineColor);
+ const QPointF topLeft(optRect.topLeft());
+ QRectF arc(topLeft, QSizeF(4, 4));
+ arc.translate(0.5, 0.5);
+ painter->drawArc(arc, 1440, 1440);
+ painter->restore();
+ }
+ //END: top left corner
+
+ //BEGIN: left vertical line
+ {
+ QPoint start(optRect.topLeft());
+ start.ry() += 3;
+ QPoint verticalGradBottom(optRect.topLeft());
+ verticalGradBottom.ry() += fontMetrics.height() + 5;
+ QLinearGradient gradient(start, verticalGradBottom);
+ gradient.setColorAt(0, outlineColor);
+ gradient.setColorAt(1, Qt::transparent);
+ painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient);
+ }
+ //END: left vertical line
+
+ //BEGIN: horizontal line
+ {
+ QPoint start(optRect.topLeft());
+ start.rx() += 3;
+ QPoint horizontalGradTop(optRect.topLeft());
+ horizontalGradTop.rx() += optRect.width() - 6;
+ painter->fillRect(QRect(start, QSize(optRect.width() - 6, 1)), outlineColor);
+ }
+ //END: horizontal line
+
+ //BEGIN: top right corner
+ {
+ painter->save();
+ painter->setPen(outlineColor);
+ QPointF topRight(optRect.topRight());
+ topRight.rx() -= 4;
+ QRectF arc(topRight, QSizeF(4, 4));
+ arc.translate(0.5, 0.5);
+ painter->drawArc(arc, 0, 1440);
+ painter->restore();
+ }
+ //END: top right corner
+
+ //BEGIN: right vertical line
+ {
+ QPoint start(optRect.topRight());
+ start.ry() += 3;
+ QPoint verticalGradBottom(optRect.topRight());
+ verticalGradBottom.ry() += fontMetrics.height() + 5;
+ QLinearGradient gradient(start, verticalGradBottom);
+ gradient.setColorAt(0, outlineColor);
+ gradient.setColorAt(1, Qt::transparent);
+ painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient);
+ }
+ //END: right vertical line
+
+ //BEGIN: checkboxy thing
+ {
+ painter->save();
+ painter->setRenderHint(QPainter::Antialiasing, false);
+ painter->setFont(font);
+ QColor penColor(option.palette.text().color());
+ penColor.setAlphaF(0.6);
+ painter->setPen(penColor);
+ QRect iconSubRect(option.rect);
+ iconSubRect.setTop(iconSubRect.top() + 7);
+ iconSubRect.setLeft(iconSubRect.left() + 7);
+
+ int sizing = fontMetrics.height();
+ int even = ( (sizing - 1) % 2 );
+
+ iconSubRect.setHeight(sizing - even);
+ iconSubRect.setWidth(sizing - even);
+ painter->drawRect(iconSubRect);
+
+
+ /*
+ if(collapsed)
+ painter->drawText(iconSubRect, Qt::AlignHCenter | Qt::AlignVCenter, "+");
+ else
+ painter->drawText(iconSubRect, Qt::AlignHCenter | Qt::AlignVCenter, "-");
+ */
+ painter->setBrush(option.palette.text());
+ painter->fillRect(iconSubRect.x(), iconSubRect.y() + iconSubRect.height() / 2,
+ iconSubRect.width(), 2, penColor);
+ if (collapsed)
+ {
+ painter->fillRect(iconSubRect.x() + iconSubRect.width() / 2, iconSubRect.y(), 2,
+ iconSubRect.height(), penColor);
+ }
+
+ painter->restore();
+ }
+ //END: checkboxy thing
+
+ //BEGIN: text
+ {
+ QRect textRect(option.rect);
+ textRect.setTop(textRect.top() + 7);
+ textRect.setLeft(textRect.left() + 7 + fontMetrics.height() + 7);
+ textRect.setHeight(fontMetrics.height());
+ textRect.setRight(textRect.right() - 7);
+
+ painter->save();
+ painter->setFont(font);
+ QColor penColor(option.palette.text().color());
+ penColor.setAlphaF(0.6);
+ painter->setPen(penColor);
+ painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text);
+ painter->restore();
+ }
+ //END: text
}
int VisualGroup::totalHeight() const
{
- return headerHeight() + 5 + contentHeight(); // FIXME: wtf is that '5'?
+ return headerHeight() + 5 + contentHeight(); // FIXME: wtf is that '5'?
}
int VisualGroup::headerHeight() const
{
- QFont font(QApplication::font());
+ QFont font(QApplication::font());
font.setBold(true);
QFontMetrics fontMetrics(font);
const int height = fontMetrics.height() + 1 /* 1 pixel-width gradient */
+ 11 /* top and bottom separation */;
return height;
- /*
- int raw = view->viewport()->fontMetrics().height() + 4;
- // add english. maybe. depends on font height.
- if (raw % 2 == 0)
- raw++;
- return std::min(raw, 25);
- */
+ /*
+ int raw = view->viewport()->fontMetrics().height() + 4;
+ // add english. maybe. depends on font height.
+ if (raw % 2 == 0)
+ raw++;
+ return std::min(raw, 25);
+ */
}
int VisualGroup::contentHeight() const
{
- if (collapsed)
- {
- return 0;
- }
- auto last = rows[numRows() - 1];
- return last.top + last.height;
+ if (collapsed)
+ {
+ return 0;
+ }
+ auto last = rows[numRows() - 1];
+ return last.top + last.height;
}
int VisualGroup::numRows() const
{
- return rows.size();
+ return rows.size();
}
int VisualGroup::verticalPosition() const
{
- return m_verticalPosition;
+ return m_verticalPosition;
}
QList<QModelIndex> VisualGroup::items() const
{
- QList<QModelIndex> indices;
- for (int i = 0; i < view->model()->rowCount(); ++i)
- {
- const QModelIndex index = view->model()->index(i, 0);
- if (index.data(GroupViewRoles::GroupRole).toString() == text)
- {
- indices.append(index);
- }
- }
- return indices;
+ QList<QModelIndex> indices;
+ for (int i = 0; i < view->model()->rowCount(); ++i)
+ {
+ const QModelIndex index = view->model()->index(i, 0);
+ if (index.data(GroupViewRoles::GroupRole).toString() == text)
+ {
+ indices.append(index);
+ }
+ }
+ return indices;
}
diff --git a/application/groupview/VisualGroup.h b/application/groupview/VisualGroup.h
index 2caac49f..356a6da2 100644
--- a/application/groupview/VisualGroup.h
+++ b/application/groupview/VisualGroup.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,81 +26,81 @@ class QModelIndex;
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];
- }
+ 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 */
- VisualGroup(const QString &text, GroupView *view);
- VisualGroup(const VisualGroup *other);
+ VisualGroup(const QString &text, GroupView *view);
+ VisualGroup(const VisualGroup *other);
/* data */
- GroupView *view = nullptr;
- QString text;
- bool collapsed = false;
- QVector<VisualRow> rows;
- int firstItemIndex = 0;
- int m_verticalPosition = 0;
+ GroupView *view = nullptr;
+ QString text;
+ bool collapsed = false;
+ QVector<VisualRow> rows;
+ int firstItemIndex = 0;
+ int m_verticalPosition = 0;
/* logic */
- /// update the internal list of items and flow them into the rows.
- void update();
+ /// update the internal list of items and flow them into the rows.
+ void update();
- /// draw the header at y-position.
- void drawHeader(QPainter *painter, const QStyleOptionViewItem &option);
+ /// draw the header at y-position.
+ void drawHeader(QPainter *painter, const QStyleOptionViewItem &option);
- /// height of the group, in total. includes a small bit of padding.
- int totalHeight() const;
+ /// height of the group, in total. includes a small bit of padding.
+ int totalHeight() const;
- /// height of the group header, in pixels
- int headerHeight() const;
+ /// height of the group header, in pixels
+ int headerHeight() const;
- /// height of the group content, in pixels
- int contentHeight() const;
+ /// height of the group content, in pixels
+ int contentHeight() const;
- /// the number of visual rows this group has
- int numRows() const;
+ /// the number of visual rows this group has
+ int numRows() const;
- /// actually calculate the above value
- int calculateNumRows() const;
+ /// actually calculate the above value
+ int calculateNumRows() const;
- /// the height at which this group starts, in pixels
- int verticalPosition() 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;
+ /// 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;
+ /// 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;
+ /// x/y position of the given item inside the group (in items!)
+ QPair<int, int> positionOf(const QModelIndex &index) const;
- enum HitResult
- {
- NoHit = 0x0,
- TextHit = 0x1,
- CheckboxHit = 0x2,
- HeaderHit = 0x4,
- BodyHit = 0x8
- };
- Q_DECLARE_FLAGS(HitResults, HitResult)
+ enum HitResult
+ {
+ NoHit = 0x0,
+ TextHit = 0x1,
+ CheckboxHit = 0x2,
+ HeaderHit = 0x4,
+ BodyHit = 0x8
+ };
+ Q_DECLARE_FLAGS(HitResults, HitResult)
- /// shoot! BANG! what did we hit?
- HitResults hitScan (const QPoint &pos) const;
+ /// shoot! BANG! what did we hit?
+ HitResults hitScan (const QPoint &pos) const;
- QList<QModelIndex> items() const;
+ QList<QModelIndex> items() const;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(VisualGroup::HitResults)
diff --git a/application/install_prereqs.cmake.in b/application/install_prereqs.cmake.in
index 2906a4ec..e4408d16 100644
--- a/application/install_prereqs.cmake.in
+++ b/application/install_prereqs.cmake.in
@@ -1,20 +1,20 @@
set(CMAKE_MODULE_PATH "@CMAKE_MODULE_PATH@")
-file(GLOB_RECURSE QTPLUGINS "${CMAKE_INSTALL_PREFIX}/@PLUGIN_DEST_DIR@/*@CMAKE_SHARED_LIBRARY_SUFFIX@")
+file(GLOB_RECURSE QTPLUGINS "${CMAKE_INSTALL_PREFIX}/@PLUGIN_DEST_DIR@/*@CMAKE_SHARED_LIBRARY_SUFFIX@")
function(gp_resolved_file_type_override resolved_file type_var)
- if(resolved_file MATCHES "^/(usr/)?lib/libQt")
- set(${type_var} other PARENT_SCOPE)
- elseif(resolved_file MATCHES "^/(usr/)?lib(.+)?/libxcb-")
- set(${type_var} other PARENT_SCOPE)
- elseif(resolved_file MATCHES "^/(usr/)?lib(.+)?/libicu")
- set(${type_var} other PARENT_SCOPE)
- elseif(resolved_file MATCHES "^/(usr/)?lib(.+)?/libpng")
- set(${type_var} other PARENT_SCOPE)
- elseif(resolved_file MATCHES "^/(usr/)?lib(.+)?/libproxy")
- set(${type_var} other PARENT_SCOPE)
- elseif((resolved_file MATCHES "^/(usr/)?lib(.+)?/libstdc\\+\\+") AND (UNIX AND NOT APPLE))
- set(${type_var} other PARENT_SCOPE)
- endif()
+ if(resolved_file MATCHES "^/(usr/)?lib/libQt")
+ set(${type_var} other PARENT_SCOPE)
+ elseif(resolved_file MATCHES "^/(usr/)?lib(.+)?/libxcb-")
+ set(${type_var} other PARENT_SCOPE)
+ elseif(resolved_file MATCHES "^/(usr/)?lib(.+)?/libicu")
+ set(${type_var} other PARENT_SCOPE)
+ elseif(resolved_file MATCHES "^/(usr/)?lib(.+)?/libpng")
+ set(${type_var} other PARENT_SCOPE)
+ elseif(resolved_file MATCHES "^/(usr/)?lib(.+)?/libproxy")
+ set(${type_var} other PARENT_SCOPE)
+ elseif((resolved_file MATCHES "^/(usr/)?lib(.+)?/libstdc\\+\\+") AND (UNIX AND NOT APPLE))
+ set(${type_var} other PARENT_SCOPE)
+ endif()
endfunction()
set(gp_tool "@CMAKE_GP_TOOL@")
diff --git a/application/main.cpp b/application/main.cpp
index 2f90f2b3..c871bf1b 100644
--- a/application/main.cpp
+++ b/application/main.cpp
@@ -16,46 +16,47 @@
int main(int argc, char *argv[])
{
#ifdef BREAK_INFINITE_LOOP
- while(true)
- {
- std::this_thread::sleep_for(std::chrono::milliseconds(250));
- }
+ while(true)
+ {
+ std::this_thread::sleep_for(std::chrono::milliseconds(250));
+ }
#endif
#ifdef BREAK_EXCEPTION
- throw 42;
+ throw 42;
#endif
#ifdef BREAK_RETURN
- return 42;
+ return 42;
#endif
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
- QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+ QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+ QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif
- // initialize Qt
- MultiMC app(argc, argv);
+ // initialize Qt
+ MultiMC app(argc, argv);
- switch (app.status())
- {
- case MultiMC::StartingUp:
- case MultiMC::Initialized:
- {
- Q_INIT_RESOURCE(multimc);
- Q_INIT_RESOURCE(backgrounds);
- Q_INIT_RESOURCE(assets);
+ switch (app.status())
+ {
+ case MultiMC::StartingUp:
+ case MultiMC::Initialized:
+ {
+ Q_INIT_RESOURCE(multimc);
+ Q_INIT_RESOURCE(backgrounds);
+ Q_INIT_RESOURCE(assets);
- Q_INIT_RESOURCE(pe_dark);
- Q_INIT_RESOURCE(pe_light);
- Q_INIT_RESOURCE(pe_blue);
- Q_INIT_RESOURCE(pe_colored);
- Q_INIT_RESOURCE(OSX);
- Q_INIT_RESOURCE(iOS);
- Q_INIT_RESOURCE(flat);
- return app.exec();
- }
- case MultiMC::Failed:
- return 1;
- case MultiMC::Succeeded:
- return 0;
- }
+ Q_INIT_RESOURCE(pe_dark);
+ Q_INIT_RESOURCE(pe_light);
+ Q_INIT_RESOURCE(pe_blue);
+ Q_INIT_RESOURCE(pe_colored);
+ Q_INIT_RESOURCE(OSX);
+ Q_INIT_RESOURCE(iOS);
+ Q_INIT_RESOURCE(flat);
+ return app.exec();
+ }
+ case MultiMC::Failed:
+ return 1;
+ case MultiMC::Succeeded:
+ return 0;
+ }
}
diff --git a/application/package/linux/MultiMC b/application/package/linux/MultiMC
index 2d4be9f0..da6373bc 100755
--- a/application/package/linux/MultiMC
+++ b/application/package/linux/MultiMC
@@ -2,10 +2,10 @@
# Basic start script for running MultiMC with the libs packaged with it.
function printerror {
- printf "$1"
- if which zenity >/dev/null; then zenity --error --text="$1" &>/dev/null;
- elif which kdialog >/dev/null; then kdialog --error "$1" &>/dev/null;
- fi
+ printf "$1"
+ if which zenity >/dev/null; then zenity --error --text="$1" &>/dev/null;
+ elif which kdialog >/dev/null; then kdialog --error "$1" &>/dev/null;
+ fi
}
if [[ $EUID -eq 0 ]]; then
@@ -28,66 +28,66 @@ export QT_FONTPATH="${MMC_DIR}/fonts"
# Detect missing dependencies...
DEPS_LIST=`ldd "${MMC_DIR}"/plugins/*/*.so 2>/dev/null | grep "not found" | sort -u | awk -vORS=", " '{ print $1 }'`
if [ "x$DEPS_LIST" = "x" ]; then
- # We have all our dependencies. Run MultiMC.
- echo "No missing dependencies found."
+ # We have all our dependencies. Run MultiMC.
+ echo "No missing dependencies found."
- # Just to be sure...
- chmod +x "${MMC_DIR}/bin/MultiMC"
+ # Just to be sure...
+ chmod +x "${MMC_DIR}/bin/MultiMC"
- # Run MultiMC
- "${MMC_DIR}/bin/MultiMC" -d "${MMC_DIR}" "$@"
+ # Run MultiMC
+ "${MMC_DIR}/bin/MultiMC" -d "${MMC_DIR}" "$@"
- # Run MultiMC in valgrind
- # valgrind --log-file="valgrind.log" --leak-check=full --track-origins=yes "${MMC_DIR}/bin/MultiMC" -d "${MMC_DIR}" "$@"
+ # Run MultiMC in valgrind
+ # valgrind --log-file="valgrind.log" --leak-check=full --track-origins=yes "${MMC_DIR}/bin/MultiMC" -d "${MMC_DIR}" "$@"
- # Run MultiMC with callgrind, delay instrumentation
- # valgrind --log-file="valgrind.log" --tool=callgrind --instr-atstart=no "${MMC_DIR}/bin/MultiMC" -d "${MMC_DIR}" "$@"
- # use callgrind_control -i on/off to profile actions
+ # Run MultiMC with callgrind, delay instrumentation
+ # valgrind --log-file="valgrind.log" --tool=callgrind --instr-atstart=no "${MMC_DIR}/bin/MultiMC" -d "${MMC_DIR}" "$@"
+ # use callgrind_control -i on/off to profile actions
- # Exit with MultiMC's exit code.
- exit $?
+ # Exit with MultiMC's exit code.
+ exit $?
else
- # apt
- if which apt-file &>/dev/null; then
- LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
- COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do apt-file -l search $LIBRARY; done`
- COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
- INSTALL_CMD="sudo apt-get install $COMMAND_LIBS"
- # pacman
- elif which pkgfile &>/dev/null; then
- LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
- COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do pkgfile $LIBRARY; done`
- COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
- INSTALL_CMD="sudo pacman -S $COMMAND_LIBS"
- # dnf
- elif which dnf &>/dev/null; then
- LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
- COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do dnf whatprovides -q $LIBRARY; done`
- COMMAND_LIBS=`echo "$COMMAND_LIBS" | grep -v 'Repo' | sort -u | awk -vORS=" " '{ print $1 }'`
- INSTALL_CMD="sudo dnf install $COMMAND_LIBS"
- # yum
- elif which yum &>/dev/null; then
- LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
- COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do yum whatprovides $LIBRARY; done`
- COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
- INSTALL_CMD="sudo yum install $COMMAND_LIBS"
- # zypper
- elif which zypper &>/dev/null; then
- LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
- COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do zypper wp $LIBRARY; done`
- COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
- INSTALL_CMD="sudo zypper install $COMMAND_LIBS"
- # emerge
- elif which pfl &>/dev/null; then
- LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
- COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do pfl $LIBRARY; done`
- COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
- INSTALL_CMD="sudo emerge $COMMAND_LIBS"
- fi
+ # apt
+ if which apt-file &>/dev/null; then
+ LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
+ COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do apt-file -l search $LIBRARY; done`
+ COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
+ INSTALL_CMD="sudo apt-get install $COMMAND_LIBS"
+ # pacman
+ elif which pkgfile &>/dev/null; then
+ LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
+ COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do pkgfile $LIBRARY; done`
+ COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
+ INSTALL_CMD="sudo pacman -S $COMMAND_LIBS"
+ # dnf
+ elif which dnf &>/dev/null; then
+ LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
+ COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do dnf whatprovides -q $LIBRARY; done`
+ COMMAND_LIBS=`echo "$COMMAND_LIBS" | grep -v 'Repo' | sort -u | awk -vORS=" " '{ print $1 }'`
+ INSTALL_CMD="sudo dnf install $COMMAND_LIBS"
+ # yum
+ elif which yum &>/dev/null; then
+ LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
+ COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do yum whatprovides $LIBRARY; done`
+ COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
+ INSTALL_CMD="sudo yum install $COMMAND_LIBS"
+ # zypper
+ elif which zypper &>/dev/null; then
+ LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
+ COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do zypper wp $LIBRARY; done`
+ COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
+ INSTALL_CMD="sudo zypper install $COMMAND_LIBS"
+ # emerge
+ elif which pfl &>/dev/null; then
+ LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
+ COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do pfl $LIBRARY; done`
+ COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
+ INSTALL_CMD="sudo emerge $COMMAND_LIBS"
+ fi
- MESSAGE="Error: MultiMC is missing the following libraries that it needs to work correctly:\n\t${DEPS_LIST}\nPlease install them from your distribution's package manager."
- MESSAGE="$MESSAGE\n\nHint (please apply common sense): $INSTALL_CMD\n"
+ MESSAGE="Error: MultiMC is missing the following libraries that it needs to work correctly:\n\t${DEPS_LIST}\nPlease install them from your distribution's package manager."
+ MESSAGE="$MESSAGE\n\nHint (please apply common sense): $INSTALL_CMD\n"
- printerror "$MESSAGE"
- exit 1
+ printerror "$MESSAGE"
+ exit 1
fi
diff --git a/application/package/linux/multimc.desktop b/application/package/linux/multimc.desktop
index 514b330f..770f24f1 100755
--- a/application/package/linux/multimc.desktop
+++ b/application/package/linux/multimc.desktop
@@ -8,3 +8,4 @@ Terminal=false
Exec=multimc
Icon=multimc
Categories=Game
+Keywords=game;minecraft;
diff --git a/application/package/ubuntu/multimc/DEBIAN/control b/application/package/ubuntu/multimc/DEBIAN/control
new file mode 100644
index 00000000..34c223a5
--- /dev/null
+++ b/application/package/ubuntu/multimc/DEBIAN/control
@@ -0,0 +1,12 @@
+Package: multimc
+Version: 1.3-1
+Architecture: all
+Maintainer: Petr Mrázek <peterix@gmail.com>
+Section: games
+Priority: optional
+Installed-Size: 75
+Depends: zenity, desktop-file-utils, qt5-default
+Recommends: openjdk-8-jre
+Homepage: http://multimc.org
+Description: A local install wrapper for MultiMC
+
diff --git a/application/package/ubuntu/multimc/DEBIAN/postrm b/application/package/ubuntu/multimc/DEBIAN/postrm
new file mode 100755
index 00000000..f9bbc8a7
--- /dev/null
+++ b/application/package/ubuntu/multimc/DEBIAN/postrm
@@ -0,0 +1,3 @@
+#!/bin/sh
+set -e
+update-desktop-database
diff --git a/application/package/ubuntu/multimc/opt/multimc/icon.svg b/application/package/ubuntu/multimc/opt/multimc/icon.svg
new file mode 100644
index 00000000..8bb0e289
--- /dev/null
+++ b/application/package/ubuntu/multimc/opt/multimc/icon.svg
@@ -0,0 +1,353 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="68.26667"
+ height="68.26667"
+ id="svg4427"
+ version="1.1"
+ inkscape:version="0.92.1 r"
+ sodipodi:docname="multimc-smooth-biginfinity.svg"
+ inkscape:export-filename="/home/peterix/playground/MultiMC-icons/multimc-smooth-biginfinity.png"
+ inkscape:export-xdpi="180"
+ inkscape:export-ydpi="180">
+ <defs
+ id="defs4429">
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4809">
+ <stop
+ style="stop-color:#98c867;stop-opacity:1"
+ offset="0"
+ id="stop4805" />
+ <stop
+ style="stop-color:#5c9a33;stop-opacity:1"
+ offset="1"
+ id="stop4807" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5668"
+ inkscape:collect="always">
+ <stop
+ id="stop5670"
+ offset="0"
+ style="stop-color:#75b54b;stop-opacity:1;" />
+ <stop
+ id="stop5672"
+ offset="1"
+ style="stop-color:#75b54b;stop-opacity:0.6" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5084"
+ inkscape:collect="always">
+ <stop
+ id="stop5086"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:0.8" />
+ <stop
+ id="stop5088"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0.35" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5668"
+ id="linearGradient5072"
+ x1="6.7342591"
+ y1="28.510933"
+ x2="50.506943"
+ y2="61.773685"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-0.01532073,-0.00938002)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5084"
+ id="linearGradient5082"
+ x1="14.312115"
+ y1="9.7948904"
+ x2="44.097023"
+ y2="82.973114"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5668"
+ id="linearGradient3281"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-0.01532073,-0.00938002)"
+ x1="6.7342591"
+ y1="28.510933"
+ x2="50.506943"
+ y2="61.773685" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5668"
+ id="linearGradient3283"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-0.01532073,-0.00938002)"
+ x1="6.7342591"
+ y1="28.510933"
+ x2="50.506943"
+ y2="61.773685" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5668"
+ id="linearGradient3286"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.2671525,0,0,0.89790119,-0.01941371,-0.00842234)"
+ x1="6.7342591"
+ y1="28.510933"
+ x2="50.506943"
+ y2="61.773685" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5084"
+ id="linearGradient3288"
+ gradientUnits="userSpaceOnUse"
+ x1="14.312115"
+ y1="9.7948904"
+ x2="44.097023"
+ y2="82.973114" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5084"
+ id="linearGradient3290"
+ gradientUnits="userSpaceOnUse"
+ x1="14.312115"
+ y1="9.7948904"
+ x2="44.097023"
+ y2="82.973114" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5084"
+ id="linearGradient3293"
+ gradientUnits="userSpaceOnUse"
+ x1="14.312115"
+ y1="9.7948904"
+ x2="44.097023"
+ y2="82.973114"
+ gradientTransform="scale(1.2671525,0.89790119)" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient5580">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.0627451"
+ offset="0"
+ id="stop5576" />
+ <stop
+ style="stop-color:#322217;stop-opacity:0.58823532"
+ offset="1"
+ id="stop5578" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3999"
+ inkscape:collect="always">
+ <stop
+ id="stop3995"
+ offset="0"
+ style="stop-color:#a3704b;stop-opacity:1" />
+ <stop
+ id="stop3997"
+ offset="1"
+ style="stop-color:#6a4a33;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2727"
+ inkscape:collect="always">
+ <stop
+ id="stop2723"
+ offset="0"
+ style="stop-color:#966c4a;stop-opacity:1" />
+ <stop
+ id="stop2725"
+ offset="1"
+ style="stop-color:#593d29;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2727"
+ id="linearGradient2050"
+ gradientUnits="userSpaceOnUse"
+ x1="36.546478"
+ y1="33.80484"
+ x2="86.415741"
+ y2="97.065842" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3999"
+ id="radialGradient2052"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-9.105292e-4,-0.00104444)"
+ cx="34.133331"
+ cy="34.133335"
+ fx="34.133331"
+ fy="34.133335"
+ r="29.866665" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5580"
+ id="linearGradient2140"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-0.0010513,-9.083059e-4)"
+ x1="29.866674"
+ y1="29.867579"
+ x2="38.400005"
+ y2="38.400913" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5084"
+ id="linearGradient4790"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.2671525,0,0,0.89790119,-0.82864077,-1.0012743)"
+ x1="14.312115"
+ y1="9.7948904"
+ x2="44.097023"
+ y2="82.973114" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4809"
+ id="radialGradient4803"
+ cx="-42.66758"
+ cy="-34.134373"
+ fx="-42.66758"
+ fy="-34.134373"
+ r="34.132812"
+ gradientTransform="matrix(1.7500268,0.1250019,-0.01781176,0.24936465,95.393964,18.110151)"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="3.6203867"
+ inkscape:cx="52.171166"
+ inkscape:cy="11.292073"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:document-units="px"
+ inkscape:grid-bbox="true"
+ inkscape:window-width="1368"
+ inkscape:window-height="905"
+ inkscape:window-x="2452"
+ inkscape:window-y="723"
+ inkscape:window-maximized="0"
+ inkscape:snap-bbox="true"
+ inkscape:bbox-paths="false"
+ inkscape:snap-bbox-edge-midpoints="false"
+ inkscape:bbox-nodes="true"
+ inkscape:snap-bbox-midpoints="false"
+ inkscape:snap-smooth-nodes="true"
+ inkscape:snap-midpoints="false"
+ inkscape:snap-intersection-paths="true"
+ inkscape:object-paths="true"
+ inkscape:snap-object-midpoints="true"
+ inkscape:snap-text-baseline="true"
+ inkscape:snap-center="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid4446"
+ empspacing="16"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true"
+ spacingx="4.2666667"
+ spacingy="4.2666667"
+ originx="0"
+ originy="0" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata4432">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer">
+ <g
+ id="g2048"
+ transform="translate(9.113e-4,0.00104183)">
+ <rect
+ rx="8.5333338"
+ ry="8.5333338"
+ style="fill:url(#linearGradient2050);fill-opacity:1;stroke:none;stroke-width:17.06666756"
+ id="rect2026"
+ width="68.26667"
+ height="68.26667"
+ x="-1.3322676e-15"
+ y="3.0270508e-06" />
+ <rect
+ rx="4.2666626"
+ y="4.2656283"
+ x="4.2657552"
+ height="59.733334"
+ width="59.73333"
+ id="rect2028"
+ style="fill:url(#radialGradient2052);fill-opacity:1;stroke:none;stroke-width:14.93333435"
+ ry="4.2666669" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4811"
+ d="m 4.2669272,4.2645856 -9.11e-4,8.5333334 h 4.267577 v 4.267579 h 8.5332038 v 4.265625 h 4.265625 V 8.5322946 H 25.6 v 8.5332034 h 4.265625 v -4.267579 h 4.267578 v 8.533204 h 4.265625 v -4.265625 h 4.267578 v 4.265625 h 4.267579 v -4.265625 h 4.265624 v -4.267579 h 4.267579 v 4.267579 h 8.533203 l -1.3e-4,-12.8009124 z"
+ style="opacity:0.6;fill:#593d29;fill-opacity:1;stroke:none;stroke-width:17.06666756"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccc" />
+ <path
+ style="fill:url(#radialGradient4803);fill-opacity:1;stroke:none;stroke-width:17.06666756"
+ d="m 8.5329442,-0.0018207 c -4.7274675,0 -8.5332035,3.805736 -8.5332035,8.533203 v 4.2675787 h 4.265625 V 8.5313823 c 0,-0.521698 0.105433,-1.01339 0.27539,-1.47461 -0.169616,0.460814 -0.27539,0.953462 -0.27539,1.47461 h 4.2675785 v 4.2675787 h 4.2656248 4.267578 v 4.265625 h 4.265625 V 12.798961 8.5313823 4.2657573 h 4.267578 v 4.265625 4.2675787 h 4.265625 V 8.5313823 h 4.267578 v 4.2675787 4.265625 h 4.265625 v -4.265625 h 4.267578 v 4.265625 h 4.267579 v -4.265625 h 4.265624 V 8.5313823 h 4.267579 v 4.2675787 h 4.265625 4.267578 V 8.5313823 h 4.265625 c 0,-4.727467 -3.805737,-8.533203 -8.533203,-8.533203 z m -3.019531,5.513671 c -0.318089,0.317888 -0.570428,0.695824 -0.7753915,1.101563 0.2048795,-0.405231 0.4576385,-0.784012 0.7753915,-1.101563 z"
+ id="path4794"
+ inkscape:connector-curvature="0" />
+ <path
+ style="opacity:1;fill:url(#linearGradient2140);fill-opacity:1;stroke:none;stroke-width:17.06666756"
+ d="m 8.5322887,-9.083059e-4 c -4.72747,0 -8.5332,3.8057359059 -8.5332,8.5332029059 V 59.731515 c 0,4.727467 3.80573,8.535156 8.5332,8.535156 H 59.731502 c 4.72747,0 8.5332,-3.807689 8.5332,-8.535156 V 8.5322946 c 0,-4.727467 -3.80573,-8.5332029059 -8.5332,-8.5332029059 z m 0,4.2675779059 H 59.731502 c 2.36373,0 4.26758,1.901892 4.26758,4.265625 V 59.731515 c 0,2.363733 -1.90385,4.267578 -4.26758,4.267578 H 8.5322887 c -2.36373,0 -4.26758,-1.903845 -4.26758,-4.267578 V 8.5322946 c 0,-2.363733 1.90385,-4.265625 4.26758,-4.265625 z"
+ id="path2046"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g1092">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4786"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:76.18933868px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient4790);fill-opacity:1;stroke:none;stroke-width:1.06666672;opacity:0.5"
+ d="m 38.886673,44.940882 c -0.974277,-0.801673 -2.231353,-2.137814 -3.771231,-4.008427 -2.105641,2.672298 -4.085536,4.598569 -5.939688,5.778816 -2.325625,1.425227 -5.295467,2.137836 -8.909534,2.137828 -4.242656,8e-6 -7.762467,-1.124578 -10.5594458,-3.37376 C 6.7526311,43.114834 5.275567,39.986037 5.2755773,36.088937 5.275567,32.347763 6.7526311,29.207831 9.7067742,26.669132 12.346618,24.419991 15.897857,23.295407 20.360501,23.295373 c 2.294138,3.4e-5 4.289747,0.334069 5.986829,1.002107 1.979863,0.73491 3.645488,1.737016 4.996881,3.00632 1.257039,1.135751 2.514115,2.471891 3.771231,4.008428 2.105563,-2.672257 4.085457,-4.598527 5.939689,-5.778816 2.325544,-1.425186 5.295385,-2.137794 8.909533,-2.137828 4.242577,3.4e-5 7.762388,1.124618 10.559447,3.37376 2.954063,2.360546 4.431127,5.489343 4.431197,9.386401 -7e-5,3.741216 -1.477134,6.881147 -4.431197,9.419806 -2.639925,2.24918 -6.191163,3.373767 -10.653727,3.373758 -2.294219,9e-6 -4.289826,-0.334026 -5.98683,-1.002106 -1.697101,-0.601255 -3.362726,-1.603361 -4.996881,-3.006321 M 19.747676,44.473233 c 5.185412,1.1e-5 9.333763,-2.672271 12.445062,-8.016856 -3.991253,-5.834464 -8.139602,-8.751705 -12.445062,-8.751733 -3.142715,2.8e-5 -5.515446,0.801713 -7.118198,2.405057 -1.728498,1.71474 -2.592737,3.707818 -2.592722,5.979236 -1.5e-5,2.494152 0.864224,4.509499 2.592722,6.046046 1.759887,1.558846 4.132618,2.338261 7.118198,2.33825 M 50.483209,27.77145 c -4.682663,2.9e-5 -8.831013,2.672312 -12.445062,8.016856 3.959745,5.834503 8.108095,8.751746 12.445062,8.751733 3.142633,1.3e-5 5.515364,-0.801671 7.118198,-2.405056 1.728416,-1.714701 2.592656,-3.707778 2.592722,-5.979238 -6.6e-5,-2.49411 -0.864306,-4.509456 -2.592722,-6.046044 -1.759968,-1.558805 -4.132699,-2.338222 -7.118198,-2.338251" />
+ <path
+ d="m 39.715314,45.942156 c -0.974277,-0.801673 -2.231353,-2.137814 -3.771231,-4.008427 -2.105641,2.672298 -4.085536,4.598569 -5.939688,5.778816 -2.325625,1.425227 -5.295467,2.137836 -8.909534,2.137828 -4.242656,8e-6 -7.762467,-1.124578 -10.559446,-3.37376 -2.9541431,-2.360505 -4.4312072,-5.489302 -4.4311969,-9.386402 -1.03e-5,-3.741174 1.4770538,-6.881106 4.4311969,-9.419805 2.639844,-2.249141 6.191083,-3.373725 10.653727,-3.373759 2.294138,3.4e-5 4.289747,0.334069 5.986829,1.002107 1.979863,0.73491 3.645488,1.737016 4.996881,3.00632 1.257039,1.135751 2.514115,2.471891 3.771231,4.008428 2.105563,-2.672257 4.085457,-4.598527 5.939689,-5.778816 2.325544,-1.425186 5.295385,-2.137794 8.909533,-2.137828 4.242577,3.4e-5 7.762388,1.124618 10.559447,3.37376 2.954063,2.360546 4.431127,5.489343 4.431197,9.386401 -7e-5,3.741216 -1.477134,6.881147 -4.431197,9.419806 -2.639925,2.24918 -6.191163,3.373767 -10.653727,3.373758 -2.294219,9e-6 -4.289826,-0.334026 -5.98683,-1.002106 -1.697101,-0.601255 -3.362726,-1.603361 -4.996881,-3.006321 M 20.576317,45.474507 c 5.185412,1.1e-5 9.333763,-2.672271 12.445062,-8.016856 -3.991253,-5.834464 -8.139602,-8.751705 -12.445062,-8.751733 -3.142715,2.8e-5 -5.515446,0.801713 -7.118198,2.405057 -1.728498,1.71474 -2.592737,3.707818 -2.592722,5.979236 -1.5e-5,2.494152 0.864224,4.509499 2.592722,6.046046 1.759887,1.558846 4.132618,2.338261 7.118198,2.33825 M 51.31185,28.772724 c -4.682663,2.9e-5 -8.831013,2.672312 -12.445062,8.016856 3.959745,5.834503 8.108095,8.751746 12.445062,8.751733 3.142633,1.3e-5 5.515364,-0.801671 7.118198,-2.405056 1.728416,-1.714701 2.592656,-3.707778 2.592722,-5.979238 -6.6e-5,-2.49411 -0.864306,-4.509456 -2.592722,-6.046044 C 56.67008,29.55217 54.297349,28.772753 51.31185,28.772724"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:76.18933868px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient3293);fill-opacity:1;stroke:none;stroke-width:1.06666672;opacity:0.5"
+ id="path3279"
+ inkscape:connector-curvature="0" />
+ <path
+ d="m 37.904564,42.951873 c -0.974278,-0.801672 -2.231352,-2.137814 -3.771231,-4.008428 -2.105642,2.672298 -4.085537,4.598568 -5.939688,5.778817 -2.325625,1.425227 -5.295466,2.137836 -8.909534,2.137828 -4.242656,8e-6 -7.762467,-1.124577 -10.5594464,-3.37376 -2.9541428,-2.360505 -4.4312068,-5.489302 -4.4311963,-9.386401 -1.05e-5,-3.741175 1.4770535,-6.881107 4.4311963,-9.419805 2.6398444,-2.249142 6.1910824,-3.373727 10.6537284,-3.37376 2.294137,3.3e-5 4.289745,0.334068 5.986829,1.002107 1.979863,0.734909 3.645487,1.737016 4.99688,3.00632 1.257039,1.13575 2.514116,2.471891 3.771231,4.008428 2.105562,-2.672257 4.085456,-4.598528 5.939689,-5.778817 2.325544,-1.425185 5.295387,-2.137795 8.909534,-2.137828 4.242576,3.3e-5 7.762387,1.12462 10.559446,3.373761 2.954062,2.360545 4.431127,5.489343 4.431197,9.386401 -7e-5,3.741216 -1.477135,6.881148 -4.431197,9.419805 -2.639924,2.249182 -6.191164,3.373767 -10.653728,3.37376 -2.294217,7e-6 -4.289826,-0.334028 -5.986828,-1.002107 -1.697101,-0.601254 -3.362727,-1.603361 -4.996882,-3.006321 m -19.138997,-0.46765 c 5.185412,1.3e-5 9.333762,-2.67227 12.445062,-8.016856 -3.991252,-5.834462 -8.139602,-8.751704 -12.445062,-8.751733 -3.142714,2.9e-5 -5.515444,0.801714 -7.118198,2.405056 -1.7284972,1.714743 -2.5927368,3.707819 -2.5927216,5.979239 -1.52e-5,2.49415 0.8642244,4.509496 2.5927216,6.046045 1.759888,1.558845 4.132618,2.338262 7.118198,2.338249 M 49.5011,25.782442 c -4.682663,2.8e-5 -8.831014,2.672311 -12.445063,8.016855 3.959745,5.834504 8.108096,8.751745 12.445063,8.751733 3.142634,1.2e-5 5.515365,-0.801673 7.118198,-2.405056 1.728417,-1.7147 2.592657,-3.707778 2.592721,-5.979238 -6.4e-5,-2.49411 -0.864304,-4.509456 -2.592721,-6.046046 C 54.85933,26.561886 52.486599,25.78247 49.5011,25.782442"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:76.18933868px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient3286);fill-opacity:1;stroke:none;stroke-width:1.06666672"
+ id="path3272"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="ccscsccccccccccccccccccccscscccccsccscccccc"
+ inkscape:connector-curvature="0"
+ id="text5100"
+ d="m 19.4,21.166667 c -4.462644,3.3e-5 -8.026822,1.150858 -10.6666667,3.4 -2.9541428,2.538698 -4.4333436,5.658825 -4.4333333,9.4 -1.03e-5,3.897098 1.4791905,7.039495 4.4333333,9.4 -1.622701,-2.044271 -2.433341,-4.51168 -2.4333333,-7.4 -1.03e-5,-3.741175 1.4791905,-6.861302 4.433333,-9.4 2.639845,-2.249142 6.204023,-3.399967 10.666667,-3.4 2.294138,3.3e-5 4.302916,0.365295 6,1.033333 1.979862,0.73491 3.615274,1.730695 4.966667,3 0.06836,0.06177 0.131637,0.137049 0.2,0.2 -0.731813,-0.797005 -1.468213,-1.538822 -2.2,-2.2 -1.351393,-1.269305 -2.986805,-2.26509 -4.966667,-3 -1.697084,-0.668038 -3.705862,-1.0333 -6,-1.033333 z m 29.6,0.1 c -3.614148,3.3e-5 -6.574457,0.74148 -8.9,2.166666 -1.818222,1.157367 -3.923451,3.291388 -5.983333,5.883334 0.618278,0.658774 1.248369,1.377605 1.866666,2.133333 2.105562,-2.672257 4.262434,-4.836378 6.116667,-6.016667 2.325543,-1.425186 5.285852,-2.166633 8.9,-2.166666 4.242576,3.3e-5 7.769607,1.150858 10.566667,3.4 -0.570388,-0.722129 -1.227721,-1.382884 -2,-2 C 56.769607,22.417525 53.242576,21.2667 49,21.266667 Z m 8.866667,8.1 c 0.9092,1.305235 1.366619,2.857751 1.366666,4.666666 -6.5e-5,2.271461 -0.871584,4.285301 -2.6,6 -1.602834,1.603384 -3.957366,2.400012 -7.1,2.4 -2.653707,8e-6 -5.320858,-1.032242 -7.833333,-3.216666 3.136636,3.509305 6.469807,5.216676 9.833333,5.216666 3.142634,1.2e-5 5.497166,-0.796616 7.1,-2.4 1.728416,-1.714699 2.599935,-3.728539 2.6,-6 -6.5e-5,-2.49411 -0.871584,-4.496744 -2.6,-6.033333 -0.24943,-0.220921 -0.49262,-0.443723 -0.766666,-0.633333 z m -26.633334,4.966666 c -3.1113,5.344585 -7.247921,8.033345 -12.433333,8.033334 -2.58055,1e-5 -4.543473,-0.352086 -6.208333,-1.516667 0.348871,0.50642 0.590094,0.752276 1.075,1.183333 1.759888,1.558846 4.147753,2.333345 7.133333,2.333334 5.185412,1.1e-5 9.322033,-2.688749 12.433333,-8.033334 z m 4.933334,6.5 c -0.04103,0.05207 -0.09239,0.08182 -0.133334,0.133334 0.687326,0.744419 1.306949,1.359747 1.833334,1.8 -0.529404,-0.580895 -1.078447,-1.178283 -1.7,-1.933334 z"
+ style="font-style:normal;font-weight:normal;font-size:76.18933868px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;opacity:0.3;fill:#ccff00;fill-opacity:1;stroke:none;stroke-width:1.06666672" />
+ <path
+ sodipodi:nodetypes="ccsccscccccccccccccccccccscscccccsccsccccccc"
+ id="text5058-0"
+ d="m 19.730474,21.54714 c -4.462645,3.3e-5 -8.026823,1.150859 -10.6666669,3.4 -2.9541429,2.538699 -4.433344,5.658826 -4.4333333,9.4 -1.07e-5,3.897099 1.4791904,7.039495 4.4333333,9.4 0.042837,0.03444 0.090155,0.06608 0.1333334,0.1 -2.2392086,-2.228193 -3.3666752,-5.040417 -3.3666667,-8.433333 -1.07e-5,-3.741174 1.4791904,-6.861301 4.4333332,-9.4 2.639844,-2.249141 6.204022,-3.399967 10.666667,-3.4 2.294137,3.3e-5 4.302916,0.365295 6,1.033333 1.870874,0.694455 3.42364,1.628367 4.733333,2.8 -0.314265,-0.308986 -0.652406,-0.582729 -0.966667,-0.866666 -1.351393,-1.269305 -2.986804,-2.265091 -4.966666,-3 -1.697084,-0.668039 -3.705863,-1.033301 -6,-1.033334 z m 29.6,0.1 c -3.614149,3.3e-5 -6.574457,0.741481 -8.9,2.166667 -1.813279,1.154221 -3.963039,3.235656 -6.016667,5.816667 0.355649,0.402628 0.711011,0.798625 1.066667,1.233333 2.105561,-2.672257 4.295767,-4.803044 6.15,-5.983333 2.325543,-1.425187 5.285851,-2.166634 8.9,-2.166667 4.22442,3.3e-5 7.742084,1.136734 10.533333,3.366667 -0.36096,-0.367566 -0.745726,-0.696967 -1.166667,-1.033334 -2.797059,-2.249141 -6.32409,-3.399967 -10.566666,-3.4 z m 8.233333,7.333334 c 1.323326,1.449243 1.999942,3.250987 2,5.433333 -6.5e-5,2.27146 -0.871584,4.2853 -2.6,6 -1.602834,1.603383 -3.957366,2.400012 -7.1,2.4 -2.406328,6e-6 -4.776468,-0.90386 -7.066667,-2.7 2.669147,2.483838 5.436929,3.766674 8.266667,3.766667 3.142634,1.1e-5 5.497166,-0.796617 7.1,-2.4 1.728416,-1.7147 2.599935,-3.72854 2.6,-6 -6.5e-5,-2.49411 -0.871584,-4.496745 -2.6,-6.033334 -0.185641,-0.164422 -0.400724,-0.319587 -0.6,-0.466666 z m -26,5.733333 c -3.1113,5.344584 -7.247921,8.033345 -12.433333,8.033333 -2.612382,1.1e-5 -4.759372,-0.60651 -6.433334,-1.8 0.166027,0.176488 0.313947,0.367942 0.5,0.533334 1.759888,1.558845 4.147754,2.333345 7.133334,2.333333 5.185412,1.2e-5 9.322033,-2.688749 12.433333,-8.033333 z m 4.133333,5.566667 c -0.04657,0.05909 -0.08689,0.108298 -0.133333,0.166666 1.038571,1.18897 1.9748,2.169945 2.7,2.766667 0.06249,0.05364 0.137426,0.08086 0.2,0.133333 -0.792178,-0.781249 -1.706288,-1.778539 -2.766667,-3.066666 z"
+ style="font-style:normal;font-weight:normal;font-size:76.18933868px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;opacity:0.6;fill:#ccff00;fill-opacity:1;stroke:none;stroke-width:1.06666672"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+</svg>
diff --git a/application/package/ubuntu/multimc/opt/multimc/run.sh b/application/package/ubuntu/multimc/opt/multimc/run.sh
new file mode 100755
index 00000000..c493a513
--- /dev/null
+++ b/application/package/ubuntu/multimc/opt/multimc/run.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+INSTDIR="${XDG_DATA_HOME-$HOME/.local/share}/multimc"
+
+if [ `getconf LONG_BIT` = "64" ]
+then
+ PACKAGE="mmc-stable-lin64.tar.gz"
+else
+ PACKAGE="mmc-stable-lin32.tar.gz"
+fi
+
+deploy() {
+ mkdir -p $INSTDIR
+ cd ${INSTDIR}
+
+ wget --progress=dot:force "https://files.multimc.org/downloads/${PACKAGE}" 2>&1 | sed -u 's/.* \([0-9]\+%\)\ \+\([0-9.]\+.\) \(.*\)/\1\n# Downloading at \2\/s, ETA \3/' | zenity --progress --auto-close --auto-kill --title="Downloading MultiMC..."
+
+ tar -xzf ${PACKAGE} --transform='s,MultiMC/,,'
+ rm ${PACKAGE}
+ chmod +x MultiMC
+}
+
+runmmc() {
+ cd ${INSTDIR}
+ ./MultiMC "$@"
+}
+
+if [[ ! -f ${INSTDIR}/MultiMC ]]; then
+ deploy
+ runmmc "$@"
+else
+ runmmc "$@"
+fi
diff --git a/application/package/ubuntu/multimc/usr/share/applications/multimc.desktop b/application/package/ubuntu/multimc/usr/share/applications/multimc.desktop
new file mode 100755
index 00000000..e0456f89
--- /dev/null
+++ b/application/package/ubuntu/multimc/usr/share/applications/multimc.desktop
@@ -0,0 +1,16 @@
+[Desktop Entry]
+Categories=Game;
+Exec=/opt/multimc/run.sh
+Icon=/opt/multimc/icon.svg
+Keywords=game;Minecraft;
+MimeType=
+Name=MultiMC 5
+Path=
+StartupNotify=true
+Terminal=false
+TerminalOptions=
+Type=Application
+X-DBUS-ServiceName=
+X-DBUS-StartupType=
+X-KDE-SubstituteUID=false
+X-KDE-Username=
diff --git a/application/package/ubuntu/readme.md b/application/package/ubuntu/readme.md
new file mode 100644
index 00000000..5b0d6b27
--- /dev/null
+++ b/application/package/ubuntu/readme.md
@@ -0,0 +1,12 @@
+# What is this?
+A simple ubuntu package for MultiMC that wraps the contains a script that downloads and installs real MultiMC on ubuntu based systems.
+
+It contains a `.desktop` file, an icon, and a simple script that does the heavy lifting.
+
+# How to build this?
+You need dpkg utils. Rename the `multimc` folder to `multimc_1.3-1` and then run:
+```
+fakeroot dpkg-deb --build multimc_1.3-1
+```
+
+Replace the version with whatever is appropriate.
diff --git a/application/pagedialog/PageDialog.cpp b/application/pagedialog/PageDialog.cpp
index 1b5284d2..a1a78d78 100644
--- a/application/pagedialog/PageDialog.cpp
+++ b/application/pagedialog/PageDialog.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,35 +26,36 @@
#include "widgets/PageContainer.h"
PageDialog::PageDialog(BasePageProvider *pageProvider, QString defaultId, QWidget *parent)
- : QDialog(parent)
+ : QDialog(parent)
{
- setWindowTitle(pageProvider->dialogTitle());
- m_container = new PageContainer(pageProvider, defaultId, 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);
+ 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);
+ QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Close);
+ buttons->button(QDialogButtonBox::Close)->setDefault(true);
+ buttons->setContentsMargins(6, 0, 6, 0);
+ 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()));
+ 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()));
+ restoreGeometry(QByteArray::fromBase64(MMC->settings()->get("PagedGeometry").toByteArray()));
}
void PageDialog::closeEvent(QCloseEvent *event)
{
- qDebug() << "Paged dialog close requested";
- if (m_container->prepareToClose())
- {
- qDebug() << "Paged dialog close approved";
- MMC->settings()->set("PagedGeometry", saveGeometry().toBase64());
- qDebug() << "Paged dialog geometry saved";
- QDialog::closeEvent(event);
- }
+ qDebug() << "Paged dialog close requested";
+ if (m_container->prepareToClose())
+ {
+ qDebug() << "Paged dialog close approved";
+ MMC->settings()->set("PagedGeometry", saveGeometry().toBase64());
+ qDebug() << "Paged dialog geometry saved";
+ QDialog::closeEvent(event);
+ }
}
diff --git a/application/pagedialog/PageDialog.h b/application/pagedialog/PageDialog.h
index a287f9c9..b92d90b5 100644
--- a/application/pagedialog/PageDialog.h
+++ b/application/pagedialog/PageDialog.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,15 +21,15 @@
class PageContainer;
class PageDialog : public QDialog
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit PageDialog(BasePageProvider *pageProvider, QString defaultId = QString(), QWidget *parent = 0);
- virtual ~PageDialog() {}
+ explicit PageDialog(BasePageProvider *pageProvider, QString defaultId = QString(), QWidget *parent = 0);
+ virtual ~PageDialog() {}
private
slots:
- virtual void closeEvent(QCloseEvent *event);
+ virtual void closeEvent(QCloseEvent *event);
private:
- PageContainer * m_container;
+ PageContainer * m_container;
};
diff --git a/application/pages/BasePage.h b/application/pages/BasePage.h
index d4547770..2ad56d71 100644
--- a/application/pages/BasePage.h
+++ b/application/pages/BasePage.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,35 +24,35 @@
class BasePage
{
public:
- 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(); }
- void opened()
- {
- isOpened = true;
- openedImpl();
- }
- void closed()
- {
- isOpened = false;
- closedImpl();
- }
- virtual void openedImpl() {}
- virtual void closedImpl() {}
- virtual void setParentContainer(BasePageContainer * container)
- {
- m_container = container;
- };
+ 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(); }
+ void opened()
+ {
+ isOpened = true;
+ openedImpl();
+ }
+ void closed()
+ {
+ isOpened = false;
+ closedImpl();
+ }
+ virtual void openedImpl() {}
+ virtual void closedImpl() {}
+ virtual void setParentContainer(BasePageContainer * container)
+ {
+ m_container = container;
+ };
public:
- int stackIndex = -1;
- int listIndex = -1;
+ int stackIndex = -1;
+ int listIndex = -1;
protected:
- BasePageContainer * m_container = nullptr;
- bool isOpened = false;
+ BasePageContainer * m_container = nullptr;
+ bool isOpened = false;
};
typedef std::shared_ptr<BasePage> BasePagePtr;
diff --git a/application/pages/BasePageContainer.h b/application/pages/BasePageContainer.h
index ff7315c2..f8c7adeb 100644
--- a/application/pages/BasePageContainer.h
+++ b/application/pages/BasePageContainer.h
@@ -3,8 +3,8 @@
class BasePageContainer
{
public:
- virtual ~BasePageContainer(){};
- virtual bool selectPage(QString pageId) = 0;
- virtual void refreshContainer() = 0;
- virtual bool requestClose() = 0;
+ virtual ~BasePageContainer(){};
+ virtual bool selectPage(QString pageId) = 0;
+ virtual void refreshContainer() = 0;
+ virtual bool requestClose() = 0;
};
diff --git a/application/pages/BasePageProvider.h b/application/pages/BasePageProvider.h
index 1cc7458a..ad29f163 100644
--- a/application/pages/BasePageProvider.h
+++ b/application/pages/BasePageProvider.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,46 +22,47 @@
class BasePageProvider
{
public:
- virtual QList<BasePage *> getPages() = 0;
- virtual QString dialogTitle() = 0;
+ virtual QList<BasePage *> getPages() = 0;
+ virtual QString dialogTitle() = 0;
};
class GenericPageProvider : public BasePageProvider
{
- typedef std::function<BasePage *()> PageCreator;
+ typedef std::function<BasePage *()> PageCreator;
public:
- explicit GenericPageProvider(const QString &dialogTitle)
- : m_dialogTitle(dialogTitle)
- {
- }
+ explicit GenericPageProvider(const QString &dialogTitle)
+ : m_dialogTitle(dialogTitle)
+ {
+ }
+ virtual ~GenericPageProvider() {}
- QList<BasePage *> getPages() override
- {
- QList<BasePage *> pages;
- for (PageCreator creator : m_creators)
- {
- pages.append(creator());
- }
- return pages;
- }
- QString dialogTitle() override { return m_dialogTitle; }
+ QList<BasePage *> getPages() override
+ {
+ QList<BasePage *> pages;
+ for (PageCreator creator : m_creators)
+ {
+ pages.append(creator());
+ }
+ return pages;
+ }
+ QString dialogTitle() override { return m_dialogTitle; }
- void setDialogTitle(const QString &title)
- {
- m_dialogTitle = title;
- }
- void addPageCreator(PageCreator page)
- {
- m_creators.append(page);
- }
+ void setDialogTitle(const QString &title)
+ {
+ m_dialogTitle = title;
+ }
+ void addPageCreator(PageCreator page)
+ {
+ m_creators.append(page);
+ }
- template<typename PageClass>
- void addPage()
- {
- addPageCreator([](){return new PageClass();});
- }
+ template<typename PageClass>
+ void addPage()
+ {
+ addPageCreator([](){return new PageClass();});
+ }
private:
- QList<PageCreator> m_creators;
- QString m_dialogTitle;
+ QList<PageCreator> m_creators;
+ QString m_dialogTitle;
};
diff --git a/application/pages/global/AccountListPage.cpp b/application/pages/global/AccountListPage.cpp
index 63943174..c14134f3 100644
--- a/application/pages/global/AccountListPage.cpp
+++ b/application/pages/global/AccountListPage.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
#include "ui_AccountListPage.h"
#include <QItemSelectionModel>
+#include <QMenu>
#include <QDebug>
@@ -34,120 +35,159 @@
#include "MultiMC.h"
AccountListPage::AccountListPage(QWidget *parent)
- : QWidget(parent), ui(new Ui::AccountListPage)
+ : QMainWindow(parent), ui(new Ui::AccountListPage)
{
- ui->setupUi(this);
- ui->tabWidget->tabBar()->hide();
+ ui->setupUi(this);
+ ui->listView->setEmptyString(tr(
+ "Welcome!\n"
+ "If you're new here, you can click the \"Add\" button to add your Mojang or Minecraft account."
+ ));
+ ui->listView->setEmptyMode(VersionListView::String);
+ ui->listView->setContextMenuPolicy(Qt::CustomContextMenu);
- m_accounts = MMC->accounts();
+ m_accounts = MMC->accounts();
- ui->listView->setModel(m_accounts.get());
- ui->listView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
+ ui->listView->setModel(m_accounts.get());
+ ui->listView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
+ ui->listView->setSelectionMode(QAbstractItemView::SingleSelection);
- // Expand the account column
- ui->listView->header()->setSectionResizeMode(1, QHeaderView::Stretch);
+ // Expand the account column
+ ui->listView->header()->setSectionResizeMode(1, QHeaderView::Stretch);
- QItemSelectionModel *selectionModel = ui->listView->selectionModel();
+ QItemSelectionModel *selectionModel = ui->listView->selectionModel();
- connect(selectionModel, &QItemSelectionModel::selectionChanged,
- [this](const QItemSelection &sel, const QItemSelection &dsel)
- { updateButtonStates(); });
+ connect(selectionModel, &QItemSelectionModel::selectionChanged, [this](const QItemSelection &sel, const QItemSelection &dsel) {
+ updateButtonStates();
+ });
+ connect(ui->listView, &VersionListView::customContextMenuRequested, this, &AccountListPage::ShowContextMenu);
- connect(m_accounts.get(), SIGNAL(listChanged()), SLOT(listChanged()));
- connect(m_accounts.get(), SIGNAL(activeAccountChanged()), SLOT(listChanged()));
+ connect(m_accounts.get(), SIGNAL(listChanged()), SLOT(listChanged()));
+ connect(m_accounts.get(), SIGNAL(activeAccountChanged()), SLOT(listChanged()));
- updateButtonStates();
+ updateButtonStates();
}
AccountListPage::~AccountListPage()
{
- delete ui;
+ delete ui;
}
+void AccountListPage::ShowContextMenu(const QPoint& pos)
+{
+ auto menu = ui->toolBar->createContextMenu(this, tr("Context menu"));
+ menu->exec(ui->listView->mapToGlobal(pos));
+ delete menu;
+}
+
+void AccountListPage::changeEvent(QEvent* event)
+{
+ if (event->type() == QEvent::LanguageChange)
+ {
+ ui->retranslateUi(this);
+ }
+ QMainWindow::changeEvent(event);
+}
+
+QMenu * AccountListPage::createPopupMenu()
+{
+ QMenu* filteredMenu = QMainWindow::createPopupMenu();
+ filteredMenu->removeAction(ui->toolBar->toggleViewAction() );
+ return filteredMenu;
+}
+
+
void AccountListPage::listChanged()
{
- updateButtonStates();
+ updateButtonStates();
}
-void AccountListPage::on_addAccountBtn_clicked()
+void AccountListPage::on_actionAdd_triggered()
{
- addAccount(tr("Please enter your Mojang or Minecraft account username and password to add "
- "your account."));
+ addAccount(tr("Please enter your Mojang or Minecraft account username and password to add "
+ "your account."));
}
-void AccountListPage::on_rmAccountBtn_clicked()
+void AccountListPage::on_actionRemove_triggered()
{
- QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
- if (selection.size() > 0)
- {
- QModelIndex selected = selection.first();
- m_accounts->removeAccount(selected);
- }
+ QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
+ if (selection.size() > 0)
+ {
+ QModelIndex selected = selection.first();
+ m_accounts->removeAccount(selected);
+ }
}
-void AccountListPage::on_setDefaultBtn_clicked()
+void AccountListPage::on_actionSetDefault_triggered()
{
- QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
- if (selection.size() > 0)
- {
- QModelIndex selected = selection.first();
- MojangAccountPtr account =
- selected.data(MojangAccountList::PointerRole).value<MojangAccountPtr>();
- m_accounts->setActiveAccount(account->username());
- }
+ QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
+ if (selection.size() > 0)
+ {
+ QModelIndex selected = selection.first();
+ MojangAccountPtr account =
+ selected.data(MojangAccountList::PointerRole).value<MojangAccountPtr>();
+ m_accounts->setActiveAccount(account->username());
+ }
}
-void AccountListPage::on_noDefaultBtn_clicked()
+void AccountListPage::on_actionNoDefault_triggered()
{
- m_accounts->setActiveAccount("");
+ m_accounts->setActiveAccount("");
}
void AccountListPage::updateButtonStates()
{
- // If there is no selection, disable buttons that require something selected.
- QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
-
- ui->rmAccountBtn->setEnabled(selection.size() > 0);
- ui->setDefaultBtn->setEnabled(selection.size() > 0);
- ui->uploadSkinBtn->setEnabled(selection.size() > 0);
+ // If there is no selection, disable buttons that require something selected.
+ QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
+
+ ui->actionRemove->setEnabled(selection.size() > 0);
+ ui->actionSetDefault->setEnabled(selection.size() > 0);
+ ui->actionUploadSkin->setEnabled(selection.size() > 0);
+
+ if(m_accounts->activeAccount().get() == nullptr) {
+ ui->actionNoDefault->setEnabled(false);
+ ui->actionNoDefault->setChecked(true);
+ }
+ else {
+ ui->actionNoDefault->setEnabled(true);
+ ui->actionNoDefault->setChecked(false);
+ }
- ui->noDefaultBtn->setDown(m_accounts->activeAccount().get() == nullptr);
}
void AccountListPage::addAccount(const QString &errMsg)
{
- // TODO: The login dialog isn't quite done yet
- MojangAccountPtr account = LoginDialog::newAccount(this, errMsg);
-
- if (account != nullptr)
- {
- m_accounts->addAccount(account);
- if (m_accounts->count() == 1)
- m_accounts->setActiveAccount(account->username());
-
- // Grab associated player skins
- auto job = new NetJob("Player skins: " + account->username());
-
- for (AccountProfile profile : account->profiles())
- {
- auto meta = Env::getInstance().metacache()->resolveEntry("skins", profile.id + ".png");
- auto action = Net::Download::makeCached(QUrl("https://" + URLConstants::SKINS_BASE + profile.id + ".png"), meta);
- job->addNetAction(action);
- meta->setStale(true);
- }
-
- job->start();
- }
+ // TODO: The login dialog isn't quite done yet
+ MojangAccountPtr account = LoginDialog::newAccount(this, errMsg);
+
+ if (account != nullptr)
+ {
+ m_accounts->addAccount(account);
+ if (m_accounts->count() == 1)
+ m_accounts->setActiveAccount(account->username());
+
+ // Grab associated player skins
+ auto job = new NetJob("Player skins: " + account->username());
+
+ for (AccountProfile profile : account->profiles())
+ {
+ auto meta = Env::getInstance().metacache()->resolveEntry("skins", profile.id + ".png");
+ auto action = Net::Download::makeCached(QUrl(URLConstants::SKINS_BASE + profile.id + ".png"), meta);
+ job->addNetAction(action);
+ meta->setStale(true);
+ }
+
+ job->start();
+ }
}
-void AccountListPage::on_uploadSkinBtn_clicked()
+void AccountListPage::on_actionUploadSkin_triggered()
{
- QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
- if (selection.size() > 0)
- {
- QModelIndex selected = selection.first();
- MojangAccountPtr account = selected.data(MojangAccountList::PointerRole).value<MojangAccountPtr>();
- SkinUploadDialog dialog(account, this);
- dialog.exec();
- }
+ QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
+ if (selection.size() > 0)
+ {
+ QModelIndex selected = selection.first();
+ MojangAccountPtr account = selected.data(MojangAccountList::PointerRole).value<MojangAccountPtr>();
+ SkinUploadDialog dialog(account, this);
+ dialog.exec();
+ }
}
diff --git a/application/pages/global/AccountListPage.h b/application/pages/global/AccountListPage.h
index fa5561fe..4c8bc00b 100644
--- a/application/pages/global/AccountListPage.h
+++ b/application/pages/global/AccountListPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 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,7 +15,7 @@
#pragma once
-#include <QDialog>
+#include <QMainWindow>
#include <memory>
#include "pages/BasePage.h"
@@ -30,59 +30,64 @@ class AccountListPage;
class AuthenticateTask;
-class AccountListPage : public QWidget, public BasePage
+class AccountListPage : public QMainWindow, public BasePage
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit AccountListPage(QWidget *parent = 0);
- ~AccountListPage();
-
- QString displayName() const override
- {
- return tr("Accounts");
- }
- QIcon icon() const override
- {
- auto icon = MMC->getThemedIcon("accounts");
- if(icon.isNull())
- {
- icon = MMC->getThemedIcon("noaccount");
- }
- return icon;
- }
- QString id() const override
- {
- return "accounts";
- }
- QString helpPage() const override
- {
- return "Getting-Started#adding-an-account";
- }
+ explicit AccountListPage(QWidget *parent = 0);
+ ~AccountListPage();
+
+ QString displayName() const override
+ {
+ return tr("Accounts");
+ }
+ QIcon icon() const override
+ {
+ auto icon = MMC->getThemedIcon("accounts");
+ if(icon.isNull())
+ {
+ icon = MMC->getThemedIcon("noaccount");
+ }
+ return icon;
+ }
+ QString id() const override
+ {
+ return "accounts";
+ }
+ QString helpPage() const override
+ {
+ return "Getting-Started#adding-an-account";
+ }
+
+private:
+ void changeEvent(QEvent * event) override;
+ QMenu * createPopupMenu() override;
public
slots:
- void on_addAccountBtn_clicked();
+ void on_actionAdd_triggered();
- void on_rmAccountBtn_clicked();
+ void on_actionRemove_triggered();
- void on_setDefaultBtn_clicked();
+ void on_actionSetDefault_triggered();
- void on_noDefaultBtn_clicked();
+ void on_actionNoDefault_triggered();
- void on_uploadSkinBtn_clicked();
+ void on_actionUploadSkin_triggered();
- void listChanged();
+ void listChanged();
- //! Updates the states of the dialog's buttons.
- void updateButtonStates();
+ //! Updates the states of the dialog's buttons.
+ void updateButtonStates();
protected:
- std::shared_ptr<MojangAccountList> m_accounts;
+ std::shared_ptr<MojangAccountList> m_accounts;
protected
slots:
- void addAccount(const QString& errMsg="");
+ void ShowContextMenu(const QPoint &pos);
+ void addAccount(const QString& errMsg="");
private:
- Ui::AccountListPage *ui;
+ Ui::AccountListPage *ui;
};
diff --git a/application/pages/global/AccountListPage.ui b/application/pages/global/AccountListPage.ui
index f4e87680..433c1f7f 100644
--- a/application/pages/global/AccountListPage.ui
+++ b/application/pages/global/AccountListPage.ui
@@ -1,122 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AccountListPage</class>
- <widget class="QWidget" name="AccountListPage">
+ <widget class="QMainWindow" name="AccountListPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
- <width>694</width>
- <height>609</height>
+ <width>800</width>
+ <height>600</height>
</rect>
</property>
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <property name="leftMargin">
- <number>0</number>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <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="VersionListView" name="listView"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="WideBar" name="toolBar">
+ <property name="windowTitle">
+ <string>toolBar</string>
+ </property>
+ <attribute name="toolBarArea">
+ <enum>RightToolBarArea</enum>
+ </attribute>
+ <attribute name="toolBarBreak">
+ <bool>false</bool>
+ </attribute>
+ <addaction name="actionAdd"/>
+ <addaction name="actionRemove"/>
+ <addaction name="actionSetDefault"/>
+ <addaction name="actionNoDefault"/>
+ <addaction name="actionUploadSkin"/>
+ </widget>
+ <action name="actionAdd">
+ <property name="text">
+ <string>Add</string>
+ </property>
+ </action>
+ <action name="actionRemove">
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </action>
+ <action name="actionSetDefault">
+ <property name="text">
+ <string>Set Default</string>
</property>
- <property name="topMargin">
- <number>0</number>
+ </action>
+ <action name="actionNoDefault">
+ <property name="checkable">
+ <bool>true</bool>
</property>
- <property name="rightMargin">
- <number>0</number>
+ <property name="text">
+ <string>No Default</string>
</property>
- <property name="bottomMargin">
- <number>0</number>
+ </action>
+ <action name="actionUploadSkin">
+ <property name="text">
+ <string>Upload Skin</string>
</property>
- <item>
- <widget class="QTabWidget" name="tabWidget">
- <property name="currentIndex">
- <number>0</number>
- </property>
- <widget class="QWidget" name="tab">
- <attribute name="title">
- <string notr="true">Tab 1</string>
- </attribute>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QLabel" name="welcomeLabel">
- <property name="text">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Welcome! If you're new here, you can click the &amp;quot;Add&amp;quot; button to add your Mojang or Minecraft account.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- <property name="wordWrap">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QTreeView" name="listView"/>
- </item>
- <item>
- <layout class="QVBoxLayout" name="manageAcctsBtnBox">
- <item>
- <widget class="QPushButton" name="addAccountBtn">
- <property name="text">
- <string>&amp;Add</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="rmAccountBtn">
- <property name="text">
- <string>&amp;Remove</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="buttonSpacer">
- <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="setDefaultBtn">
- <property name="toolTip">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set the currently selected account as the active account. The active account is the account that is used to log in (unless it is overridden in an instance-specific setting).&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- <property name="text">
- <string>&amp;Set Default</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="noDefaultBtn">
- <property name="toolTip">
- <string>Set no default account. This will cause MultiMC to prompt you to select an account every time you launch an instance that doesn't have its own default set.</string>
- </property>
- <property name="text">
- <string>&amp;No Default</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="uploadSkinBtn">
- <property name="toolTip">
- <string>Opens a dialog to select and upload a skin image to the selected account.</string>
- </property>
- <property name="text">
- <string>&amp;Upload Skin</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </widget>
- </item>
- </layout>
+ </action>
</widget>
+ <customwidgets>
+ <customwidget>
+ <class>VersionListView</class>
+ <extends>QTreeView</extends>
+ <header>widgets/VersionListView.h</header>
+ </customwidget>
+ <customwidget>
+ <class>WideBar</class>
+ <extends>QToolBar</extends>
+ <header>widgets/WideBar.h</header>
+ </customwidget>
+ </customwidgets>
<resources/>
<connections/>
</ui>
diff --git a/application/pages/global/CustomCommandsPage.cpp b/application/pages/global/CustomCommandsPage.cpp
index 1352b6be..3b182319 100644
--- a/application/pages/global/CustomCommandsPage.cpp
+++ b/application/pages/global/CustomCommandsPage.cpp
@@ -6,17 +6,18 @@
CustomCommandsPage::CustomCommandsPage(QWidget* parent): QWidget(parent)
{
- auto verticalLayout = new QVBoxLayout(this);
- verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
- verticalLayout->setContentsMargins(0, 0, 0, 0);
+ auto verticalLayout = new QVBoxLayout(this);
+ verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
+ verticalLayout->setContentsMargins(0, 0, 0, 0);
- auto tabWidget = new QTabWidget(this);
- tabWidget->setObjectName(QStringLiteral("tabWidget"));
- commands = new CustomCommands(this);
- tabWidget->addTab(commands, "Foo");
- tabWidget->tabBar()->hide();
- verticalLayout->addWidget(tabWidget);
- loadSettings();
+ auto tabWidget = new QTabWidget(this);
+ tabWidget->setObjectName(QStringLiteral("tabWidget"));
+ commands = new CustomCommands(this);
+ commands->setContentsMargins(6, 6, 6, 6);
+ tabWidget->addTab(commands, "Foo");
+ tabWidget->tabBar()->hide();
+ verticalLayout->addWidget(tabWidget);
+ loadSettings();
}
CustomCommandsPage::~CustomCommandsPage()
@@ -25,26 +26,26 @@ CustomCommandsPage::~CustomCommandsPage()
bool CustomCommandsPage::apply()
{
- applySettings();
- return true;
+ applySettings();
+ return true;
}
void CustomCommandsPage::applySettings()
{
- auto s = MMC->settings();
- s->set("PreLaunchCommand", commands->prelaunchCommand());
- s->set("WrapperCommand", commands->wrapperCommand());
- s->set("PostExitCommand", commands->postexitCommand());
+ auto s = MMC->settings();
+ s->set("PreLaunchCommand", commands->prelaunchCommand());
+ s->set("WrapperCommand", commands->wrapperCommand());
+ s->set("PostExitCommand", commands->postexitCommand());
}
void CustomCommandsPage::loadSettings()
{
- auto s = MMC->settings();
- commands->initialize(
- false,
- true,
- s->get("PreLaunchCommand").toString(),
- s->get("WrapperCommand").toString(),
- s->get("PostExitCommand").toString()
- );
+ auto s = MMC->settings();
+ commands->initialize(
+ false,
+ true,
+ s->get("PreLaunchCommand").toString(),
+ s->get("WrapperCommand").toString(),
+ s->get("PostExitCommand").toString()
+ );
}
diff --git a/application/pages/global/CustomCommandsPage.h b/application/pages/global/CustomCommandsPage.h
index 52256ed3..a9047e63 100644
--- a/application/pages/global/CustomCommandsPage.h
+++ b/application/pages/global/CustomCommandsPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2018-2018 MultiMC Contributors
+/* Copyright 2018-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,32 +24,32 @@
class CustomCommandsPage : public QWidget, public BasePage
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit CustomCommandsPage(QWidget *parent = 0);
- ~CustomCommandsPage();
+ explicit CustomCommandsPage(QWidget *parent = 0);
+ ~CustomCommandsPage();
- QString displayName() const override
- {
- return tr("Custom Commands");
- }
- QIcon icon() const override
- {
- return MMC->getThemedIcon("custom-commands");
- }
- QString id() const override
- {
- return "custom-commands";
- }
- QString helpPage() const override
- {
- return "Custom-commands";
- }
- bool apply() override;
+ QString displayName() const override
+ {
+ return tr("Custom Commands");
+ }
+ QIcon icon() const override
+ {
+ return MMC->getThemedIcon("custom-commands");
+ }
+ QString id() const override
+ {
+ return "custom-commands";
+ }
+ QString helpPage() const override
+ {
+ return "Custom-commands";
+ }
+ bool apply() override;
private:
- void applySettings();
- void loadSettings();
- CustomCommands * commands;
+ void applySettings();
+ void loadSettings();
+ CustomCommands * commands;
};
diff --git a/application/pages/global/ExternalToolsPage.cpp b/application/pages/global/ExternalToolsPage.cpp
index 20887b54..7de6f858 100644
--- a/application/pages/global/ExternalToolsPage.cpp
+++ b/application/pages/global/ExternalToolsPage.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
#include <QMessageBox>
#include <QFileDialog>
#include <QStandardPaths>
+#include <QTabBar>
#include "settings/SettingsObject.h"
#include "tools/BaseProfiler.h"
@@ -28,206 +29,206 @@
#include <QTabBar>
ExternalToolsPage::ExternalToolsPage(QWidget *parent) :
- QWidget(parent),
- ui(new Ui::ExternalToolsPage)
+ QWidget(parent),
+ ui(new Ui::ExternalToolsPage)
{
- ui->setupUi(this);
- ui->tabWidget->tabBar()->hide();
+ ui->setupUi(this);
+ ui->tabWidget->tabBar()->hide();
- #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
- ui->jsonEditorTextBox->setClearButtonEnabled(true);
- #endif
+ #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
+ ui->jsonEditorTextBox->setClearButtonEnabled(true);
+ #endif
- ui->mceditLink->setOpenExternalLinks(true);
- ui->jvisualvmLink->setOpenExternalLinks(true);
- ui->jprofilerLink->setOpenExternalLinks(true);
- loadSettings();
+ ui->mceditLink->setOpenExternalLinks(true);
+ ui->jvisualvmLink->setOpenExternalLinks(true);
+ ui->jprofilerLink->setOpenExternalLinks(true);
+ loadSettings();
}
ExternalToolsPage::~ExternalToolsPage()
{
- delete ui;
+ delete ui;
}
void ExternalToolsPage::loadSettings()
{
- auto s = MMC->settings();
- ui->jprofilerPathEdit->setText(s->get("JProfilerPath").toString());
- ui->jvisualvmPathEdit->setText(s->get("JVisualVMPath").toString());
- ui->mceditPathEdit->setText(s->get("MCEditPath").toString());
+ auto s = MMC->settings();
+ ui->jprofilerPathEdit->setText(s->get("JProfilerPath").toString());
+ ui->jvisualvmPathEdit->setText(s->get("JVisualVMPath").toString());
+ ui->mceditPathEdit->setText(s->get("MCEditPath").toString());
- // Editors
- ui->jsonEditorTextBox->setText(s->get("JsonEditor").toString());
+ // Editors
+ ui->jsonEditorTextBox->setText(s->get("JsonEditor").toString());
}
void ExternalToolsPage::applySettings()
{
- auto s = MMC->settings();
-
- s->set("JProfilerPath", ui->jprofilerPathEdit->text());
- s->set("JVisualVMPath", ui->jvisualvmPathEdit->text());
- s->set("MCEditPath", ui->mceditPathEdit->text());
-
- // Editors
- QString jsonEditor = ui->jsonEditorTextBox->text();
- if (!jsonEditor.isEmpty() &&
- (!QFileInfo(jsonEditor).exists() || !QFileInfo(jsonEditor).isExecutable()))
- {
- QString found = QStandardPaths::findExecutable(jsonEditor);
- if (!found.isEmpty())
- {
- jsonEditor = found;
- }
- }
- s->set("JsonEditor", jsonEditor);
+ auto s = MMC->settings();
+
+ s->set("JProfilerPath", ui->jprofilerPathEdit->text());
+ s->set("JVisualVMPath", ui->jvisualvmPathEdit->text());
+ s->set("MCEditPath", ui->mceditPathEdit->text());
+
+ // Editors
+ QString jsonEditor = ui->jsonEditorTextBox->text();
+ if (!jsonEditor.isEmpty() &&
+ (!QFileInfo(jsonEditor).exists() || !QFileInfo(jsonEditor).isExecutable()))
+ {
+ QString found = QStandardPaths::findExecutable(jsonEditor);
+ if (!found.isEmpty())
+ {
+ jsonEditor = found;
+ }
+ }
+ s->set("JsonEditor", jsonEditor);
}
void ExternalToolsPage::on_jprofilerPathBtn_clicked()
{
- QString raw_dir = ui->jprofilerPathEdit->text();
- QString error;
- do
- {
- raw_dir = QFileDialog::getExistingDirectory(this, tr("JProfiler Folder"), raw_dir);
- if (raw_dir.isEmpty())
- {
- break;
- }
- QString cooked_dir = FS::NormalizePath(raw_dir);
- if (!MMC->profilers()["jprofiler"]->check(cooked_dir, &error))
- {
- QMessageBox::critical(this, tr("Error"), tr("Error while checking JProfiler install:\n%1").arg(error));
- continue;
- }
- else
- {
- ui->jprofilerPathEdit->setText(cooked_dir);
- break;
- }
- } while (1);
+ QString raw_dir = ui->jprofilerPathEdit->text();
+ QString error;
+ do
+ {
+ raw_dir = QFileDialog::getExistingDirectory(this, tr("JProfiler Folder"), raw_dir);
+ if (raw_dir.isEmpty())
+ {
+ break;
+ }
+ QString cooked_dir = FS::NormalizePath(raw_dir);
+ if (!MMC->profilers()["jprofiler"]->check(cooked_dir, &error))
+ {
+ QMessageBox::critical(this, tr("Error"), tr("Error while checking JProfiler install:\n%1").arg(error));
+ continue;
+ }
+ else
+ {
+ ui->jprofilerPathEdit->setText(cooked_dir);
+ break;
+ }
+ } while (1);
}
void ExternalToolsPage::on_jprofilerCheckBtn_clicked()
{
- QString error;
- if (!MMC->profilers()["jprofiler"]->check(ui->jprofilerPathEdit->text(), &error))
- {
- QMessageBox::critical(this, tr("Error"), tr("Error while checking JProfiler install:\n%1").arg(error));
- }
- else
- {
- QMessageBox::information(this, tr("OK"), tr("JProfiler setup seems to be OK"));
- }
+ QString error;
+ if (!MMC->profilers()["jprofiler"]->check(ui->jprofilerPathEdit->text(), &error))
+ {
+ QMessageBox::critical(this, tr("Error"), tr("Error while checking JProfiler install:\n%1").arg(error));
+ }
+ else
+ {
+ QMessageBox::information(this, tr("OK"), tr("JProfiler setup seems to be OK"));
+ }
}
void ExternalToolsPage::on_jvisualvmPathBtn_clicked()
{
- QString raw_dir = ui->jvisualvmPathEdit->text();
- QString error;
- do
- {
- raw_dir = QFileDialog::getOpenFileName(this, tr("JVisualVM Executable"), raw_dir);
- if (raw_dir.isEmpty())
- {
- break;
- }
- QString cooked_dir = FS::NormalizePath(raw_dir);
- if (!MMC->profilers()["jvisualvm"]->check(cooked_dir, &error))
- {
- QMessageBox::critical(this, tr("Error"), tr("Error while checking JVisualVM install:\n%1").arg(error));
- continue;
- }
- else
- {
- ui->jvisualvmPathEdit->setText(cooked_dir);
- break;
- }
- } while (1);
+ QString raw_dir = ui->jvisualvmPathEdit->text();
+ QString error;
+ do
+ {
+ raw_dir = QFileDialog::getOpenFileName(this, tr("JVisualVM Executable"), raw_dir);
+ if (raw_dir.isEmpty())
+ {
+ break;
+ }
+ QString cooked_dir = FS::NormalizePath(raw_dir);
+ if (!MMC->profilers()["jvisualvm"]->check(cooked_dir, &error))
+ {
+ QMessageBox::critical(this, tr("Error"), tr("Error while checking JVisualVM install:\n%1").arg(error));
+ continue;
+ }
+ else
+ {
+ ui->jvisualvmPathEdit->setText(cooked_dir);
+ break;
+ }
+ } while (1);
}
void ExternalToolsPage::on_jvisualvmCheckBtn_clicked()
{
- QString error;
- if (!MMC->profilers()["jvisualvm"]->check(ui->jvisualvmPathEdit->text(), &error))
- {
- QMessageBox::critical(this, tr("Error"), tr("Error while checking JVisualVM install:\n%1").arg(error));
- }
- else
- {
- QMessageBox::information(this, tr("OK"), tr("JVisualVM setup seems to be OK"));
- }
+ QString error;
+ if (!MMC->profilers()["jvisualvm"]->check(ui->jvisualvmPathEdit->text(), &error))
+ {
+ QMessageBox::critical(this, tr("Error"), tr("Error while checking JVisualVM install:\n%1").arg(error));
+ }
+ else
+ {
+ QMessageBox::information(this, tr("OK"), tr("JVisualVM setup seems to be OK"));
+ }
}
void ExternalToolsPage::on_mceditPathBtn_clicked()
{
- QString raw_dir = ui->mceditPathEdit->text();
- QString error;
- do
- {
+ QString raw_dir = ui->mceditPathEdit->text();
+ QString error;
+ do
+ {
#ifdef Q_OS_OSX
- raw_dir = QFileDialog::getOpenFileName(this, tr("MCEdit Application"), raw_dir);
+ raw_dir = QFileDialog::getOpenFileName(this, tr("MCEdit Application"), raw_dir);
#else
- raw_dir = QFileDialog::getExistingDirectory(this, tr("MCEdit Folder"), raw_dir);
+ raw_dir = QFileDialog::getExistingDirectory(this, tr("MCEdit Folder"), raw_dir);
#endif
- if (raw_dir.isEmpty())
- {
- break;
- }
- QString cooked_dir = FS::NormalizePath(raw_dir);
- if (!MMC->mcedit()->check(cooked_dir, error))
- {
- QMessageBox::critical(this, tr("Error"), tr("Error while checking MCEdit install:\n%1").arg(error));
- continue;
- }
- else
- {
- ui->mceditPathEdit->setText(cooked_dir);
- break;
- }
- } while (1);
+ if (raw_dir.isEmpty())
+ {
+ break;
+ }
+ QString cooked_dir = FS::NormalizePath(raw_dir);
+ if (!MMC->mcedit()->check(cooked_dir, error))
+ {
+ QMessageBox::critical(this, tr("Error"), tr("Error while checking MCEdit install:\n%1").arg(error));
+ continue;
+ }
+ else
+ {
+ ui->mceditPathEdit->setText(cooked_dir);
+ break;
+ }
+ } while (1);
}
void ExternalToolsPage::on_mceditCheckBtn_clicked()
{
- QString error;
- if (!MMC->mcedit()->check(ui->mceditPathEdit->text(), error))
- {
- QMessageBox::critical(this, tr("Error"), tr("Error while checking MCEdit install:\n%1").arg(error));
- }
- else
- {
- QMessageBox::information(this, tr("OK"), tr("MCEdit setup seems to be OK"));
- }
+ QString error;
+ if (!MMC->mcedit()->check(ui->mceditPathEdit->text(), error))
+ {
+ QMessageBox::critical(this, tr("Error"), tr("Error while checking MCEdit install:\n%1").arg(error));
+ }
+ else
+ {
+ QMessageBox::information(this, tr("OK"), tr("MCEdit setup seems to be OK"));
+ }
}
void ExternalToolsPage::on_jsonEditorBrowseBtn_clicked()
{
- QString raw_file = QFileDialog::getOpenFileName(
- this, tr("JSON Editor"),
- ui->jsonEditorTextBox->text().isEmpty()
+ QString raw_file = QFileDialog::getOpenFileName(
+ this, tr("JSON Editor"),
+ ui->jsonEditorTextBox->text().isEmpty()
#if defined(Q_OS_LINUX)
- ? QString("/usr/bin")
+ ? QString("/usr/bin")
#else
- ? QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).first()
+ ? QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).first()
#endif
- : ui->jsonEditorTextBox->text());
-
- if (raw_file.isEmpty())
- {
- return;
- }
- QString cooked_file = FS::NormalizePath(raw_file);
-
- // it has to exist and be an executable
- if (QFileInfo(cooked_file).exists() && QFileInfo(cooked_file).isExecutable())
- {
- ui->jsonEditorTextBox->setText(cooked_file);
- }
- else
- {
- QMessageBox::warning(this, tr("Invalid"),
- tr("The file chosen does not seem to be an executable"));
- }
+ : ui->jsonEditorTextBox->text());
+
+ if (raw_file.isEmpty())
+ {
+ return;
+ }
+ QString cooked_file = FS::NormalizePath(raw_file);
+
+ // it has to exist and be an executable
+ if (QFileInfo(cooked_file).exists() && QFileInfo(cooked_file).isExecutable())
+ {
+ ui->jsonEditorTextBox->setText(cooked_file);
+ }
+ else
+ {
+ QMessageBox::warning(this, tr("Invalid"),
+ tr("The file chosen does not seem to be an executable"));
+ }
}
bool ExternalToolsPage::apply()
{
- applySettings();
- return true;
+ applySettings();
+ return true;
}
diff --git a/application/pages/global/ExternalToolsPage.h b/application/pages/global/ExternalToolsPage.h
index de46d8a6..06e64273 100644
--- a/application/pages/global/ExternalToolsPage.h
+++ b/application/pages/global/ExternalToolsPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,49 +26,49 @@ class ExternalToolsPage;
class ExternalToolsPage : public QWidget, public BasePage
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit ExternalToolsPage(QWidget *parent = 0);
- ~ExternalToolsPage();
+ explicit ExternalToolsPage(QWidget *parent = 0);
+ ~ExternalToolsPage();
- QString displayName() const override
- {
- return tr("External Tools");
- }
- QIcon icon() const override
- {
- auto icon = MMC->getThemedIcon("externaltools");
- if(icon.isNull())
- {
- icon = MMC->getThemedIcon("loadermods");
- }
- return icon;
- }
- QString id() const override
- {
- return "external-tools";
- }
- QString helpPage() const override
- {
- return "Tools";
- }
- virtual bool apply() override;
+ QString displayName() const override
+ {
+ return tr("External Tools");
+ }
+ QIcon icon() const override
+ {
+ auto icon = MMC->getThemedIcon("externaltools");
+ if(icon.isNull())
+ {
+ icon = MMC->getThemedIcon("loadermods");
+ }
+ return icon;
+ }
+ QString id() const override
+ {
+ return "external-tools";
+ }
+ QString helpPage() const override
+ {
+ return "Tools";
+ }
+ virtual bool apply() override;
private:
- void loadSettings();
- void applySettings();
+ void loadSettings();
+ void applySettings();
private:
- Ui::ExternalToolsPage *ui;
+ Ui::ExternalToolsPage *ui;
private
slots:
- void on_jprofilerPathBtn_clicked();
- void on_jprofilerCheckBtn_clicked();
- void on_jvisualvmPathBtn_clicked();
- void on_jvisualvmCheckBtn_clicked();
- void on_mceditPathBtn_clicked();
- void on_mceditCheckBtn_clicked();
- void on_jsonEditorBrowseBtn_clicked();
+ void on_jprofilerPathBtn_clicked();
+ void on_jprofilerCheckBtn_clicked();
+ void on_jvisualvmPathBtn_clicked();
+ void on_jvisualvmCheckBtn_clicked();
+ void on_mceditPathBtn_clicked();
+ void on_mceditCheckBtn_clicked();
+ void on_jsonEditorBrowseBtn_clicked();
};
diff --git a/application/pages/global/ExternalToolsPage.ui b/application/pages/global/ExternalToolsPage.ui
index 5f19898b..e79e9388 100644
--- a/application/pages/global/ExternalToolsPage.ui
+++ b/application/pages/global/ExternalToolsPage.ui
@@ -63,7 +63,7 @@
<item>
<widget class="QLabel" name="jprofilerLink">
<property name="text">
- <string notr="true">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;http://www.ej-technologies.com/products/jprofiler/overview.html&quot;&gt;http://www.ej-technologies.com/products/jprofiler/overview.html&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ <string notr="true">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://www.ej-technologies.com/products/jprofiler/overview.html&quot;&gt;https://www.ej-technologies.com/products/jprofiler/overview.html&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
@@ -137,7 +137,7 @@
<item>
<widget class="QLabel" name="mceditLink">
<property name="text">
- <string notr="true">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;http://www.mcedit.net/&quot;&gt;http://www.mcedit.net/&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ <string notr="true">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://www.mcedit.net/&quot;&gt;https://www.mcedit.net/&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
diff --git a/application/pages/global/JavaPage.cpp b/application/pages/global/JavaPage.cpp
index ce733778..211dc929 100644
--- a/application/pages/global/JavaPage.cpp
+++ b/application/pages/global/JavaPage.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
#include <QFileDialog>
#include <QMessageBox>
#include <QDir>
+#include <QTabBar>
#include "dialogs/VersionSelectDialog.h"
@@ -34,120 +35,120 @@
JavaPage::JavaPage(QWidget *parent) : QWidget(parent), ui(new Ui::JavaPage)
{
- ui->setupUi(this);
- ui->tabWidget->tabBar()->hide();
+ ui->setupUi(this);
+ ui->tabWidget->tabBar()->hide();
- auto sysMB = Sys::getSystemRam() / Sys::megabyte;
- ui->maxMemSpinBox->setMaximum(sysMB);
- loadSettings();
+ auto sysMB = Sys::getSystemRam() / Sys::megabyte;
+ ui->maxMemSpinBox->setMaximum(sysMB);
+ loadSettings();
}
JavaPage::~JavaPage()
{
- delete ui;
+ delete ui;
}
bool JavaPage::apply()
{
- applySettings();
- return true;
+ applySettings();
+ return true;
}
void JavaPage::applySettings()
{
- auto s = MMC->settings();
-
- // Memory
- int min = ui->minMemSpinBox->value();
- int max = ui->maxMemSpinBox->value();
- if(min < max)
- {
- s->set("MinMemAlloc", min);
- s->set("MaxMemAlloc", max);
- }
- else
- {
- s->set("MinMemAlloc", max);
- s->set("MaxMemAlloc", min);
- }
- s->set("PermGen", ui->permGenSpinBox->value());
-
- // Java Settings
- s->set("JavaPath", ui->javaPathTextBox->text());
- s->set("JvmArgs", ui->jvmArgsTextBox->text());
- JavaCommon::checkJVMArgs(s->get("JvmArgs").toString(), this->parentWidget());
+ auto s = MMC->settings();
+
+ // Memory
+ int min = ui->minMemSpinBox->value();
+ int max = ui->maxMemSpinBox->value();
+ if(min < max)
+ {
+ s->set("MinMemAlloc", min);
+ s->set("MaxMemAlloc", max);
+ }
+ else
+ {
+ s->set("MinMemAlloc", max);
+ s->set("MaxMemAlloc", min);
+ }
+ s->set("PermGen", ui->permGenSpinBox->value());
+
+ // Java Settings
+ s->set("JavaPath", ui->javaPathTextBox->text());
+ s->set("JvmArgs", ui->jvmArgsTextBox->text());
+ JavaCommon::checkJVMArgs(s->get("JvmArgs").toString(), this->parentWidget());
}
void JavaPage::loadSettings()
{
- auto s = MMC->settings();
- // Memory
- int min = s->get("MinMemAlloc").toInt();
- int max = s->get("MaxMemAlloc").toInt();
- if(min < max)
- {
- ui->minMemSpinBox->setValue(min);
- ui->maxMemSpinBox->setValue(max);
- }
- else
- {
- ui->minMemSpinBox->setValue(max);
- ui->maxMemSpinBox->setValue(min);
- }
- ui->permGenSpinBox->setValue(s->get("PermGen").toInt());
-
- // Java Settings
- ui->javaPathTextBox->setText(s->get("JavaPath").toString());
- ui->jvmArgsTextBox->setText(s->get("JvmArgs").toString());
+ auto s = MMC->settings();
+ // Memory
+ int min = s->get("MinMemAlloc").toInt();
+ int max = s->get("MaxMemAlloc").toInt();
+ if(min < max)
+ {
+ ui->minMemSpinBox->setValue(min);
+ ui->maxMemSpinBox->setValue(max);
+ }
+ else
+ {
+ ui->minMemSpinBox->setValue(max);
+ ui->maxMemSpinBox->setValue(min);
+ }
+ ui->permGenSpinBox->setValue(s->get("PermGen").toInt());
+
+ // Java Settings
+ ui->javaPathTextBox->setText(s->get("JavaPath").toString());
+ ui->jvmArgsTextBox->setText(s->get("JvmArgs").toString());
}
void JavaPage::on_javaDetectBtn_clicked()
{
- JavaInstallPtr java;
+ JavaInstallPtr java;
- VersionSelectDialog vselect(MMC->javalist().get(), tr("Select a Java version"), this, true);
- vselect.setResizeOn(2);
- vselect.exec();
+ 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<JavaInstall>(vselect.selectedVersion());
- ui->javaPathTextBox->setText(java->path);
- }
+ if (vselect.result() == QDialog::Accepted && vselect.selectedVersion())
+ {
+ java = std::dynamic_pointer_cast<JavaInstall>(vselect.selectedVersion());
+ ui->javaPathTextBox->setText(java->path);
+ }
}
void JavaPage::on_javaBrowseBtn_clicked()
{
- QString raw_path = QFileDialog::getOpenFileName(this, tr("Find Java executable"));
-
- // do not allow current dir - it's dirty. Do not allow dirs that don't exist
- if(raw_path.isEmpty())
- {
- return;
- }
-
- QString cooked_path = FS::NormalizePath(raw_path);
- QFileInfo javaInfo(cooked_path);;
- if(!javaInfo.exists() || !javaInfo.isExecutable())
- {
- return;
- }
- ui->javaPathTextBox->setText(cooked_path);
+ QString raw_path = QFileDialog::getOpenFileName(this, tr("Find Java executable"));
+
+ // do not allow current dir - it's dirty. Do not allow dirs that don't exist
+ if(raw_path.isEmpty())
+ {
+ return;
+ }
+
+ QString cooked_path = FS::NormalizePath(raw_path);
+ QFileInfo javaInfo(cooked_path);;
+ if(!javaInfo.exists() || !javaInfo.isExecutable())
+ {
+ return;
+ }
+ ui->javaPathTextBox->setText(cooked_path);
}
void JavaPage::on_javaTestBtn_clicked()
{
- if(checker)
- {
- return;
- }
- checker.reset(new JavaCommon::TestCheck(
- this, ui->javaPathTextBox->text(), ui->jvmArgsTextBox->text(),
- ui->minMemSpinBox->value(), ui->maxMemSpinBox->value(), ui->permGenSpinBox->value()));
- connect(checker.get(), SIGNAL(finished()), SLOT(checkerFinished()));
- checker->run();
+ if(checker)
+ {
+ return;
+ }
+ checker.reset(new JavaCommon::TestCheck(
+ this, ui->javaPathTextBox->text(), ui->jvmArgsTextBox->text(),
+ ui->minMemSpinBox->value(), ui->maxMemSpinBox->value(), ui->permGenSpinBox->value()));
+ connect(checker.get(), SIGNAL(finished()), SLOT(checkerFinished()));
+ checker->run();
}
void JavaPage::checkerFinished()
{
- checker.reset();
+ checker.reset();
}
diff --git a/application/pages/global/JavaPage.h b/application/pages/global/JavaPage.h
index e3a9f37f..3efebb78 100644
--- a/application/pages/global/JavaPage.h
+++ b/application/pages/global/JavaPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,42 +31,42 @@ class JavaPage;
class JavaPage : public QWidget, public BasePage
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit JavaPage(QWidget *parent = 0);
- ~JavaPage();
+ explicit JavaPage(QWidget *parent = 0);
+ ~JavaPage();
- QString displayName() const override
- {
- return tr("Java");
- }
- QIcon icon() const override
- {
- return MMC->getThemedIcon("java");
- }
- QString id() const override
- {
- return "java-settings";
- }
- QString helpPage() const override
- {
- return "Java-settings";
- }
- bool apply() override;
+ QString displayName() const override
+ {
+ return tr("Java");
+ }
+ QIcon icon() const override
+ {
+ return MMC->getThemedIcon("java");
+ }
+ QString id() const override
+ {
+ return "java-settings";
+ }
+ QString helpPage() const override
+ {
+ return "Java-settings";
+ }
+ bool apply() override;
private:
- void applySettings();
- void loadSettings();
+ void applySettings();
+ void loadSettings();
private
slots:
- void on_javaDetectBtn_clicked();
- void on_javaTestBtn_clicked();
- void on_javaBrowseBtn_clicked();
- void checkerFinished();
+ void on_javaDetectBtn_clicked();
+ void on_javaTestBtn_clicked();
+ void on_javaBrowseBtn_clicked();
+ void checkerFinished();
private:
- Ui::JavaPage *ui;
- unique_qobject_ptr<JavaCommon::TestCheck> checker;
+ Ui::JavaPage *ui;
+ unique_qobject_ptr<JavaCommon::TestCheck> checker;
};
diff --git a/application/pages/global/LanguagePage.cpp b/application/pages/global/LanguagePage.cpp
new file mode 100644
index 00000000..ae3168cc
--- /dev/null
+++ b/application/pages/global/LanguagePage.cpp
@@ -0,0 +1,51 @@
+#include "LanguagePage.h"
+
+#include "widgets/LanguageSelectionWidget.h"
+#include <QVBoxLayout>
+
+LanguagePage::LanguagePage(QWidget* parent) :
+ QWidget(parent)
+{
+ setObjectName(QStringLiteral("languagePage"));
+ auto layout = new QVBoxLayout(this);
+ mainWidget = new LanguageSelectionWidget(this);
+ layout->setContentsMargins(0,0,0,0);
+ layout->addWidget(mainWidget);
+ retranslate();
+}
+
+LanguagePage::~LanguagePage()
+{
+}
+
+bool LanguagePage::apply()
+{
+ applySettings();
+ return true;
+}
+
+void LanguagePage::applySettings()
+{
+ auto settings = MMC->settings();
+ QString key = mainWidget->getSelectedLanguageKey();
+ settings->set("Language", key);
+}
+
+void LanguagePage::loadSettings()
+{
+ // NIL
+}
+
+void LanguagePage::retranslate()
+{
+ mainWidget->retranslate();
+}
+
+void LanguagePage::changeEvent(QEvent* event)
+{
+ if (event->type() == QEvent::LanguageChange)
+ {
+ retranslate();
+ }
+ QWidget::changeEvent(event);
+}
diff --git a/application/pages/global/LanguagePage.h b/application/pages/global/LanguagePage.h
new file mode 100644
index 00000000..c4df2ea9
--- /dev/null
+++ b/application/pages/global/LanguagePage.h
@@ -0,0 +1,60 @@
+/* Copyright 2013-2019 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 <memory>
+#include "pages/BasePage.h"
+#include <MultiMC.h>
+#include <QWidget>
+
+class LanguageSelectionWidget;
+
+class LanguagePage : public QWidget, public BasePage
+{
+ Q_OBJECT
+
+public:
+ explicit LanguagePage(QWidget *parent = 0);
+ virtual ~LanguagePage();
+
+ QString displayName() const override
+ {
+ return tr("Language");
+ }
+ QIcon icon() const override
+ {
+ return MMC->getThemedIcon("language");
+ }
+ QString id() const override
+ {
+ return "language-settings";
+ }
+ QString helpPage() const override
+ {
+ return "Language-settings";
+ }
+ bool apply() override;
+
+ void changeEvent(QEvent * ) override;
+
+private:
+ void applySettings();
+ void loadSettings();
+ void retranslate();
+
+private:
+ LanguageSelectionWidget *mainWidget;
+};
diff --git a/application/pages/global/MinecraftPage.cpp b/application/pages/global/MinecraftPage.cpp
index 4efc2fa0..5e0d9625 100644
--- a/application/pages/global/MinecraftPage.cpp
+++ b/application/pages/global/MinecraftPage.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
#include <QMessageBox>
#include <QDir>
+#include <QTabBar>
#include "settings/SettingsObject.h"
#include "MultiMC.h"
@@ -25,52 +26,52 @@
MinecraftPage::MinecraftPage(QWidget *parent) : QWidget(parent), ui(new Ui::MinecraftPage)
{
- ui->setupUi(this);
- ui->tabWidget->tabBar()->hide();
- loadSettings();
- updateCheckboxStuff();
+ ui->setupUi(this);
+ ui->tabWidget->tabBar()->hide();
+ loadSettings();
+ updateCheckboxStuff();
}
MinecraftPage::~MinecraftPage()
{
- delete ui;
+ delete ui;
}
bool MinecraftPage::apply()
{
- applySettings();
- return true;
+ applySettings();
+ return true;
}
void MinecraftPage::updateCheckboxStuff()
{
- ui->windowWidthSpinBox->setEnabled(!ui->maximizedCheckBox->isChecked());
- ui->windowHeightSpinBox->setEnabled(!ui->maximizedCheckBox->isChecked());
+ ui->windowWidthSpinBox->setEnabled(!ui->maximizedCheckBox->isChecked());
+ ui->windowHeightSpinBox->setEnabled(!ui->maximizedCheckBox->isChecked());
}
void MinecraftPage::on_maximizedCheckBox_clicked(bool checked)
{
- Q_UNUSED(checked);
- updateCheckboxStuff();
+ Q_UNUSED(checked);
+ updateCheckboxStuff();
}
void MinecraftPage::applySettings()
{
- auto s = MMC->settings();
+ auto s = MMC->settings();
- // Window Size
- s->set("LaunchMaximized", ui->maximizedCheckBox->isChecked());
- s->set("MinecraftWinWidth", ui->windowWidthSpinBox->value());
- s->set("MinecraftWinHeight", ui->windowHeightSpinBox->value());
+ // Window Size
+ s->set("LaunchMaximized", ui->maximizedCheckBox->isChecked());
+ s->set("MinecraftWinWidth", ui->windowWidthSpinBox->value());
+ s->set("MinecraftWinHeight", ui->windowHeightSpinBox->value());
}
void MinecraftPage::loadSettings()
{
- auto s = MMC->settings();
+ auto s = MMC->settings();
- // Window Size
- ui->maximizedCheckBox->setChecked(s->get("LaunchMaximized").toBool());
- ui->windowWidthSpinBox->setValue(s->get("MinecraftWinWidth").toInt());
- ui->windowHeightSpinBox->setValue(s->get("MinecraftWinHeight").toInt());
+ // Window Size
+ ui->maximizedCheckBox->setChecked(s->get("LaunchMaximized").toBool());
+ ui->windowWidthSpinBox->setValue(s->get("MinecraftWinWidth").toInt());
+ ui->windowHeightSpinBox->setValue(s->get("MinecraftWinHeight").toInt());
}
diff --git a/application/pages/global/MinecraftPage.h b/application/pages/global/MinecraftPage.h
index d1abd6fe..39265fbe 100644
--- a/application/pages/global/MinecraftPage.h
+++ b/application/pages/global/MinecraftPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,40 +31,40 @@ class MinecraftPage;
class MinecraftPage : public QWidget, public BasePage
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit MinecraftPage(QWidget *parent = 0);
- ~MinecraftPage();
+ explicit MinecraftPage(QWidget *parent = 0);
+ ~MinecraftPage();
- QString displayName() const override
- {
- return tr("Minecraft");
- }
- QIcon icon() const override
- {
- return MMC->getThemedIcon("minecraft");
- }
- QString id() const override
- {
- return "minecraft-settings";
- }
- QString helpPage() const override
- {
- return "Minecraft-settings";
- }
- bool apply() override;
+ QString displayName() const override
+ {
+ return tr("Minecraft");
+ }
+ QIcon icon() const override
+ {
+ return MMC->getThemedIcon("minecraft");
+ }
+ QString id() const override
+ {
+ return "minecraft-settings";
+ }
+ QString helpPage() const override
+ {
+ return "Minecraft-settings";
+ }
+ bool apply() override;
private:
- void updateCheckboxStuff();
- void applySettings();
- void loadSettings();
+ void updateCheckboxStuff();
+ void applySettings();
+ void loadSettings();
private
slots:
- void on_maximizedCheckBox_clicked(bool checked);
+ void on_maximizedCheckBox_clicked(bool checked);
private:
- Ui::MinecraftPage *ui;
+ Ui::MinecraftPage *ui;
};
diff --git a/application/pages/global/MultiMCPage.cpp b/application/pages/global/MultiMCPage.cpp
index 21e8123c..d10d4caa 100644
--- a/application/pages/global/MultiMCPage.cpp
+++ b/application/pages/global/MultiMCPage.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,208 +32,190 @@
// FIXME: possibly move elsewhere
enum InstSortMode
{
- // Sort alphabetically by name.
- Sort_Name,
- // Sort by which instance was launched most recently.
- Sort_LastLaunch
+ // Sort alphabetically by name.
+ Sort_Name,
+ // Sort by which instance was launched most recently.
+ Sort_LastLaunch
};
MultiMCPage::MultiMCPage(QWidget *parent) : QWidget(parent), ui(new Ui::MultiMCPage)
{
- ui->setupUi(this);
- auto origForeground = ui->fontPreview->palette().color(ui->fontPreview->foregroundRole());
- auto origBackground = ui->fontPreview->palette().color(ui->fontPreview->backgroundRole());
- m_colors.reset(new LogColorCache(origForeground, origBackground));
-
- ui->sortingModeGroup->setId(ui->sortByNameBtn, Sort_Name);
- ui->sortingModeGroup->setId(ui->sortLastLaunchedBtn, Sort_LastLaunch);
-
- defaultFormat = new QTextCharFormat(ui->fontPreview->currentCharFormat());
-
- m_languageModel = MMC->translations();
- loadSettings();
-
- if(BuildConfig.UPDATER_ENABLED)
- {
- QObject::connect(MMC->updateChecker().get(), &UpdateChecker::channelListLoaded, this,
- &MultiMCPage::refreshUpdateChannelList);
-
- if (MMC->updateChecker()->hasChannels())
- {
- refreshUpdateChannelList();
- }
- else
- {
- MMC->updateChecker()->updateChanList(false);
- }
- }
- else
- {
- ui->updateSettingsBox->setHidden(true);
- }
-/* // Analytics
- if(BuildConfig.ANALYTICS_ID.isEmpty())
- {
- ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->analyticsTab));
- }
-*/ connect(ui->fontSizeBox, SIGNAL(valueChanged(int)), SLOT(refreshFontPreview()));
- connect(ui->consoleFont, SIGNAL(currentFontChanged(QFont)), SLOT(refreshFontPreview()));
- connect(ui->languageBox, SIGNAL(currentIndexChanged(int)), SLOT(languageIndexChanged(int)));
+ ui->setupUi(this);
+ auto origForeground = ui->fontPreview->palette().color(ui->fontPreview->foregroundRole());
+ auto origBackground = ui->fontPreview->palette().color(ui->fontPreview->backgroundRole());
+ m_colors.reset(new LogColorCache(origForeground, origBackground));
+
+ ui->sortingModeGroup->setId(ui->sortByNameBtn, Sort_Name);
+ ui->sortingModeGroup->setId(ui->sortLastLaunchedBtn, Sort_LastLaunch);
+
+ defaultFormat = new QTextCharFormat(ui->fontPreview->currentCharFormat());
+
+ m_languageModel = MMC->translations();
+ loadSettings();
+
+ if(BuildConfig.UPDATER_ENABLED)
+ {
+ QObject::connect(MMC->updateChecker().get(), &UpdateChecker::channelListLoaded, this,
+ &MultiMCPage::refreshUpdateChannelList);
+
+ if (MMC->updateChecker()->hasChannels())
+ {
+ refreshUpdateChannelList();
+ }
+ else
+ {
+ MMC->updateChecker()->updateChanList(false);
+ }
+ }
+ else
+ {
+ ui->updateSettingsBox->setHidden(true);
+ }
+ connect(ui->fontSizeBox, SIGNAL(valueChanged(int)), SLOT(refreshFontPreview()));
+ connect(ui->consoleFont, SIGNAL(currentFontChanged(QFont)), SLOT(refreshFontPreview()));
}
MultiMCPage::~MultiMCPage()
{
- delete ui;
+ delete ui;
}
bool MultiMCPage::apply()
{
- applySettings();
- return true;
+ applySettings();
+ return true;
}
void MultiMCPage::on_instDirBrowseBtn_clicked()
{
- QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Instance Folder"), ui->instDirTextBox->text());
-
- // do not allow current dir - it's dirty. Do not allow dirs that don't exist
- if (!raw_dir.isEmpty() && QDir(raw_dir).exists())
- {
- QString cooked_dir = FS::NormalizePath(raw_dir);
- if (FS::checkProblemticPathJava(QDir(cooked_dir)))
- {
- QMessageBox warning;
- warning.setText(tr("You're trying to specify an instance folder which\'s path "
- "contains at least one \'!\'. "
- "Java is known to cause problems if that is the case, your "
- "instances (probably) won't start!"));
- warning.setInformativeText(
- tr("Do you really want to use this path? "
- "Selecting \"No\" will close this and not alter your instance path."));
- warning.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
- int result = warning.exec();
- if (result == QMessageBox::Yes)
- {
- ui->instDirTextBox->setText(cooked_dir);
- }
- }
- else
- {
- ui->instDirTextBox->setText(cooked_dir);
- }
- }
+ QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Instance Folder"), ui->instDirTextBox->text());
+
+ // do not allow current dir - it's dirty. Do not allow dirs that don't exist
+ if (!raw_dir.isEmpty() && QDir(raw_dir).exists())
+ {
+ QString cooked_dir = FS::NormalizePath(raw_dir);
+ if (FS::checkProblemticPathJava(QDir(cooked_dir)))
+ {
+ QMessageBox warning;
+ warning.setText(tr("You're trying to specify an instance folder which\'s path "
+ "contains at least one \'!\'. "
+ "Java is known to cause problems if that is the case, your "
+ "instances (probably) won't start!"));
+ warning.setInformativeText(
+ tr("Do you really want to use this path? "
+ "Selecting \"No\" will close this and not alter your instance path."));
+ warning.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
+ int result = warning.exec();
+ if (result == QMessageBox::Yes)
+ {
+ ui->instDirTextBox->setText(cooked_dir);
+ }
+ }
+ else
+ {
+ ui->instDirTextBox->setText(cooked_dir);
+ }
+ }
}
void MultiMCPage::on_iconsDirBrowseBtn_clicked()
{
- QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Icons Folder"), ui->iconsDirTextBox->text());
-
- // do not allow current dir - it's dirty. Do not allow dirs that don't exist
- if (!raw_dir.isEmpty() && QDir(raw_dir).exists())
- {
- QString cooked_dir = FS::NormalizePath(raw_dir);
- ui->iconsDirTextBox->setText(cooked_dir);
- }
+ QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Icons Folder"), ui->iconsDirTextBox->text());
+
+ // do not allow current dir - it's dirty. Do not allow dirs that don't exist
+ if (!raw_dir.isEmpty() && QDir(raw_dir).exists())
+ {
+ QString cooked_dir = FS::NormalizePath(raw_dir);
+ ui->iconsDirTextBox->setText(cooked_dir);
+ }
}
void MultiMCPage::on_modsDirBrowseBtn_clicked()
{
- QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Mods Folder"), ui->modsDirTextBox->text());
-
- // do not allow current dir - it's dirty. Do not allow dirs that don't exist
- if (!raw_dir.isEmpty() && QDir(raw_dir).exists())
- {
- QString cooked_dir = FS::NormalizePath(raw_dir);
- ui->modsDirTextBox->setText(cooked_dir);
- }
-}
-
-void MultiMCPage::languageIndexChanged(int index)
-{
- auto languageCode = ui->languageBox->itemData(ui->languageBox->currentIndex()).toString();
- if(languageCode.isEmpty())
- {
- qWarning() << "Unknown language at index" << index;
- return;
- }
- auto translations = MMC->translations();
- translations->selectLanguage(languageCode);
- translations->updateLanguage(languageCode);
+ QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Mods Folder"), ui->modsDirTextBox->text());
+
+ // do not allow current dir - it's dirty. Do not allow dirs that don't exist
+ if (!raw_dir.isEmpty() && QDir(raw_dir).exists())
+ {
+ QString cooked_dir = FS::NormalizePath(raw_dir);
+ ui->modsDirTextBox->setText(cooked_dir);
+ }
}
void MultiMCPage::refreshUpdateChannelList()
{
- // Stop listening for selection changes. It's going to change a lot while we update it and
- // we don't need to update the
- // description label constantly.
- QObject::disconnect(ui->updateChannelComboBox, SIGNAL(currentIndexChanged(int)), this,
- SLOT(updateChannelSelectionChanged(int)));
-
- QList<UpdateChecker::ChannelListEntry> channelList = MMC->updateChecker()->getChannelList();
- ui->updateChannelComboBox->clear();
- int selection = -1;
- for (int i = 0; i < channelList.count(); i++)
- {
- UpdateChecker::ChannelListEntry entry = channelList.at(i);
-
- // When it comes to selection, we'll rely on the indexes of a channel entry being the
- // same in the
- // combo box as it is in the update checker's channel list.
- // This probably isn't very safe, but the channel list doesn't change often enough (or
- // at all) for
- // this to be a big deal. Hope it doesn't break...
- ui->updateChannelComboBox->addItem(entry.name);
-
- // If the update channel we just added was the selected one, set the current index in
- // the combo box to it.
- if (entry.id == m_currentUpdateChannel)
- {
- qDebug() << "Selected index" << i << "channel id" << m_currentUpdateChannel;
- selection = i;
- }
- }
-
- ui->updateChannelComboBox->setCurrentIndex(selection);
-
- // Start listening for selection changes again and update the description label.
- QObject::connect(ui->updateChannelComboBox, SIGNAL(currentIndexChanged(int)), this,
- SLOT(updateChannelSelectionChanged(int)));
- refreshUpdateChannelDesc();
-
- // Now that we've updated the channel list, we can enable the combo box.
- // It starts off disabled so that if the channel list hasn't been loaded, it will be
- // disabled.
- ui->updateChannelComboBox->setEnabled(true);
+ // Stop listening for selection changes. It's going to change a lot while we update it and
+ // we don't need to update the
+ // description label constantly.
+ QObject::disconnect(ui->updateChannelComboBox, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(updateChannelSelectionChanged(int)));
+
+ QList<UpdateChecker::ChannelListEntry> channelList = MMC->updateChecker()->getChannelList();
+ ui->updateChannelComboBox->clear();
+ int selection = -1;
+ for (int i = 0; i < channelList.count(); i++)
+ {
+ UpdateChecker::ChannelListEntry entry = channelList.at(i);
+
+ // When it comes to selection, we'll rely on the indexes of a channel entry being the
+ // same in the
+ // combo box as it is in the update checker's channel list.
+ // This probably isn't very safe, but the channel list doesn't change often enough (or
+ // at all) for
+ // this to be a big deal. Hope it doesn't break...
+ ui->updateChannelComboBox->addItem(entry.name);
+
+ // If the update channel we just added was the selected one, set the current index in
+ // the combo box to it.
+ if (entry.id == m_currentUpdateChannel)
+ {
+ qDebug() << "Selected index" << i << "channel id" << m_currentUpdateChannel;
+ selection = i;
+ }
+ }
+
+ ui->updateChannelComboBox->setCurrentIndex(selection);
+
+ // Start listening for selection changes again and update the description label.
+ QObject::connect(ui->updateChannelComboBox, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(updateChannelSelectionChanged(int)));
+ refreshUpdateChannelDesc();
+
+ // Now that we've updated the channel list, we can enable the combo box.
+ // It starts off disabled so that if the channel list hasn't been loaded, it will be
+ // disabled.
+ ui->updateChannelComboBox->setEnabled(true);
}
void MultiMCPage::updateChannelSelectionChanged(int index)
{
- refreshUpdateChannelDesc();
+ refreshUpdateChannelDesc();
}
void MultiMCPage::refreshUpdateChannelDesc()
{
- // Get the channel list.
- QList<UpdateChecker::ChannelListEntry> channelList = MMC->updateChecker()->getChannelList();
- int selectedIndex = ui->updateChannelComboBox->currentIndex();
- if (selectedIndex < 0)
- {
- return;
- }
- if (selectedIndex < channelList.count())
- {
- // Find the channel list entry with the given index.
- UpdateChecker::ChannelListEntry selected = channelList.at(selectedIndex);
-
- // Set the description text.
- ui->updateChannelDescLabel->setText(selected.description);
-
- // Set the currently selected channel ID.
- m_currentUpdateChannel = selected.id;
- }
+ // Get the channel list.
+ QList<UpdateChecker::ChannelListEntry> channelList = MMC->updateChecker()->getChannelList();
+ int selectedIndex = ui->updateChannelComboBox->currentIndex();
+ if (selectedIndex < 0)
+ {
+ return;
+ }
+ if (selectedIndex < channelList.count())
+ {
+ // Find the channel list entry with the given index.
+ UpdateChecker::ChannelListEntry selected = channelList.at(selectedIndex);
+
+ // Set the description text.
+ ui->updateChannelDescLabel->setText(selected.description);
+
+ // Set the currently selected channel ID.
+ m_currentUpdateChannel = selected.id;
+ }
}
void MultiMCPage::applySettings()
{
+<<<<<<< HEAD
auto s = MMC->settings();
// Language
@@ -434,39 +416,232 @@ void MultiMCPage::loadSettings()
{
ui->analyticsCheck->setChecked(s->get("Analytics").toBool());
} */
+=======
+ auto s = MMC->settings();
+
+ if (ui->resetNotificationsBtn->isChecked())
+ {
+ s->set("ShownNotifications", QString());
+ }
+
+ // Updates
+ s->set("AutoUpdate", ui->autoUpdateCheckBox->isChecked());
+ s->set("UpdateChannel", m_currentUpdateChannel);
+ auto original = s->get("IconTheme").toString();
+ //FIXME: make generic
+ switch (ui->themeComboBox->currentIndex())
+ {
+ case 1:
+ s->set("IconTheme", "pe_dark");
+ break;
+ case 2:
+ s->set("IconTheme", "pe_light");
+ break;
+ case 3:
+ s->set("IconTheme", "pe_blue");
+ break;
+ case 4:
+ s->set("IconTheme", "pe_colored");
+ break;
+ case 5:
+ s->set("IconTheme", "OSX");
+ break;
+ case 6:
+ s->set("IconTheme", "iOS");
+ break;
+ case 7:
+ s->set("IconTheme", "flat");
+ break;
+ case 8:
+ s->set("IconTheme", "custom");
+ break;
+ case 0:
+ default:
+ s->set("IconTheme", "multimc");
+ break;
+ }
+
+ if(original != s->get("IconTheme"))
+ {
+ MMC->setIconTheme(s->get("IconTheme").toString());
+ }
+
+ auto originalAppTheme = s->get("ApplicationTheme").toString();
+ auto newAppTheme = ui->themeComboBoxColors->currentData().toString();
+ if(originalAppTheme != newAppTheme)
+ {
+ s->set("ApplicationTheme", newAppTheme);
+ MMC->setApplicationTheme(newAppTheme, false);
+ }
+
+ // Console settings
+ s->set("ShowConsole", ui->showConsoleCheck->isChecked());
+ s->set("AutoCloseConsole", ui->autoCloseConsoleCheck->isChecked());
+ s->set("ShowConsoleOnError", ui->showConsoleErrorCheck->isChecked());
+ QString consoleFontFamily = ui->consoleFont->currentFont().family();
+ s->set("ConsoleFont", consoleFontFamily);
+ s->set("ConsoleFontSize", ui->fontSizeBox->value());
+ s->set("ConsoleMaxLines", ui->lineLimitSpinBox->value());
+ s->set("ConsoleOverflowStop", ui->checkStopLogging->checkState() != Qt::Unchecked);
+
+ // Folders
+ // TODO: Offer to move instances to new instance folder.
+ s->set("InstanceDir", ui->instDirTextBox->text());
+ s->set("CentralModsDir", ui->modsDirTextBox->text());
+ s->set("IconsDir", ui->iconsDirTextBox->text());
+
+ auto sortMode = (InstSortMode)ui->sortingModeGroup->checkedId();
+ switch (sortMode)
+ {
+ case Sort_LastLaunch:
+ s->set("InstSortMode", "LastLaunch");
+ break;
+ case Sort_Name:
+ default:
+ s->set("InstSortMode", "Name");
+ break;
+ }
+
+ // Analytics
+ if(!BuildConfig.ANALYTICS_ID.isEmpty())
+ {
+ s->set("Analytics", ui->analyticsCheck->isChecked());
+ }
+}
+void MultiMCPage::loadSettings()
+{
+ auto s = MMC->settings();
+ // 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 if (theme == "pe_blue")
+ {
+ ui->themeComboBox->setCurrentIndex(3);
+ }
+ else if (theme == "pe_colored")
+ {
+ ui->themeComboBox->setCurrentIndex(4);
+ }
+ else if (theme == "OSX")
+ {
+ ui->themeComboBox->setCurrentIndex(5);
+ }
+ else if (theme == "iOS")
+ {
+ ui->themeComboBox->setCurrentIndex(6);
+ }
+ else if (theme == "flat")
+ {
+ ui->themeComboBox->setCurrentIndex(7);
+ }
+ else if (theme == "custom")
+ {
+ ui->themeComboBox->setCurrentIndex(8);
+ }
+ else
+ {
+ ui->themeComboBox->setCurrentIndex(0);
+ }
+
+ {
+ auto currentTheme = s->get("ApplicationTheme").toString();
+ auto themes = MMC->getValidApplicationThemes();
+ int idx = 0;
+ for(auto &theme: themes)
+ {
+ ui->themeComboBoxColors->addItem(theme->name(), theme->id());
+ if(currentTheme == theme->id())
+ {
+ ui->themeComboBoxColors->setCurrentIndex(idx);
+ }
+ idx++;
+ }
+ }
+
+ // Console settings
+ ui->showConsoleCheck->setChecked(s->get("ShowConsole").toBool());
+ ui->autoCloseConsoleCheck->setChecked(s->get("AutoCloseConsole").toBool());
+ ui->showConsoleErrorCheck->setChecked(s->get("ShowConsoleOnError").toBool());
+ QString fontFamily = MMC->settings()->get("ConsoleFont").toString();
+ QFont consoleFont(fontFamily);
+ ui->consoleFont->setCurrentFont(consoleFont);
+
+ bool conversionOk = true;
+ int fontSize = MMC->settings()->get("ConsoleFontSize").toInt(&conversionOk);
+ if(!conversionOk)
+ {
+ fontSize = 11;
+ }
+ ui->fontSizeBox->setValue(fontSize);
+ refreshFontPreview();
+ ui->lineLimitSpinBox->setValue(s->get("ConsoleMaxLines").toInt());
+ ui->checkStopLogging->setChecked(s->get("ConsoleOverflowStop").toBool());
+
+ // Folders
+ ui->instDirTextBox->setText(s->get("InstanceDir").toString());
+ ui->modsDirTextBox->setText(s->get("CentralModsDir").toString());
+ ui->iconsDirTextBox->setText(s->get("IconsDir").toString());
+
+ QString sortMode = s->get("InstSortMode").toString();
+
+ if (sortMode == "LastLaunch")
+ {
+ ui->sortLastLaunchedBtn->setChecked(true);
+ }
+ else
+ {
+ ui->sortByNameBtn->setChecked(true);
+ }
+
+ // Analytics
+ if(!BuildConfig.ANALYTICS_ID.isEmpty())
+ {
+ ui->analyticsCheck->setChecked(s->get("Analytics").toBool());
+ }
+>>>>>>> origin/stable
}
void MultiMCPage::refreshFontPreview()
{
- int fontSize = ui->fontSizeBox->value();
- QString fontFamily = ui->consoleFont->currentFont().family();
- ui->fontPreview->clear();
- defaultFormat->setFont(QFont(fontFamily, fontSize));
- {
- QTextCharFormat format(*defaultFormat);
- format.setForeground(m_colors->getFront(MessageLevel::Error));
- // append a paragraph/line
- auto workCursor = ui->fontPreview->textCursor();
- workCursor.movePosition(QTextCursor::End);
- workCursor.insertText(tr("[Something/ERROR] A spooky error!"), format);
- workCursor.insertBlock();
- }
- {
- QTextCharFormat format(*defaultFormat);
- format.setForeground(m_colors->getFront(MessageLevel::Message));
- // append a paragraph/line
- auto workCursor = ui->fontPreview->textCursor();
- workCursor.movePosition(QTextCursor::End);
- workCursor.insertText(tr("[Test/INFO] A harmless message..."), format);
- workCursor.insertBlock();
- }
- {
- QTextCharFormat format(*defaultFormat);
- format.setForeground(m_colors->getFront(MessageLevel::Warning));
- // append a paragraph/line
- auto workCursor = ui->fontPreview->textCursor();
- workCursor.movePosition(QTextCursor::End);
- workCursor.insertText(tr("[Something/WARN] A not so spooky warning."), format);
- workCursor.insertBlock();
- }
+ int fontSize = ui->fontSizeBox->value();
+ QString fontFamily = ui->consoleFont->currentFont().family();
+ ui->fontPreview->clear();
+ defaultFormat->setFont(QFont(fontFamily, fontSize));
+ {
+ QTextCharFormat format(*defaultFormat);
+ format.setForeground(m_colors->getFront(MessageLevel::Error));
+ // append a paragraph/line
+ auto workCursor = ui->fontPreview->textCursor();
+ workCursor.movePosition(QTextCursor::End);
+ workCursor.insertText(tr("[Something/ERROR] A spooky error!"), format);
+ workCursor.insertBlock();
+ }
+ {
+ QTextCharFormat format(*defaultFormat);
+ format.setForeground(m_colors->getFront(MessageLevel::Message));
+ // append a paragraph/line
+ auto workCursor = ui->fontPreview->textCursor();
+ workCursor.movePosition(QTextCursor::End);
+ workCursor.insertText(tr("[Test/INFO] A harmless message..."), format);
+ workCursor.insertBlock();
+ }
+ {
+ QTextCharFormat format(*defaultFormat);
+ format.setForeground(m_colors->getFront(MessageLevel::Warning));
+ // append a paragraph/line
+ auto workCursor = ui->fontPreview->textCursor();
+ workCursor.movePosition(QTextCursor::End);
+ workCursor.insertText(tr("[Something/WARN] A not so spooky warning."), format);
+ workCursor.insertBlock();
+ }
}
diff --git a/application/pages/global/MultiMCPage.h b/application/pages/global/MultiMCPage.h
index d5194c0e..27a801be 100644
--- a/application/pages/global/MultiMCPage.h
+++ b/application/pages/global/MultiMCPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,71 +34,69 @@ class MultiMCPage;
class MultiMCPage : public QWidget, public BasePage
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit MultiMCPage(QWidget *parent = 0);
- ~MultiMCPage();
-
- QString displayName() const override
- {
- return "MultiMC";
- }
- QIcon icon() const override
- {
- return MMC->getThemedIcon("multimc");
- }
- QString id() const override
- {
- return "multimc-settings";
- }
- QString helpPage() const override
- {
- return "MultiMC-settings";
- }
- bool apply() override;
+ explicit MultiMCPage(QWidget *parent = 0);
+ ~MultiMCPage();
+
+ QString displayName() const override
+ {
+ return "MultiMC";
+ }
+ QIcon icon() const override
+ {
+ return MMC->getThemedIcon("multimc");
+ }
+ QString id() const override
+ {
+ return "multimc-settings";
+ }
+ QString helpPage() const override
+ {
+ return "MultiMC-settings";
+ }
+ bool apply() override;
private:
- void applySettings();
- void loadSettings();
+ void applySettings();
+ void loadSettings();
private
slots:
- void on_instDirBrowseBtn_clicked();
- void on_modsDirBrowseBtn_clicked();
- void on_iconsDirBrowseBtn_clicked();
+ void on_instDirBrowseBtn_clicked();
+ void on_modsDirBrowseBtn_clicked();
+ void on_iconsDirBrowseBtn_clicked();
- void languageIndexChanged(int index);
+ /*!
+ * Updates the list of update channels in the combo box.
+ */
+ void refreshUpdateChannelList();
- /*!
- * Updates the list of update channels in the combo box.
- */
- void refreshUpdateChannelList();
+ /*!
+ * Updates the channel description label.
+ */
+ void refreshUpdateChannelDesc();
- /*!
- * Updates the channel description label.
- */
- void refreshUpdateChannelDesc();
+ /*!
+ * Updates the font preview
+ */
+ void refreshFontPreview();
- /*!
- * Updates the font preview
- */
- void refreshFontPreview();
-
- void updateChannelSelectionChanged(int index);
+ void updateChannelSelectionChanged(int index);
private:
- Ui::MultiMCPage *ui;
+ Ui::MultiMCPage *ui;
- /*!
- * Stores the currently selected update channel.
- */
- QString m_currentUpdateChannel;
+ /*!
+ * Stores the currently selected update channel.
+ */
+ QString m_currentUpdateChannel;
- // default format for the font preview...
- QTextCharFormat *defaultFormat;
+ // default format for the font preview...
+ QTextCharFormat *defaultFormat;
- std::unique_ptr<LogColorCache> m_colors;
+ std::unique_ptr<LogColorCache> m_colors;
- std::shared_ptr<TranslationsModel> m_languageModel;
+ std::shared_ptr<TranslationsModel> m_languageModel;
};
diff --git a/application/pages/global/MultiMCPage.ui b/application/pages/global/MultiMCPage.ui
index 124401c3..ea034919 100644
--- a/application/pages/global/MultiMCPage.ui
+++ b/application/pages/global/MultiMCPage.ui
@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
- <width>467</width>
+ <width>514</width>
<height>629</height>
</rect>
</property>
@@ -229,18 +229,6 @@
</widget>
</item>
<item>
- <widget class="QGroupBox" name="groupBox_2">
- <property name="title">
- <string>Language:</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QComboBox" name="languageBox"/>
- </item>
- </layout>
- </widget>
- </item>
- <item>
<widget class="QGroupBox" name="themeBox">
<property name="title">
<string>Theme</string>
@@ -570,7 +558,6 @@
<tabstop>resetNotificationsBtn</tabstop>
<tabstop>sortLastLaunchedBtn</tabstop>
<tabstop>sortByNameBtn</tabstop>
- <tabstop>languageBox</tabstop>
<tabstop>themeComboBox</tabstop>
<tabstop>themeComboBoxColors</tabstop>
<tabstop>showConsoleCheck</tabstop>
diff --git a/application/pages/global/PackagesPage.cpp b/application/pages/global/PackagesPage.cpp
index 7cf1e3f5..1bbbed7a 100644
--- a/application/pages/global/PackagesPage.cpp
+++ b/application/pages/global/PackagesPage.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2015-2018 MultiMC Contributors
+/* Copyright 2015-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,192 +33,192 @@ using namespace Meta;
static QString formatRequires(const VersionPtr &version)
{
- QStringList lines;
- auto & reqs = version->requires();
- auto iter = reqs.begin();
- while (iter != reqs.end())
- {
- auto &uid = iter->uid;
- auto &version = iter->equalsVersion;
- const QString readable = ENV.metadataIndex()->hasUid(uid) ? ENV.metadataIndex()->get(uid)->humanReadable() : uid;
- if(!version.isEmpty())
- {
- lines.append(QString("%1 (%2)").arg(readable, version));
- }
- else
- {
- lines.append(QString("%1").arg(readable));
- }
- iter++;
- }
- return lines.join('\n');
+ QStringList lines;
+ auto & reqs = version->requires();
+ auto iter = reqs.begin();
+ while (iter != reqs.end())
+ {
+ auto &uid = iter->uid;
+ auto &version = iter->equalsVersion;
+ const QString readable = ENV.metadataIndex()->hasUid(uid) ? ENV.metadataIndex()->get(uid)->humanReadable() : uid;
+ if(!version.isEmpty())
+ {
+ lines.append(QString("%1 (%2)").arg(readable, version));
+ }
+ else
+ {
+ lines.append(QString("%1").arg(readable));
+ }
+ iter++;
+ }
+ return lines.join('\n');
}
PackagesPage::PackagesPage(QWidget *parent) :
- QWidget(parent),
- ui(new Ui::PackagesPage)
+ QWidget(parent),
+ ui(new Ui::PackagesPage)
{
- ui->setupUi(this);
- ui->tabWidget->tabBar()->hide();
-
- m_fileProxy = new QSortFilterProxyModel(this);
- m_fileProxy->setSortRole(Qt::DisplayRole);
- m_fileProxy->setSortCaseSensitivity(Qt::CaseInsensitive);
- m_fileProxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
- m_fileProxy->setFilterRole(Qt::DisplayRole);
- m_fileProxy->setFilterKeyColumn(0);
- m_fileProxy->sort(0);
- m_fileProxy->setSourceModel(ENV.metadataIndex().get());
- ui->indexView->setModel(m_fileProxy);
-
- m_filterProxy = new QSortFilterProxyModel(this);
- m_filterProxy->setSortRole(VersionList::SortRole);
- m_filterProxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
- m_filterProxy->setFilterRole(Qt::DisplayRole);
- m_filterProxy->setFilterKeyColumn(0);
- m_filterProxy->sort(0, Qt::DescendingOrder);
- ui->versionsView->setModel(m_filterProxy);
-
- m_versionProxy = new VersionProxyModel(this);
- m_filterProxy->setSourceModel(m_versionProxy);
-
- connect(ui->indexView->selectionModel(), &QItemSelectionModel::currentChanged, this, &PackagesPage::updateCurrentVersionList);
- connect(ui->versionsView->selectionModel(), &QItemSelectionModel::currentChanged, this, &PackagesPage::updateVersion);
- connect(m_filterProxy, &QSortFilterProxyModel::dataChanged, this, &PackagesPage::versionListDataChanged);
-
- updateCurrentVersionList(QModelIndex());
- updateVersion();
+ ui->setupUi(this);
+ ui->tabWidget->tabBar()->hide();
+
+ m_fileProxy = new QSortFilterProxyModel(this);
+ m_fileProxy->setSortRole(Qt::DisplayRole);
+ m_fileProxy->setSortCaseSensitivity(Qt::CaseInsensitive);
+ m_fileProxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
+ m_fileProxy->setFilterRole(Qt::DisplayRole);
+ m_fileProxy->setFilterKeyColumn(0);
+ m_fileProxy->sort(0);
+ m_fileProxy->setSourceModel(ENV.metadataIndex().get());
+ ui->indexView->setModel(m_fileProxy);
+
+ m_filterProxy = new QSortFilterProxyModel(this);
+ m_filterProxy->setSortRole(VersionList::SortRole);
+ m_filterProxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
+ m_filterProxy->setFilterRole(Qt::DisplayRole);
+ m_filterProxy->setFilterKeyColumn(0);
+ m_filterProxy->sort(0, Qt::DescendingOrder);
+ ui->versionsView->setModel(m_filterProxy);
+
+ m_versionProxy = new VersionProxyModel(this);
+ m_filterProxy->setSourceModel(m_versionProxy);
+
+ connect(ui->indexView->selectionModel(), &QItemSelectionModel::currentChanged, this, &PackagesPage::updateCurrentVersionList);
+ connect(ui->versionsView->selectionModel(), &QItemSelectionModel::currentChanged, this, &PackagesPage::updateVersion);
+ connect(m_filterProxy, &QSortFilterProxyModel::dataChanged, this, &PackagesPage::versionListDataChanged);
+
+ updateCurrentVersionList(QModelIndex());
+ updateVersion();
}
PackagesPage::~PackagesPage()
{
- delete ui;
+ delete ui;
}
QIcon PackagesPage::icon() const
{
- return MMC->getThemedIcon("packages");
+ return MMC->getThemedIcon("packages");
}
void PackagesPage::on_refreshIndexBtn_clicked()
{
- ENV.metadataIndex()->load(Net::Mode::Online);
+ ENV.metadataIndex()->load(Net::Mode::Online);
}
void PackagesPage::on_refreshFileBtn_clicked()
{
- VersionListPtr list = ui->indexView->currentIndex().data(Index::ListPtrRole).value<VersionListPtr>();
- if (!list)
- {
- return;
- }
- list->load(Net::Mode::Online);
+ VersionListPtr list = ui->indexView->currentIndex().data(Index::ListPtrRole).value<VersionListPtr>();
+ if (!list)
+ {
+ return;
+ }
+ list->load(Net::Mode::Online);
}
void PackagesPage::on_refreshVersionBtn_clicked()
{
- VersionPtr version = ui->versionsView->currentIndex().data(VersionList::VersionPtrRole).value<VersionPtr>();
- if (!version)
- {
- return;
- }
- version->load(Net::Mode::Online);
+ VersionPtr version = ui->versionsView->currentIndex().data(VersionList::VersionPtrRole).value<VersionPtr>();
+ if (!version)
+ {
+ return;
+ }
+ version->load(Net::Mode::Online);
}
void PackagesPage::on_fileSearchEdit_textChanged(const QString &search)
{
- if (search.isEmpty())
- {
- m_fileProxy->setFilterFixedString(QString());
- }
- else
- {
- QStringList parts = search.split(' ');
- std::transform(parts.begin(), parts.end(), parts.begin(), &QRegularExpression::escape);
- m_fileProxy->setFilterRegExp(".*" + parts.join(".*") + ".*");
- }
+ if (search.isEmpty())
+ {
+ m_fileProxy->setFilterFixedString(QString());
+ }
+ else
+ {
+ QStringList parts = search.split(' ');
+ std::transform(parts.begin(), parts.end(), parts.begin(), &QRegularExpression::escape);
+ m_fileProxy->setFilterRegExp(".*" + parts.join(".*") + ".*");
+ }
}
void PackagesPage::on_versionSearchEdit_textChanged(const QString &search)
{
- if (search.isEmpty())
- {
- m_filterProxy->setFilterFixedString(QString());
- }
- else
- {
- QStringList parts = search.split(' ');
- std::transform(parts.begin(), parts.end(), parts.begin(), &QRegularExpression::escape);
- m_filterProxy->setFilterRegExp(".*" + parts.join(".*") + ".*");
- }
+ if (search.isEmpty())
+ {
+ m_filterProxy->setFilterFixedString(QString());
+ }
+ else
+ {
+ QStringList parts = search.split(' ');
+ std::transform(parts.begin(), parts.end(), parts.begin(), &QRegularExpression::escape);
+ m_filterProxy->setFilterRegExp(".*" + parts.join(".*") + ".*");
+ }
}
void PackagesPage::updateCurrentVersionList(const QModelIndex &index)
{
- if (index.isValid())
- {
- VersionListPtr list = index.data(Index::ListPtrRole).value<VersionListPtr>();
- ui->versionsBox->setEnabled(true);
- ui->refreshFileBtn->setEnabled(true);
- ui->fileUidLabel->setEnabled(true);
- ui->fileUid->setText(list->uid());
- ui->fileNameLabel->setEnabled(true);
- ui->fileName->setText(list->name());
- m_versionProxy->setSourceModel(list.get());
- ui->refreshFileBtn->setText(tr("Refresh %1").arg(list->humanReadable()));
- list->load(Net::Mode::Offline);
- }
- else
- {
- ui->versionsBox->setEnabled(false);
- ui->refreshFileBtn->setEnabled(false);
- ui->fileUidLabel->setEnabled(false);
- ui->fileUid->clear();
- ui->fileNameLabel->setEnabled(false);
- ui->fileName->clear();
- m_versionProxy->setSourceModel(nullptr);
- ui->refreshFileBtn->setText(tr("Refresh"));
- }
+ if (index.isValid())
+ {
+ VersionListPtr list = index.data(Index::ListPtrRole).value<VersionListPtr>();
+ ui->versionsBox->setEnabled(true);
+ ui->refreshFileBtn->setEnabled(true);
+ ui->fileUidLabel->setEnabled(true);
+ ui->fileUid->setText(list->uid());
+ ui->fileNameLabel->setEnabled(true);
+ ui->fileName->setText(list->name());
+ m_versionProxy->setSourceModel(list.get());
+ ui->refreshFileBtn->setText(tr("Refresh %1").arg(list->humanReadable()));
+ list->load(Net::Mode::Offline);
+ }
+ else
+ {
+ ui->versionsBox->setEnabled(false);
+ ui->refreshFileBtn->setEnabled(false);
+ ui->fileUidLabel->setEnabled(false);
+ ui->fileUid->clear();
+ ui->fileNameLabel->setEnabled(false);
+ ui->fileName->clear();
+ m_versionProxy->setSourceModel(nullptr);
+ ui->refreshFileBtn->setText(tr("Refresh"));
+ }
}
void PackagesPage::versionListDataChanged(const QModelIndex &tl, const QModelIndex &br)
{
- if (QItemSelection(tl, br).contains(ui->versionsView->currentIndex()))
- {
- updateVersion();
- }
+ if (QItemSelection(tl, br).contains(ui->versionsView->currentIndex()))
+ {
+ updateVersion();
+ }
}
void PackagesPage::updateVersion()
{
- VersionPtr version = std::dynamic_pointer_cast<Version>(
- ui->versionsView->currentIndex().data(VersionList::VersionPointerRole).value<BaseVersionPtr>());
- if (version)
- {
- ui->refreshVersionBtn->setEnabled(true);
- ui->versionVersionLabel->setEnabled(true);
- ui->versionVersion->setText(version->version());
- ui->versionTimeLabel->setEnabled(true);
- ui->versionTime->setText(version->time().toString("yyyy-MM-dd HH:mm"));
- ui->versionTypeLabel->setEnabled(true);
- ui->versionType->setText(version->type());
- ui->versionRequiresLabel->setEnabled(true);
- ui->versionRequires->setText(formatRequires(version));
- ui->refreshVersionBtn->setText(tr("Refresh %1").arg(version->version()));
- }
- else
- {
- ui->refreshVersionBtn->setEnabled(false);
- ui->versionVersionLabel->setEnabled(false);
- ui->versionVersion->clear();
- ui->versionTimeLabel->setEnabled(false);
- ui->versionTime->clear();
- ui->versionTypeLabel->setEnabled(false);
- ui->versionType->clear();
- ui->versionRequiresLabel->setEnabled(false);
- ui->versionRequires->clear();
- ui->refreshVersionBtn->setText(tr("Refresh"));
- }
+ VersionPtr version = std::dynamic_pointer_cast<Version>(
+ ui->versionsView->currentIndex().data(VersionList::VersionPointerRole).value<BaseVersionPtr>());
+ if (version)
+ {
+ ui->refreshVersionBtn->setEnabled(true);
+ ui->versionVersionLabel->setEnabled(true);
+ ui->versionVersion->setText(version->version());
+ ui->versionTimeLabel->setEnabled(true);
+ ui->versionTime->setText(version->time().toString("yyyy-MM-dd HH:mm"));
+ ui->versionTypeLabel->setEnabled(true);
+ ui->versionType->setText(version->type());
+ ui->versionRequiresLabel->setEnabled(true);
+ ui->versionRequires->setText(formatRequires(version));
+ ui->refreshVersionBtn->setText(tr("Refresh %1").arg(version->version()));
+ }
+ else
+ {
+ ui->refreshVersionBtn->setEnabled(false);
+ ui->versionVersionLabel->setEnabled(false);
+ ui->versionVersion->clear();
+ ui->versionTimeLabel->setEnabled(false);
+ ui->versionTime->clear();
+ ui->versionTypeLabel->setEnabled(false);
+ ui->versionType->clear();
+ ui->versionRequiresLabel->setEnabled(false);
+ ui->versionRequires->clear();
+ ui->refreshVersionBtn->setText(tr("Refresh"));
+ }
}
void PackagesPage::openedImpl()
{
- ENV.metadataIndex()->load(Net::Mode::Offline);
+ ENV.metadataIndex()->load(Net::Mode::Offline);
}
diff --git a/application/pages/global/PackagesPage.h b/application/pages/global/PackagesPage.h
index ad155d9e..872961a5 100644
--- a/application/pages/global/PackagesPage.h
+++ b/application/pages/global/PackagesPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2015-2018 MultiMC Contributors
+/* Copyright 2015-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,30 +28,30 @@ class VersionProxyModel;
class PackagesPage : public QWidget, public BasePage
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit PackagesPage(QWidget *parent = 0);
- ~PackagesPage();
+ explicit PackagesPage(QWidget *parent = 0);
+ ~PackagesPage();
- QString id() const override { return "packages-global"; }
- QString displayName() const override { return tr("Packages"); }
- QIcon icon() const override;
- void openedImpl() override;
+ QString id() const override { return "packages-global"; }
+ QString displayName() const override { return tr("Packages"); }
+ QIcon icon() const override;
+ void openedImpl() override;
private slots:
- void on_refreshIndexBtn_clicked();
- void on_refreshFileBtn_clicked();
- void on_refreshVersionBtn_clicked();
- void on_fileSearchEdit_textChanged(const QString &search);
- void on_versionSearchEdit_textChanged(const QString &search);
- void updateCurrentVersionList(const QModelIndex &index);
- void versionListDataChanged(const QModelIndex &tl, const QModelIndex &br);
+ void on_refreshIndexBtn_clicked();
+ void on_refreshFileBtn_clicked();
+ void on_refreshVersionBtn_clicked();
+ void on_fileSearchEdit_textChanged(const QString &search);
+ void on_versionSearchEdit_textChanged(const QString &search);
+ void updateCurrentVersionList(const QModelIndex &index);
+ void versionListDataChanged(const QModelIndex &tl, const QModelIndex &br);
private:
- Ui::PackagesPage *ui;
- QSortFilterProxyModel *m_fileProxy;
- QSortFilterProxyModel *m_filterProxy;
- VersionProxyModel *m_versionProxy;
+ Ui::PackagesPage *ui;
+ QSortFilterProxyModel *m_fileProxy;
+ QSortFilterProxyModel *m_filterProxy;
+ VersionProxyModel *m_versionProxy;
- void updateVersion();
+ void updateVersion();
};
diff --git a/application/pages/global/PasteEEPage.cpp b/application/pages/global/PasteEEPage.cpp
index 83dd6411..5355d63a 100644
--- a/application/pages/global/PasteEEPage.cpp
+++ b/application/pages/global/PasteEEPage.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
#include <QMessageBox>
#include <QFileDialog>
#include <QStandardPaths>
+#include <QTabBar>
#include "settings/SettingsObject.h"
#include "tools/BaseProfiler.h"
@@ -26,56 +27,56 @@
#include <QTabBar>
PasteEEPage::PasteEEPage(QWidget *parent) :
- QWidget(parent),
- ui(new Ui::PasteEEPage)
+ QWidget(parent),
+ ui(new Ui::PasteEEPage)
{
- ui->setupUi(this);
- ui->tabWidget->tabBar()->hide();\
- connect(ui->customAPIkeyEdit, &QLineEdit::textEdited, this, &PasteEEPage::textEdited);
- loadSettings();
+ ui->setupUi(this);
+ ui->tabWidget->tabBar()->hide();\
+ connect(ui->customAPIkeyEdit, &QLineEdit::textEdited, this, &PasteEEPage::textEdited);
+ loadSettings();
}
PasteEEPage::~PasteEEPage()
{
- delete ui;
+ delete ui;
}
void PasteEEPage::loadSettings()
{
- auto s = MMC->settings();
- QString keyToUse = s->get("PasteEEAPIKey").toString();
- if(keyToUse == "multimc")
- {
- ui->multimcButton->setChecked(true);
- }
- else
- {
- ui->customButton->setChecked(true);
- ui->customAPIkeyEdit->setText(keyToUse);
- }
+ auto s = MMC->settings();
+ QString keyToUse = s->get("PasteEEAPIKey").toString();
+ if(keyToUse == "multimc")
+ {
+ ui->multimcButton->setChecked(true);
+ }
+ else
+ {
+ ui->customButton->setChecked(true);
+ ui->customAPIkeyEdit->setText(keyToUse);
+ }
}
void PasteEEPage::applySettings()
{
- auto s = MMC->settings();
+ auto s = MMC->settings();
- QString pasteKeyToUse;
- if (ui->customButton->isChecked())
- pasteKeyToUse = ui->customAPIkeyEdit->text();
- else
- {
- pasteKeyToUse = "multimc";
- }
- s->set("PasteEEAPIKey", pasteKeyToUse);
+ QString pasteKeyToUse;
+ if (ui->customButton->isChecked())
+ pasteKeyToUse = ui->customAPIkeyEdit->text();
+ else
+ {
+ pasteKeyToUse = "multimc";
+ }
+ s->set("PasteEEAPIKey", pasteKeyToUse);
}
bool PasteEEPage::apply()
{
- applySettings();
- return true;
+ applySettings();
+ return true;
}
void PasteEEPage::textEdited(const QString& text)
{
- ui->customButton->setChecked(true);
+ ui->customButton->setChecked(true);
}
diff --git a/application/pages/global/PasteEEPage.h b/application/pages/global/PasteEEPage.h
index 1b152577..78cf41f4 100644
--- a/application/pages/global/PasteEEPage.h
+++ b/application/pages/global/PasteEEPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,37 +26,37 @@ class PasteEEPage;
class PasteEEPage : public QWidget, public BasePage
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit PasteEEPage(QWidget *parent = 0);
- ~PasteEEPage();
-
- QString displayName() const override
- {
- return tr("Log Upload");
- }
- QIcon icon() const override
- {
- return MMC->getThemedIcon("log");
- }
- QString id() const override
- {
- return "log-upload";
- }
- QString helpPage() const override
- {
- return "Log-Upload";
- }
- virtual bool apply() override;
+ explicit PasteEEPage(QWidget *parent = 0);
+ ~PasteEEPage();
+
+ QString displayName() const override
+ {
+ return tr("Log Upload");
+ }
+ QIcon icon() const override
+ {
+ return MMC->getThemedIcon("log");
+ }
+ QString id() const override
+ {
+ return "log-upload";
+ }
+ QString helpPage() const override
+ {
+ return "Log-Upload";
+ }
+ virtual bool apply() override;
private:
- void loadSettings();
- void applySettings();
+ void loadSettings();
+ void applySettings();
private slots:
- void textEdited(const QString &text);
+ void textEdited(const QString &text);
private:
- Ui::PasteEEPage *ui;
+ Ui::PasteEEPage *ui;
};
diff --git a/application/pages/global/ProxyPage.cpp b/application/pages/global/ProxyPage.cpp
index 7dbcb860..ee56a54e 100644
--- a/application/pages/global/ProxyPage.cpp
+++ b/application/pages/global/ProxyPage.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 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,81 +16,86 @@
#include "ProxyPage.h"
#include "ui_ProxyPage.h"
+#include <QTabBar>
+
#include "settings/SettingsObject.h"
#include "MultiMC.h"
-#include <QTabBar>
+#include "Env.h"
ProxyPage::ProxyPage(QWidget *parent) : QWidget(parent), ui(new Ui::ProxyPage)
{
- ui->setupUi(this);
- ui->tabWidget->tabBar()->hide();
- loadSettings();
- updateCheckboxStuff();
+ ui->setupUi(this);
+ ui->tabWidget->tabBar()->hide();
+ loadSettings();
+ updateCheckboxStuff();
- connect(ui->proxyGroup, SIGNAL(buttonClicked(int)), SLOT(proxyChanged(int)));
+ connect(ui->proxyGroup, SIGNAL(buttonClicked(int)), SLOT(proxyChanged(int)));
}
ProxyPage::~ProxyPage()
{
- delete ui;
+ delete ui;
}
bool ProxyPage::apply()
{
- applySettings();
- return true;
+ applySettings();
+ return true;
}
void ProxyPage::updateCheckboxStuff()
{
- ui->proxyAddrBox->setEnabled(!ui->proxyNoneBtn->isChecked() &&
- !ui->proxyDefaultBtn->isChecked());
- ui->proxyAuthBox->setEnabled(!ui->proxyNoneBtn->isChecked() &&
- !ui->proxyDefaultBtn->isChecked());
+ ui->proxyAddrBox->setEnabled(!ui->proxyNoneBtn->isChecked() &&
+ !ui->proxyDefaultBtn->isChecked());
+ ui->proxyAuthBox->setEnabled(!ui->proxyNoneBtn->isChecked() &&
+ !ui->proxyDefaultBtn->isChecked());
}
void ProxyPage::proxyChanged(int)
{
- updateCheckboxStuff();
+ updateCheckboxStuff();
}
void ProxyPage::applySettings()
{
- auto s = MMC->settings();
+ auto s = MMC->settings();
+
+ // Proxy
+ QString proxyType = "None";
+ if (ui->proxyDefaultBtn->isChecked())
+ proxyType = "Default";
+ else if (ui->proxyNoneBtn->isChecked())
+ proxyType = "None";
+ else if (ui->proxySOCKS5Btn->isChecked())
+ proxyType = "SOCKS5";
+ else if (ui->proxyHTTPBtn->isChecked())
+ proxyType = "HTTP";
- // Proxy
- QString proxyType = "None";
- if (ui->proxyDefaultBtn->isChecked())
- proxyType = "Default";
- else if (ui->proxyNoneBtn->isChecked())
- proxyType = "None";
- else if (ui->proxySOCKS5Btn->isChecked())
- proxyType = "SOCKS5";
- else if (ui->proxyHTTPBtn->isChecked())
- proxyType = "HTTP";
+ s->set("ProxyType", proxyType);
+ s->set("ProxyAddr", ui->proxyAddrEdit->text());
+ s->set("ProxyPort", ui->proxyPortEdit->value());
+ s->set("ProxyUser", ui->proxyUserEdit->text());
+ s->set("ProxyPass", ui->proxyPassEdit->text());
- s->set("ProxyType", proxyType);
- s->set("ProxyAddr", ui->proxyAddrEdit->text());
- s->set("ProxyPort", ui->proxyPortEdit->value());
- s->set("ProxyUser", ui->proxyUserEdit->text());
- s->set("ProxyPass", ui->proxyPassEdit->text());
+ ENV.updateProxySettings(proxyType, ui->proxyAddrEdit->text(), ui->proxyPortEdit->value(),
+ ui->proxyUserEdit->text(), ui->proxyPassEdit->text());
}
void ProxyPage::loadSettings()
{
- auto s = MMC->settings();
- // Proxy
- QString proxyType = s->get("ProxyType").toString();
- if (proxyType == "Default")
- ui->proxyDefaultBtn->setChecked(true);
- else if (proxyType == "None")
- ui->proxyNoneBtn->setChecked(true);
- else if (proxyType == "SOCKS5")
- ui->proxySOCKS5Btn->setChecked(true);
- else if (proxyType == "HTTP")
- ui->proxyHTTPBtn->setChecked(true);
+ auto s = MMC->settings();
+ // Proxy
+ QString proxyType = s->get("ProxyType").toString();
+ if (proxyType == "Default")
+ ui->proxyDefaultBtn->setChecked(true);
+ else if (proxyType == "None")
+ ui->proxyNoneBtn->setChecked(true);
+ else if (proxyType == "SOCKS5")
+ ui->proxySOCKS5Btn->setChecked(true);
+ else if (proxyType == "HTTP")
+ ui->proxyHTTPBtn->setChecked(true);
- ui->proxyAddrEdit->setText(s->get("ProxyAddr").toString());
- ui->proxyPortEdit->setValue(s->get("ProxyPort").value<qint16>());
- ui->proxyUserEdit->setText(s->get("ProxyUser").toString());
- ui->proxyPassEdit->setText(s->get("ProxyPass").toString());
+ ui->proxyAddrEdit->setText(s->get("ProxyAddr").toString());
+ ui->proxyPortEdit->setValue(s->get("ProxyPort").value<qint16>());
+ ui->proxyUserEdit->setText(s->get("ProxyUser").toString());
+ ui->proxyPassEdit->setText(s->get("ProxyPass").toString());
}
diff --git a/application/pages/global/ProxyPage.h b/application/pages/global/ProxyPage.h
index 565c2857..d87bc120 100644
--- a/application/pages/global/ProxyPage.h
+++ b/application/pages/global/ProxyPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,39 +28,39 @@ class ProxyPage;
class ProxyPage : public QWidget, public BasePage
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit ProxyPage(QWidget *parent = 0);
- ~ProxyPage();
+ explicit ProxyPage(QWidget *parent = 0);
+ ~ProxyPage();
- QString displayName() const override
- {
- return tr("Proxy");
- }
- QIcon icon() const override
- {
- return MMC->getThemedIcon("proxy");
- }
- QString id() const override
- {
- return "proxy-settings";
- }
- QString helpPage() const override
- {
- return "Proxy-settings";
- }
- bool apply() override;
+ QString displayName() const override
+ {
+ return tr("Proxy");
+ }
+ QIcon icon() const override
+ {
+ return MMC->getThemedIcon("proxy");
+ }
+ QString id() const override
+ {
+ return "proxy-settings";
+ }
+ QString helpPage() const override
+ {
+ return "Proxy-settings";
+ }
+ bool apply() override;
private:
- void updateCheckboxStuff();
- void applySettings();
- void loadSettings();
+ void updateCheckboxStuff();
+ void applySettings();
+ void loadSettings();
private
slots:
- void proxyChanged(int);
+ void proxyChanged(int);
private:
- Ui::ProxyPage *ui;
+ Ui::ProxyPage *ui;
};
diff --git a/application/pages/instance/GameOptionsPage.cpp b/application/pages/instance/GameOptionsPage.cpp
new file mode 100644
index 00000000..5555fc79
--- /dev/null
+++ b/application/pages/instance/GameOptionsPage.cpp
@@ -0,0 +1,40 @@
+#include "GameOptionsPage.h"
+#include "ui_GameOptionsPage.h"
+#include "minecraft/MinecraftInstance.h"
+#include "minecraft/gameoptions/GameOptions.h"
+
+GameOptionsPage::GameOptionsPage(MinecraftInstance * inst, QWidget* parent)
+ : QWidget(parent), ui(new Ui::GameOptionsPage)
+{
+ ui->setupUi(this);
+ ui->tabWidget->tabBar()->hide();
+ m_model = inst->gameOptionsModel();
+ ui->optionsView->setModel(m_model.get());
+ auto head = ui->optionsView->header();
+ if(head->count())
+ {
+ head->setSectionResizeMode(0, QHeaderView::ResizeToContents);
+ for(int i = 1; i < head->count(); i++)
+ {
+ head->setSectionResizeMode(i, QHeaderView::Stretch);
+ }
+ }
+}
+
+GameOptionsPage::~GameOptionsPage()
+{
+ // m_model->save();
+}
+
+void GameOptionsPage::openedImpl()
+{
+ // m_model->observe();
+}
+
+void GameOptionsPage::closedImpl()
+{
+ // m_model->unobserve();
+}
+
+#include "GameOptionsPage.moc"
+
diff --git a/application/pages/instance/GameOptionsPage.h b/application/pages/instance/GameOptionsPage.h
new file mode 100644
index 00000000..ae47747f
--- /dev/null
+++ b/application/pages/instance/GameOptionsPage.h
@@ -0,0 +1,63 @@
+/* Copyright 2013-2019 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 <QString>
+
+#include "pages/BasePage.h"
+#include <MultiMC.h>
+
+namespace Ui
+{
+class GameOptionsPage;
+}
+
+class GameOptions;
+class MinecraftInstance;
+
+class GameOptionsPage : public QWidget, public BasePage
+{
+ Q_OBJECT
+
+public:
+ explicit GameOptionsPage(MinecraftInstance *inst, QWidget *parent = 0);
+ virtual ~GameOptionsPage();
+
+ void openedImpl() override;
+ void closedImpl() override;
+
+ virtual QString displayName() const override
+ {
+ return tr("Game Options");
+ }
+ virtual QIcon icon() const override
+ {
+ return MMC->getThemedIcon("settings");
+ }
+ virtual QString id() const override
+ {
+ return "gameoptions";
+ }
+ virtual QString helpPage() const override
+ {
+ return "Game-Options-management";
+ }
+
+private: // data
+ Ui::GameOptionsPage *ui = nullptr;
+ std::shared_ptr<GameOptions> m_model;
+};
diff --git a/application/pages/instance/GameOptionsPage.ui b/application/pages/instance/GameOptionsPage.ui
new file mode 100644
index 00000000..f0a5ce0e
--- /dev/null
+++ b/application/pages/instance/GameOptionsPage.ui
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>GameOptionsPage</class>
+ <widget class="QWidget" name="GameOptionsPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>706</width>
+ <height>575</height>
+ </rect>
+ </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="0" column="0">
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tab">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <attribute name="title">
+ <string notr="true">Tab 1</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0" colspan="2">
+ <widget class="QTreeView" name="optionsView">
+ <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="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>64</width>
+ <height>64</height>
+ </size>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <attribute name="headerStretchLastSection">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>tabWidget</tabstop>
+ <tabstop>optionsView</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/application/pages/instance/InstanceSettingsPage.cpp b/application/pages/instance/InstanceSettingsPage.cpp
index 71e90a32..b7b0a863 100644
--- a/application/pages/instance/InstanceSettingsPage.cpp
+++ b/application/pages/instance/InstanceSettingsPage.cpp
@@ -15,237 +15,271 @@
#include <widgets/CustomCommands.h>
InstanceSettingsPage::InstanceSettingsPage(BaseInstance *inst, QWidget *parent)
- : QWidget(parent), ui(new Ui::InstanceSettingsPage), m_instance(inst)
+ : QWidget(parent), ui(new Ui::InstanceSettingsPage), m_instance(inst)
{
- m_settings = inst->settings();
- ui->setupUi(this);
- auto sysMB = Sys::getSystemRam() / Sys::megabyte;
- ui->maxMemSpinBox->setMaximum(sysMB);
- loadSettings();
+ m_settings = inst->settings();
+ ui->setupUi(this);
+ auto sysMB = Sys::getSystemRam() / Sys::megabyte;
+ ui->maxMemSpinBox->setMaximum(sysMB);
+ connect(ui->openGlobalJavaSettingsButton, &QCommandLinkButton::clicked, this, &InstanceSettingsPage::globalSettingsButtonClicked);
+ connect(MMC, &MultiMC::globalSettingsAboutToOpen, this, &InstanceSettingsPage::applySettings);
+ connect(MMC, &MultiMC::globalSettingsClosed, this, &InstanceSettingsPage::loadSettings);
+ loadSettings();
}
bool InstanceSettingsPage::shouldDisplay() const
{
- return !m_instance->isRunning();
+ return !m_instance->isRunning();
}
InstanceSettingsPage::~InstanceSettingsPage()
{
- delete ui;
+ delete ui;
+}
+
+void InstanceSettingsPage::globalSettingsButtonClicked(bool)
+{
+ switch(ui->settingsTabs->currentIndex()) {
+ case 0:
+ MMC->ShowGlobalSettings(this, "java-settings");
+ return;
+ case 1:
+ MMC->ShowGlobalSettings(this, "minecraft-settings");
+ return;
+ case 2:
+ MMC->ShowGlobalSettings(this, "custom-commands");
+ return;
+ }
}
bool InstanceSettingsPage::apply()
{
- applySettings();
- return true;
+ applySettings();
+ return true;
}
void InstanceSettingsPage::applySettings()
{
- SettingsObject::Lock lock(m_settings);
-
- // 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());
- m_settings->set("ShowConsoleOnError", ui->showConsoleErrorCheck->isChecked());
- }
- else
- {
- m_settings->reset("ShowConsole");
- m_settings->reset("AutoCloseConsole");
- m_settings->reset("ShowConsoleOnError");
- }
-
- // 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)
- {
- int min = ui->minMemSpinBox->value();
- int max = ui->maxMemSpinBox->value();
- if(min < max)
- {
- m_settings->set("MinMemAlloc", min);
- m_settings->set("MaxMemAlloc", max);
- }
- else
- {
- m_settings->set("MinMemAlloc", max);
- m_settings->set("MaxMemAlloc", min);
- }
- 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", " "));
- JavaCommon::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->customCommands->checked();
- m_settings->set("OverrideCommands", custcmd);
- if (custcmd)
- {
- m_settings->set("PreLaunchCommand", ui->customCommands->prelaunchCommand());
- m_settings->set("WrapperCommand", ui->customCommands->wrapperCommand());
- m_settings->set("PostExitCommand", ui->customCommands->postexitCommand());
- }
- else
- {
- m_settings->reset("PreLaunchCommand");
- m_settings->reset("WrapperCommand");
- m_settings->reset("PostExitCommand");
- }
+ SettingsObject::Lock lock(m_settings);
+
+ // 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());
+ m_settings->set("ShowConsoleOnError", ui->showConsoleErrorCheck->isChecked());
+ }
+ else
+ {
+ m_settings->reset("ShowConsole");
+ m_settings->reset("AutoCloseConsole");
+ m_settings->reset("ShowConsoleOnError");
+ }
+
+ // 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)
+ {
+ int min = ui->minMemSpinBox->value();
+ int max = ui->maxMemSpinBox->value();
+ if(min < max)
+ {
+ m_settings->set("MinMemAlloc", min);
+ m_settings->set("MaxMemAlloc", max);
+ }
+ else
+ {
+ m_settings->set("MinMemAlloc", max);
+ m_settings->set("MaxMemAlloc", min);
+ }
+ 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", " "));
+ JavaCommon::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->customCommands->checked();
+ m_settings->set("OverrideCommands", custcmd);
+ if (custcmd)
+ {
+ m_settings->set("PreLaunchCommand", ui->customCommands->prelaunchCommand());
+ m_settings->set("WrapperCommand", ui->customCommands->wrapperCommand());
+ m_settings->set("PostExitCommand", ui->customCommands->postexitCommand());
+ }
+ else
+ {
+ m_settings->reset("PreLaunchCommand");
+ m_settings->reset("WrapperCommand");
+ 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());
- ui->showConsoleErrorCheck->setChecked(m_settings->get("ShowConsoleOnError").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());
- int min = m_settings->get("MinMemAlloc").toInt();
- int max = m_settings->get("MaxMemAlloc").toInt();
- if(min < max)
- {
- ui->minMemSpinBox->setValue(min);
- ui->maxMemSpinBox->setValue(max);
- }
- else
- {
- ui->minMemSpinBox->setValue(max);
- ui->maxMemSpinBox->setValue(min);
- }
- 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->customCommands->initialize(
- true,
- m_settings->get("OverrideCommands").toBool(),
- m_settings->get("PreLaunchCommand").toString(),
- m_settings->get("WrapperCommand").toString(),
- m_settings->get("PostExitCommand").toString()
- );
+ // 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());
+ ui->showConsoleErrorCheck->setChecked(m_settings->get("ShowConsoleOnError").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());
+ int min = m_settings->get("MinMemAlloc").toInt();
+ int max = m_settings->get("MaxMemAlloc").toInt();
+ if(min < max)
+ {
+ ui->minMemSpinBox->setValue(min);
+ ui->maxMemSpinBox->setValue(max);
+ }
+ else
+ {
+ ui->minMemSpinBox->setValue(max);
+ ui->maxMemSpinBox->setValue(min);
+ }
+ ui->permGenSpinBox->setValue(m_settings->get("PermGen").toInt());
+ bool permGenVisible = m_settings->get("PermGenVisible").toBool();
+ ui->permGenSpinBox->setVisible(permGenVisible);
+ ui->labelPermGen->setVisible(permGenVisible);
+ ui->labelPermgenNote->setVisible(permGenVisible);
+
+
+ // 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->customCommands->initialize(
+ true,
+ m_settings->get("OverrideCommands").toBool(),
+ m_settings->get("PreLaunchCommand").toString(),
+ m_settings->get("WrapperCommand").toString(),
+ m_settings->get("PostExitCommand").toString()
+ );
}
void InstanceSettingsPage::on_javaDetectBtn_clicked()
{
- JavaInstallPtr java;
+ JavaInstallPtr java;
- VersionSelectDialog vselect(MMC->javalist().get(), tr("Select a Java version"), this, true);
- vselect.setResizeOn(2);
- vselect.exec();
+ 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<JavaInstall>(vselect.selectedVersion());
- ui->javaPathTextBox->setText(java->path);
- }
+ if (vselect.result() == QDialog::Accepted && vselect.selectedVersion())
+ {
+ java = std::dynamic_pointer_cast<JavaInstall>(vselect.selectedVersion());
+ ui->javaPathTextBox->setText(java->path);
+ bool visible = java->id.requiresPermGen() && m_settings->get("OverrideMemory").toBool();
+ ui->permGenSpinBox->setVisible(visible);
+ ui->labelPermGen->setVisible(visible);
+ ui->labelPermgenNote->setVisible(visible);
+ m_settings->set("PermGenVisible", visible);
+ }
}
void InstanceSettingsPage::on_javaBrowseBtn_clicked()
{
- QString raw_path = QFileDialog::getOpenFileName(this, tr("Find Java executable"));
-
- // do not allow current dir - it's dirty. Do not allow dirs that don't exist
- if(raw_path.isEmpty())
- {
- return;
- }
- QString cooked_path = FS::NormalizePath(raw_path);
-
- QFileInfo javaInfo(cooked_path);;
- if(!javaInfo.exists() || !javaInfo.isExecutable())
- {
- return;
- }
- ui->javaPathTextBox->setText(cooked_path);
+ QString raw_path = QFileDialog::getOpenFileName(this, tr("Find Java executable"));
+
+ // do not allow current dir - it's dirty. Do not allow dirs that don't exist
+ if(raw_path.isEmpty())
+ {
+ return;
+ }
+ QString cooked_path = FS::NormalizePath(raw_path);
+
+ QFileInfo javaInfo(cooked_path);
+ if(!javaInfo.exists() || !javaInfo.isExecutable())
+ {
+ return;
+ }
+ ui->javaPathTextBox->setText(cooked_path);
+
+ // custom Java could be anything... enable perm gen option
+ ui->permGenSpinBox->setVisible(true);
+ ui->labelPermGen->setVisible(true);
+ ui->labelPermgenNote->setVisible(true);
+ m_settings->set("PermGenVisible", true);
}
void InstanceSettingsPage::on_javaTestBtn_clicked()
{
- if(checker)
- {
- return;
- }
- checker.reset(new JavaCommon::TestCheck(
- this, ui->javaPathTextBox->text(), ui->jvmArgsTextBox->toPlainText().replace("\n", " "),
- ui->minMemSpinBox->value(), ui->maxMemSpinBox->value(), ui->permGenSpinBox->value()));
- connect(checker.get(), SIGNAL(finished()), SLOT(checkerFinished()));
- checker->run();
+ if(checker)
+ {
+ return;
+ }
+ checker.reset(new JavaCommon::TestCheck(
+ this, ui->javaPathTextBox->text(), ui->jvmArgsTextBox->toPlainText().replace("\n", " "),
+ ui->minMemSpinBox->value(), ui->maxMemSpinBox->value(), ui->permGenSpinBox->value()));
+ connect(checker.get(), SIGNAL(finished()), SLOT(checkerFinished()));
+ checker->run();
}
void InstanceSettingsPage::checkerFinished()
{
- checker.reset();
+ checker.reset();
}
diff --git a/application/pages/instance/InstanceSettingsPage.h b/application/pages/instance/InstanceSettingsPage.h
index c5d7d3b6..c3c78fd5 100644
--- a/application/pages/instance/InstanceSettingsPage.h
+++ b/application/pages/instance/InstanceSettingsPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,43 +32,45 @@ class InstanceSettingsPage;
class InstanceSettingsPage : public QWidget, public BasePage
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit InstanceSettingsPage(BaseInstance *inst, QWidget *parent = 0);
- virtual ~InstanceSettingsPage();
- virtual QString displayName() const override
- {
- return tr("Settings");
- }
- virtual QIcon icon() const override
- {
- return MMC->getThemedIcon("instance-settings");
- }
- virtual QString id() const override
- {
- return "settings";
- }
- virtual bool apply() override;
- virtual QString helpPage() const override
- {
- return "Instance-settings";
- }
- virtual bool shouldDisplay() const override;
+ explicit InstanceSettingsPage(BaseInstance *inst, QWidget *parent = 0);
+ virtual ~InstanceSettingsPage();
+ virtual QString displayName() const override
+ {
+ return tr("Settings");
+ }
+ virtual QIcon icon() const override
+ {
+ return MMC->getThemedIcon("instance-settings");
+ }
+ virtual QString id() const override
+ {
+ return "settings";
+ }
+ virtual bool apply() override;
+ virtual QString helpPage() const override
+ {
+ return "Instance-settings";
+ }
+ virtual bool shouldDisplay() const override;
private slots:
- void on_javaDetectBtn_clicked();
- void on_javaTestBtn_clicked();
- void on_javaBrowseBtn_clicked();
+ void on_javaDetectBtn_clicked();
+ void on_javaTestBtn_clicked();
+ void on_javaBrowseBtn_clicked();
- void applySettings();
- void loadSettings();
+ void applySettings();
+ void loadSettings();
- void checkerFinished();
+ void checkerFinished();
+
+ void globalSettingsButtonClicked(bool checked);
private:
- Ui::InstanceSettingsPage *ui;
- BaseInstance *m_instance;
- SettingsObjectPtr m_settings;
- unique_qobject_ptr<JavaCommon::TestCheck> checker;
+ Ui::InstanceSettingsPage *ui;
+ BaseInstance *m_instance;
+ SettingsObjectPtr m_settings;
+ unique_qobject_ptr<JavaCommon::TestCheck> checker;
};
diff --git a/application/pages/instance/InstanceSettingsPage.ui b/application/pages/instance/InstanceSettingsPage.ui
index 0c180df3..d6de53ee 100644
--- a/application/pages/instance/InstanceSettingsPage.ui
+++ b/application/pages/instance/InstanceSettingsPage.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>553</width>
- <height>522</height>
+ <width>738</width>
+ <height>804</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
@@ -24,6 +24,16 @@
<number>0</number>
</property>
<item>
+ <widget class="QCommandLinkButton" name="openGlobalJavaSettingsButton">
+ <property name="text">
+ <string>Open Global Settings</string>
+ </property>
+ <property name="description">
+ <string>The settings here are overrides for global settings.</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QTabWidget" name="settingsTabs">
<property name="tabShape">
<enum>QTabWidget::Rounded</enum>
@@ -367,6 +377,7 @@
</customwidget>
</customwidgets>
<tabstops>
+ <tabstop>openGlobalJavaSettingsButton</tabstop>
<tabstop>settingsTabs</tabstop>
<tabstop>javaSettingsGroupBox</tabstop>
<tabstop>javaPathTextBox</tabstop>
diff --git a/application/pages/instance/LegacyUpgradePage.cpp b/application/pages/instance/LegacyUpgradePage.cpp
index f808ab88..af800b03 100644
--- a/application/pages/instance/LegacyUpgradePage.cpp
+++ b/application/pages/instance/LegacyUpgradePage.cpp
@@ -1,50 +1,50 @@
#include "LegacyUpgradePage.h"
#include "ui_LegacyUpgradePage.h"
+#include "InstanceList.h"
#include "minecraft/legacy/LegacyInstance.h"
#include "minecraft/legacy/LegacyUpgradeTask.h"
#include "MultiMC.h"
-#include "FolderInstanceProvider.h"
#include "dialogs/CustomMessageBox.h"
#include "dialogs/ProgressDialog.h"
LegacyUpgradePage::LegacyUpgradePage(InstancePtr inst, QWidget *parent)
- : QWidget(parent), ui(new Ui::LegacyUpgradePage), m_inst(inst)
+ : QWidget(parent), ui(new Ui::LegacyUpgradePage), m_inst(inst)
{
- ui->setupUi(this);
+ ui->setupUi(this);
}
LegacyUpgradePage::~LegacyUpgradePage()
{
- delete ui;
+ delete ui;
}
void LegacyUpgradePage::runModalTask(Task *task)
{
- connect(task, &Task::failed, [this](QString reason)
- {
- CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Warning)->show();
- });
- ProgressDialog loadDialog(this);
- loadDialog.setSkipButton(true, tr("Abort"));
- if(loadDialog.execWithTask(task) == QDialog::Accepted)
- {
- m_container->requestClose();
- }
+ connect(task, &Task::failed, [this](QString reason)
+ {
+ CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Warning)->show();
+ });
+ ProgressDialog loadDialog(this);
+ loadDialog.setSkipButton(true, tr("Abort"));
+ if(loadDialog.execWithTask(task) == QDialog::Accepted)
+ {
+ m_container->requestClose();
+ }
}
void LegacyUpgradePage::on_upgradeButton_clicked()
{
- QString newName = tr("%1 (Migrated)").arg(m_inst->name());
- auto upgradeTask = new LegacyUpgradeTask(m_inst);
- upgradeTask->setName(newName);
- upgradeTask->setGroup(m_inst->group());
- upgradeTask->setIcon(m_inst->iconKey());
- std::unique_ptr<Task> task(MMC->folderProvider()->wrapInstanceTask(upgradeTask));
- runModalTask(task.get());
+ QString newName = tr("%1 (Migrated)").arg(m_inst->name());
+ auto upgradeTask = new LegacyUpgradeTask(m_inst);
+ upgradeTask->setName(newName);
+ upgradeTask->setGroup(MMC->instances()->getInstanceGroup(m_inst->id()));
+ upgradeTask->setIcon(m_inst->iconKey());
+ unique_qobject_ptr<Task> task(MMC->instances()->wrapInstanceTask(upgradeTask));
+ runModalTask(task.get());
}
bool LegacyUpgradePage::shouldDisplay() const
{
- return !m_inst->isRunning();
+ return !m_inst->isRunning();
}
diff --git a/application/pages/instance/LegacyUpgradePage.h b/application/pages/instance/LegacyUpgradePage.h
index 3e1abe93..4f86a721 100644
--- a/application/pages/instance/LegacyUpgradePage.h
+++ b/application/pages/instance/LegacyUpgradePage.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,36 +29,36 @@ class LegacyUpgradePage;
class LegacyUpgradePage : public QWidget, public BasePage
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit LegacyUpgradePage(InstancePtr inst, QWidget *parent = 0);
- virtual ~LegacyUpgradePage();
- virtual QString displayName() const override
- {
- return tr("Upgrade");
- }
- virtual QIcon icon() const override
- {
- return MMC->getThemedIcon("checkupdate");
- }
- virtual QString id() const override
- {
- return "upgrade";
- }
- virtual QString helpPage() const override
- {
- return "Legacy-upgrade";
- }
- virtual bool shouldDisplay() const override;
+ explicit LegacyUpgradePage(InstancePtr inst, QWidget *parent = 0);
+ virtual ~LegacyUpgradePage();
+ virtual QString displayName() const override
+ {
+ return tr("Upgrade");
+ }
+ virtual QIcon icon() const override
+ {
+ return MMC->getThemedIcon("checkupdate");
+ }
+ virtual QString id() const override
+ {
+ return "upgrade";
+ }
+ virtual QString helpPage() const override
+ {
+ return "Legacy-upgrade";
+ }
+ virtual bool shouldDisplay() const override;
private slots:
- void on_upgradeButton_clicked();
+ void on_upgradeButton_clicked();
private:
- void runModalTask(Task *task);
+ void runModalTask(Task *task);
private:
- Ui::LegacyUpgradePage *ui;
- InstancePtr m_inst;
+ Ui::LegacyUpgradePage *ui;
+ InstancePtr m_inst;
};
diff --git a/application/pages/instance/LogPage.cpp b/application/pages/instance/LogPage.cpp
index 0fa1ee67..94ada424 100644
--- a/application/pages/instance/LogPage.cpp
+++ b/application/pages/instance/LogPage.cpp
@@ -15,298 +15,298 @@
class LogFormatProxyModel : public QIdentityProxyModel
{
public:
- LogFormatProxyModel(QObject* parent = nullptr) : QIdentityProxyModel(parent)
- {
- }
- QVariant data(const QModelIndex &index, int role) const override
- {
- switch(role)
- {
- case Qt::FontRole:
- return m_font;
- case Qt::TextColorRole:
- {
- MessageLevel::Enum level = (MessageLevel::Enum) QIdentityProxyModel::data(index, LogModel::LevelRole).toInt();
- return m_colors->getFront(level);
- }
- case Qt::BackgroundRole:
- {
- MessageLevel::Enum level = (MessageLevel::Enum) QIdentityProxyModel::data(index, LogModel::LevelRole).toInt();
- return m_colors->getBack(level);
- }
- default:
- return QIdentityProxyModel::data(index, role);
- }
- }
-
- void setFont(QFont font)
- {
- m_font = font;
- }
-
- void setColors(LogColorCache* colors)
- {
- m_colors.reset(colors);
- }
-
- QModelIndex find(const QModelIndex &start, const QString &value, bool reverse) const
- {
- QModelIndex parentIndex = parent(start);
- auto compare = [&](int r) -> QModelIndex
- {
- QModelIndex idx = index(r, start.column(), parentIndex);
- if (!idx.isValid() || idx == start)
- {
- return QModelIndex();
- }
- QVariant v = data(idx, Qt::DisplayRole);
- QString t = v.toString();
- if (t.contains(value, Qt::CaseInsensitive))
- return idx;
- return QModelIndex();
- };
- if(reverse)
- {
- int from = start.row();
- int to = 0;
-
- for (int i = 0; i < 2; ++i)
- {
- for (int r = from; (r >= to); --r)
- {
- auto idx = compare(r);
- if(idx.isValid())
- return idx;
- }
- // prepare for the next iteration
- from = rowCount() - 1;
- to = start.row();
- }
- }
- else
- {
- int from = start.row();
- int to = rowCount(parentIndex);
-
- for (int i = 0; i < 2; ++i)
- {
- for (int r = from; (r < to); ++r)
- {
- auto idx = compare(r);
- if(idx.isValid())
- return idx;
- }
- // prepare for the next iteration
- from = 0;
- to = start.row();
- }
- }
- return QModelIndex();
- }
+ LogFormatProxyModel(QObject* parent = nullptr) : QIdentityProxyModel(parent)
+ {
+ }
+ QVariant data(const QModelIndex &index, int role) const override
+ {
+ switch(role)
+ {
+ case Qt::FontRole:
+ return m_font;
+ case Qt::TextColorRole:
+ {
+ MessageLevel::Enum level = (MessageLevel::Enum) QIdentityProxyModel::data(index, LogModel::LevelRole).toInt();
+ return m_colors->getFront(level);
+ }
+ case Qt::BackgroundRole:
+ {
+ MessageLevel::Enum level = (MessageLevel::Enum) QIdentityProxyModel::data(index, LogModel::LevelRole).toInt();
+ return m_colors->getBack(level);
+ }
+ default:
+ return QIdentityProxyModel::data(index, role);
+ }
+ }
+
+ void setFont(QFont font)
+ {
+ m_font = font;
+ }
+
+ void setColors(LogColorCache* colors)
+ {
+ m_colors.reset(colors);
+ }
+
+ QModelIndex find(const QModelIndex &start, const QString &value, bool reverse) const
+ {
+ QModelIndex parentIndex = parent(start);
+ auto compare = [&](int r) -> QModelIndex
+ {
+ QModelIndex idx = index(r, start.column(), parentIndex);
+ if (!idx.isValid() || idx == start)
+ {
+ return QModelIndex();
+ }
+ QVariant v = data(idx, Qt::DisplayRole);
+ QString t = v.toString();
+ if (t.contains(value, Qt::CaseInsensitive))
+ return idx;
+ return QModelIndex();
+ };
+ if(reverse)
+ {
+ int from = start.row();
+ int to = 0;
+
+ for (int i = 0; i < 2; ++i)
+ {
+ for (int r = from; (r >= to); --r)
+ {
+ auto idx = compare(r);
+ if(idx.isValid())
+ return idx;
+ }
+ // prepare for the next iteration
+ from = rowCount() - 1;
+ to = start.row();
+ }
+ }
+ else
+ {
+ int from = start.row();
+ int to = rowCount(parentIndex);
+
+ for (int i = 0; i < 2; ++i)
+ {
+ for (int r = from; (r < to); ++r)
+ {
+ auto idx = compare(r);
+ if(idx.isValid())
+ return idx;
+ }
+ // prepare for the next iteration
+ from = 0;
+ to = start.row();
+ }
+ }
+ return QModelIndex();
+ }
private:
- QFont m_font;
- std::unique_ptr<LogColorCache> m_colors;
+ QFont m_font;
+ std::unique_ptr<LogColorCache> m_colors;
};
LogPage::LogPage(InstancePtr instance, QWidget *parent)
- : QWidget(parent), ui(new Ui::LogPage), m_instance(instance)
+ : QWidget(parent), ui(new Ui::LogPage), m_instance(instance)
{
- ui->setupUi(this);
- ui->tabWidget->tabBar()->hide();
-
- m_proxy = new LogFormatProxyModel(this);
- // set up text colors in the log proxy and adapt them to the current theme foreground and background
- {
- auto origForeground = ui->text->palette().color(ui->text->foregroundRole());
- auto origBackground = ui->text->palette().color(ui->text->backgroundRole());
- m_proxy->setColors(new LogColorCache(origForeground, origBackground));
- }
-
- // set up fonts in the log proxy
- {
- QString fontFamily = MMC->settings()->get("ConsoleFont").toString();
- bool conversionOk = false;
- int fontSize = MMC->settings()->get("ConsoleFontSize").toInt(&conversionOk);
- if(!conversionOk)
- {
- fontSize = 11;
- }
- m_proxy->setFont(QFont(fontFamily, fontSize));
- }
-
- ui->text->setModel(m_proxy);
-
- // set up instance and launch process recognition
- {
- auto launchTask = m_instance->getLaunchTask();
- if(launchTask)
- {
- setInstanceLaunchTaskChanged(launchTask, true);
- }
- connect(m_instance.get(), &BaseInstance::launchTaskChanged, this, &LogPage::onInstanceLaunchTaskChanged);
- }
-
- auto findShortcut = new QShortcut(QKeySequence(QKeySequence::Find), this);
- connect(findShortcut, SIGNAL(activated()), SLOT(findActivated()));
- auto findNextShortcut = new QShortcut(QKeySequence(QKeySequence::FindNext), this);
- connect(findNextShortcut, SIGNAL(activated()), SLOT(findNextActivated()));
- connect(ui->searchBar, SIGNAL(returnPressed()), SLOT(on_findButton_clicked()));
- auto findPreviousShortcut = new QShortcut(QKeySequence(QKeySequence::FindPrevious), this);
- connect(findPreviousShortcut, SIGNAL(activated()), SLOT(findPreviousActivated()));
+ ui->setupUi(this);
+ ui->tabWidget->tabBar()->hide();
+
+ m_proxy = new LogFormatProxyModel(this);
+ // set up text colors in the log proxy and adapt them to the current theme foreground and background
+ {
+ auto origForeground = ui->text->palette().color(ui->text->foregroundRole());
+ auto origBackground = ui->text->palette().color(ui->text->backgroundRole());
+ m_proxy->setColors(new LogColorCache(origForeground, origBackground));
+ }
+
+ // set up fonts in the log proxy
+ {
+ QString fontFamily = MMC->settings()->get("ConsoleFont").toString();
+ bool conversionOk = false;
+ int fontSize = MMC->settings()->get("ConsoleFontSize").toInt(&conversionOk);
+ if(!conversionOk)
+ {
+ fontSize = 11;
+ }
+ m_proxy->setFont(QFont(fontFamily, fontSize));
+ }
+
+ ui->text->setModel(m_proxy);
+
+ // set up instance and launch process recognition
+ {
+ auto launchTask = m_instance->getLaunchTask();
+ if(launchTask)
+ {
+ setInstanceLaunchTaskChanged(launchTask, true);
+ }
+ connect(m_instance.get(), &BaseInstance::launchTaskChanged, this, &LogPage::onInstanceLaunchTaskChanged);
+ }
+
+ auto findShortcut = new QShortcut(QKeySequence(QKeySequence::Find), this);
+ connect(findShortcut, SIGNAL(activated()), SLOT(findActivated()));
+ auto findNextShortcut = new QShortcut(QKeySequence(QKeySequence::FindNext), this);
+ connect(findNextShortcut, SIGNAL(activated()), SLOT(findNextActivated()));
+ connect(ui->searchBar, SIGNAL(returnPressed()), SLOT(on_findButton_clicked()));
+ auto findPreviousShortcut = new QShortcut(QKeySequence(QKeySequence::FindPrevious), this);
+ connect(findPreviousShortcut, SIGNAL(activated()), SLOT(findPreviousActivated()));
}
LogPage::~LogPage()
{
- delete ui;
+ delete ui;
}
void LogPage::modelStateToUI()
{
- if(m_model->wrapLines())
- {
- ui->text->setWordWrap(true);
- ui->wrapCheckbox->setCheckState(Qt::Checked);
- }
- else
- {
- ui->text->setWordWrap(false);
- ui->wrapCheckbox->setCheckState(Qt::Unchecked);
- }
- if(m_model->suspended())
- {
- ui->trackLogCheckbox->setCheckState(Qt::Unchecked);
- }
- else
- {
- ui->trackLogCheckbox->setCheckState(Qt::Checked);
- }
+ if(m_model->wrapLines())
+ {
+ ui->text->setWordWrap(true);
+ ui->wrapCheckbox->setCheckState(Qt::Checked);
+ }
+ else
+ {
+ ui->text->setWordWrap(false);
+ ui->wrapCheckbox->setCheckState(Qt::Unchecked);
+ }
+ if(m_model->suspended())
+ {
+ ui->trackLogCheckbox->setCheckState(Qt::Unchecked);
+ }
+ else
+ {
+ ui->trackLogCheckbox->setCheckState(Qt::Checked);
+ }
}
void LogPage::UIToModelState()
{
- if(!m_model)
- {
- return;
- }
- m_model->setLineWrap(ui->wrapCheckbox->checkState() == Qt::Checked);
- m_model->suspend(ui->trackLogCheckbox->checkState() != Qt::Checked);
+ if(!m_model)
+ {
+ return;
+ }
+ m_model->setLineWrap(ui->wrapCheckbox->checkState() == Qt::Checked);
+ m_model->suspend(ui->trackLogCheckbox->checkState() != Qt::Checked);
}
-void LogPage::setInstanceLaunchTaskChanged(std::shared_ptr<LaunchTask> proc, bool initial)
+void LogPage::setInstanceLaunchTaskChanged(shared_qobject_ptr<LaunchTask> proc, bool initial)
{
- m_process = proc;
- if(m_process)
- {
- m_model = proc->getLogModel();
- m_proxy->setSourceModel(m_model.get());
- if(initial)
- {
- modelStateToUI();
- }
- else
- {
- UIToModelState();
- }
- }
- else
- {
- m_proxy->setSourceModel(nullptr);
- m_model.reset();
- }
+ m_process = proc;
+ if(m_process)
+ {
+ m_model = proc->getLogModel();
+ m_proxy->setSourceModel(m_model.get());
+ if(initial)
+ {
+ modelStateToUI();
+ }
+ else
+ {
+ UIToModelState();
+ }
+ }
+ else
+ {
+ m_proxy->setSourceModel(nullptr);
+ m_model.reset();
+ }
}
-void LogPage::onInstanceLaunchTaskChanged(std::shared_ptr<LaunchTask> proc)
+void LogPage::onInstanceLaunchTaskChanged(shared_qobject_ptr<LaunchTask> proc)
{
- setInstanceLaunchTaskChanged(proc, false);
+ setInstanceLaunchTaskChanged(proc, false);
}
bool LogPage::apply()
{
- return true;
+ return true;
}
bool LogPage::shouldDisplay() const
{
- return m_instance->isRunning() || m_proxy->rowCount() > 0;
+ return m_instance->isRunning() || m_proxy->rowCount() > 0;
}
void LogPage::on_btnPaste_clicked()
{
- if(!m_model)
- return;
-
- //FIXME: turn this into a proper task and move the upload logic out of GuiUtil!
- m_model->append(MessageLevel::MultiMC, tr("MultiMC: Log upload triggered at: %1").arg(QDateTime::currentDateTime().toString(Qt::RFC2822Date)));
- auto url = GuiUtil::uploadPaste(m_model->toPlainText(), this);
- if(!url.isEmpty())
- {
- m_model->append(MessageLevel::MultiMC, tr("MultiMC: Log uploaded to: %1").arg(url));
- }
- else
- {
- m_model->append(MessageLevel::Error, tr("MultiMC: Log upload failed!"));
- }
+ if(!m_model)
+ return;
+
+ //FIXME: turn this into a proper task and move the upload logic out of GuiUtil!
+ m_model->append(MessageLevel::MultiMC, tr("MultiMC: Log upload triggered at: %1").arg(QDateTime::currentDateTime().toString(Qt::RFC2822Date)));
+ auto url = GuiUtil::uploadPaste(m_model->toPlainText(), this);
+ if(!url.isEmpty())
+ {
+ m_model->append(MessageLevel::MultiMC, tr("MultiMC: Log uploaded to: %1").arg(url));
+ }
+ else
+ {
+ m_model->append(MessageLevel::Error, tr("MultiMC: Log upload failed!"));
+ }
}
void LogPage::on_btnCopy_clicked()
{
- if(!m_model)
- return;
- m_model->append(MessageLevel::MultiMC, QString("Clipboard copy at: %1").arg(QDateTime::currentDateTime().toString(Qt::RFC2822Date)));
- GuiUtil::setClipboardText(m_model->toPlainText());
+ if(!m_model)
+ return;
+ m_model->append(MessageLevel::MultiMC, QString("Clipboard copy at: %1").arg(QDateTime::currentDateTime().toString(Qt::RFC2822Date)));
+ GuiUtil::setClipboardText(m_model->toPlainText());
}
void LogPage::on_btnClear_clicked()
{
- if(!m_model)
- return;
- m_model->clear();
- m_container->refreshContainer();
+ if(!m_model)
+ return;
+ m_model->clear();
+ m_container->refreshContainer();
}
void LogPage::on_btnBottom_clicked()
{
- ui->text->scrollToBottom();
+ ui->text->scrollToBottom();
}
void LogPage::on_trackLogCheckbox_clicked(bool checked)
{
- if(!m_model)
- return;
- m_model->suspend(!checked);
+ if(!m_model)
+ return;
+ m_model->suspend(!checked);
}
void LogPage::on_wrapCheckbox_clicked(bool checked)
{
- ui->text->setWordWrap(checked);
- if(!m_model)
- return;
- m_model->setLineWrap(checked);
+ ui->text->setWordWrap(checked);
+ if(!m_model)
+ return;
+ m_model->setLineWrap(checked);
}
void LogPage::on_findButton_clicked()
{
- auto modifiers = QApplication::keyboardModifiers();
- bool reverse = modifiers & Qt::ShiftModifier;
- ui->text->findNext(ui->searchBar->text(), reverse);
+ auto modifiers = QApplication::keyboardModifiers();
+ bool reverse = modifiers & Qt::ShiftModifier;
+ ui->text->findNext(ui->searchBar->text(), reverse);
}
void LogPage::findNextActivated()
{
- ui->text->findNext(ui->searchBar->text(), false);
+ ui->text->findNext(ui->searchBar->text(), false);
}
void LogPage::findPreviousActivated()
{
- ui->text->findNext(ui->searchBar->text(), true);
+ ui->text->findNext(ui->searchBar->text(), true);
}
void LogPage::findActivated()
{
- // focus the search bar if it doesn't have focus
- if (!ui->searchBar->hasFocus())
- {
- ui->searchBar->setFocus();
- ui->searchBar->selectAll();
- }
+ // focus the search bar if it doesn't have focus
+ if (!ui->searchBar->hasFocus())
+ {
+ ui->searchBar->setFocus();
+ ui->searchBar->selectAll();
+ }
}
diff --git a/application/pages/instance/LogPage.h b/application/pages/instance/LogPage.h
index 2229418d..9c3b56a9 100644
--- a/application/pages/instance/LogPage.h
+++ b/application/pages/instance/LogPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,56 +31,56 @@ class LogFormatProxyModel;
class LogPage : public QWidget, public BasePage
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit LogPage(InstancePtr instance, QWidget *parent = 0);
- virtual ~LogPage();
- virtual QString displayName() const override
- {
- return tr("Minecraft Log");
- }
- virtual QIcon icon() const override
- {
- return MMC->getThemedIcon("log");
- }
- virtual QString id() const override
- {
- return "console";
- }
- virtual bool apply() override;
- virtual QString helpPage() const override
- {
- return "Minecraft-Logs";
- }
- virtual bool shouldDisplay() const override;
+ explicit LogPage(InstancePtr instance, QWidget *parent = 0);
+ virtual ~LogPage();
+ virtual QString displayName() const override
+ {
+ return tr("Minecraft Log");
+ }
+ virtual QIcon icon() const override
+ {
+ return MMC->getThemedIcon("log");
+ }
+ virtual QString id() const override
+ {
+ return "console";
+ }
+ virtual bool apply() override;
+ virtual QString helpPage() const override
+ {
+ return "Minecraft-Logs";
+ }
+ virtual bool shouldDisplay() const override;
private slots:
- void on_btnPaste_clicked();
- void on_btnCopy_clicked();
- void on_btnClear_clicked();
- void on_btnBottom_clicked();
+ void on_btnPaste_clicked();
+ void on_btnCopy_clicked();
+ void on_btnClear_clicked();
+ void on_btnBottom_clicked();
- void on_trackLogCheckbox_clicked(bool checked);
- void on_wrapCheckbox_clicked(bool checked);
+ void on_trackLogCheckbox_clicked(bool checked);
+ void on_wrapCheckbox_clicked(bool checked);
- void on_findButton_clicked();
- void findActivated();
- void findNextActivated();
- void findPreviousActivated();
+ void on_findButton_clicked();
+ void findActivated();
+ void findNextActivated();
+ void findPreviousActivated();
- void onInstanceLaunchTaskChanged(std::shared_ptr<LaunchTask> proc);
+ void onInstanceLaunchTaskChanged(shared_qobject_ptr<LaunchTask> proc);
private:
- void modelStateToUI();
- void UIToModelState();
- void setInstanceLaunchTaskChanged(std::shared_ptr<LaunchTask> proc, bool initial);
+ void modelStateToUI();
+ void UIToModelState();
+ void setInstanceLaunchTaskChanged(shared_qobject_ptr<LaunchTask> proc, bool initial);
private:
- Ui::LogPage *ui;
- InstancePtr m_instance;
- std::shared_ptr<LaunchTask> m_process;
+ Ui::LogPage *ui;
+ InstancePtr m_instance;
+ shared_qobject_ptr<LaunchTask> m_process;
- LogFormatProxyModel * m_proxy;
- shared_qobject_ptr <LogModel> m_model;
+ LogFormatProxyModel * m_proxy;
+ shared_qobject_ptr <LogModel> m_model;
};
diff --git a/application/pages/instance/ModFolderPage.cpp b/application/pages/instance/ModFolderPage.cpp
index 90155df3..d449f8bf 100644
--- a/application/pages/instance/ModFolderPage.cpp
+++ b/application/pages/instance/ModFolderPage.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,191 +20,324 @@
#include <QEvent>
#include <QKeyEvent>
#include <QAbstractItemModel>
+#include <QMenu>
#include "MultiMC.h"
#include "dialogs/CustomMessageBox.h"
-#include "dialogs/ModEditDialogCommon.h"
#include <GuiUtil.h>
-#include "minecraft/ModList.h"
-#include "minecraft/Mod.h"
+#include "minecraft/mod/ModFolderModel.h"
+#include "minecraft/mod/Mod.h"
#include "minecraft/VersionFilterData.h"
#include "minecraft/ComponentList.h"
#include <DesktopServices.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);
- ui->tabWidget->tabBar()->hide();
- m_inst = inst;
- m_mods = mods;
- m_id = id;
- m_displayName = displayName;
- m_iconName = iconName;
- m_helpName = helpPage;
- m_fileSelectionFilter = "%1 (*.zip *.jar)";
- m_filterModel = new QSortFilterProxyModel(this);
- m_filterModel->setDynamicSortFilter(true);
- m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
- m_filterModel->setSortCaseSensitivity(Qt::CaseInsensitive);
- m_filterModel->setSourceModel(m_mods.get());
- m_filterModel->setFilterKeyColumn(-1);
- ui->modTreeView->setModel(m_filterModel);
- ui->modTreeView->installEventFilter(this);
- ui->modTreeView->sortByColumn(1, Qt::AscendingOrder);
- auto smodel = ui->modTreeView->selectionModel();
- connect(smodel, &QItemSelectionModel::currentChanged, this, &ModFolderPage::modCurrent);
- connect(ui->filterEdit, &QLineEdit::textChanged, this, &ModFolderPage::on_filterTextChanged );
+#include <QSortFilterProxyModel>
+#include "Version.h"
+
+namespace {
+ // FIXME: wasteful
+ void RemoveThePrefix(QString & string) {
+ QRegularExpression regex(QStringLiteral("^(([Tt][Hh][eE])|([Tt][eE][Hh])) +"));
+ string.remove(regex);
+ string = string.trimmed();
+ }
+}
+
+class ModSortProxy : public QSortFilterProxyModel
+{
+public:
+ explicit ModSortProxy(QObject *parent = 0) : QSortFilterProxyModel(parent)
+ {
+ }
+
+protected:
+ bool lessThan(const QModelIndex & source_left, const QModelIndex & source_right) const override
+ {
+ ModFolderModel *model = qobject_cast<ModFolderModel *>(sourceModel());
+ if(
+ !model ||
+ !source_left.isValid() ||
+ !source_right.isValid() ||
+ source_left.column() != source_right.column()
+ ) {
+ return QSortFilterProxyModel::lessThan(source_left, source_right);
+ }
+
+ // we are now guaranteed to have two valid indexes in the same column... we love the provided invariants unconditionally and proceed.
+
+ auto column = (ModFolderModel::Columns) source_left.column();
+ bool invert = false;
+ switch(column) {
+ // GH-2550 - sort by enabled/disabled
+ case ModFolderModel::ActiveColumn: {
+ auto dataL = source_left.data(Qt::CheckStateRole).toBool();
+ auto dataR = source_right.data(Qt::CheckStateRole).toBool();
+ if(dataL != dataR) {
+ return dataL > dataR;
+ }
+ // fallthrough
+ invert = sortOrder() == Qt::DescendingOrder;
+ }
+ // GH-2722 - sort mod names in a way that discards "The" prefixes
+ case ModFolderModel::NameColumn: {
+ auto dataL = model->data(model->index(source_left.row(), ModFolderModel::NameColumn)).toString();
+ RemoveThePrefix(dataL);
+ auto dataR = model->data(model->index(source_right.row(), ModFolderModel::NameColumn)).toString();
+ RemoveThePrefix(dataR);
+
+ auto less = dataL.compare(dataR, sortCaseSensitivity());
+ if(less != 0) {
+ return invert ? (less > 0) : (less < 0);
+ }
+ // fallthrough
+ invert = sortOrder() == Qt::DescendingOrder;
+ }
+ // GH-2762 - sort versions by parsing them as versions
+ case ModFolderModel::VersionColumn: {
+ auto dataL = Version(model->data(model->index(source_left.row(), ModFolderModel::VersionColumn)).toString());
+ auto dataR = Version(model->data(model->index(source_right.row(), ModFolderModel::VersionColumn)).toString());
+ return invert ? (dataL > dataR) : (dataL < dataR);
+ }
+ default: {
+ return QSortFilterProxyModel::lessThan(source_left, source_right);
+ }
+ }
+ }
+};
+
+ModFolderPage::ModFolderPage(
+ BaseInstance *inst,
+ std::shared_ptr<ModFolderModel> mods,
+ QString id,
+ QString iconName,
+ QString displayName,
+ QString helpPage,
+ QWidget *parent
+) :
+ QMainWindow(parent),
+ ui(new Ui::ModFolderPage)
+{
+ ui->setupUi(this);
+ ui->actionsToolbar->insertSpacer(ui->actionView_configs);
+
+ m_inst = inst;
+ on_RunningState_changed(m_inst && m_inst->isRunning());
+ m_mods = mods;
+ m_id = id;
+ m_displayName = displayName;
+ m_iconName = iconName;
+ m_helpName = helpPage;
+ m_fileSelectionFilter = "%1 (*.zip *.jar)";
+ m_filterModel = new ModSortProxy(this);
+ m_filterModel->setDynamicSortFilter(true);
+ m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
+ m_filterModel->setSortCaseSensitivity(Qt::CaseInsensitive);
+ m_filterModel->setSourceModel(m_mods.get());
+ m_filterModel->setFilterKeyColumn(-1);
+ ui->modTreeView->setModel(m_filterModel);
+ ui->modTreeView->installEventFilter(this);
+ ui->modTreeView->sortByColumn(1, Qt::AscendingOrder);
+ ui->modTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(ui->modTreeView, &ModListView::customContextMenuRequested, this, &ModFolderPage::ShowContextMenu);
+ connect(ui->modTreeView, &ModListView::activated, this, &ModFolderPage::modItemActivated);
+
+ auto smodel = ui->modTreeView->selectionModel();
+ connect(smodel, &QItemSelectionModel::currentChanged, this, &ModFolderPage::modCurrent);
+ connect(ui->filterEdit, &QLineEdit::textChanged, this, &ModFolderPage::on_filterTextChanged );
+ connect(m_inst, &BaseInstance::runningStatusChanged, this, &ModFolderPage::on_RunningState_changed);
+}
+
+void ModFolderPage::modItemActivated(const QModelIndex&)
+{
+ if(!m_controlsEnabled) {
+ return;
+ }
+ auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
+ m_mods->setModStatus(selection.indexes(), ModFolderModel::Toggle);
+}
+
+QMenu * ModFolderPage::createPopupMenu()
+{
+ QMenu* filteredMenu = QMainWindow::createPopupMenu();
+ filteredMenu->removeAction(ui->actionsToolbar->toggleViewAction() );
+ return filteredMenu;
+}
+
+void ModFolderPage::ShowContextMenu(const QPoint& pos)
+{
+ auto menu = ui->actionsToolbar->createContextMenu(this, tr("Context menu"));
+ menu->exec(ui->modTreeView->mapToGlobal(pos));
+ delete menu;
}
void ModFolderPage::openedImpl()
{
- m_mods->startWatching();
+ m_mods->startWatching();
}
void ModFolderPage::closedImpl()
{
- m_mods->stopWatching();
+ m_mods->stopWatching();
}
void ModFolderPage::on_filterTextChanged(const QString& newContents)
{
- m_viewFilter = newContents;
- m_filterModel->setFilterFixedString(m_viewFilter);
+ m_viewFilter = newContents;
+ m_filterModel->setFilterFixedString(m_viewFilter);
}
-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)
+CoreModFolderPage::CoreModFolderPage(BaseInstance *inst, std::shared_ptr<ModFolderModel> 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;
+ m_mods->stopWatching();
+ delete ui;
+}
+
+void ModFolderPage::on_RunningState_changed(bool running)
+{
+ if(m_controlsEnabled == !running) {
+ return;
+ }
+ m_controlsEnabled = !running;
+ ui->actionAdd->setEnabled(m_controlsEnabled);
+ ui->actionDisable->setEnabled(m_controlsEnabled);
+ ui->actionEnable->setEnabled(m_controlsEnabled);
+ ui->actionRemove->setEnabled(m_controlsEnabled);
}
bool ModFolderPage::shouldDisplay() const
{
- if (m_inst)
- return !m_inst->isRunning();
- return true;
+ return true;
}
bool CoreModFolderPage::shouldDisplay() const
{
- if (ModFolderPage::shouldDisplay())
- {
- auto inst = dynamic_cast<MinecraftInstance *>(m_inst);
- if (!inst)
- return true;
- auto version = inst->getComponentList();
- if (!version)
- return true;
- if(!version->getComponent("net.minecraftforge"))
- {
- return false;
- }
- if(!version->getComponent("net.minecraft"))
- {
- return false;
- }
- if(version->getComponent("net.minecraft")->getReleaseDateTime() < g_VersionFilterData.legacyCutoffDate)
- {
- return true;
- }
- }
- return false;
+ if (ModFolderPage::shouldDisplay())
+ {
+ auto inst = dynamic_cast<MinecraftInstance *>(m_inst);
+ if (!inst)
+ return true;
+ auto version = inst->getComponentList();
+ if (!version)
+ return true;
+ if(!version->getComponent("net.minecraftforge"))
+ {
+ return false;
+ }
+ if(!version->getComponent("net.minecraft"))
+ {
+ return false;
+ }
+ if(version->getComponent("net.minecraft")->getReleaseDateTime() < 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);
+ switch (keyEvent->key())
+ {
+ case Qt::Key_Delete:
+ on_actionRemove_triggered();
+ return true;
+ case Qt::Key_Plus:
+ on_actionAdd_triggered();
+ 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);
+ 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()
+void ModFolderPage::on_actionAdd_triggered()
{
- auto list = GuiUtil::BrowseForFiles(
- m_helpName,
- tr("Select %1",
- "Select whatever type of files the page contains. Example: 'Loader Mods'")
- .arg(m_displayName),
- m_fileSelectionFilter.arg(m_displayName), MMC->settings()->get("CentralModsDir").toString(),
- this->parentWidget());
- if (!list.empty())
- {
- for (auto filename : list)
- {
- m_mods->installMod(filename);
- }
- }
+ if(!m_controlsEnabled) {
+ return;
+ }
+ auto list = GuiUtil::BrowseForFiles(
+ m_helpName,
+ tr("Select %1",
+ "Select whatever type of files the page contains. Example: 'Loader Mods'")
+ .arg(m_displayName),
+ m_fileSelectionFilter.arg(m_displayName), MMC->settings()->get("CentralModsDir").toString(),
+ this->parentWidget());
+ if (!list.empty())
+ {
+ for (auto filename : list)
+ {
+ m_mods->installMod(filename);
+ }
+ }
}
-void ModFolderPage::on_enableModBtn_clicked()
+void ModFolderPage::on_actionEnable_triggered()
{
- auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
- m_mods->enableMods(selection.indexes(), true);
+ if(!m_controlsEnabled) {
+ return;
+ }
+ auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
+ m_mods->setModStatus(selection.indexes(), ModFolderModel::Enable);
}
-void ModFolderPage::on_disableModBtn_clicked()
+void ModFolderPage::on_actionDisable_triggered()
{
- auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
- m_mods->enableMods(selection.indexes(), false);
+ if(!m_controlsEnabled) {
+ return;
+ }
+ auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
+ m_mods->setModStatus(selection.indexes(), ModFolderModel::Disable);
}
-void ModFolderPage::on_rmModBtn_clicked()
+void ModFolderPage::on_actionRemove_triggered()
{
- auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
- m_mods->deleteMods(selection.indexes());
+ if(!m_controlsEnabled) {
+ return;
+ }
+ auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
+ m_mods->deleteMods(selection.indexes());
}
-void ModFolderPage::on_configFolderBtn_clicked()
+void ModFolderPage::on_actionView_configs_triggered()
{
- DesktopServices::openDirectory(m_inst->instanceConfigFolder(), true);
+ DesktopServices::openDirectory(m_inst->instanceConfigFolder(), true);
}
-void ModFolderPage::on_viewModBtn_clicked()
+void ModFolderPage::on_actionView_Folder_triggered()
{
- DesktopServices::openDirectory(m_mods->dir().absolutePath(), true);
+ DesktopServices::openDirectory(m_mods->dir().absolutePath(), true);
}
void ModFolderPage::modCurrent(const QModelIndex &current, const QModelIndex &previous)
{
- if (!current.isValid())
- {
- ui->frame->clear();
- return;
- }
- auto sourceCurrent = m_filterModel->mapToSource(current);
- int row = sourceCurrent.row();
- Mod &m = m_mods->operator[](row);
- ui->frame->updateWithMod(m);
+ if (!current.isValid())
+ {
+ ui->frame->clear();
+ return;
+ }
+ auto sourceCurrent = m_filterModel->mapToSource(current);
+ int row = sourceCurrent.row();
+ Mod &m = m_mods->operator[](row);
+ ui->frame->updateWithMod(m);
}
diff --git a/application/pages/instance/ModFolderPage.h b/application/pages/instance/ModFolderPage.h
index 15e728cb..d49d25c3 100644
--- a/application/pages/instance/ModFolderPage.h
+++ b/application/pages/instance/ModFolderPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 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,94 +15,105 @@
#pragma once
-#include <QWidget>
+#include <QMainWindow>
#include "minecraft/MinecraftInstance.h"
#include "pages/BasePage.h"
#include <MultiMC.h>
-class ModList;
+class ModFolderModel;
namespace Ui
{
class ModFolderPage;
}
-class ModFolderPage : public QWidget, public BasePage
+class ModFolderPage : public QMainWindow, public BasePage
{
- Q_OBJECT
+ 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();
+ explicit ModFolderPage(
+ BaseInstance *inst,
+ std::shared_ptr<ModFolderModel> mods,
+ QString id,
+ QString iconName,
+ QString displayName,
+ QString helpPage = "",
+ QWidget *parent = 0
+ );
+ virtual ~ModFolderPage();
- void setFilter(const QString & filter)
- {
- m_fileSelectionFilter = filter;
- }
+ void setFilter(const QString & filter)
+ {
+ m_fileSelectionFilter = filter;
+ }
- virtual QString displayName() const override
- {
- return m_displayName;
- }
- virtual QIcon icon() const override
- {
- return MMC->getThemedIcon(m_iconName);
- }
- virtual QString id() const override
- {
- return m_id;
- }
- virtual QString helpPage() const override
- {
- return m_helpName;
- }
- virtual bool shouldDisplay() const override;
+ virtual QString displayName() const override
+ {
+ return m_displayName;
+ }
+ virtual QIcon icon() const override
+ {
+ return MMC->getThemedIcon(m_iconName);
+ }
+ virtual QString id() const override
+ {
+ return m_id;
+ }
+ virtual QString helpPage() const override
+ {
+ return m_helpName;
+ }
+ virtual bool shouldDisplay() const override;
- virtual void openedImpl() override;
- virtual void closedImpl() override;
+ virtual void openedImpl() override;
+ virtual void closedImpl() override;
protected:
- bool eventFilter(QObject *obj, QEvent *ev) override;
- bool modListFilter(QKeyEvent *ev);
+ bool eventFilter(QObject *obj, QEvent *ev) override;
+ bool modListFilter(QKeyEvent *ev);
+ QMenu * createPopupMenu() override;
protected:
- BaseInstance *m_inst;
+ BaseInstance *m_inst = nullptr;
protected:
- Ui::ModFolderPage *ui;
- std::shared_ptr<ModList> m_mods;
- QSortFilterProxyModel *m_filterModel;
- QString m_iconName;
- QString m_id;
- QString m_displayName;
- QString m_helpName;
- QString m_fileSelectionFilter;
- QString m_viewFilter;
+ Ui::ModFolderPage *ui = nullptr;
+ std::shared_ptr<ModFolderModel> m_mods;
+ QSortFilterProxyModel *m_filterModel = nullptr;
+ QString m_iconName;
+ QString m_id;
+ QString m_displayName;
+ QString m_helpName;
+ QString m_fileSelectionFilter;
+ QString m_viewFilter;
+ bool m_controlsEnabled = true;
public
slots:
- void modCurrent(const QModelIndex &current, const QModelIndex &previous);
+ void modCurrent(const QModelIndex &current, const QModelIndex &previous);
private
slots:
- void on_filterTextChanged(const QString & newContents);
- void on_addModBtn_clicked();
- void on_rmModBtn_clicked();
- void on_viewModBtn_clicked();
- void on_enableModBtn_clicked();
- void on_disableModBtn_clicked();
- void on_configFolderBtn_clicked();
+ void modItemActivated(const QModelIndex &index);
+ void on_filterTextChanged(const QString & newContents);
+ void on_RunningState_changed(bool running);
+ void on_actionAdd_triggered();
+ void on_actionRemove_triggered();
+ void on_actionEnable_triggered();
+ void on_actionDisable_triggered();
+ void on_actionView_Folder_triggered();
+ void on_actionView_configs_triggered();
+ void ShowContextMenu(const QPoint &pos);
};
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;
+ explicit CoreModFolderPage(BaseInstance *inst, std::shared_ptr<ModFolderModel> mods, QString id,
+ QString iconName, QString displayName, QString helpPage = "",
+ QWidget *parent = 0);
+ virtual ~CoreModFolderPage()
+ {
+ }
+ virtual bool shouldDisplay() const;
};
diff --git a/application/pages/instance/ModFolderPage.ui b/application/pages/instance/ModFolderPage.ui
index b5597bdc..052df602 100644
--- a/application/pages/instance/ModFolderPage.ui
+++ b/application/pages/instance/ModFolderPage.ui
@@ -1,155 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ModFolderPage</class>
- <widget class="QWidget" name="ModFolderPage">
+ <widget class="QMainWindow" name="ModFolderPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
- <width>723</width>
- <height>532</height>
+ <width>1042</width>
+ <height>501</height>
</rect>
</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="tabWidget">
- <property name="currentIndex">
- <number>0</number>
- </property>
- <widget class="QWidget" name="tab">
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <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="4" column="1" colspan="3">
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="filterEdit">
+ <property name="clearButtonEnabled">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="filterLabel">
+ <property name="text">
+ <string>Filter:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="1" colspan="3">
+ <widget class="MCModInfoFrame" name="frame">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" colspan="3">
+ <widget class="ModListView" name="modTreeView">
<property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
- <attribute name="title">
- <string notr="true">Tab 1</string>
- </attribute>
- <layout class="QGridLayout" name="gridLayout" columnstretch="0,1,0">
- <item row="0" column="2">
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <item>
- <widget class="QPushButton" name="addModBtn">
- <property name="text">
- <string>&amp;Add</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="rmModBtn">
- <property name="text">
- <string>&amp;Remove</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="enableModBtn">
- <property name="text">
- <string>Enable</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="disableModBtn">
- <property name="text">
- <string>Disable</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="configFolderBtn">
- <property name="toolTip">
- <string>Open the 'config' folder in the system file manager.</string>
- </property>
- <property name="text">
- <string>View configs</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>&amp;View Folder</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="1" column="0" colspan="3">
- <widget class="MCModInfoFrame" name="frame">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
- </item>
- <item row="0" column="0" colspan="2">
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="1" column="1">
- <widget class="QLineEdit" name="filterEdit">
- <property name="clearButtonEnabled">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="filterLabel">
- <property name="text">
- <string>Filter:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="0" colspan="3">
- <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>
- </layout>
+ <property name="acceptDrops">
+ <bool>true</bool>
+ </property>
+ <property name="dragDropMode">
+ <enum>QAbstractItemView::DropOnly</enum>
+ </property>
</widget>
- </widget>
- </item>
- </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="WideBar" name="actionsToolbar">
+ <property name="windowTitle">
+ <string>Actions</string>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextOnly</enum>
+ </property>
+ <attribute name="toolBarArea">
+ <enum>RightToolBarArea</enum>
+ </attribute>
+ <attribute name="toolBarBreak">
+ <bool>false</bool>
+ </attribute>
+ <addaction name="actionAdd"/>
+ <addaction name="separator"/>
+ <addaction name="actionRemove"/>
+ <addaction name="actionEnable"/>
+ <addaction name="actionDisable"/>
+ <addaction name="actionView_configs"/>
+ <addaction name="actionView_Folder"/>
+ </widget>
+ <action name="actionAdd">
+ <property name="text">
+ <string>&amp;Add</string>
+ </property>
+ <property name="toolTip">
+ <string>Add mods</string>
+ </property>
+ </action>
+ <action name="actionRemove">
+ <property name="text">
+ <string>&amp;Remove</string>
+ </property>
+ <property name="toolTip">
+ <string>Remove selected mods</string>
+ </property>
+ </action>
+ <action name="actionEnable">
+ <property name="text">
+ <string>&amp;Enable</string>
+ </property>
+ <property name="toolTip">
+ <string>Enable selected mods</string>
+ </property>
+ </action>
+ <action name="actionDisable">
+ <property name="text">
+ <string>&amp;Disable</string>
+ </property>
+ <property name="toolTip">
+ <string>Disable selected mods</string>
+ </property>
+ </action>
+ <action name="actionView_configs">
+ <property name="text">
+ <string>View &amp;Configs</string>
+ </property>
+ <property name="toolTip">
+ <string>Open the 'config' folder in the system file manager.</string>
+ </property>
+ </action>
+ <action name="actionView_Folder">
+ <property name="text">
+ <string>View &amp;Folder</string>
+ </property>
+ </action>
</widget>
<customwidgets>
<customwidget>
@@ -163,17 +152,15 @@
<header>widgets/MCModInfoFrame.h</header>
<container>1</container>
</customwidget>
+ <customwidget>
+ <class>WideBar</class>
+ <extends>QToolBar</extends>
+ <header>widgets/WideBar.h</header>
+ </customwidget>
</customwidgets>
<tabstops>
- <tabstop>tabWidget</tabstop>
<tabstop>modTreeView</tabstop>
<tabstop>filterEdit</tabstop>
- <tabstop>addModBtn</tabstop>
- <tabstop>rmModBtn</tabstop>
- <tabstop>enableModBtn</tabstop>
- <tabstop>disableModBtn</tabstop>
- <tabstop>configFolderBtn</tabstop>
- <tabstop>viewModBtn</tabstop>
</tabstops>
<resources/>
<connections/>
diff --git a/application/pages/instance/NotesPage.cpp b/application/pages/instance/NotesPage.cpp
index 3925fdfc..fa966c91 100644
--- a/application/pages/instance/NotesPage.cpp
+++ b/application/pages/instance/NotesPage.cpp
@@ -3,20 +3,19 @@
#include <QTabBar>
NotesPage::NotesPage(BaseInstance *inst, QWidget *parent)
- : QWidget(parent), ui(new Ui::NotesPage), m_inst(inst)
+ : QWidget(parent), ui(new Ui::NotesPage), m_inst(inst)
{
- ui->setupUi(this);
- ui->tabWidget->tabBar()->hide();
- ui->noteEditor->setText(m_inst->notes());
+ ui->setupUi(this);
+ ui->noteEditor->setText(m_inst->notes());
}
NotesPage::~NotesPage()
{
- delete ui;
+ delete ui;
}
bool NotesPage::apply()
{
- m_inst->setNotes(ui->noteEditor->toPlainText());
- return true;
+ m_inst->setNotes(ui->noteEditor->toPlainText());
+ return true;
}
diff --git a/application/pages/instance/NotesPage.h b/application/pages/instance/NotesPage.h
index 4a25f9b1..f96e5374 100644
--- a/application/pages/instance/NotesPage.h
+++ b/application/pages/instance/NotesPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,33 +28,33 @@ class NotesPage;
class NotesPage : public QWidget, public BasePage
{
- Q_OBJECT
+ 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
- {
- auto icon = MMC->getThemedIcon("notes");
- if(icon.isNull())
- icon = MMC->getThemedIcon("news");
- return icon;
- }
- virtual QString id() const override
- {
- return "notes";
- }
- virtual bool apply() override;
- virtual QString helpPage() const override
- {
- return "Notes";
- }
+ explicit NotesPage(BaseInstance *inst, QWidget *parent = 0);
+ virtual ~NotesPage();
+ virtual QString displayName() const override
+ {
+ return tr("Notes");
+ }
+ virtual QIcon icon() const override
+ {
+ auto icon = MMC->getThemedIcon("notes");
+ if(icon.isNull())
+ icon = MMC->getThemedIcon("news");
+ return icon;
+ }
+ virtual QString id() const override
+ {
+ return "notes";
+ }
+ virtual bool apply() override;
+ virtual QString helpPage() const override
+ {
+ return "Notes";
+ }
private:
- Ui::NotesPage *ui;
- BaseInstance *m_inst;
+ Ui::NotesPage *ui;
+ BaseInstance *m_inst;
};
diff --git a/application/pages/instance/NotesPage.ui b/application/pages/instance/NotesPage.ui
index 88cca92f..67cb261c 100644
--- a/application/pages/instance/NotesPage.ui
+++ b/application/pages/instance/NotesPage.ui
@@ -10,7 +10,7 @@
<height>538</height>
</rect>
</property>
- <layout class="QVBoxLayout" name="verticalLayout_2">
+ <layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
@@ -24,34 +24,26 @@
<number>0</number>
</property>
<item>
- <widget class="QTabWidget" name="tabWidget">
- <property name="currentIndex">
- <number>0</number>
+ <widget class="QTextEdit" name="noteEditor">
+ <property name="verticalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOn</enum>
+ </property>
+ <property name="tabChangesFocus">
+ <bool>true</bool>
+ </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 class="QWidget" name="tab">
- <attribute name="title">
- <string notr="true">Tab 1</string>
- </attribute>
- <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>
- </layout>
- </widget>
</widget>
</item>
</layout>
</widget>
+ <tabstops>
+ <tabstop>noteEditor</tabstop>
+ </tabstops>
<resources/>
<connections/>
</ui>
diff --git a/application/pages/instance/OtherLogsPage.cpp b/application/pages/instance/OtherLogsPage.cpp
index 10cb1145..387db74f 100644
--- a/application/pages/instance/OtherLogsPage.cpp
+++ b/application/pages/instance/OtherLogsPage.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,289 +25,289 @@
#include <QShortcut>
OtherLogsPage::OtherLogsPage(QString path, IPathMatcher::Ptr fileFilter, QWidget *parent)
- : QWidget(parent), ui(new Ui::OtherLogsPage), m_path(path), m_fileFilter(fileFilter),
- m_watcher(new RecursiveFileSystemWatcher(this))
+ : QWidget(parent), ui(new Ui::OtherLogsPage), m_path(path), m_fileFilter(fileFilter),
+ m_watcher(new RecursiveFileSystemWatcher(this))
{
- ui->setupUi(this);
- ui->tabWidget->tabBar()->hide();
+ ui->setupUi(this);
+ ui->tabWidget->tabBar()->hide();
- m_watcher->setMatcher(fileFilter);
- m_watcher->setRootDir(QDir::current().absoluteFilePath(m_path));
+ m_watcher->setMatcher(fileFilter);
+ m_watcher->setRootDir(QDir::current().absoluteFilePath(m_path));
- connect(m_watcher, &RecursiveFileSystemWatcher::filesChanged, this, &OtherLogsPage::populateSelectLogBox);
- populateSelectLogBox();
+ connect(m_watcher, &RecursiveFileSystemWatcher::filesChanged, this, &OtherLogsPage::populateSelectLogBox);
+ populateSelectLogBox();
- auto findShortcut = new QShortcut(QKeySequence(QKeySequence::Find), this);
- connect(findShortcut, &QShortcut::activated, this, &OtherLogsPage::findActivated);
+ auto findShortcut = new QShortcut(QKeySequence(QKeySequence::Find), this);
+ connect(findShortcut, &QShortcut::activated, this, &OtherLogsPage::findActivated);
- auto findNextShortcut = new QShortcut(QKeySequence(QKeySequence::FindNext), this);
- connect(findNextShortcut, &QShortcut::activated, this, &OtherLogsPage::findNextActivated);
+ auto findNextShortcut = new QShortcut(QKeySequence(QKeySequence::FindNext), this);
+ connect(findNextShortcut, &QShortcut::activated, this, &OtherLogsPage::findNextActivated);
- auto findPreviousShortcut = new QShortcut(QKeySequence(QKeySequence::FindPrevious), this);
- connect(findPreviousShortcut, &QShortcut::activated, this, &OtherLogsPage::findPreviousActivated);
+ auto findPreviousShortcut = new QShortcut(QKeySequence(QKeySequence::FindPrevious), this);
+ connect(findPreviousShortcut, &QShortcut::activated, this, &OtherLogsPage::findPreviousActivated);
- connect(ui->searchBar, &QLineEdit::returnPressed, this, &OtherLogsPage::on_findButton_clicked);
+ connect(ui->searchBar, &QLineEdit::returnPressed, this, &OtherLogsPage::on_findButton_clicked);
}
OtherLogsPage::~OtherLogsPage()
{
- delete ui;
+ delete ui;
}
void OtherLogsPage::openedImpl()
{
- m_watcher->enable();
+ m_watcher->enable();
}
void OtherLogsPage::closedImpl()
{
- m_watcher->disable();
+ m_watcher->disable();
}
void OtherLogsPage::populateSelectLogBox()
{
- ui->selectLogBox->clear();
- ui->selectLogBox->addItems(m_watcher->files());
- if (m_currentFile.isEmpty())
- {
- setControlsEnabled(false);
- ui->selectLogBox->setCurrentIndex(-1);
- }
- else
- {
- const int index = ui->selectLogBox->findText(m_currentFile);
- if (index != -1)
- {
- ui->selectLogBox->setCurrentIndex(index);
- setControlsEnabled(true);
- }
- else
- {
- setControlsEnabled(false);
- }
- }
+ ui->selectLogBox->clear();
+ ui->selectLogBox->addItems(m_watcher->files());
+ if (m_currentFile.isEmpty())
+ {
+ setControlsEnabled(false);
+ ui->selectLogBox->setCurrentIndex(-1);
+ }
+ else
+ {
+ const int index = ui->selectLogBox->findText(m_currentFile);
+ if (index != -1)
+ {
+ ui->selectLogBox->setCurrentIndex(index);
+ setControlsEnabled(true);
+ }
+ else
+ {
+ setControlsEnabled(false);
+ }
+ }
}
void OtherLogsPage::on_selectLogBox_currentIndexChanged(const int index)
{
- QString file;
- if (index != -1)
- {
- file = ui->selectLogBox->itemText(index);
- }
+ QString file;
+ if (index != -1)
+ {
+ file = ui->selectLogBox->itemText(index);
+ }
- if (file.isEmpty() || !QFile::exists(FS::PathCombine(m_path, file)))
- {
- m_currentFile = QString();
- ui->text->clear();
- setControlsEnabled(false);
- }
- else
- {
- m_currentFile = file;
- on_btnReload_clicked();
- setControlsEnabled(true);
- }
+ if (file.isEmpty() || !QFile::exists(FS::PathCombine(m_path, file)))
+ {
+ m_currentFile = QString();
+ ui->text->clear();
+ setControlsEnabled(false);
+ }
+ else
+ {
+ m_currentFile = file;
+ on_btnReload_clicked();
+ setControlsEnabled(true);
+ }
}
void OtherLogsPage::on_btnReload_clicked()
{
- if(m_currentFile.isEmpty())
- {
- setControlsEnabled(false);
- return;
- }
- QFile file(FS::PathCombine(m_path, 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
- {
- auto setPlainText = [&](const QString & text)
- {
- QString fontFamily = MMC->settings()->get("ConsoleFont").toString();
- bool conversionOk = false;
- int fontSize = MMC->settings()->get("ConsoleFontSize").toInt(&conversionOk);
- if(!conversionOk)
- {
- fontSize = 11;
- }
- QTextDocument *doc = ui->text->document();
- doc->setDefaultFont(QFont(fontFamily, fontSize));
- ui->text->setPlainText(text);
- };
- auto showTooBig = [&]()
- {
- setPlainText(
- tr("The file (%1) is too big. You may want to open it in a viewer optimized "
- "for large files.").arg(file.fileName()));
- };
- if(file.size() > (1024ll * 1024ll * 12ll))
- {
- showTooBig();
- return;
- }
- QString content;
- if(file.fileName().endsWith(".gz"))
- {
- QByteArray temp;
- if(!GZip::unzip(file.readAll(), temp))
- {
- setPlainText(
- tr("The file (%1) is not readable.").arg(file.fileName()));
- return;
- }
- content = QString::fromUtf8(temp);
- }
- else
- {
- content = QString::fromUtf8(file.readAll());
- }
- if (content.size() >= 50000000ll)
- {
- showTooBig();
- return;
- }
- setPlainText(content);
- }
+ if(m_currentFile.isEmpty())
+ {
+ setControlsEnabled(false);
+ return;
+ }
+ QFile file(FS::PathCombine(m_path, 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
+ {
+ auto setPlainText = [&](const QString & text)
+ {
+ QString fontFamily = MMC->settings()->get("ConsoleFont").toString();
+ bool conversionOk = false;
+ int fontSize = MMC->settings()->get("ConsoleFontSize").toInt(&conversionOk);
+ if(!conversionOk)
+ {
+ fontSize = 11;
+ }
+ QTextDocument *doc = ui->text->document();
+ doc->setDefaultFont(QFont(fontFamily, fontSize));
+ ui->text->setPlainText(text);
+ };
+ auto showTooBig = [&]()
+ {
+ setPlainText(
+ tr("The file (%1) is too big. You may want to open it in a viewer optimized "
+ "for large files.").arg(file.fileName()));
+ };
+ if(file.size() > (1024ll * 1024ll * 12ll))
+ {
+ showTooBig();
+ return;
+ }
+ QString content;
+ if(file.fileName().endsWith(".gz"))
+ {
+ QByteArray temp;
+ if(!GZip::unzip(file.readAll(), temp))
+ {
+ setPlainText(
+ tr("The file (%1) is not readable.").arg(file.fileName()));
+ return;
+ }
+ content = QString::fromUtf8(temp);
+ }
+ else
+ {
+ content = QString::fromUtf8(file.readAll());
+ }
+ if (content.size() >= 50000000ll)
+ {
+ showTooBig();
+ return;
+ }
+ setPlainText(content);
+ }
}
void OtherLogsPage::on_btnPaste_clicked()
{
- GuiUtil::uploadPaste(ui->text->toPlainText(), this);
+ GuiUtil::uploadPaste(ui->text->toPlainText(), this);
}
void OtherLogsPage::on_btnCopy_clicked()
{
- GuiUtil::setClipboardText(ui->text->toPlainText());
+ GuiUtil::setClipboardText(ui->text->toPlainText());
}
void OtherLogsPage::on_btnDelete_clicked()
{
- if(m_currentFile.isEmpty())
- {
- setControlsEnabled(false);
- return;
- }
- 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(FS::PathCombine(m_path, m_currentFile));
- if (!file.remove())
- {
- QMessageBox::critical(this, tr("Error"), tr("Unable to delete %1: %2")
- .arg(m_currentFile, file.errorString()));
- }
+ if(m_currentFile.isEmpty())
+ {
+ setControlsEnabled(false);
+ return;
+ }
+ 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(FS::PathCombine(m_path, m_currentFile));
+ if (!file.remove())
+ {
+ QMessageBox::critical(this, tr("Error"), tr("Unable to delete %1: %2")
+ .arg(m_currentFile, file.errorString()));
+ }
}
void OtherLogsPage::on_btnClean_clicked()
{
- auto toDelete = m_watcher->files();
- if(toDelete.isEmpty())
- {
- return;
- }
- QMessageBox *messageBox = new QMessageBox(this);
- messageBox->setWindowTitle(tr("Clean up"));
- if(toDelete.size() > 5)
- {
- messageBox->setText(tr("Do you really want to delete all log files?"));
- messageBox->setDetailedText(toDelete.join('\n'));
- }
- else
- {
- messageBox->setText(tr("Do you really want to delete these files?\n%1").arg(toDelete.join('\n')));
- }
- messageBox->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
- messageBox->setDefaultButton(QMessageBox::Ok);
- messageBox->setTextInteractionFlags(Qt::TextSelectableByMouse);
- messageBox->setIcon(QMessageBox::Question);
- messageBox->setTextInteractionFlags(Qt::TextBrowserInteraction);
+ auto toDelete = m_watcher->files();
+ if(toDelete.isEmpty())
+ {
+ return;
+ }
+ QMessageBox *messageBox = new QMessageBox(this);
+ messageBox->setWindowTitle(tr("Clean up"));
+ if(toDelete.size() > 5)
+ {
+ messageBox->setText(tr("Do you really want to delete all log files?"));
+ messageBox->setDetailedText(toDelete.join('\n'));
+ }
+ else
+ {
+ messageBox->setText(tr("Do you really want to delete these files?\n%1").arg(toDelete.join('\n')));
+ }
+ messageBox->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
+ messageBox->setDefaultButton(QMessageBox::Ok);
+ messageBox->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ messageBox->setIcon(QMessageBox::Question);
+ messageBox->setTextInteractionFlags(Qt::TextBrowserInteraction);
- if (messageBox->exec() != QMessageBox::Ok)
- {
- return;
- }
- QStringList failed;
- for(auto item: toDelete)
- {
- QFile file(FS::PathCombine(m_path, item));
- if (!file.remove())
- {
- failed.push_back(item);
- }
- }
- if(!failed.empty())
- {
- QMessageBox *messageBox = new QMessageBox(this);
- messageBox->setWindowTitle(tr("Error"));
- if(failed.size() > 5)
- {
- messageBox->setText(tr("Couldn't delete some files!"));
- messageBox->setDetailedText(failed.join('\n'));
- }
- else
- {
- messageBox->setText(tr("Couldn't delete some files:\n%1").arg(failed.join('\n')));
- }
- messageBox->setStandardButtons(QMessageBox::Ok);
- messageBox->setDefaultButton(QMessageBox::Ok);
- messageBox->setTextInteractionFlags(Qt::TextSelectableByMouse);
- messageBox->setIcon(QMessageBox::Critical);
- messageBox->setTextInteractionFlags(Qt::TextBrowserInteraction);
- messageBox->exec();
- }
+ if (messageBox->exec() != QMessageBox::Ok)
+ {
+ return;
+ }
+ QStringList failed;
+ for(auto item: toDelete)
+ {
+ QFile file(FS::PathCombine(m_path, item));
+ if (!file.remove())
+ {
+ failed.push_back(item);
+ }
+ }
+ if(!failed.empty())
+ {
+ QMessageBox *messageBox = new QMessageBox(this);
+ messageBox->setWindowTitle(tr("Error"));
+ if(failed.size() > 5)
+ {
+ messageBox->setText(tr("Couldn't delete some files!"));
+ messageBox->setDetailedText(failed.join('\n'));
+ }
+ else
+ {
+ messageBox->setText(tr("Couldn't delete some files:\n%1").arg(failed.join('\n')));
+ }
+ messageBox->setStandardButtons(QMessageBox::Ok);
+ messageBox->setDefaultButton(QMessageBox::Ok);
+ messageBox->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ messageBox->setIcon(QMessageBox::Critical);
+ messageBox->setTextInteractionFlags(Qt::TextBrowserInteraction);
+ messageBox->exec();
+ }
}
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);
- ui->btnClean->setEnabled(enabled);
+ ui->btnReload->setEnabled(enabled);
+ ui->btnDelete->setEnabled(enabled);
+ ui->btnCopy->setEnabled(enabled);
+ ui->btnPaste->setEnabled(enabled);
+ ui->text->setEnabled(enabled);
+ ui->btnClean->setEnabled(enabled);
}
// FIXME: HACK, use LogView instead?
static void findNext(QPlainTextEdit * _this, const QString& what, bool reverse)
{
- _this->find(what, reverse ? QTextDocument::FindFlag::FindBackward : QTextDocument::FindFlag(0));
+ _this->find(what, reverse ? QTextDocument::FindFlag::FindBackward : QTextDocument::FindFlag(0));
}
void OtherLogsPage::on_findButton_clicked()
{
- auto modifiers = QApplication::keyboardModifiers();
- bool reverse = modifiers & Qt::ShiftModifier;
- findNext(ui->text, ui->searchBar->text(), reverse);
+ auto modifiers = QApplication::keyboardModifiers();
+ bool reverse = modifiers & Qt::ShiftModifier;
+ findNext(ui->text, ui->searchBar->text(), reverse);
}
void OtherLogsPage::findNextActivated()
{
- findNext(ui->text, ui->searchBar->text(), false);
+ findNext(ui->text, ui->searchBar->text(), false);
}
void OtherLogsPage::findPreviousActivated()
{
- findNext(ui->text, ui->searchBar->text(), true);
+ findNext(ui->text, ui->searchBar->text(), true);
}
void OtherLogsPage::findActivated()
{
- // focus the search bar if it doesn't have focus
- if (!ui->searchBar->hasFocus())
- {
- ui->searchBar->setFocus();
- ui->searchBar->selectAll();
- }
+ // focus the search bar if it doesn't have focus
+ if (!ui->searchBar->hasFocus())
+ {
+ ui->searchBar->setFocus();
+ ui->searchBar->selectAll();
+ }
}
diff --git a/application/pages/instance/OtherLogsPage.h b/application/pages/instance/OtherLogsPage.h
index ac01ef0a..226f3af3 100644
--- a/application/pages/instance/OtherLogsPage.h
+++ b/application/pages/instance/OtherLogsPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,52 +30,52 @@ class RecursiveFileSystemWatcher;
class OtherLogsPage : public QWidget, public BasePage
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit OtherLogsPage(QString path, IPathMatcher::Ptr fileFilter, QWidget *parent = 0);
- ~OtherLogsPage();
+ explicit OtherLogsPage(QString path, IPathMatcher::Ptr fileFilter, QWidget *parent = 0);
+ ~OtherLogsPage();
- QString id() const override
- {
- return "logs";
- }
- QString displayName() const override
- {
- return tr("Other logs");
- }
- QIcon icon() const override
- {
- return MMC->getThemedIcon("log");
- }
- QString helpPage() const override
- {
- return "Minecraft-Logs";
- }
- void openedImpl() override;
- void closedImpl() override;
+ QString id() const override
+ {
+ return "logs";
+ }
+ QString displayName() const override
+ {
+ return tr("Other logs");
+ }
+ QIcon icon() const override
+ {
+ return MMC->getThemedIcon("log");
+ }
+ QString helpPage() const override
+ {
+ return "Minecraft-Logs";
+ }
+ void openedImpl() override;
+ void closedImpl() 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();
- void on_btnClean_clicked();
+ 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();
+ void on_btnClean_clicked();
- void on_findButton_clicked();
- void findActivated();
- void findNextActivated();
- void findPreviousActivated();
+ void on_findButton_clicked();
+ void findActivated();
+ void findNextActivated();
+ void findPreviousActivated();
private:
- void setControlsEnabled(const bool enabled);
+ void setControlsEnabled(const bool enabled);
private:
- Ui::OtherLogsPage *ui;
- QString m_path;
- QString m_currentFile;
- IPathMatcher::Ptr m_fileFilter;
- RecursiveFileSystemWatcher *m_watcher;
+ Ui::OtherLogsPage *ui;
+ QString m_path;
+ QString m_currentFile;
+ IPathMatcher::Ptr m_fileFilter;
+ RecursiveFileSystemWatcher *m_watcher;
};
diff --git a/application/pages/instance/ResourcePackPage.h b/application/pages/instance/ResourcePackPage.h
index 19dc78da..e11c78a3 100644
--- a/application/pages/instance/ResourcePackPage.h
+++ b/application/pages/instance/ResourcePackPage.h
@@ -4,18 +4,19 @@
class ResourcePackPage : public ModFolderPage
{
+ Q_OBJECT
public:
- explicit ResourcePackPage(MinecraftInstance *instance, QWidget *parent = 0)
- : ModFolderPage(instance, instance->resourcePackList(), "resourcepacks",
- "resourcepacks", tr("Resource packs"), "Resource-packs", parent)
- {
- ui->configFolderBtn->setHidden(true);
- }
+ explicit ResourcePackPage(MinecraftInstance *instance, QWidget *parent = 0)
+ : ModFolderPage(instance, instance->resourcePackList(), "resourcepacks",
+ "resourcepacks", tr("Resource packs"), "Resource-packs", parent)
+ {
+ ui->actionView_configs->setVisible(false);
+ }
- virtual ~ResourcePackPage() {}
- virtual bool shouldDisplay() const override
- {
- return !m_inst->traits().contains("no-texturepacks") &&
- !m_inst->traits().contains("texturepacks");
- }
+ virtual ~ResourcePackPage() {}
+ virtual bool shouldDisplay() const override
+ {
+ return !m_inst->traits().contains("no-texturepacks") &&
+ !m_inst->traits().contains("texturepacks");
+ }
};
diff --git a/application/pages/instance/ScreenshotsPage.cpp b/application/pages/instance/ScreenshotsPage.cpp
index 71458386..efa0f9f2 100644
--- a/application/pages/instance/ScreenshotsPage.cpp
+++ b/application/pages/instance/ScreenshotsPage.cpp
@@ -13,6 +13,7 @@
#include <QPainter>
#include <QClipboard>
#include <QKeyEvent>
+#include <QMenu>
#include <MultiMC.h>
@@ -32,341 +33,390 @@ typedef std::shared_ptr<SharedIconCache> SharedIconCachePtr;
class ThumbnailingResult : public QObject
{
- Q_OBJECT
+ Q_OBJECT
public slots:
- inline void emitResultsReady(const QString &path) { emit resultsReady(path); }
- inline void emitResultsFailed(const QString &path) { emit resultsFailed(path); }
+ 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);
+ 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);
- 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;
+ 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);
+ 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
+ Q_OBJECT
public:
- explicit FilterModel(QObject *parent = 0) : QIdentityProxyModel(parent)
- {
- m_thumbnailingPool.setMaxThreadCount(4);
- m_thumbnailCache = std::make_shared<SharedIconCache>();
- m_thumbnailCache->add("placeholder", MMC->getThemedIcon("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);
- }
+ explicit FilterModel(QObject *parent = 0) : QIdentityProxyModel(parent)
+ {
+ m_thumbnailingPool.setMaxThreadCount(4);
+ m_thumbnailCache = std::make_shared<SharedIconCache>();
+ m_thumbnailCache->add("placeholder", MMC->getThemedIcon("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);
- }
+ 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);
- }
+ 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;
+ 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;
- }
+ 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(QString path, QWidget *parent)
- : QWidget(parent), ui(new Ui::ScreenshotsPage)
+ : QMainWindow(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 = path;
- m_valid = FS::ensureFolderPathExists(m_folder);
-
- ui->setupUi(this);
- ui->tabWidget->tabBar()->hide();
- 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)));
+ 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 = path;
+ m_valid = FS::ensureFolderPathExists(m_folder);
+
+ ui->setupUi(this);
+ ui->toolBar->insertSpacer(ui->actionView_Folder);
+
+ 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));
+ ui->listView->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(ui->listView, &QListView::customContextMenuRequested, this, &ScreenshotsPage::ShowContextMenu);
+ 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);
+ 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_actionDelete_triggered();
+ return true;
+ case Qt::Key_F2:
+ on_actionRename_triggered();
+ return true;
+ default:
+ break;
+ }
+ return QWidget::eventFilter(obj, evt);
}
ScreenshotsPage::~ScreenshotsPage()
{
- delete ui;
+ delete ui;
+}
+
+void ScreenshotsPage::ShowContextMenu(const QPoint& pos)
+{
+ auto menu = ui->toolBar->createContextMenu(this, tr("Context menu"));
+ menu->exec(ui->listView->mapToGlobal(pos));
+ delete menu;
+}
+
+QMenu * ScreenshotsPage::createPopupMenu()
+{
+ QMenu* filteredMenu = QMainWindow::createPopupMenu();
+ filteredMenu->removeAction( ui->toolBar->toggleViewAction() );
+ return filteredMenu;
}
void ScreenshotsPage::onItemActivated(QModelIndex index)
{
- if (!index.isValid())
- return;
- auto info = m_model->fileInfo(index);
- QString fileName = info.absoluteFilePath();
- DesktopServices::openFile(info.absoluteFilePath());
+ if (!index.isValid())
+ return;
+ auto info = m_model->fileInfo(index);
+ QString fileName = info.absoluteFilePath();
+ DesktopServices::openFile(info.absoluteFilePath());
}
-void ScreenshotsPage::on_viewFolderBtn_clicked()
+void ScreenshotsPage::on_actionView_Folder_triggered()
{
- DesktopServices::openDirectory(m_folder, true);
+ DesktopServices::openDirectory(m_folder, true);
}
-void ScreenshotsPage::on_uploadBtn_clicked()
+void ScreenshotsPage::on_actionUpload_triggered()
{
- auto selection = ui->listView->selectionModel()->selectedRows();
- if (selection.isEmpty())
- return;
-
- QList<ScreenshotPtr> uploaded;
- auto job = NetJobPtr(new 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 = NetJobPtr(new NetJob("Imgur Album Creation"));
- auto imgurAlbum = ImgurAlbumCreation::make(uploaded);
- albumTask->addNetAction(imgurAlbum);
- task.addTask(job.unwrap());
- task.addTask(albumTask.unwrap());
- m_uploadActive = true;
- ProgressDialog prog(this);
- if (prog.execWithTask(&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);
- CustomMessageBox::selectable(
- this,
- tr("Upload finished"),
- tr("The <a href=\"%1\">link to the uploaded album</a> has been placed in your clipboard.") .arg(link),
- QMessageBox::Information
- )->exec();
- }
- m_uploadActive = false;
+ auto selection = ui->listView->selectionModel()->selectedRows();
+ if (selection.isEmpty())
+ return;
+
+ QList<ScreenshotPtr> uploaded;
+ auto job = NetJobPtr(new NetJob("Screenshot Upload"));
+ if(selection.size() < 2)
+ {
+ auto item = selection.at(0);
+ auto info = m_model->fileInfo(item);
+ auto screenshot = std::make_shared<ScreenShot>(info);
+ job->addNetAction(ImgurUpload::make(screenshot));
+
+ m_uploadActive = true;
+ ProgressDialog dialog(this);
+ if(dialog.execWithTask(job.get()) != QDialog::Accepted)
+ {
+ CustomMessageBox::selectable(this, tr("Failed to upload screenshots!"),
+ tr("Unknown error"), QMessageBox::Warning)->exec();
+ }
+ else
+ {
+ auto link = screenshot->m_url;
+ QClipboard *clipboard = QApplication::clipboard();
+ clipboard->setText(link);
+ CustomMessageBox::selectable(
+ this,
+ tr("Upload finished"),
+ tr("The <a href=\"%1\">link to the uploaded screenshot</a> has been placed in your clipboard.")
+ .arg(link),
+ QMessageBox::Information
+ )->exec();
+ }
+
+ m_uploadActive = false;
+ return;
+ }
+
+ 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 = NetJobPtr(new NetJob("Imgur Album Creation"));
+ auto imgurAlbum = ImgurAlbumCreation::make(uploaded);
+ albumTask->addNetAction(imgurAlbum);
+ task.addTask(job.unwrap());
+ task.addTask(albumTask.unwrap());
+ m_uploadActive = true;
+ ProgressDialog prog(this);
+ if (prog.execWithTask(&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);
+ CustomMessageBox::selectable(
+ this,
+ tr("Upload finished"),
+ tr("The <a href=\"%1\">link to the uploaded album</a> has been placed in your clipboard.") .arg(link),
+ QMessageBox::Information
+ )->exec();
+ }
+ m_uploadActive = false;
}
-void ScreenshotsPage::on_deleteBtn_clicked()
+void ScreenshotsPage::on_actionDelete_triggered()
{
- 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);
- }
+ 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()
+void ScreenshotsPage::on_actionRename_triggered()
{
- auto selection = ui->listView->selectionModel()->selectedIndexes();
- if (selection.isEmpty())
- return;
- ui->listView->edit(selection[0]);
- // TODO: mass renaming
+ auto selection = ui->listView->selectionModel()->selectedIndexes();
+ if (selection.isEmpty())
+ return;
+ ui->listView->edit(selection[0]);
+ // TODO: mass renaming
}
void ScreenshotsPage::openedImpl()
{
- if(!m_valid)
- {
- m_valid = FS::ensureFolderPathExists(m_folder);
- }
- if (m_valid)
- {
- QString path = QDir(m_folder).absolutePath();
- auto idx = m_model->setRootPath(path);
- if(idx.isValid())
- {
- ui->listView->setModel(m_filterModel.get());
- ui->listView->setRootIndex(m_filterModel->mapFromSource(idx));
- }
- else
- {
- ui->listView->setModel(nullptr);
- }
- }
+ if(!m_valid)
+ {
+ m_valid = FS::ensureFolderPathExists(m_folder);
+ }
+ if (m_valid)
+ {
+ QString path = QDir(m_folder).absolutePath();
+ auto idx = m_model->setRootPath(path);
+ if(idx.isValid())
+ {
+ ui->listView->setModel(m_filterModel.get());
+ ui->listView->setRootIndex(m_filterModel->mapFromSource(idx));
+ }
+ else
+ {
+ ui->listView->setModel(nullptr);
+ }
+ }
}
#include "ScreenshotsPage.moc"
diff --git a/application/pages/instance/ScreenshotsPage.h b/application/pages/instance/ScreenshotsPage.h
index e31fb8b4..9adf79af 100644
--- a/application/pages/instance/ScreenshotsPage.h
+++ b/application/pages/instance/ScreenshotsPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 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,7 +15,7 @@
#pragma once
-#include <QWidget>
+#include <QMainWindow>
#include "pages/BasePage.h"
#include <MultiMC.h>
@@ -31,54 +31,59 @@ struct ScreenShot;
class ScreenshotList;
class ImgurAlbumCreation;
-class ScreenshotsPage : public QWidget, public BasePage
+class ScreenshotsPage : public QMainWindow, public BasePage
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit ScreenshotsPage(QString path, QWidget *parent = 0);
- virtual ~ScreenshotsPage();
+ explicit ScreenshotsPage(QString path, QWidget *parent = 0);
+ virtual ~ScreenshotsPage();
- virtual void openedImpl() override;
+ virtual void openedImpl() override;
- enum
- {
- NothingDone = 0x42
- };
+ enum
+ {
+ NothingDone = 0x42
+ };
+
+ virtual bool eventFilter(QObject *, QEvent *) override;
+ virtual QString displayName() const override
+ {
+ return tr("Screenshots");
+ }
+ virtual QIcon icon() const override
+ {
+ return MMC->getThemedIcon("screenshots");
+ }
+ virtual QString id() const override
+ {
+ return "screenshots";
+ }
+ virtual QString helpPage() const override
+ {
+ return "Screenshots-management";
+ }
+ virtual bool apply() override
+ {
+ return !m_uploadActive;
+ }
+
+protected:
+ QMenu * createPopupMenu() override;
- virtual bool eventFilter(QObject *, QEvent *) override;
- virtual QString displayName() const override
- {
- return tr("Screenshots");
- }
- virtual QIcon icon() const override
- {
- return MMC->getThemedIcon("screenshots");
- }
- virtual QString id() const override
- {
- return "screenshots";
- }
- virtual QString helpPage() const override
- {
- return "Screenshots-management";
- }
- virtual bool apply() override
- {
- return !m_uploadActive;
- }
private slots:
- void on_uploadBtn_clicked();
- void on_deleteBtn_clicked();
- void on_renameBtn_clicked();
- void on_viewFolderBtn_clicked();
- void onItemActivated(QModelIndex);
+ void on_actionUpload_triggered();
+ void on_actionDelete_triggered();
+ void on_actionRename_triggered();
+ void on_actionView_Folder_triggered();
+ void onItemActivated(QModelIndex);
+ void ShowContextMenu(const QPoint &pos);
private:
- Ui::ScreenshotsPage *ui;
- std::shared_ptr<QFileSystemModel> m_model;
- std::shared_ptr<QIdentityProxyModel> m_filterModel;
- QString m_folder;
- bool m_valid = false;
- bool m_uploadActive = false;
+ Ui::ScreenshotsPage *ui;
+ std::shared_ptr<QFileSystemModel> m_model;
+ std::shared_ptr<QIdentityProxyModel> m_filterModel;
+ QString m_folder;
+ bool m_valid = false;
+ bool m_uploadActive = false;
};
diff --git a/application/pages/instance/ScreenshotsPage.ui b/application/pages/instance/ScreenshotsPage.ui
index d05c4384..42d4db64 100644
--- a/application/pages/instance/ScreenshotsPage.ui
+++ b/application/pages/instance/ScreenshotsPage.ui
@@ -1,106 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ScreenshotsPage</class>
- <widget class="QWidget" name="ScreenshotsPage">
+ <widget class="QMainWindow" name="ScreenshotsPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
- <width>723</width>
- <height>532</height>
+ <width>800</width>
+ <height>600</height>
</rect>
</property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <property name="leftMargin">
- <number>0</number>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <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="QListView" name="listView">
+ <property name="selectionMode">
+ <enum>QAbstractItemView::ExtendedSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="WideBar" name="toolBar">
+ <property name="windowTitle">
+ <string>toolBar</string>
</property>
- <property name="topMargin">
- <number>0</number>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextOnly</enum>
</property>
- <property name="rightMargin">
- <number>0</number>
+ <attribute name="toolBarArea">
+ <enum>RightToolBarArea</enum>
+ </attribute>
+ <attribute name="toolBarBreak">
+ <bool>false</bool>
+ </attribute>
+ <addaction name="actionUpload"/>
+ <addaction name="actionDelete"/>
+ <addaction name="actionRename"/>
+ <addaction name="actionView_Folder"/>
+ </widget>
+ <action name="actionUpload">
+ <property name="text">
+ <string>Upload</string>
</property>
- <property name="bottomMargin">
- <number>0</number>
+ </action>
+ <action name="actionDelete">
+ <property name="text">
+ <string>Delete</string>
</property>
- <item>
- <widget class="QTabWidget" name="tabWidget">
- <property name="currentIndex">
- <number>0</number>
- </property>
- <widget class="QWidget" name="tab">
- <attribute name="title">
- <string notr="true">Tab 1</string>
- </attribute>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QListView" name="listView">
- <property name="selectionMode">
- <enum>QAbstractItemView::ExtendedSelection</enum>
- </property>
- <property name="selectionBehavior">
- <enum>QAbstractItemView::SelectRows</enum>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <item>
- <widget class="QPushButton" name="uploadBtn">
- <property name="text">
- <string>&amp;Upload</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="deleteBtn">
- <property name="text">
- <string>&amp;Delete</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="renameBtn">
- <property name="text">
- <string>&amp;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>&amp;View Folder</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </widget>
- </item>
- </layout>
+ </action>
+ <action name="actionRename">
+ <property name="text">
+ <string>Rename</string>
+ </property>
+ </action>
+ <action name="actionView_Folder">
+ <property name="text">
+ <string>View Folder</string>
+ </property>
+ </action>
</widget>
- <tabstops>
- <tabstop>listView</tabstop>
- <tabstop>uploadBtn</tabstop>
- <tabstop>deleteBtn</tabstop>
- <tabstop>renameBtn</tabstop>
- <tabstop>viewFolderBtn</tabstop>
- </tabstops>
+ <customwidgets>
+ <customwidget>
+ <class>WideBar</class>
+ <extends>QToolBar</extends>
+ <header>widgets/WideBar.h</header>
+ </customwidget>
+ </customwidgets>
<resources/>
<connections/>
</ui>
diff --git a/application/pages/instance/ServersPage.cpp b/application/pages/instance/ServersPage.cpp
new file mode 100644
index 00000000..c33eef1f
--- /dev/null
+++ b/application/pages/instance/ServersPage.cpp
@@ -0,0 +1,760 @@
+#include "ServersPage.h"
+#include "ui_ServersPage.h"
+
+#include <FileSystem.h>
+#include <sstream>
+#include <io/stream_reader.h>
+#include <tag_string.h>
+#include <tag_primitive.h>
+#include <tag_list.h>
+#include <tag_compound.h>
+#include <minecraft/MinecraftInstance.h>
+
+#include <QFileSystemWatcher>
+#include <QMenu>
+
+static const int COLUMN_COUNT = 2; // 3 , TBD: latency and other nice things.
+
+struct Server
+{
+ // Types
+ enum class AcceptsTextures : int
+ {
+ ASK = 0,
+ ALWAYS = 1,
+ NEVER = 2
+ };
+
+ // Methods
+ Server()
+ {
+ m_name = QObject::tr("Minecraft Server");
+ }
+ Server(const QString & name, const QString & address)
+ {
+ m_name = name;
+ m_address = address;
+ }
+ Server(nbt::tag_compound& server)
+ {
+ std::string addressStr(server["ip"]);
+ m_address = QString::fromUtf8(addressStr.c_str());
+
+ std::string nameStr(server["name"]);
+ m_name = QString::fromUtf8(nameStr.c_str());
+
+ if(server["icon"])
+ {
+ std::string base64str(server["icon"]);
+ m_icon = QByteArray::fromBase64(base64str.c_str());
+ }
+
+ if(server.has_key("acceptTextures", nbt::tag_type::Byte))
+ {
+ bool value = server["acceptTextures"].as<nbt::tag_byte>().get();
+ if(value)
+ {
+ m_acceptsTextures = AcceptsTextures::ALWAYS;
+ }
+ else
+ {
+ m_acceptsTextures = AcceptsTextures::NEVER;
+ }
+ }
+ }
+
+ void serialize(nbt::tag_compound& server)
+ {
+ server.insert("name", m_name.trimmed().toUtf8().toStdString());
+ server.insert("ip", m_address.trimmed().toUtf8().toStdString());
+ if(m_icon.size())
+ {
+ server.insert("icon", m_icon.toBase64().toStdString());
+ }
+ if(m_acceptsTextures != AcceptsTextures::ASK)
+ {
+ server.insert("acceptTextures", nbt::tag_byte(m_acceptsTextures == AcceptsTextures::ALWAYS));
+ }
+ }
+
+ // Data - persistent and user changeable
+ QString m_name;
+ QString m_address;
+ AcceptsTextures m_acceptsTextures = AcceptsTextures::ASK;
+
+ // Data - persistent and automatically updated
+ QByteArray m_icon;
+
+ // Data - temporary
+ bool m_checked = false;
+ bool m_up = false;
+ QString m_motd; // https://mctools.org/motd-creator
+ int m_ping = 0;
+ int m_currentPlayers = 0;
+ int m_maxPlayers = 0;
+};
+
+static std::unique_ptr <nbt::tag_compound> parseServersDat(const QString& filename)
+{
+ try
+ {
+ QByteArray input = FS::read(filename);
+ std::istringstream foo(std::string(input.constData(), input.size()));
+ auto pair = nbt::io::read_compound(foo);
+
+ if(pair.first != "")
+ return nullptr;
+
+ if(pair.second == nullptr)
+ return nullptr;
+
+ return std::move(pair.second);
+ }
+ catch (...)
+ {
+ return nullptr;
+ }
+}
+
+static bool serializeServerDat(const QString& filename, nbt::tag_compound * levelInfo)
+{
+ try
+ {
+ if(!FS::ensureFilePathExists(filename))
+ {
+ return false;
+ }
+ std::ostringstream s;
+ nbt::io::write_tag("", *levelInfo, s);
+ QByteArray val(s.str().data(), (int) s.str().size() );
+ FS::write(filename, val);
+ return true;
+ }
+ catch (...)
+ {
+ return false;
+ }
+}
+
+class ServersModel: public QAbstractListModel
+{
+ Q_OBJECT
+public:
+ enum Roles
+ {
+ ServerPtrRole = Qt::UserRole,
+ };
+ explicit ServersModel(const QString &path, QObject *parent = 0)
+ : QAbstractListModel(parent)
+ {
+ m_path = path;
+ m_watcher = new QFileSystemWatcher(this);
+ connect(m_watcher, &QFileSystemWatcher::fileChanged, this, &ServersModel::fileChanged);
+ connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, &ServersModel::dirChanged);
+ m_saveTimer.setSingleShot(true);
+ m_saveTimer.setInterval(5000);
+ connect(&m_saveTimer, &QTimer::timeout, this, &ServersModel::save_internal);
+ }
+ virtual ~ServersModel() {};
+
+ void observe()
+ {
+ if(m_observed)
+ {
+ return;
+ }
+ m_observed = true;
+
+ if(!m_loaded)
+ {
+ load();
+ }
+
+ updateFSObserver();
+ }
+
+ void unobserve()
+ {
+ if(!m_observed)
+ {
+ return;
+ }
+ m_observed = false;
+
+ updateFSObserver();
+ }
+
+ void lock()
+ {
+ if(m_locked)
+ {
+ return;
+ }
+ saveNow();
+
+ m_locked = true;
+ updateFSObserver();
+ }
+
+ void unlock()
+ {
+ if(!m_locked)
+ {
+ return;
+ }
+ m_locked = false;
+
+ updateFSObserver();
+ }
+
+ int addEmptyRow(int position)
+ {
+ if(m_locked)
+ {
+ return -1;
+ }
+ if(position < 0 || position >= rowCount())
+ {
+ position = rowCount();
+ }
+ beginInsertRows(QModelIndex(), position, position);
+ m_servers.insert(position, Server());
+ endInsertRows();
+ scheduleSave();
+ return position;
+ }
+
+ bool removeRow(int row)
+ {
+ if(m_locked)
+ {
+ return false;
+ }
+ if(row < 0 || row >= rowCount())
+ {
+ return false;
+ }
+ beginRemoveRows(QModelIndex(), row, row);
+ m_servers.removeAt(row);
+ endRemoveRows(); // does absolutely nothing, the selected server stays as the next line...
+ scheduleSave();
+ return true;
+ }
+
+ bool moveUp(int row)
+ {
+ if(m_locked)
+ {
+ return false;
+ }
+ if(row <= 0)
+ {
+ return false;
+ }
+ beginMoveRows(QModelIndex(), row, row, QModelIndex(), row - 1);
+ m_servers.swap(row-1, row);
+ endMoveRows();
+ scheduleSave();
+ return true;
+ }
+
+ bool moveDown(int row)
+ {
+ if(m_locked)
+ {
+ return false;
+ }
+ int count = rowCount();
+ if(row + 1 >= count)
+ {
+ return false;
+ }
+ beginMoveRows(QModelIndex(), row, row, QModelIndex(), row + 2);
+ m_servers.swap(row+1, row);
+ endMoveRows();
+ scheduleSave();
+ return true;
+ }
+
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const override
+ {
+ if (section < 0 || section >= COLUMN_COUNT)
+ return QVariant();
+
+ if(role == Qt::DisplayRole)
+ {
+ switch(section)
+ {
+ case 0:
+ return tr("Name");
+ case 1:
+ return tr("Address");
+ case 2:
+ return tr("Latency");
+ }
+ }
+
+ return QAbstractListModel::headerData(section, orientation, role);
+ }
+
+ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
+ {
+ if (!index.isValid())
+ return QVariant();
+
+ int row = index.row();
+ int column = index.column();
+ if(column < 0 || column >= COLUMN_COUNT)
+ return QVariant();
+
+ if (row < 0 || row >= m_servers.size())
+ return QVariant();
+
+ switch(column)
+ {
+ case 0:
+ switch (role)
+ {
+ case Qt::DecorationRole:
+ {
+ auto & bytes = m_servers[row].m_icon;
+ if(bytes.size())
+ {
+ QPixmap px;
+ if(px.loadFromData(bytes))
+ return QIcon(px);
+ }
+ return MMC->getThemedIcon("unknown_server");
+ }
+ case Qt::DisplayRole:
+ return m_servers[row].m_name;
+ case ServerPtrRole:
+ return QVariant::fromValue<void *>((void *)&m_servers[row]);
+ default:
+ return QVariant();
+ }
+ case 1:
+ switch (role)
+ {
+ case Qt::DisplayRole:
+ return m_servers[row].m_address;
+ default:
+ return QVariant();
+ }
+ case 2:
+ switch (role)
+ {
+ case Qt::DisplayRole:
+ return m_servers[row].m_ping;
+ default:
+ return QVariant();
+ }
+ default:
+ return QVariant();
+ }
+ }
+
+ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override
+ {
+ return m_servers.size();
+ }
+ int columnCount(const QModelIndex & parent) const override
+ {
+ return COLUMN_COUNT;
+ }
+
+ Server * at(int index)
+ {
+ if(index < 0 || index >= rowCount())
+ {
+ return nullptr;
+ }
+ return &m_servers[index];
+ }
+
+ void setName(int row, const QString & name)
+ {
+ if(m_locked)
+ {
+ return;
+ }
+ auto server = at(row);
+ if(!server || server->m_name == name)
+ {
+ return;
+ }
+ server->m_name = name;
+ emit dataChanged(index(row, 0), index(row, COLUMN_COUNT - 1));
+ scheduleSave();
+ }
+
+ void setAddress(int row, const QString & address)
+ {
+ if(m_locked)
+ {
+ return;
+ }
+ auto server = at(row);
+ if(!server || server->m_address == address)
+ {
+ return;
+ }
+ server->m_address = address;
+ emit dataChanged(index(row, 0), index(row, COLUMN_COUNT - 1));
+ scheduleSave();
+ }
+
+ void setAcceptsTextures(int row, Server::AcceptsTextures textures)
+ {
+ if(m_locked)
+ {
+ return;
+ }
+ auto server = at(row);
+ if(!server || server->m_acceptsTextures == textures)
+ {
+ return;
+ }
+ server->m_acceptsTextures = textures;
+ emit dataChanged(index(row, 0), index(row, COLUMN_COUNT - 1));
+ scheduleSave();
+ }
+
+ void load()
+ {
+ cancelSave();
+ beginResetModel();
+ QList<Server> servers;
+ auto serversDat = parseServersDat(serversPath());
+ if(serversDat)
+ {
+ auto &serversList = serversDat->at("servers").as<nbt::tag_list>();
+ for(auto iter = serversList.begin(); iter != serversList.end(); iter++)
+ {
+ auto & serverTag = (*iter).as<nbt::tag_compound>();
+ Server s(serverTag);
+ servers.append(s);
+ }
+ }
+ m_servers.swap(servers);
+ m_loaded = true;
+ endResetModel();
+ }
+
+ void saveNow()
+ {
+ if(saveIsScheduled())
+ {
+ save_internal();
+ }
+ }
+
+
+public slots:
+ void dirChanged(const QString& path)
+ {
+ qDebug() << "Changed:" << path;
+ load();
+ }
+ void fileChanged(const QString& path)
+ {
+ qDebug() << "Changed:" << path;
+ }
+
+private slots:
+ void save_internal()
+ {
+ cancelSave();
+ QString path = serversPath();
+ qDebug() << "Server list about to be saved to" << path;
+
+ nbt::tag_compound out;
+ nbt::tag_list list;
+ for(auto & server: m_servers)
+ {
+ nbt::tag_compound serverNbt;
+ server.serialize(serverNbt);
+ list.push_back(std::move(serverNbt));
+ }
+ out.insert("servers", nbt::value(std::move(list)));
+
+ if(!serializeServerDat(path, &out))
+ {
+ qDebug() << "Failed to save server list:" << path << "Will try again.";
+ scheduleSave();
+ }
+ }
+
+private:
+ void scheduleSave()
+ {
+ if(!m_loaded)
+ {
+ qDebug() << "Server list should never save if it didn't successfully load, path:" << m_path;
+ return;
+ }
+ if(!m_dirty)
+ {
+ m_dirty = true;
+ qDebug() << "Server list save is scheduled for" << m_path;
+ }
+ m_saveTimer.start();
+ }
+
+ void cancelSave()
+ {
+ m_dirty = false;
+ m_saveTimer.stop();
+ }
+
+ bool saveIsScheduled() const
+ {
+ return m_dirty;
+ }
+
+ void updateFSObserver()
+ {
+ bool observingFS = m_watcher->directories().contains(m_path);
+ if(m_observed && m_locked)
+ {
+ if(!observingFS)
+ {
+ qWarning() << "Will watch" << m_path;
+ if(!m_watcher->addPath(m_path))
+ {
+ qWarning() << "Failed to start watching" << m_path;
+ }
+ }
+ }
+ else
+ {
+ if(observingFS)
+ {
+ qWarning() << "Will stop watching" << m_path;
+ if(!m_watcher->removePath(m_path))
+ {
+ qWarning() << "Failed to stop watching" << m_path;
+ }
+ }
+ }
+ }
+
+ QString serversPath()
+ {
+ QFileInfo foo(FS::PathCombine(m_path, "servers.dat"));
+ return foo.filePath();
+ }
+
+private:
+ bool m_loaded = false;
+ bool m_locked = false;
+ bool m_observed = false;
+ bool m_dirty = false;
+ QString m_path;
+ QList<Server> m_servers;
+ QFileSystemWatcher *m_watcher = nullptr;
+ QTimer m_saveTimer;
+};
+
+ServersPage::ServersPage(MinecraftInstance * inst, QWidget* parent)
+ : QMainWindow(parent), ui(new Ui::ServersPage)
+{
+ ui->setupUi(this);
+ m_inst = inst;
+ m_model = new ServersModel(inst->gameRoot(), this);
+ ui->serversView->setIconSize(QSize(64,64));
+ ui->serversView->setModel(m_model);
+ ui->serversView->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(ui->serversView, &QTreeView::customContextMenuRequested, this, &ServersPage::ShowContextMenu);
+
+ auto head = ui->serversView->header();
+ if(head->count())
+ {
+ head->setSectionResizeMode(0, QHeaderView::Stretch);
+ for(int i = 1; i < head->count(); i++)
+ {
+ head->setSectionResizeMode(i, QHeaderView::ResizeToContents);
+ }
+ }
+
+ auto selectionModel = ui->serversView->selectionModel();
+ connect(selectionModel, &QItemSelectionModel::currentChanged, this, &ServersPage::currentChanged);
+ connect(m_inst, &MinecraftInstance::runningStatusChanged, this, &ServersPage::on_RunningState_changed);
+ connect(ui->nameLine, &QLineEdit::textEdited, this, &ServersPage::nameEdited);
+ connect(ui->addressLine, &QLineEdit::textEdited, this, &ServersPage::addressEdited);
+ connect(ui->resourceComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(resourceIndexChanged(int)));
+ connect(m_model, &QAbstractItemModel::rowsRemoved, this, &ServersPage::rowsRemoved);
+
+ m_locked = m_inst->isRunning();
+ if(m_locked)
+ {
+ m_model->lock();
+ }
+
+ updateState();
+}
+
+ServersPage::~ServersPage()
+{
+ m_model->saveNow();
+}
+
+void ServersPage::ShowContextMenu(const QPoint& pos)
+{
+ auto menu = ui->toolBar->createContextMenu(this, tr("Context menu"));
+ menu->exec(ui->serversView->mapToGlobal(pos));
+ delete menu;
+}
+
+QMenu * ServersPage::createPopupMenu()
+{
+ QMenu* filteredMenu = QMainWindow::createPopupMenu();
+ filteredMenu->removeAction( ui->toolBar->toggleViewAction() );
+ return filteredMenu;
+}
+
+void ServersPage::on_RunningState_changed(bool running)
+{
+ if(m_locked == running)
+ {
+ return;
+ }
+ m_locked = running;
+ if(m_locked)
+ {
+ m_model->lock();
+ }
+ else
+ {
+ m_model->unlock();
+ }
+ updateState();
+}
+
+void ServersPage::currentChanged(const QModelIndex &current, const QModelIndex &previous)
+{
+ int nextServer = -1;
+ if (!current.isValid())
+ {
+ nextServer = -1;
+ }
+ else
+ {
+ nextServer = current.row();
+ }
+ currentServer = nextServer;
+ updateState();
+}
+
+// WARNING: this is here because currentChanged is not accurate when removing rows. the current item needs to be fixed up after removal.
+void ServersPage::rowsRemoved(const QModelIndex& parent, int first, int last)
+{
+ if(currentServer < first)
+ {
+ // current was before the removal
+ return;
+ }
+ else if(currentServer >= first && currentServer <= last)
+ {
+ // current got removed...
+ return;
+ }
+ else
+ {
+ // current was past the removal
+ int count = last - first + 1;
+ currentServer -= count;
+ }
+}
+
+void ServersPage::nameEdited(const QString& name)
+{
+ m_model->setName(currentServer, name);
+}
+
+void ServersPage::addressEdited(const QString& address)
+{
+ m_model->setAddress(currentServer, address);
+}
+
+void ServersPage::resourceIndexChanged(int index)
+{
+ auto acceptsTextures = Server::AcceptsTextures(index);
+ m_model->setAcceptsTextures(currentServer, acceptsTextures);
+}
+
+void ServersPage::updateState()
+{
+ auto server = m_model->at(currentServer);
+
+ bool serverEditEnabled = server && !m_locked;
+ ui->addressLine->setEnabled(serverEditEnabled);
+ ui->nameLine->setEnabled(serverEditEnabled);
+ ui->resourceComboBox->setEnabled(serverEditEnabled);
+ ui->actionMove_Down->setEnabled(serverEditEnabled);
+ ui->actionMove_Up->setEnabled(serverEditEnabled);
+ ui->actionRemove->setEnabled(serverEditEnabled);
+
+ if(server)
+ {
+ ui->addressLine->setText(server->m_address);
+ ui->nameLine->setText(server->m_name);
+ ui->resourceComboBox->setCurrentIndex(int(server->m_acceptsTextures));
+ }
+ else
+ {
+ ui->addressLine->setText(QString());
+ ui->nameLine->setText(QString());
+ ui->resourceComboBox->setCurrentIndex(0);
+ }
+
+ ui->actionAdd->setDisabled(m_locked);
+}
+
+void ServersPage::openedImpl()
+{
+ m_model->observe();
+}
+
+void ServersPage::closedImpl()
+{
+ m_model->unobserve();
+}
+
+void ServersPage::on_actionAdd_triggered()
+{
+ int position = m_model->addEmptyRow(currentServer + 1);
+ if(position < 0)
+ {
+ return;
+ }
+ // select the new row
+ ui->serversView->selectionModel()->setCurrentIndex(
+ m_model->index(position),
+ QItemSelectionModel::SelectCurrent | QItemSelectionModel::Clear | QItemSelectionModel::Rows
+ );
+ currentServer = position;
+}
+
+void ServersPage::on_actionRemove_triggered()
+{
+ m_model->removeRow(currentServer);
+}
+
+void ServersPage::on_actionMove_Up_triggered()
+{
+ if(m_model->moveUp(currentServer))
+ {
+ currentServer --;
+ }
+}
+
+void ServersPage::on_actionMove_Down_triggered()
+{
+ if(m_model->moveDown(currentServer))
+ {
+ currentServer ++;
+ }
+}
+
+#include "ServersPage.moc"
diff --git a/application/pages/instance/ServersPage.h b/application/pages/instance/ServersPage.h
new file mode 100644
index 00000000..c81f47be
--- /dev/null
+++ b/application/pages/instance/ServersPage.h
@@ -0,0 +1,93 @@
+/* Copyright 2013-2019 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 <QMainWindow>
+#include <QString>
+
+#include "pages/BasePage.h"
+#include <MultiMC.h>
+
+namespace Ui
+{
+class ServersPage;
+}
+
+struct Server;
+class ServersModel;
+class MinecraftInstance;
+
+class ServersPage : public QMainWindow, public BasePage
+{
+ Q_OBJECT
+
+public:
+ explicit ServersPage(MinecraftInstance *inst, QWidget *parent = 0);
+ virtual ~ServersPage();
+
+ void openedImpl() override;
+ void closedImpl() override;
+
+ virtual QString displayName() const override
+ {
+ return tr("Servers");
+ }
+ virtual QIcon icon() const override
+ {
+ return MMC->getThemedIcon("unknown_server");
+ }
+ virtual QString id() const override
+ {
+ return "servers";
+ }
+ virtual QString helpPage() const override
+ {
+ return "Servers-management";
+ }
+
+protected:
+ QMenu * createPopupMenu() override;
+
+private:
+ void updateState();
+ void scheduleSave();
+ bool saveIsScheduled() const;
+
+private slots:
+ void currentChanged(const QModelIndex &current, const QModelIndex &previous);
+ void rowsRemoved(const QModelIndex &parent, int first, int last);
+
+ void on_actionAdd_triggered();
+ void on_actionRemove_triggered();
+ void on_actionMove_Up_triggered();
+ void on_actionMove_Down_triggered();
+
+ void on_RunningState_changed(bool running);
+
+ void nameEdited(const QString & name);
+ void addressEdited(const QString & address);
+ void resourceIndexChanged(int index);\
+
+ void ShowContextMenu(const QPoint &pos);
+
+private: // data
+ int currentServer = -1;
+ bool m_locked = true;
+ Ui::ServersPage *ui = nullptr;
+ ServersModel * m_model = nullptr;
+ MinecraftInstance * m_inst = nullptr;
+};
+
diff --git a/application/pages/instance/ServersPage.ui b/application/pages/instance/ServersPage.ui
new file mode 100644
index 00000000..9c31abe3
--- /dev/null
+++ b/application/pages/instance/ServersPage.ui
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ServersPage</class>
+ <widget class="QMainWindow" name="ServersPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1318</width>
+ <height>879</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <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="QTreeView" name="serversView">
+ <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="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>64</width>
+ <height>64</height>
+ </size>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <attribute name="headerStretchLastSection">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ </item>
+ <item>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+ <property name="rightMargin">
+ <number>6</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="nameLabel">
+ <property name="text">
+ <string>&amp;Name</string>
+ </property>
+ <property name="buddy">
+ <cstring>nameLine</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="nameLine"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="addressLabel">
+ <property name="text">
+ <string>Address</string>
+ </property>
+ <property name="buddy">
+ <cstring>addressLine</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="addressLine"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="resourcesLabel">
+ <property name="text">
+ <string>Reso&amp;urces</string>
+ </property>
+ <property name="buddy">
+ <cstring>resourceComboBox</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QComboBox" name="resourceComboBox">
+ <item>
+ <property name="text">
+ <string>Ask to download</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Always download</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Never download</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="WideBar" name="toolBar">
+ <property name="windowTitle">
+ <string>toolBar</string>
+ </property>
+ <property name="allowedAreas">
+ <set>Qt::LeftToolBarArea|Qt::RightToolBarArea</set>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextOnly</enum>
+ </property>
+ <property name="floatable">
+ <bool>false</bool>
+ </property>
+ <attribute name="toolBarArea">
+ <enum>RightToolBarArea</enum>
+ </attribute>
+ <attribute name="toolBarBreak">
+ <bool>false</bool>
+ </attribute>
+ <addaction name="actionAdd"/>
+ <addaction name="actionRemove"/>
+ <addaction name="actionMove_Up"/>
+ <addaction name="actionMove_Down"/>
+ </widget>
+ <action name="actionAdd">
+ <property name="text">
+ <string>Add</string>
+ </property>
+ </action>
+ <action name="actionRemove">
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </action>
+ <action name="actionMove_Up">
+ <property name="text">
+ <string>Move Up</string>
+ </property>
+ </action>
+ <action name="actionMove_Down">
+ <property name="text">
+ <string>Move Down</string>
+ </property>
+ </action>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>WideBar</class>
+ <extends>QToolBar</extends>
+ <header>widgets/WideBar.h</header>
+ </customwidget>
+ </customwidgets>
+ <tabstops>
+ <tabstop>serversView</tabstop>
+ <tabstop>nameLine</tabstop>
+ <tabstop>addressLine</tabstop>
+ <tabstop>resourceComboBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/application/pages/instance/TexturePackPage.h b/application/pages/instance/TexturePackPage.h
index b03614f0..a792ba07 100644
--- a/application/pages/instance/TexturePackPage.h
+++ b/application/pages/instance/TexturePackPage.h
@@ -4,16 +4,17 @@
class TexturePackPage : public ModFolderPage
{
+ Q_OBJECT
public:
- explicit TexturePackPage(MinecraftInstance *instance, QWidget *parent = 0)
- : ModFolderPage(instance, instance->texturePackList(), "texturepacks", "resourcepacks",
- tr("Texture packs"), "Texture-packs", parent)
- {
- ui->configFolderBtn->setHidden(true);
- }
- virtual ~TexturePackPage() {}
- virtual bool shouldDisplay() const override
- {
- return m_inst->traits().contains("texturepacks");
- }
+ explicit TexturePackPage(MinecraftInstance *instance, QWidget *parent = 0)
+ : ModFolderPage(instance, instance->texturePackList(), "texturepacks", "resourcepacks",
+ tr("Texture packs"), "Texture-packs", parent)
+ {
+ ui->actionView_configs->setVisible(false);
+ }
+ virtual ~TexturePackPage() {}
+ virtual bool shouldDisplay() const override
+ {
+ return m_inst->traits().contains("texturepacks");
+ }
};
diff --git a/application/pages/instance/VersionPage.cpp b/application/pages/instance/VersionPage.cpp
index 00ae0a7e..2acc13c2 100644
--- a/application/pages/instance/VersionPage.cpp
+++ b/application/pages/instance/VersionPage.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 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,8 +16,10 @@
#include "MultiMC.h"
#include <QMessageBox>
+#include <QLabel>
#include <QEvent>
#include <QKeyEvent>
+#include <QMenu>
#include "VersionPage.h"
#include "ui_VersionPage.h"
@@ -25,7 +27,6 @@
#include "dialogs/CustomMessageBox.h"
#include "dialogs/VersionSelectDialog.h"
#include "dialogs/NewComponentDialog.h"
-#include "dialogs/ModEditDialogCommon.h"
#include "dialogs/ProgressDialog.h"
#include <GuiUtil.h>
@@ -38,532 +39,574 @@
#include "minecraft/ComponentList.h"
#include "minecraft/auth/MojangAccountList.h"
-#include "minecraft/Mod.h"
+#include "minecraft/mod/Mod.h"
#include "icons/IconList.h"
#include "Exception.h"
-
-#include "MultiMC.h"
+#include "Version.h"
#include <meta/Index.h>
#include <meta/VersionList.h>
class IconProxy : public QIdentityProxyModel
{
- Q_OBJECT
+ Q_OBJECT
public:
- IconProxy(QWidget *parentWidget) : QIdentityProxyModel(parentWidget)
- {
- connect(parentWidget, &QObject::destroyed, this, &IconProxy::widgetGone);
- m_parentWidget = parentWidget;
- }
-
- virtual QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const override
- {
- QVariant var = QIdentityProxyModel::data(mapToSource(proxyIndex), role);
- int column = proxyIndex.column();
- if(column == 0 && role == Qt::DecorationRole && m_parentWidget)
- {
- if(!var.isNull())
- {
- auto string = var.toString();
- if(string == "warning")
- {
- return MMC->getThemedIcon("status-yellow");
- }
- else if(string == "error")
- {
- return MMC->getThemedIcon("status-bad");
- }
- }
- return MMC->getThemedIcon("status-good");
- }
- return var;
- }
+ IconProxy(QWidget *parentWidget) : QIdentityProxyModel(parentWidget)
+ {
+ connect(parentWidget, &QObject::destroyed, this, &IconProxy::widgetGone);
+ m_parentWidget = parentWidget;
+ }
+
+ virtual QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const override
+ {
+ QVariant var = QIdentityProxyModel::data(mapToSource(proxyIndex), role);
+ int column = proxyIndex.column();
+ if(column == 0 && role == Qt::DecorationRole && m_parentWidget)
+ {
+ if(!var.isNull())
+ {
+ auto string = var.toString();
+ if(string == "warning")
+ {
+ return MMC->getThemedIcon("status-yellow");
+ }
+ else if(string == "error")
+ {
+ return MMC->getThemedIcon("status-bad");
+ }
+ }
+ return MMC->getThemedIcon("status-good");
+ }
+ return var;
+ }
private slots:
- void widgetGone()
- {
- m_parentWidget = nullptr;
- }
+ void widgetGone()
+ {
+ m_parentWidget = nullptr;
+ }
private:
- QWidget *m_parentWidget = nullptr;
+ QWidget *m_parentWidget = nullptr;
};
QIcon VersionPage::icon() const
{
- return MMC->icons()->getIcon(m_inst->iconKey());
+ return MMC->icons()->getIcon(m_inst->iconKey());
}
bool VersionPage::shouldDisplay() const
{
- return !m_inst->isRunning();
+ return true;
+}
+
+QMenu * VersionPage::createPopupMenu()
+{
+ QMenu* filteredMenu = QMainWindow::createPopupMenu();
+ filteredMenu->removeAction( ui->toolBar->toggleViewAction() );
+ return filteredMenu;
}
VersionPage::VersionPage(MinecraftInstance *inst, QWidget *parent)
- : QWidget(parent), ui(new Ui::VersionPage), m_inst(inst)
-{
- ui->setupUi(this);
- ui->tabWidget->tabBar()->hide();
- m_profile = m_inst->getComponentList();
-
- reloadComponentList();
-
- if (m_profile)
- {
- auto proxy = new IconProxy(ui->packageView);
- proxy->setSourceModel(m_profile.get());
- ui->packageView->setModel(proxy);
- ui->packageView->installEventFilter(this);
- ui->packageView->setSelectionMode(QAbstractItemView::SingleSelection);
- connect(ui->packageView->selectionModel(), &QItemSelectionModel::currentChanged, this, &VersionPage::versionCurrent);
- auto smodel = ui->packageView->selectionModel();
- connect(smodel, &QItemSelectionModel::currentChanged, this, &VersionPage::packageCurrent);
- updateVersionControls();
- // select first item.
- preselect(0);
- }
- else
- {
- disableVersionControls();
- }
- connect(m_inst, &MinecraftInstance::versionReloaded, this,
- &VersionPage::updateVersionControls);
+ : QMainWindow(parent), ui(new Ui::VersionPage), m_inst(inst)
+{
+ ui->setupUi(this);
+
+ ui->toolBar->insertSpacer(ui->actionReload);
+
+ m_profile = m_inst->getComponentList();
+
+ reloadComponentList();
+
+ auto proxy = new IconProxy(ui->packageView);
+ proxy->setSourceModel(m_profile.get());
+ ui->packageView->setModel(proxy);
+ ui->packageView->installEventFilter(this);
+ ui->packageView->setSelectionMode(QAbstractItemView::SingleSelection);
+ ui->packageView->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ connect(ui->packageView->selectionModel(), &QItemSelectionModel::currentChanged, this, &VersionPage::versionCurrent);
+ auto smodel = ui->packageView->selectionModel();
+ connect(smodel, &QItemSelectionModel::currentChanged, this, &VersionPage::packageCurrent);
+
+ connect(m_profile.get(), &ComponentList::minecraftChanged, this, &VersionPage::updateVersionControls);
+ controlsEnabled = !m_inst->isRunning();
+ updateVersionControls();
+ preselect(0);
+ connect(m_inst, &BaseInstance::runningStatusChanged, this, &VersionPage::updateRunningStatus);
+ connect(ui->packageView, &ModListView::customContextMenuRequested, this, &VersionPage::ShowContextMenu);
}
VersionPage::~VersionPage()
{
- delete ui;
+ delete ui;
+}
+
+void VersionPage::ShowContextMenu(const QPoint& pos)
+{
+ auto menu = ui->toolBar->createContextMenu(this, tr("Context menu"));
+ menu->exec(ui->packageView->mapToGlobal(pos));
+ delete menu;
}
void VersionPage::packageCurrent(const QModelIndex &current, const QModelIndex &previous)
{
- if (!current.isValid())
- {
- ui->frame->clear();
- return;
- }
- int row = current.row();
- auto patch = m_profile->getComponent(row);
- auto severity = patch->getProblemSeverity();
- switch(severity)
- {
- case ProblemSeverity::Warning:
- ui->frame->setModText(tr("%1 possibly has issues.").arg(patch->getName()));
- break;
- case ProblemSeverity::Error:
- ui->frame->setModText(tr("%1 has issues!").arg(patch->getName()));
- break;
- default:
- case ProblemSeverity::None:
- ui->frame->clear();
- return;
- }
-
- auto &problems = patch->getProblems();
- QString problemOut;
- for (auto &problem: problems)
- {
- if(problem.m_severity == ProblemSeverity::Error)
- {
- problemOut += tr("Error: ");
- }
- else if(problem.m_severity == ProblemSeverity::Warning)
- {
- problemOut += tr("Warning: ");
- }
- problemOut += problem.m_description;
- problemOut += "\n";
- }
- ui->frame->setModDescription(problemOut);
+ if (!current.isValid())
+ {
+ ui->frame->clear();
+ return;
+ }
+ int row = current.row();
+ auto patch = m_profile->getComponent(row);
+ auto severity = patch->getProblemSeverity();
+ switch(severity)
+ {
+ case ProblemSeverity::Warning:
+ ui->frame->setModText(tr("%1 possibly has issues.").arg(patch->getName()));
+ break;
+ case ProblemSeverity::Error:
+ ui->frame->setModText(tr("%1 has issues!").arg(patch->getName()));
+ break;
+ default:
+ case ProblemSeverity::None:
+ ui->frame->clear();
+ return;
+ }
+
+ auto &problems = patch->getProblems();
+ QString problemOut;
+ for (auto &problem: problems)
+ {
+ if(problem.m_severity == ProblemSeverity::Error)
+ {
+ problemOut += tr("Error: ");
+ }
+ else if(problem.m_severity == ProblemSeverity::Warning)
+ {
+ problemOut += tr("Warning: ");
+ }
+ problemOut += problem.m_description;
+ problemOut += "\n";
+ }
+ ui->frame->setModDescription(problemOut);
}
+void VersionPage::updateRunningStatus(bool running)
+{
+ if(controlsEnabled == running) {
+ controlsEnabled = !running;
+ updateVersionControls();
+ }
+}
void VersionPage::updateVersionControls()
{
- ui->forgeBtn->setEnabled(true);
- ui->liteloaderBtn->setEnabled(true);
- updateButtons();
+ // FIXME: this is a dirty hack
+ auto minecraftVersion = Version(m_profile->getComponentVersion("net.minecraft"));
+ bool newCraft = controlsEnabled && (minecraftVersion >= Version("1.14"));
+ bool oldCraft = controlsEnabled && (minecraftVersion <= Version("1.12.2"));
+ ui->actionInstall_Fabric->setEnabled(newCraft);
+ ui->actionInstall_Forge->setEnabled(oldCraft);
+ ui->actionInstall_LiteLoader->setEnabled(oldCraft);
+ ui->actionReload->setEnabled(true);
+ updateButtons();
}
-void VersionPage::disableVersionControls()
+void VersionPage::updateButtons(int row)
{
- ui->forgeBtn->setEnabled(false);
- ui->liteloaderBtn->setEnabled(false);
- ui->reloadBtn->setEnabled(false);
- updateButtons();
+ if(row == -1)
+ row = currentRow();
+ auto patch = m_profile->getComponent(row);
+ ui->actionRemove->setEnabled(controlsEnabled && patch && patch->isRemovable());
+ ui->actionMove_down->setEnabled(controlsEnabled && patch && patch->isMoveable());
+ ui->actionMove_up->setEnabled(controlsEnabled && patch && patch->isMoveable());
+ ui->actionChange_version->setEnabled(controlsEnabled && patch && patch->isVersionChangeable());
+ ui->actionEdit->setEnabled(controlsEnabled && patch && patch->isCustom());
+ ui->actionCustomize->setEnabled(controlsEnabled && patch && patch->isCustomizable());
+ ui->actionRevert->setEnabled(controlsEnabled && patch && patch->isRevertible());
+ ui->actionDownload_All->setEnabled(controlsEnabled);
+ ui->actionAdd_Empty->setEnabled(controlsEnabled);
+ ui->actionReload->setEnabled(controlsEnabled);
+ ui->actionInstall_mods->setEnabled(controlsEnabled);
+ ui->actionReplace_Minecraft_jar->setEnabled(controlsEnabled);
+ ui->actionAdd_to_Minecraft_jar->setEnabled(controlsEnabled);
}
bool VersionPage::reloadComponentList()
{
- try
- {
- m_profile->reload(Net::Mode::Online);
- return true;
- }
- catch (Exception &e)
- {
- QMessageBox::critical(this, tr("Error"), e.cause());
- return false;
- }
- catch (...)
- {
- QMessageBox::critical(
- this, tr("Error"),
- tr("Couldn't load the instance profile."));
- return false;
- }
-}
-
-void VersionPage::on_reloadBtn_clicked()
-{
- reloadComponentList();
- m_container->refreshContainer();
-}
-
-void VersionPage::on_removeBtn_clicked()
-{
- if (ui->packageView->currentIndex().isValid())
- {
- // FIXME: use actual model, not reloading.
- if (!m_profile->remove(ui->packageView->currentIndex().row()))
- {
- QMessageBox::critical(this, tr("Error"), tr("Couldn't remove file"));
- }
- }
- updateButtons();
- reloadComponentList();
- m_container->refreshContainer();
-}
-
-void VersionPage::on_modBtn_clicked()
-{
- if(m_container)
- {
- m_container->selectPage("mods");
- }
-}
-
-void VersionPage::on_jarmodBtn_clicked()
-{
- auto list = GuiUtil::BrowseForFiles("jarmod", tr("Select jar mods"), tr("Minecraft.jar mods (*.zip *.jar)"), MMC->settings()->get("CentralModsDir").toString(), this->parentWidget());
- if(!list.empty())
- {
- m_profile->installJarMods(list);
- }
- updateButtons();
-}
-
-void VersionPage::on_jarBtn_clicked()
-{
- auto jarPath = GuiUtil::BrowseForFile("jar", tr("Select jar"), tr("Minecraft.jar replacement (*.jar)"), MMC->settings()->get("CentralModsDir").toString(), this->parentWidget());
- if(!jarPath.isEmpty())
- {
- m_profile->installCustomJar(jarPath);
- }
- updateButtons();
-}
-
-void VersionPage::on_moveUpBtn_clicked()
-{
- try
- {
- m_profile->move(currentRow(), ComponentList::MoveUp);
- }
- catch (Exception &e)
- {
- QMessageBox::critical(this, tr("Error"), e.cause());
- }
- updateButtons();
-}
-
-void VersionPage::on_moveDownBtn_clicked()
-{
- try
- {
- m_profile->move(currentRow(), ComponentList::MoveDown);
- }
- catch (Exception &e)
- {
- QMessageBox::critical(this, tr("Error"), e.cause());
- }
- updateButtons();
-}
-
-void VersionPage::on_changeVersionBtn_clicked()
-{
- auto versionRow = currentRow();
- if(versionRow == -1)
- {
- return;
- }
- auto patch = m_profile->getComponent(versionRow);
- auto name = patch->getName();
- auto list = patch->getVersionList();
- if(!list)
- {
- return;
- }
- auto uid = list->uid();
- // FIXME: this is a horrible HACK. Get version filtering information from the actual metadata...
- if(uid == "net.minecraftforge")
- {
- on_forgeBtn_clicked();
- return;
- }
- else if (uid == "com.mumfrey.liteloader")
- {
- on_liteloaderBtn_clicked();
- return;
- }
- VersionSelectDialog vselect(list.get(), tr("Change %1 version").arg(name), this);
- auto currentVersion = patch->getVersion();
- if(!currentVersion.isEmpty())
- {
- vselect.setCurrentVersion(currentVersion);
- }
- if (!vselect.exec() || !vselect.selectedVersion())
- return;
-
- qDebug() << "Change" << uid << "to" << vselect.selectedVersion()->descriptor();
- bool important = false;
- if(uid == "net.minecraft")
- {
- important = true;
- }
- m_profile->setComponentVersion(uid, vselect.selectedVersion()->descriptor(), important);
- m_profile->resolve(Net::Mode::Online);
- m_container->refreshContainer();
-}
-
-void VersionPage::on_downloadBtn_clicked()
-{
- 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;
- }
-
- auto updateTask = m_inst->createUpdateTask(Net::Mode::Online);
- if (!updateTask)
- {
- return;
- }
- ProgressDialog tDialog(this);
- connect(updateTask.get(), SIGNAL(failed(QString)), SLOT(onGameUpdateError(QString)));
- // FIXME: unused return value
- tDialog.execWithTask(updateTask.get());
- updateButtons();
- m_container->refreshContainer();
-}
-
-void VersionPage::on_forgeBtn_clicked()
-{
- auto vlist = ENV.metadataIndex()->get("net.minecraftforge");
- if(!vlist)
- {
- return;
- }
- VersionSelectDialog vselect(vlist.get(), tr("Select Forge version"), this);
- vselect.setExactFilter(BaseVersionList::ParentVersionRole, m_profile->getComponentVersion("net.minecraft"));
- vselect.setEmptyString(tr("No Forge versions are currently available for Minecraft ") + m_profile->getComponentVersion("net.minecraft"));
- vselect.setEmptyErrorString(tr("Couldn't load or download the Forge version lists!"));
-
- auto currentVersion = m_profile->getComponentVersion("net.minecraftforge");
- if(!currentVersion.isEmpty())
- {
- vselect.setCurrentVersion(currentVersion);
- }
-
- if (vselect.exec() && vselect.selectedVersion())
- {
- auto vsn = vselect.selectedVersion();
- m_profile->setComponentVersion("net.minecraftforge", vsn->descriptor());
- m_profile->resolve(Net::Mode::Online);
- // m_profile->installVersion();
- preselect(m_profile->rowCount(QModelIndex())-1);
- m_container->refreshContainer();
- }
-}
-
-void VersionPage::on_addEmptyBtn_clicked()
-{
- NewComponentDialog compdialog(QString(), QString(), this);
- QStringList blacklist;
- for(int i = 0; i < m_profile->rowCount(); i++)
- {
- auto comp = m_profile->getComponent(i);
- blacklist.push_back(comp->getID());
- }
- compdialog.setBlacklist(blacklist);
- if (compdialog.exec())
- {
- qDebug() << "name:" << compdialog.name();
- qDebug() << "uid:" << compdialog.uid();
- m_profile->installEmpty(compdialog.uid(), compdialog.name());
- }
-}
-
-void VersionPage::on_liteloaderBtn_clicked()
-{
- auto vlist = ENV.metadataIndex()->get("com.mumfrey.liteloader");
- if(!vlist)
- {
- return;
- }
- VersionSelectDialog vselect(vlist.get(), tr("Select LiteLoader version"), this);
- vselect.setExactFilter(BaseVersionList::ParentVersionRole, m_profile->getComponentVersion("net.minecraft"));
- vselect.setEmptyString(tr("No LiteLoader versions are currently available for Minecraft ") + m_profile->getComponentVersion("net.minecraft"));
- vselect.setEmptyErrorString(tr("Couldn't load or download the LiteLoader version lists!"));
-
- auto currentVersion = m_profile->getComponentVersion("com.mumfrey.liteloader");
- if(!currentVersion.isEmpty())
- {
- vselect.setCurrentVersion(currentVersion);
- }
-
- if (vselect.exec() && vselect.selectedVersion())
- {
- auto vsn = vselect.selectedVersion();
- m_profile->setComponentVersion("com.mumfrey.liteloader", vsn->descriptor());
- m_profile->resolve(Net::Mode::Online);
- // m_profile->installVersion(vselect.selectedVersion());
- preselect(m_profile->rowCount(QModelIndex())-1);
- m_container->refreshContainer();
- }
+ try
+ {
+ m_profile->reload(Net::Mode::Online);
+ return true;
+ }
+ catch (const Exception &e)
+ {
+ QMessageBox::critical(this, tr("Error"), e.cause());
+ return false;
+ }
+ catch (...)
+ {
+ QMessageBox::critical(
+ this, tr("Error"),
+ tr("Couldn't load the instance profile."));
+ return false;
+ }
}
-void VersionPage::versionCurrent(const QModelIndex &current, const QModelIndex &previous)
+void VersionPage::on_actionReload_triggered()
{
- currentIdx = current.row();
- updateButtons(currentIdx);
+ reloadComponentList();
+ m_container->refreshContainer();
}
-void VersionPage::preselect(int row)
+void VersionPage::on_actionRemove_triggered()
{
- if(row < 0)
- {
- row = 0;
- }
- if(row >= m_profile->rowCount(QModelIndex()))
- {
- row = m_profile->rowCount(QModelIndex()) - 1;
- }
- if(row < 0)
- {
- return;
- }
- auto model_index = m_profile->index(row);
- ui->packageView->selectionModel()->select(model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
- updateButtons(row);
+ if (ui->packageView->currentIndex().isValid())
+ {
+ // FIXME: use actual model, not reloading.
+ if (!m_profile->remove(ui->packageView->currentIndex().row()))
+ {
+ QMessageBox::critical(this, tr("Error"), tr("Couldn't remove file"));
+ }
+ }
+ updateButtons();
+ reloadComponentList();
+ m_container->refreshContainer();
}
-void VersionPage::updateButtons(int row)
+void VersionPage::on_actionInstall_mods_triggered()
+{
+ if(m_container)
+ {
+ m_container->selectPage("mods");
+ }
+}
+
+void VersionPage::on_actionAdd_to_Minecraft_jar_triggered()
+{
+ auto list = GuiUtil::BrowseForFiles("jarmod", tr("Select jar mods"), tr("Minecraft.jar mods (*.zip *.jar)"), MMC->settings()->get("CentralModsDir").toString(), this->parentWidget());
+ if(!list.empty())
+ {
+ m_profile->installJarMods(list);
+ }
+ updateButtons();
+}
+
+void VersionPage::on_actionReplace_Minecraft_jar_triggered()
+{
+ auto jarPath = GuiUtil::BrowseForFile("jar", tr("Select jar"), tr("Minecraft.jar replacement (*.jar)"), MMC->settings()->get("CentralModsDir").toString(), this->parentWidget());
+ if(!jarPath.isEmpty())
+ {
+ m_profile->installCustomJar(jarPath);
+ }
+ updateButtons();
+}
+
+void VersionPage::on_actionMove_up_triggered()
+{
+ try
+ {
+ m_profile->move(currentRow(), ComponentList::MoveUp);
+ }
+ catch (const Exception &e)
+ {
+ QMessageBox::critical(this, tr("Error"), e.cause());
+ }
+ updateButtons();
+}
+
+void VersionPage::on_actionMove_down_triggered()
+{
+ try
+ {
+ m_profile->move(currentRow(), ComponentList::MoveDown);
+ }
+ catch (const Exception &e)
+ {
+ QMessageBox::critical(this, tr("Error"), e.cause());
+ }
+ updateButtons();
+}
+
+void VersionPage::on_actionChange_version_triggered()
+{
+ auto versionRow = currentRow();
+ if(versionRow == -1)
+ {
+ return;
+ }
+ auto patch = m_profile->getComponent(versionRow);
+ auto name = patch->getName();
+ auto list = patch->getVersionList();
+ if(!list)
+ {
+ return;
+ }
+ auto uid = list->uid();
+ // FIXME: this is a horrible HACK. Get version filtering information from the actual metadata...
+ if(uid == "net.minecraftforge")
+ {
+ on_actionInstall_Forge_triggered();
+ return;
+ }
+ else if (uid == "com.mumfrey.liteloader")
+ {
+ on_actionInstall_LiteLoader_triggered();
+ return;
+ }
+ VersionSelectDialog vselect(list.get(), tr("Change %1 version").arg(name), this);
+ if (uid == "net.fabricmc.intermediary")
+ {
+ vselect.setEmptyString(tr("No Fabric Loader versions are currently available."));
+ vselect.setEmptyErrorString(tr("Couldn't load or download the Fabric Loader version lists!"));
+ vselect.setExactFilter(BaseVersionList::ParentVersionRole, m_profile->getComponentVersion("net.minecraft"));
+ }
+ auto currentVersion = patch->getVersion();
+ if(!currentVersion.isEmpty())
+ {
+ vselect.setCurrentVersion(currentVersion);
+ }
+ if (!vselect.exec() || !vselect.selectedVersion())
+ return;
+
+ qDebug() << "Change" << uid << "to" << vselect.selectedVersion()->descriptor();
+ bool important = false;
+ if(uid == "net.minecraft")
+ {
+ important = true;
+ }
+ m_profile->setComponentVersion(uid, vselect.selectedVersion()->descriptor(), important);
+ m_profile->resolve(Net::Mode::Online);
+ m_container->refreshContainer();
+}
+
+void VersionPage::on_actionDownload_triggered()
+{
+ 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;
+ }
+
+ auto updateTask = m_inst->createUpdateTask(Net::Mode::Online);
+ if (!updateTask)
+ {
+ return;
+ }
+ ProgressDialog tDialog(this);
+ connect(updateTask.get(), SIGNAL(failed(QString)), SLOT(onGameUpdateError(QString)));
+ // FIXME: unused return value
+ tDialog.execWithTask(updateTask.get());
+ updateButtons();
+ m_container->refreshContainer();
+}
+
+void VersionPage::on_actionInstall_Forge_triggered()
+{
+ auto vlist = ENV.metadataIndex()->get("net.minecraftforge");
+ if(!vlist)
+ {
+ return;
+ }
+ VersionSelectDialog vselect(vlist.get(), tr("Select Forge version"), this);
+ vselect.setExactFilter(BaseVersionList::ParentVersionRole, m_profile->getComponentVersion("net.minecraft"));
+ vselect.setEmptyString(tr("No Forge versions are currently available for Minecraft ") + m_profile->getComponentVersion("net.minecraft"));
+ vselect.setEmptyErrorString(tr("Couldn't load or download the Forge version lists!"));
+
+ auto currentVersion = m_profile->getComponentVersion("net.minecraftforge");
+ if(!currentVersion.isEmpty())
+ {
+ vselect.setCurrentVersion(currentVersion);
+ }
+
+ if (vselect.exec() && vselect.selectedVersion())
+ {
+ auto vsn = vselect.selectedVersion();
+ m_profile->setComponentVersion("net.minecraftforge", vsn->descriptor());
+ m_profile->resolve(Net::Mode::Online);
+ // m_profile->installVersion();
+ preselect(m_profile->rowCount(QModelIndex())-1);
+ m_container->refreshContainer();
+ }
+}
+
+void VersionPage::on_actionInstall_Fabric_triggered()
+{
+ auto vlist = ENV.metadataIndex()->get("net.fabricmc.fabric-loader");
+ if(!vlist)
+ {
+ return;
+ }
+ VersionSelectDialog vselect(vlist.get(), tr("Select Fabric Loader version"), this);
+ vselect.setEmptyString(tr("No Fabric Loader versions are currently available."));
+ vselect.setEmptyErrorString(tr("Couldn't load or download the Fabric Loader version lists!"));
+
+ auto currentVersion = m_profile->getComponentVersion("net.fabricmc.fabric-loader");
+ if(!currentVersion.isEmpty())
+ {
+ vselect.setCurrentVersion(currentVersion);
+ }
+
+ if (vselect.exec() && vselect.selectedVersion())
+ {
+ auto vsn = vselect.selectedVersion();
+ m_profile->setComponentVersion("net.fabricmc.fabric-loader", vsn->descriptor());
+ m_profile->resolve(Net::Mode::Online);
+ preselect(m_profile->rowCount(QModelIndex())-1);
+ m_container->refreshContainer();
+ }
+}
+
+void VersionPage::on_actionAdd_Empty_triggered()
+{
+ NewComponentDialog compdialog(QString(), QString(), this);
+ QStringList blacklist;
+ for(int i = 0; i < m_profile->rowCount(); i++)
+ {
+ auto comp = m_profile->getComponent(i);
+ blacklist.push_back(comp->getID());
+ }
+ compdialog.setBlacklist(blacklist);
+ if (compdialog.exec())
+ {
+ qDebug() << "name:" << compdialog.name();
+ qDebug() << "uid:" << compdialog.uid();
+ m_profile->installEmpty(compdialog.uid(), compdialog.name());
+ }
+}
+
+void VersionPage::on_actionInstall_LiteLoader_triggered()
{
- if(row == -1)
- row = currentRow();
- auto patch = m_profile->getComponent(row);
- if (!patch)
- {
- ui->removeBtn->setDisabled(true);
- ui->moveDownBtn->setDisabled(true);
- ui->moveUpBtn->setDisabled(true);
- ui->changeVersionBtn->setDisabled(true);
- ui->editBtn->setDisabled(true);
- ui->customizeBtn->setDisabled(true);
- ui->revertBtn->setDisabled(true);
- }
- else
- {
- ui->removeBtn->setEnabled(patch->isRemovable());
- ui->moveDownBtn->setEnabled(patch->isMoveable());
- ui->moveUpBtn->setEnabled(patch->isMoveable());
- ui->changeVersionBtn->setEnabled(patch->isVersionChangeable());
- ui->editBtn->setEnabled(patch->isCustom());
- ui->customizeBtn->setEnabled(patch->isCustomizable());
- ui->revertBtn->setEnabled(patch->isRevertible());
- }
+ auto vlist = ENV.metadataIndex()->get("com.mumfrey.liteloader");
+ if(!vlist)
+ {
+ return;
+ }
+ VersionSelectDialog vselect(vlist.get(), tr("Select LiteLoader version"), this);
+ vselect.setExactFilter(BaseVersionList::ParentVersionRole, m_profile->getComponentVersion("net.minecraft"));
+ vselect.setEmptyString(tr("No LiteLoader versions are currently available for Minecraft ") + m_profile->getComponentVersion("net.minecraft"));
+ vselect.setEmptyErrorString(tr("Couldn't load or download the LiteLoader version lists!"));
+
+ auto currentVersion = m_profile->getComponentVersion("com.mumfrey.liteloader");
+ if(!currentVersion.isEmpty())
+ {
+ vselect.setCurrentVersion(currentVersion);
+ }
+
+ if (vselect.exec() && vselect.selectedVersion())
+ {
+ auto vsn = vselect.selectedVersion();
+ m_profile->setComponentVersion("com.mumfrey.liteloader", vsn->descriptor());
+ m_profile->resolve(Net::Mode::Online);
+ // m_profile->installVersion(vselect.selectedVersion());
+ preselect(m_profile->rowCount(QModelIndex())-1);
+ m_container->refreshContainer();
+ }
+}
+
+void VersionPage::versionCurrent(const QModelIndex &current, const QModelIndex &previous)
+{
+ currentIdx = current.row();
+ updateButtons(currentIdx);
+}
+
+void VersionPage::preselect(int row)
+{
+ if(row < 0)
+ {
+ row = 0;
+ }
+ if(row >= m_profile->rowCount(QModelIndex()))
+ {
+ row = m_profile->rowCount(QModelIndex()) - 1;
+ }
+ if(row < 0)
+ {
+ return;
+ }
+ auto model_index = m_profile->index(row);
+ ui->packageView->selectionModel()->select(model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
+ updateButtons(row);
}
void VersionPage::onGameUpdateError(QString error)
{
- CustomMessageBox::selectable(this, tr("Error updating instance"), error,
- QMessageBox::Warning)->show();
+ CustomMessageBox::selectable(this, tr("Error updating instance"), error, QMessageBox::Warning)->show();
}
Component * VersionPage::current()
{
- auto row = currentRow();
- if(row < 0)
- {
- return nullptr;
- }
- return m_profile->getComponent(row);
+ auto row = currentRow();
+ if(row < 0)
+ {
+ return nullptr;
+ }
+ return m_profile->getComponent(row);
}
int VersionPage::currentRow()
{
- if (ui->packageView->selectionModel()->selectedRows().isEmpty())
- {
- return -1;
- }
- return ui->packageView->selectionModel()->selectedRows().first().row();
-}
-
-void VersionPage::on_customizeBtn_clicked()
-{
- auto version = currentRow();
- if(version == -1)
- {
- return;
- }
- auto patch = m_profile->getComponent(version);
- if(!patch->getVersionFile())
- {
- // TODO: wait for the update task to finish here...
- return;
- }
- if(!m_profile->customize(version))
- {
- // TODO: some error box here
- }
- updateButtons();
- preselect(currentIdx);
-}
-
-void VersionPage::on_editBtn_clicked()
-{
- auto version = current();
- if(!version)
- {
- return;
- }
- auto filename = version->getFilename();
- if(!QFileInfo::exists(filename))
- {
- qWarning() << "file" << filename << "can't be opened for editing, doesn't exist!";
- return;
- }
- MMC->openJsonEditor(filename);
-}
-
-void VersionPage::on_revertBtn_clicked()
-{
- auto version = currentRow();
- if(version == -1)
- {
- return;
- }
- if(!m_profile->revertToBase(version))
- {
- // TODO: some error box here
- }
- updateButtons();
- preselect(currentIdx);
- m_container->refreshContainer();
+ if (ui->packageView->selectionModel()->selectedRows().isEmpty())
+ {
+ return -1;
+ }
+ return ui->packageView->selectionModel()->selectedRows().first().row();
+}
+
+void VersionPage::on_actionCustomize_triggered()
+{
+ auto version = currentRow();
+ if(version == -1)
+ {
+ return;
+ }
+ auto patch = m_profile->getComponent(version);
+ if(!patch->getVersionFile())
+ {
+ // TODO: wait for the update task to finish here...
+ return;
+ }
+ if(!m_profile->customize(version))
+ {
+ // TODO: some error box here
+ }
+ updateButtons();
+ preselect(currentIdx);
+}
+
+void VersionPage::on_actionEdit_triggered()
+{
+ auto version = current();
+ if(!version)
+ {
+ return;
+ }
+ auto filename = version->getFilename();
+ if(!QFileInfo::exists(filename))
+ {
+ qWarning() << "file" << filename << "can't be opened for editing, doesn't exist!";
+ return;
+ }
+ MMC->openJsonEditor(filename);
+}
+
+void VersionPage::on_actionRevert_triggered()
+{
+ auto version = currentRow();
+ if(version == -1)
+ {
+ return;
+ }
+ if(!m_profile->revertToBase(version))
+ {
+ // TODO: some error box here
+ }
+ updateButtons();
+ preselect(currentIdx);
+ m_container->refreshContainer();
}
#include "VersionPage.moc"
diff --git a/application/pages/instance/VersionPage.h b/application/pages/instance/VersionPage.h
index 85304ea5..31344eb9 100644
--- a/application/pages/instance/VersionPage.h
+++ b/application/pages/instance/VersionPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 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,7 +15,7 @@
#pragma once
-#include <QWidget>
+#include <QMainWindow>
#include "minecraft/MinecraftInstance.h"
#include "minecraft/ComponentList.h"
@@ -26,70 +26,74 @@ namespace Ui
class VersionPage;
}
-class VersionPage : public QWidget, public BasePage
+class VersionPage : public QMainWindow, public BasePage
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit VersionPage(MinecraftInstance *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 override;
+ explicit VersionPage(MinecraftInstance *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 override;
private slots:
- void on_forgeBtn_clicked();
- void on_addEmptyBtn_clicked();
- void on_liteloaderBtn_clicked();
- void on_reloadBtn_clicked();
- void on_removeBtn_clicked();
- void on_moveUpBtn_clicked();
- void on_moveDownBtn_clicked();
- void on_jarmodBtn_clicked();
- void on_jarBtn_clicked();
- void on_revertBtn_clicked();
- void on_editBtn_clicked();
- void on_modBtn_clicked();
- void on_customizeBtn_clicked();
- void on_downloadBtn_clicked();
+ void on_actionChange_version_triggered();
+ void on_actionInstall_Forge_triggered();
+ void on_actionInstall_Fabric_triggered();
+ void on_actionAdd_Empty_triggered();
+ void on_actionInstall_LiteLoader_triggered();
+ void on_actionReload_triggered();
+ void on_actionRemove_triggered();
+ void on_actionMove_up_triggered();
+ void on_actionMove_down_triggered();
+ void on_actionAdd_to_Minecraft_jar_triggered();
+ void on_actionReplace_Minecraft_jar_triggered();
+ void on_actionRevert_triggered();
+ void on_actionEdit_triggered();
+ void on_actionInstall_mods_triggered();
+ void on_actionCustomize_triggered();
+ void on_actionDownload_triggered();
- void updateVersionControls();
- void disableVersionControls();
- void on_changeVersionBtn_clicked();
+ void updateVersionControls();
private:
- Component * current();
- int currentRow();
- void updateButtons(int row = -1);
- void preselect(int row = 0);
- int doUpdate();
+ Component * current();
+ int currentRow();
+ void updateButtons(int row = -1);
+ void preselect(int row = 0);
+ int doUpdate();
protected:
- /// FIXME: this shouldn't be necessary!
- bool reloadComponentList();
+ QMenu * createPopupMenu() override;
+
+ /// FIXME: this shouldn't be necessary!
+ bool reloadComponentList();
private:
- Ui::VersionPage *ui;
- std::shared_ptr<ComponentList> m_profile;
- MinecraftInstance *m_inst;
- int currentIdx = 0;
+ Ui::VersionPage *ui;
+ std::shared_ptr<ComponentList> m_profile;
+ MinecraftInstance *m_inst;
+ int currentIdx = 0;
+ bool controlsEnabled = false;
public slots:
- void versionCurrent(const QModelIndex &current, const QModelIndex &previous);
+ void versionCurrent(const QModelIndex &current, const QModelIndex &previous);
private slots:
- void onGameUpdateError(QString error);
- void packageCurrent(const QModelIndex &current, const QModelIndex &previous);
-
+ void updateRunningStatus(bool running);
+ void onGameUpdateError(QString error);
+ void packageCurrent(const QModelIndex &current, const QModelIndex &previous);
+ void ShowContextMenu(const QPoint &pos);
};
diff --git a/application/pages/instance/VersionPage.ui b/application/pages/instance/VersionPage.ui
index d54dd840..e16f18bc 100644
--- a/application/pages/instance/VersionPage.ui
+++ b/application/pages/instance/VersionPage.ui
@@ -1,279 +1,231 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>VersionPage</class>
- <widget class="QWidget" name="VersionPage">
+ <widget class="QMainWindow" name="VersionPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
- <width>870</width>
- <height>1008</height>
+ <width>961</width>
+ <height>1091</height>
</rect>
</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="tabWidget">
- <property name="currentIndex">
- <number>0</number>
- </property>
- <widget class="QWidget" name="tab">
- <attribute name="title">
- <string notr="true">Tab 1</string>
- </attribute>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0">
- <widget class="ModListView" name="packageView">
- <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>
- <item row="0" column="1">
- <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="changeVersionBtn">
- <property name="toolTip">
- <string>Change version of the selected package.</string>
- </property>
- <property name="text">
- <string>Change version</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="moveUpBtn">
- <property name="toolTip">
- <string>Make the selected package apply sooner.</string>
- </property>
- <property name="text">
- <string>Move up</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="moveDownBtn">
- <property name="toolTip">
- <string>Make the selected package apply later.</string>
- </property>
- <property name="text">
- <string>Move down</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="removeBtn">
- <property name="toolTip">
- <string>Remove selected package from the instance.</string>
- </property>
- <property name="text">
- <string>Remove</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="LineSeparator" name="separator_4" native="true"/>
- </item>
- <item>
- <widget class="QLabel" name="label_10">
- <property name="text">
- <string>Edit</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="customizeBtn">
- <property name="toolTip">
- <string>Customize selected package.</string>
- </property>
- <property name="text">
- <string>Customize</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="editBtn">
- <property name="toolTip">
- <string>Edit selected package.</string>
- </property>
- <property name="text">
- <string>Edit</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="revertBtn">
- <property name="toolTip">
- <string>Revert the selected package to default.</string>
- </property>
- <property name="text">
- <string>Revert</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>Install the Minecraft Forge package.</string>
- </property>
- <property name="text">
- <string>Install Forge</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="liteloaderBtn">
- <property name="toolTip">
- <string>Install the LiteLoader package.</string>
- </property>
- <property name="text">
- <string>Install LiteLoader</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="modBtn">
- <property name="toolTip">
- <string>Install normal mods.</string>
- </property>
- <property name="text">
- <string>Install mods</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="LineSeparator" name="widget" native="true"/>
- </item>
- <item>
- <widget class="QLabel" name="label_5">
- <property name="text">
- <string>Advanced</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="jarmodBtn">
- <property name="toolTip">
- <string>Add a mod into the Minecraft jar file.</string>
- </property>
- <property name="text">
- <string>Add to Minecraft.jar</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="jarBtn">
- <property name="text">
- <string>Replace Minecraft.jar</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="addEmptyBtn">
- <property name="text">
- <string>Add Empty</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="reloadBtn">
- <property name="toolTip">
- <string>Reload all packages.</string>
- </property>
- <property name="text">
- <string>Reload</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="downloadBtn">
- <property name="toolTip">
- <string>Download the files needed to launch the instance now.</string>
- </property>
- <property name="text">
- <string>Download All</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer_7">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>111</width>
- <height>13</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
- <item row="1" column="0" colspan="2">
- <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>
- </item>
- </layout>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <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>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="ModListView" name="packageView">
+ <property name="verticalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOn</enum>
+ </property>
+ <property name="horizontalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOff</enum>
+ </property>
+ <property name="sortingEnabled">
+ <bool>false</bool>
+ </property>
+ <property name="headerHidden">
+ <bool>false</bool>
+ </property>
+ <attribute name="headerVisible">
+ <bool>true</bool>
+ </attribute>
+ </widget>
+ </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>
+ </item>
+ </layout>
+ </widget>
+ <widget class="WideBar" name="toolBar">
+ <property name="windowTitle">
+ <string>toolBar</string>
+ </property>
+ <property name="allowedAreas">
+ <set>Qt::LeftToolBarArea|Qt::RightToolBarArea</set>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextOnly</enum>
+ </property>
+ <property name="floatable">
+ <bool>false</bool>
+ </property>
+ <attribute name="toolBarArea">
+ <enum>RightToolBarArea</enum>
+ </attribute>
+ <attribute name="toolBarBreak">
+ <bool>false</bool>
+ </attribute>
+ <addaction name="actionChange_version"/>
+ <addaction name="actionMove_up"/>
+ <addaction name="actionMove_down"/>
+ <addaction name="actionRemove"/>
+ <addaction name="separator"/>
+ <addaction name="actionCustomize"/>
+ <addaction name="actionEdit"/>
+ <addaction name="actionRevert"/>
+ <addaction name="separator"/>
+ <addaction name="actionInstall_Forge"/>
+ <addaction name="actionInstall_Fabric"/>
+ <addaction name="actionInstall_LiteLoader"/>
+ <addaction name="actionInstall_mods"/>
+ <addaction name="separator"/>
+ <addaction name="actionAdd_to_Minecraft_jar"/>
+ <addaction name="actionReplace_Minecraft_jar"/>
+ <addaction name="actionAdd_Empty"/>
+ <addaction name="actionReload"/>
+ <addaction name="actionDownload_All"/>
+ </widget>
+ <action name="actionChange_version">
+ <property name="text">
+ <string>Change version</string>
+ </property>
+ <property name="toolTip">
+ <string>Change version of the selected package.</string>
+ </property>
+ </action>
+ <action name="actionMove_up">
+ <property name="text">
+ <string>Move up</string>
+ </property>
+ <property name="toolTip">
+ <string>Make the selected package apply sooner.</string>
+ </property>
+ </action>
+ <action name="actionMove_down">
+ <property name="text">
+ <string>Move down</string>
+ </property>
+ <property name="toolTip">
+ <string>Make the selected package apply later.</string>
+ </property>
+ </action>
+ <action name="actionRemove">
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ <property name="toolTip">
+ <string>Remove selected package from the instance.</string>
+ </property>
+ </action>
+ <action name="actionCustomize">
+ <property name="text">
+ <string>Customize</string>
+ </property>
+ <property name="toolTip">
+ <string>Customize selected package.</string>
+ </property>
+ </action>
+ <action name="actionEdit">
+ <property name="text">
+ <string>Edit</string>
+ </property>
+ <property name="toolTip">
+ <string>Edit selected package.</string>
+ </property>
+ </action>
+ <action name="actionRevert">
+ <property name="text">
+ <string>Revert</string>
+ </property>
+ <property name="toolTip">
+ <string>Revert the selected package to default.</string>
+ </property>
+ </action>
+ <action name="actionInstall_Forge">
+ <property name="text">
+ <string>Install Forge</string>
+ </property>
+ <property name="toolTip">
+ <string>Install the Minecraft Forge package.</string>
+ </property>
+ </action>
+ <action name="actionInstall_Fabric">
+ <property name="text">
+ <string>Install Fabric</string>
+ </property>
+ <property name="toolTip">
+ <string>Install the Fabric Loader package.</string>
+ </property>
+ </action>
+ <action name="actionInstall_LiteLoader">
+ <property name="text">
+ <string>Install LiteLoader</string>
+ </property>
+ <property name="toolTip">
+ <string>Install the LiteLoader package.</string>
+ </property>
+ </action>
+ <action name="actionInstall_mods">
+ <property name="text">
+ <string>Install mods</string>
+ </property>
+ <property name="toolTip">
+ <string>Install normal mods.</string>
+ </property>
+ </action>
+ <action name="actionAdd_to_Minecraft_jar">
+ <property name="text">
+ <string>Add to Minecraft.jar</string>
+ </property>
+ <property name="toolTip">
+ <string>Add a mod into the Minecraft jar file.</string>
+ </property>
+ </action>
+ <action name="actionReplace_Minecraft_jar">
+ <property name="text">
+ <string>Replace Minecraft.jar</string>
+ </property>
+ </action>
+ <action name="actionAdd_Empty">
+ <property name="text">
+ <string>Add Empty</string>
+ </property>
+ <property name="toolTip">
+ <string>Add an empty custom package.</string>
+ </property>
+ </action>
+ <action name="actionReload">
+ <property name="text">
+ <string>Reload</string>
+ </property>
+ <property name="toolTip">
+ <string>Reload all packages.</string>
+ </property>
+ </action>
+ <action name="actionDownload_All">
+ <property name="text">
+ <string>Download All</string>
+ </property>
+ <property name="toolTip">
+ <string>Download the files needed to launch the instance now.</string>
+ </property>
+ </action>
</widget>
<customwidgets>
<customwidget>
@@ -282,37 +234,17 @@
<header>widgets/ModListView.h</header>
</customwidget>
<customwidget>
- <class>LineSeparator</class>
- <extends>QWidget</extends>
- <header>widgets/LineSeparator.h</header>
- <container>1</container>
- </customwidget>
- <customwidget>
<class>MCModInfoFrame</class>
<extends>QFrame</extends>
<header>widgets/MCModInfoFrame.h</header>
<container>1</container>
</customwidget>
+ <customwidget>
+ <class>WideBar</class>
+ <extends>QToolBar</extends>
+ <header>widgets/WideBar.h</header>
+ </customwidget>
</customwidgets>
- <tabstops>
- <tabstop>packageView</tabstop>
- <tabstop>changeVersionBtn</tabstop>
- <tabstop>moveUpBtn</tabstop>
- <tabstop>moveDownBtn</tabstop>
- <tabstop>removeBtn</tabstop>
- <tabstop>customizeBtn</tabstop>
- <tabstop>editBtn</tabstop>
- <tabstop>revertBtn</tabstop>
- <tabstop>forgeBtn</tabstop>
- <tabstop>liteloaderBtn</tabstop>
- <tabstop>modBtn</tabstop>
- <tabstop>jarmodBtn</tabstop>
- <tabstop>jarBtn</tabstop>
- <tabstop>addEmptyBtn</tabstop>
- <tabstop>reloadBtn</tabstop>
- <tabstop>downloadBtn</tabstop>
- <tabstop>tabWidget</tabstop>
- </tabstops>
<resources/>
<connections/>
</ui>
diff --git a/application/pages/instance/WorldListPage.cpp b/application/pages/instance/WorldListPage.cpp
index 539d26a0..8358a0f1 100644
--- a/application/pages/instance/WorldListPage.cpp
+++ b/application/pages/instance/WorldListPage.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2015-2018 MultiMC Contributors
+/* Copyright 2015-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,8 +17,8 @@
#include "ui_WorldListPage.h"
#include "minecraft/WorldList.h"
#include <DesktopServices.h>
-#include "dialogs/ModEditDialogCommon.h"
#include <QEvent>
+#include <QMenu>
#include <QKeyEvent>
#include <QClipboard>
#include <QMessageBox>
@@ -31,300 +31,314 @@
#include <QProcess>
#include <FileSystem.h>
-WorldListPage::WorldListPage(BaseInstance *inst, std::shared_ptr<WorldList> worlds, QString id,
- QString iconName, QString displayName, QString helpPage,
- QWidget *parent)
- : QWidget(parent), m_inst(inst), ui(new Ui::WorldListPage), m_worlds(worlds), m_iconName(iconName), m_id(id), m_displayName(displayName), m_helpName(helpPage)
+WorldListPage::WorldListPage(BaseInstance *inst, std::shared_ptr<WorldList> worlds, QWidget *parent)
+ : QMainWindow(parent), m_inst(inst), ui(new Ui::WorldListPage), m_worlds(worlds)
{
- ui->setupUi(this);
- ui->tabWidget->tabBar()->hide();
- QSortFilterProxyModel * proxy = new QSortFilterProxyModel(this);
- proxy->setSortCaseSensitivity(Qt::CaseInsensitive);
- proxy->setSourceModel(m_worlds.get());
- ui->worldTreeView->setSortingEnabled(true);
- ui->worldTreeView->setModel(proxy);
- ui->worldTreeView->installEventFilter(this);
-
- auto head = ui->worldTreeView->header();
-
- head->setSectionResizeMode(0, QHeaderView::Stretch);
- head->setSectionResizeMode(1, QHeaderView::ResizeToContents);
- connect(ui->worldTreeView->selectionModel(),
- SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), this,
- SLOT(worldChanged(const QModelIndex &, const QModelIndex &)));
- worldChanged(QModelIndex(), QModelIndex());
+ ui->setupUi(this);
+
+ ui->toolBar->insertSpacer(ui->actionRefresh);
+
+ QSortFilterProxyModel * proxy = new QSortFilterProxyModel(this);
+ proxy->setSortCaseSensitivity(Qt::CaseInsensitive);
+ proxy->setSourceModel(m_worlds.get());
+ ui->worldTreeView->setSortingEnabled(true);
+ ui->worldTreeView->setModel(proxy);
+ ui->worldTreeView->installEventFilter(this);
+ ui->worldTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(ui->worldTreeView, &QTreeView::customContextMenuRequested, this, &WorldListPage::ShowContextMenu);
+
+ auto head = ui->worldTreeView->header();
+ head->setSectionResizeMode(0, QHeaderView::Stretch);
+ head->setSectionResizeMode(1, QHeaderView::ResizeToContents);
+
+ connect(ui->worldTreeView->selectionModel(), &QItemSelectionModel::currentChanged, this, &WorldListPage::worldChanged);
+ worldChanged(QModelIndex(), QModelIndex());
}
void WorldListPage::openedImpl()
{
- m_worlds->startWatching();
+ m_worlds->startWatching();
}
void WorldListPage::closedImpl()
{
- m_worlds->stopWatching();
+ m_worlds->stopWatching();
}
WorldListPage::~WorldListPage()
{
- m_worlds->stopWatching();
- delete ui;
+ m_worlds->stopWatching();
+ delete ui;
+}
+
+void WorldListPage::ShowContextMenu(const QPoint& pos)
+{
+ auto menu = ui->toolBar->createContextMenu(this, tr("Context menu"));
+ menu->exec(ui->worldTreeView->mapToGlobal(pos));
+ delete menu;
+}
+
+QMenu * WorldListPage::createPopupMenu()
+{
+ QMenu* filteredMenu = QMainWindow::createPopupMenu();
+ filteredMenu->removeAction( ui->toolBar->toggleViewAction() );
+ return filteredMenu;
}
bool WorldListPage::shouldDisplay() const
{
- return true;
+ return true;
}
bool WorldListPage::worldListFilter(QKeyEvent *keyEvent)
{
- switch (keyEvent->key())
- {
- case Qt::Key_Delete:
- on_rmWorldBtn_clicked();
- return true;
- default:
- break;
- }
- return QWidget::eventFilter(ui->worldTreeView, keyEvent);
+ switch (keyEvent->key())
+ {
+ case Qt::Key_Delete:
+ on_actionRemove_triggered();
+ return true;
+ default:
+ break;
+ }
+ return QWidget::eventFilter(ui->worldTreeView, keyEvent);
}
bool WorldListPage::eventFilter(QObject *obj, QEvent *ev)
{
- if (ev->type() != QEvent::KeyPress)
- {
- return QWidget::eventFilter(obj, ev);
- }
- QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
- if (obj == ui->worldTreeView)
- return worldListFilter(keyEvent);
- return QWidget::eventFilter(obj, ev);
+ if (ev->type() != QEvent::KeyPress)
+ {
+ return QWidget::eventFilter(obj, ev);
+ }
+ QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
+ if (obj == ui->worldTreeView)
+ return worldListFilter(keyEvent);
+ return QWidget::eventFilter(obj, ev);
}
-void WorldListPage::on_rmWorldBtn_clicked()
+void WorldListPage::on_actionRemove_triggered()
{
- auto proxiedIndex = getSelectedWorld();
-
- if(!proxiedIndex.isValid())
- return;
-
- auto result = QMessageBox::question(this,
- tr("Are you sure?"),
- tr("This will remove the selected world permenantly.\n"
- "The world will be gone forever (A LONG TIME).\n"
- "\n"
- "Do you want to continue?"));
- if(result != QMessageBox::Yes)
- {
- return;
- }
- m_worlds->stopWatching();
- m_worlds->deleteWorld(proxiedIndex.row());
- m_worlds->startWatching();
+ auto proxiedIndex = getSelectedWorld();
+
+ if(!proxiedIndex.isValid())
+ return;
+
+ auto result = QMessageBox::question(this,
+ tr("Are you sure?"),
+ tr("This will remove the selected world permenantly.\n"
+ "The world will be gone forever (A LONG TIME).\n"
+ "\n"
+ "Do you want to continue?"));
+ if(result != QMessageBox::Yes)
+ {
+ return;
+ }
+ m_worlds->stopWatching();
+ m_worlds->deleteWorld(proxiedIndex.row());
+ m_worlds->startWatching();
}
-void WorldListPage::on_viewFolderBtn_clicked()
+void WorldListPage::on_actionView_Folder_triggered()
{
- DesktopServices::openDirectory(m_worlds->dir().absolutePath(), true);
+ DesktopServices::openDirectory(m_worlds->dir().absolutePath(), true);
}
QModelIndex WorldListPage::getSelectedWorld()
{
- auto index = ui->worldTreeView->selectionModel()->currentIndex();
+ auto index = ui->worldTreeView->selectionModel()->currentIndex();
- auto proxy = (QSortFilterProxyModel *) ui->worldTreeView->model();
- return proxy->mapToSource(index);
+ auto proxy = (QSortFilterProxyModel *) ui->worldTreeView->model();
+ return proxy->mapToSource(index);
}
-void WorldListPage::on_copySeedBtn_clicked()
+void WorldListPage::on_actionCopy_Seed_triggered()
{
- QModelIndex index = getSelectedWorld();
-
- if (!index.isValid())
- {
- return;
- }
- int64_t seed = m_worlds->data(index, WorldList::SeedRole).toLongLong();
- MMC->clipboard()->setText(QString::number(seed));
+ QModelIndex index = getSelectedWorld();
+
+ if (!index.isValid())
+ {
+ return;
+ }
+ int64_t seed = m_worlds->data(index, WorldList::SeedRole).toLongLong();
+ MMC->clipboard()->setText(QString::number(seed));
}
-void WorldListPage::on_mcEditBtn_clicked()
+void WorldListPage::on_actionMCEdit_triggered()
{
- if(m_mceditStarting)
- return;
+ if(m_mceditStarting)
+ return;
- auto mcedit = MMC->mcedit();
+ auto mcedit = MMC->mcedit();
- const QString mceditPath = mcedit->path();
+ const QString mceditPath = mcedit->path();
- QModelIndex index = getSelectedWorld();
+ QModelIndex index = getSelectedWorld();
- if (!index.isValid())
- {
- return;
- }
+ if (!index.isValid())
+ {
+ return;
+ }
- if(!worldSafetyNagQuestion())
- return;
+ if(!worldSafetyNagQuestion())
+ return;
- auto fullPath = m_worlds->data(index, WorldList::FolderRole).toString();
+ auto fullPath = m_worlds->data(index, WorldList::FolderRole).toString();
- auto program = mcedit->getProgramPath();
- if(program.size())
- {
+ auto program = mcedit->getProgramPath();
+ if(program.size())
+ {
#ifdef Q_OS_WIN32
- if(!QProcess::startDetached(program, {fullPath}, mceditPath))
- {
- mceditError();
- }
+ if(!QProcess::startDetached(program, {fullPath}, mceditPath))
+ {
+ mceditError();
+ }
#else
- m_mceditProcess.reset(new LoggedProcess());
- m_mceditProcess->setDetachable(true);
- connect(m_mceditProcess.get(), &LoggedProcess::stateChanged, this, &WorldListPage::mceditState);
- m_mceditProcess->start(program, {fullPath});
- m_mceditProcess->setWorkingDirectory(mceditPath);
- m_mceditStarting = true;
+ m_mceditProcess.reset(new LoggedProcess());
+ m_mceditProcess->setDetachable(true);
+ connect(m_mceditProcess.get(), &LoggedProcess::stateChanged, this, &WorldListPage::mceditState);
+ m_mceditProcess->start(program, {fullPath});
+ m_mceditProcess->setWorkingDirectory(mceditPath);
+ m_mceditStarting = true;
#endif
- }
- else
- {
- QMessageBox::warning(
- this->parentWidget(),
- tr("No MCEdit found or set up!"),
- tr("You do not have MCEdit set up or it was moved.\nYou can set it up in the global settings.")
- );
- }
+ }
+ else
+ {
+ QMessageBox::warning(
+ this->parentWidget(),
+ tr("No MCEdit found or set up!"),
+ tr("You do not have MCEdit set up or it was moved.\nYou can set it up in the global settings.")
+ );
+ }
}
void WorldListPage::mceditError()
{
- QMessageBox::warning(
- this->parentWidget(),
- tr("MCEdit failed to start!"),
- tr("MCEdit failed to start.\nIt may be necessary to reinstall it.")
- );
+ QMessageBox::warning(
+ this->parentWidget(),
+ tr("MCEdit failed to start!"),
+ tr("MCEdit failed to start.\nIt may be necessary to reinstall it.")
+ );
}
void WorldListPage::mceditState(LoggedProcess::State state)
{
- bool failed = false;
- switch(state)
- {
- case LoggedProcess::NotRunning:
- case LoggedProcess::Starting:
- return;
- case LoggedProcess::FailedToStart:
- case LoggedProcess::Crashed:
- case LoggedProcess::Aborted:
- {
- failed = true;
- }
- case LoggedProcess::Running:
- case LoggedProcess::Finished:
- {
- m_mceditStarting = false;
- break;
- }
- }
- if(failed)
- {
- mceditError();
- }
+ bool failed = false;
+ switch(state)
+ {
+ case LoggedProcess::NotRunning:
+ case LoggedProcess::Starting:
+ return;
+ case LoggedProcess::FailedToStart:
+ case LoggedProcess::Crashed:
+ case LoggedProcess::Aborted:
+ {
+ failed = true;
+ }
+ case LoggedProcess::Running:
+ case LoggedProcess::Finished:
+ {
+ m_mceditStarting = false;
+ break;
+ }
+ }
+ if(failed)
+ {
+ mceditError();
+ }
}
void WorldListPage::worldChanged(const QModelIndex &current, const QModelIndex &previous)
{
- QModelIndex index = getSelectedWorld();
- bool enable = index.isValid();
- ui->copySeedBtn->setEnabled(enable);
- ui->mcEditBtn->setEnabled(enable);
- ui->rmWorldBtn->setEnabled(enable);
- ui->copyBtn->setEnabled(enable);
- ui->renameBtn->setEnabled(enable);
+ QModelIndex index = getSelectedWorld();
+ bool enable = index.isValid();
+ ui->actionCopy_Seed->setEnabled(enable);
+ ui->actionMCEdit->setEnabled(enable);
+ ui->actionRemove->setEnabled(enable);
+ ui->actionCopy->setEnabled(enable);
+ ui->actionRename->setEnabled(enable);
}
-void WorldListPage::on_addBtn_clicked()
+void WorldListPage::on_actionAdd_triggered()
{
- auto list = GuiUtil::BrowseForFiles(
- m_helpName,
- tr("Select a Minecraft world zip"),
- tr("Minecraft World Zip File (*.zip)"), QString(), this->parentWidget());
- if (!list.empty())
- {
- m_worlds->stopWatching();
- for (auto filename : list)
- {
- m_worlds->installWorld(QFileInfo(filename));
- }
- m_worlds->startWatching();
- }
+ auto list = GuiUtil::BrowseForFiles(
+ displayName(),
+ tr("Select a Minecraft world zip"),
+ tr("Minecraft World Zip File (*.zip)"), QString(), this->parentWidget());
+ if (!list.empty())
+ {
+ m_worlds->stopWatching();
+ for (auto filename : list)
+ {
+ m_worlds->installWorld(QFileInfo(filename));
+ }
+ m_worlds->startWatching();
+ }
}
bool WorldListPage::isWorldSafe(QModelIndex)
{
- return !m_inst->isRunning();
+ return !m_inst->isRunning();
}
bool WorldListPage::worldSafetyNagQuestion()
{
- if(!isWorldSafe(getSelectedWorld()))
- {
- auto result = QMessageBox::question(this, tr("Copy World"), tr("Changing a world while Minecraft is running is potentially unsafe.\nDo you wish to proceed?"));
- if(result == QMessageBox::No)
- {
- return false;
- }
- }
- return true;
+ if(!isWorldSafe(getSelectedWorld()))
+ {
+ auto result = QMessageBox::question(this, tr("Copy World"), tr("Changing a world while Minecraft is running is potentially unsafe.\nDo you wish to proceed?"));
+ if(result == QMessageBox::No)
+ {
+ return false;
+ }
+ }
+ return true;
}
-void WorldListPage::on_copyBtn_clicked()
+void WorldListPage::on_actionCopy_triggered()
{
- QModelIndex index = getSelectedWorld();
- if (!index.isValid())
- {
- return;
- }
-
- if(!worldSafetyNagQuestion())
- return;
-
- auto worldVariant = m_worlds->data(index, WorldList::ObjectRole);
- auto world = (World *) worldVariant.value<void *>();
- bool ok = false;
- QString name = QInputDialog::getText(this, tr("World name"), tr("Enter a new name for the copy."), QLineEdit::Normal, world->name(), &ok);
-
- if (ok && name.length() > 0)
- {
- world->install(m_worlds->dir().absolutePath(), name);
- }
+ QModelIndex index = getSelectedWorld();
+ if (!index.isValid())
+ {
+ return;
+ }
+
+ if(!worldSafetyNagQuestion())
+ return;
+
+ auto worldVariant = m_worlds->data(index, WorldList::ObjectRole);
+ auto world = (World *) worldVariant.value<void *>();
+ bool ok = false;
+ QString name = QInputDialog::getText(this, tr("World name"), tr("Enter a new name for the copy."), QLineEdit::Normal, world->name(), &ok);
+
+ if (ok && name.length() > 0)
+ {
+ world->install(m_worlds->dir().absolutePath(), name);
+ }
}
-void WorldListPage::on_renameBtn_clicked()
+void WorldListPage::on_actionRename_triggered()
{
- QModelIndex index = getSelectedWorld();
- if (!index.isValid())
- {
- return;
- }
+ QModelIndex index = getSelectedWorld();
+ if (!index.isValid())
+ {
+ return;
+ }
- if(!worldSafetyNagQuestion())
- return;
+ if(!worldSafetyNagQuestion())
+ return;
- auto worldVariant = m_worlds->data(index, WorldList::ObjectRole);
- auto world = (World *) worldVariant.value<void *>();
+ auto worldVariant = m_worlds->data(index, WorldList::ObjectRole);
+ auto world = (World *) worldVariant.value<void *>();
- bool ok = false;
- QString name = QInputDialog::getText(this, tr("World name"), tr("Enter a new world name."), QLineEdit::Normal, world->name(), &ok);
+ bool ok = false;
+ QString name = QInputDialog::getText(this, tr("World name"), tr("Enter a new world name."), QLineEdit::Normal, world->name(), &ok);
- if (ok && name.length() > 0)
- {
- world->rename(name);
- }
+ if (ok && name.length() > 0)
+ {
+ world->rename(name);
+ }
}
-void WorldListPage::on_refreshBtn_clicked()
+void WorldListPage::on_actionRefresh_triggered()
{
- m_worlds->update();
+ m_worlds->update();
}
diff --git a/application/pages/instance/WorldListPage.h b/application/pages/instance/WorldListPage.h
index 71b87bda..c39420da 100644
--- a/application/pages/instance/WorldListPage.h
+++ b/application/pages/instance/WorldListPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2015-2018 MultiMC Contributors
+/* Copyright 2015-2019 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,7 +15,7 @@
#pragma once
-#include <QWidget>
+#include <QMainWindow>
#include "minecraft/MinecraftInstance.h"
#include "pages/BasePage.h"
@@ -28,69 +28,70 @@ namespace Ui
class WorldListPage;
}
-class WorldListPage : public QWidget, public BasePage
+class WorldListPage : public QMainWindow, public BasePage
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit WorldListPage(BaseInstance *inst, std::shared_ptr<WorldList> worlds, QString id,
- QString iconName, QString displayName, QString helpPage = "",
- QWidget *parent = 0);
- virtual ~WorldListPage();
+ explicit WorldListPage(
+ BaseInstance *inst,
+ std::shared_ptr<WorldList> worlds,
+ QWidget *parent = 0
+ );
+ virtual ~WorldListPage();
- virtual QString displayName() const override
- {
- return m_displayName;
- }
- virtual QIcon icon() const override
- {
- return MMC->getThemedIcon(m_iconName);
- }
- virtual QString id() const override
- {
- return m_id;
- }
- virtual QString helpPage() const override
- {
- return m_helpName;
- }
- virtual bool shouldDisplay() const override;
+ virtual QString displayName() const override
+ {
+ return tr("Worlds");
+ }
+ virtual QIcon icon() const override
+ {
+ return MMC->getThemedIcon("worlds");
+ }
+ virtual QString id() const override
+ {
+ return "worlds";
+ }
+ virtual QString helpPage() const override
+ {
+ return "Worlds";
+ }
+ virtual bool shouldDisplay() const override;
- virtual void openedImpl() override;
- virtual void closedImpl() override;
+ virtual void openedImpl() override;
+ virtual void closedImpl() override;
protected:
- bool eventFilter(QObject *obj, QEvent *ev) override;
- bool worldListFilter(QKeyEvent *ev);
+ bool eventFilter(QObject *obj, QEvent *ev) override;
+ bool worldListFilter(QKeyEvent *ev);
+ QMenu * createPopupMenu() override;
protected:
- BaseInstance *m_inst;
+ BaseInstance *m_inst;
private:
- QModelIndex getSelectedWorld();
- bool isWorldSafe(QModelIndex index);
- bool worldSafetyNagQuestion();
- void mceditError();
+ QModelIndex getSelectedWorld();
+ bool isWorldSafe(QModelIndex index);
+ bool worldSafetyNagQuestion();
+ void mceditError();
private:
- Ui::WorldListPage *ui;
- std::shared_ptr<WorldList> m_worlds;
- unique_qobject_ptr<LoggedProcess> m_mceditProcess;
- bool m_mceditStarting = false;
- QString m_iconName;
- QString m_id;
- QString m_displayName;
- QString m_helpName;
+ Ui::WorldListPage *ui;
+ std::shared_ptr<WorldList> m_worlds;
+ unique_qobject_ptr<LoggedProcess> m_mceditProcess;
+ bool m_mceditStarting = false;
private slots:
- void on_copySeedBtn_clicked();
- void on_mcEditBtn_clicked();
- void on_rmWorldBtn_clicked();
- void on_addBtn_clicked();
- void on_copyBtn_clicked();
- void on_renameBtn_clicked();
- void on_refreshBtn_clicked();
- void on_viewFolderBtn_clicked();
- void worldChanged(const QModelIndex &current, const QModelIndex &previous);
- void mceditState(LoggedProcess::State state);
+ void on_actionCopy_Seed_triggered();
+ void on_actionMCEdit_triggered();
+ void on_actionRemove_triggered();
+ void on_actionAdd_triggered();
+ void on_actionCopy_triggered();
+ void on_actionRename_triggered();
+ void on_actionRefresh_triggered();
+ void on_actionView_Folder_triggered();
+ void worldChanged(const QModelIndex &current, const QModelIndex &previous);
+ void mceditState(LoggedProcess::State state);
+
+ void ShowContextMenu(const QPoint &pos);
};
diff --git a/application/pages/instance/WorldListPage.ui b/application/pages/instance/WorldListPage.ui
index 0018ddf3..b7a9e57a 100644
--- a/application/pages/instance/WorldListPage.ui
+++ b/application/pages/instance/WorldListPage.ui
@@ -1,168 +1,140 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>WorldListPage</class>
- <widget class="QWidget" name="WorldListPage">
+ <widget class="QMainWindow" name="WorldListPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
- <width>723</width>
- <height>532</height>
+ <width>800</width>
+ <height>600</height>
</rect>
</property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <property name="leftMargin">
- <number>0</number>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <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="QTreeView" name="worldTreeView">
+ <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::DragDrop</enum>
+ </property>
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <attribute name="headerStretchLastSection">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="WideBar" name="toolBar">
+ <property name="windowTitle">
+ <string>toolBar</string>
</property>
- <property name="topMargin">
- <number>0</number>
+ <property name="allowedAreas">
+ <set>Qt::LeftToolBarArea|Qt::RightToolBarArea</set>
</property>
- <property name="rightMargin">
- <number>0</number>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextOnly</enum>
</property>
- <property name="bottomMargin">
- <number>0</number>
+ <property name="floatable">
+ <bool>false</bool>
</property>
- <item>
- <widget class="QTabWidget" name="tabWidget">
- <property name="currentIndex">
- <number>0</number>
- </property>
- <widget class="QWidget" name="tab">
- <attribute name="title">
- <string notr="true">Tab 1</string>
- </attribute>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="2">
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <item>
- <widget class="QPushButton" name="addBtn">
- <property name="text">
- <string>Add</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="LineSeparator" name="separator" native="true"/>
- </item>
- <item>
- <widget class="QPushButton" name="renameBtn">
- <property name="text">
- <string>Rename</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="copyBtn">
- <property name="text">
- <string>Copy</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="rmWorldBtn">
- <property name="text">
- <string>&amp;Remove</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="mcEditBtn">
- <property name="text">
- <string notr="true">MCEdit</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="LineSeparator" name="separator_2" native="true"/>
- </item>
- <item>
- <widget class="QPushButton" name="copySeedBtn">
- <property name="text">
- <string>Copy Seed</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="refreshBtn">
- <property name="text">
- <string>Refresh</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="viewFolderBtn">
- <property name="text">
- <string>&amp;View Folder</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="0" column="1">
- <widget class="QTreeView" name="worldTreeView">
- <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::DragDrop</enum>
- </property>
- <property name="sortingEnabled">
- <bool>true</bool>
- </property>
- <property name="allColumnsShowFocus">
- <bool>true</bool>
- </property>
- <attribute name="headerStretchLastSection">
- <bool>false</bool>
- </attribute>
- </widget>
- </item>
- </layout>
- </widget>
- </widget>
- </item>
- </layout>
+ <attribute name="toolBarArea">
+ <enum>RightToolBarArea</enum>
+ </attribute>
+ <attribute name="toolBarBreak">
+ <bool>false</bool>
+ </attribute>
+ <addaction name="actionAdd"/>
+ <addaction name="separator"/>
+ <addaction name="actionRename"/>
+ <addaction name="actionCopy"/>
+ <addaction name="actionRemove"/>
+ <addaction name="actionMCEdit"/>
+ <addaction name="separator"/>
+ <addaction name="actionCopy_Seed"/>
+ <addaction name="actionRefresh"/>
+ <addaction name="actionView_Folder"/>
+ </widget>
+ <action name="actionAdd">
+ <property name="text">
+ <string>Add</string>
+ </property>
+ </action>
+ <action name="actionRename">
+ <property name="text">
+ <string>Rename</string>
+ </property>
+ </action>
+ <action name="actionCopy">
+ <property name="text">
+ <string>Copy</string>
+ </property>
+ </action>
+ <action name="actionRemove">
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </action>
+ <action name="actionMCEdit">
+ <property name="text">
+ <string>MCEdit</string>
+ </property>
+ </action>
+ <action name="actionCopy_Seed">
+ <property name="text">
+ <string>Copy Seed</string>
+ </property>
+ </action>
+ <action name="actionRefresh">
+ <property name="text">
+ <string>Refresh</string>
+ </property>
+ </action>
+ <action name="actionView_Folder">
+ <property name="text">
+ <string>View Folder</string>
+ </property>
+ </action>
</widget>
<customwidgets>
<customwidget>
- <class>LineSeparator</class>
- <extends>QWidget</extends>
- <header>widgets/LineSeparator.h</header>
- <container>1</container>
+ <class>WideBar</class>
+ <extends>QToolBar</extends>
+ <header>widgets/WideBar.h</header>
</customwidget>
</customwidgets>
- <tabstops>
- <tabstop>tabWidget</tabstop>
- <tabstop>worldTreeView</tabstop>
- <tabstop>addBtn</tabstop>
- <tabstop>renameBtn</tabstop>
- <tabstop>copyBtn</tabstop>
- <tabstop>rmWorldBtn</tabstop>
- <tabstop>mcEditBtn</tabstop>
- <tabstop>copySeedBtn</tabstop>
- <tabstop>refreshBtn</tabstop>
- <tabstop>viewFolderBtn</tabstop>
- </tabstops>
<resources/>
<connections/>
</ui>
diff --git a/application/pages/modplatform/FTBPage.cpp b/application/pages/modplatform/FTBPage.cpp
index f438fce7..dca86efd 100644
--- a/application/pages/modplatform/FTBPage.cpp
+++ b/application/pages/modplatform/FTBPage.cpp
@@ -1,222 +1,364 @@
#include "FTBPage.h"
#include "ui_FTBPage.h"
+#include <QInputDialog>
+
#include "MultiMC.h"
-#include "FolderInstanceProvider.h"
#include "dialogs/CustomMessageBox.h"
#include "dialogs/NewInstanceDialog.h"
#include "modplatform/ftb/FtbPackFetchTask.h"
#include "modplatform/ftb/FtbPackInstallTask.h"
+#include "modplatform/ftb/FtbPrivatePackManager.h"
#include "FtbListModel.h"
FTBPage::FTBPage(NewInstanceDialog* dialog, QWidget *parent)
- : QWidget(parent), dialog(dialog), ui(new Ui::FTBPage)
+ : QWidget(parent), dialog(dialog), ui(new Ui::FTBPage)
{
- ftbFetchTask = new FtbPackFetchTask();
+ ftbFetchTask.reset(new FtbPackFetchTask());
+ ftbPrivatePacks.reset(new FtbPrivatePackManager());
+
+ ui->setupUi(this);
+
+ {
+ publicFilterModel = new FtbFilterModel(this);
+ publicListModel = new FtbListModel(this);
+ publicFilterModel->setSourceModel(publicListModel);
+
+ ui->publicPackList->setModel(publicFilterModel);
+ ui->publicPackList->setSortingEnabled(true);
+ ui->publicPackList->header()->hide();
+ ui->publicPackList->setIndentation(0);
+ ui->publicPackList->setIconSize(QSize(42, 42));
- ui->setupUi(this);
- ui->tabWidget->tabBar()->hide();
+ for(int i = 0; i < publicFilterModel->getAvailableSortings().size(); i++)
+ {
+ ui->sortByBox->addItem(publicFilterModel->getAvailableSortings().keys().at(i));
+ }
- {
- publicFilterModel = new FtbFilterModel(this);
- publicListModel = new FtbListModel(this);
- publicFilterModel->setSourceModel(publicListModel);
+ ui->sortByBox->setCurrentText(publicFilterModel->translateCurrentSorting());
+ }
- ui->publicPackList->setModel(publicFilterModel);
- ui->publicPackList->setSortingEnabled(true);
- ui->publicPackList->header()->hide();
- ui->publicPackList->setIndentation(0);
- ui->publicPackList->setIconSize(QSize(42, 42));
+ {
+ thirdPartyFilterModel = new FtbFilterModel(this);
+ thirdPartyModel = new FtbListModel(this);
+ thirdPartyFilterModel->setSourceModel(thirdPartyModel);
- for(int i = 0; i < publicFilterModel->getAvailableSortings().size(); i++)
- {
- ui->sortByBox->addItem(publicFilterModel->getAvailableSortings().keys().at(i));
- }
+ ui->thirdPartyPackList->setModel(thirdPartyFilterModel);
+ ui->thirdPartyPackList->setSortingEnabled(true);
+ ui->thirdPartyPackList->header()->hide();
+ ui->thirdPartyPackList->setIndentation(0);
+ ui->thirdPartyPackList->setIconSize(QSize(42, 42));
- ui->sortByBox->setCurrentText(publicFilterModel->translateCurrentSorting());
- }
+ thirdPartyFilterModel->setSorting(publicFilterModel->getCurrentSorting());
+ }
- {
- thirdPartyFilterModel = new FtbFilterModel(this);
- thirdPartyModel = new FtbListModel(this);
- thirdPartyFilterModel->setSourceModel(thirdPartyModel);
+ {
+ privateFilterModel = new FtbFilterModel(this);
+ privateListModel = new FtbListModel(this);
+ privateFilterModel->setSourceModel(privateListModel);
- ui->thirdPartyPackList->setModel(thirdPartyFilterModel);
- ui->thirdPartyPackList->setSortingEnabled(true);
- ui->thirdPartyPackList->header()->hide();
- ui->thirdPartyPackList->setIndentation(0);
- ui->thirdPartyPackList->setIconSize(QSize(42, 42));
+ ui->privatePackList->setModel(privateFilterModel);
+ ui->privatePackList->setSortingEnabled(true);
+ ui->privatePackList->header()->hide();
+ ui->privatePackList->setIndentation(0);
+ ui->privatePackList->setIconSize(QSize(42, 42));
- thirdPartyFilterModel->setSorting(publicFilterModel->getCurrentSorting());
- }
+ privateFilterModel->setSorting(publicFilterModel->getCurrentSorting());
+ }
- ui->packVersionSelection->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
- ui->packVersionSelection->view()->parentWidget()->setMaximumHeight(300);
+ ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300);
- connect(ui->sortByBox, &QComboBox::currentTextChanged, this, &FTBPage::onSortingSelectionChanged);
- connect(ui->packVersionSelection, &QComboBox::currentTextChanged, this, &FTBPage::onVersionSelectionItemChanged);
+ connect(ui->sortByBox, &QComboBox::currentTextChanged, this, &FTBPage::onSortingSelectionChanged);
+ connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &FTBPage::onVersionSelectionItemChanged);
- connect(ui->publicPackList->selectionModel(), &QItemSelectionModel::currentChanged, this, &FTBPage::onPublicPackSelectionChanged);
- connect(ui->thirdPartyPackList->selectionModel(), &QItemSelectionModel::currentChanged, this, &FTBPage::onThirdPartyPackSelectionChanged);
+ connect(ui->publicPackList->selectionModel(), &QItemSelectionModel::currentChanged, this, &FTBPage::onPublicPackSelectionChanged);
+ connect(ui->thirdPartyPackList->selectionModel(), &QItemSelectionModel::currentChanged, this, &FTBPage::onThirdPartyPackSelectionChanged);
+ connect(ui->privatePackList->selectionModel(), &QItemSelectionModel::currentChanged, this, &FTBPage::onPrivatePackSelectionChanged);
- connect(ui->ftbTabWidget, &QTabWidget::currentChanged, this, &FTBPage::onTabChanged);
+ connect(ui->addPackBtn, &QPushButton::pressed, this, &FTBPage::onAddPackClicked);
+ connect(ui->removePackBtn, &QPushButton::pressed, this, &FTBPage::onRemovePackClicked);
- ui->modpackInfo->setOpenExternalLinks(true);
+ connect(ui->tabWidget, &QTabWidget::currentChanged, this, &FTBPage::onTabChanged);
- ui->publicPackList->selectionModel()->reset();
- ui->thirdPartyPackList->selectionModel()->reset();
+ // ui->modpackInfo->setOpenExternalLinks(true);
+
+ ui->publicPackList->selectionModel()->reset();
+ ui->thirdPartyPackList->selectionModel()->reset();
+ ui->privatePackList->selectionModel()->reset();
+
+ onTabChanged(ui->tabWidget->currentIndex());
}
FTBPage::~FTBPage()
{
- delete ui;
- if(ftbFetchTask) {
- ftbFetchTask->deleteLater();
- }
+ delete ui;
}
bool FTBPage::shouldDisplay() const
{
- return true;
+ return true;
}
void FTBPage::openedImpl()
{
- if(!initialized)
- {
- connect(ftbFetchTask, &FtbPackFetchTask::finished, this, &FTBPage::ftbPackDataDownloadSuccessfully);
- connect(ftbFetchTask, &FtbPackFetchTask::failed, this, &FTBPage::ftbPackDataDownloadFailed);
- ftbFetchTask->fetch();
- initialized = true;
- }
- suggestCurrent();
+ if(!initialized)
+ {
+ connect(ftbFetchTask.get(), &FtbPackFetchTask::finished, this, &FTBPage::ftbPackDataDownloadSuccessfully);
+ connect(ftbFetchTask.get(), &FtbPackFetchTask::failed, this, &FTBPage::ftbPackDataDownloadFailed);
+
+ connect(ftbFetchTask.get(), &FtbPackFetchTask::privateFileDownloadFinished, this, &FTBPage::ftbPrivatePackDataDownloadSuccessfully);
+ connect(ftbFetchTask.get(), &FtbPackFetchTask::privateFileDownloadFailed, this, &FTBPage::ftbPrivatePackDataDownloadFailed);
+
+ ftbFetchTask->fetch();
+ ftbPrivatePacks->load();
+ ftbFetchTask->fetchPrivate(ftbPrivatePacks->getCurrentPackCodes().toList());
+ initialized = true;
+ }
+ suggestCurrent();
}
void FTBPage::suggestCurrent()
{
- if(isOpened)
- {
- if(!selected.broken)
- {
- dialog->setSuggestedPack(selected.name, new FtbPackInstallTask(selected, selectedVersion));
- if(selected.type == FtbPackType::Public) {
- publicListModel->getLogo(selected.logo, [this](QString logo){
- dialog->setSuggestedIconFromFile(logo, "ftb_" + selected.name);
- });
- } else if (selected.type == FtbPackType::ThirdParty) {
- thirdPartyModel->getLogo(selected.logo, [this](QString logo){
- dialog->setSuggestedIconFromFile(logo, "ftb_" + selected.name);
- });
- }
- }
- else
- {
- dialog->setSuggestedPack();
- }
- }
+ if(isOpened)
+ {
+ if(!selected.broken)
+ {
+ dialog->setSuggestedPack(selected.name, new FtbPackInstallTask(selected, selectedVersion));
+ QString editedLogoName;
+ if(selected.logo.toLower().startsWith("ftb"))
+ {
+ editedLogoName = selected.logo;
+ }
+ else
+ {
+ editedLogoName = "ftb_" + selected.logo;
+ }
+
+ editedLogoName = editedLogoName.left(editedLogoName.lastIndexOf(".png"));
+
+ if(selected.type == FtbPackType::Public)
+ {
+ publicListModel->getLogo(selected.logo, [this, editedLogoName](QString logo)
+ {
+ dialog->setSuggestedIconFromFile(logo, editedLogoName);
+ });
+ }
+ else if (selected.type == FtbPackType::ThirdParty)
+ {
+ thirdPartyModel->getLogo(selected.logo, [this, editedLogoName](QString logo)
+ {
+ dialog->setSuggestedIconFromFile(logo, editedLogoName);
+ });
+ }
+ else if (selected.type == FtbPackType::Private)
+ {
+ privateListModel->getLogo(selected.logo, [this, editedLogoName](QString logo)
+ {
+ dialog->setSuggestedIconFromFile(logo, editedLogoName);
+ });
+ }
+ }
+ else
+ {
+ dialog->setSuggestedPack();
+ }
+ }
}
void FTBPage::ftbPackDataDownloadSuccessfully(FtbModpackList publicPacks, FtbModpackList thirdPartyPacks)
{
- publicListModel->fill(publicPacks);
- thirdPartyModel->fill(thirdPartyPacks);
+ publicListModel->fill(publicPacks);
+ thirdPartyModel->fill(thirdPartyPacks);
}
void FTBPage::ftbPackDataDownloadFailed(QString reason)
{
- //TODO: Display the error
+ //TODO: Display the error
+}
+
+void FTBPage::ftbPrivatePackDataDownloadSuccessfully(FtbModpack pack)
+{
+ privateListModel->addPack(pack);
+}
+
+void FTBPage::ftbPrivatePackDataDownloadFailed(QString reason, QString packCode)
+{
+ auto reply = QMessageBox::question(
+ this,
+ tr("FTB private packs"),
+ tr("Failed to download pack information for code %1.\nShould it be removed now?").arg(packCode)
+ );
+ if(reply == QMessageBox::Yes)
+ {
+ ftbPrivatePacks->remove(packCode);
+ }
}
void FTBPage::onPublicPackSelectionChanged(QModelIndex now, QModelIndex prev)
{
- if(!now.isValid())
- {
- onPackSelectionChanged();
- return;
- }
- FtbModpack selectedPack = publicFilterModel->data(now, Qt::UserRole).value<FtbModpack>();
- onPackSelectionChanged(&selectedPack);
+ if(!now.isValid())
+ {
+ onPackSelectionChanged();
+ return;
+ }
+ FtbModpack selectedPack = publicFilterModel->data(now, Qt::UserRole).value<FtbModpack>();
+ onPackSelectionChanged(&selectedPack);
}
void FTBPage::onThirdPartyPackSelectionChanged(QModelIndex now, QModelIndex prev)
{
- if(!now.isValid())
- {
- onPackSelectionChanged();
- return;
- }
- FtbModpack selectedPack = thirdPartyFilterModel->data(now, Qt::UserRole).value<FtbModpack>();
- onPackSelectionChanged(&selectedPack);
+ if(!now.isValid())
+ {
+ onPackSelectionChanged();
+ return;
+ }
+ FtbModpack selectedPack = thirdPartyFilterModel->data(now, Qt::UserRole).value<FtbModpack>();
+ onPackSelectionChanged(&selectedPack);
+}
+
+void FTBPage::onPrivatePackSelectionChanged(QModelIndex now, QModelIndex prev)
+{
+ if(!now.isValid())
+ {
+ onPackSelectionChanged();
+ return;
+ }
+ FtbModpack selectedPack = privateFilterModel->data(now, Qt::UserRole).value<FtbModpack>();
+ onPackSelectionChanged(&selectedPack);
}
void FTBPage::onPackSelectionChanged(FtbModpack* pack)
{
- ui->packVersionSelection->clear();
- if(pack)
- {
- ui->modpackInfo->setHtml("Pack by <b>" + pack->author + "</b>" + "<br>Minecraft " + pack->mcVersion + "<br>"
- "<br>" + pack->description + "<ul><li>" + pack->mods.replace(";", "</li><li>") + "</li></ul>");
- bool currentAdded = false;
-
- for(int i = 0; i < pack->oldVersions.size(); i++)
- {
- if(pack->currentVersion == pack->oldVersions.at(i))
- {
- currentAdded = true;
- }
- ui->packVersionSelection->addItem(pack->oldVersions.at(i));
- }
-
- if(!currentAdded)
- {
- ui->packVersionSelection->addItem(pack->currentVersion);
- }
- selected = *pack;
- }
- suggestCurrent();
+ ui->versionSelectionBox->clear();
+ if(pack)
+ {
+ currentModpackInfo->setHtml("Pack by <b>" + pack->author + "</b>" +
+ "<br>Minecraft " + pack->mcVersion + "<br>" + "<br>" + pack->description + "<ul><li>" + pack->mods.replace(";", "</li><li>")
+ + "</li></ul>");
+ bool currentAdded = false;
+
+ for(int i = 0; i < pack->oldVersions.size(); i++)
+ {
+ if(pack->currentVersion == pack->oldVersions.at(i))
+ {
+ currentAdded = true;
+ }
+ ui->versionSelectionBox->addItem(pack->oldVersions.at(i));
+ }
+
+ if(!currentAdded)
+ {
+ ui->versionSelectionBox->addItem(pack->currentVersion);
+ }
+ selected = *pack;
+ }
+ else
+ {
+ currentModpackInfo->setHtml("");
+ ui->versionSelectionBox->clear();
+ if(isOpened)
+ {
+ dialog->setSuggestedPack();
+ }
+ return;
+ }
+ suggestCurrent();
}
void FTBPage::onVersionSelectionItemChanged(QString data)
{
- if(data.isNull() || data.isEmpty())
- {
- selectedVersion = "";
- return;
- }
+ if(data.isNull() || data.isEmpty())
+ {
+ selectedVersion = "";
+ return;
+ }
- selectedVersion = data;
- suggestCurrent();
+ selectedVersion = data;
+ suggestCurrent();
}
void FTBPage::onSortingSelectionChanged(QString data)
{
- FtbFilterModel::Sorting toSet = publicFilterModel->getAvailableSortings().value(data);
- publicFilterModel->setSorting(toSet);
- thirdPartyFilterModel->setSorting(toSet);
+ FtbFilterModel::Sorting toSet = publicFilterModel->getAvailableSortings().value(data);
+ publicFilterModel->setSorting(toSet);
+ thirdPartyFilterModel->setSorting(toSet);
+ privateFilterModel->setSorting(toSet);
}
void FTBPage::onTabChanged(int tab)
{
- FtbFilterModel* currentModel = nullptr;
- QTreeView* currentList = nullptr;
- if (tab == 0)
- {
- currentModel = publicFilterModel;
- currentList = ui->publicPackList;
- }
- else
- {
- currentModel = thirdPartyFilterModel;
- currentList = ui->thirdPartyPackList;
- }
- QModelIndex idx = currentList->currentIndex();
- if(idx.isValid())
- {
- auto pack = currentModel->data(idx, Qt::UserRole).value<FtbModpack>();
- onPackSelectionChanged(&pack);
- }
- else
- {
- onPackSelectionChanged();
- }
+ if(tab == 1)
+ {
+ currentModel = thirdPartyFilterModel;
+ currentList = ui->thirdPartyPackList;
+ currentModpackInfo = ui->thirdPartyPackDescription;
+ }
+ else if(tab == 2)
+ {
+ currentModel = privateFilterModel;
+ currentList = ui->privatePackList;
+ currentModpackInfo = ui->privatePackDescription;
+ }
+ else
+ {
+ currentModel = publicFilterModel;
+ currentList = ui->publicPackList;
+ currentModpackInfo = ui->publicPackDescription;
+ }
+
+ currentList->selectionModel()->reset();
+ QModelIndex idx = currentList->currentIndex();
+ if(idx.isValid())
+ {
+ auto pack = currentModel->data(idx, Qt::UserRole).value<FtbModpack>();
+ onPackSelectionChanged(&pack);
+ }
+ else
+ {
+ onPackSelectionChanged();
+ }
+}
+
+void FTBPage::onAddPackClicked()
+{
+ bool ok;
+ QString text = QInputDialog::getText(
+ this,
+ tr("Add FTB pack"),
+ tr("Enter pack code:"),
+ QLineEdit::Normal,
+ QString(),
+ &ok
+ );
+ if(ok && !text.isEmpty())
+ {
+ ftbPrivatePacks->add(text);
+ ftbFetchTask->fetchPrivate({text});
+ }
+}
+
+void FTBPage::onRemovePackClicked()
+{
+ auto index = ui->privatePackList->currentIndex();
+ if(!index.isValid())
+ {
+ return;
+ }
+ auto row = index.row();
+ FtbModpack pack = privateListModel->at(row);
+ auto answer = QMessageBox::question(
+ this,
+ tr("Remove pack"),
+ tr("Are you sure you want to remove pack %1?").arg(pack.name),
+ QMessageBox::Yes | QMessageBox::No
+ );
+ if(answer != QMessageBox::Yes)
+ {
+ return;
+ }
+
+ ftbPrivatePacks->remove(pack.packCode);
+ privateListModel->remove(row);
+ onPackSelectionChanged();
}
diff --git a/application/pages/modplatform/FTBPage.h b/application/pages/modplatform/FTBPage.h
index 00c5e9c5..215252ee 100644
--- a/application/pages/modplatform/FTBPage.h
+++ b/application/pages/modplatform/FTBPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 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,12 +16,15 @@
#pragma once
#include <QWidget>
+#include <QTreeView>
+#include <QTextBrowser>
#include "pages/BasePage.h"
#include <MultiMC.h>
#include "tasks/Task.h"
#include "modplatform/ftb/PackHelpers.h"
#include "modplatform/ftb/FtbPackFetchTask.h"
+#include "QObjectPtr.h"
namespace Ui
{
@@ -31,62 +34,81 @@ class FTBPage;
class FtbListModel;
class FtbFilterModel;
class NewInstanceDialog;
+class FtbPrivatePackListModel;
+class FtbPrivatePackFilterModel;
+class FtbPrivatePackManager;
class FTBPage : public QWidget, public BasePage
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit FTBPage(NewInstanceDialog * dialog, QWidget *parent = 0);
- virtual ~FTBPage();
- QString displayName() const override
- {
- return tr("FTB Legacy");
- }
- QIcon icon() const override
- {
- return MMC->getThemedIcon("ftb_logo");
- }
- QString id() const override
- {
- return "ftb";
- }
- QString helpPage() const override
- {
- return "FTB-platform";
- }
- bool shouldDisplay() const override;
- void openedImpl() override;
+ explicit FTBPage(NewInstanceDialog * dialog, QWidget *parent = 0);
+ virtual ~FTBPage();
+ QString displayName() const override
+ {
+ return tr("FTB Legacy");
+ }
+ QIcon icon() const override
+ {
+ return MMC->getThemedIcon("ftb_logo");
+ }
+ QString id() const override
+ {
+ return "ftb";
+ }
+ QString helpPage() const override
+ {
+ return "FTB-platform";
+ }
+ bool shouldDisplay() const override;
+ void openedImpl() override;
private:
- void suggestCurrent();
- void onPackSelectionChanged(FtbModpack *pack = nullptr);
+ void suggestCurrent();
+ void onPackSelectionChanged(FtbModpack *pack = nullptr);
private slots:
- void ftbPackDataDownloadSuccessfully(FtbModpackList publicPacks, FtbModpackList thirdPartyPacks);
- void ftbPackDataDownloadFailed(QString reason);
+ void ftbPackDataDownloadSuccessfully(FtbModpackList publicPacks, FtbModpackList thirdPartyPacks);
+ void ftbPackDataDownloadFailed(QString reason);
- void onSortingSelectionChanged(QString data);
- void onVersionSelectionItemChanged(QString data);
+ void ftbPrivatePackDataDownloadSuccessfully(FtbModpack pack);
+ void ftbPrivatePackDataDownloadFailed(QString reason, QString packCode);
- void onPublicPackSelectionChanged(QModelIndex first, QModelIndex second);
- void onThirdPartyPackSelectionChanged(QModelIndex first, QModelIndex second);
+ void onSortingSelectionChanged(QString data);
+ void onVersionSelectionItemChanged(QString data);
- void onTabChanged(int tab);
+ void onPublicPackSelectionChanged(QModelIndex first, QModelIndex second);
+ void onThirdPartyPackSelectionChanged(QModelIndex first, QModelIndex second);
+ void onPrivatePackSelectionChanged(QModelIndex first, QModelIndex second);
+
+ void onTabChanged(int tab);
+
+ void onAddPackClicked();
+ void onRemovePackClicked();
private:
- bool initialized = false;
- FtbModpack selected;
- QString selectedVersion;
+ FtbFilterModel* currentModel = nullptr;
+ QTreeView* currentList = nullptr;
+ QTextBrowser* currentModpackInfo = nullptr;
+
+ bool initialized = false;
+ FtbModpack selected;
+ QString selectedVersion;
+
+ FtbListModel* publicListModel = nullptr;
+ FtbFilterModel* publicFilterModel = nullptr;
+
+ FtbListModel *thirdPartyModel = nullptr;
+ FtbFilterModel *thirdPartyFilterModel = nullptr;
- FtbListModel* publicListModel = nullptr;
- FtbFilterModel* publicFilterModel = nullptr;
+ FtbListModel *privateListModel = nullptr;
+ FtbFilterModel *privateFilterModel = nullptr;
- FtbListModel *thirdPartyModel = nullptr;
- FtbFilterModel *thirdPartyFilterModel = nullptr;
+ unique_qobject_ptr<FtbPackFetchTask> ftbFetchTask;
+ std::unique_ptr<FtbPrivatePackManager> ftbPrivatePacks;
- FtbPackFetchTask *ftbFetchTask = nullptr;
- NewInstanceDialog* dialog = nullptr;
+ NewInstanceDialog* dialog = nullptr;
- Ui::FTBPage *ui = nullptr;
+ Ui::FTBPage *ui = nullptr;
};
diff --git a/application/pages/modplatform/FTBPage.ui b/application/pages/modplatform/FTBPage.ui
index cb085af2..e5ed78cb 100644
--- a/application/pages/modplatform/FTBPage.ui
+++ b/application/pages/modplatform/FTBPage.ui
@@ -11,18 +11,6 @@
</rect>
</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="tabWidget">
<property name="currentIndex">
@@ -30,86 +18,107 @@
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
- <string notr="true"/>
+ <string>Public</string>
</attribute>
- <layout class="QGridLayout" name="gridLayout" columnstretch="0,0,0,0">
- <item row="1" column="2" colspan="2">
- <widget class="QTextBrowser" name="modpackInfo">
- <property name="verticalScrollBarPolicy">
- <enum>Qt::ScrollBarAsNeeded</enum>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QTreeView" name="publicPackList">
+ <property name="maximumSize">
+ <size>
+ <width>250</width>
+ <height>16777215</height>
+ </size>
</property>
</widget>
</item>
- <item row="2" column="2">
- <widget class="QLabel" name="selectedVersionLabel">
- <property name="text">
- <string>Version selected:</string>
+ <item row="0" column="1">
+ <widget class="QTextBrowser" name="publicPackDescription"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_2">
+ <attribute name="title">
+ <string>3rd Party</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="0" column="1">
+ <widget class="QTextBrowser" name="thirdPartyPackDescription"/>
+ </item>
+ <item row="0" column="0">
+ <widget class="QTreeView" name="thirdPartyPackList">
+ <property name="maximumSize">
+ <size>
+ <width>250</width>
+ <height>16777215</height>
+ </size>
</property>
- <property name="alignment">
- <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_3">
+ <attribute name="title">
+ <string>Private</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <widget class="QTreeView" name="privatePackList">
+ <property name="maximumSize">
+ <size>
+ <width>250</width>
+ <height>16777215</height>
+ </size>
</property>
</widget>
</item>
- <item row="2" column="3">
- <widget class="QComboBox" name="packVersionSelection"/>
+ <item row="1" column="0">
+ <widget class="QPushButton" name="addPackBtn">
+ <property name="text">
+ <string>Add pack</string>
+ </property>
+ </widget>
</item>
<item row="2" column="0">
- <widget class="QComboBox" name="sortByBox"/>
- </item>
- <item row="0" column="0" rowspan="2">
- <widget class="QTabWidget" name="ftbTabWidget">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="tabShape">
- <enum>QTabWidget::Rounded</enum>
- </property>
- <property name="currentIndex">
- <number>0</number>
+ <widget class="QPushButton" name="removePackBtn">
+ <property name="text">
+ <string>Remove selected pack</string>
</property>
- <widget class="QWidget" name="tab_2">
- <attribute name="title">
- <string>Public Packs</string>
- </attribute>
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <item>
- <widget class="QTreeView" name="publicPackList">
- <property name="verticalScrollBarPolicy">
- <enum>Qt::ScrollBarAsNeeded</enum>
- </property>
- <property name="horizontalScrollBarPolicy">
- <enum>Qt::ScrollBarAlwaysOff</enum>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <widget class="QWidget" name="tab_3">
- <attribute name="title">
- <string>3rd Party Packs</string>
- </attribute>
- <layout class="QVBoxLayout" name="verticalLayout_3">
- <item>
- <widget class="QTreeView" name="thirdPartyPackList">
- <property name="verticalScrollBarPolicy">
- <enum>Qt::ScrollBarAsNeeded</enum>
- </property>
- <property name="horizontalScrollBarPolicy">
- <enum>Qt::ScrollBarAlwaysOff</enum>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
</widget>
</item>
+ <item row="0" column="1" rowspan="3">
+ <widget class="QTextBrowser" name="privatePackDescription"/>
+ </item>
</layout>
</widget>
</widget>
</item>
+ <item>
+ <layout class="QGridLayout" name="gridLayout_4">
+ <item row="0" column="1">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Version selected:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QComboBox" name="versionSelectionBox"/>
+ </item>
+ <item row="0" column="0">
+ <widget class="QComboBox" name="sortByBox">
+ <property name="minimumSize">
+ <size>
+ <width>265</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
</layout>
</widget>
<resources/>
diff --git a/application/pages/modplatform/FtbListModel.cpp b/application/pages/modplatform/FtbListModel.cpp
index c14907c6..51aec890 100644
--- a/application/pages/modplatform/FtbListModel.cpp
+++ b/application/pages/modplatform/FtbListModel.cpp
@@ -10,56 +10,58 @@
#include <RWStorage.h>
#include <Env.h>
+#include "net/URLConstants.h"
+
FtbFilterModel::FtbFilterModel(QObject *parent) : QSortFilterProxyModel(parent)
{
- currentSorting = Sorting::ByGameVersion;
- sortings.insert(tr("Sort by name"), Sorting::ByName);
- sortings.insert(tr("Sort by game version"), Sorting::ByGameVersion);
+ currentSorting = Sorting::ByGameVersion;
+ sortings.insert(tr("Sort by name"), Sorting::ByName);
+ sortings.insert(tr("Sort by game version"), Sorting::ByGameVersion);
}
bool FtbFilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
- FtbModpack leftPack = sourceModel()->data(left, Qt::UserRole).value<FtbModpack>();
- FtbModpack rightPack = sourceModel()->data(right, Qt::UserRole).value<FtbModpack>();
+ FtbModpack leftPack = sourceModel()->data(left, Qt::UserRole).value<FtbModpack>();
+ FtbModpack rightPack = sourceModel()->data(right, Qt::UserRole).value<FtbModpack>();
- if(currentSorting == Sorting::ByGameVersion) {
- Version lv(leftPack.mcVersion);
- Version rv(rightPack.mcVersion);
- return lv < rv;
+ if(currentSorting == Sorting::ByGameVersion) {
+ Version lv(leftPack.mcVersion);
+ Version rv(rightPack.mcVersion);
+ return lv < rv;
- } else if(currentSorting == Sorting::ByName) {
- return Strings::naturalCompare(leftPack.name, rightPack.name, Qt::CaseSensitive) >= 0;
- }
+ } else if(currentSorting == Sorting::ByName) {
+ return Strings::naturalCompare(leftPack.name, rightPack.name, Qt::CaseSensitive) >= 0;
+ }
- //UHM, some inavlid value set?!
- qWarning() << "Invalid sorting set!";
- return true;
+ //UHM, some inavlid value set?!
+ qWarning() << "Invalid sorting set!";
+ return true;
}
bool FtbFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
- return true;
+ return true;
}
const QMap<QString, FtbFilterModel::Sorting> FtbFilterModel::getAvailableSortings()
{
- return sortings;
+ return sortings;
}
QString FtbFilterModel::translateCurrentSorting()
{
- return sortings.key(currentSorting);
+ return sortings.key(currentSorting);
}
void FtbFilterModel::setSorting(Sorting s)
{
- currentSorting = s;
- invalidate();
+ currentSorting = s;
+ invalidate();
}
FtbFilterModel::Sorting FtbFilterModel::getCurrentSorting()
{
- return currentSorting;
+ return currentSorting;
}
FtbListModel::FtbListModel(QObject *parent) : QAbstractListModel(parent)
@@ -72,128 +74,183 @@ FtbListModel::~FtbListModel()
QString FtbListModel::translatePackType(FtbPackType type) const
{
- if(type == FtbPackType::Public) {
- return tr("Public Modpack");
- } else if(type == FtbPackType::ThirdParty) {
- return tr("Third Party Modpack");
- } else if(type == FtbPackType::Private) {
- return tr("Private Modpack");
- } else {
- return tr("Unknown Type");
- }
+ switch(type)
+ {
+ case FtbPackType::Public:
+ return tr("Public Modpack");
+ case FtbPackType::ThirdParty:
+ return tr("Third Party Modpack");
+ case FtbPackType::Private:
+ return tr("Private Modpack");
+ }
+ qWarning() << "Unknown FTB modpack type:" << int(type);
+ return QString();
}
int FtbListModel::rowCount(const QModelIndex &parent) const
{
- return modpacks.size();
+ return modpacks.size();
}
int FtbListModel::columnCount(const QModelIndex &parent) const
{
- return 1;
+ return 1;
}
QVariant FtbListModel::data(const QModelIndex &index, int role) const
{
- int pos = index.row();
- if(pos >= modpacks.size() || pos < 0 || !index.isValid()) {
- return QString("INVALID INDEX %1").arg(pos);
- }
-
- FtbModpack pack = modpacks.at(pos);
- if(role == Qt::DisplayRole) {
- return pack.name + "\n" + translatePackType(pack.type);
- } else if (role == Qt::ToolTipRole) {
- if(pack.description.length() > 100) {
- //some magic to prevent to long tooltips and replace html linebreaks
- QString edit = pack.description.left(97);
- edit = edit.left(edit.lastIndexOf("<br>")).left(edit.lastIndexOf(" ")).append("...");
- return edit;
-
- }
- return pack.description;
- } else if(role == Qt::DecorationRole) {
- if(m_logoMap.contains(pack.logo)) {
- return (m_logoMap.value(pack.logo));
- }
- QIcon icon = MMC->getThemedIcon("screenshot-placeholder");
- ((FtbListModel *)this)->requestLogo(pack.logo);
- return icon;
- } else if(role == Qt::TextColorRole) {
- if(pack.broken) {
- //FIXME: Hardcoded color
- return QColor(255, 0, 50);
- } else if(pack.bugged) {
- //FIXME: Hardcoded color
- //bugged pack, currently only indicates bugged xml
- return QColor(244, 229, 66);
- }
- } else if(role == Qt::UserRole) {
- QVariant v;
- v.setValue(pack);
- return v;
- }
-
- return QVariant();
+ int pos = index.row();
+ if(pos >= modpacks.size() || pos < 0 || !index.isValid())
+ {
+ return QString("INVALID INDEX %1").arg(pos);
+ }
+
+ FtbModpack pack = modpacks.at(pos);
+ if(role == Qt::DisplayRole)
+ {
+ return pack.name + "\n" + translatePackType(pack.type);
+ }
+ else if (role == Qt::ToolTipRole)
+ {
+ if(pack.description.length() > 100)
+ {
+ //some magic to prevent to long tooltips and replace html linebreaks
+ QString edit = pack.description.left(97);
+ edit = edit.left(edit.lastIndexOf("<br>")).left(edit.lastIndexOf(" ")).append("...");
+ return edit;
+
+ }
+ return pack.description;
+ }
+ else if(role == Qt::DecorationRole)
+ {
+ if(m_logoMap.contains(pack.logo))
+ {
+ return (m_logoMap.value(pack.logo));
+ }
+ QIcon icon = MMC->getThemedIcon("screenshot-placeholder");
+ ((FtbListModel *)this)->requestLogo(pack.logo);
+ return icon;
+ }
+ else if(role == Qt::TextColorRole)
+ {
+ if(pack.broken)
+ {
+ //FIXME: Hardcoded color
+ return QColor(255, 0, 50);
+ }
+ else if(pack.bugged)
+ {
+ //FIXME: Hardcoded color
+ //bugged pack, currently only indicates bugged xml
+ return QColor(244, 229, 66);
+ }
+ }
+ else if(role == Qt::UserRole)
+ {
+ QVariant v;
+ v.setValue(pack);
+ return v;
+ }
+
+ return QVariant();
}
void FtbListModel::fill(FtbModpackList modpacks)
{
- beginResetModel();
- this->modpacks = modpacks;
- endResetModel();
+ beginResetModel();
+ this->modpacks = modpacks;
+ endResetModel();
+}
+
+void FtbListModel::addPack(FtbModpack modpack)
+{
+ beginResetModel();
+ this->modpacks.append(modpack);
+ endResetModel();
+}
+
+void FtbListModel::clear()
+{
+ beginResetModel();
+ modpacks.clear();
+ endResetModel();
}
FtbModpack FtbListModel::at(int row)
{
- return modpacks.at(row);
+ return modpacks.at(row);
+}
+
+void FtbListModel::remove(int row)
+{
+ if(row < 0 || row >= modpacks.size())
+ {
+ qWarning() << "Attempt to remove FTB modpacks with invalid row" << row;
+ return;
+ }
+ beginRemoveRows(QModelIndex(), row, row);
+ modpacks.removeAt(row);
+ endRemoveRows();
}
void FtbListModel::logoLoaded(QString logo, QIcon out)
{
- m_loadingLogos.removeAll(logo);
- m_logoMap.insert(logo, out);
- emit dataChanged(createIndex(0, 0), createIndex(1, 0));
+ m_loadingLogos.removeAll(logo);
+ m_logoMap.insert(logo, out);
+ emit dataChanged(createIndex(0, 0), createIndex(1, 0));
}
void FtbListModel::logoFailed(QString logo)
{
- m_failedLogos.append(logo);
- m_loadingLogos.removeAll(logo);
+ m_failedLogos.append(logo);
+ m_loadingLogos.removeAll(logo);
}
void FtbListModel::requestLogo(QString file)
{
- if(m_loadingLogos.contains(file) || m_failedLogos.contains(file)) {
- return;
- }
-
- MetaEntryPtr entry = ENV.metacache()->resolveEntry("FTBPacks", QString("logos/%1").arg(file.section(".", 0, 0)));
- NetJob *job = new NetJob(QString("FTB Icon Download for %1").arg(file));
- job->addNetAction(Net::Download::makeCached(QUrl(QString("https://ftb.cursecdn.com/FTB2/static/%1").arg(file)), entry));
-
- auto fullPath = entry->getFullPath();
- QObject::connect(job, &NetJob::finished, this, [this, file, fullPath]{
- emit logoLoaded(file, QIcon(fullPath));
- if(waitingCallbacks.contains(file)) {
- waitingCallbacks.value(file)(fullPath);
- }
- });
-
- QObject::connect(job, &NetJob::failed, this, [this, file]{
- emit logoFailed(file);
- });
-
- job->start();
-
- m_loadingLogos.append(file);
+ if(m_loadingLogos.contains(file) || m_failedLogos.contains(file))
+ {
+ return;
+ }
+
+ MetaEntryPtr entry = ENV.metacache()->resolveEntry("FTBPacks", QString("logos/%1").arg(file.section(".", 0, 0)));
+ NetJob *job = new NetJob(QString("FTB Icon Download for %1").arg(file));
+ job->addNetAction(Net::Download::makeCached(QUrl(QString(URLConstants::FTB_CDN_BASE_URL + "static/%1").arg(file)), entry));
+
+ auto fullPath = entry->getFullPath();
+ QObject::connect(job, &NetJob::finished, this, [this, file, fullPath]
+ {
+ emit logoLoaded(file, QIcon(fullPath));
+ if(waitingCallbacks.contains(file))
+ {
+ waitingCallbacks.value(file)(fullPath);
+ }
+ });
+
+ QObject::connect(job, &NetJob::failed, this, [this, file]
+ {
+ emit logoFailed(file);
+ });
+
+ job->start();
+
+ m_loadingLogos.append(file);
}
void FtbListModel::getLogo(const QString &logo, LogoCallback callback)
{
- if(m_logoMap.contains(logo)) {
- callback(ENV.metacache()->resolveEntry("FTBPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath());
- } else {
- requestLogo(logo);
- }
+ if(m_logoMap.contains(logo))
+ {
+ callback(ENV.metacache()->resolveEntry("FTBPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath());
+ }
+ else
+ {
+ requestLogo(logo);
+ }
+}
+
+Qt::ItemFlags FtbListModel::flags(const QModelIndex &index) const
+{
+ return QAbstractListModel::flags(index);
}
diff --git a/application/pages/modplatform/FtbListModel.h b/application/pages/modplatform/FtbListModel.h
index d3a82b73..34749b24 100644
--- a/application/pages/modplatform/FtbListModel.h
+++ b/application/pages/modplatform/FtbListModel.h
@@ -7,6 +7,7 @@
#include <QSortFilterProxyModel>
#include <QThreadPool>
#include <QIcon>
+#include <QStyledItemDelegate>
#include <functional>
@@ -15,54 +16,59 @@ typedef std::function<void(QString)> LogoCallback;
class FtbFilterModel : public QSortFilterProxyModel
{
+ Q_OBJECT
public:
- FtbFilterModel(QObject* parent = Q_NULLPTR);
- enum Sorting {
- ByName,
- ByGameVersion
- };
- const QMap<QString, Sorting> getAvailableSortings();
- QString translateCurrentSorting();
- void setSorting(Sorting sorting);
- Sorting getCurrentSorting();
+ FtbFilterModel(QObject* parent = Q_NULLPTR);
+ enum Sorting {
+ ByName,
+ ByGameVersion
+ };
+ const QMap<QString, Sorting> getAvailableSortings();
+ QString translateCurrentSorting();
+ void setSorting(Sorting sorting);
+ Sorting getCurrentSorting();
protected:
- bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
- bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
+ bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
+ bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
private:
- QMap<QString, Sorting> sortings;
- Sorting currentSorting;
+ QMap<QString, Sorting> sortings;
+ Sorting currentSorting;
};
class FtbListModel : public QAbstractListModel
{
- Q_OBJECT
+ Q_OBJECT
private:
- FtbModpackList modpacks;
- QStringList m_failedLogos;
- QStringList m_loadingLogos;
- FtbLogoMap m_logoMap;
- QMap<QString, LogoCallback> waitingCallbacks;
+ FtbModpackList modpacks;
+ QStringList m_failedLogos;
+ QStringList m_loadingLogos;
+ FtbLogoMap m_logoMap;
+ QMap<QString, LogoCallback> waitingCallbacks;
- void requestLogo(QString file);
- QString translatePackType(FtbPackType type) const;
+ void requestLogo(QString file);
+ QString translatePackType(FtbPackType type) const;
private slots:
- void logoFailed(QString logo);
- void logoLoaded(QString logo, QIcon out);
+ void logoFailed(QString logo);
+ void logoLoaded(QString logo, QIcon out);
public:
- FtbListModel(QObject *parent);
- ~FtbListModel();
- int rowCount(const QModelIndex &parent) const override;
- int columnCount(const QModelIndex &parent) const override;
- QVariant data(const QModelIndex &index, int role) const override;
+ FtbListModel(QObject *parent);
+ ~FtbListModel();
+ int rowCount(const QModelIndex &parent) const override;
+ int columnCount(const QModelIndex &parent) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+ Qt::ItemFlags flags(const QModelIndex &index) const override;
- void fill(FtbModpackList modpacks);
+ void fill(FtbModpackList modpacks);
+ void addPack(FtbModpack modpack);
+ void clear();
+ void remove(int row);
- FtbModpack at(int row);
- void getLogo(const QString &logo, LogoCallback callback);
+ FtbModpack at(int row);
+ void getLogo(const QString &logo, LogoCallback callback);
};
diff --git a/application/pages/modplatform/ImportPage.cpp b/application/pages/modplatform/ImportPage.cpp
index 75a51245..af243511 100644
--- a/application/pages/modplatform/ImportPage.cpp
+++ b/application/pages/modplatform/ImportPage.cpp
@@ -2,11 +2,9 @@
#include "ui_ImportPage.h"
#include "MultiMC.h"
-#include "FolderInstanceProvider.h"
-#include "dialogs/CustomMessageBox.h"
-#include "dialogs/ProgressDialog.h"
#include "dialogs/NewInstanceDialog.h"
#include <QFileDialog>
+#include <QValidator>
#include <InstanceImportTask.h>
#include <QTabBar>
#include <QValidator>
@@ -14,114 +12,119 @@
class UrlValidator : public QValidator
{
public:
- using QValidator::QValidator;
+ using QValidator::QValidator;
- State validate(QString &in, int &pos) const
- {
- const QUrl url(in);
- if (url.isValid() && !url.isRelative() && !url.isEmpty())
- {
- return Acceptable;
- }
- else if (QFile::exists(in))
- {
- return Acceptable;
- }
- else
- {
- return Intermediate;
- }
- }
+ State validate(QString &in, int &pos) const
+ {
+ const QUrl url(in);
+ if (url.isValid() && !url.isRelative() && !url.isEmpty())
+ {
+ return Acceptable;
+ }
+ else if (QFile::exists(in))
+ {
+ return Acceptable;
+ }
+ else
+ {
+ return Intermediate;
+ }
+ }
};
ImportPage::ImportPage(NewInstanceDialog* dialog, QWidget *parent)
- : QWidget(parent), ui(new Ui::ImportPage), dialog(dialog)
+ : QWidget(parent), ui(new Ui::ImportPage), dialog(dialog)
{
- ui->setupUi(this);
- ui->modpackEdit->setValidator(new UrlValidator(ui->modpackEdit));
- connect(ui->modpackEdit, &QLineEdit::textChanged, this, &ImportPage::updateState);
+ ui->setupUi(this);
+ ui->modpackEdit->setValidator(new UrlValidator(ui->modpackEdit));
+ connect(ui->modpackEdit, &QLineEdit::textChanged, this, &ImportPage::updateState);
}
ImportPage::~ImportPage()
{
- delete ui;
+ delete ui;
}
bool ImportPage::shouldDisplay() const
{
- return true;
+ return true;
}
void ImportPage::openedImpl()
{
- updateState();
+ updateState();
}
void ImportPage::updateState()
{
- if(!isOpened)
- {
- return;
- }
- if(ui->modpackEdit->hasAcceptableInput())
- {
- QString input = ui->modpackEdit->text();
- auto url = QUrl::fromUserInput(input);
- if(url.isLocalFile())
- {
- // FIXME: actually do some validation of what's inside here... this is fake AF
- QFileInfo fi(input);
- if(fi.exists() && fi.suffix() == "zip")
- {
- QFileInfo fi(url.fileName());
- dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url));
- }
- }
- else
- {
- // hook, line and sinker.
- QFileInfo fi(url.fileName());
- dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url));
- }
- }
- else
- {
- dialog->setSuggestedPack();
- }
+ if(!isOpened)
+ {
+ return;
+ }
+ if(ui->modpackEdit->hasAcceptableInput())
+ {
+ QString input = ui->modpackEdit->text();
+ auto url = QUrl::fromUserInput(input);
+ if(url.isLocalFile())
+ {
+ // FIXME: actually do some validation of what's inside here... this is fake AF
+ QFileInfo fi(input);
+ if(fi.exists() && fi.suffix() == "zip")
+ {
+ QFileInfo fi(url.fileName());
+ dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url));
+ }
+ }
+ else
+ {
+ if(input.endsWith("?client=y")) {
+ input.chop(9);
+ input.append("/file");
+ url = QUrl::fromUserInput(input);
+ }
+ // hook, line and sinker.
+ QFileInfo fi(url.fileName());
+ dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url));
+ }
+ }
+ else
+ {
+ dialog->setSuggestedPack();
+ }
}
void ImportPage::setUrl(const QString& url)
{
- ui->modpackEdit->setText(url);
- updateState();
+ ui->modpackEdit->setText(url);
+ updateState();
}
void ImportPage::on_modpackBtn_clicked()
{
- const QUrl url = QFileDialog::getOpenFileUrl(this, tr("Choose modpack"), modpackUrl(), tr("Zip (*.zip)"));
- if (url.isValid())
- {
- if (url.isLocalFile())
- {
- ui->modpackEdit->setText(url.toLocalFile());
- }
- else
- {
- ui->modpackEdit->setText(url.toString());
- }
- }
+ const QUrl url = QFileDialog::getOpenFileUrl(this, tr("Choose modpack"), modpackUrl(), tr("Zip (*.zip)"));
+ if (url.isValid())
+ {
+ if (url.isLocalFile())
+ {
+ ui->modpackEdit->setText(url.toLocalFile());
+ }
+ else
+ {
+ ui->modpackEdit->setText(url.toString());
+ }
+ }
}
QUrl ImportPage::modpackUrl() const
{
- const QUrl url(ui->modpackEdit->text());
- if (url.isValid() && !url.isRelative() && !url.host().isEmpty())
- {
- return url;
- }
- else
- {
- return QUrl::fromLocalFile(ui->modpackEdit->text());
- }
+ const QUrl url(ui->modpackEdit->text());
+ if (url.isValid() && !url.isRelative() && !url.host().isEmpty())
+ {
+ return url;
+ }
+ else
+ {
+ return QUrl::fromLocalFile(ui->modpackEdit->text());
+ }
}
diff --git a/application/pages/modplatform/ImportPage.h b/application/pages/modplatform/ImportPage.h
index 8f62e6b1..3afb0045 100644
--- a/application/pages/modplatform/ImportPage.h
+++ b/application/pages/modplatform/ImportPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,41 +30,41 @@ class NewInstanceDialog;
class ImportPage : public QWidget, public BasePage
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit ImportPage(NewInstanceDialog* dialog, QWidget *parent = 0);
- virtual ~ImportPage();
- virtual QString displayName() const override
- {
- return tr("Import from zip");
- }
- virtual QIcon icon() const override
- {
- return MMC->getThemedIcon("viewfolder");
- }
- virtual QString id() const override
- {
- return "import";
- }
- virtual QString helpPage() const override
- {
- return "Zip-import";
- }
- virtual bool shouldDisplay() const override;
+ explicit ImportPage(NewInstanceDialog* dialog, QWidget *parent = 0);
+ virtual ~ImportPage();
+ virtual QString displayName() const override
+ {
+ return tr("Import from zip");
+ }
+ virtual QIcon icon() const override
+ {
+ return MMC->getThemedIcon("viewfolder");
+ }
+ virtual QString id() const override
+ {
+ return "import";
+ }
+ virtual QString helpPage() const override
+ {
+ return "Zip-import";
+ }
+ virtual bool shouldDisplay() const override;
- void setUrl(const QString & url);
- void openedImpl() override;
+ void setUrl(const QString & url);
+ void openedImpl() override;
private slots:
- void on_modpackBtn_clicked();
- void updateState();
+ void on_modpackBtn_clicked();
+ void updateState();
private:
- QUrl modpackUrl() const;
+ QUrl modpackUrl() const;
private:
- Ui::ImportPage *ui = nullptr;
- NewInstanceDialog* dialog = nullptr;
+ Ui::ImportPage *ui = nullptr;
+ NewInstanceDialog* dialog = nullptr;
};
diff --git a/application/pages/modplatform/TechnicPage.cpp b/application/pages/modplatform/TechnicPage.cpp
index c0f4faa5..2f95bec8 100644
--- a/application/pages/modplatform/TechnicPage.cpp
+++ b/application/pages/modplatform/TechnicPage.cpp
@@ -2,28 +2,25 @@
#include "ui_TechnicPage.h"
#include "MultiMC.h"
-#include "FolderInstanceProvider.h"
-#include "dialogs/CustomMessageBox.h"
-#include "dialogs/ProgressDialog.h"
#include "dialogs/NewInstanceDialog.h"
TechnicPage::TechnicPage(NewInstanceDialog* dialog, QWidget *parent)
- : QWidget(parent), ui(new Ui::TechnicPage), dialog(dialog)
+ : QWidget(parent), ui(new Ui::TechnicPage), dialog(dialog)
{
- ui->setupUi(this);
+ ui->setupUi(this);
}
TechnicPage::~TechnicPage()
{
- delete ui;
+ delete ui;
}
bool TechnicPage::shouldDisplay() const
{
- return true;
+ return true;
}
void TechnicPage::openedImpl()
{
- dialog->setSuggestedPack();
+ dialog->setSuggestedPack();
}
diff --git a/application/pages/modplatform/TechnicPage.h b/application/pages/modplatform/TechnicPage.h
index 5b0f16a6..cc82ddf3 100644
--- a/application/pages/modplatform/TechnicPage.h
+++ b/application/pages/modplatform/TechnicPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,32 +30,32 @@ class NewInstanceDialog;
class TechnicPage : public QWidget, public BasePage
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit TechnicPage(NewInstanceDialog* dialog, QWidget *parent = 0);
- virtual ~TechnicPage();
- virtual QString displayName() const override
- {
- return tr("Technic");
- }
- virtual QIcon icon() const override
- {
- return MMC->getThemedIcon("technic");
- }
- virtual QString id() const override
- {
- return "technic";
- }
- virtual QString helpPage() const override
- {
- return "Technic-platform";
- }
- virtual bool shouldDisplay() const override;
-
- void openedImpl() override;
+ explicit TechnicPage(NewInstanceDialog* dialog, QWidget *parent = 0);
+ virtual ~TechnicPage();
+ virtual QString displayName() const override
+ {
+ return tr("Technic");
+ }
+ virtual QIcon icon() const override
+ {
+ return MMC->getThemedIcon("technic");
+ }
+ virtual QString id() const override
+ {
+ return "technic";
+ }
+ virtual QString helpPage() const override
+ {
+ return "Technic-platform";
+ }
+ virtual bool shouldDisplay() const override;
+
+ void openedImpl() override;
private:
- Ui::TechnicPage *ui = nullptr;
- NewInstanceDialog* dialog = nullptr;
+ Ui::TechnicPage *ui = nullptr;
+ NewInstanceDialog* dialog = nullptr;
};
diff --git a/application/pages/modplatform/TwitchPage.cpp b/application/pages/modplatform/TwitchPage.cpp
index 42aa46be..ea0f9267 100644
--- a/application/pages/modplatform/TwitchPage.cpp
+++ b/application/pages/modplatform/TwitchPage.cpp
@@ -2,28 +2,59 @@
#include "ui_TwitchPage.h"
#include "MultiMC.h"
-#include "FolderInstanceProvider.h"
-#include "dialogs/CustomMessageBox.h"
-#include "dialogs/ProgressDialog.h"
#include "dialogs/NewInstanceDialog.h"
+#include <InstanceImportTask.h>
TwitchPage::TwitchPage(NewInstanceDialog* dialog, QWidget *parent)
- : QWidget(parent), ui(new Ui::TwitchPage), dialog(dialog)
+ : QWidget(parent), ui(new Ui::TwitchPage), dialog(dialog)
{
- ui->setupUi(this);
+ ui->setupUi(this);
+ connect(ui->checkButton, &QPushButton::clicked, this, &TwitchPage::triggerCheck);
}
TwitchPage::~TwitchPage()
{
- delete ui;
+ delete ui;
}
bool TwitchPage::shouldDisplay() const
{
- return false;
+ return true;
}
void TwitchPage::openedImpl()
{
- dialog->setSuggestedPack();
+ dialog->setSuggestedPack();
+}
+
+void TwitchPage::triggerCheck(bool)
+{
+ if(m_modIdResolver) {
+ return;
+ }
+ auto task = new Flame::UrlResolvingTask(ui->lineEdit->text());
+ connect(task, &Task::finished, this, &TwitchPage::checkDone);
+ m_modIdResolver.reset(task);
+ task->start();
+}
+
+void TwitchPage::setUrl(const QString& url)
+{
+ ui->lineEdit->setText(url);
+ triggerCheck(true);
+}
+
+void TwitchPage::checkDone()
+{
+ auto result = m_modIdResolver->getResults();
+ auto formatted = QString("Project %1, File %2").arg(result.projectId).arg(result.fileId);
+ if(result.resolved && result.type == Flame::File::Type::Modpack) {
+ ui->twitchLabel->setText(formatted);
+ QFileInfo fi(result.fileName);
+ dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(result.url));
+ } else {
+ ui->twitchLabel->setPixmap(QPixmap(QString::fromUtf8(":/assets/deadglitch")));
+ dialog->setSuggestedPack();
+ }
+ m_modIdResolver.reset();
}
diff --git a/application/pages/modplatform/TwitchPage.h b/application/pages/modplatform/TwitchPage.h
index 8e072917..600913cd 100644
--- a/application/pages/modplatform/TwitchPage.h
+++ b/application/pages/modplatform/TwitchPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
#include "pages/BasePage.h"
#include <MultiMC.h>
#include "tasks/Task.h"
+#include "modplatform/flame/UrlResolvingTask.h"
namespace Ui
{
@@ -30,32 +31,39 @@ class NewInstanceDialog;
class TwitchPage : public QWidget, public BasePage
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit TwitchPage(NewInstanceDialog* dialog, QWidget *parent = 0);
- virtual ~TwitchPage();
- virtual QString displayName() const override
- {
- return tr("Twitch");
- }
- virtual QIcon icon() const override
- {
- return MMC->getThemedIcon("twitch");
- }
- virtual QString id() const override
- {
- return "twitch";
- }
- virtual QString helpPage() const override
- {
- return "Twitch-platform";
- }
- virtual bool shouldDisplay() const override;
-
- void openedImpl() override;
+ explicit TwitchPage(NewInstanceDialog* dialog, QWidget *parent = 0);
+ virtual ~TwitchPage();
+ virtual QString displayName() const override
+ {
+ return tr("Twitch URL");
+ }
+ virtual QIcon icon() const override
+ {
+ return MMC->getThemedIcon("twitch");
+ }
+ virtual QString id() const override
+ {
+ return "twitch";
+ }
+ virtual QString helpPage() const override
+ {
+ return "Twitch-platform";
+ }
+ virtual bool shouldDisplay() const override;
+
+ void openedImpl() override;
+
+ void setUrl(const QString & url);
+
+private slots:
+ void triggerCheck(bool checked);
+ void checkDone();
private:
- Ui::TwitchPage *ui = nullptr;
- NewInstanceDialog* dialog = nullptr;
+ Ui::TwitchPage *ui = nullptr;
+ NewInstanceDialog* dialog = nullptr;
+ shared_qobject_ptr<Flame::UrlResolvingTask> m_modIdResolver;
};
diff --git a/application/pages/modplatform/TwitchPage.ui b/application/pages/modplatform/TwitchPage.ui
index 0930f541..0db2484d 100644
--- a/application/pages/modplatform/TwitchPage.ui
+++ b/application/pages/modplatform/TwitchPage.ui
@@ -10,9 +10,25 @@
<height>405</height>
</rect>
</property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QLabel" name="label_3">
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="lineEdit"/>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Twitch URL:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="3">
+ <widget class="QLabel" name="twitchLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
<property name="font">
<font>
<pointsize>40</pointsize>
@@ -26,8 +42,19 @@
</property>
</widget>
</item>
+ <item row="0" column="2">
+ <widget class="QPushButton" name="checkButton">
+ <property name="text">
+ <string>Check</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
+ <tabstops>
+ <tabstop>lineEdit</tabstop>
+ <tabstop>checkButton</tabstop>
+ </tabstops>
<resources>
<include location="../../resources/assets/assets.qrc"/>
</resources>
diff --git a/application/pages/modplatform/VanillaPage.cpp b/application/pages/modplatform/VanillaPage.cpp
index c355fccb..17535f1e 100644
--- a/application/pages/modplatform/VanillaPage.cpp
+++ b/application/pages/modplatform/VanillaPage.cpp
@@ -2,9 +2,6 @@
#include "ui_VanillaPage.h"
#include "MultiMC.h"
-#include "FolderInstanceProvider.h"
-#include "dialogs/CustomMessageBox.h"
-#include "dialogs/ProgressDialog.h"
#include <meta/Index.h>
#include <meta/VersionList.h>
@@ -15,81 +12,84 @@
#include <QTabBar>
VanillaPage::VanillaPage(NewInstanceDialog *dialog, QWidget *parent)
- : QWidget(parent), dialog(dialog), ui(new Ui::VanillaPage)
+ : QWidget(parent), dialog(dialog), ui(new Ui::VanillaPage)
{
- ui->setupUi(this);
- ui->tabWidget->tabBar()->hide();
- connect(ui->versionList, &VersionSelectWidget::selectedVersionChanged, this, &VanillaPage::setSelectedVersion);
- filterChanged();
- connect(ui->alphaFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged);
- connect(ui->betaFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged);
- connect(ui->snapshotFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged);
- connect(ui->oldSnapshotFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged);
- connect(ui->releaseFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged);
- connect(ui->refreshBtn, &QPushButton::clicked, this, &VanillaPage::refresh);
+ ui->setupUi(this);
+ ui->tabWidget->tabBar()->hide();
+ connect(ui->versionList, &VersionSelectWidget::selectedVersionChanged, this, &VanillaPage::setSelectedVersion);
+ filterChanged();
+ connect(ui->alphaFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged);
+ connect(ui->betaFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged);
+ connect(ui->snapshotFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged);
+ connect(ui->oldSnapshotFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged);
+ connect(ui->releaseFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged);
+ connect(ui->experimentsFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged);
+ connect(ui->refreshBtn, &QPushButton::clicked, this, &VanillaPage::refresh);
}
void VanillaPage::openedImpl()
{
- if(!initialized)
- {
- auto vlist = ENV.metadataIndex()->get("net.minecraft");
- ui->versionList->initialize(vlist.get());
- initialized = true;
- }
- else
- {
- suggestCurrent();
- }
+ if(!initialized)
+ {
+ auto vlist = ENV.metadataIndex()->get("net.minecraft");
+ ui->versionList->initialize(vlist.get());
+ initialized = true;
+ }
+ else
+ {
+ suggestCurrent();
+ }
}
void VanillaPage::refresh()
{
- ui->versionList->loadList();
+ ui->versionList->loadList();
}
void VanillaPage::filterChanged()
{
- QStringList out;
- if(ui->alphaFilter->isChecked())
- out << "(old_alpha)";
- if(ui->betaFilter->isChecked())
- out << "(old_beta)";
- if(ui->snapshotFilter->isChecked())
- out << "(snapshot)";
- if(ui->oldSnapshotFilter->isChecked())
- out << "(old_snapshot)";
- if(ui->releaseFilter->isChecked())
- out << "(release)";
- auto regexp = out.join('|');
- ui->versionList->setFilter(BaseVersionList::TypeRole, new RegexpFilter(regexp, false));
+ QStringList out;
+ if(ui->alphaFilter->isChecked())
+ out << "(old_alpha)";
+ if(ui->betaFilter->isChecked())
+ out << "(old_beta)";
+ if(ui->snapshotFilter->isChecked())
+ out << "(snapshot)";
+ if(ui->oldSnapshotFilter->isChecked())
+ out << "(old_snapshot)";
+ if(ui->releaseFilter->isChecked())
+ out << "(release)";
+ if(ui->experimentsFilter->isChecked())
+ out << "(experiment)";
+ auto regexp = out.join('|');
+ ui->versionList->setFilter(BaseVersionList::TypeRole, new RegexpFilter(regexp, false));
}
VanillaPage::~VanillaPage()
{
- delete ui;
+ delete ui;
}
bool VanillaPage::shouldDisplay() const
{
- return true;
+ return true;
}
BaseVersionPtr VanillaPage::selectedVersion() const
{
- return m_selectedVersion;
+ return m_selectedVersion;
}
void VanillaPage::suggestCurrent()
{
- if(m_selectedVersion && isOpened)
- {
- dialog->setSuggestedPack(m_selectedVersion->descriptor(), new InstanceCreationTask(m_selectedVersion));
- }
+ if(m_selectedVersion && isOpened)
+ {
+ dialog->setSuggestedPack(m_selectedVersion->descriptor(), new InstanceCreationTask(m_selectedVersion));
+ }
}
void VanillaPage::setSelectedVersion(BaseVersionPtr version)
{
- m_selectedVersion = version;
- suggestCurrent();
+ m_selectedVersion = version;
+ suggestCurrent();
}
diff --git a/application/pages/modplatform/VanillaPage.h b/application/pages/modplatform/VanillaPage.h
index 91c65edf..cc77733c 100644
--- a/application/pages/modplatform/VanillaPage.h
+++ b/application/pages/modplatform/VanillaPage.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,46 +30,46 @@ class NewInstanceDialog;
class VanillaPage : public QWidget, public BasePage
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit VanillaPage(NewInstanceDialog *dialog, QWidget *parent = 0);
- virtual ~VanillaPage();
- virtual QString displayName() const override
- {
- return tr("Vanilla");
- }
- virtual QIcon icon() const override
- {
- return MMC->getThemedIcon("minecraft");
- }
- virtual QString id() const override
- {
- return "vanilla";
- }
- virtual QString helpPage() const override
- {
- return "Vanilla-platform";
- }
- virtual bool shouldDisplay() const override;
- void openedImpl() override;
+ explicit VanillaPage(NewInstanceDialog *dialog, QWidget *parent = 0);
+ virtual ~VanillaPage();
+ virtual QString displayName() const override
+ {
+ return tr("Vanilla");
+ }
+ virtual QIcon icon() const override
+ {
+ return MMC->getThemedIcon("minecraft");
+ }
+ virtual QString id() const override
+ {
+ return "vanilla";
+ }
+ virtual QString helpPage() const override
+ {
+ return "Vanilla-platform";
+ }
+ virtual bool shouldDisplay() const override;
+ void openedImpl() override;
- BaseVersionPtr selectedVersion() const;
+ BaseVersionPtr selectedVersion() const;
public slots:
- void setSelectedVersion(BaseVersionPtr version);
+ void setSelectedVersion(BaseVersionPtr version);
private slots:
- void filterChanged();
+ void filterChanged();
private:
- void refresh();
- void suggestCurrent();
+ void refresh();
+ void suggestCurrent();
private:
- bool initialized = false;
- NewInstanceDialog *dialog = nullptr;
- Ui::VanillaPage *ui = nullptr;
- bool m_versionSetByUser = false;
- BaseVersionPtr m_selectedVersion;
+ bool initialized = false;
+ NewInstanceDialog *dialog = nullptr;
+ Ui::VanillaPage *ui = nullptr;
+ bool m_versionSetByUser = false;
+ BaseVersionPtr m_selectedVersion;
};
diff --git a/application/pages/modplatform/VanillaPage.ui b/application/pages/modplatform/VanillaPage.ui
index ae9cab47..47effc86 100644
--- a/application/pages/modplatform/VanillaPage.ui
+++ b/application/pages/modplatform/VanillaPage.ui
@@ -99,6 +99,16 @@
</widget>
</item>
<item>
+ <widget class="QCheckBox" name="experimentsFilter">
+ <property name="text">
+ <string>Experiments</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -144,6 +154,16 @@
<container>1</container>
</customwidget>
</customwidgets>
+ <tabstops>
+ <tabstop>tabWidget</tabstop>
+ <tabstop>releaseFilter</tabstop>
+ <tabstop>snapshotFilter</tabstop>
+ <tabstop>oldSnapshotFilter</tabstop>
+ <tabstop>betaFilter</tabstop>
+ <tabstop>alphaFilter</tabstop>
+ <tabstop>experimentsFilter</tabstop>
+ <tabstop>refreshBtn</tabstop>
+ </tabstops>
<resources/>
<connections/>
</ui>
diff --git a/application/resources/OSX/OSX.qrc b/application/resources/OSX/OSX.qrc
index a7d7be17..19fd4b6a 100644
--- a/application/resources/OSX/OSX.qrc
+++ b/application/resources/OSX/OSX.qrc
@@ -1,37 +1,38 @@
<!DOCTYPE RCC>
<RCC version="1.0">
- <qresource prefix="/icons/OSX">
- <file>index.theme</file>
- <file>scalable/about.svg</file>
- <file>scalable/accounts.svg</file>
- <file>scalable/bug.svg</file>
- <file>scalable/centralmods.svg</file>
- <file>scalable/checkupdate.svg</file>
- <file>scalable/copy.svg</file>
- <file>scalable/coremods.svg</file>
- <file>scalable/externaltools.svg</file>
- <file>scalable/help.svg</file>
+ <qresource prefix="/icons/OSX">
+ <file>index.theme</file>
+ <file>scalable/about.svg</file>
+ <file>scalable/accounts.svg</file>
+ <file>scalable/bug.svg</file>
+ <file>scalable/centralmods.svg</file>
+ <file>scalable/checkupdate.svg</file>
+ <file>scalable/copy.svg</file>
+ <file>scalable/coremods.svg</file>
+ <file>scalable/externaltools.svg</file>
+ <file>scalable/help.svg</file>
<file>scalable/instance-settings.svg</file>
- <file>scalable/jarmods.svg</file>
- <file>scalable/java.svg</file>
- <file>scalable/loadermods.svg</file>
- <file>scalable/log.svg</file>
- <file>scalable/minecraft.svg</file>
- <file>scalable/multimc.svg</file>
- <file>scalable/new.svg</file>
- <file>scalable/news.svg</file>
- <file>scalable/notes.svg</file>
- <file>scalable/patreon.svg</file>
- <file>scalable/proxy.svg</file>
- <file>scalable/quickmods.svg</file>
- <file>scalable/refresh.svg</file>
- <file>scalable/resourcepacks.svg</file>
- <file>scalable/screenshots.svg</file>
- <file>scalable/settings.svg</file>
- <file>scalable/status-bad.svg</file>
- <file>scalable/status-good.svg</file>
- <file>scalable/status-yellow.svg</file>
- <file>scalable/viewfolder.svg</file>
- <file>scalable/worlds.svg</file>
- </qresource>
+ <file>scalable/jarmods.svg</file>
+ <file>scalable/java.svg</file>
+ <file>scalable/language.svg</file>
+ <file>scalable/loadermods.svg</file>
+ <file>scalable/log.svg</file>
+ <file>scalable/minecraft.svg</file>
+ <file>scalable/multimc.svg</file>
+ <file>scalable/new.svg</file>
+ <file>scalable/news.svg</file>
+ <file>scalable/notes.svg</file>
+ <file>scalable/patreon.svg</file>
+ <file>scalable/proxy.svg</file>
+ <file>scalable/quickmods.svg</file>
+ <file>scalable/refresh.svg</file>
+ <file>scalable/resourcepacks.svg</file>
+ <file>scalable/screenshots.svg</file>
+ <file>scalable/settings.svg</file>
+ <file>scalable/status-bad.svg</file>
+ <file>scalable/status-good.svg</file>
+ <file>scalable/status-yellow.svg</file>
+ <file>scalable/viewfolder.svg</file>
+ <file>scalable/worlds.svg</file>
+ </qresource>
</RCC>
diff --git a/application/resources/OSX/scalable/language.svg b/application/resources/OSX/scalable/language.svg
new file mode 100644
index 00000000..4f7d002a
--- /dev/null
+++ b/application/resources/OSX/scalable/language.svg
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ id="Calque_1"
+ x="0px"
+ y="0px"
+ viewBox="0 0 24 24"
+ enable-background="new 0 0 24 24"
+ xml:space="preserve"><metadata
+ id="metadata22"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+ id="defs20" /><path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ fill="#E6E6E6"
+ d="M21,20H9c-1.1,0-2-0.9-2-2V6c0-1.1,0.9-2,2-2h12c1.1,0,2,0.9,2,2 v12C23,19.1,22.1,20,21,20z"
+ id="path2" /><rect
+ fill="none"
+ width="24"
+ height="24"
+ id="rect4" /><g
+ id="_x36__8_"><g
+ id="g8"><path
+ d="M 21,4 H 9 C 7.9,4 7,4.9 7,6 v 12 c 0,1.1 0.9,2 2,2 h 12 c 1.1,0 2,-0.9 2,-2 V 6 C 23,4.9 22.1,4 21,4 Z m 1,14 -1,1 H 9 L 8,18 V 6 C 8,5.4 8.4,5 9,5 h 12 c 0.6,0 1,0.4 1,1 z"
+ id="path6"
+ style="fill:#585858" /></g></g><circle
+ cx="-3.8492424"
+ cy="11.559504"
+ r="1"
+ id="circle11"
+ style="clip-rule:evenodd;fill:#ffffff;fill-rule:evenodd" /><path
+ d="m 10.985086,8.5301236 c -0.285244,0 -0.531238,0.2015787 -0.587348,0.480998 L 9.2012867,14.998205 c -0.064883,0.324431 0.1450781,0.638482 0.4689122,0.703366 0.3279037,0.0672 0.6390781,-0.145078 0.7033681,-0.468911 l 0.384313,-1.91432 h 1.69195 l 0.381898,1.91432 c 0.06544,0.328662 0.388374,0.53424 0.705784,0.468911 0.323873,-0.06488 0.533795,-0.378935 0.468912,-0.703366 L 12.809973,9.0111216 c -0.05611,-0.2794193 -0.302101,-0.480998 -0.587347,-0.480998 z m 0.362559,1.3487256 h 0.256212 l 0.478579,2.3953168 h -1.21337 z m 6.429409,-1.5928481 c -0.330857,0 -0.599434,0.2698964 -0.599434,0.6018494 v 0.5994329 h -1.795884 c -0.330855,0 -0.597015,0.269898 -0.597015,0.6018506 0,0.331951 0.266159,0.599434 0.597015,0.599434 h 0.161945 c 0.340555,1.096391 0.840589,1.953495 1.401899,2.629772 -0.439717,0.403341 -0.871563,0.734012 -1.339055,1.104601 -0.25779,0.207035 -0.298799,0.58673 -0.09185,0.845975 0.205993,0.258844 0.58387,0.299404 0.841141,0.09185 0.507959,-0.402258 0.944446,-0.738141 1.421237,-1.177114 0.476792,0.438973 0.95437,0.774856 1.462328,1.177114 0.257273,0.207554 0.635147,0.166994 0.841141,-0.09185 0.206952,-0.259245 0.163525,-0.63894 -0.09426,-0.845975 -0.467495,-0.370589 -0.938012,-0.70126 -1.377731,-1.104601 0.561312,-0.676317 1.102396,-1.53342 1.442991,-2.629772 h 0.159526 c 0.330857,0 0.599433,-0.267483 0.599433,-0.599434 0,-0.3319526 -0.268576,-0.6018506 -0.599433,-0.6018506 H 18.376487 V 8.8878505 c 0,-0.331953 -0.268576,-0.6018494 -0.599433,-0.6018494 z m -0.983747,2.4025669 h 2.006168 c -0.25847,0.696576 -0.641961,1.260479 -1.022421,1.74029 -0.380459,-0.479811 -0.725279,-1.043674 -0.983747,-1.74029 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#585858;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.7126205;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect977" /></svg> \ No newline at end of file
diff --git a/application/resources/assets/assets.qrc b/application/resources/assets/assets.qrc
index 8d213387..38638e7f 100644
--- a/application/resources/assets/assets.qrc
+++ b/application/resources/assets/assets.qrc
@@ -2,6 +2,6 @@
<RCC version="1.0">
<qresource prefix="/assets">
<file alias="underconstruction">underconstruction.png</file>
- <file alias="deadglitch">deadglitch.svg</file>
+ <file alias="deadglitch">deadglitch.svg</file>
</qresource>
</RCC>
diff --git a/application/resources/backgrounds/backgrounds.qrc b/application/resources/backgrounds/backgrounds.qrc
index 55de139e..83505635 100644
--- a/application/resources/backgrounds/backgrounds.qrc
+++ b/application/resources/backgrounds/backgrounds.qrc
@@ -2,5 +2,6 @@
<RCC version="1.0">
<qresource prefix="/backgrounds">
<file alias="kitteh">catbgrnd2.png</file>
+ <file alias="catmas">catmas.png</file>
</qresource>
</RCC>
diff --git a/application/resources/backgrounds/catbgrnd2.png b/application/resources/backgrounds/catbgrnd2.png
index 2b949e0b..e9de7f27 100644
--- a/application/resources/backgrounds/catbgrnd2.png
+++ b/application/resources/backgrounds/catbgrnd2.png
Binary files differ
diff --git a/application/resources/backgrounds/catmas.png b/application/resources/backgrounds/catmas.png
new file mode 100644
index 00000000..8bdb1d5c
--- /dev/null
+++ b/application/resources/backgrounds/catmas.png
Binary files differ
diff --git a/application/resources/documents/documents.qrc b/application/resources/documents/documents.qrc
index 77fc0cf4..007efcde 100644
--- a/application/resources/documents/documents.qrc
+++ b/application/resources/documents/documents.qrc
@@ -1,7 +1,7 @@
<!DOCTYPE RCC>
<RCC version="1.0">
- <qresource prefix="/documents">
- <file>../../../COPYING.md</file>
- </qresource>
+ <qresource prefix="/documents">
+ <file>../../../COPYING.md</file>
+ </qresource>
</RCC>
diff --git a/application/resources/flat/flat.qrc b/application/resources/flat/flat.qrc
index aee2e30c..b6e2ee38 100644
--- a/application/resources/flat/flat.qrc
+++ b/application/resources/flat/flat.qrc
@@ -1,44 +1,45 @@
<!DOCTYPE RCC>
<RCC version="1.0">
- <qresource prefix="/icons/flat">
- <file>index.theme</file>
- <file>scalable/about.svg</file>
- <file>scalable/accounts.svg</file>
- <file>scalable/bug.svg</file>
- <file>scalable/cat.svg</file>
- <file>scalable/centralmods.svg</file>
- <file>scalable/checkupdate.svg</file>
- <file>scalable/copy.svg</file>
- <file>scalable/coremods.svg</file>
- <file>scalable/discord.svg</file>
- <file>scalable/externaltools.svg</file>
- <file>scalable/help.svg</file>
- <file>scalable/instance-settings.svg</file>
- <file>scalable/jarmods.svg</file>
- <file>scalable/java.svg</file>
- <file>scalable/loadermods.svg</file>
- <file>scalable/log.svg</file>
- <file>scalable/minecraft.svg</file>
- <file>scalable/multimc.svg</file>
- <file>scalable/new.svg</file>
- <file>scalable/news.svg</file>
- <file>scalable/notes.svg</file>
- <file>scalable/packages.svg</file>
- <file>scalable/patreon.svg</file>
- <file>scalable/proxy.svg</file>
- <file>scalable/quickmods.svg</file>
- <file>scalable/reddit-alien.svg</file>
- <file>scalable/refresh.svg</file>
- <file>scalable/resourcepacks.svg</file>
- <file>scalable/screenshot-placeholder.svg</file>
- <file>scalable/screenshots.svg</file>
- <file>scalable/settings.svg</file>
- <file>scalable/star.svg</file>
- <file>scalable/status-bad.svg</file>
- <file>scalable/status-good.svg</file>
- <file>scalable/status-running.svg</file>
- <file>scalable/status-yellow.svg</file>
- <file>scalable/viewfolder.svg</file>
- <file>scalable/worlds.svg</file>
- </qresource>
+ <qresource prefix="/icons/flat">
+ <file>index.theme</file>
+ <file>scalable/about.svg</file>
+ <file>scalable/accounts.svg</file>
+ <file>scalable/bug.svg</file>
+ <file>scalable/cat.svg</file>
+ <file>scalable/centralmods.svg</file>
+ <file>scalable/checkupdate.svg</file>
+ <file>scalable/copy.svg</file>
+ <file>scalable/coremods.svg</file>
+ <file>scalable/discord.svg</file>
+ <file>scalable/externaltools.svg</file>
+ <file>scalable/help.svg</file>
+ <file>scalable/instance-settings.svg</file>
+ <file>scalable/jarmods.svg</file>
+ <file>scalable/java.svg</file>
+ <file>scalable/language.svg</file>
+ <file>scalable/loadermods.svg</file>
+ <file>scalable/log.svg</file>
+ <file>scalable/minecraft.svg</file>
+ <file>scalable/multimc.svg</file>
+ <file>scalable/new.svg</file>
+ <file>scalable/news.svg</file>
+ <file>scalable/notes.svg</file>
+ <file>scalable/packages.svg</file>
+ <file>scalable/patreon.svg</file>
+ <file>scalable/proxy.svg</file>
+ <file>scalable/quickmods.svg</file>
+ <file>scalable/reddit-alien.svg</file>
+ <file>scalable/refresh.svg</file>
+ <file>scalable/resourcepacks.svg</file>
+ <file>scalable/screenshot-placeholder.svg</file>
+ <file>scalable/screenshots.svg</file>
+ <file>scalable/settings.svg</file>
+ <file>scalable/star.svg</file>
+ <file>scalable/status-bad.svg</file>
+ <file>scalable/status-good.svg</file>
+ <file>scalable/status-running.svg</file>
+ <file>scalable/status-yellow.svg</file>
+ <file>scalable/viewfolder.svg</file>
+ <file>scalable/worlds.svg</file>
+ </qresource>
</RCC>
diff --git a/application/resources/flat/scalable/language.svg b/application/resources/flat/scalable/language.svg
new file mode 100644
index 00000000..f4d3f2f4
--- /dev/null
+++ b/application/resources/flat/scalable/language.svg
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ fill="#757575"
+ height="24"
+ viewBox="0 0 24 24"
+ width="24"
+ version="1.1"
+ id="svg4"
+ sodipodi:docname="language.svg"
+ inkscape:version="0.92.2 2405546, 2018-03-11">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </defs>
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="3840"
+ inkscape:window-height="2123"
+ id="namedview6"
+ showgrid="true"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:zoom="6.9532167"
+ inkscape:cx="-18.49351"
+ inkscape:cy="-12.477971"
+ inkscape:window-x="1200"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg4">
+ <inkscape:grid
+ type="xygrid"
+ id="grid981" />
+ <sodipodi:guide
+ position="-8,11.440678"
+ orientation="1,0"
+ id="guide1060"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="-28.34375,24"
+ orientation="0,1"
+ id="guide1062"
+ inkscape:locked="false" />
+ </sodipodi:namedview>
+ <path
+ d="M 5,3 C 3.89,3 3,3.89 3,5 v 14 c 0,1.104569 0.895431,2 2,2 h 14 c 1.104569,0 2,-0.895431 2,-2 V 5 C 21,3.89 20.1,3 19,3 Z m 10.359375,4.505859 c 0.400344,0 0.726563,0.326845 0.726563,0.728516 v 0.724609 h 2.21875 c 0.400344,0 0.726562,0.326845 0.726562,0.728516 0,0.401669 -0.326217,0.726562 -0.726562,0.726562 h -0.191407 c -0.412128,1.326612 -1.066893,2.363281 -1.746093,3.181641 0.53207,0.488052 1.100334,0.887517 1.666015,1.335938 0.311924,0.250518 0.365651,0.709744 0.115235,1.023437 -0.249259,0.313205 -0.708226,0.362473 -1.019532,0.111328 -0.614642,-0.486742 -1.192601,-0.892661 -1.769531,-1.423828 -0.576929,0.531167 -1.104107,0.937086 -1.71875,1.423828 -0.311303,0.251148 -0.768322,0.201879 -1.017578,-0.111328 -0.250416,-0.313693 -0.200604,-0.772919 0.111328,-1.023437 0.565677,-0.448421 1.087072,-0.847886 1.619141,-1.335938 -0.679199,-0.818312 -1.283234,-1.854981 -1.695313,-3.181641 h -0.197265 c -0.400344,0 -0.720704,-0.324893 -0.720704,-0.726562 0,-0.401671 0.320361,-0.728516 0.720704,-0.728516 h 2.173828 V 8.234375 c 0,-0.401671 0.324264,-0.728516 0.724609,-0.728516 z M 7.142578,7.800781 h 1.496094 c 0.345155,0 0.643047,0.243927 0.710937,0.582031 l 1.447266,7.244141 c 0.07851,0.39257 -0.174512,0.773053 -0.566406,0.851563 -0.384074,0.07905 -0.774336,-0.168718 -0.853516,-0.566407 L 8.914062,13.595703 H 6.867188 L 6.402344,15.912109 C 6.324551,16.303955 5.947553,16.559826 5.550781,16.478516 5.158934,16.400005 4.905865,16.019523 4.984375,15.626953 L 6.431641,8.382812 C 6.499536,8.044708 6.797425,7.800781 7.142578,7.800781 Z m 0.4375,1.632813 -0.578125,2.898437 H 8.46875 L 7.890625,9.433594 Z m 6.589844,0.980468 c 0.312752,0.842923 0.729088,1.524886 1.189453,2.105469 0.460366,-0.580583 0.925527,-1.262594 1.238281,-2.105469 z"
+ id="path1072"
+ inkscape:connector-curvature="0" />
+ <g
+ style="fill:#000000"
+ id="g821"
+ transform="matrix(0.0322459,0,0,0.0322459,-17.878956,30.647558)">
+ <g
+ style="fill:#000000"
+ id="g819" />
+ </g>
+</svg>
diff --git a/application/resources/iOS/iOS.qrc b/application/resources/iOS/iOS.qrc
index 0cb642f4..511e390b 100644
--- a/application/resources/iOS/iOS.qrc
+++ b/application/resources/iOS/iOS.qrc
@@ -1,37 +1,38 @@
<!DOCTYPE RCC>
<RCC version="1.0">
- <qresource prefix="/icons/iOS">
- <file>index.theme</file>
- <file>scalable/about.svg</file>
- <file>scalable/accounts.svg</file>
- <file>scalable/bug.svg</file>
- <file>scalable/centralmods.svg</file>
- <file>scalable/checkupdate.svg</file>
- <file>scalable/copy.svg</file>
- <file>scalable/coremods.svg</file>
- <file>scalable/externaltools.svg</file>
- <file>scalable/help.svg</file>
- <file>scalable/instance-settings.svg</file>
- <file>scalable/jarmods.svg</file>
- <file>scalable/java.svg</file>
- <file>scalable/loadermods.svg</file>
- <file>scalable/log.svg</file>
- <file>scalable/minecraft.svg</file>
- <file>scalable/multimc.svg</file>
- <file>scalable/new.svg</file>
- <file>scalable/news.svg</file>
- <file>scalable/notes.svg</file>
- <file>scalable/patreon.svg</file>
- <file>scalable/proxy.svg</file>
- <file>scalable/quickmods.svg</file>
- <file>scalable/refresh.svg</file>
- <file>scalable/resourcepacks.svg</file>
- <file>scalable/screenshots.svg</file>
- <file>scalable/settings.svg</file>
- <file>scalable/status-bad.svg</file>
- <file>scalable/status-good.svg</file>
- <file>scalable/status-yellow.svg</file>
- <file>scalable/viewfolder.svg</file>
- <file>scalable/worlds.svg</file>
- </qresource>
+ <qresource prefix="/icons/iOS">
+ <file>index.theme</file>
+ <file>scalable/about.svg</file>
+ <file>scalable/accounts.svg</file>
+ <file>scalable/bug.svg</file>
+ <file>scalable/centralmods.svg</file>
+ <file>scalable/checkupdate.svg</file>
+ <file>scalable/copy.svg</file>
+ <file>scalable/coremods.svg</file>
+ <file>scalable/externaltools.svg</file>
+ <file>scalable/help.svg</file>
+ <file>scalable/instance-settings.svg</file>
+ <file>scalable/jarmods.svg</file>
+ <file>scalable/java.svg</file>
+ <file>scalable/language.svg</file>
+ <file>scalable/loadermods.svg</file>
+ <file>scalable/log.svg</file>
+ <file>scalable/minecraft.svg</file>
+ <file>scalable/multimc.svg</file>
+ <file>scalable/new.svg</file>
+ <file>scalable/news.svg</file>
+ <file>scalable/notes.svg</file>
+ <file>scalable/patreon.svg</file>
+ <file>scalable/proxy.svg</file>
+ <file>scalable/quickmods.svg</file>
+ <file>scalable/refresh.svg</file>
+ <file>scalable/resourcepacks.svg</file>
+ <file>scalable/screenshots.svg</file>
+ <file>scalable/settings.svg</file>
+ <file>scalable/status-bad.svg</file>
+ <file>scalable/status-good.svg</file>
+ <file>scalable/status-yellow.svg</file>
+ <file>scalable/viewfolder.svg</file>
+ <file>scalable/worlds.svg</file>
+ </qresource>
</RCC>
diff --git a/application/resources/iOS/scalable/language.svg b/application/resources/iOS/scalable/language.svg
new file mode 100644
index 00000000..fcc3436e
--- /dev/null
+++ b/application/resources/iOS/scalable/language.svg
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xml:space="preserve"
+ enable-background="new 0 0 32 32"
+ viewBox="0 0 32 32"
+ y="0px"
+ x="0px"
+ id="Calque_1"
+ version="1.1"><metadata
+ id="metadata15"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+ id="defs13" />
+<g
+ id="g8">
+
+ <path
+ id="path6"
+ d="M28,32H4c-2.2,0-4-1.8-4-4V4c0-2.2,1.8-4,4-4h24c2.2,0,4,1.8,4,4 v24C32,30.2,30.2,32,28,32z M30,4c0-1.1-0.9-2-2-2H4C2.9,2,2,2.9,2,4v24c0,1.1,0.9,2,2,2h24c1.1,0,2-0.9,2-2V4z"
+ fill="#3366CC"
+ clip-rule="evenodd"
+ fill-rule="evenodd" />
+</g>
+<path
+ d="m 8.8837922,9.8498439 c -0.5055801,0 -0.9415895,0.3572871 -1.0410421,0.8525411 L 5.7221093,21.314148 c -0.1150014,0.575036 0.2571428,1.131673 0.8311203,1.246676 0.5811915,0.119103 1.1327283,-0.257142 1.2466794,-0.831119 l 0.6811731,-3.393021 h 2.9988849 l 0.676892,3.393021 c 0.115982,0.582535 0.688371,0.946911 1.250962,0.831119 0.574046,-0.115001 0.94612,-0.67164 0.831119,-1.246676 L 12.118299,10.702385 C 12.018854,10.207131 11.582843,9.8498439 11.07726,9.8498439 Z m 0.642615,2.3905391 h 0.4541203 l 0.8482535,4.245562 H 8.6781534 Z M 20.922167,9.4171507 c -0.586426,0 -1.062464,0.4783758 -1.062464,1.0667433 v 1.062461 h -3.183102 c -0.58642,0 -1.058175,0.478378 -1.058175,1.066747 0,0.588364 0.471753,1.062461 1.058175,1.062461 h 0.28704 c 0.603613,1.943292 1.489894,3.462457 2.484785,4.661121 -0.779374,0.714899 -1.544795,1.300994 -2.373399,1.957842 -0.456918,0.366958 -0.529604,1.039945 -0.162795,1.499442 0.36511,0.458786 1.034877,0.530676 1.490873,0.162795 0.900329,-0.71298 1.673977,-1.308312 2.519064,-2.086367 0.845087,0.778055 1.691565,1.373387 2.591893,2.086367 0.456001,0.367877 1.125761,0.295987 1.490873,-0.162795 0.366811,-0.459497 0.289838,-1.132484 -0.167067,-1.499442 -0.82861,-0.656848 -1.662574,-1.242943 -2.441951,-1.957842 0.994894,-1.198734 1.953935,-2.7179 2.55762,-4.661121 h 0.28275 c 0.586426,0 1.062461,-0.474097 1.062461,-1.062461 0,-0.588369 -0.476035,-1.066747 -1.062461,-1.066747 h -3.251659 v -1.062461 c 0,-0.5883675 -0.476037,-1.0667433 -1.062461,-1.0667433 z m -1.743636,4.2584123 h 3.555818 c -0.458122,1.234642 -1.137838,2.234128 -1.812182,3.084565 -0.674344,-0.850437 -1.285517,-1.849853 -1.743636,-3.084565 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#3366cc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6.58040667;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect977" /></svg> \ No newline at end of file
diff --git a/application/resources/multimc/128x128/unknown_server.png b/application/resources/multimc/128x128/unknown_server.png
new file mode 100644
index 00000000..ec98382d
--- /dev/null
+++ b/application/resources/multimc/128x128/unknown_server.png
Binary files differ
diff --git a/application/resources/multimc/index.theme b/application/resources/multimc/index.theme
index 0fe7e7d7..6061b7f8 100644
--- a/application/resources/multimc/index.theme
+++ b/application/resources/multimc/index.theme
@@ -2,7 +2,7 @@
Name=multimc
Comment=MultiMC Default Icons
Inherits=default
-Directories=8x8,16x16,22x22,24x24,32x32,32x32/instances,48x48,50x50/instances,64x64,128x128/instances,256x256,scalable
+Directories=8x8,16x16,22x22,24x24,32x32,32x32/instances,48x48,50x50/instances,64x64,128x128/instances,256x256,scalable,scalable/instances
[8x8]
Size=8
@@ -33,6 +33,11 @@ Size=50
[64x64]
Size=64
+[128x128]
+Size=128
+MinSize=33
+MaxSize=128
+
[128x128/instances]
Size=128
MinSize=33
@@ -46,3 +51,8 @@ Size=48
Type=Scalable
MinSize=16
MaxSize=256
+
+[scalable/instances]
+Size=128
+MinSize=16
+MaxSize=256
diff --git a/application/resources/multimc/multimc.qrc b/application/resources/multimc/multimc.qrc
index bea3a325..22e7af86 100644
--- a/application/resources/multimc/multimc.qrc
+++ b/application/resources/multimc/multimc.qrc
@@ -1,306 +1,314 @@
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource prefix="/icons/multimc">
- <file>index.theme</file>
- <!-- Logo. Our own. For use in branding. -->
- <file>scalable/logo.svg</file>
-
- <!-- Logo. Our own. For use within the application (Settings pages and similar). -->
- <file>scalable/multimc.svg</file>
-
- <!-- REDDIT logo icon, needs reddit license! -->
- <file>scalable/reddit-alien.svg</file>
-
- <!-- twitch logo icon -->
- <file>scalable/twitch.svg</file>
-
- <!-- technic logo icon -->
- <file>scalable/technic.svg</file>
-
- <!-- A proxy icon. Our own. SSSsss -->
- <file>scalable/proxy.svg</file>
-
- <!-- Java icon. From Oracle, fixed because it was derpy. -->
- <file>scalable/java.svg</file>
-
- <!-- Star, CC-BY-SA 3.0, Oxygen icons.-->
- <file>16x16/star.png</file>
- <file>24x24/star.png</file>
- <file>32x32/star.png</file>
- <file>48x48/star.png</file>
- <file>64x64/star.png</file>
-
- <!-- "folder-remote", CC-BY-SA 3.0, Oxygen icons. Used for the worlds folder-->
- <file>16x16/worlds.png</file>
- <file>22x22/worlds.png</file>
- <file>32x32/worlds.png</file>
- <file>48x48/worlds.png</file>
- <file>64x64/worlds.png</file>
-
- <!-- Minecraft icon. Source: http://www.minecraftforum.net/forums/show-your-creation/fan-art/1574882-icon-better-minecraft-icon -->
- <file>16x16/minecraft.png</file>
- <file>24x24/minecraft.png</file>
- <file>32x32/minecraft.png</file>
- <file>48x48/minecraft.png</file>
- <file>256x256/minecraft.png</file>
-
- <!-- About dialog. GPLv2, http://openiconlibrary.sourceforge.net/gallery2/?./Icons/actions/help-contents.png -->
- <file>16x16/about.png</file>
- <file>22x22/about.png</file>
- <file>32x32/about.png</file>
- <file>48x48/about.png</file>
- <file>64x64/about.png</file>
-
- <!-- Report bug. Our own. -->
- <file>scalable/bug.svg</file>
- <file>16x16/bug.png</file>
- <file>22x22/bug.png</file>
- <file>32x32/bug.png</file>
- <file>48x48/bug.png</file>
- <file>64x64/bug.png</file>
-
- <!-- Screenshots. Our own. -->
- <!-- frame is adapted and simplified from http://www.wpclipart.com/page_frames/picture_frames/golden_picture_frame.png.html -->
- <file>16x16/screenshots.png</file>
- <file>22x22/screenshots.png</file>
- <file>32x32/screenshots.png</file>
- <file>48x48/screenshots.png</file>
- <file>64x64/screenshots.png</file>
- <file>scalable/screenshots.svg</file>
-
- <!-- Custom commands. -->
- <file>scalable/custom-commands.svg</file>
-
- <!-- Patron logo. (C) 2014 Patreon, Inc., http://www.patreon.com/toolbox?ftyp=media -->
- <file>16x16/patreon.png</file>
- <file>22x22/patreon.png</file>
- <file>24x24/patreon.png</file>
- <file>32x32/patreon.png</file>
- <file>48x48/patreon.png</file>
- <file>64x64/patreon.png</file>
-
- <!-- The cat button. Freeware, http://findicons.com/icon/73096/black_cat -->
- <file>16x16/cat.png</file>
- <file>22x22/cat.png</file>
- <file>24x24/cat.png</file>
- <file>32x32/cat.png</file>
- <file>48x48/cat.png</file>
- <file>64x64/cat.png</file>
-
- <!-- Show mods folder. CC-BY-SA 3.0 http://openiconlibrary.sourceforge.net/gallery2/?./Icons/places/oxygen-style/folder-favorites.png -->
- <file>scalable/centralmods.svg</file>
- <file>16x16/centralmods.png</file>
- <file>22x22/centralmods.png</file>
- <file>32x32/centralmods.png</file>
- <file>48x48/centralmods.png</file>
- <file>64x64/centralmods.png</file>
-
- <!-- Update. GPLv2, https://code.google.com/p/gnome-colors/ -->
- <file>scalable/checkupdate.svg</file>
- <file>16x16/checkupdate.png</file>
- <file>22x22/checkupdate.png</file>
- <file>32x32/checkupdate.png</file>
- <file>48x48/checkupdate.png</file>
- <file>64x64/checkupdate.png</file>
-
- <!-- copy instance. CC-BY-SA 3.0, http://openiconlibrary.sourceforge.net/gallery2/?./Icons/actions/edit-copy-6.png -->
- <file>16x16/copy.png</file>
- <file>22x22/copy.png</file>
- <file>32x32/copy.png</file>
- <file>48x48/copy.png</file>
- <file>64x64/copy.png</file>
-
- <!-- Help. CC-BY-SA 3.0, http://openiconlibrary.sourceforge.net/gallery2/?./Icons/actions/help.png -->
- <file>16x16/help.png</file>
- <file>22x22/help.png</file>
- <file>32x32/help.png</file>
- <file>48x48/help.png</file>
- <file>64x64/help.png</file>
-
- <!-- New instance. GPLv2, http://openiconlibrary.sourceforge.net/gallery2/?./Icons/actions/document-new-3.png -->
- <file>16x16/new.png</file>
+ <file>index.theme</file>
+ <!-- Logo. Our own. For use in branding. -->
+ <file>scalable/logo.svg</file>
+
+ <!-- Logo. Our own. For use within the application (Settings pages and similar). -->
+ <file>scalable/multimc.svg</file>
+
+ <!-- REDDIT logo icon, needs reddit license! -->
+ <file>scalable/reddit-alien.svg</file>
+
+ <!-- twitch logo icon -->
+ <file>scalable/twitch.svg</file>
+
+ <!-- technic logo icon -->
+ <file>scalable/technic.svg</file>
+
+ <!-- A proxy icon. Our own. SSSsss -->
+ <file>scalable/proxy.svg</file>
+
+ <!-- A free language icon. http://www.languageicon.org/ -->
+ <file>scalable/language.svg</file>
+
+ <!-- Java icon. From Oracle, fixed because it was derpy. -->
+ <file>scalable/java.svg</file>
+
+ <!-- Star, CC-BY-SA 3.0, Oxygen icons.-->
+ <file>16x16/star.png</file>
+ <file>24x24/star.png</file>
+ <file>32x32/star.png</file>
+ <file>48x48/star.png</file>
+ <file>64x64/star.png</file>
+
+ <!-- "folder-remote", CC-BY-SA 3.0, Oxygen icons. Used for the worlds folder-->
+ <file>16x16/worlds.png</file>
+ <file>22x22/worlds.png</file>
+ <file>32x32/worlds.png</file>
+ <file>48x48/worlds.png</file>
+ <file>64x64/worlds.png</file>
+
+ <!-- Minecraft icon. Source: http://www.minecraftforum.net/forums/show-your-creation/fan-art/1574882-icon-better-minecraft-icon -->
+ <file>16x16/minecraft.png</file>
+ <file>24x24/minecraft.png</file>
+ <file>32x32/minecraft.png</file>
+ <file>48x48/minecraft.png</file>
+ <file>256x256/minecraft.png</file>
+
+ <!-- About dialog. GPLv2, http://openiconlibrary.sourceforge.net/gallery2/?./Icons/actions/help-contents.png -->
+ <file>16x16/about.png</file>
+ <file>22x22/about.png</file>
+ <file>32x32/about.png</file>
+ <file>48x48/about.png</file>
+ <file>64x64/about.png</file>
+
+ <!-- Report bug. Our own. -->
+ <file>scalable/bug.svg</file>
+ <file>16x16/bug.png</file>
+ <file>22x22/bug.png</file>
+ <file>32x32/bug.png</file>
+ <file>48x48/bug.png</file>
+ <file>64x64/bug.png</file>
+
+ <!-- Screenshots. Our own. -->
+ <!-- frame is adapted and simplified from http://www.wpclipart.com/page_frames/picture_frames/golden_picture_frame.png.html -->
+ <file>16x16/screenshots.png</file>
+ <file>22x22/screenshots.png</file>
+ <file>32x32/screenshots.png</file>
+ <file>48x48/screenshots.png</file>
+ <file>64x64/screenshots.png</file>
+ <file>scalable/screenshots.svg</file>
+
+ <!-- Custom commands. -->
+ <file>scalable/custom-commands.svg</file>
+
+ <!-- Patron logo. (C) 2014 Patreon, Inc., http://www.patreon.com/toolbox?ftyp=media -->
+ <file>16x16/patreon.png</file>
+ <file>22x22/patreon.png</file>
+ <file>24x24/patreon.png</file>
+ <file>32x32/patreon.png</file>
+ <file>48x48/patreon.png</file>
+ <file>64x64/patreon.png</file>
+
+ <!-- The cat button. Freeware, http://findicons.com/icon/73096/black_cat -->
+ <file>16x16/cat.png</file>
+ <file>22x22/cat.png</file>
+ <file>24x24/cat.png</file>
+ <file>32x32/cat.png</file>
+ <file>48x48/cat.png</file>
+ <file>64x64/cat.png</file>
+
+ <!-- Show mods folder. CC-BY-SA 3.0 http://openiconlibrary.sourceforge.net/gallery2/?./Icons/places/oxygen-style/folder-favorites.png -->
+ <file>scalable/centralmods.svg</file>
+ <file>16x16/centralmods.png</file>
+ <file>22x22/centralmods.png</file>
+ <file>32x32/centralmods.png</file>
+ <file>48x48/centralmods.png</file>
+ <file>64x64/centralmods.png</file>
+
+ <!-- Update. GPLv2, https://code.google.com/p/gnome-colors/ -->
+ <file>scalable/checkupdate.svg</file>
+ <file>16x16/checkupdate.png</file>
+ <file>22x22/checkupdate.png</file>
+ <file>32x32/checkupdate.png</file>
+ <file>48x48/checkupdate.png</file>
+ <file>64x64/checkupdate.png</file>
+
+ <!-- copy instance. CC-BY-SA 3.0, http://openiconlibrary.sourceforge.net/gallery2/?./Icons/actions/edit-copy-6.png -->
+ <file>16x16/copy.png</file>
+ <file>22x22/copy.png</file>
+ <file>32x32/copy.png</file>
+ <file>48x48/copy.png</file>
+ <file>64x64/copy.png</file>
+
+ <!-- Help. CC-BY-SA 3.0, http://openiconlibrary.sourceforge.net/gallery2/?./Icons/actions/help.png -->
+ <file>16x16/help.png</file>
+ <file>22x22/help.png</file>
+ <file>32x32/help.png</file>
+ <file>48x48/help.png</file>
+ <file>64x64/help.png</file>
+
+ <!-- New instance. GPLv2, http://openiconlibrary.sourceforge.net/gallery2/?./Icons/actions/document-new-3.png -->
+ <file>16x16/new.png</file>
<file>22x22/new.png</file>
<file>32x32/new.png</file>
- <file>48x48/new.png</file>
- <file>64x64/new.png</file>
-
- <!-- Open news. Our own. -->
- <file>scalable/news.svg</file>
- <file>16x16/news.png</file>
- <file>22x22/news.png</file>
- <file>32x32/news.png</file>
- <file>48x48/news.png</file>
- <file>64x64/news.png</file>
-
- <!-- Bad status. Our own. -->
- <file>16x16/status-bad.png</file>
- <file>24x24/status-bad.png</file>
- <file>22x22/status-bad.png</file>
- <file>32x32/status-bad.png</file>
- <file>48x48/status-bad.png</file>
- <file>64x64/status-bad.png</file>
-
- <!-- Good status. Our own. -->
- <file>16x16/status-good.png</file>
- <file>24x24/status-good.png</file>
- <file>22x22/status-good.png</file>
- <file>32x32/status-good.png</file>
- <file>48x48/status-good.png</file>
- <file>64x64/status-good.png</file>
-
- <!-- Yellow status. Whatever that means... Our own. -->
- <file>16x16/status-yellow.png</file>
- <file>24x24/status-yellow.png</file>
- <file>22x22/status-yellow.png</file>
- <file>32x32/status-yellow.png</file>
- <file>48x48/status-yellow.png</file>
- <file>64x64/status-yellow.png</file>
-
- <!-- A status icon for things that are in progress/running... Our own. -->
- <file>16x16/status-running.png</file>
- <file>24x24/status-running.png</file>
- <file>22x22/status-running.png</file>
- <file>32x32/status-running.png</file>
- <file>48x48/status-running.png</file>
- <file>64x64/status-running.png</file>
- <file>scalable/status-running.svg</file>
-
- <!-- Plugin (blue recolor), CC-BY-SA 3.0, Oxygen icons. -->
- <file>16x16/loadermods.png</file>
- <file>24x24/loadermods.png</file>
- <file>32x32/loadermods.png</file>
- <file>64x64/loadermods.png</file>
-
- <!-- Plugin (red recolor), CC-BY-SA 3.0, Oxygen icons. -->
- <file>16x16/jarmods.png</file>
- <file>24x24/jarmods.png</file>
- <file>32x32/jarmods.png</file>
- <file>64x64/jarmods.png</file>
-
- <!-- Plugin (green original), CC-BY-SA 3.0, Oxygen icons. -->
- <file>16x16/coremods.png</file>
- <file>24x24/coremods.png</file>
- <file>32x32/coremods.png</file>
- <file>64x64/coremods.png</file>
-
- <!-- Resource packs, CC-BY-SA 3.0, Oxygen icons. -->
- <file>16x16/resourcepacks.png</file>
- <file>24x24/resourcepacks.png</file>
- <file>32x32/resourcepacks.png</file>
- <file>64x64/resourcepacks.png</file>
-
- <!-- Refresh, CC-BY-SA 3.0, Oxygen icons. -->
- <file>16x16/refresh.png</file>
- <file>22x22/refresh.png</file>
- <file>32x32/refresh.png</file>
- <file>48x48/refresh.png</file>
- <file>64x64/refresh.png</file>
-
- <!-- Settings, LGPL-2.1, http://openiconlibrary.sourceforge.net/gallery2/?./Icons/apps/system-settings-3.png -->
- <file>16x16/settings.png</file>
+ <file>48x48/new.png</file>
+ <file>64x64/new.png</file>
+
+ <!-- Open news. Our own. -->
+ <file>scalable/news.svg</file>
+ <file>16x16/news.png</file>
+ <file>22x22/news.png</file>
+ <file>32x32/news.png</file>
+ <file>48x48/news.png</file>
+ <file>64x64/news.png</file>
+
+ <!-- Bad status. Our own. -->
+ <file>16x16/status-bad.png</file>
+ <file>24x24/status-bad.png</file>
+ <file>22x22/status-bad.png</file>
+ <file>32x32/status-bad.png</file>
+ <file>48x48/status-bad.png</file>
+ <file>64x64/status-bad.png</file>
+
+ <!-- Good status. Our own. -->
+ <file>16x16/status-good.png</file>
+ <file>24x24/status-good.png</file>
+ <file>22x22/status-good.png</file>
+ <file>32x32/status-good.png</file>
+ <file>48x48/status-good.png</file>
+ <file>64x64/status-good.png</file>
+
+ <!-- Yellow status. Whatever that means... Our own. -->
+ <file>16x16/status-yellow.png</file>
+ <file>24x24/status-yellow.png</file>
+ <file>22x22/status-yellow.png</file>
+ <file>32x32/status-yellow.png</file>
+ <file>48x48/status-yellow.png</file>
+ <file>64x64/status-yellow.png</file>
+
+ <!-- A status icon for things that are in progress/running... Our own. -->
+ <file>16x16/status-running.png</file>
+ <file>24x24/status-running.png</file>
+ <file>22x22/status-running.png</file>
+ <file>32x32/status-running.png</file>
+ <file>48x48/status-running.png</file>
+ <file>64x64/status-running.png</file>
+ <file>scalable/status-running.svg</file>
+
+ <!-- Plugin (blue recolor), CC-BY-SA 3.0, Oxygen icons. -->
+ <file>16x16/loadermods.png</file>
+ <file>24x24/loadermods.png</file>
+ <file>32x32/loadermods.png</file>
+ <file>64x64/loadermods.png</file>
+
+ <!-- Plugin (red recolor), CC-BY-SA 3.0, Oxygen icons. -->
+ <file>16x16/jarmods.png</file>
+ <file>24x24/jarmods.png</file>
+ <file>32x32/jarmods.png</file>
+ <file>64x64/jarmods.png</file>
+
+ <!-- Plugin (green original), CC-BY-SA 3.0, Oxygen icons. -->
+ <file>16x16/coremods.png</file>
+ <file>24x24/coremods.png</file>
+ <file>32x32/coremods.png</file>
+ <file>64x64/coremods.png</file>
+
+ <!-- Resource packs, CC-BY-SA 3.0, Oxygen icons. -->
+ <file>16x16/resourcepacks.png</file>
+ <file>24x24/resourcepacks.png</file>
+ <file>32x32/resourcepacks.png</file>
+ <file>64x64/resourcepacks.png</file>
+
+ <!-- Refresh, CC-BY-SA 3.0, Oxygen icons. -->
+ <file>16x16/refresh.png</file>
+ <file>22x22/refresh.png</file>
+ <file>32x32/refresh.png</file>
+ <file>48x48/refresh.png</file>
+ <file>64x64/refresh.png</file>
+
+ <!-- Settings, LGPL-2.1, http://openiconlibrary.sourceforge.net/gallery2/?./Icons/apps/system-settings-3.png -->
+ <file>16x16/settings.png</file>
<file>22x22/settings.png</file>
- <file>32x32/settings.png</file>
- <file>48x48/settings.png</file>
- <file>64x64/settings.png</file>
-
- <!-- Same, used for instance settings -->
- <file>16x16/instance-settings.png</file>
- <file>22x22/instance-settings.png</file>
- <file>32x32/instance-settings.png</file>
- <file>48x48/instance-settings.png</file>
- <file>64x64/instance-settings.png</file>
-
- <!-- View folder. CC-BY-SA 3.0, http://openiconlibrary.sourceforge.net/gallery2/?./Icons/actions/document-open-folder.png -->
- <file>scalable/viewfolder.svg</file>
- <file>16x16/viewfolder.png</file>
+ <file>32x32/settings.png</file>
+ <file>48x48/settings.png</file>
+ <file>64x64/settings.png</file>
+
+ <!-- Same, used for instance settings -->
+ <file>16x16/instance-settings.png</file>
+ <file>22x22/instance-settings.png</file>
+ <file>32x32/instance-settings.png</file>
+ <file>48x48/instance-settings.png</file>
+ <file>64x64/instance-settings.png</file>
+
+ <!-- View folder. CC-BY-SA 3.0, http://openiconlibrary.sourceforge.net/gallery2/?./Icons/actions/document-open-folder.png -->
+ <file>scalable/viewfolder.svg</file>
+ <file>16x16/viewfolder.png</file>
<file>22x22/viewfolder.png</file>
- <file>32x32/viewfolder.png</file>
- <file>48x48/viewfolder.png</file>
- <file>64x64/viewfolder.png</file>
+ <file>32x32/viewfolder.png</file>
+ <file>48x48/viewfolder.png</file>
+ <file>64x64/viewfolder.png</file>
- <!-- Default minecraft skin, desaturated, cutout of head, Mojang -->
- <file>8x8/noaccount.png</file>
- <file>16x16/noaccount.png</file>
- <file>24x24/noaccount.png</file>
- <file>32x32/noaccount.png</file>
- <file>48x48/noaccount.png</file>
+ <!-- Default minecraft skin, desaturated, cutout of head, Mojang -->
+ <file>8x8/noaccount.png</file>
+ <file>16x16/noaccount.png</file>
+ <file>24x24/noaccount.png</file>
+ <file>32x32/noaccount.png</file>
+ <file>48x48/noaccount.png</file>
- <!-- and the same again. TODO: make a nice accounts icon -->
- <file alias="8x8/accounts.png">8x8/noaccount.png</file>
- <file alias="16x16/accounts.png">16x16/noaccount.png</file>
- <file alias="24x24/accounts.png">24x24/noaccount.png</file>
- <file alias="32x32/accounts.png">32x32/noaccount.png</file>
- <file alias="48x48/accounts.png">48x48/noaccount.png</file>
+ <!-- and the same again. TODO: make a nice accounts icon -->
+ <file alias="8x8/accounts.png">8x8/noaccount.png</file>
+ <file alias="16x16/accounts.png">16x16/noaccount.png</file>
+ <file alias="24x24/accounts.png">24x24/noaccount.png</file>
+ <file alias="32x32/accounts.png">32x32/noaccount.png</file>
+ <file alias="48x48/accounts.png">48x48/noaccount.png</file>
- <!-- Log file, LGPL, http://www.iconarchive.com/show/crystal-clear-icons-by-everaldo/Mimetype-text-icon.html -->
- <file>16x16/log.png</file>
- <file>24x24/log.png</file>
- <file>32x32/log.png</file>
- <file>48x48/log.png</file>
- <file>64x64/log.png</file>
+ <!-- Log file, LGPL, http://www.iconarchive.com/show/crystal-clear-icons-by-everaldo/Mimetype-text-icon.html -->
+ <file>16x16/log.png</file>
+ <file>24x24/log.png</file>
+ <file>32x32/log.png</file>
+ <file>48x48/log.png</file>
+ <file>64x64/log.png</file>
- <!-- placeholder when loading screenshot images -->
- <file>scalable/screenshot-placeholder.svg</file>
+ <!-- placeholder for minecraft servers -->
+ <file>128x128/unknown_server.png</file>
- <!-- discord logo icon thing. from discord. traced from bitmap -->
- <file>scalable/discord.svg</file>
+ <!-- placeholder when loading screenshot images -->
+ <file>scalable/screenshot-placeholder.svg</file>
- <!-- instance icons -->
- <file>32x32/instances/chicken.png</file>
- <file>128x128/instances/chicken.png</file>
+ <!-- discord logo icon thing. from discord. traced from bitmap -->
+ <file>scalable/discord.svg</file>
- <file>32x32/instances/creeper.png</file>
- <file>128x128/instances/creeper.png</file>
+ <!-- instance icons -->
+ <file>32x32/instances/chicken.png</file>
+ <file>128x128/instances/chicken.png</file>
- <file>32x32/instances/enderpearl.png</file>
- <file>128x128/instances/enderpearl.png</file>
+ <file>32x32/instances/creeper.png</file>
+ <file>128x128/instances/creeper.png</file>
- <file>32x32/instances/ftb_glow.png</file>
- <file>128x128/instances/ftb_glow.png</file>
+ <file>32x32/instances/enderpearl.png</file>
+ <file>128x128/instances/enderpearl.png</file>
- <file>32x32/instances/ftb_logo.png</file>
- <file>128x128/instances/ftb_logo.png</file>
+ <file>32x32/instances/ftb_glow.png</file>
+ <file>128x128/instances/ftb_glow.png</file>
- <file>32x32/instances/flame.png</file>
- <file>128x128/instances/flame.png</file>
+ <file>32x32/instances/ftb_logo.png</file>
+ <file>128x128/instances/ftb_logo.png</file>
- <file>32x32/instances/gear.png</file>
- <file>128x128/instances/gear.png</file>
+ <file>32x32/instances/flame.png</file>
+ <file>128x128/instances/flame.png</file>
- <file>32x32/instances/herobrine.png</file>
- <file>128x128/instances/herobrine.png</file>
+ <file>32x32/instances/gear.png</file>
+ <file>128x128/instances/gear.png</file>
- <file>32x32/instances/infinity.png</file>
- <file>128x128/instances/infinity.png</file>
+ <file>32x32/instances/herobrine.png</file>
+ <file>128x128/instances/herobrine.png</file>
- <file>32x32/instances/magitech.png</file>
- <file>128x128/instances/magitech.png</file>
+ <file>32x32/instances/infinity.png</file>
+ <file>128x128/instances/infinity.png</file>
- <file>32x32/instances/meat.png</file>
- <file>128x128/instances/meat.png</file>
+ <file>32x32/instances/magitech.png</file>
+ <file>128x128/instances/magitech.png</file>
- <file>32x32/instances/netherstar.png</file>
- <file>128x128/instances/netherstar.png</file>
+ <file>32x32/instances/meat.png</file>
+ <file>128x128/instances/meat.png</file>
- <file>32x32/instances/skeleton.png</file>
- <file>128x128/instances/skeleton.png</file>
+ <file>32x32/instances/netherstar.png</file>
+ <file>128x128/instances/netherstar.png</file>
- <file>32x32/instances/squarecreeper.png</file>
- <file>128x128/instances/squarecreeper.png</file>
+ <file>32x32/instances/skeleton.png</file>
+ <file>128x128/instances/skeleton.png</file>
- <file>32x32/instances/steve.png</file>
- <file>128x128/instances/steve.png</file>
+ <file>32x32/instances/squarecreeper.png</file>
+ <file>128x128/instances/squarecreeper.png</file>
- <file>32x32/instances/brick.png</file>
- <file>32x32/instances/diamond.png</file>
- <file>32x32/instances/dirt.png</file>
- <file>32x32/instances/gold.png</file>
- <file>32x32/instances/grass.png</file>
- <file>32x32/instances/iron.png</file>
- <file>32x32/instances/planks.png</file>
- <file>32x32/instances/stone.png</file>
- <file>32x32/instances/tnt.png</file>
+ <file>32x32/instances/steve.png</file>
+ <file>128x128/instances/steve.png</file>
- <file>50x50/instances/enderman.png</file>
- </qresource>
+ <file>32x32/instances/brick.png</file>
+ <file>32x32/instances/diamond.png</file>
+ <file>32x32/instances/dirt.png</file>
+ <file>32x32/instances/gold.png</file>
+ <file>32x32/instances/grass.png</file>
+ <file>32x32/instances/iron.png</file>
+ <file>32x32/instances/planks.png</file>
+ <file>32x32/instances/stone.png</file>
+ <file>32x32/instances/tnt.png</file>
+
+ <file>50x50/instances/enderman.png</file>
+
+ <file>scalable/instances/fox.svg</file>
+ </qresource>
</RCC>
diff --git a/application/resources/multimc/scalable/instances/fox.svg b/application/resources/multimc/scalable/instances/fox.svg
new file mode 100644
index 00000000..fcf16b2f
--- /dev/null
+++ b/application/resources/multimc/scalable/instances/fox.svg
@@ -0,0 +1,290 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ id="svg8"
+ version="1.1"
+ viewBox="0 0 33.866666 33.866666"
+ height="128"
+ width="128">
+ <defs
+ id="defs2" />
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ transform="translate(0,-263.13334)"
+ id="layer1">
+ <path
+ id="rect4750"
+ d="m 4.233333,267.36667 v 6.35 6.35 3.175 3.175 3.175 3.175 h 25.4 v -3.175 -3.175 -3.175 -3.175 -6.35 -6.35 h -6.35 v 6.35 h -12.7 v -3.175 -3.175 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#800000;stroke-width:0.79375;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
+ <g
+ id="g4748">
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#f9f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.19062567;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4553"
+ width="6.3500032"
+ height="6.3499975"
+ x="4.233326"
+ y="267.36667" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#b48f83;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.59531283;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4553-6-2"
+ width="3.1750014"
+ height="3.1749992"
+ x="7.4083276"
+ y="270.54166" />
+ <rect
+ y="267.36667"
+ x="23.283335"
+ height="6.3499975"
+ width="6.3500032"
+ id="rect4623"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#f9f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.19062567;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
+ <rect
+ y="270.54166"
+ x="23.283335"
+ height="3.1749992"
+ width="3.1750014"
+ id="rect4627"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#b48f83;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.59531283;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#e27c21;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.59531283;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4672"
+ width="25.400013"
+ height="15.875009"
+ x="4.233326"
+ y="273.71667" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#cc6920;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.59531283;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4629"
+ width="3.1750016"
+ height="6.3500032"
+ x="4.2333255"
+ y="273.71667" />
+ <rect
+ y="273.71667"
+ x="26.458338"
+ height="6.3500032"
+ width="3.1750016"
+ id="rect4631"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#cc6920;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.59531283;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#e78f41;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.59531283;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4636"
+ width="6.3500032"
+ height="3.1750016"
+ x="13.758331"
+ y="283.24167" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#b05122;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.59531283;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4638"
+ width="3.1750016"
+ height="3.1750016"
+ x="4.2333255"
+ y="280.06668" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#cc6920;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.59531283;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4640"
+ width="3.1750016"
+ height="3.1750016"
+ x="7.4083276"
+ y="280.06668" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#f9f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.84189939;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4644"
+ width="6.3500028"
+ height="3.1750016"
+ x="4.233326"
+ y="283.24167" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#06040e;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.59531283;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4642"
+ width="3.1750016"
+ height="3.1750016"
+ x="4.2333255"
+ y="283.24167" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#f9f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.84189939;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4646"
+ width="6.3500028"
+ height="3.1750016"
+ x="23.283337"
+ y="283.24167" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#06040e;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.59531283;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4648"
+ width="3.1750016"
+ height="3.1750016"
+ x="26.45834"
+ y="283.24167" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#cc6920;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.59531283;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4650"
+ width="3.1750016"
+ height="3.1750016"
+ x="23.283337"
+ y="280.06668" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#b05122;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.59531283;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4652"
+ width="3.1750016"
+ height="3.1750016"
+ x="26.45834"
+ y="280.06668" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#cc6920;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.59531283;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4654"
+ width="25.400013"
+ height="3.1750016"
+ x="4.2333255"
+ y="286.41666" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#e7d9d3;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.59531283;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4656"
+ width="25.400013"
+ height="3.1750016"
+ x="4.2333255"
+ y="289.59167" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.25;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5612604;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4917"
+ width="25.4"
+ height="0.26457807"
+ x="4.2333331"
+ y="273.71667" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.25;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.48607069;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4921"
+ width="0.2645835"
+ height="19.049997"
+ x="4.2333331"
+ y="273.71667" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#f9f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.19062555;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4658"
+ width="12.700007"
+ height="6.3500013"
+ x="10.583333"
+ y="286.41666" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#06040e;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.19062555;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4660"
+ width="6.3500037"
+ height="3.1750007"
+ x="13.758333"
+ y="286.41669" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#e7d9d3;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.19062555;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4662"
+ width="3.1750019"
+ height="3.1750007"
+ x="10.583333"
+ y="286.41669" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#e7d9d3;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.19062555;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4664"
+ width="3.1750019"
+ height="3.1750007"
+ x="20.108334"
+ y="286.41669" />
+ <rect
+ y="286.41669"
+ x="10.583333"
+ height="6.3499832"
+ width="0.2645835"
+ id="rect4923"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.25;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.2806327;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.25;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.39686465;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4951"
+ width="12.699996"
+ height="0.26456967"
+ x="10.583333"
+ y="286.41669" />
+ <rect
+ y="273.71667"
+ x="29.36875"
+ height="19.049982"
+ width="0.26458356"
+ id="rect4953"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.25;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.48607057;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
+ <rect
+ y="292.50208"
+ x="23.283333"
+ height="0.26457682"
+ width="6.3499994"
+ id="rect4957"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.25;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.28062955;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.25;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.2806325;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4959"
+ width="0.2645838"
+ height="6.3499656"
+ x="23.018749"
+ y="286.41669" />
+ <rect
+ y="292.50208"
+ x="4.2333331"
+ height="0.26457968"
+ width="6.3499999"
+ id="rect4961"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.25;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.28063107;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
+ <rect
+ y="267.36667"
+ x="4.2333331"
+ height="6.3499956"
+ width="0.2645835"
+ id="rect4963"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.25;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.28063297;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.25;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.28063536;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4965"
+ width="6.349998"
+ height="0.26458791"
+ x="4.2333331"
+ y="267.36667" />
+ <rect
+ y="267.36667"
+ x="23.283333"
+ height="6.3499956"
+ width="0.2645835"
+ id="rect4963-9"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.25;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.280633;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.25;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.28063536;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4965-1"
+ width="6.349998"
+ height="0.26458791"
+ x="23.283333"
+ y="267.36667" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.25;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.28063306;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect4985"
+ width="0.26458356"
+ height="6.3499975"
+ x="29.36875"
+ y="267.36667" />
+ <rect
+ y="267.36667"
+ x="10.318749"
+ height="6.3499975"
+ width="0.26458356"
+ id="rect4987"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.25;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.28063306;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
+ </g>
+ </g>
+</svg>
diff --git a/application/resources/multimc/scalable/language.svg b/application/resources/multimc/scalable/language.svg
new file mode 100644
index 00000000..968e3538
--- /dev/null
+++ b/application/resources/multimc/scalable/language.svg
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ viewBox="0 0 128 128"
+ height="128"
+ width="128"
+ xml:space="preserve"
+ id="svg2"
+ version="1.1"
+ sodipodi:docname="language.svg"
+ inkscape:version="0.92.2 2405546, 2018-03-11"><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="3840"
+ inkscape:window-height="2123"
+ id="namedview30"
+ showgrid="false"
+ inkscape:zoom="1.84375"
+ inkscape:cx="325.0346"
+ inkscape:cy="134.81864"
+ inkscape:window-x="1200"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="g888" /><metadata
+ id="metadata8"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+ id="defs6" /><g
+ transform="matrix(1.3333333,0,0,-1.3333333,0,128.00004)"
+ id="g10"><g
+ transform="scale(0.1)"
+ id="g12"><g
+ transform="matrix(0.0334181,0,0,0.0334181,77.111273,13.149509)"
+ id="g888"><g
+ id="g14"
+ transform="scale(1.69573)"
+ style="fill:#0066cc;fill-opacity:1"><path
+ d="M 7103.55,14358.7 1603.03,16300 V 4328.22 l 5500.52,1779.59 v 8250.89"
+ style="fill:#0066cc;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path16" /></g><g
+ id="g18"
+ transform="scale(1.69635)"><path
+ d="M 6968.96,14359.4 12678,16300 V 4332.6 L 6968.96,6111.53 v 8247.87"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path20" /></g><g
+ id="g22"
+ transform="scale(1.49453)"><path
+ d="M 200.466,2533.04 7910.06,5102.75 V 16300 L 200.466,13730.3 V 2533.04"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path24" /></g><g
+ id="g26"
+ transform="scale(1.20038)"
+ style="fill:#003399;fill-opacity:1"><path
+ d="M 14222.2,2943.15 15582.6,705.027 16300,2784.12 14222.2,2943.15"
+ style="fill:#003399;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path28" /></g><g
+ id="g30"
+ transform="scale(1.16442)"
+ style="fill:#003399;fill-opacity:1"><path
+ d="m 3621.88,15967.1 c -52.56,51.6 68.45,-421.7 236.85,-592 298.61,-301.3 531.85,-340.1 656.04,-345.1 274.81,-11 613.95,68.5 815.34,152.9 194.86,83.1 536.31,257.4 665.56,511.7 27.4,54.4 102.2,145.7 55.22,371.2 -35.64,173.5 -146.08,234.2 -280.74,224.6 -134.66,-9.1 -542.33,-117.8 -739.51,-178.5 -197.26,-59.8 -603.56,-183.5 -780.64,-221.9 -176.65,-38.3 -566.12,17.8 -628.12,77.1"
+ style="fill:#003399;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path32" /></g><g
+ id="g34"
+ transform="scale(1.0917)"
+ style="fill:#003399;fill-opacity:1"><path
+ d="m 9188.43,10995.1 c -83.18,30.2 -1803.98,743 -2047.91,859.8 -199.6,96 -689.02,302.9 -919.3,396.9 648.62,1000.1 1058.07,1754.8 1112.58,1869.8 100.85,210.3 787.39,1553.7 803.42,1636.4 15.57,83.8 35.08,393.4 19.97,467 -15.11,75 -266.83,-69.2 -608.59,-185.1 -342.31,-115.4 -992.86,-538.5 -1244.12,-591.5 -252.17,-52.6 -1058.07,-357.9 -1470.46,-494.7 -412.38,-136.9 -1192.45,-375 -1513.33,-461.6 -321.33,-86.7 -601.81,-93.5 -781.53,-148 0,0 23.91,-251.8 71.63,-327.2 47.18,-75.5 217.19,-260.5 414.86,-312.2 197.67,-52 524.87,-31.2 673.9,2.9 148.95,34.6 406.98,160.7 441.61,215.7 34.99,56 -18.05,228.4 40.85,280.5 59.45,51.6 844.83,235.2 1141.34,324.7 296.51,91.2 1431.53,482.1 1585.42,462.2 C 6860.04,14829 5947.06,13020.6 5653.02,12481.1 5358.89,11941.7 3650.37,9568.39 3286.62,9150.14 3010.54,8832.19 2341.49,8018.6 2109.74,7835.03 c 58.44,-16.12 472.75,19.42 548.23,66.14 470.36,289.73 1253.82,1265 1506.09,1562.06 749.84,879.37 1408.63,1803.07 1931.02,2595.77 h 0.56 c 101.76,-42.4 924.61,-712.8 1139.32,-861.4 214.71,-148.5 1062.01,-621.2 1245.58,-699.7 183.57,-79.4 889.07,-404.6 918.75,-294.5 29.68,111 -127.6,760.1 -210.86,791.7"
+ style="fill:#003399;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path36" /></g><g
+ id="g38"
+ transform="scale(1.12147)"
+ style="fill:#003399;fill-opacity:1"><path
+ d="m 5073.69,1979.54 c 160.5,-98.08 312.09,-178.34 481.51,-258.59 338.84,-169.42 722.26,-347.76 1087.85,-481.51 499.35,-187.25 998.69,-338.838 1498.03,-454.757 276.43,-62.418 579.6,-115.919 873.85,-160.504 26.76,0 820.35,-98.085 980.86,-98.085 h 802.51 c 312.1,26.751 606.4,44.584 918.4,89.169 249.7,35.667 526.1,80.251 793.6,142.669 196.2,44.584 401.3,89.169 597.5,151.587 187.2,53.501 401.2,124.831 606.3,196.171 133.8,44.58 276.4,107 419.1,160.5 115.9,53.5 258.6,115.92 392.3,169.42 160.6,71.34 347.8,169.42 526.1,258.59 142.7,71.34 303.2,160.5 454.8,249.67 115.9,62.42 383.4,267.51 526.1,267.51 160.5,0 267.5,-142.67 267.5,-267.51 0,-258.59 -347.8,-338.84 -508.3,-454.76 -169.4,-115.92 -374.5,-205.08 -552.8,-303.17 -356.7,-187.253 -722.3,-347.756 -1070,-481.509 -454.8,-169.42 -954.1,-329.923 -1400,-436.926 -169.4,-35.667 -338.8,-80.251 -508.2,-107.002 C 12171.5,142.67 11244.1,0 10985.6,0 H 9808.53 c -312.09,26.7505 -642.01,62.4179 -954.1,107.002 -276.42,44.584 -570.68,98.086 -847.1,160.503 -214,44.585 -445.84,107.003 -650.93,169.421 -356.67,98.085 -704.43,222.921 -1043.27,356.674 -615.26,231.84 -1257.28,535.01 -1863.62,936.27 -107,71.33 -115.92,142.67 -115.92,222.92 0,133.75 98.08,258.59 258.59,258.59 142.67,0 428.01,-205.09 481.51,-231.84"
+ style="fill:#003399;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ id="path40" /></g><g
+ id="g42"
+ transform="scale(1.51227)"
+ style="fill:#003399;fill-opacity:1"><path
+ d="M 8014.44,16134.7 V 5025.56 c -6.61,-33.07 -19.84,-66.13 -46.29,-99.19 -13.22,-19.84 -39.67,-46.29 -59.51,-52.9 C 7743.33,4807.34 297.566,2307.79 198.377,2307.79 c -79.351,0 -152.089,52.9 -191.76442,138.86 0,6.62 -6.61258,13.23 -6.61258,26.45 v 11115.7 c 13.2252,33.1 19.8377,79.4 46.288,105.8 52.9006,72.8 145.477,86 204.99,105.8 112.414,39.7 7445.762,2499.6 7551.562,2499.6 66.13,0 211.6,-46.3 211.6,-165.3 z M 7611.07,5190.87 403.367,2790.51 V 13423.5 L 7611.07,15823.9 V 5190.87"
+ style="fill:#003399;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ id="path44" /></g><g
+ id="g46"
+ transform="scale(1.71411)"
+ style="fill:#003399;fill-opacity:1"><path
+ d="M 12723.8,16113.3 V 4311.27 c -5.8,-134.18 -99.2,-192.52 -186.7,-192.52 -75.8,0 -624.2,186.69 -717.6,215.86 -735,227.52 -1475.9,455.05 -2205.18,682.57 -163.35,52.51 -332.54,105.01 -490.05,157.52 -140.02,40.83 -291.7,87.5 -431.71,134.18 -624.23,192.52 -1260.13,385.04 -1884.36,595.06 -23.34,5.83 -81.68,87.51 -81.68,105.01 v 8243.35 c 11.67,29.2 23.34,64.2 52.51,87.5 46.67,52.5 2047.71,717.6 2835.29,980.1 210.02,75.8 2841.08,980.1 2922.78,980.1 105,0 186.7,-75.8 186.7,-186.7 z M 12367.9,4532.96 7076.56,6178.13 V 14083.1 L 12367.9,15880 V 4532.96"
+ style="fill:#003399;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ id="path48" /></g><g
+ id="g50"
+ transform="scale(1.48515)"
+ style="fill:#0066cc;fill-opacity:1"><path
+ d="M 16235.4,2378.81 8076.61,4979.28 8110.74,16300 16235.4,13714.1 V 2378.81"
+ style="fill:#0066cc;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path52" /></g><g
+ id="g54"
+ transform="scale(1.33098)"><path
+ d="m 12990.3,14581.8 1172.9,-355.3 2136.8,-7701.24 -1204.8,365.52 -432.8,1581.01 -2489.7,754.63 -535.4,-1287.92 -1205.1,365.6 z m 536.2,-2038.8 -893.6,-2159.8 1642.8,-497.94 -749.2,2657.74"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ id="path56" /></g></g></g></g></svg> \ No newline at end of file
diff --git a/application/resources/pe_blue/pe_blue.qrc b/application/resources/pe_blue/pe_blue.qrc
index 1706371a..98445d88 100644
--- a/application/resources/pe_blue/pe_blue.qrc
+++ b/application/resources/pe_blue/pe_blue.qrc
@@ -1,37 +1,38 @@
<!DOCTYPE RCC>
<RCC version="1.0">
- <qresource prefix="/icons/pe_blue">
- <file>index.theme</file>
- <file>scalable/about.svg</file>
- <file>scalable/accounts.svg</file>
- <file>scalable/bug.svg</file>
- <file>scalable/centralmods.svg</file>
- <file>scalable/checkupdate.svg</file>
- <file>scalable/copy.svg</file>
- <file>scalable/coremods.svg</file>
- <file>scalable/externaltools.svg</file>
- <file>scalable/help.svg</file>
- <file>scalable/instance-settings.svg</file>
- <file>scalable/jarmods.svg</file>
- <file>scalable/java.svg</file>
- <file>scalable/loadermods.svg</file>
- <file>scalable/log.svg</file>
- <file>scalable/minecraft.svg</file>
- <file>scalable/multimc.svg</file>
- <file>scalable/new.svg</file>
- <file>scalable/news.svg</file>
- <file>scalable/notes.svg</file>
- <file>scalable/patreon.svg</file>
- <file>scalable/proxy.svg</file>
- <file>scalable/quickmods.svg</file>
- <file>scalable/refresh.svg</file>
- <file>scalable/resourcepacks.svg</file>
- <file>scalable/screenshots.svg</file>
- <file>scalable/settings.svg</file>
- <file>scalable/status-bad.svg</file>
- <file>scalable/status-good.svg</file>
- <file>scalable/status-yellow.svg</file>
- <file>scalable/viewfolder.svg</file>
- <file>scalable/worlds.svg</file>
- </qresource>
+ <qresource prefix="/icons/pe_blue">
+ <file>index.theme</file>
+ <file>scalable/about.svg</file>
+ <file>scalable/accounts.svg</file>
+ <file>scalable/bug.svg</file>
+ <file>scalable/centralmods.svg</file>
+ <file>scalable/checkupdate.svg</file>
+ <file>scalable/copy.svg</file>
+ <file>scalable/coremods.svg</file>
+ <file>scalable/externaltools.svg</file>
+ <file>scalable/help.svg</file>
+ <file>scalable/instance-settings.svg</file>
+ <file>scalable/jarmods.svg</file>
+ <file>scalable/java.svg</file>
+ <file>scalable/language.svg</file>
+ <file>scalable/loadermods.svg</file>
+ <file>scalable/log.svg</file>
+ <file>scalable/minecraft.svg</file>
+ <file>scalable/multimc.svg</file>
+ <file>scalable/new.svg</file>
+ <file>scalable/news.svg</file>
+ <file>scalable/notes.svg</file>
+ <file>scalable/patreon.svg</file>
+ <file>scalable/proxy.svg</file>
+ <file>scalable/quickmods.svg</file>
+ <file>scalable/refresh.svg</file>
+ <file>scalable/resourcepacks.svg</file>
+ <file>scalable/screenshots.svg</file>
+ <file>scalable/settings.svg</file>
+ <file>scalable/status-bad.svg</file>
+ <file>scalable/status-good.svg</file>
+ <file>scalable/status-yellow.svg</file>
+ <file>scalable/viewfolder.svg</file>
+ <file>scalable/worlds.svg</file>
+ </qresource>
</RCC>
diff --git a/application/resources/pe_blue/scalable/language.svg b/application/resources/pe_blue/scalable/language.svg
new file mode 100644
index 00000000..92868516
--- /dev/null
+++ b/application/resources/pe_blue/scalable/language.svg
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ id="Calque_1"
+ x="0px"
+ y="0px"
+ viewBox="0 0 32 32"
+ enable-background="new 0 0 32 32"
+ xml:space="preserve"><metadata
+ id="metadata45"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+ id="defs43" /><path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ fill="#3366CC"
+ d="M26,32H6c-3.3,0-6-2.7-6-6V6c0-3.3,2.7-6,6-6h20c3.3,0,6,2.7,6,6 v20C32,29.3,29.3,32,26,32z"
+ id="path2" /><path
+ fill="#DAEEFF"
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M28,6c0-1.1-0.9-2-2-2H6C4.9,4,4,4.9,4,6v20c0,1.1,0.9,2,2,2h20 c1.1,0,2-0.9,2-2V6z"
+ id="path4" /><g
+ id="g10" /><g
+ id="g12" /><g
+ id="g14" /><g
+ id="g16" /><g
+ id="g18" /><g
+ id="g20" /><g
+ id="g22" /><g
+ id="g24" /><g
+ id="g26" /><g
+ id="g28" /><g
+ id="g30" /><g
+ id="g32" /><g
+ id="g34" /><g
+ id="g36" /><g
+ id="g38" /><path
+ d="m 9.1897907,10.114301 c -0.4838401,0 -0.9011011,0.341924 -0.9962772,0.815883 L 6.1640606,21.085639 c -0.1100564,0.55031 0.2460855,1.083011 0.7953819,1.193069 0.5562003,0.113982 1.0840209,-0.246085 1.1930722,-0.79538 l 0.6518824,-3.247122 h 2.8699319 l 0.647785,3.247122 c 0.110996,0.557485 0.658771,0.906193 1.197171,0.79538 0.549363,-0.110056 0.905437,-0.642759 0.795381,-1.193069 L 12.285213,10.930184 c -0.09517,-0.473959 -0.512431,-0.815883 -0.996274,-0.815883 z m 0.6149825,2.287746 h 0.4345928 l 0.811779,4.063002 H 8.9929943 Z M 20.710512,9.7002137 c -0.561209,0 -1.016777,0.4578063 -1.016777,1.0208743 v 1.016774 h -3.046227 c -0.561205,0 -1.012673,0.457809 -1.012673,1.020876 0,0.563065 0.451466,1.016776 1.012673,1.016776 h 0.274696 c 0.577658,1.85973 1.425829,3.313572 2.37794,4.460692 -0.745862,0.684158 -1.478369,1.245052 -2.271343,1.873654 -0.437271,0.35118 -0.506831,0.995228 -0.155795,1.434967 0.349411,0.439057 0.990377,0.507857 1.426766,0.155794 0.861615,-0.682321 1.601995,-1.252055 2.410742,-1.996652 0.808748,0.744597 1.618828,1.314331 2.480441,1.996652 0.436393,0.352059 1.077353,0.283261 1.426766,-0.155794 0.351038,-0.439739 0.277375,-1.083787 -0.159884,-1.434967 -0.792979,-0.628602 -1.591082,-1.189496 -2.336946,-1.873654 0.952113,-1.147188 1.869915,-2.601029 2.447642,-4.460692 h 0.270592 c 0.561209,0 1.016774,-0.453711 1.016774,-1.016776 0,-0.563067 -0.455565,-1.020876 -1.016774,-1.020876 h -3.111838 v -1.016774 c 0,-0.563068 -0.455567,-1.0208743 -1.016775,-1.0208743 z m -1.668658,4.0753003 h 3.402916 c -0.438423,1.181552 -1.08891,2.13806 -1.734258,2.951929 -0.645345,-0.813869 -1.230238,-1.770309 -1.668658,-2.951929 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#c1272d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6.29744864;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect977" /></svg> \ No newline at end of file
diff --git a/application/resources/pe_colored/pe_colored.qrc b/application/resources/pe_colored/pe_colored.qrc
index 588e3ac0..fbaaf9e4 100644
--- a/application/resources/pe_colored/pe_colored.qrc
+++ b/application/resources/pe_colored/pe_colored.qrc
@@ -1,37 +1,38 @@
<!DOCTYPE RCC>
<RCC version="1.0">
- <qresource prefix="/icons/pe_colored">
- <file>index.theme</file>
- <file>scalable/about.svg</file>
- <file>scalable/accounts.svg</file>
- <file>scalable/bug.svg</file>
- <file>scalable/centralmods.svg</file>
- <file>scalable/checkupdate.svg</file>
- <file>scalable/copy.svg</file>
- <file>scalable/coremods.svg</file>
- <file>scalable/externaltools.svg</file>
- <file>scalable/help.svg</file>
- <file>scalable/instance-settings.svg</file>
- <file>scalable/jarmods.svg</file>
- <file>scalable/java.svg</file>
- <file>scalable/loadermods.svg</file>
- <file>scalable/log.svg</file>
- <file>scalable/minecraft.svg</file>
- <file>scalable/multimc.svg</file>
- <file>scalable/new.svg</file>
- <file>scalable/news.svg</file>
- <file>scalable/notes.svg</file>
- <file>scalable/patreon.svg</file>
- <file>scalable/proxy.svg</file>
- <file>scalable/quickmods.svg</file>
- <file>scalable/refresh.svg</file>
- <file>scalable/resourcepacks.svg</file>
- <file>scalable/screenshots.svg</file>
- <file>scalable/settings.svg</file>
- <file>scalable/status-bad.svg</file>
- <file>scalable/status-good.svg</file>
- <file>scalable/status-yellow.svg</file>
- <file>scalable/viewfolder.svg</file>
- <file>scalable/worlds.svg</file>
- </qresource>
+ <qresource prefix="/icons/pe_colored">
+ <file>index.theme</file>
+ <file>scalable/about.svg</file>
+ <file>scalable/accounts.svg</file>
+ <file>scalable/bug.svg</file>
+ <file>scalable/centralmods.svg</file>
+ <file>scalable/checkupdate.svg</file>
+ <file>scalable/copy.svg</file>
+ <file>scalable/coremods.svg</file>
+ <file>scalable/externaltools.svg</file>
+ <file>scalable/help.svg</file>
+ <file>scalable/instance-settings.svg</file>
+ <file>scalable/jarmods.svg</file>
+ <file>scalable/java.svg</file>
+ <file>scalable/language.svg</file>
+ <file>scalable/loadermods.svg</file>
+ <file>scalable/log.svg</file>
+ <file>scalable/minecraft.svg</file>
+ <file>scalable/multimc.svg</file>
+ <file>scalable/new.svg</file>
+ <file>scalable/news.svg</file>
+ <file>scalable/notes.svg</file>
+ <file>scalable/patreon.svg</file>
+ <file>scalable/proxy.svg</file>
+ <file>scalable/quickmods.svg</file>
+ <file>scalable/refresh.svg</file>
+ <file>scalable/resourcepacks.svg</file>
+ <file>scalable/screenshots.svg</file>
+ <file>scalable/settings.svg</file>
+ <file>scalable/status-bad.svg</file>
+ <file>scalable/status-good.svg</file>
+ <file>scalable/status-yellow.svg</file>
+ <file>scalable/viewfolder.svg</file>
+ <file>scalable/worlds.svg</file>
+ </qresource>
</RCC>
diff --git a/application/resources/pe_colored/scalable/language.svg b/application/resources/pe_colored/scalable/language.svg
new file mode 100644
index 00000000..80c1dcad
--- /dev/null
+++ b/application/resources/pe_colored/scalable/language.svg
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xml:space="preserve"
+ enable-background="new 0 0 32 32"
+ viewBox="0 0 32 32"
+ y="0px"
+ x="0px"
+ id="Calque_1"
+ version="1.1"><metadata
+ id="metadata19"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+ id="defs17" />
+<path
+ id="path2"
+ d="M28,6c0-1.1-0.9-2-2-2H6C4.9,4,4,4.9,4,6v20c0,1.1,0.9,2,2,2h20 c1.1,0,2-0.9,2-2V6z"
+ fill="#F2F2F2"
+ clip-rule="evenodd"
+ fill-rule="evenodd" />
+
+<g
+ id="g12">
+ <path
+ id="path6"
+ d="M6,28h20c1.1,0,2-0.9,2-2V9V6c0-1.1-0.9-2-2-2H6C4.9,4,4,4.9,4,6v3v17C4,27.1,4.9,28,6,28z"
+ fill="none" />
+ <path
+ id="path8"
+ d="M26,0H6C2.7,0,0,2.7,0,6v3h4V6c0-1.1,0.9-2,2-2h20c1.1,0,2,0.9,2,2v3h4V6C32,2.7,29.3,0,26,0z"
+ fill="#39B54A" />
+ <path
+ id="path10"
+ d="M28,26c0,1.1-0.9,2-2,2H6c-1.1,0-2-0.9-2-2V9H0v17c0,3.3,2.7,6,6,6h20c3.3,0,6-2.7,6-6V9h-4V26z"
+ fill="#8C6239" />
+</g>
+<path
+ d="m 9.1897919,10.114302 c -0.483841,0 -0.901102,0.341924 -0.996278,0.815883 l -2.029453,10.155454 c -0.110056,0.55031 0.246086,1.083011 0.795382,1.193069 0.556201,0.113982 1.084021,-0.246085 1.193073,-0.79538 l 0.651882,-3.247121 H 11.67433 l 0.647785,3.247121 c 0.110996,0.557485 0.658771,0.906193 1.197171,0.79538 0.549363,-0.110056 0.905437,-0.642759 0.795381,-1.193069 L 12.285214,10.930185 c -0.09517,-0.473959 -0.512431,-0.815883 -0.996274,-0.815883 z m 0.614982,2.287746 h 0.4345931 l 0.811779,4.063002 H 8.9929949 Z M 20.710512,9.7002137 c -0.561209,0 -1.016777,0.4578073 -1.016777,1.0208753 v 1.016774 h -3.046227 c -0.561204,0 -1.012672,0.457809 -1.012672,1.020876 0,0.563065 0.451466,1.016776 1.012672,1.016776 h 0.274696 c 0.577658,1.85973 1.425829,3.313572 2.37794,4.460692 -0.745862,0.684158 -1.478369,1.245052 -2.271343,1.873653 -0.437271,0.35118 -0.506831,0.995228 -0.155795,1.434967 0.349411,0.439057 0.990377,0.507857 1.426766,0.155794 0.861615,-0.682321 1.601995,-1.252055 2.410742,-1.996652 0.808748,0.744597 1.618828,1.314331 2.480441,1.996652 0.436393,0.352059 1.077353,0.283261 1.426766,-0.155794 0.351038,-0.439739 0.277375,-1.083787 -0.159884,-1.434967 -0.792979,-0.628601 -1.591082,-1.189495 -2.336946,-1.873653 0.952113,-1.147188 1.869915,-2.601029 2.447642,-4.460692 h 0.270592 c 0.561209,0 1.016774,-0.453711 1.016774,-1.016776 0,-0.563067 -0.455565,-1.020876 -1.016774,-1.020876 h -3.111838 v -1.016774 c 0,-0.563068 -0.455567,-1.0208753 -1.016775,-1.0208753 z m -1.668658,4.0753013 h 3.402916 c -0.438423,1.181552 -1.08891,2.13806 -1.734258,2.951929 -0.645345,-0.813869 -1.230238,-1.770309 -1.668658,-2.951929 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#c1272d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6.29744864;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect977" /></svg> \ No newline at end of file
diff --git a/application/resources/pe_dark/pe_dark.qrc b/application/resources/pe_dark/pe_dark.qrc
index 3543f590..a57b6a14 100644
--- a/application/resources/pe_dark/pe_dark.qrc
+++ b/application/resources/pe_dark/pe_dark.qrc
@@ -1,37 +1,38 @@
<!DOCTYPE RCC>
<RCC version="1.0">
- <qresource prefix="/icons/pe_dark">
- <file>index.theme</file>
- <file>scalable/about.svg</file>
- <file>scalable/accounts.svg</file>
- <file>scalable/bug.svg</file>
- <file>scalable/centralmods.svg</file>
- <file>scalable/checkupdate.svg</file>
- <file>scalable/copy.svg</file>
- <file>scalable/coremods.svg</file>
- <file>scalable/externaltools.svg</file>
- <file>scalable/help.svg</file>
- <file>scalable/instance-settings.svg</file>
- <file>scalable/jarmods.svg</file>
- <file>scalable/java.svg</file>
- <file>scalable/loadermods.svg</file>
- <file>scalable/log.svg</file>
- <file>scalable/minecraft.svg</file>
- <file>scalable/multimc.svg</file>
- <file>scalable/new.svg</file>
- <file>scalable/news.svg</file>
- <file>scalable/notes.svg</file>
- <file>scalable/patreon.svg</file>
- <file>scalable/proxy.svg</file>
- <file>scalable/quickmods.svg</file>
- <file>scalable/refresh.svg</file>
- <file>scalable/resourcepacks.svg</file>
- <file>scalable/screenshots.svg</file>
- <file>scalable/settings.svg</file>
- <file>scalable/status-bad.svg</file>
- <file>scalable/status-good.svg</file>
- <file>scalable/status-yellow.svg</file>
- <file>scalable/viewfolder.svg</file>
- <file>scalable/worlds.svg</file>
- </qresource>
+ <qresource prefix="/icons/pe_dark">
+ <file>index.theme</file>
+ <file>scalable/about.svg</file>
+ <file>scalable/accounts.svg</file>
+ <file>scalable/bug.svg</file>
+ <file>scalable/centralmods.svg</file>
+ <file>scalable/checkupdate.svg</file>
+ <file>scalable/copy.svg</file>
+ <file>scalable/coremods.svg</file>
+ <file>scalable/externaltools.svg</file>
+ <file>scalable/help.svg</file>
+ <file>scalable/instance-settings.svg</file>
+ <file>scalable/jarmods.svg</file>
+ <file>scalable/java.svg</file>
+ <file>scalable/language.svg</file>
+ <file>scalable/loadermods.svg</file>
+ <file>scalable/log.svg</file>
+ <file>scalable/minecraft.svg</file>
+ <file>scalable/multimc.svg</file>
+ <file>scalable/new.svg</file>
+ <file>scalable/news.svg</file>
+ <file>scalable/notes.svg</file>
+ <file>scalable/patreon.svg</file>
+ <file>scalable/proxy.svg</file>
+ <file>scalable/quickmods.svg</file>
+ <file>scalable/refresh.svg</file>
+ <file>scalable/resourcepacks.svg</file>
+ <file>scalable/screenshots.svg</file>
+ <file>scalable/settings.svg</file>
+ <file>scalable/status-bad.svg</file>
+ <file>scalable/status-good.svg</file>
+ <file>scalable/status-yellow.svg</file>
+ <file>scalable/viewfolder.svg</file>
+ <file>scalable/worlds.svg</file>
+ </qresource>
</RCC>
diff --git a/application/resources/pe_dark/scalable/language.svg b/application/resources/pe_dark/scalable/language.svg
new file mode 100644
index 00000000..1a9b4c5c
--- /dev/null
+++ b/application/resources/pe_dark/scalable/language.svg
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ id="Calque_1"
+ x="0px"
+ y="0px"
+ viewBox="0 0 32 32"
+ enable-background="new 0 0 32 32"
+ xml:space="preserve"><metadata
+ id="metadata45"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+ id="defs43" /><path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ d="M26,32H6c-3.3,0-6-2.7-6-6V6c0-3.3,2.7-6,6-6h20c3.3,0,6,2.7,6,6v20 C32,29.3,29.3,32,26,32z"
+ id="path2" /><path
+ fill-rule="evenodd"
+ clip-rule="evenodd"
+ fill="#F2F2F2"
+ d="M28,6c0-1.1-0.9-2-2-2H6C4.9,4,4,4.9,4,6v20c0,1.1,0.9,2,2,2h20 c1.1,0,2-0.9,2-2V6z"
+ id="path4" /><g
+ id="g10" /><g
+ id="g12" /><g
+ id="g14" /><g
+ id="g16" /><g
+ id="g18" /><g
+ id="g20" /><g
+ id="g22" /><g
+ id="g24" /><g
+ id="g26" /><g
+ id="g28" /><g
+ id="g30" /><g
+ id="g32" /><g
+ id="g34" /><g
+ id="g36" /><g
+ id="g38" /><path
+ d="m 9.1897911,10.114301 c -0.48384,0 -0.901101,0.341924 -0.996278,0.815883 l -2.029452,10.155455 c -0.110057,0.55031 0.246085,1.083011 0.795381,1.193069 0.556201,0.113982 1.084021,-0.246085 1.193073,-0.79538 l 0.651882,-3.247122 h 2.8699319 l 0.647785,3.247122 c 0.110996,0.557485 0.658771,0.906193 1.197171,0.79538 0.549363,-0.110056 0.905437,-0.642759 0.795381,-1.193069 L 12.285213,10.930184 c -0.09517,-0.473959 -0.512431,-0.815883 -0.996274,-0.815883 z m 0.614982,2.287746 h 0.4345929 l 0.811779,4.063002 H 8.9929941 Z M 20.710512,9.7002137 c -0.561209,0 -1.016777,0.4578063 -1.016777,1.0208743 v 1.016774 h -3.046227 c -0.561205,0 -1.012673,0.457809 -1.012673,1.020876 0,0.563065 0.451466,1.016776 1.012673,1.016776 h 0.274696 c 0.577658,1.85973 1.425829,3.313572 2.37794,4.460692 -0.745862,0.684158 -1.478369,1.245052 -2.271343,1.873654 -0.437271,0.35118 -0.506831,0.995228 -0.155795,1.434967 0.349411,0.439057 0.990377,0.507857 1.426766,0.155794 0.861615,-0.682321 1.601995,-1.252055 2.410742,-1.996652 0.808748,0.744597 1.618828,1.314331 2.480441,1.996652 0.436393,0.352059 1.077353,0.283261 1.426766,-0.155794 0.351038,-0.439739 0.277375,-1.083787 -0.159884,-1.434967 -0.792979,-0.628602 -1.591082,-1.189496 -2.336946,-1.873654 0.952113,-1.147188 1.869915,-2.601029 2.447642,-4.460692 h 0.270592 c 0.561209,0 1.016774,-0.453711 1.016774,-1.016776 0,-0.563067 -0.455565,-1.020876 -1.016774,-1.020876 h -3.111838 v -1.016774 c 0,-0.563068 -0.455567,-1.0208743 -1.016775,-1.0208743 z m -1.668658,4.0753003 h 3.402916 c -0.438423,1.181552 -1.08891,2.13806 -1.734258,2.951929 -0.645345,-0.813869 -1.230238,-1.770309 -1.668658,-2.951929 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#666666;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6.29744864;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect977" /></svg> \ No newline at end of file
diff --git a/application/resources/pe_light/pe_light.qrc b/application/resources/pe_light/pe_light.qrc
index f83d6eba..6d77c835 100644
--- a/application/resources/pe_light/pe_light.qrc
+++ b/application/resources/pe_light/pe_light.qrc
@@ -1,38 +1,39 @@
<!DOCTYPE RCC>
<RCC version="1.0">
- <qresource prefix="/icons/pe_light">
- <file>index.theme</file>
- <file>scalable/about.svg</file>
- <file>scalable/accounts.svg</file>
- <file>scalable/bug.svg</file>
- <file>scalable/centralmods.svg</file>
- <file>scalable/checkupdate.svg</file>
- <file>scalable/copy.svg</file>
- <file>scalable/coremods.svg</file>
- <file>scalable/externaltools.svg</file>
- <file>scalable/help.svg</file>
- <file>scalable/instance-settings.svg</file>
- <file>scalable/jarmods.svg</file>
- <file>scalable/java.svg</file>
- <file>scalable/loadermods.svg</file>
- <file>scalable/log.svg</file>
- <file>scalable/minecraft.svg</file>
- <file>scalable/multimc.svg</file>
- <file>scalable/new.svg</file>
- <file>scalable/news.svg</file>
- <file>scalable/notes.svg</file>
- <file>scalable/patreon.svg</file>
- <file>scalable/proxy.svg</file>
- <file>scalable/quickmods.svg</file>
- <file>scalable/refresh.svg</file>
- <file>scalable/resourcepacks.svg</file>
- <file>scalable/screenshots.svg</file>
- <file>scalable/settings.svg</file>
- <file>scalable/status-bad.svg</file>
- <file>scalable/status-good.svg</file>
- <file>scalable/status-yellow.svg</file>
- <file>scalable/viewfolder.svg</file>
- <file>scalable/worlds.svg</file>
- </qresource>
+ <qresource prefix="/icons/pe_light">
+ <file>index.theme</file>
+ <file>scalable/about.svg</file>
+ <file>scalable/accounts.svg</file>
+ <file>scalable/bug.svg</file>
+ <file>scalable/centralmods.svg</file>
+ <file>scalable/checkupdate.svg</file>
+ <file>scalable/copy.svg</file>
+ <file>scalable/coremods.svg</file>
+ <file>scalable/externaltools.svg</file>
+ <file>scalable/help.svg</file>
+ <file>scalable/instance-settings.svg</file>
+ <file>scalable/jarmods.svg</file>
+ <file>scalable/java.svg</file>
+ <file>scalable/language.svg</file>
+ <file>scalable/loadermods.svg</file>
+ <file>scalable/log.svg</file>
+ <file>scalable/minecraft.svg</file>
+ <file>scalable/multimc.svg</file>
+ <file>scalable/new.svg</file>
+ <file>scalable/news.svg</file>
+ <file>scalable/notes.svg</file>
+ <file>scalable/patreon.svg</file>
+ <file>scalable/proxy.svg</file>
+ <file>scalable/quickmods.svg</file>
+ <file>scalable/refresh.svg</file>
+ <file>scalable/resourcepacks.svg</file>
+ <file>scalable/screenshots.svg</file>
+ <file>scalable/settings.svg</file>
+ <file>scalable/status-bad.svg</file>
+ <file>scalable/status-good.svg</file>
+ <file>scalable/status-yellow.svg</file>
+ <file>scalable/viewfolder.svg</file>
+ <file>scalable/worlds.svg</file>
+ </qresource>
</RCC>
diff --git a/application/resources/pe_light/scalable/language.svg b/application/resources/pe_light/scalable/language.svg
new file mode 100644
index 00000000..57d5e3de
--- /dev/null
+++ b/application/resources/pe_light/scalable/language.svg
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xml:space="preserve"
+ enable-background="new 0 0 32 32"
+ viewBox="0 0 32 32"
+ y="0px"
+ x="0px"
+ id="Calque_1"
+ version="1.1"><metadata
+ id="metadata43"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+ id="defs41" />
+<path
+ id="path2"
+ d="M28,6c0-1.1-0.9-2-2-2H6C4.9,4,4,4.9,4,6v20c0,1.1,0.9,2,2,2h20 c1.1,0,2-0.9,2-2V6z"
+ fill="#4D4D4D"
+ clip-rule="evenodd"
+ fill-rule="evenodd" />
+
+<path
+ id="path6"
+ d="M26,32H6c-3.3,0-6-2.7-6-6V6c0-3.3,2.7-6,6-6h20c3.3,0,6,2.7,6,6 v20C32,29.3,29.3,32,26,32z M28,6c0-1.1-0.9-2-2-2H6C4.9,4,4,4.9,4,6v20c0,1.1,0.9,2,2,2h20c1.1,0,2-0.9,2-2V6z"
+ fill="#F2F2F2"
+ clip-rule="evenodd"
+ fill-rule="evenodd" />
+<g
+ id="g8">
+</g>
+<g
+ id="g10">
+</g>
+<g
+ id="g12">
+</g>
+<g
+ id="g14">
+</g>
+<g
+ id="g16">
+</g>
+<g
+ id="g18">
+</g>
+<g
+ id="g20">
+</g>
+<g
+ id="g22">
+</g>
+<g
+ id="g24">
+</g>
+<g
+ id="g26">
+</g>
+<g
+ id="g28">
+</g>
+<g
+ id="g30">
+</g>
+<g
+ id="g32">
+</g>
+<g
+ id="g34">
+</g>
+<g
+ id="g36">
+</g>
+<path
+ d="m 9.1897911,10.114301 c -0.48384,0 -0.901101,0.341924 -0.996278,0.815883 l -2.029452,10.155455 c -0.110057,0.55031 0.246085,1.083011 0.795381,1.193069 0.556201,0.113982 1.084021,-0.246085 1.193073,-0.79538 l 0.651882,-3.247122 h 2.8699319 l 0.647785,3.247122 c 0.110996,0.557485 0.658771,0.906193 1.197171,0.79538 0.549363,-0.110056 0.905437,-0.642759 0.795381,-1.193069 L 12.285213,10.930184 c -0.09517,-0.473959 -0.512431,-0.815883 -0.996274,-0.815883 z m 0.614982,2.287746 h 0.4345929 l 0.811779,4.063002 H 8.9929941 Z M 20.710512,9.7002137 c -0.561209,0 -1.016777,0.4578063 -1.016777,1.0208743 v 1.016774 h -3.046227 c -0.561205,0 -1.012673,0.457809 -1.012673,1.020876 0,0.563065 0.451466,1.016776 1.012673,1.016776 h 0.274696 c 0.577658,1.85973 1.425829,3.313572 2.37794,4.460692 -0.745862,0.684158 -1.478369,1.245052 -2.271343,1.873654 -0.437271,0.35118 -0.506831,0.995228 -0.155795,1.434967 0.349411,0.439057 0.990377,0.507857 1.426766,0.155794 0.861615,-0.682321 1.601995,-1.252055 2.410742,-1.996652 0.808748,0.744597 1.618828,1.314331 2.480441,1.996652 0.436393,0.352059 1.077353,0.283261 1.426766,-0.155794 0.351038,-0.439739 0.277375,-1.083787 -0.159884,-1.434967 -0.792979,-0.628602 -1.591082,-1.189496 -2.336946,-1.873654 0.952113,-1.147188 1.869915,-2.601029 2.447642,-4.460692 h 0.270592 c 0.561209,0 1.016774,-0.453711 1.016774,-1.016776 0,-0.563067 -0.455565,-1.020876 -1.016774,-1.020876 h -3.111838 v -1.016774 c 0,-0.563068 -0.455567,-1.0208743 -1.016775,-1.0208743 z m -1.668658,4.0753003 h 3.402916 c -0.438423,1.181552 -1.08891,2.13806 -1.734258,2.951929 -0.645345,-0.813869 -1.230238,-1.770309 -1.668658,-2.951929 z"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6.29744864;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect977" /></svg> \ No newline at end of file
diff --git a/application/setupwizard/AnalyticsWizardPage.cpp b/application/setupwizard/AnalyticsWizardPage.cpp
index 1109249b..6e063e99 100644
--- a/application/setupwizard/AnalyticsWizardPage.cpp
+++ b/application/setupwizard/AnalyticsWizardPage.cpp
@@ -8,22 +8,22 @@
#include <BuildConfig.h>
AnalyticsWizardPage::AnalyticsWizardPage(QWidget *parent)
- : BaseWizardPage(parent)
+ : BaseWizardPage(parent)
{
- setObjectName(QStringLiteral("analyticsPage"));
- verticalLayout_3 = new QVBoxLayout(this);
- verticalLayout_3->setObjectName(QStringLiteral("verticalLayout_3"));
- textBrowser = new QTextBrowser(this);
- textBrowser->setObjectName(QStringLiteral("textBrowser"));
- textBrowser->setAcceptRichText(false);
- textBrowser->setOpenExternalLinks(true);
- verticalLayout_3->addWidget(textBrowser);
+ setObjectName(QStringLiteral("analyticsPage"));
+ verticalLayout_3 = new QVBoxLayout(this);
+ verticalLayout_3->setObjectName(QStringLiteral("verticalLayout_3"));
+ textBrowser = new QTextBrowser(this);
+ textBrowser->setObjectName(QStringLiteral("textBrowser"));
+ textBrowser->setAcceptRichText(false);
+ textBrowser->setOpenExternalLinks(true);
+ verticalLayout_3->addWidget(textBrowser);
- checkBox = new QCheckBox(this);
- checkBox->setObjectName(QStringLiteral("checkBox"));
- checkBox->setChecked(true);
- verticalLayout_3->addWidget(checkBox);
- retranslate();
+ checkBox = new QCheckBox(this);
+ checkBox->setObjectName(QStringLiteral("checkBox"));
+ checkBox->setChecked(true);
+ verticalLayout_3->addWidget(checkBox);
+ retranslate();
}
AnalyticsWizardPage::~AnalyticsWizardPage()
@@ -32,29 +32,29 @@ AnalyticsWizardPage::~AnalyticsWizardPage()
bool AnalyticsWizardPage::validatePage()
{
- auto settings = MMC->settings();
- auto status = checkBox->isChecked();
- settings->set("Analytics", status);
- return true;
+ auto settings = MMC->settings();
+ auto status = checkBox->isChecked();
+ settings->set("Analytics", status);
+ return true;
}
void AnalyticsWizardPage::retranslate()
{
- setTitle(tr("Analytics"));
- setSubTitle(tr("We track some anonymous statistics about users."));
- textBrowser->setHtml(tr(
- "<html><body>"
- "<p>MultiMC sends anonymous usage statistics on every start of the application. This helps us decide what platforms and issues to focus on.</p>"
- "<p>The data is processed by Google Analytics, see their <a href=\"https://support.google.com/analytics/answer/6004245?hl=en\">article on the "
- "matter</a>.</p>"
- "<p>The following data is collected:</p>"
- "<ul><li>A random unique ID of the MultiMC installation.<br />It is stored in the application settings (multimc.cfg).</li>"
- "<li>Anonymized (partial) IP address.</li>"
- "<li>MultiMC version.</li>"
- "<li>Operating system name, version and architecture.</li>"
- "<li>CPU architecture (kernel architecture on linux).</li>"
- "<li>Size of system memory.</li>"
- "<li>Java version, architecture and memory settings.</li></ul>"
- "<p>If we change the tracked information, you will see this page again.</p></body></html>"));
- checkBox->setText(tr("Enable Analytics"));
+ setTitle(tr("Analytics"));
+ setSubTitle(tr("We track some anonymous statistics about users."));
+ textBrowser->setHtml(tr(
+ "<html><body>"
+ "<p>MultiMC sends anonymous usage statistics on every start of the application. This helps us decide what platforms and issues to focus on.</p>"
+ "<p>The data is processed by Google Analytics, see their <a href=\"https://support.google.com/analytics/answer/6004245?hl=en\">article on the "
+ "matter</a>.</p>"
+ "<p>The following data is collected:</p>"
+ "<ul><li>A random unique ID of the MultiMC installation.<br />It is stored in the application settings (multimc.cfg).</li>"
+ "<li>Anonymized (partial) IP address.</li>"
+ "<li>MultiMC version.</li>"
+ "<li>Operating system name, version and architecture.</li>"
+ "<li>CPU architecture (kernel architecture on linux).</li>"
+ "<li>Size of system memory.</li>"
+ "<li>Java version, architecture and memory settings.</li></ul>"
+ "<p>If we change the tracked information, you will see this page again.</p></body></html>"));
+ checkBox->setText(tr("Enable Analytics"));
}
diff --git a/application/setupwizard/AnalyticsWizardPage.h b/application/setupwizard/AnalyticsWizardPage.h
index 03de9cb0..c451db2c 100644
--- a/application/setupwizard/AnalyticsWizardPage.h
+++ b/application/setupwizard/AnalyticsWizardPage.h
@@ -8,18 +8,18 @@ class QCheckBox;
class AnalyticsWizardPage : public BaseWizardPage
{
- Q_OBJECT;
+ Q_OBJECT
public:
- explicit AnalyticsWizardPage(QWidget *parent = Q_NULLPTR);
- virtual ~AnalyticsWizardPage();
+ explicit AnalyticsWizardPage(QWidget *parent = Q_NULLPTR);
+ virtual ~AnalyticsWizardPage();
- bool validatePage() override;
+ bool validatePage() override;
protected:
- void retranslate() override;
+ void retranslate() override;
private:
- QVBoxLayout *verticalLayout_3 = nullptr;
- QTextBrowser *textBrowser = nullptr;
- QCheckBox *checkBox = nullptr;
+ QVBoxLayout *verticalLayout_3 = nullptr;
+ QTextBrowser *textBrowser = nullptr;
+ QCheckBox *checkBox = nullptr;
}; \ No newline at end of file
diff --git a/application/setupwizard/BaseWizardPage.h b/application/setupwizard/BaseWizardPage.h
index 9ad54e09..72dbecfd 100644
--- a/application/setupwizard/BaseWizardPage.h
+++ b/application/setupwizard/BaseWizardPage.h
@@ -6,28 +6,28 @@
class BaseWizardPage : public QWizardPage
{
public:
- explicit BaseWizardPage(QWidget *parent = Q_NULLPTR)
- : QWizardPage(parent)
- {
- }
- virtual ~BaseWizardPage() {};
+ explicit BaseWizardPage(QWidget *parent = Q_NULLPTR)
+ : QWizardPage(parent)
+ {
+ }
+ virtual ~BaseWizardPage() {};
- virtual bool wantsRefreshButton()
- {
- return false;
- }
- virtual void refresh()
- {
- }
+ virtual bool wantsRefreshButton()
+ {
+ return false;
+ }
+ virtual void refresh()
+ {
+ }
protected:
- virtual void retranslate() = 0;
- void changeEvent(QEvent * event) override
- {
- if (event->type() == QEvent::LanguageChange)
- {
- retranslate();
- }
- QWizardPage::changeEvent(event);
- }
+ virtual void retranslate() = 0;
+ void changeEvent(QEvent * event) override
+ {
+ if (event->type() == QEvent::LanguageChange)
+ {
+ retranslate();
+ }
+ QWizardPage::changeEvent(event);
+ }
};
diff --git a/application/setupwizard/JavaWizardPage.cpp b/application/setupwizard/JavaWizardPage.cpp
index cd2bca46..ad571c09 100644
--- a/application/setupwizard/JavaWizardPage.cpp
+++ b/application/setupwizard/JavaWizardPage.cpp
@@ -21,76 +21,76 @@
JavaWizardPage::JavaWizardPage(QWidget *parent)
- :BaseWizardPage(parent)
+ :BaseWizardPage(parent)
{
- setupUi();
+ setupUi();
}
void JavaWizardPage::setupUi()
{
- setObjectName(QStringLiteral("javaPage"));
- QVBoxLayout * layout = new QVBoxLayout(this);
+ setObjectName(QStringLiteral("javaPage"));
+ QVBoxLayout * layout = new QVBoxLayout(this);
- m_java_widget = new JavaSettingsWidget(this);
- layout->addWidget(m_java_widget);
- setLayout(layout);
+ m_java_widget = new JavaSettingsWidget(this);
+ layout->addWidget(m_java_widget);
+ setLayout(layout);
- retranslate();
+ retranslate();
}
void JavaWizardPage::refresh()
{
- m_java_widget->refresh();
+ m_java_widget->refresh();
}
void JavaWizardPage::initializePage()
{
- m_java_widget->initialize();
+ m_java_widget->initialize();
}
bool JavaWizardPage::wantsRefreshButton()
{
- return true;
+ return true;
}
bool JavaWizardPage::validatePage()
{
- auto settings = MMC->settings();
- auto result = m_java_widget->validate();
- switch(result)
- {
- default:
- case JavaSettingsWidget::ValidationStatus::Bad:
- {
- return false;
- }
- case JavaSettingsWidget::ValidationStatus::AllOK:
- {
- settings->set("JavaPath", m_java_widget->javaPath());
- }
- case JavaSettingsWidget::ValidationStatus::JavaBad:
- {
- // Memory
- auto s = MMC->settings();
- s->set("MinMemAlloc", m_java_widget->minHeapSize());
- s->set("MaxMemAlloc", m_java_widget->maxHeapSize());
- if (m_java_widget->permGenEnabled())
- {
- s->set("PermGen", m_java_widget->permGenSize());
- }
- else
- {
- s->reset("PermGen");
- }
- return true;
- }
- }
+ auto settings = MMC->settings();
+ auto result = m_java_widget->validate();
+ switch(result)
+ {
+ default:
+ case JavaSettingsWidget::ValidationStatus::Bad:
+ {
+ return false;
+ }
+ case JavaSettingsWidget::ValidationStatus::AllOK:
+ {
+ settings->set("JavaPath", m_java_widget->javaPath());
+ }
+ case JavaSettingsWidget::ValidationStatus::JavaBad:
+ {
+ // Memory
+ auto s = MMC->settings();
+ s->set("MinMemAlloc", m_java_widget->minHeapSize());
+ s->set("MaxMemAlloc", m_java_widget->maxHeapSize());
+ if (m_java_widget->permGenEnabled())
+ {
+ s->set("PermGen", m_java_widget->permGenSize());
+ }
+ else
+ {
+ s->reset("PermGen");
+ }
+ return true;
+ }
+ }
}
void JavaWizardPage::retranslate()
{
- setTitle(tr("Java"));
- setSubTitle(tr("You do not have a working Java set up yet or it went missing.\n"
- "Please select one of the following or browse for a java executable."));
- m_java_widget->retranslate();
+ setTitle(tr("Java"));
+ setSubTitle(tr("You do not have a working Java set up yet or it went missing.\n"
+ "Please select one of the following or browse for a java executable."));
+ m_java_widget->retranslate();
}
diff --git a/application/setupwizard/JavaWizardPage.h b/application/setupwizard/JavaWizardPage.h
index 4ea31d24..0d749039 100644
--- a/application/setupwizard/JavaWizardPage.h
+++ b/application/setupwizard/JavaWizardPage.h
@@ -6,24 +6,24 @@ class JavaSettingsWidget;
class JavaWizardPage : public BaseWizardPage
{
- Q_OBJECT;
+ Q_OBJECT
public:
- explicit JavaWizardPage(QWidget *parent = Q_NULLPTR);
+ explicit JavaWizardPage(QWidget *parent = Q_NULLPTR);
- virtual ~JavaWizardPage()
- {
- };
+ virtual ~JavaWizardPage()
+ {
+ };
- bool wantsRefreshButton() override;
- void refresh() override;
- void initializePage() override;
- bool validatePage() override;
+ bool wantsRefreshButton() override;
+ void refresh() override;
+ void initializePage() override;
+ bool validatePage() override;
protected: /* methods */
- void setupUi();
- void retranslate() override;
+ void setupUi();
+ void retranslate() override;
private: /* data */
- JavaSettingsWidget *m_java_widget = nullptr;
+ JavaSettingsWidget *m_java_widget = nullptr;
};
diff --git a/application/setupwizard/LanguageWizardPage.cpp b/application/setupwizard/LanguageWizardPage.cpp
index b884c91a..ca93c6f5 100644
--- a/application/setupwizard/LanguageWizardPage.cpp
+++ b/application/setupwizard/LanguageWizardPage.cpp
@@ -2,25 +2,19 @@
#include <MultiMC.h>
#include <translations/TranslationsModel.h>
+#include "widgets/LanguageSelectionWidget.h"
#include <QVBoxLayout>
-#include <QListView>
LanguageWizardPage::LanguageWizardPage(QWidget *parent)
- : BaseWizardPage(parent)
+ : BaseWizardPage(parent)
{
- setObjectName(QStringLiteral("languagePage"));
- verticalLayout = new QVBoxLayout(this);
- verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
- languageView = new QListView(this);
- languageView->setObjectName(QStringLiteral("languageView"));
- verticalLayout->addWidget(languageView);
- retranslate();
+ setObjectName(QStringLiteral("languagePage"));
+ auto layout = new QVBoxLayout(this);
+ mainWidget = new LanguageSelectionWidget(this);
+ layout->setContentsMargins(0,0,0,0);
+ layout->addWidget(mainWidget);
- auto translations = MMC->translations();
- auto index = translations->selectedIndex();
- languageView->setModel(translations.get());
- languageView->setCurrentIndex(index);
- connect(languageView->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &LanguageWizardPage::languageRowChanged);
+ retranslate();
}
LanguageWizardPage::~LanguageWizardPage()
@@ -29,38 +23,26 @@ LanguageWizardPage::~LanguageWizardPage()
bool LanguageWizardPage::wantsRefreshButton()
{
- return true;
+ return true;
}
void LanguageWizardPage::refresh()
{
- auto translations = MMC->translations();
- translations->downloadIndex();
+ auto translations = MMC->translations();
+ translations->downloadIndex();
}
bool LanguageWizardPage::validatePage()
{
- auto settings = MMC->settings();
- auto translations = MMC->translations();
- QString key = translations->data(languageView->currentIndex(), Qt::UserRole).toString();
- settings->set("Language", key);
- return true;
+ auto settings = MMC->settings();
+ QString key = mainWidget->getSelectedLanguageKey();
+ settings->set("Language", key);
+ return true;
}
void LanguageWizardPage::retranslate()
{
- setTitle(tr("Language"));
- setSubTitle(tr("Select the language to use in MultiMC"));
-}
-
-void LanguageWizardPage::languageRowChanged(const QModelIndex &current, const QModelIndex &previous)
-{
- if (current == previous)
- {
- return;
- }
- auto translations = MMC->translations();
- QString key = translations->data(current, Qt::UserRole).toString();
- translations->selectLanguage(key);
- translations->updateLanguage(key);
+ setTitle(tr("Language"));
+ setSubTitle(tr("Select the language to use in MultiMC"));
+ mainWidget->retranslate();
}
diff --git a/application/setupwizard/LanguageWizardPage.h b/application/setupwizard/LanguageWizardPage.h
index 8b55d57f..45a0e5c0 100644
--- a/application/setupwizard/LanguageWizardPage.h
+++ b/application/setupwizard/LanguageWizardPage.h
@@ -2,30 +2,25 @@
#include "BaseWizardPage.h"
-class QVBoxLayout;
-class QListView;
+class LanguageSelectionWidget;
class LanguageWizardPage : public BaseWizardPage
{
- Q_OBJECT;
+ Q_OBJECT
public:
- explicit LanguageWizardPage(QWidget *parent = Q_NULLPTR);
+ explicit LanguageWizardPage(QWidget *parent = Q_NULLPTR);
- virtual ~LanguageWizardPage();
+ virtual ~LanguageWizardPage();
- bool wantsRefreshButton() override;
+ bool wantsRefreshButton() override;
- void refresh() override;
+ void refresh() override;
- bool validatePage() override;
+ bool validatePage() override;
protected:
- void retranslate() override;
-
-protected slots:
- void languageRowChanged(const QModelIndex &current, const QModelIndex &previous);
+ void retranslate() override;
private:
- QVBoxLayout *verticalLayout = nullptr;
- QListView *languageView = nullptr;
+ LanguageSelectionWidget *mainWidget = nullptr;
};
diff --git a/application/setupwizard/SetupWizard.cpp b/application/setupwizard/SetupWizard.cpp
index c4b21713..5c2d60ac 100644
--- a/application/setupwizard/SetupWizard.cpp
+++ b/application/setupwizard/SetupWizard.cpp
@@ -12,74 +12,74 @@
SetupWizard::SetupWizard(QWidget *parent) : QWizard(parent)
{
- setObjectName(QStringLiteral("SetupWizard"));
- resize(615, 659);
- // make it ugly everywhere to avoid variability in theming
- setWizardStyle(QWizard::ClassicStyle);
- setOptions(QWizard::NoCancelButton | QWizard::IndependentPages | QWizard::HaveCustomButton1);
+ setObjectName(QStringLiteral("SetupWizard"));
+ resize(615, 659);
+ // make it ugly everywhere to avoid variability in theming
+ setWizardStyle(QWizard::ClassicStyle);
+ setOptions(QWizard::NoCancelButton | QWizard::IndependentPages | QWizard::HaveCustomButton1);
- retranslate();
+ retranslate();
- connect(this, &QWizard::currentIdChanged, this, &SetupWizard::pageChanged);
+ connect(this, &QWizard::currentIdChanged, this, &SetupWizard::pageChanged);
}
void SetupWizard::retranslate()
{
- setButtonText(QWizard::NextButton, tr("&Next >"));
- setButtonText(QWizard::BackButton, tr("< &Back"));
- setButtonText(QWizard::FinishButton, tr("&Finish"));
- setButtonText(QWizard::CustomButton1, tr("&Refresh"));
- setWindowTitle(tr("MultiMC Quick Setup"));
+ setButtonText(QWizard::NextButton, tr("&Next >"));
+ setButtonText(QWizard::BackButton, tr("< &Back"));
+ setButtonText(QWizard::FinishButton, tr("&Finish"));
+ setButtonText(QWizard::CustomButton1, tr("&Refresh"));
+ setWindowTitle(tr("MultiMC Quick Setup"));
}
BaseWizardPage * SetupWizard::getBasePage(int id)
{
- if(id == -1)
- return nullptr;
- auto pagePtr = page(id);
- if(!pagePtr)
- return nullptr;
- return dynamic_cast<BaseWizardPage *>(pagePtr);
+ if(id == -1)
+ return nullptr;
+ auto pagePtr = page(id);
+ if(!pagePtr)
+ return nullptr;
+ return dynamic_cast<BaseWizardPage *>(pagePtr);
}
BaseWizardPage * SetupWizard::getCurrentBasePage()
{
- return getBasePage(currentId());
+ return getBasePage(currentId());
}
void SetupWizard::pageChanged(int id)
{
- auto basePagePtr = getBasePage(id);
- if(!basePagePtr)
- {
- return;
- }
- if(basePagePtr->wantsRefreshButton())
- {
- setButtonLayout({QWizard::CustomButton1, QWizard::Stretch, QWizard::BackButton, QWizard::NextButton, QWizard::FinishButton});
- auto customButton = button(QWizard::CustomButton1);
- connect(customButton, &QAbstractButton::pressed, [&](){
- auto basePagePtr = getCurrentBasePage();
- if(basePagePtr)
- {
- basePagePtr->refresh();
- }
- });
- }
- else
- {
- setButtonLayout({QWizard::Stretch, QWizard::BackButton, QWizard::NextButton, QWizard::FinishButton});
- }
+ auto basePagePtr = getBasePage(id);
+ if(!basePagePtr)
+ {
+ return;
+ }
+ if(basePagePtr->wantsRefreshButton())
+ {
+ setButtonLayout({QWizard::CustomButton1, QWizard::Stretch, QWizard::BackButton, QWizard::NextButton, QWizard::FinishButton});
+ auto customButton = button(QWizard::CustomButton1);
+ connect(customButton, &QAbstractButton::pressed, [&](){
+ auto basePagePtr = getCurrentBasePage();
+ if(basePagePtr)
+ {
+ basePagePtr->refresh();
+ }
+ });
+ }
+ else
+ {
+ setButtonLayout({QWizard::Stretch, QWizard::BackButton, QWizard::NextButton, QWizard::FinishButton});
+ }
}
void SetupWizard::changeEvent(QEvent *event)
{
- if (event->type() == QEvent::LanguageChange)
- {
- retranslate();
- }
- QWizard::changeEvent(event);
+ if (event->type() == QEvent::LanguageChange)
+ {
+ retranslate();
+ }
+ QWizard::changeEvent(event);
}
SetupWizard::~SetupWizard()
diff --git a/application/setupwizard/SetupWizard.h b/application/setupwizard/SetupWizard.h
index e3292997..08b0d805 100644
--- a/application/setupwizard/SetupWizard.h
+++ b/application/setupwizard/SetupWizard.h
@@ -1,4 +1,4 @@
-/* Copyright 2017-2018 MultiMC Contributors
+/* Copyright 2017-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,20 +26,20 @@ class BaseWizardPage;
class SetupWizard : public QWizard
{
- Q_OBJECT
+ Q_OBJECT
public: /* con/destructors */
- explicit SetupWizard(QWidget *parent = 0);
- virtual ~SetupWizard();
+ explicit SetupWizard(QWidget *parent = 0);
+ virtual ~SetupWizard();
- void changeEvent(QEvent * event) override;
- BaseWizardPage *getBasePage(int id);
- BaseWizardPage *getCurrentBasePage();
+ void changeEvent(QEvent * event) override;
+ BaseWizardPage *getBasePage(int id);
+ BaseWizardPage *getCurrentBasePage();
private slots:
- void pageChanged(int id);
+ void pageChanged(int id);
private: /* methods */
- void retranslate();
+ void retranslate();
};
diff --git a/application/themes/BrightTheme.cpp b/application/themes/BrightTheme.cpp
index 2763c982..b9188bdd 100644
--- a/application/themes/BrightTheme.cpp
+++ b/application/themes/BrightTheme.cpp
@@ -2,55 +2,55 @@
QString BrightTheme::id()
{
- return "bright";
+ return "bright";
}
QString BrightTheme::name()
{
- return QObject::tr("Bright");
+ return QObject::tr("Bright");
}
bool BrightTheme::hasColorScheme()
{
- return true;
+ return true;
}
QPalette BrightTheme::colorScheme()
{
- QPalette brightPalette;
- brightPalette.setColor(QPalette::Window, QColor(239,240,241));
- brightPalette.setColor(QPalette::WindowText, QColor(49,54,59));
- brightPalette.setColor(QPalette::Base, QColor(252,252,252));
- brightPalette.setColor(QPalette::AlternateBase, QColor(239,240,241));
- brightPalette.setColor(QPalette::ToolTipBase, QColor(49,54,59));
- brightPalette.setColor(QPalette::ToolTipText, QColor(239,240,241));
- brightPalette.setColor(QPalette::Text, QColor(49,54,59));
- brightPalette.setColor(QPalette::Button, QColor(239,240,241));
- brightPalette.setColor(QPalette::ButtonText, QColor(49,54,59));
- brightPalette.setColor(QPalette::BrightText, Qt::red);
- brightPalette.setColor(QPalette::Link, QColor(41, 128, 185));
- brightPalette.setColor(QPalette::Highlight, QColor(61, 174, 233));
- brightPalette.setColor(QPalette::HighlightedText, QColor(239,240,241));
- return fadeInactive(brightPalette, fadeAmount(), fadeColor());
+ QPalette brightPalette;
+ brightPalette.setColor(QPalette::Window, QColor(239,240,241));
+ brightPalette.setColor(QPalette::WindowText, QColor(49,54,59));
+ brightPalette.setColor(QPalette::Base, QColor(252,252,252));
+ brightPalette.setColor(QPalette::AlternateBase, QColor(239,240,241));
+ brightPalette.setColor(QPalette::ToolTipBase, QColor(49,54,59));
+ brightPalette.setColor(QPalette::ToolTipText, QColor(239,240,241));
+ brightPalette.setColor(QPalette::Text, QColor(49,54,59));
+ brightPalette.setColor(QPalette::Button, QColor(239,240,241));
+ brightPalette.setColor(QPalette::ButtonText, QColor(49,54,59));
+ brightPalette.setColor(QPalette::BrightText, Qt::red);
+ brightPalette.setColor(QPalette::Link, QColor(41, 128, 185));
+ brightPalette.setColor(QPalette::Highlight, QColor(61, 174, 233));
+ brightPalette.setColor(QPalette::HighlightedText, QColor(239,240,241));
+ return fadeInactive(brightPalette, fadeAmount(), fadeColor());
}
double BrightTheme::fadeAmount()
{
- return 0.5;
+ return 0.5;
}
QColor BrightTheme::fadeColor()
{
- return QColor(239,240,241);
+ return QColor(239,240,241);
}
bool BrightTheme::hasStyleSheet()
{
- return false;
+ return false;
}
QString BrightTheme::appStyleSheet()
{
- return QString();
+ return QString();
}
diff --git a/application/themes/BrightTheme.h b/application/themes/BrightTheme.h
index 31b31b2d..c61f52d5 100644
--- a/application/themes/BrightTheme.h
+++ b/application/themes/BrightTheme.h
@@ -5,15 +5,15 @@
class BrightTheme: public FusionTheme
{
public:
- virtual ~BrightTheme() {}
+ virtual ~BrightTheme() {}
- QString id() override;
- QString name() override;
- bool hasStyleSheet() override;
- QString appStyleSheet() override;
- bool hasColorScheme() override;
- QPalette colorScheme() override;
- double fadeAmount() override;
- QColor fadeColor() override;
+ QString id() override;
+ QString name() override;
+ bool hasStyleSheet() override;
+ QString appStyleSheet() override;
+ bool hasColorScheme() override;
+ QPalette colorScheme() override;
+ double fadeAmount() override;
+ QColor fadeColor() override;
};
diff --git a/application/themes/CustomTheme.cpp b/application/themes/CustomTheme.cpp
index a6c7bf8c..3e3e27de 100644
--- a/application/themes/CustomTheme.cpp
+++ b/application/themes/CustomTheme.cpp
@@ -8,237 +8,237 @@ const char * styleFile = "themeStyle.css";
static bool readThemeJson(const QString &path, QPalette &palette, double &fadeAmount, QColor &fadeColor, QString &name, QString &widgets)
{
- QFileInfo pathInfo(path);
- if(pathInfo.exists() && pathInfo.isFile())
- {
- try
- {
- auto doc = Json::requireDocument(path, "Theme JSON file");
- const QJsonObject root = doc.object();
- name = Json::requireString(root, "name", "Theme name");
- widgets = Json::requireString(root, "widgets", "Qt widget theme");
- auto colorsRoot = Json::requireObject(root, "colors", "colors object");
- auto readColor = [&](QString colorName) -> QColor
- {
- auto colorValue = Json::ensureString(colorsRoot, colorName, QString());
- if(!colorValue.isEmpty())
- {
- QColor color(colorValue);
- if(!color.isValid())
- {
- qWarning() << "Color value" << colorValue << "for" << colorName << "was not recognized.";
- return QColor();
- }
- return color;
- }
- return QColor();
- };
- auto readAndSetColor = [&](QPalette::ColorRole role, QString colorName)
- {
- auto color = readColor(colorName);
- if(color.isValid())
- {
- palette.setColor(role, color);
- }
- else
- {
- qDebug() << "Color value for" << colorName << "was not present.";
- }
- };
-
- // palette
- readAndSetColor(QPalette::Window, "Window");
- readAndSetColor(QPalette::WindowText, "WindowText");
- readAndSetColor(QPalette::Base, "Base");
- readAndSetColor(QPalette::AlternateBase, "AlternateBase");
- readAndSetColor(QPalette::ToolTipBase, "ToolTipBase");
- readAndSetColor(QPalette::ToolTipText, "ToolTipText");
- readAndSetColor(QPalette::Text, "Text");
- readAndSetColor(QPalette::Button, "Button");
- readAndSetColor(QPalette::ButtonText, "ButtonText");
- readAndSetColor(QPalette::BrightText, "BrightText");
- readAndSetColor(QPalette::Link, "Link");
- readAndSetColor(QPalette::Highlight, "Highlight");
- readAndSetColor(QPalette::HighlightedText, "HighlightedText");
-
- //fade
- fadeColor = readColor("fadeColor");
- fadeAmount = Json::ensureDouble(colorsRoot, "fadeAmount", 0.5, "fade amount");
-
- }
- catch(Exception e)
- {
- qWarning() << "Couldn't load theme json: " << e.cause();
- return false;
- }
- }
- else
- {
- qDebug() << "No theme json present.";
- return false;
- }
- return true;
+ QFileInfo pathInfo(path);
+ if(pathInfo.exists() && pathInfo.isFile())
+ {
+ try
+ {
+ auto doc = Json::requireDocument(path, "Theme JSON file");
+ const QJsonObject root = doc.object();
+ name = Json::requireString(root, "name", "Theme name");
+ widgets = Json::requireString(root, "widgets", "Qt widget theme");
+ auto colorsRoot = Json::requireObject(root, "colors", "colors object");
+ auto readColor = [&](QString colorName) -> QColor
+ {
+ auto colorValue = Json::ensureString(colorsRoot, colorName, QString());
+ if(!colorValue.isEmpty())
+ {
+ QColor color(colorValue);
+ if(!color.isValid())
+ {
+ qWarning() << "Color value" << colorValue << "for" << colorName << "was not recognized.";
+ return QColor();
+ }
+ return color;
+ }
+ return QColor();
+ };
+ auto readAndSetColor = [&](QPalette::ColorRole role, QString colorName)
+ {
+ auto color = readColor(colorName);
+ if(color.isValid())
+ {
+ palette.setColor(role, color);
+ }
+ else
+ {
+ qDebug() << "Color value for" << colorName << "was not present.";
+ }
+ };
+
+ // palette
+ readAndSetColor(QPalette::Window, "Window");
+ readAndSetColor(QPalette::WindowText, "WindowText");
+ readAndSetColor(QPalette::Base, "Base");
+ readAndSetColor(QPalette::AlternateBase, "AlternateBase");
+ readAndSetColor(QPalette::ToolTipBase, "ToolTipBase");
+ readAndSetColor(QPalette::ToolTipText, "ToolTipText");
+ readAndSetColor(QPalette::Text, "Text");
+ readAndSetColor(QPalette::Button, "Button");
+ readAndSetColor(QPalette::ButtonText, "ButtonText");
+ readAndSetColor(QPalette::BrightText, "BrightText");
+ readAndSetColor(QPalette::Link, "Link");
+ readAndSetColor(QPalette::Highlight, "Highlight");
+ readAndSetColor(QPalette::HighlightedText, "HighlightedText");
+
+ //fade
+ fadeColor = readColor("fadeColor");
+ fadeAmount = Json::ensureDouble(colorsRoot, "fadeAmount", 0.5, "fade amount");
+
+ }
+ catch (const Exception &e)
+ {
+ qWarning() << "Couldn't load theme json: " << e.cause();
+ return false;
+ }
+ }
+ else
+ {
+ qDebug() << "No theme json present.";
+ return false;
+ }
+ return true;
}
static bool writeThemeJson(const QString &path, const QPalette &palette, double fadeAmount, QColor fadeColor, QString name, QString widgets)
{
- QJsonObject rootObj;
- rootObj.insert("name", name);
- rootObj.insert("widgets", widgets);
-
- QJsonObject colorsObj;
- auto insertColor = [&](QPalette::ColorRole role, QString colorName)
- {
- colorsObj.insert(colorName, palette.color(role).name());
- };
-
- // palette
- insertColor(QPalette::Window, "Window");
- insertColor(QPalette::WindowText, "WindowText");
- insertColor(QPalette::Base, "Base");
- insertColor(QPalette::AlternateBase, "AlternateBase");
- insertColor(QPalette::ToolTipBase, "ToolTipBase");
- insertColor(QPalette::ToolTipText, "ToolTipText");
- insertColor(QPalette::Text, "Text");
- insertColor(QPalette::Button, "Button");
- insertColor(QPalette::ButtonText, "ButtonText");
- insertColor(QPalette::BrightText, "BrightText");
- insertColor(QPalette::Link, "Link");
- insertColor(QPalette::Highlight, "Highlight");
- insertColor(QPalette::HighlightedText, "HighlightedText");
-
- // fade
- colorsObj.insert("fadeColor", fadeColor.name());
- colorsObj.insert("fadeAmount", fadeAmount);
-
- rootObj.insert("colors", colorsObj);
- try
- {
- Json::write(rootObj, path);
- return true;
- }
- catch (Exception e)
- {
- qWarning() << "Failed to write theme json to" << path;
- return false;
- }
+ QJsonObject rootObj;
+ rootObj.insert("name", name);
+ rootObj.insert("widgets", widgets);
+
+ QJsonObject colorsObj;
+ auto insertColor = [&](QPalette::ColorRole role, QString colorName)
+ {
+ colorsObj.insert(colorName, palette.color(role).name());
+ };
+
+ // palette
+ insertColor(QPalette::Window, "Window");
+ insertColor(QPalette::WindowText, "WindowText");
+ insertColor(QPalette::Base, "Base");
+ insertColor(QPalette::AlternateBase, "AlternateBase");
+ insertColor(QPalette::ToolTipBase, "ToolTipBase");
+ insertColor(QPalette::ToolTipText, "ToolTipText");
+ insertColor(QPalette::Text, "Text");
+ insertColor(QPalette::Button, "Button");
+ insertColor(QPalette::ButtonText, "ButtonText");
+ insertColor(QPalette::BrightText, "BrightText");
+ insertColor(QPalette::Link, "Link");
+ insertColor(QPalette::Highlight, "Highlight");
+ insertColor(QPalette::HighlightedText, "HighlightedText");
+
+ // fade
+ colorsObj.insert("fadeColor", fadeColor.name());
+ colorsObj.insert("fadeAmount", fadeAmount);
+
+ rootObj.insert("colors", colorsObj);
+ try
+ {
+ Json::write(rootObj, path);
+ return true;
+ }
+ catch (const Exception &e)
+ {
+ qWarning() << "Failed to write theme json to" << path;
+ return false;
+ }
}
CustomTheme::CustomTheme(ITheme* baseTheme, QString folder)
{
- m_id = folder;
- QString path = FS::PathCombine("themes", m_id);
- QString pathResources = FS::PathCombine("themes", m_id, "resources");
-
- qDebug() << "Loading theme" << m_id;
-
- if(!FS::ensureFolderPathExists(path) || !FS::ensureFolderPathExists(pathResources))
- {
- qWarning() << "couldn't create folder for theme!";
- m_palette = baseTheme->colorScheme();
- m_styleSheet = baseTheme->appStyleSheet();
- return;
- }
-
- auto themeFilePath = FS::PathCombine(path, themeFile);
-
- m_palette = baseTheme->colorScheme();
- if (!readThemeJson(themeFilePath, m_palette, m_fadeAmount, m_fadeColor, m_name, m_widgets))
- {
- m_name = "Custom";
- m_palette = baseTheme->colorScheme();
- m_fadeColor = baseTheme->fadeColor();
- m_fadeAmount = baseTheme->fadeAmount();
- m_widgets = baseTheme->qtTheme();
-
- QFileInfo info(themeFilePath);
- if(!info.exists())
- {
- writeThemeJson(themeFilePath, m_palette, m_fadeAmount, m_fadeColor, "Custom", m_widgets);
- }
- }
- else
- {
- m_palette = fadeInactive(m_palette, m_fadeAmount, m_fadeColor);
- }
-
- auto cssFilePath = FS::PathCombine(path, styleFile);
- QFileInfo info (cssFilePath);
- if(info.isFile())
- {
- try
- {
- // TODO: validate css?
- m_styleSheet = QString::fromUtf8(FS::read(cssFilePath));
- }
- catch(Exception e)
- {
- qWarning() << "Couldn't load css:" << e.cause() << "from" << cssFilePath;
- m_styleSheet = baseTheme->appStyleSheet();
- }
- }
- else
- {
- qDebug() << "No theme css present.";
- m_styleSheet = baseTheme->appStyleSheet();
- try
- {
- FS::write(cssFilePath, m_styleSheet.toUtf8());
- }
- catch(Exception e)
- {
- qWarning() << "Couldn't write css:" << e.cause() << "to" << cssFilePath;
- }
- }
+ m_id = folder;
+ QString path = FS::PathCombine("themes", m_id);
+ QString pathResources = FS::PathCombine("themes", m_id, "resources");
+
+ qDebug() << "Loading theme" << m_id;
+
+ if(!FS::ensureFolderPathExists(path) || !FS::ensureFolderPathExists(pathResources))
+ {
+ qWarning() << "couldn't create folder for theme!";
+ m_palette = baseTheme->colorScheme();
+ m_styleSheet = baseTheme->appStyleSheet();
+ return;
+ }
+
+ auto themeFilePath = FS::PathCombine(path, themeFile);
+
+ m_palette = baseTheme->colorScheme();
+ if (!readThemeJson(themeFilePath, m_palette, m_fadeAmount, m_fadeColor, m_name, m_widgets))
+ {
+ m_name = "Custom";
+ m_palette = baseTheme->colorScheme();
+ m_fadeColor = baseTheme->fadeColor();
+ m_fadeAmount = baseTheme->fadeAmount();
+ m_widgets = baseTheme->qtTheme();
+
+ QFileInfo info(themeFilePath);
+ if(!info.exists())
+ {
+ writeThemeJson(themeFilePath, m_palette, m_fadeAmount, m_fadeColor, "Custom", m_widgets);
+ }
+ }
+ else
+ {
+ m_palette = fadeInactive(m_palette, m_fadeAmount, m_fadeColor);
+ }
+
+ auto cssFilePath = FS::PathCombine(path, styleFile);
+ QFileInfo info (cssFilePath);
+ if(info.isFile())
+ {
+ try
+ {
+ // TODO: validate css?
+ m_styleSheet = QString::fromUtf8(FS::read(cssFilePath));
+ }
+ catch (const Exception &e)
+ {
+ qWarning() << "Couldn't load css:" << e.cause() << "from" << cssFilePath;
+ m_styleSheet = baseTheme->appStyleSheet();
+ }
+ }
+ else
+ {
+ qDebug() << "No theme css present.";
+ m_styleSheet = baseTheme->appStyleSheet();
+ try
+ {
+ FS::write(cssFilePath, m_styleSheet.toUtf8());
+ }
+ catch (const Exception &e)
+ {
+ qWarning() << "Couldn't write css:" << e.cause() << "to" << cssFilePath;
+ }
+ }
}
QStringList CustomTheme::searchPaths()
{
- return { FS::PathCombine("themes", m_id, "resources") };
+ return { FS::PathCombine("themes", m_id, "resources") };
}
QString CustomTheme::id()
{
- return m_id;
+ return m_id;
}
QString CustomTheme::name()
{
- return m_name;
+ return m_name;
}
bool CustomTheme::hasColorScheme()
{
- return true;
+ return true;
}
QPalette CustomTheme::colorScheme()
{
- return m_palette;
+ return m_palette;
}
bool CustomTheme::hasStyleSheet()
{
- return true;
+ return true;
}
QString CustomTheme::appStyleSheet()
{
- return m_styleSheet;
+ return m_styleSheet;
}
double CustomTheme::fadeAmount()
{
- return m_fadeAmount;
+ return m_fadeAmount;
}
QColor CustomTheme::fadeColor()
{
- return m_fadeColor;
+ return m_fadeColor;
}
QString CustomTheme::qtTheme()
{
- return m_widgets;
+ return m_widgets;
}
diff --git a/application/themes/CustomTheme.h b/application/themes/CustomTheme.h
index 9023b13e..d216895d 100644
--- a/application/themes/CustomTheme.h
+++ b/application/themes/CustomTheme.h
@@ -5,27 +5,27 @@
class CustomTheme: public ITheme
{
public:
- CustomTheme(ITheme * baseTheme, QString folder);
- virtual ~CustomTheme() {}
+ CustomTheme(ITheme * baseTheme, QString folder);
+ virtual ~CustomTheme() {}
- QString id() override;
- QString name() override;
- bool hasStyleSheet() override;
- QString appStyleSheet() override;
- bool hasColorScheme() override;
- QPalette colorScheme() override;
- double fadeAmount() override;
- QColor fadeColor() override;
- QString qtTheme() override;
- QStringList searchPaths() override;
+ QString id() override;
+ QString name() override;
+ bool hasStyleSheet() override;
+ QString appStyleSheet() override;
+ bool hasColorScheme() override;
+ QPalette colorScheme() override;
+ double fadeAmount() override;
+ QColor fadeColor() override;
+ QString qtTheme() override;
+ QStringList searchPaths() override;
private: /* data */
- QPalette m_palette;
- QColor m_fadeColor;
- double m_fadeAmount;
- QString m_styleSheet;
- QString m_name;
- QString m_id;
- QString m_widgets;
+ QPalette m_palette;
+ QColor m_fadeColor;
+ double m_fadeAmount;
+ QString m_styleSheet;
+ QString m_name;
+ QString m_id;
+ QString m_widgets;
};
diff --git a/application/themes/DarkTheme.cpp b/application/themes/DarkTheme.cpp
index cf4a81e1..31ecd559 100644
--- a/application/themes/DarkTheme.cpp
+++ b/application/themes/DarkTheme.cpp
@@ -2,54 +2,54 @@
QString DarkTheme::id()
{
- return "dark";
+ return "dark";
}
QString DarkTheme::name()
{
- return QObject::tr("Dark");
+ return QObject::tr("Dark");
}
bool DarkTheme::hasColorScheme()
{
- return true;
+ return true;
}
QPalette DarkTheme::colorScheme()
{
- QPalette darkPalette;
- darkPalette.setColor(QPalette::Window, QColor(49,54,59));
- darkPalette.setColor(QPalette::WindowText, Qt::white);
- darkPalette.setColor(QPalette::Base, QColor(35,38,41));
- darkPalette.setColor(QPalette::AlternateBase, QColor(49,54,59));
- darkPalette.setColor(QPalette::ToolTipBase, Qt::white);
- darkPalette.setColor(QPalette::ToolTipText, Qt::white);
- darkPalette.setColor(QPalette::Text, Qt::white);
- darkPalette.setColor(QPalette::Button, QColor(49,54,59));
- darkPalette.setColor(QPalette::ButtonText, Qt::white);
- darkPalette.setColor(QPalette::BrightText, Qt::red);
- darkPalette.setColor(QPalette::Link, QColor(42, 130, 218));
- darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218));
- darkPalette.setColor(QPalette::HighlightedText, Qt::black);
- return fadeInactive(darkPalette, fadeAmount(), fadeColor());
+ QPalette darkPalette;
+ darkPalette.setColor(QPalette::Window, QColor(49,54,59));
+ darkPalette.setColor(QPalette::WindowText, Qt::white);
+ darkPalette.setColor(QPalette::Base, QColor(35,38,41));
+ darkPalette.setColor(QPalette::AlternateBase, QColor(49,54,59));
+ darkPalette.setColor(QPalette::ToolTipBase, Qt::white);
+ darkPalette.setColor(QPalette::ToolTipText, Qt::white);
+ darkPalette.setColor(QPalette::Text, Qt::white);
+ darkPalette.setColor(QPalette::Button, QColor(49,54,59));
+ darkPalette.setColor(QPalette::ButtonText, Qt::white);
+ darkPalette.setColor(QPalette::BrightText, Qt::red);
+ darkPalette.setColor(QPalette::Link, QColor(42, 130, 218));
+ darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218));
+ darkPalette.setColor(QPalette::HighlightedText, Qt::black);
+ return fadeInactive(darkPalette, fadeAmount(), fadeColor());
}
double DarkTheme::fadeAmount()
{
- return 0.5;
+ return 0.5;
}
QColor DarkTheme::fadeColor()
{
- return QColor(49,54,59);
+ return QColor(49,54,59);
}
bool DarkTheme::hasStyleSheet()
{
- return true;
+ return true;
}
QString DarkTheme::appStyleSheet()
{
- return "QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }";
+ return "QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }";
}
diff --git a/application/themes/DarkTheme.h b/application/themes/DarkTheme.h
index f3c18e22..9bd2f343 100644
--- a/application/themes/DarkTheme.h
+++ b/application/themes/DarkTheme.h
@@ -5,14 +5,14 @@
class DarkTheme: public FusionTheme
{
public:
- virtual ~DarkTheme() {}
+ virtual ~DarkTheme() {}
- QString id() override;
- QString name() override;
- bool hasStyleSheet() override;
- QString appStyleSheet() override;
- bool hasColorScheme() override;
- QPalette colorScheme() override;
- double fadeAmount() override;
- QColor fadeColor() override;
+ QString id() override;
+ QString name() override;
+ bool hasStyleSheet() override;
+ QString appStyleSheet() override;
+ bool hasColorScheme() override;
+ QPalette colorScheme() override;
+ double fadeAmount() override;
+ QColor fadeColor() override;
};
diff --git a/application/themes/FusionTheme.cpp b/application/themes/FusionTheme.cpp
index aaf7b3d5..cf3286ba 100644
--- a/application/themes/FusionTheme.cpp
+++ b/application/themes/FusionTheme.cpp
@@ -2,5 +2,5 @@
QString FusionTheme::qtTheme()
{
- return "Fusion";
+ return "Fusion";
}
diff --git a/application/themes/FusionTheme.h b/application/themes/FusionTheme.h
index e2d9014c..ee34245a 100644
--- a/application/themes/FusionTheme.h
+++ b/application/themes/FusionTheme.h
@@ -5,7 +5,7 @@
class FusionTheme: public ITheme
{
public:
- virtual ~FusionTheme() {}
+ virtual ~FusionTheme() {}
- QString qtTheme() override;
+ QString qtTheme() override;
};
diff --git a/application/themes/ITheme.cpp b/application/themes/ITheme.cpp
index b1cecf57..bfec87e7 100644
--- a/application/themes/ITheme.cpp
+++ b/application/themes/ITheme.cpp
@@ -6,42 +6,42 @@
void ITheme::apply(bool)
{
- QApplication::setStyle(QStyleFactory::create(qtTheme()));
- if(hasColorScheme())
- {
- QApplication::setPalette(colorScheme());
- }
- if(hasStyleSheet())
- {
- MMC->setStyleSheet(appStyleSheet());
- }
- else
- {
- MMC->setStyleSheet(QString());
- }
- QDir::setSearchPaths("theme", searchPaths());
+ QApplication::setStyle(QStyleFactory::create(qtTheme()));
+ if(hasColorScheme())
+ {
+ QApplication::setPalette(colorScheme());
+ }
+ if(hasStyleSheet())
+ {
+ MMC->setStyleSheet(appStyleSheet());
+ }
+ else
+ {
+ MMC->setStyleSheet(QString());
+ }
+ QDir::setSearchPaths("theme", searchPaths());
}
QPalette ITheme::fadeInactive(QPalette in, qreal bias, QColor color)
{
- auto blend = [&in, bias, color](QPalette::ColorRole role)
- {
- QColor from = in.color(QPalette::Active, role);
- QColor blended = Rainbow::mix(from, color, bias);
- in.setColor(QPalette::Disabled, role, blended);
- };
- blend(QPalette::Window);
- blend(QPalette::WindowText);
- blend(QPalette::Base);
- blend(QPalette::AlternateBase);
- blend(QPalette::ToolTipBase);
- blend(QPalette::ToolTipText);
- blend(QPalette::Text);
- blend(QPalette::Button);
- blend(QPalette::ButtonText);
- blend(QPalette::BrightText);
- blend(QPalette::Link);
- blend(QPalette::Highlight);
- blend(QPalette::HighlightedText);
- return in;
+ auto blend = [&in, bias, color](QPalette::ColorRole role)
+ {
+ QColor from = in.color(QPalette::Active, role);
+ QColor blended = Rainbow::mix(from, color, bias);
+ in.setColor(QPalette::Disabled, role, blended);
+ };
+ blend(QPalette::Window);
+ blend(QPalette::WindowText);
+ blend(QPalette::Base);
+ blend(QPalette::AlternateBase);
+ blend(QPalette::ToolTipBase);
+ blend(QPalette::ToolTipText);
+ blend(QPalette::Text);
+ blend(QPalette::Button);
+ blend(QPalette::ButtonText);
+ blend(QPalette::BrightText);
+ blend(QPalette::Link);
+ blend(QPalette::Highlight);
+ blend(QPalette::HighlightedText);
+ return in;
}
diff --git a/application/themes/ITheme.h b/application/themes/ITheme.h
index b75001c2..c2347cf6 100644
--- a/application/themes/ITheme.h
+++ b/application/themes/ITheme.h
@@ -7,21 +7,21 @@ class QStyle;
class ITheme
{
public:
- virtual ~ITheme() {}
- virtual void apply(bool initial);
- virtual QString id() = 0;
- virtual QString name() = 0;
- virtual bool hasStyleSheet() = 0;
- virtual QString appStyleSheet() = 0;
- virtual QString qtTheme() = 0;
- virtual bool hasColorScheme() = 0;
- virtual QPalette colorScheme() = 0;
- virtual QColor fadeColor() = 0;
- virtual double fadeAmount() = 0;
- virtual QStringList searchPaths()
- {
- return {};
- }
+ virtual ~ITheme() {}
+ virtual void apply(bool initial);
+ virtual QString id() = 0;
+ virtual QString name() = 0;
+ virtual bool hasStyleSheet() = 0;
+ virtual QString appStyleSheet() = 0;
+ virtual QString qtTheme() = 0;
+ virtual bool hasColorScheme() = 0;
+ virtual QPalette colorScheme() = 0;
+ virtual QColor fadeColor() = 0;
+ virtual double fadeAmount() = 0;
+ virtual QStringList searchPaths()
+ {
+ return {};
+ }
- static QPalette fadeInactive(QPalette in, qreal bias, QColor color);
+ static QPalette fadeInactive(QPalette in, qreal bias, QColor color);
};
diff --git a/application/themes/SystemTheme.cpp b/application/themes/SystemTheme.cpp
index a9ee853a..00b2300d 100644
--- a/application/themes/SystemTheme.cpp
+++ b/application/themes/SystemTheme.cpp
@@ -6,75 +6,75 @@
SystemTheme::SystemTheme()
{
- const auto & style = QApplication::style();
- systemPalette = style->standardPalette();
- QString lowerThemeName = style->objectName();
- qDebug() << systemTheme;
- QStringList styles = QStyleFactory::keys();
- for(auto &st: styles)
- {
- if(st.toLower() == lowerThemeName)
- {
- systemTheme = st;
- return;
- }
- }
- // fall back to fusion if we can't find the current theme.
- systemTheme = "Fusion";
- qDebug() << "System theme not found, defaulted to Fusion";
+ const auto & style = QApplication::style();
+ systemPalette = style->standardPalette();
+ QString lowerThemeName = style->objectName();
+ qDebug() << systemTheme;
+ QStringList styles = QStyleFactory::keys();
+ for(auto &st: styles)
+ {
+ if(st.toLower() == lowerThemeName)
+ {
+ systemTheme = st;
+ return;
+ }
+ }
+ // fall back to fusion if we can't find the current theme.
+ systemTheme = "Fusion";
+ qDebug() << "System theme not found, defaulted to Fusion";
}
void SystemTheme::apply(bool initial)
{
- // if we are applying the system theme as the first theme, just don't touch anything. it's for the better...
- if(initial)
- {
- return;
- }
- ITheme::apply(initial);
+ // if we are applying the system theme as the first theme, just don't touch anything. it's for the better...
+ if(initial)
+ {
+ return;
+ }
+ ITheme::apply(initial);
}
QString SystemTheme::id()
{
- return "system";
+ return "system";
}
QString SystemTheme::name()
{
- return QObject::tr("System");
+ return QObject::tr("System");
}
QString SystemTheme::qtTheme()
{
- return systemTheme;
+ return systemTheme;
}
QPalette SystemTheme::colorScheme()
{
- return systemPalette;
+ return systemPalette;
}
QString SystemTheme::appStyleSheet()
{
- return QString();
+ return QString();
}
double SystemTheme::fadeAmount()
{
- return 0.5;
+ return 0.5;
}
QColor SystemTheme::fadeColor()
{
- return QColor(128,128,128);
+ return QColor(128,128,128);
}
bool SystemTheme::hasStyleSheet()
{
- return false;
+ return false;
}
bool SystemTheme::hasColorScheme()
{
- return true;
+ return true;
}
diff --git a/application/themes/SystemTheme.h b/application/themes/SystemTheme.h
index 18291b68..fe450600 100644
--- a/application/themes/SystemTheme.h
+++ b/application/themes/SystemTheme.h
@@ -5,20 +5,20 @@
class SystemTheme: public ITheme
{
public:
- SystemTheme();
- virtual ~SystemTheme() {}
- void apply(bool initial) override;
+ SystemTheme();
+ virtual ~SystemTheme() {}
+ void apply(bool initial) override;
- QString id() override;
- QString name() override;
- QString qtTheme() override;
- bool hasStyleSheet() override;
- QString appStyleSheet() override;
- bool hasColorScheme() override;
- QPalette colorScheme() override;
- double fadeAmount() override;
- QColor fadeColor() override;
+ QString id() override;
+ QString name() override;
+ QString qtTheme() override;
+ bool hasStyleSheet() override;
+ QString appStyleSheet() override;
+ bool hasColorScheme() override;
+ QPalette colorScheme() override;
+ double fadeAmount() override;
+ QColor fadeColor() override;
private:
- QPalette systemPalette;
- QString systemTheme;
+ QPalette systemPalette;
+ QString systemTheme;
};
diff --git a/application/widgets/Common.cpp b/application/widgets/Common.cpp
index 9b730d6c..f72f3596 100644
--- a/application/widgets/Common.cpp
+++ b/application/widgets/Common.cpp
@@ -2,26 +2,26 @@
// Origin: Qt
QStringList viewItemTextLayout(QTextLayout &textLayout, int lineWidth, qreal &height,
- qreal &widthUsed)
+ qreal &widthUsed)
{
- QStringList lines;
- height = 0;
- widthUsed = 0;
- textLayout.beginLayout();
- QString str = textLayout.text();
- while (true)
- {
- QTextLine line = textLayout.createLine();
- if (!line.isValid())
- break;
- if (line.textLength() == 0)
- break;
- line.setLineWidth(lineWidth);
- line.setPosition(QPointF(0, height));
- height += line.height();
- lines.append(str.mid(line.textStart(), line.textLength()));
- widthUsed = qMax(widthUsed, line.naturalTextWidth());
- }
- textLayout.endLayout();
- return lines;
+ QStringList lines;
+ height = 0;
+ widthUsed = 0;
+ textLayout.beginLayout();
+ QString str = textLayout.text();
+ while (true)
+ {
+ QTextLine line = textLayout.createLine();
+ if (!line.isValid())
+ break;
+ if (line.textLength() == 0)
+ break;
+ line.setLineWidth(lineWidth);
+ line.setPosition(QPointF(0, height));
+ height += line.height();
+ lines.append(str.mid(line.textStart(), line.textLength()));
+ widthUsed = qMax(widthUsed, line.naturalTextWidth());
+ }
+ textLayout.endLayout();
+ return lines;
}
diff --git a/application/widgets/Common.h b/application/widgets/Common.h
index fc46e08f..b3fbe1a0 100644
--- a/application/widgets/Common.h
+++ b/application/widgets/Common.h
@@ -3,4 +3,4 @@
#include <QTextLayout>
QStringList viewItemTextLayout(QTextLayout &textLayout, int lineWidth, qreal &height,
- qreal &widthUsed); \ No newline at end of file
+ qreal &widthUsed); \ No newline at end of file
diff --git a/application/widgets/CustomCommands.cpp b/application/widgets/CustomCommands.cpp
index 9f11e344..9e7673fd 100644
--- a/application/widgets/CustomCommands.cpp
+++ b/application/widgets/CustomCommands.cpp
@@ -6,43 +6,43 @@ CustomCommands::~CustomCommands()
}
CustomCommands::CustomCommands(QWidget* parent):
- QWidget(parent),
- ui(new Ui::CustomCommands)
+ QWidget(parent),
+ ui(new Ui::CustomCommands)
{
- ui->setupUi(this);
+ ui->setupUi(this);
}
void CustomCommands::initialize(bool checkable, bool checked, const QString& prelaunch, const QString& wrapper, const QString& postexit)
{
- ui->customCommandsGroupBox->setCheckable(checkable);
- if(checkable)
- {
- ui->customCommandsGroupBox->setChecked(checked);
- }
- ui->preLaunchCmdTextBox->setText(prelaunch);
- ui->wrapperCmdTextBox->setText(wrapper);
- ui->postExitCmdTextBox->setText(postexit);
+ ui->customCommandsGroupBox->setCheckable(checkable);
+ if(checkable)
+ {
+ ui->customCommandsGroupBox->setChecked(checked);
+ }
+ ui->preLaunchCmdTextBox->setText(prelaunch);
+ ui->wrapperCmdTextBox->setText(wrapper);
+ ui->postExitCmdTextBox->setText(postexit);
}
bool CustomCommands::checked() const
{
- if(!ui->customCommandsGroupBox->isCheckable())
- return true;
- return ui->customCommandsGroupBox->isChecked();
+ if(!ui->customCommandsGroupBox->isCheckable())
+ return true;
+ return ui->customCommandsGroupBox->isChecked();
}
QString CustomCommands::prelaunchCommand() const
{
- return ui->preLaunchCmdTextBox->text();
+ return ui->preLaunchCmdTextBox->text();
}
QString CustomCommands::wrapperCommand() const
{
- return ui->wrapperCmdTextBox->text();
+ return ui->wrapperCmdTextBox->text();
}
QString CustomCommands::postexitCommand() const
{
- return ui->postExitCmdTextBox->text();
+ return ui->postExitCmdTextBox->text();
}
diff --git a/application/widgets/CustomCommands.h b/application/widgets/CustomCommands.h
index 2bc7cb1a..451b2cc0 100644
--- a/application/widgets/CustomCommands.h
+++ b/application/widgets/CustomCommands.h
@@ -1,4 +1,4 @@
-/* Copyright 2018-2018 MultiMC Contributors
+/* Copyright 2018-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,20 +24,20 @@ class CustomCommands;
class CustomCommands : public QWidget
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit CustomCommands(QWidget *parent = 0);
- ~CustomCommands();
- void initialize(bool checkable, bool checked, const QString & prelaunch, const QString & wrapper, const QString & postexit);
+ explicit CustomCommands(QWidget *parent = 0);
+ ~CustomCommands();
+ void initialize(bool checkable, bool checked, const QString & prelaunch, const QString & wrapper, const QString & postexit);
- bool checked() const;
- QString prelaunchCommand() const;
- QString wrapperCommand() const;
- QString postexitCommand() const;
+ bool checked() const;
+ QString prelaunchCommand() const;
+ QString wrapperCommand() const;
+ QString postexitCommand() const;
private:
- Ui::CustomCommands *ui;
+ Ui::CustomCommands *ui;
};
diff --git a/application/widgets/CustomCommands.ui b/application/widgets/CustomCommands.ui
index d3bc86b8..c302fe39 100644
--- a/application/widgets/CustomCommands.ui
+++ b/application/widgets/CustomCommands.ui
@@ -14,6 +14,18 @@
<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="QGroupBox" name="customCommandsGroupBox">
<property name="enabled">
diff --git a/application/widgets/FocusLineEdit.cpp b/application/widgets/FocusLineEdit.cpp
index 139126c8..b272100c 100644
--- a/application/widgets/FocusLineEdit.cpp
+++ b/application/widgets/FocusLineEdit.cpp
@@ -3,23 +3,23 @@
FocusLineEdit::FocusLineEdit(QWidget *parent) : QLineEdit(parent)
{
- _selectOnMousePress = false;
+ _selectOnMousePress = false;
}
void FocusLineEdit::focusInEvent(QFocusEvent *e)
{
- QLineEdit::focusInEvent(e);
- selectAll();
- _selectOnMousePress = true;
+ QLineEdit::focusInEvent(e);
+ selectAll();
+ _selectOnMousePress = true;
}
void FocusLineEdit::mousePressEvent(QMouseEvent *me)
{
- QLineEdit::mousePressEvent(me);
- if (_selectOnMousePress)
- {
- selectAll();
- _selectOnMousePress = false;
- }
- qDebug() << selectedText();
+ QLineEdit::mousePressEvent(me);
+ if (_selectOnMousePress)
+ {
+ selectAll();
+ _selectOnMousePress = false;
+ }
+ qDebug() << selectedText();
}
diff --git a/application/widgets/FocusLineEdit.h b/application/widgets/FocusLineEdit.h
index 6d1c78a8..71b4f140 100644
--- a/application/widgets/FocusLineEdit.h
+++ b/application/widgets/FocusLineEdit.h
@@ -2,16 +2,16 @@
class FocusLineEdit : public QLineEdit
{
- Q_OBJECT
+ Q_OBJECT
public:
- FocusLineEdit(QWidget *parent);
- virtual ~FocusLineEdit()
- {
- }
+ FocusLineEdit(QWidget *parent);
+ virtual ~FocusLineEdit()
+ {
+ }
protected:
- void focusInEvent(QFocusEvent *e);
- void mousePressEvent(QMouseEvent *me);
+ void focusInEvent(QFocusEvent *e);
+ void mousePressEvent(QMouseEvent *me);
- bool _selectOnMousePress;
+ bool _selectOnMousePress;
};
diff --git a/application/widgets/IconLabel.cpp b/application/widgets/IconLabel.cpp
index 86c8a431..bf1c2358 100644
--- a/application/widgets/IconLabel.cpp
+++ b/application/widgets/IconLabel.cpp
@@ -7,37 +7,37 @@
#include <QRect>
IconLabel::IconLabel(QWidget *parent, QIcon icon, QSize size)
- : QWidget(parent), m_size(size), m_icon(icon)
+ : QWidget(parent), m_size(size), m_icon(icon)
{
- setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
}
QSize IconLabel::sizeHint() const
{
- return m_size;
+ return m_size;
}
void IconLabel::setIcon(QIcon icon)
{
- m_icon = icon;
- update();
+ m_icon = icon;
+ update();
}
void IconLabel::paintEvent(QPaintEvent *)
{
- QPainter p(this);
- QRect rect = contentsRect();
- int width = rect.width();
- int height = rect.height();
- if(width < height)
- {
- rect.setHeight(width);
- rect.translate(0, (height - width) / 2);
- }
- else if (width > height)
- {
- rect.setWidth(height);
- rect.translate((width - height) / 2, 0);
- }
- m_icon.paint(&p, rect);
+ QPainter p(this);
+ QRect rect = contentsRect();
+ int width = rect.width();
+ int height = rect.height();
+ if(width < height)
+ {
+ rect.setHeight(width);
+ rect.translate(0, (height - width) / 2);
+ }
+ else if (width > height)
+ {
+ rect.setWidth(height);
+ rect.translate((width - height) / 2, 0);
+ }
+ m_icon.paint(&p, rect);
}
diff --git a/application/widgets/IconLabel.h b/application/widgets/IconLabel.h
index a2f1eef3..6d212c4c 100644
--- a/application/widgets/IconLabel.h
+++ b/application/widgets/IconLabel.h
@@ -9,18 +9,18 @@ class QStyleOption;
*/
class IconLabel : public QWidget
{
- Q_OBJECT
+ Q_OBJECT
public:
- /// Create a line separator. orientation is the orientation of the line.
- explicit IconLabel(QWidget *parent, QIcon icon, QSize size);
+ /// 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 *);
+ virtual QSize sizeHint() const;
+ virtual void paintEvent(QPaintEvent *);
- void setIcon(QIcon icon);
+ void setIcon(QIcon icon);
private:
- QSize m_size;
- QIcon m_icon;
+ QSize m_size;
+ QIcon m_icon;
};
diff --git a/application/widgets/JavaSettingsWidget.cpp b/application/widgets/JavaSettingsWidget.cpp
index 1e9d5546..a11dd1aa 100644
--- a/application/widgets/JavaSettingsWidget.cpp
+++ b/application/widgets/JavaSettingsWidget.cpp
@@ -19,410 +19,410 @@
JavaSettingsWidget::JavaSettingsWidget(QWidget* parent) : QWidget(parent)
{
- m_availableMemory = Sys::getSystemRam() / Sys::megabyte;
-
- goodIcon = MMC->getThemedIcon("status-good");
- yellowIcon = MMC->getThemedIcon("status-yellow");
- badIcon = MMC->getThemedIcon("status-bad");
- setupUi();
-
- connect(m_minMemSpinBox, SIGNAL(valueChanged(int)), this, SLOT(memoryValueChanged(int)));
- connect(m_maxMemSpinBox, SIGNAL(valueChanged(int)), this, SLOT(memoryValueChanged(int)));
- connect(m_permGenSpinBox, SIGNAL(valueChanged(int)), this, SLOT(memoryValueChanged(int)));
- connect(m_versionWidget, &VersionSelectWidget::selectedVersionChanged, this, &JavaSettingsWidget::javaVersionSelected);
- connect(m_javaBrowseBtn, &QPushButton::clicked, this, &JavaSettingsWidget::on_javaBrowseBtn_clicked);
- connect(m_javaPathTextBox, &QLineEdit::textEdited, this, &JavaSettingsWidget::javaPathEdited);
- connect(m_javaStatusBtn, &QToolButton::clicked, this, &JavaSettingsWidget::on_javaStatusBtn_clicked);
+ m_availableMemory = Sys::getSystemRam() / Sys::megabyte;
+
+ goodIcon = MMC->getThemedIcon("status-good");
+ yellowIcon = MMC->getThemedIcon("status-yellow");
+ badIcon = MMC->getThemedIcon("status-bad");
+ setupUi();
+
+ connect(m_minMemSpinBox, SIGNAL(valueChanged(int)), this, SLOT(memoryValueChanged(int)));
+ connect(m_maxMemSpinBox, SIGNAL(valueChanged(int)), this, SLOT(memoryValueChanged(int)));
+ connect(m_permGenSpinBox, SIGNAL(valueChanged(int)), this, SLOT(memoryValueChanged(int)));
+ connect(m_versionWidget, &VersionSelectWidget::selectedVersionChanged, this, &JavaSettingsWidget::javaVersionSelected);
+ connect(m_javaBrowseBtn, &QPushButton::clicked, this, &JavaSettingsWidget::on_javaBrowseBtn_clicked);
+ connect(m_javaPathTextBox, &QLineEdit::textEdited, this, &JavaSettingsWidget::javaPathEdited);
+ connect(m_javaStatusBtn, &QToolButton::clicked, this, &JavaSettingsWidget::on_javaStatusBtn_clicked);
}
void JavaSettingsWidget::setupUi()
{
- setObjectName(QStringLiteral("javaSettingsWidget"));
- m_verticalLayout = new QVBoxLayout(this);
- m_verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
-
- m_versionWidget = new VersionSelectWidget(this);
- m_verticalLayout->addWidget(m_versionWidget);
-
- m_horizontalLayout = new QHBoxLayout();
- m_horizontalLayout->setObjectName(QStringLiteral("horizontalLayout"));
- m_javaPathTextBox = new QLineEdit(this);
- m_javaPathTextBox->setObjectName(QStringLiteral("javaPathTextBox"));
-
- m_horizontalLayout->addWidget(m_javaPathTextBox);
-
- m_javaBrowseBtn = new QPushButton(this);
- m_javaBrowseBtn->setObjectName(QStringLiteral("javaBrowseBtn"));
-
- m_horizontalLayout->addWidget(m_javaBrowseBtn);
-
- m_javaStatusBtn = new QToolButton(this);
- m_javaStatusBtn->setIcon(yellowIcon);
- m_horizontalLayout->addWidget(m_javaStatusBtn);
-
- m_verticalLayout->addLayout(m_horizontalLayout);
-
- m_memoryGroupBox = new QGroupBox(this);
- m_memoryGroupBox->setObjectName(QStringLiteral("memoryGroupBox"));
- m_gridLayout_2 = new QGridLayout(m_memoryGroupBox);
- m_gridLayout_2->setObjectName(QStringLiteral("gridLayout_2"));
-
- m_labelMinMem = new QLabel(m_memoryGroupBox);
- m_labelMinMem->setObjectName(QStringLiteral("labelMinMem"));
- m_gridLayout_2->addWidget(m_labelMinMem, 0, 0, 1, 1);
-
- m_minMemSpinBox = new QSpinBox(m_memoryGroupBox);
- m_minMemSpinBox->setObjectName(QStringLiteral("minMemSpinBox"));
- m_minMemSpinBox->setSuffix(QStringLiteral(" MB"));
- m_minMemSpinBox->setMinimum(128);
- m_minMemSpinBox->setMaximum(m_availableMemory);
- m_minMemSpinBox->setSingleStep(128);
- m_labelMinMem->setBuddy(m_minMemSpinBox);
- m_gridLayout_2->addWidget(m_minMemSpinBox, 0, 1, 1, 1);
-
- m_labelMaxMem = new QLabel(m_memoryGroupBox);
- m_labelMaxMem->setObjectName(QStringLiteral("labelMaxMem"));
- m_gridLayout_2->addWidget(m_labelMaxMem, 1, 0, 1, 1);
-
- m_maxMemSpinBox = new QSpinBox(m_memoryGroupBox);
- m_maxMemSpinBox->setObjectName(QStringLiteral("maxMemSpinBox"));
- m_maxMemSpinBox->setSuffix(QStringLiteral(" MB"));
- m_maxMemSpinBox->setMinimum(128);
- m_maxMemSpinBox->setMaximum(m_availableMemory);
- m_maxMemSpinBox->setSingleStep(128);
- m_labelMaxMem->setBuddy(m_maxMemSpinBox);
- m_gridLayout_2->addWidget(m_maxMemSpinBox, 1, 1, 1, 1);
-
- m_labelPermGen = new QLabel(m_memoryGroupBox);
- m_labelPermGen->setObjectName(QStringLiteral("labelPermGen"));
- m_labelPermGen->setText(QStringLiteral("PermGen:"));
- m_gridLayout_2->addWidget(m_labelPermGen, 2, 0, 1, 1);
- m_labelPermGen->setVisible(false);
-
- m_permGenSpinBox = new QSpinBox(m_memoryGroupBox);
- m_permGenSpinBox->setObjectName(QStringLiteral("permGenSpinBox"));
- m_permGenSpinBox->setSuffix(QStringLiteral(" MB"));
- m_permGenSpinBox->setMinimum(64);
- m_permGenSpinBox->setMaximum(m_availableMemory);
- m_permGenSpinBox->setSingleStep(8);
- m_gridLayout_2->addWidget(m_permGenSpinBox, 2, 1, 1, 1);
- m_permGenSpinBox->setVisible(false);
-
- m_verticalLayout->addWidget(m_memoryGroupBox);
-
- retranslate();
+ setObjectName(QStringLiteral("javaSettingsWidget"));
+ m_verticalLayout = new QVBoxLayout(this);
+ m_verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
+
+ m_versionWidget = new VersionSelectWidget(this);
+ m_verticalLayout->addWidget(m_versionWidget);
+
+ m_horizontalLayout = new QHBoxLayout();
+ m_horizontalLayout->setObjectName(QStringLiteral("horizontalLayout"));
+ m_javaPathTextBox = new QLineEdit(this);
+ m_javaPathTextBox->setObjectName(QStringLiteral("javaPathTextBox"));
+
+ m_horizontalLayout->addWidget(m_javaPathTextBox);
+
+ m_javaBrowseBtn = new QPushButton(this);
+ m_javaBrowseBtn->setObjectName(QStringLiteral("javaBrowseBtn"));
+
+ m_horizontalLayout->addWidget(m_javaBrowseBtn);
+
+ m_javaStatusBtn = new QToolButton(this);
+ m_javaStatusBtn->setIcon(yellowIcon);
+ m_horizontalLayout->addWidget(m_javaStatusBtn);
+
+ m_verticalLayout->addLayout(m_horizontalLayout);
+
+ m_memoryGroupBox = new QGroupBox(this);
+ m_memoryGroupBox->setObjectName(QStringLiteral("memoryGroupBox"));
+ m_gridLayout_2 = new QGridLayout(m_memoryGroupBox);
+ m_gridLayout_2->setObjectName(QStringLiteral("gridLayout_2"));
+
+ m_labelMinMem = new QLabel(m_memoryGroupBox);
+ m_labelMinMem->setObjectName(QStringLiteral("labelMinMem"));
+ m_gridLayout_2->addWidget(m_labelMinMem, 0, 0, 1, 1);
+
+ m_minMemSpinBox = new QSpinBox(m_memoryGroupBox);
+ m_minMemSpinBox->setObjectName(QStringLiteral("minMemSpinBox"));
+ m_minMemSpinBox->setSuffix(QStringLiteral(" MB"));
+ m_minMemSpinBox->setMinimum(128);
+ m_minMemSpinBox->setMaximum(m_availableMemory);
+ m_minMemSpinBox->setSingleStep(128);
+ m_labelMinMem->setBuddy(m_minMemSpinBox);
+ m_gridLayout_2->addWidget(m_minMemSpinBox, 0, 1, 1, 1);
+
+ m_labelMaxMem = new QLabel(m_memoryGroupBox);
+ m_labelMaxMem->setObjectName(QStringLiteral("labelMaxMem"));
+ m_gridLayout_2->addWidget(m_labelMaxMem, 1, 0, 1, 1);
+
+ m_maxMemSpinBox = new QSpinBox(m_memoryGroupBox);
+ m_maxMemSpinBox->setObjectName(QStringLiteral("maxMemSpinBox"));
+ m_maxMemSpinBox->setSuffix(QStringLiteral(" MB"));
+ m_maxMemSpinBox->setMinimum(128);
+ m_maxMemSpinBox->setMaximum(m_availableMemory);
+ m_maxMemSpinBox->setSingleStep(128);
+ m_labelMaxMem->setBuddy(m_maxMemSpinBox);
+ m_gridLayout_2->addWidget(m_maxMemSpinBox, 1, 1, 1, 1);
+
+ m_labelPermGen = new QLabel(m_memoryGroupBox);
+ m_labelPermGen->setObjectName(QStringLiteral("labelPermGen"));
+ m_labelPermGen->setText(QStringLiteral("PermGen:"));
+ m_gridLayout_2->addWidget(m_labelPermGen, 2, 0, 1, 1);
+ m_labelPermGen->setVisible(false);
+
+ m_permGenSpinBox = new QSpinBox(m_memoryGroupBox);
+ m_permGenSpinBox->setObjectName(QStringLiteral("permGenSpinBox"));
+ m_permGenSpinBox->setSuffix(QStringLiteral(" MB"));
+ m_permGenSpinBox->setMinimum(64);
+ m_permGenSpinBox->setMaximum(m_availableMemory);
+ m_permGenSpinBox->setSingleStep(8);
+ m_gridLayout_2->addWidget(m_permGenSpinBox, 2, 1, 1, 1);
+ m_permGenSpinBox->setVisible(false);
+
+ m_verticalLayout->addWidget(m_memoryGroupBox);
+
+ retranslate();
}
void JavaSettingsWidget::initialize()
{
- m_versionWidget->initialize(MMC->javalist().get());
- m_versionWidget->setResizeOn(2);
- auto s = MMC->settings();
- // Memory
- observedMinMemory = s->get("MinMemAlloc").toInt();
- observedMaxMemory = s->get("MaxMemAlloc").toInt();
- observedPermGenMemory = s->get("PermGen").toInt();
- m_minMemSpinBox->setValue(observedMinMemory);
- m_maxMemSpinBox->setValue(observedMaxMemory);
- m_permGenSpinBox->setValue(observedPermGenMemory);
+ m_versionWidget->initialize(MMC->javalist().get());
+ m_versionWidget->setResizeOn(2);
+ auto s = MMC->settings();
+ // Memory
+ observedMinMemory = s->get("MinMemAlloc").toInt();
+ observedMaxMemory = s->get("MaxMemAlloc").toInt();
+ observedPermGenMemory = s->get("PermGen").toInt();
+ m_minMemSpinBox->setValue(observedMinMemory);
+ m_maxMemSpinBox->setValue(observedMaxMemory);
+ m_permGenSpinBox->setValue(observedPermGenMemory);
}
void JavaSettingsWidget::refresh()
{
- m_versionWidget->loadList();
+ m_versionWidget->loadList();
}
JavaSettingsWidget::ValidationStatus JavaSettingsWidget::validate()
{
- switch(javaStatus)
- {
- default:
- case JavaStatus::NotSet:
- case JavaStatus::DoesNotExist:
- case JavaStatus::DoesNotStart:
- case JavaStatus::ReturnedInvalidData:
- {
- int button = CustomMessageBox::selectable(
- this,
- tr("No Java version selected"),
- tr("You didn't select a Java version or selected something that doesn't work.\n"
- "MultiMC will not be able to start Minecraft.\n"
- "Do you wish to proceed without any Java?"
- "\n\n"
- "You can change the Java version in the settings later.\n"
- ),
- QMessageBox::Warning,
- QMessageBox::Yes | QMessageBox::No,
- QMessageBox::NoButton
- )->exec();
- if(button == QMessageBox::No)
- {
- return ValidationStatus::Bad;
- }
- return ValidationStatus::JavaBad;
- }
- break;
- case JavaStatus::Pending:
- {
- return ValidationStatus::Bad;
- }
- case JavaStatus::Good:
- {
- return ValidationStatus::AllOK;
- }
- }
+ switch(javaStatus)
+ {
+ default:
+ case JavaStatus::NotSet:
+ case JavaStatus::DoesNotExist:
+ case JavaStatus::DoesNotStart:
+ case JavaStatus::ReturnedInvalidData:
+ {
+ int button = CustomMessageBox::selectable(
+ this,
+ tr("No Java version selected"),
+ tr("You didn't select a Java version or selected something that doesn't work.\n"
+ "MultiMC will not be able to start Minecraft.\n"
+ "Do you wish to proceed without any Java?"
+ "\n\n"
+ "You can change the Java version in the settings later.\n"
+ ),
+ QMessageBox::Warning,
+ QMessageBox::Yes | QMessageBox::No,
+ QMessageBox::NoButton
+ )->exec();
+ if(button == QMessageBox::No)
+ {
+ return ValidationStatus::Bad;
+ }
+ return ValidationStatus::JavaBad;
+ }
+ break;
+ case JavaStatus::Pending:
+ {
+ return ValidationStatus::Bad;
+ }
+ case JavaStatus::Good:
+ {
+ return ValidationStatus::AllOK;
+ }
+ }
}
QString JavaSettingsWidget::javaPath() const
{
- return m_javaPathTextBox->text();
+ return m_javaPathTextBox->text();
}
int JavaSettingsWidget::maxHeapSize() const
{
- return m_maxMemSpinBox->value();
+ return m_maxMemSpinBox->value();
}
int JavaSettingsWidget::minHeapSize() const
{
- return m_minMemSpinBox->value();
+ return m_minMemSpinBox->value();
}
bool JavaSettingsWidget::permGenEnabled() const
{
- return m_permGenSpinBox->isVisible();
+ return m_permGenSpinBox->isVisible();
}
int JavaSettingsWidget::permGenSize() const
{
- return m_permGenSpinBox->value();
+ return m_permGenSpinBox->value();
}
void JavaSettingsWidget::memoryValueChanged(int)
{
- bool actuallyChanged = false;
- int min = m_minMemSpinBox->value();
- int max = m_maxMemSpinBox->value();
- int permgen = m_permGenSpinBox->value();
- QObject *obj = sender();
- if (obj == m_minMemSpinBox && min != observedMinMemory)
- {
- observedMinMemory = min;
- actuallyChanged = true;
- if (min > max)
- {
- observedMaxMemory = min;
- m_maxMemSpinBox->setValue(min);
- }
- }
- else if (obj == m_maxMemSpinBox && max != observedMaxMemory)
- {
- observedMaxMemory = max;
- actuallyChanged = true;
- if (min > max)
- {
- observedMinMemory = max;
- m_minMemSpinBox->setValue(max);
- }
- }
- else if (obj == m_permGenSpinBox && permgen != observedPermGenMemory)
- {
- observedPermGenMemory = permgen;
- actuallyChanged = true;
- }
- if(actuallyChanged)
- {
- checkJavaPathOnEdit(m_javaPathTextBox->text());
- }
+ bool actuallyChanged = false;
+ int min = m_minMemSpinBox->value();
+ int max = m_maxMemSpinBox->value();
+ int permgen = m_permGenSpinBox->value();
+ QObject *obj = sender();
+ if (obj == m_minMemSpinBox && min != observedMinMemory)
+ {
+ observedMinMemory = min;
+ actuallyChanged = true;
+ if (min > max)
+ {
+ observedMaxMemory = min;
+ m_maxMemSpinBox->setValue(min);
+ }
+ }
+ else if (obj == m_maxMemSpinBox && max != observedMaxMemory)
+ {
+ observedMaxMemory = max;
+ actuallyChanged = true;
+ if (min > max)
+ {
+ observedMinMemory = max;
+ m_minMemSpinBox->setValue(max);
+ }
+ }
+ else if (obj == m_permGenSpinBox && permgen != observedPermGenMemory)
+ {
+ observedPermGenMemory = permgen;
+ actuallyChanged = true;
+ }
+ if(actuallyChanged)
+ {
+ checkJavaPathOnEdit(m_javaPathTextBox->text());
+ }
}
void JavaSettingsWidget::javaVersionSelected(BaseVersionPtr version)
{
- auto java = std::dynamic_pointer_cast<JavaInstall>(version);
- if(!java)
- {
- return;
- }
- auto visible = java->id.requiresPermGen();
- m_labelPermGen->setVisible(visible);
- m_permGenSpinBox->setVisible(visible);
- m_javaPathTextBox->setText(java->path);
- checkJavaPath(java->path);
+ auto java = std::dynamic_pointer_cast<JavaInstall>(version);
+ if(!java)
+ {
+ return;
+ }
+ auto visible = java->id.requiresPermGen();
+ m_labelPermGen->setVisible(visible);
+ m_permGenSpinBox->setVisible(visible);
+ m_javaPathTextBox->setText(java->path);
+ checkJavaPath(java->path);
}
void JavaSettingsWidget::on_javaBrowseBtn_clicked()
{
- QString filter;
+ QString filter;
#if defined Q_OS_WIN32
- filter = "Java (javaw.exe)";
+ filter = "Java (javaw.exe)";
#else
- filter = "Java (java)";
+ filter = "Java (java)";
#endif
- QString raw_path = QFileDialog::getOpenFileName(this, tr("Find Java executable"), QString(), filter);
- if(raw_path.isEmpty())
- {
- return;
- }
- QString cooked_path = FS::NormalizePath(raw_path);
- m_javaPathTextBox->setText(cooked_path);
- checkJavaPath(cooked_path);
+ QString raw_path = QFileDialog::getOpenFileName(this, tr("Find Java executable"), QString(), filter);
+ if(raw_path.isEmpty())
+ {
+ return;
+ }
+ QString cooked_path = FS::NormalizePath(raw_path);
+ m_javaPathTextBox->setText(cooked_path);
+ checkJavaPath(cooked_path);
}
void JavaSettingsWidget::on_javaStatusBtn_clicked()
{
- QString text;
- bool failed = false;
- switch(javaStatus)
- {
- case JavaStatus::NotSet:
- checkJavaPath(m_javaPathTextBox->text());
- return;
- case JavaStatus::DoesNotExist:
- text += QObject::tr("The specified file either doesn't exist or is not a proper executable.");
- failed = true;
- break;
- case JavaStatus::DoesNotStart:
- {
- text += QObject::tr("The specified java binary didn't start properly.<br />");
- auto htmlError = m_result.errorLog;
- if(!htmlError.isEmpty())
- {
- htmlError.replace('\n', "<br />");
- text += QString("<font color=\"red\">%1</font>").arg(htmlError);
- }
- failed = true;
- break;
- }
- case JavaStatus::ReturnedInvalidData:
- {
- text += QObject::tr("The specified java binary returned unexpected results:<br />");
- auto htmlOut = m_result.outLog;
- if(!htmlOut.isEmpty())
- {
- htmlOut.replace('\n', "<br />");
- text += QString("<font color=\"red\">%1</font>").arg(htmlOut);
- }
- failed = true;
- break;
- }
- case JavaStatus::Good:
- text += QObject::tr("Java test succeeded!<br />Platform reported: %1<br />Java version "
- "reported: %2<br />").arg(m_result.realPlatform, m_result.javaVersion.toString());
- break;
- case JavaStatus::Pending:
- // TODO: abort here?
- return;
- }
- CustomMessageBox::selectable(
- this,
- failed ? QObject::tr("Java test success") : QObject::tr("Java test failure"),
- text,
- failed ? QMessageBox::Critical : QMessageBox::Information
- )->show();
+ QString text;
+ bool failed = false;
+ switch(javaStatus)
+ {
+ case JavaStatus::NotSet:
+ checkJavaPath(m_javaPathTextBox->text());
+ return;
+ case JavaStatus::DoesNotExist:
+ text += QObject::tr("The specified file either doesn't exist or is not a proper executable.");
+ failed = true;
+ break;
+ case JavaStatus::DoesNotStart:
+ {
+ text += QObject::tr("The specified java binary didn't start properly.<br />");
+ auto htmlError = m_result.errorLog;
+ if(!htmlError.isEmpty())
+ {
+ htmlError.replace('\n', "<br />");
+ text += QString("<font color=\"red\">%1</font>").arg(htmlError);
+ }
+ failed = true;
+ break;
+ }
+ case JavaStatus::ReturnedInvalidData:
+ {
+ text += QObject::tr("The specified java binary returned unexpected results:<br />");
+ auto htmlOut = m_result.outLog;
+ if(!htmlOut.isEmpty())
+ {
+ htmlOut.replace('\n', "<br />");
+ text += QString("<font color=\"red\">%1</font>").arg(htmlOut);
+ }
+ failed = true;
+ break;
+ }
+ case JavaStatus::Good:
+ text += QObject::tr("Java test succeeded!<br />Platform reported: %1<br />Java version "
+ "reported: %2<br />").arg(m_result.realPlatform, m_result.javaVersion.toString());
+ break;
+ case JavaStatus::Pending:
+ // TODO: abort here?
+ return;
+ }
+ CustomMessageBox::selectable(
+ this,
+ failed ? QObject::tr("Java test success") : QObject::tr("Java test failure"),
+ text,
+ failed ? QMessageBox::Critical : QMessageBox::Information
+ )->show();
}
void JavaSettingsWidget::setJavaStatus(JavaSettingsWidget::JavaStatus status)
{
- javaStatus = status;
- switch(javaStatus)
- {
- case JavaStatus::Good:
- m_javaStatusBtn->setIcon(goodIcon);
- break;
- case JavaStatus::NotSet:
- case JavaStatus::Pending:
- m_javaStatusBtn->setIcon(yellowIcon);
- break;
- default:
- m_javaStatusBtn->setIcon(badIcon);
- break;
- }
+ javaStatus = status;
+ switch(javaStatus)
+ {
+ case JavaStatus::Good:
+ m_javaStatusBtn->setIcon(goodIcon);
+ break;
+ case JavaStatus::NotSet:
+ case JavaStatus::Pending:
+ m_javaStatusBtn->setIcon(yellowIcon);
+ break;
+ default:
+ m_javaStatusBtn->setIcon(badIcon);
+ break;
+ }
}
void JavaSettingsWidget::javaPathEdited(const QString& path)
{
- checkJavaPathOnEdit(path);
+ checkJavaPathOnEdit(path);
}
void JavaSettingsWidget::checkJavaPathOnEdit(const QString& path)
{
- auto realPath = FS::ResolveExecutable(path);
- QFileInfo pathInfo(realPath);
- if (pathInfo.baseName().toLower().contains("java"))
- {
- checkJavaPath(path);
- }
- else
- {
- if(!m_checker)
- {
- setJavaStatus(JavaStatus::NotSet);
- }
- }
+ auto realPath = FS::ResolveExecutable(path);
+ QFileInfo pathInfo(realPath);
+ if (pathInfo.baseName().toLower().contains("java"))
+ {
+ checkJavaPath(path);
+ }
+ else
+ {
+ if(!m_checker)
+ {
+ setJavaStatus(JavaStatus::NotSet);
+ }
+ }
}
void JavaSettingsWidget::checkJavaPath(const QString &path)
{
- if(m_checker)
- {
- queuedCheck = path;
- return;
- }
- auto realPath = FS::ResolveExecutable(path);
- if(realPath.isNull())
- {
- setJavaStatus(JavaStatus::DoesNotExist);
- return;
- }
- setJavaStatus(JavaStatus::Pending);
- m_checker.reset(new JavaChecker());
- m_checker->m_path = path;
- m_checker->m_minMem = m_minMemSpinBox->value();
- m_checker->m_maxMem = m_maxMemSpinBox->value();
- if(m_permGenSpinBox->isVisible())
- {
- m_checker->m_permGen = m_permGenSpinBox->value();
- }
- connect(m_checker.get(), &JavaChecker::checkFinished, this, &JavaSettingsWidget::checkFinished);
- m_checker->performCheck();
+ if(m_checker)
+ {
+ queuedCheck = path;
+ return;
+ }
+ auto realPath = FS::ResolveExecutable(path);
+ if(realPath.isNull())
+ {
+ setJavaStatus(JavaStatus::DoesNotExist);
+ return;
+ }
+ setJavaStatus(JavaStatus::Pending);
+ m_checker.reset(new JavaChecker());
+ m_checker->m_path = path;
+ m_checker->m_minMem = m_minMemSpinBox->value();
+ m_checker->m_maxMem = m_maxMemSpinBox->value();
+ if(m_permGenSpinBox->isVisible())
+ {
+ m_checker->m_permGen = m_permGenSpinBox->value();
+ }
+ connect(m_checker.get(), &JavaChecker::checkFinished, this, &JavaSettingsWidget::checkFinished);
+ m_checker->performCheck();
}
void JavaSettingsWidget::checkFinished(JavaCheckResult result)
{
- m_result = result;
- switch(result.validity)
- {
- case JavaCheckResult::Validity::Valid:
- {
- setJavaStatus(JavaStatus::Good);
- break;
- }
- case JavaCheckResult::Validity::ReturnedInvalidData:
- {
- setJavaStatus(JavaStatus::ReturnedInvalidData);
- break;
- }
- case JavaCheckResult::Validity::Errored:
- {
- setJavaStatus(JavaStatus::DoesNotStart);
- break;
- }
- }
- m_checker.reset();
- if(!queuedCheck.isNull())
- {
- checkJavaPath(queuedCheck);
- queuedCheck.clear();
- }
+ m_result = result;
+ switch(result.validity)
+ {
+ case JavaCheckResult::Validity::Valid:
+ {
+ setJavaStatus(JavaStatus::Good);
+ break;
+ }
+ case JavaCheckResult::Validity::ReturnedInvalidData:
+ {
+ setJavaStatus(JavaStatus::ReturnedInvalidData);
+ break;
+ }
+ case JavaCheckResult::Validity::Errored:
+ {
+ setJavaStatus(JavaStatus::DoesNotStart);
+ break;
+ }
+ }
+ m_checker.reset();
+ if(!queuedCheck.isNull())
+ {
+ checkJavaPath(queuedCheck);
+ queuedCheck.clear();
+ }
}
void JavaSettingsWidget::retranslate()
{
- m_memoryGroupBox->setTitle(tr("Memory"));
- m_maxMemSpinBox->setToolTip(tr("The maximum amount of memory Minecraft is allowed to use."));
- m_labelMinMem->setText(tr("Minimum memory allocation:"));
- m_labelMaxMem->setText(tr("Maximum memory allocation:"));
- m_minMemSpinBox->setToolTip(tr("The amount of memory Minecraft is started with."));
- m_permGenSpinBox->setToolTip(tr("The amount of memory available to store loaded Java classes."));
- m_javaBrowseBtn->setText(tr("Browse"));
+ m_memoryGroupBox->setTitle(tr("Memory"));
+ m_maxMemSpinBox->setToolTip(tr("The maximum amount of memory Minecraft is allowed to use."));
+ m_labelMinMem->setText(tr("Minimum memory allocation:"));
+ m_labelMaxMem->setText(tr("Maximum memory allocation:"));
+ m_minMemSpinBox->setToolTip(tr("The amount of memory Minecraft is started with."));
+ m_permGenSpinBox->setToolTip(tr("The amount of memory available to store loaded Java classes."));
+ m_javaBrowseBtn->setText(tr("Browse"));
}
diff --git a/application/widgets/JavaSettingsWidget.h b/application/widgets/JavaSettingsWidget.h
index 3a94f851..0d280daf 100644
--- a/application/widgets/JavaSettingsWidget.h
+++ b/application/widgets/JavaSettingsWidget.h
@@ -22,81 +22,81 @@ class QToolButton;
*/
class JavaSettingsWidget : public QWidget
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit JavaSettingsWidget(QWidget *parent);
- virtual ~JavaSettingsWidget() {};
+ explicit JavaSettingsWidget(QWidget *parent);
+ virtual ~JavaSettingsWidget() {};
- enum class JavaStatus
- {
- NotSet,
- Pending,
- Good,
- DoesNotExist,
- DoesNotStart,
- ReturnedInvalidData
- } javaStatus = JavaStatus::NotSet;
+ enum class JavaStatus
+ {
+ NotSet,
+ Pending,
+ Good,
+ DoesNotExist,
+ DoesNotStart,
+ ReturnedInvalidData
+ } javaStatus = JavaStatus::NotSet;
- enum class ValidationStatus
- {
- Bad,
- JavaBad,
- AllOK
- };
+ enum class ValidationStatus
+ {
+ Bad,
+ JavaBad,
+ AllOK
+ };
- void refresh();
- void initialize();
- ValidationStatus validate();
- void retranslate();
+ void refresh();
+ void initialize();
+ ValidationStatus validate();
+ void retranslate();
- bool permGenEnabled() const;
- int permGenSize() const;
- int minHeapSize() const;
- int maxHeapSize() const;
- QString javaPath() const;
+ bool permGenEnabled() const;
+ int permGenSize() const;
+ int minHeapSize() const;
+ int maxHeapSize() const;
+ QString javaPath() const;
protected slots:
- void memoryValueChanged(int);
- void javaPathEdited(const QString &path);
- void javaVersionSelected(BaseVersionPtr version);
- void on_javaBrowseBtn_clicked();
- void on_javaStatusBtn_clicked();
- void checkFinished(JavaCheckResult result);
+ void memoryValueChanged(int);
+ void javaPathEdited(const QString &path);
+ void javaVersionSelected(BaseVersionPtr version);
+ void on_javaBrowseBtn_clicked();
+ void on_javaStatusBtn_clicked();
+ void checkFinished(JavaCheckResult result);
protected: /* methods */
- void checkJavaPathOnEdit(const QString &path);
- void checkJavaPath(const QString &path);
- void setJavaStatus(JavaStatus status);
- void setupUi();
+ void checkJavaPathOnEdit(const QString &path);
+ void checkJavaPath(const QString &path);
+ void setJavaStatus(JavaStatus status);
+ void setupUi();
private: /* data */
- VersionSelectWidget *m_versionWidget = nullptr;
- QVBoxLayout *m_verticalLayout = nullptr;
+ VersionSelectWidget *m_versionWidget = nullptr;
+ QVBoxLayout *m_verticalLayout = nullptr;
- QLineEdit * m_javaPathTextBox = nullptr;
- QPushButton * m_javaBrowseBtn = nullptr;
- QToolButton * m_javaStatusBtn = nullptr;
- QHBoxLayout *m_horizontalLayout = nullptr;
+ QLineEdit * m_javaPathTextBox = nullptr;
+ QPushButton * m_javaBrowseBtn = nullptr;
+ QToolButton * m_javaStatusBtn = nullptr;
+ QHBoxLayout *m_horizontalLayout = nullptr;
- QGroupBox *m_memoryGroupBox = nullptr;
- QGridLayout *m_gridLayout_2 = nullptr;
- QSpinBox *m_maxMemSpinBox = nullptr;
- QLabel *m_labelMinMem = nullptr;
- QLabel *m_labelMaxMem = nullptr;
- QSpinBox *m_minMemSpinBox = nullptr;
- QLabel *m_labelPermGen = nullptr;
- QSpinBox *m_permGenSpinBox = nullptr;
- QIcon goodIcon;
- QIcon yellowIcon;
- QIcon badIcon;
+ QGroupBox *m_memoryGroupBox = nullptr;
+ QGridLayout *m_gridLayout_2 = nullptr;
+ QSpinBox *m_maxMemSpinBox = nullptr;
+ QLabel *m_labelMinMem = nullptr;
+ QLabel *m_labelMaxMem = nullptr;
+ QSpinBox *m_minMemSpinBox = nullptr;
+ QLabel *m_labelPermGen = nullptr;
+ QSpinBox *m_permGenSpinBox = nullptr;
+ QIcon goodIcon;
+ QIcon yellowIcon;
+ QIcon badIcon;
- int observedMinMemory = 0;
- int observedMaxMemory = 0;
- int observedPermGenMemory = 0;
- QString queuedCheck;
- uint64_t m_availableMemory = 0ull;
- shared_qobject_ptr<JavaChecker> m_checker;
- JavaCheckResult m_result;
+ int observedMinMemory = 0;
+ int observedMaxMemory = 0;
+ int observedPermGenMemory = 0;
+ QString queuedCheck;
+ uint64_t m_availableMemory = 0ull;
+ shared_qobject_ptr<JavaChecker> m_checker;
+ JavaCheckResult m_result;
};
diff --git a/application/widgets/LabeledToolButton.cpp b/application/widgets/LabeledToolButton.cpp
index 744d2e00..ab273b65 100644
--- a/application/widgets/LabeledToolButton.cpp
+++ b/application/widgets/LabeledToolButton.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,32 +28,32 @@
*/
LabeledToolButton::LabeledToolButton(QWidget * parent)
- : QToolButton(parent)
- , m_label(new QLabel(this))
+ : QToolButton(parent)
+ , m_label(new QLabel(this))
{
- //QToolButton::setText(" ");
- m_label->setWordWrap(true);
- m_label->setMouseTracking(false);
- m_label->setAlignment(Qt::AlignCenter);
- m_label->setTextInteractionFlags(Qt::NoTextInteraction);
- // somehow, this makes word wrap work in the QLabel. yay.
- //m_label->setMinimumWidth(100);
+ //QToolButton::setText(" ");
+ m_label->setWordWrap(true);
+ m_label->setMouseTracking(false);
+ m_label->setAlignment(Qt::AlignCenter);
+ m_label->setTextInteractionFlags(Qt::NoTextInteraction);
+ // somehow, this makes word wrap work in the QLabel. yay.
+ //m_label->setMinimumWidth(100);
}
QString LabeledToolButton::text() const
{
- return m_label->text();
+ return m_label->text();
}
void LabeledToolButton::setText(const QString & text)
{
- m_label->setText(text);
+ m_label->setText(text);
}
void LabeledToolButton::setIcon(QIcon icon)
{
- m_icon = icon;
- resetIcon();
+ m_icon = icon;
+ resetIcon();
}
@@ -62,54 +62,54 @@ void LabeledToolButton::setIcon(QIcon icon)
*/
QSize LabeledToolButton::sizeHint() const
{
- /*
- Q_D(const QToolButton);
- if (d->sizeHint.isValid())
- return d->sizeHint;
- */
- ensurePolished();
+ /*
+ Q_D(const QToolButton);
+ if (d->sizeHint.isValid())
+ return d->sizeHint;
+ */
+ ensurePolished();
- int w = 0, h = 0;
- QStyleOptionToolButton opt;
- initStyleOption(&opt);
- QSize sz =m_label->sizeHint();
- w = sz.width();
- h = sz.height();
+ int w = 0, h = 0;
+ QStyleOptionToolButton opt;
+ initStyleOption(&opt);
+ QSize sz =m_label->sizeHint();
+ w = sz.width();
+ h = sz.height();
- opt.rect.setSize(QSize(w, h)); // PM_MenuButtonIndicator depends on the height
- if (popupMode() == MenuButtonPopup)
- w += style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt, this);
-
- QSize rawSize = style()->sizeFromContents(QStyle::CT_ToolButton, &opt, QSize(w, h), this);
- QSize sizeHint = rawSize.expandedTo(QApplication::globalStrut());
- return sizeHint;
+ opt.rect.setSize(QSize(w, h)); // PM_MenuButtonIndicator depends on the height
+ if (popupMode() == MenuButtonPopup)
+ w += style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt, this);
+
+ QSize rawSize = style()->sizeFromContents(QStyle::CT_ToolButton, &opt, QSize(w, h), this);
+ QSize sizeHint = rawSize.expandedTo(QApplication::globalStrut());
+ return sizeHint;
}
void LabeledToolButton::resizeEvent(QResizeEvent * event)
{
- m_label->setGeometry(QRect(4, 4, width()-8, height()-8));
- if(!m_icon.isNull())
- {
- resetIcon();
- }
- QWidget::resizeEvent(event);
+ m_label->setGeometry(QRect(4, 4, width()-8, height()-8));
+ if(!m_icon.isNull())
+ {
+ resetIcon();
+ }
+ QWidget::resizeEvent(event);
}
void LabeledToolButton::resetIcon()
{
- auto iconSz = m_icon.actualSize(QSize(160, 80));
- float w = iconSz.width();
- float h = iconSz.height();
- float ar = w/h;
- // FIXME: hardcoded max size of 160x80
- int newW = 80 * ar;
- if(newW > 160)
- newW = 160;
- QSize newSz (newW, 80);
- auto pixmap = m_icon.pixmap(newSz);
- m_label->setPixmap(pixmap);
- m_label->setMinimumHeight(80);
- m_label->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred );
+ auto iconSz = m_icon.actualSize(QSize(160, 80));
+ float w = iconSz.width();
+ float h = iconSz.height();
+ float ar = w/h;
+ // FIXME: hardcoded max size of 160x80
+ int newW = 80 * ar;
+ if(newW > 160)
+ newW = 160;
+ QSize newSz (newW, 80);
+ auto pixmap = m_icon.pixmap(newSz);
+ m_label->setPixmap(pixmap);
+ m_label->setMinimumHeight(80);
+ m_label->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred );
}
diff --git a/application/widgets/LabeledToolButton.h b/application/widgets/LabeledToolButton.h
index 151a5c2c..136ebd23 100644
--- a/application/widgets/LabeledToolButton.h
+++ b/application/widgets/LabeledToolButton.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,19 +22,19 @@ class QLabel;
class LabeledToolButton : public QToolButton
{
- Q_OBJECT
+ Q_OBJECT
- QLabel * m_label;
- QIcon m_icon;
+ QLabel * m_label;
+ QIcon m_icon;
public:
- LabeledToolButton(QWidget * parent = 0);
+ LabeledToolButton(QWidget * parent = 0);
- QString text() const;
- void setText(const QString & text);
- void setIcon(QIcon icon);
- virtual QSize sizeHint() const;
+ QString text() const;
+ void setText(const QString & text);
+ void setIcon(QIcon icon);
+ virtual QSize sizeHint() const;
protected:
- void resizeEvent(QResizeEvent * event);
- void resetIcon();
+ void resizeEvent(QResizeEvent * event);
+ void resetIcon();
};
diff --git a/application/widgets/LanguageSelectionWidget.cpp b/application/widgets/LanguageSelectionWidget.cpp
new file mode 100644
index 00000000..80e26b39
--- /dev/null
+++ b/application/widgets/LanguageSelectionWidget.cpp
@@ -0,0 +1,68 @@
+#include "LanguageSelectionWidget.h"
+
+#include <QVBoxLayout>
+#include <QTreeView>
+#include <QHeaderView>
+#include <QLabel>
+#include "MultiMC.h"
+#include "translations/TranslationsModel.h"
+
+LanguageSelectionWidget::LanguageSelectionWidget(QWidget *parent) :
+ QWidget(parent)
+{
+ verticalLayout = new QVBoxLayout(this);
+ verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
+ languageView = new QTreeView(this);
+ languageView->setObjectName(QStringLiteral("languageView"));
+ languageView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ languageView->setAlternatingRowColors(true);
+ languageView->setRootIsDecorated(false);
+ languageView->setItemsExpandable(false);
+ languageView->setWordWrap(true);
+ languageView->header()->setCascadingSectionResizes(true);
+ languageView->header()->setStretchLastSection(false);
+ verticalLayout->addWidget(languageView);
+ helpUsLabel = new QLabel(this);
+ helpUsLabel->setObjectName(QStringLiteral("helpUsLabel"));
+ helpUsLabel->setTextInteractionFlags(Qt::LinksAccessibleByMouse);
+ helpUsLabel->setOpenExternalLinks(true);
+ helpUsLabel->setWordWrap(true);
+ verticalLayout->addWidget(helpUsLabel);
+
+ auto translations = MMC->translations();
+ auto index = translations->selectedIndex();
+ languageView->setModel(translations.get());
+ languageView->setCurrentIndex(index);
+ languageView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
+ languageView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
+ connect(languageView->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &LanguageSelectionWidget::languageRowChanged);
+ verticalLayout->setContentsMargins(0,0,0,0);
+}
+
+QString LanguageSelectionWidget::getSelectedLanguageKey() const
+{
+ auto translations = MMC->translations();
+ return translations->data(languageView->currentIndex(), Qt::UserRole).toString();
+}
+
+void LanguageSelectionWidget::retranslate()
+{
+ QString text =
+ tr("Don't see your language or the quality is poor?") +
+ "<br/>" +
+ QString("<a href=\"https://github.com/MultiMC/MultiMC5/wiki/Translating-MultiMC\">%1</a>").arg(tr("Help us with translations!"));
+ helpUsLabel->setText(text);
+
+}
+
+void LanguageSelectionWidget::languageRowChanged(const QModelIndex& current, const QModelIndex& previous)
+{
+ if (current == previous)
+ {
+ return;
+ }
+ auto translations = MMC->translations();
+ QString key = translations->data(current, Qt::UserRole).toString();
+ translations->selectLanguage(key);
+ translations->updateLanguage(key);
+}
diff --git a/application/widgets/LanguageSelectionWidget.h b/application/widgets/LanguageSelectionWidget.h
new file mode 100644
index 00000000..03e29bd8
--- /dev/null
+++ b/application/widgets/LanguageSelectionWidget.h
@@ -0,0 +1,41 @@
+/* Copyright 2013-2019 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>
+
+class QVBoxLayout;
+class QTreeView;
+class QLabel;
+
+class LanguageSelectionWidget: public QWidget
+{
+ Q_OBJECT
+public:
+ explicit LanguageSelectionWidget(QWidget *parent = 0);
+ virtual ~LanguageSelectionWidget() { };
+
+ QString getSelectedLanguageKey() const;
+ void retranslate();
+
+protected slots:
+ void languageRowChanged(const QModelIndex &current, const QModelIndex &previous);
+
+private:
+ QVBoxLayout *verticalLayout = nullptr;
+ QTreeView *languageView = nullptr;
+ QLabel *helpUsLabel = nullptr;
+};
diff --git a/application/widgets/LineSeparator.cpp b/application/widgets/LineSeparator.cpp
index f4ee173d..d03e6762 100644
--- a/application/widgets/LineSeparator.cpp
+++ b/application/widgets/LineSeparator.cpp
@@ -7,31 +7,31 @@
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;
+ 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)
+ : QWidget(parent), m_orientation(orientation)
{
- setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ 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);
+ 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());
+ QPainter p(this);
+ QStyleOption opt;
+ initStyleOption(&opt);
+ style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, &opt, &p, parentWidget());
}
diff --git a/application/widgets/LineSeparator.h b/application/widgets/LineSeparator.h
index 9546e747..22927b68 100644
--- a/application/widgets/LineSeparator.h
+++ b/application/widgets/LineSeparator.h
@@ -5,14 +5,14 @@ class QStyleOption;
class LineSeparator : public QWidget
{
- Q_OBJECT
+ 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;
+ /// 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;
+ Qt::Orientation m_orientation = Qt::Horizontal;
};
diff --git a/application/widgets/LogView.cpp b/application/widgets/LogView.cpp
index 8e0346fa..26a2a527 100644
--- a/application/widgets/LogView.cpp
+++ b/application/widgets/LogView.cpp
@@ -4,141 +4,141 @@
LogView::LogView(QWidget* parent) : QPlainTextEdit(parent)
{
- setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
- m_defaultFormat = new QTextCharFormat(currentCharFormat());
+ setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
+ m_defaultFormat = new QTextCharFormat(currentCharFormat());
}
LogView::~LogView()
{
- delete m_defaultFormat;
+ delete m_defaultFormat;
}
void LogView::setWordWrap(bool wrapping)
{
- if(wrapping)
- {
- setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- setLineWrapMode(QPlainTextEdit::WidgetWidth);
- }
- else
- {
- setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
- setLineWrapMode(QPlainTextEdit::NoWrap);
- }
+ if(wrapping)
+ {
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setLineWrapMode(QPlainTextEdit::WidgetWidth);
+ }
+ else
+ {
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ setLineWrapMode(QPlainTextEdit::NoWrap);
+ }
}
void LogView::setModel(QAbstractItemModel* model)
{
- if(m_model)
- {
- disconnect(m_model, &QAbstractItemModel::modelReset, this, &LogView::repopulate);
- disconnect(m_model, &QAbstractItemModel::rowsInserted, this, &LogView::rowsInserted);
- disconnect(m_model, &QAbstractItemModel::rowsAboutToBeInserted, this, &LogView::rowsAboutToBeInserted);
- disconnect(m_model, &QAbstractItemModel::rowsRemoved, this, &LogView::rowsRemoved);
- }
- m_model = model;
- if(m_model)
- {
- connect(m_model, &QAbstractItemModel::modelReset, this, &LogView::repopulate);
- connect(m_model, &QAbstractItemModel::rowsInserted, this, &LogView::rowsInserted);
- connect(m_model, &QAbstractItemModel::rowsAboutToBeInserted, this, &LogView::rowsAboutToBeInserted);
- connect(m_model, &QAbstractItemModel::rowsRemoved, this, &LogView::rowsRemoved);
- connect(m_model, &QAbstractItemModel::destroyed, this, &LogView::modelDestroyed);
- }
- repopulate();
+ if(m_model)
+ {
+ disconnect(m_model, &QAbstractItemModel::modelReset, this, &LogView::repopulate);
+ disconnect(m_model, &QAbstractItemModel::rowsInserted, this, &LogView::rowsInserted);
+ disconnect(m_model, &QAbstractItemModel::rowsAboutToBeInserted, this, &LogView::rowsAboutToBeInserted);
+ disconnect(m_model, &QAbstractItemModel::rowsRemoved, this, &LogView::rowsRemoved);
+ }
+ m_model = model;
+ if(m_model)
+ {
+ connect(m_model, &QAbstractItemModel::modelReset, this, &LogView::repopulate);
+ connect(m_model, &QAbstractItemModel::rowsInserted, this, &LogView::rowsInserted);
+ connect(m_model, &QAbstractItemModel::rowsAboutToBeInserted, this, &LogView::rowsAboutToBeInserted);
+ connect(m_model, &QAbstractItemModel::rowsRemoved, this, &LogView::rowsRemoved);
+ connect(m_model, &QAbstractItemModel::destroyed, this, &LogView::modelDestroyed);
+ }
+ repopulate();
}
QAbstractItemModel * LogView::model() const
{
- return m_model;
+ return m_model;
}
void LogView::modelDestroyed(QObject* model)
{
- if(m_model == model)
- {
- setModel(nullptr);
- }
+ if(m_model == model)
+ {
+ setModel(nullptr);
+ }
}
void LogView::repopulate()
{
- auto doc = document();
- doc->clear();
- if(!m_model)
- {
- return;
- }
- rowsInserted(QModelIndex(), 0, m_model->rowCount() - 1);
+ auto doc = document();
+ doc->clear();
+ if(!m_model)
+ {
+ return;
+ }
+ rowsInserted(QModelIndex(), 0, m_model->rowCount() - 1);
}
void LogView::rowsAboutToBeInserted(const QModelIndex& parent, int first, int last)
{
- Q_UNUSED(parent)
- Q_UNUSED(first)
- Q_UNUSED(last)
- QScrollBar *bar = verticalScrollBar();
- int max_bar = bar->maximum();
- int val_bar = bar->value();
- if (m_scroll)
- {
- m_scroll = (max_bar - val_bar) <= 1;
- }
- else
- {
- m_scroll = val_bar == max_bar;
- }
+ Q_UNUSED(parent)
+ Q_UNUSED(first)
+ Q_UNUSED(last)
+ QScrollBar *bar = verticalScrollBar();
+ int max_bar = bar->maximum();
+ int val_bar = bar->value();
+ if (m_scroll)
+ {
+ m_scroll = (max_bar - val_bar) <= 1;
+ }
+ else
+ {
+ m_scroll = val_bar == max_bar;
+ }
}
void LogView::rowsInserted(const QModelIndex& parent, int first, int last)
{
- for(int i = first; i <= last; i++)
- {
- auto idx = m_model->index(i, 0, parent);
- auto text = m_model->data(idx, Qt::DisplayRole).toString();
- QTextCharFormat format(*m_defaultFormat);
- auto font = m_model->data(idx, Qt::FontRole);
- if(font.isValid())
- {
- format.setFont(font.value<QFont>());
- }
- auto fg = m_model->data(idx, Qt::TextColorRole);
- if(fg.isValid())
- {
- format.setForeground(fg.value<QColor>());
- }
- auto bg = m_model->data(idx, Qt::BackgroundRole);
- if(bg.isValid())
- {
- format.setBackground(bg.value<QColor>());
- }
- auto workCursor = textCursor();
- workCursor.movePosition(QTextCursor::End);
- workCursor.insertText(text, format);
- workCursor.insertBlock();
- }
- if(m_scroll && !m_scrolling)
- {
- m_scrolling = true;
- QMetaObject::invokeMethod( this, "scrollToBottom", Qt::QueuedConnection);
- }
+ for(int i = first; i <= last; i++)
+ {
+ auto idx = m_model->index(i, 0, parent);
+ auto text = m_model->data(idx, Qt::DisplayRole).toString();
+ QTextCharFormat format(*m_defaultFormat);
+ auto font = m_model->data(idx, Qt::FontRole);
+ if(font.isValid())
+ {
+ format.setFont(font.value<QFont>());
+ }
+ auto fg = m_model->data(idx, Qt::TextColorRole);
+ if(fg.isValid())
+ {
+ format.setForeground(fg.value<QColor>());
+ }
+ auto bg = m_model->data(idx, Qt::BackgroundRole);
+ if(bg.isValid())
+ {
+ format.setBackground(bg.value<QColor>());
+ }
+ auto workCursor = textCursor();
+ workCursor.movePosition(QTextCursor::End);
+ workCursor.insertText(text, format);
+ workCursor.insertBlock();
+ }
+ if(m_scroll && !m_scrolling)
+ {
+ m_scrolling = true;
+ QMetaObject::invokeMethod( this, "scrollToBottom", Qt::QueuedConnection);
+ }
}
void LogView::rowsRemoved(const QModelIndex& parent, int first, int last)
{
- // TODO: some day... maybe
- Q_UNUSED(parent)
- Q_UNUSED(first)
- Q_UNUSED(last)
+ // TODO: some day... maybe
+ Q_UNUSED(parent)
+ Q_UNUSED(first)
+ Q_UNUSED(last)
}
void LogView::scrollToBottom()
{
- m_scrolling = false;
- verticalScrollBar()->setSliderPosition(verticalScrollBar()->maximum());
+ m_scrolling = false;
+ verticalScrollBar()->setSliderPosition(verticalScrollBar()->maximum());
}
void LogView::findNext(const QString& what, bool reverse)
{
- find(what, reverse ? QTextDocument::FindFlag::FindBackward : QTextDocument::FindFlag(0));
+ find(what, reverse ? QTextDocument::FindFlag::FindBackward : QTextDocument::FindFlag(0));
}
diff --git a/application/widgets/LogView.h b/application/widgets/LogView.h
index bb6747cd..3143360a 100644
--- a/application/widgets/LogView.h
+++ b/application/widgets/LogView.h
@@ -6,31 +6,31 @@ class QAbstractItemModel;
class LogView: public QPlainTextEdit
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit LogView(QWidget *parent = nullptr);
- virtual ~LogView();
+ explicit LogView(QWidget *parent = nullptr);
+ virtual ~LogView();
- virtual void setModel(QAbstractItemModel *model);
- QAbstractItemModel *model() const;
+ virtual void setModel(QAbstractItemModel *model);
+ QAbstractItemModel *model() const;
public slots:
- void setWordWrap(bool wrapping);
- void findNext(const QString & what, bool reverse);
- void scrollToBottom();
+ void setWordWrap(bool wrapping);
+ void findNext(const QString & what, bool reverse);
+ void scrollToBottom();
protected slots:
- void repopulate();
- // note: this supports only appending
- void rowsInserted(const QModelIndex &parent, int first, int last);
- void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last);
- // note: this supports only removing from front
- void rowsRemoved(const QModelIndex &parent, int first, int last);
- void modelDestroyed(QObject * model);
+ void repopulate();
+ // note: this supports only appending
+ void rowsInserted(const QModelIndex &parent, int first, int last);
+ void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last);
+ // note: this supports only removing from front
+ void rowsRemoved(const QModelIndex &parent, int first, int last);
+ void modelDestroyed(QObject * model);
protected:
- QAbstractItemModel *m_model = nullptr;
- QTextCharFormat *m_defaultFormat = nullptr;
- bool m_scroll = false;
- bool m_scrolling = false;
+ QAbstractItemModel *m_model = nullptr;
+ QTextCharFormat *m_defaultFormat = nullptr;
+ bool m_scroll = false;
+ bool m_scrolling = false;
};
diff --git a/application/widgets/MCModInfoFrame.cpp b/application/widgets/MCModInfoFrame.cpp
index 629c17e7..577b32a7 100644
--- a/application/widgets/MCModInfoFrame.cpp
+++ b/application/widgets/MCModInfoFrame.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,145 +22,145 @@
void MCModInfoFrame::updateWithMod(Mod &m)
{
- if (m.type() == m.MOD_FOLDER)
- {
- clear();
- return;
- }
+ if (m.type() == m.MOD_FOLDER)
+ {
+ clear();
+ return;
+ }
- QString text = "";
- QString name = "";
- if (m.name().isEmpty())
- name = m.mmc_id();
- else
- name = m.name();
+ QString text = "";
+ QString name = "";
+ if (m.name().isEmpty())
+ name = m.mmc_id();
+ else
+ name = m.name();
- if (m.homeurl().isEmpty())
- text = name;
- else
- text = "<a href=\"" + m.homeurl() + "\">" + name + "</a>";
- if (!m.authors().isEmpty())
- text += " by " + m.authors();
+ if (m.homeurl().isEmpty())
+ text = name;
+ else
+ text = "<a href=\"" + m.homeurl() + "\">" + name + "</a>";
+ if (!m.authors().isEmpty())
+ text += " by " + m.authors().join(", ");
- setModText(text);
+ setModText(text);
- if (m.description().isEmpty())
- {
- setModDescription(QString());
- }
- else
- {
- setModDescription(m.description());
- }
+ if (m.description().isEmpty())
+ {
+ setModDescription(QString());
+ }
+ else
+ {
+ setModDescription(m.description());
+ }
}
void MCModInfoFrame::clear()
{
- setModText(QString());
- setModDescription(QString());
+ setModText(QString());
+ setModDescription(QString());
}
MCModInfoFrame::MCModInfoFrame(QWidget *parent) :
- QFrame(parent),
- ui(new Ui::MCModInfoFrame)
+ QFrame(parent),
+ ui(new Ui::MCModInfoFrame)
{
- ui->setupUi(this);
- ui->label_ModDescription->setHidden(true);
- ui->label_ModText->setHidden(true);
- updateHiddenState();
+ ui->setupUi(this);
+ ui->label_ModDescription->setHidden(true);
+ ui->label_ModText->setHidden(true);
+ updateHiddenState();
}
MCModInfoFrame::~MCModInfoFrame()
{
- delete ui;
+ delete ui;
}
void MCModInfoFrame::updateHiddenState()
{
- if(ui->label_ModDescription->isHidden() && ui->label_ModText->isHidden())
- {
- setHidden(true);
- }
- else
- {
- setHidden(false);
- }
+ if(ui->label_ModDescription->isHidden() && ui->label_ModText->isHidden())
+ {
+ setHidden(true);
+ }
+ else
+ {
+ setHidden(false);
+ }
}
void MCModInfoFrame::setModText(QString text)
{
- if(text.isEmpty())
- {
- ui->label_ModText->setHidden(true);
- }
- else
- {
- ui->label_ModText->setText(text);
- ui->label_ModText->setHidden(false);
- }
- updateHiddenState();
+ if(text.isEmpty())
+ {
+ ui->label_ModText->setHidden(true);
+ }
+ else
+ {
+ ui->label_ModText->setText(text);
+ ui->label_ModText->setHidden(false);
+ }
+ updateHiddenState();
}
void MCModInfoFrame::setModDescription(QString text)
{
- if(text.isEmpty())
- {
- ui->label_ModDescription->setHidden(true);
- updateHiddenState();
- return;
- }
- else
- {
- ui->label_ModDescription->setHidden(false);
- updateHiddenState();
- }
- ui->label_ModDescription->setToolTip("");
- QString intermediatetext = text.trimmed();
- bool prev(false);
- QChar rem('\n');
- QString finaltext;
- finaltext.reserve(intermediatetext.size());
- foreach(const QChar& c, intermediatetext)
- {
- if(c == rem && prev){
- continue;
- }
- prev = c == rem;
- finaltext += c;
- }
- QString labeltext;
- labeltext.reserve(300);
- if(finaltext.length() > 290)
- {
- ui->label_ModDescription->setOpenExternalLinks(false);
- ui->label_ModDescription->setTextFormat(Qt::TextFormat::RichText);
- desc = text;
- labeltext.append("<html><body>" + finaltext.left(287) + "<a href=\"#mod_desc\">...</a></body></html>");
- QObject::connect(ui->label_ModDescription, &QLabel::linkActivated, this, &MCModInfoFrame::modDescEllipsisHandler);
- }
- else
- {
- ui->label_ModDescription->setTextFormat(Qt::TextFormat::PlainText);
- labeltext.append(finaltext);
- }
- ui->label_ModDescription->setText(labeltext);
+ if(text.isEmpty())
+ {
+ ui->label_ModDescription->setHidden(true);
+ updateHiddenState();
+ return;
+ }
+ else
+ {
+ ui->label_ModDescription->setHidden(false);
+ updateHiddenState();
+ }
+ ui->label_ModDescription->setToolTip("");
+ QString intermediatetext = text.trimmed();
+ bool prev(false);
+ QChar rem('\n');
+ QString finaltext;
+ finaltext.reserve(intermediatetext.size());
+ foreach(const QChar& c, intermediatetext)
+ {
+ if(c == rem && prev){
+ continue;
+ }
+ prev = c == rem;
+ finaltext += c;
+ }
+ QString labeltext;
+ labeltext.reserve(300);
+ if(finaltext.length() > 290)
+ {
+ ui->label_ModDescription->setOpenExternalLinks(false);
+ ui->label_ModDescription->setTextFormat(Qt::TextFormat::RichText);
+ desc = text;
+ labeltext.append("<html><body>" + finaltext.left(287) + "<a href=\"#mod_desc\">...</a></body></html>");
+ QObject::connect(ui->label_ModDescription, &QLabel::linkActivated, this, &MCModInfoFrame::modDescEllipsisHandler);
+ }
+ else
+ {
+ ui->label_ModDescription->setTextFormat(Qt::TextFormat::PlainText);
+ labeltext.append(finaltext);
+ }
+ ui->label_ModDescription->setText(labeltext);
}
void MCModInfoFrame::modDescEllipsisHandler(const QString &link)
{
- if(!currentBox)
- {
- currentBox = CustomMessageBox::selectable(this, QString(), desc);
- connect(currentBox, &QMessageBox::finished, this, &MCModInfoFrame::boxClosed);
- currentBox->show();
- }
- else
- {
- currentBox->setText(desc);
- }
+ if(!currentBox)
+ {
+ currentBox = CustomMessageBox::selectable(this, QString(), desc);
+ connect(currentBox, &QMessageBox::finished, this, &MCModInfoFrame::boxClosed);
+ currentBox->show();
+ }
+ else
+ {
+ currentBox->setText(desc);
+ }
}
void MCModInfoFrame::boxClosed(int result)
{
- currentBox = nullptr;
+ currentBox = nullptr;
}
diff --git a/application/widgets/MCModInfoFrame.h b/application/widgets/MCModInfoFrame.h
index 6bcd345c..51aa4489 100644
--- a/application/widgets/MCModInfoFrame.h
+++ b/application/widgets/MCModInfoFrame.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 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,7 +16,7 @@
#pragma once
#include <QFrame>
-#include "minecraft/Mod.h"
+#include "minecraft/mod/Mod.h"
namespace Ui
{
@@ -25,28 +25,28 @@ class MCModInfoFrame;
class MCModInfoFrame : public QFrame
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit MCModInfoFrame(QWidget *parent = 0);
- ~MCModInfoFrame();
+ explicit MCModInfoFrame(QWidget *parent = 0);
+ ~MCModInfoFrame();
- void setModText(QString text);
- void setModDescription(QString text);
+ void setModText(QString text);
+ void setModDescription(QString text);
- void updateWithMod(Mod &m);
- void clear();
+ void updateWithMod(Mod &m);
+ void clear();
public slots:
- void modDescEllipsisHandler(const QString& link );
- void boxClosed(int result);
+ void modDescEllipsisHandler(const QString& link );
+ void boxClosed(int result);
private:
- void updateHiddenState();
+ void updateHiddenState();
private:
- Ui::MCModInfoFrame *ui;
- QString desc;
- class QMessageBox * currentBox = nullptr;
+ Ui::MCModInfoFrame *ui;
+ QString desc;
+ class QMessageBox * currentBox = nullptr;
};
diff --git a/application/widgets/ModListView.cpp b/application/widgets/ModListView.cpp
index 96e8d91b..99972a40 100644
--- a/application/widgets/ModListView.cpp
+++ b/application/widgets/ModListView.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,46 +21,46 @@
#include <QRect>
ModListView::ModListView ( QWidget* parent )
- :QTreeView ( parent )
+ :QTreeView ( parent )
{
- setAllColumnsShowFocus ( true );
- setExpandsOnDoubleClick ( false );
- setRootIsDecorated ( false );
- setSortingEnabled ( true );
- setAlternatingRowColors ( true );
- setSelectionMode ( QAbstractItemView::ExtendedSelection );
- setHeaderHidden ( false );
- setSelectionBehavior(QAbstractItemView::SelectRows);
- setVerticalScrollBarPolicy ( Qt::ScrollBarAlwaysOn );
- setHorizontalScrollBarPolicy ( Qt::ScrollBarAsNeeded );
- setDropIndicatorShown(true);
- setDragEnabled(true);
- setDragDropMode(QAbstractItemView::DropOnly);
- viewport()->setAcceptDrops(true);
+ setAllColumnsShowFocus ( true );
+ setExpandsOnDoubleClick ( false );
+ setRootIsDecorated ( false );
+ setSortingEnabled ( true );
+ setAlternatingRowColors ( true );
+ setSelectionMode ( QAbstractItemView::ExtendedSelection );
+ setHeaderHidden ( false );
+ setSelectionBehavior(QAbstractItemView::SelectRows);
+ setVerticalScrollBarPolicy ( Qt::ScrollBarAlwaysOn );
+ setHorizontalScrollBarPolicy ( Qt::ScrollBarAsNeeded );
+ setDropIndicatorShown(true);
+ setDragEnabled(true);
+ setDragDropMode(QAbstractItemView::DropOnly);
+ viewport()->setAcceptDrops(true);
}
void ModListView::setModel ( QAbstractItemModel* model )
{
- QTreeView::setModel ( model );
- auto head = header();
- head->setStretchLastSection(false);
- // HACK: this is true for the checkbox column of mod lists
- auto string = model->headerData(0,head->orientation()).toString();
- if(head->count() < 1)
- {
- return;
- }
- if(!string.size())
- {
- head->setSectionResizeMode(0, QHeaderView::ResizeToContents);
- head->setSectionResizeMode(1, QHeaderView::Stretch);
- for(int i = 2; i < head->count(); i++)
- head->setSectionResizeMode(i, QHeaderView::ResizeToContents);
- }
- else
- {
- head->setSectionResizeMode(0, QHeaderView::Stretch);
- for(int i = 1; i < head->count(); i++)
- head->setSectionResizeMode(i, QHeaderView::ResizeToContents);
- }
+ QTreeView::setModel ( model );
+ auto head = header();
+ head->setStretchLastSection(false);
+ // HACK: this is true for the checkbox column of mod lists
+ auto string = model->headerData(0,head->orientation()).toString();
+ if(head->count() < 1)
+ {
+ return;
+ }
+ if(!string.size())
+ {
+ head->setSectionResizeMode(0, QHeaderView::ResizeToContents);
+ head->setSectionResizeMode(1, QHeaderView::Stretch);
+ for(int i = 2; i < head->count(); i++)
+ head->setSectionResizeMode(i, QHeaderView::ResizeToContents);
+ }
+ else
+ {
+ head->setSectionResizeMode(0, QHeaderView::Stretch);
+ for(int i = 1; i < head->count(); i++)
+ head->setSectionResizeMode(i, QHeaderView::ResizeToContents);
+ }
}
diff --git a/application/widgets/ModListView.h b/application/widgets/ModListView.h
index baca23f4..5a07e868 100644
--- a/application/widgets/ModListView.h
+++ b/application/widgets/ModListView.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 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,12 +16,10 @@
#pragma once
#include <QTreeView>
-class Mod;
-
class ModListView: public QTreeView
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit ModListView ( QWidget* parent = 0 );
- virtual void setModel ( QAbstractItemModel* model );
+ explicit ModListView ( QWidget* parent = 0 );
+ virtual void setModel ( QAbstractItemModel* model );
};
diff --git a/application/widgets/PageContainer.cpp b/application/widgets/PageContainer.cpp
index 98de57e8..376e119b 100644
--- a/application/widgets/PageContainer.cpp
+++ b/application/widgets/PageContainer.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,196 +36,204 @@
class PageEntryFilterModel : public QSortFilterProxyModel
{
public:
- explicit PageEntryFilterModel(QObject *parent = 0) : QSortFilterProxyModel(parent)
- {
- }
+ explicit PageEntryFilterModel(QObject *parent = 0) : QSortFilterProxyModel(parent)
+ {
+ }
protected:
- bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
- {
- const QString pattern = filterRegExp().pattern();
- const auto model = static_cast<PageModel *>(sourceModel());
- const auto page = model->pages().at(sourceRow);
- if (!page->shouldDisplay())
- return false;
- // Regular contents check, then check page-filter.
- return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
- }
+ bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
+ {
+ const QString pattern = filterRegExp().pattern();
+ const auto model = static_cast<PageModel *>(sourceModel());
+ const auto page = model->pages().at(sourceRow);
+ if (!page->shouldDisplay())
+ return false;
+ // Regular contents check, then check page-filter.
+ return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
+ }
};
PageContainer::PageContainer(BasePageProvider *pageProvider, QString defaultId,
- QWidget *parent)
- : QWidget(parent)
+ QWidget *parent)
+ : QWidget(parent)
{
- createUI();
- m_model = new PageModel(this);
- m_proxyModel = new PageEntryFilterModel(this);
- int counter = 0;
- auto pages = pageProvider->getPages();
- for (auto page : pages)
- {
- page->stackIndex = m_pageStack->addWidget(dynamic_cast<QWidget *>(page));
- page->listIndex = counter;
- page->setParentContainer(this);
- counter++;
- }
- m_model->setPages(pages);
-
- m_proxyModel->setSourceModel(m_model);
- m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
-
- m_pageList->setIconSize(QSize(pageIconSize, pageIconSize));
- m_pageList->setSelectionMode(QAbstractItemView::SingleSelection);
- m_pageList->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
- m_pageList->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
- m_pageList->setModel(m_proxyModel);
- connect(m_pageList->selectionModel(), SIGNAL(currentRowChanged(QModelIndex, QModelIndex)),
- this, SLOT(currentChanged(QModelIndex)));
- m_pageStack->setStackingMode(QStackedLayout::StackOne);
- m_pageList->setFocus();
- selectPage(defaultId);
+ createUI();
+ m_model = new PageModel(this);
+ m_proxyModel = new PageEntryFilterModel(this);
+ int counter = 0;
+ auto pages = pageProvider->getPages();
+ for (auto page : pages)
+ {
+ page->stackIndex = m_pageStack->addWidget(dynamic_cast<QWidget *>(page));
+ page->listIndex = counter;
+ page->setParentContainer(this);
+ counter++;
+ }
+ m_model->setPages(pages);
+
+ m_proxyModel->setSourceModel(m_model);
+ m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
+
+ m_pageList->setIconSize(QSize(pageIconSize, pageIconSize));
+ m_pageList->setSelectionMode(QAbstractItemView::SingleSelection);
+ m_pageList->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
+ m_pageList->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
+ m_pageList->setModel(m_proxyModel);
+ connect(m_pageList->selectionModel(), SIGNAL(currentRowChanged(QModelIndex, QModelIndex)),
+ this, SLOT(currentChanged(QModelIndex)));
+ m_pageStack->setStackingMode(QStackedLayout::StackOne);
+ m_pageList->setFocus();
+ selectPage(defaultId);
}
bool PageContainer::selectPage(QString pageId)
{
- // now find what we want to have selected...
- auto page = m_model->findPageEntryById(pageId);
- QModelIndex index;
- if (page)
- {
- index = m_proxyModel->mapFromSource(m_model->index(page->listIndex));
- }
- if(!index.isValid())
- {
- index = m_proxyModel->index(0, 0);
- }
- if (index.isValid())
- {
- m_pageList->setCurrentIndex(index);
- return true;
- }
- return false;
+ // now find what we want to have selected...
+ auto page = m_model->findPageEntryById(pageId);
+ QModelIndex index;
+ if (page)
+ {
+ index = m_proxyModel->mapFromSource(m_model->index(page->listIndex));
+ }
+ if(!index.isValid())
+ {
+ index = m_proxyModel->index(0, 0);
+ }
+ if (index.isValid())
+ {
+ m_pageList->setCurrentIndex(index);
+ return true;
+ }
+ return false;
}
void PageContainer::refreshContainer()
{
- m_proxyModel->invalidate();
- if(!m_currentPage->shouldDisplay())
- {
- auto index = m_proxyModel->index(0, 0);
- if(index.isValid())
- {
- m_pageList->setCurrentIndex(index);
- }
- else
- {
- // FIXME: unhandled corner case: what to do when there's no page to select?
- }
- }
+ m_proxyModel->invalidate();
+ if(!m_currentPage->shouldDisplay())
+ {
+ auto index = m_proxyModel->index(0, 0);
+ if(index.isValid())
+ {
+ m_pageList->setCurrentIndex(index);
+ }
+ else
+ {
+ // FIXME: unhandled corner case: what to do when there's no page to select?
+ }
+ }
}
void PageContainer::createUI()
{
- m_pageStack = new QStackedLayout;
- m_pageList = new PageView;
- m_header = new QLabel();
- m_iconHeader = new IconLabel(this, QIcon(), QSize(24, 24));
-
- QFont headerLabelFont = m_header->font();
- headerLabelFont.setBold(true);
- const int pointSize = headerLabelFont.pointSize();
- if (pointSize > 0)
- headerLabelFont.setPointSize(pointSize + 2);
- m_header->setFont(headerLabelFont);
-
- QHBoxLayout *headerHLayout = new QHBoxLayout;
- const int leftMargin = MMC->style()->pixelMetric(QStyle::PM_LayoutLeftMargin);
- headerHLayout->addSpacerItem(
- new QSpacerItem(leftMargin, 0, QSizePolicy::Fixed, QSizePolicy::Ignored));
- headerHLayout->addWidget(m_header);
- headerHLayout->addSpacerItem(
- new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored));
- headerHLayout->addWidget(m_iconHeader);
- const int rightMargin = MMC->style()->pixelMetric(QStyle::PM_LayoutRightMargin);
- headerHLayout->addSpacerItem(
- new QSpacerItem(rightMargin, 0, QSizePolicy::Fixed, QSizePolicy::Ignored));
-
- m_pageStack->setMargin(0);
- m_pageStack->addWidget(new QWidget(this));
-
- m_layout = new QGridLayout;
- m_layout->addLayout(headerHLayout, 0, 1, 1, 1);
- m_layout->addWidget(m_pageList, 0, 0, 2, 1);
- m_layout->addLayout(m_pageStack, 1, 1, 1, 1);
- m_layout->setColumnStretch(1, 4);
- setLayout(m_layout);
+ m_pageStack = new QStackedLayout;
+ m_pageList = new PageView;
+ m_header = new QLabel();
+ m_iconHeader = new IconLabel(this, QIcon(), QSize(24, 24));
+
+ QFont headerLabelFont = m_header->font();
+ headerLabelFont.setBold(true);
+ const int pointSize = headerLabelFont.pointSize();
+ if (pointSize > 0)
+ headerLabelFont.setPointSize(pointSize + 2);
+ m_header->setFont(headerLabelFont);
+
+ QHBoxLayout *headerHLayout = new QHBoxLayout;
+ const int leftMargin = MMC->style()->pixelMetric(QStyle::PM_LayoutLeftMargin);
+ headerHLayout->addSpacerItem(new QSpacerItem(leftMargin, 0, QSizePolicy::Fixed, QSizePolicy::Ignored));
+ headerHLayout->addWidget(m_header);
+ headerHLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored));
+ headerHLayout->addWidget(m_iconHeader);
+ const int rightMargin = MMC->style()->pixelMetric(QStyle::PM_LayoutRightMargin);
+ headerHLayout->addSpacerItem(new QSpacerItem(rightMargin, 0, QSizePolicy::Fixed, QSizePolicy::Ignored));
+ headerHLayout->setContentsMargins(0, 6, 0, 0);
+
+ m_pageStack->setMargin(0);
+ m_pageStack->addWidget(new QWidget(this));
+
+ m_layout = new QGridLayout;
+ m_layout->addLayout(headerHLayout, 0, 1, 1, 1);
+ m_layout->addWidget(m_pageList, 0, 0, 2, 1);
+ m_layout->addLayout(m_pageStack, 1, 1, 1, 1);
+ m_layout->setColumnStretch(1, 4);
+ m_layout->setContentsMargins(0,0,0,6);
+ setLayout(m_layout);
}
void PageContainer::addButtons(QWidget *buttons)
{
- m_layout->addWidget(buttons, 2, 0, 1, 2);
+ m_layout->addWidget(buttons, 2, 0, 1, 2);
}
void PageContainer::addButtons(QLayout *buttons)
{
- m_layout->addLayout(buttons, 2, 0, 1, 2);
+ m_layout->addLayout(buttons, 2, 0, 1, 2);
}
void PageContainer::showPage(int row)
{
- if (m_currentPage)
- {
- m_currentPage->closed();
- }
- if (row != -1)
- {
- m_currentPage = m_model->pages().at(row);
- }
- else
- {
- m_currentPage = nullptr;
- }
- if (m_currentPage)
- {
- m_pageStack->setCurrentIndex(m_currentPage->stackIndex);
- m_header->setText(m_currentPage->displayName());
- m_iconHeader->setIcon(m_currentPage->icon());
- m_currentPage->opened();
- }
- else
- {
- m_pageStack->setCurrentIndex(0);
- m_header->setText(QString());
- m_iconHeader->setIcon(MMC->getThemedIcon("bug"));
- }
+ if (m_currentPage)
+ {
+ m_currentPage->closed();
+ }
+ if (row != -1)
+ {
+ m_currentPage = m_model->pages().at(row);
+ }
+ else
+ {
+ m_currentPage = nullptr;
+ }
+ if (m_currentPage)
+ {
+ m_pageStack->setCurrentIndex(m_currentPage->stackIndex);
+ m_header->setText(m_currentPage->displayName());
+ m_iconHeader->setIcon(m_currentPage->icon());
+ m_currentPage->opened();
+ }
+ else
+ {
+ m_pageStack->setCurrentIndex(0);
+ m_header->setText(QString());
+ m_iconHeader->setIcon(MMC->getThemedIcon("bug"));
+ }
}
void PageContainer::help()
{
- if (m_currentPage)
- {
- QString pageId = m_currentPage->helpPage();
- if (pageId.isEmpty())
- return;
- DesktopServices::openUrl(QUrl("https://github.com/MultiMC/MultiMC5/wiki/" + pageId));
- }
+ if (m_currentPage)
+ {
+ QString pageId = m_currentPage->helpPage();
+ if (pageId.isEmpty())
+ return;
+ DesktopServices::openUrl(QUrl("https://github.com/MultiMC/MultiMC5/wiki/" + pageId));
+ }
}
void PageContainer::currentChanged(const QModelIndex &current)
{
- showPage(current.isValid() ? m_proxyModel->mapToSource(current).row() : -1);
+ showPage(current.isValid() ? m_proxyModel->mapToSource(current).row() : -1);
}
bool PageContainer::prepareToClose()
{
- for (auto page : m_model->pages())
- {
- if (!page->apply())
- return false;
- }
- if (m_currentPage)
- {
- m_currentPage->closed();
- }
- return true;
+ if(!saveAll())
+ {
+ return false;
+ }
+ if (m_currentPage)
+ {
+ m_currentPage->closed();
+ }
+ return true;
+}
+
+bool PageContainer::saveAll()
+{
+ for (auto page : m_model->pages())
+ {
+ if (!page->apply())
+ return false;
+ }
+ return true;
}
diff --git a/application/widgets/PageContainer.h b/application/widgets/PageContainer.h
index ea9f8ce1..925f4ba3 100644
--- a/application/widgets/PageContainer.h
+++ b/application/widgets/PageContainer.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,56 +33,57 @@ class QGridLayout;
class PageContainer : public QWidget, public BasePageContainer
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit PageContainer(BasePageProvider *pageProvider, QString defaultId = QString(),
- QWidget *parent = 0);
- virtual ~PageContainer() {}
+ explicit PageContainer(BasePageProvider *pageProvider, QString defaultId = QString(),
+ QWidget *parent = 0);
+ virtual ~PageContainer() {}
- void addButtons(QWidget * buttons);
- void addButtons(QLayout * buttons);
- /*
- * Save any unsaved state and prepare to be closed.
- * @return true if everything can be saved, false if there is something that requires attention
- */
- bool prepareToClose();
+ void addButtons(QWidget * buttons);
+ void addButtons(QLayout * buttons);
+ /*
+ * Save any unsaved state and prepare to be closed.
+ * @return true if everything can be saved, false if there is something that requires attention
+ */
+ bool prepareToClose();
+ bool saveAll();
- /* request close - used by individual pages */
- bool requestClose() override
- {
- if(m_container)
- {
- return m_container->requestClose();
- }
- return false;
- }
+ /* request close - used by individual pages */
+ bool requestClose() override
+ {
+ if(m_container)
+ {
+ return m_container->requestClose();
+ }
+ return false;
+ }
- virtual bool selectPage(QString pageId) override;
+ virtual bool selectPage(QString pageId) override;
- void refreshContainer() override;
- virtual void setParentContainer(BasePageContainer * container)
- {
- m_container = container;
- };
+ void refreshContainer() override;
+ virtual void setParentContainer(BasePageContainer * container)
+ {
+ m_container = container;
+ };
private:
- void createUI();
+ void createUI();
public slots:
- void help();
+ void help();
private slots:
- void currentChanged(const QModelIndex &current);
- void showPage(int row);
+ void currentChanged(const QModelIndex &current);
+ void showPage(int row);
private:
- BasePageContainer * m_container = nullptr;
- BasePage * m_currentPage = 0;
- QSortFilterProxyModel *m_proxyModel;
- PageModel *m_model;
- QStackedLayout *m_pageStack;
- QListView *m_pageList;
- QLabel *m_header;
- IconLabel *m_iconHeader;
- QGridLayout *m_layout;
+ BasePageContainer * m_container = nullptr;
+ BasePage * m_currentPage = 0;
+ QSortFilterProxyModel *m_proxyModel;
+ PageModel *m_model;
+ QStackedLayout *m_pageStack;
+ QListView *m_pageList;
+ QLabel *m_header;
+ IconLabel *m_iconHeader;
+ QGridLayout *m_layout;
};
diff --git a/application/widgets/PageContainer_p.h b/application/widgets/PageContainer_p.h
index ed8171f1..4a5a9239 100644
--- a/application/widgets/PageContainer_p.h
+++ b/application/widgets/PageContainer_p.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,98 +26,98 @@ const int pageIconSize = 24;
class PageViewDelegate : public QStyledItemDelegate
{
public:
- PageViewDelegate(QObject *parent) : QStyledItemDelegate(parent)
- {
- }
- QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
- {
- QSize size = QStyledItemDelegate::sizeHint(option, index);
- size.setHeight(qMax(size.height(), 32));
- return size;
- }
+ PageViewDelegate(QObject *parent) : QStyledItemDelegate(parent)
+ {
+ }
+ QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
+ {
+ QSize size = QStyledItemDelegate::sizeHint(option, index);
+ size.setHeight(qMax(size.height(), 32));
+ return size;
+ }
};
class PageModel : public QAbstractListModel
{
public:
- PageModel(QObject *parent = 0) : QAbstractListModel(parent)
- {
- QPixmap empty(pageIconSize, pageIconSize);
- empty.fill(Qt::transparent);
- m_emptyIcon = QIcon(empty);
- }
- virtual ~PageModel() {}
+ PageModel(QObject *parent = 0) : QAbstractListModel(parent)
+ {
+ QPixmap empty(pageIconSize, pageIconSize);
+ empty.fill(Qt::transparent);
+ m_emptyIcon = QIcon(empty);
+ }
+ virtual ~PageModel() {}
- int rowCount(const QModelIndex &parent = QModelIndex()) const
- {
- return parent.isValid() ? 0 : m_pages.size();
- }
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
- {
- switch (role)
- {
- case Qt::DisplayRole:
- return m_pages.at(index.row())->displayName();
- case Qt::DecorationRole:
- {
- QIcon icon = m_pages.at(index.row())->icon();
- if (icon.isNull())
- icon = m_emptyIcon;
- // HACK: fixes icon stretching on windows. TODO: report Qt bug for this
- return QIcon(icon.pixmap(QSize(48,48)));
- }
- }
- return QVariant();
- }
+ int rowCount(const QModelIndex &parent = QModelIndex()) const
+ {
+ return parent.isValid() ? 0 : m_pages.size();
+ }
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
+ {
+ switch (role)
+ {
+ case Qt::DisplayRole:
+ return m_pages.at(index.row())->displayName();
+ case Qt::DecorationRole:
+ {
+ QIcon icon = m_pages.at(index.row())->icon();
+ if (icon.isNull())
+ icon = m_emptyIcon;
+ // HACK: fixes icon stretching on windows. TODO: report Qt bug for this
+ return QIcon(icon.pixmap(QSize(48,48)));
+ }
+ }
+ return QVariant();
+ }
- void setPages(const QList<BasePage *> &pages)
- {
- beginResetModel();
- m_pages = pages;
- endResetModel();
- }
- const QList<BasePage *> &pages() const
- {
- return m_pages;
- }
+ void setPages(const QList<BasePage *> &pages)
+ {
+ beginResetModel();
+ m_pages = pages;
+ endResetModel();
+ }
+ const QList<BasePage *> &pages() const
+ {
+ return m_pages;
+ }
- BasePage * findPageEntryById(QString id)
- {
- for(auto page: m_pages)
- {
- if (page->id() == id)
- return page;
- }
- return nullptr;
- }
+ BasePage * findPageEntryById(QString id)
+ {
+ for(auto page: m_pages)
+ {
+ if (page->id() == id)
+ return page;
+ }
+ return nullptr;
+ }
- QList<BasePage *> m_pages;
- QIcon m_emptyIcon;
+ QList<BasePage *> m_pages;
+ QIcon m_emptyIcon;
};
class PageView : public QListView
{
public:
- PageView(QWidget *parent = 0) : QListView(parent)
- {
- setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding);
- setItemDelegate(new PageViewDelegate(this));
- setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- }
+ PageView(QWidget *parent = 0) : QListView(parent)
+ {
+ setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding);
+ setItemDelegate(new PageViewDelegate(this));
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ }
- virtual QSize sizeHint() const
- {
- int width = sizeHintForColumn(0) + frameWidth() * 2 + 5;
- if (verticalScrollBar()->isVisible())
- width += verticalScrollBar()->width();
- return QSize(width, 100);
- }
+ virtual QSize sizeHint() const
+ {
+ int width = sizeHintForColumn(0) + frameWidth() * 2 + 5;
+ if (verticalScrollBar()->isVisible())
+ width += verticalScrollBar()->width();
+ return QSize(width, 100);
+ }
- virtual bool eventFilter(QObject *obj, QEvent *event)
- {
- if (obj == verticalScrollBar() &&
- (event->type() == QEvent::Show || event->type() == QEvent::Hide))
- updateGeometry();
- return QListView::eventFilter(obj, event);
- }
+ virtual bool eventFilter(QObject *obj, QEvent *event)
+ {
+ if (obj == verticalScrollBar() &&
+ (event->type() == QEvent::Show || event->type() == QEvent::Hide))
+ updateGeometry();
+ return QListView::eventFilter(obj, event);
+ }
};
diff --git a/application/widgets/ProgressWidget.cpp b/application/widgets/ProgressWidget.cpp
index fab099a9..911e555d 100644
--- a/application/widgets/ProgressWidget.cpp
+++ b/application/widgets/ProgressWidget.cpp
@@ -9,65 +9,65 @@
#include "tasks/Task.h"
ProgressWidget::ProgressWidget(QWidget *parent)
- : QWidget(parent)
+ : QWidget(parent)
{
- m_label = new QLabel(this);
- m_label->setWordWrap(true);
- m_bar = new QProgressBar(this);
- m_bar->setMinimum(0);
- m_bar->setMaximum(100);
- QVBoxLayout *layout = new QVBoxLayout(this);
- layout->addWidget(m_label);
- layout->addWidget(m_bar);
- layout->addStretch();
- setLayout(layout);
+ m_label = new QLabel(this);
+ m_label->setWordWrap(true);
+ m_bar = new QProgressBar(this);
+ m_bar->setMinimum(0);
+ m_bar->setMaximum(100);
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->addWidget(m_label);
+ layout->addWidget(m_bar);
+ layout->addStretch();
+ setLayout(layout);
}
void ProgressWidget::start(std::shared_ptr<Task> task)
{
- if (m_task)
- {
- disconnect(m_task.get(), 0, this, 0);
- }
- m_task = task;
- connect(m_task.get(), &Task::finished, this, &ProgressWidget::handleTaskFinish);
- connect(m_task.get(), &Task::status, this, &ProgressWidget::handleTaskStatus);
- connect(m_task.get(), &Task::progress, this, &ProgressWidget::handleTaskProgress);
- connect(m_task.get(), &Task::destroyed, this, &ProgressWidget::taskDestroyed);
- if (!m_task->isRunning())
- {
- QMetaObject::invokeMethod(m_task.get(), "start", Qt::QueuedConnection);
- }
+ if (m_task)
+ {
+ disconnect(m_task.get(), 0, this, 0);
+ }
+ m_task = task;
+ connect(m_task.get(), &Task::finished, this, &ProgressWidget::handleTaskFinish);
+ connect(m_task.get(), &Task::status, this, &ProgressWidget::handleTaskStatus);
+ connect(m_task.get(), &Task::progress, this, &ProgressWidget::handleTaskProgress);
+ connect(m_task.get(), &Task::destroyed, this, &ProgressWidget::taskDestroyed);
+ if (!m_task->isRunning())
+ {
+ QMetaObject::invokeMethod(m_task.get(), "start", Qt::QueuedConnection);
+ }
}
bool ProgressWidget::exec(std::shared_ptr<Task> task)
{
- QEventLoop loop;
- connect(task.get(), &Task::finished, &loop, &QEventLoop::quit);
- start(task);
- if (task->isRunning())
- {
- loop.exec();
- }
- return task->wasSuccessful();
+ QEventLoop loop;
+ connect(task.get(), &Task::finished, &loop, &QEventLoop::quit);
+ start(task);
+ if (task->isRunning())
+ {
+ loop.exec();
+ }
+ return task->wasSuccessful();
}
void ProgressWidget::handleTaskFinish()
{
- if (!m_task->wasSuccessful())
- {
- m_label->setText(m_task->failReason());
- }
+ if (!m_task->wasSuccessful())
+ {
+ m_label->setText(m_task->failReason());
+ }
}
void ProgressWidget::handleTaskStatus(const QString &status)
{
- m_label->setText(status);
+ m_label->setText(status);
}
void ProgressWidget::handleTaskProgress(qint64 current, qint64 total)
{
- m_bar->setMaximum(total);
- m_bar->setValue(current);
+ m_bar->setMaximum(total);
+ m_bar->setValue(current);
}
void ProgressWidget::taskDestroyed()
{
- m_task = nullptr;
+ m_task = nullptr;
}
diff --git a/application/widgets/ProgressWidget.h b/application/widgets/ProgressWidget.h
index 08d8a157..fa67748a 100644
--- a/application/widgets/ProgressWidget.h
+++ b/application/widgets/ProgressWidget.h
@@ -11,22 +11,22 @@ class QLabel;
class ProgressWidget : public QWidget
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit ProgressWidget(QWidget *parent = nullptr);
+ explicit ProgressWidget(QWidget *parent = nullptr);
public slots:
- void start(std::shared_ptr<Task> task);
- bool exec(std::shared_ptr<Task> task);
+ void start(std::shared_ptr<Task> task);
+ bool exec(std::shared_ptr<Task> task);
private slots:
- void handleTaskFinish();
- void handleTaskStatus(const QString &status);
- void handleTaskProgress(qint64 current, qint64 total);
- void taskDestroyed();
+ void handleTaskFinish();
+ void handleTaskStatus(const QString &status);
+ void handleTaskProgress(qint64 current, qint64 total);
+ void taskDestroyed();
private:
- QLabel *m_label;
- QProgressBar *m_bar;
- std::shared_ptr<Task> m_task;
+ QLabel *m_label;
+ QProgressBar *m_bar;
+ std::shared_ptr<Task> m_task;
};
diff --git a/application/widgets/ServerStatus.cpp b/application/widgets/ServerStatus.cpp
index f1963b68..a7016c0c 100644
--- a/application/widgets/ServerStatus.cpp
+++ b/application/widgets/ServerStatus.cpp
@@ -15,80 +15,80 @@
class ClickableLabel : public QLabel
{
- Q_OBJECT
+ Q_OBJECT
public:
- ClickableLabel(QWidget *parent) : QLabel(parent)
- {
- setCursor(Qt::PointingHandCursor);
- }
+ ClickableLabel(QWidget *parent) : QLabel(parent)
+ {
+ setCursor(Qt::PointingHandCursor);
+ }
- ~ClickableLabel(){};
+ ~ClickableLabel(){};
signals:
- void clicked();
+ void clicked();
protected:
- void mousePressEvent(QMouseEvent *event)
- {
- emit clicked();
- }
+ void mousePressEvent(QMouseEvent *event)
+ {
+ emit clicked();
+ }
};
class ClickableIconLabel : public IconLabel
{
- Q_OBJECT
+ Q_OBJECT
public:
- ClickableIconLabel(QWidget *parent, QIcon icon, QSize size) : IconLabel(parent, icon, size)
- {
- setCursor(Qt::PointingHandCursor);
- }
+ ClickableIconLabel(QWidget *parent, QIcon icon, QSize size) : IconLabel(parent, icon, size)
+ {
+ setCursor(Qt::PointingHandCursor);
+ }
- ~ClickableIconLabel(){};
+ ~ClickableIconLabel(){};
signals:
- void clicked();
+ void clicked();
protected:
- void mousePressEvent(QMouseEvent *event)
- {
- emit clicked();
- }
+ void mousePressEvent(QMouseEvent *event)
+ {
+ emit clicked();
+ }
};
ServerStatus::ServerStatus(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f)
{
- layout = new QHBoxLayout(this);
- layout->setContentsMargins(0, 0, 0, 0);
- goodIcon = MMC->getThemedIcon("status-good");
- yellowIcon = MMC->getThemedIcon("status-yellow");
- badIcon = MMC->getThemedIcon("status-bad");
-
- addStatus("authserver.mojang.com", tr("Auth"));
- addLine();
- addStatus("sessionserver.mojang.com", tr("Session"));
- addLine();
- addStatus("textures.minecraft.net", tr("Skins"));
- addLine();
- addStatus("api.mojang.com", tr("API"));
-
- m_statusRefresh = new QToolButton(this);
- m_statusRefresh->setCheckable(true);
- m_statusRefresh->setToolButtonStyle(Qt::ToolButtonIconOnly);
- m_statusRefresh->setIcon(MMC->getThemedIcon("refresh"));
- layout->addWidget(m_statusRefresh);
-
- setLayout(layout);
-
- // Start status checker
- m_statusChecker.reset(new StatusChecker());
- {
- auto reloader = m_statusChecker.get();
- connect(reloader, &StatusChecker::statusChanged, this, &ServerStatus::StatusChanged);
- connect(reloader, &StatusChecker::statusLoading, this, &ServerStatus::StatusReloading);
- connect(m_statusRefresh, &QAbstractButton::clicked, this, &ServerStatus::reloadStatus);
- m_statusChecker->startTimer(60000);
- reloadStatus();
- }
+ layout = new QHBoxLayout(this);
+ layout->setContentsMargins(0, 0, 0, 0);
+ goodIcon = MMC->getThemedIcon("status-good");
+ yellowIcon = MMC->getThemedIcon("status-yellow");
+ badIcon = MMC->getThemedIcon("status-bad");
+
+ addStatus("authserver.mojang.com", tr("Auth"));
+ addLine();
+ addStatus("sessionserver.mojang.com", tr("Session"));
+ addLine();
+ addStatus("textures.minecraft.net", tr("Skins"));
+ addLine();
+ addStatus("api.mojang.com", tr("API"));
+
+ m_statusRefresh = new QToolButton(this);
+ m_statusRefresh->setCheckable(true);
+ m_statusRefresh->setToolButtonStyle(Qt::ToolButtonIconOnly);
+ m_statusRefresh->setIcon(MMC->getThemedIcon("refresh"));
+ layout->addWidget(m_statusRefresh);
+
+ setLayout(layout);
+
+ // Start status checker
+ m_statusChecker.reset(new StatusChecker());
+ {
+ auto reloader = m_statusChecker.get();
+ connect(reloader, &StatusChecker::statusChanged, this, &ServerStatus::StatusChanged);
+ connect(reloader, &StatusChecker::statusLoading, this, &ServerStatus::StatusReloading);
+ connect(m_statusRefresh, &QAbstractButton::clicked, this, &ServerStatus::reloadStatus);
+ m_statusChecker->startTimer(60000);
+ reloadStatus();
+ }
}
ServerStatus::~ServerStatus()
@@ -97,83 +97,83 @@ ServerStatus::~ServerStatus()
void ServerStatus::reloadStatus()
{
- m_statusChecker->reloadStatus();
+ m_statusChecker->reloadStatus();
}
void ServerStatus::addLine()
{
- layout->addWidget(new LineSeparator(this, Qt::Vertical));
+ layout->addWidget(new LineSeparator(this, Qt::Vertical));
}
void ServerStatus::addStatus(QString key, QString name)
{
- {
- auto label = new ClickableIconLabel(this, badIcon, QSize(16, 16));
- label->setToolTip(key);
- serverLabels[key] = label;
- layout->addWidget(label);
- connect(label,SIGNAL(clicked()),SLOT(clicked()));
- }
- {
- auto label = new ClickableLabel(this);
- label->setText(name);
- label->setToolTip(key);
- layout->addWidget(label);
- connect(label,SIGNAL(clicked()),SLOT(clicked()));
- }
+ {
+ auto label = new ClickableIconLabel(this, badIcon, QSize(16, 16));
+ label->setToolTip(key);
+ serverLabels[key] = label;
+ layout->addWidget(label);
+ connect(label,SIGNAL(clicked()),SLOT(clicked()));
+ }
+ {
+ auto label = new ClickableLabel(this);
+ label->setText(name);
+ label->setToolTip(key);
+ layout->addWidget(label);
+ connect(label,SIGNAL(clicked()),SLOT(clicked()));
+ }
}
void ServerStatus::clicked()
{
- DesktopServices::openUrl(QUrl("https://help.mojang.com/"));
+ DesktopServices::openUrl(QUrl("https://help.mojang.com/"));
}
void ServerStatus::setStatus(QString key, int value)
{
- if (!serverLabels.contains(key))
- return;
- IconLabel *label = serverLabels[key];
- switch(value)
- {
- case 0:
- label->setIcon(goodIcon);
- break;
- case 1:
- label->setIcon(yellowIcon);
- break;
- default:
- case 2:
- label->setIcon(badIcon);
- break;
- }
+ if (!serverLabels.contains(key))
+ return;
+ IconLabel *label = serverLabels[key];
+ switch(value)
+ {
+ case 0:
+ label->setIcon(goodIcon);
+ break;
+ case 1:
+ label->setIcon(yellowIcon);
+ break;
+ default:
+ case 2:
+ label->setIcon(badIcon);
+ break;
+ }
}
void ServerStatus::StatusChanged(const QMap<QString, QString> statusEntries)
{
- auto convertStatus = [&](QString status)->int
- {
- if (status == "green")
- return 0;
- else if (status == "yellow")
- return 1;
- else if (status == "red")
- return 2;
- return 2;
- }
- ;
- auto iter = statusEntries.begin();
- while (iter != statusEntries.end())
- {
- QString key = iter.key();
- auto value = convertStatus(iter.value());
- setStatus(key, value);
- iter++;
- }
+ auto convertStatus = [&](QString status)->int
+ {
+ if (status == "green")
+ return 0;
+ else if (status == "yellow")
+ return 1;
+ else if (status == "red")
+ return 2;
+ return 2;
+ }
+ ;
+ auto iter = statusEntries.begin();
+ while (iter != statusEntries.end())
+ {
+ QString key = iter.key();
+ auto value = convertStatus(iter.value());
+ setStatus(key, value);
+ iter++;
+ }
}
void ServerStatus::StatusReloading(bool is_reloading)
{
- m_statusRefresh->setChecked(is_reloading);
+ m_statusRefresh->setChecked(is_reloading);
}
#include "ServerStatus.moc"
diff --git a/application/widgets/ServerStatus.h b/application/widgets/ServerStatus.h
index 9beb8e4f..e1e70dfb 100644
--- a/application/widgets/ServerStatus.h
+++ b/application/widgets/ServerStatus.h
@@ -12,29 +12,29 @@ class StatusChecker;
class ServerStatus: public QWidget
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit ServerStatus(QWidget *parent = nullptr, Qt::WindowFlags f = 0);
- virtual ~ServerStatus();
+ explicit ServerStatus(QWidget *parent = nullptr, Qt::WindowFlags f = 0);
+ virtual ~ServerStatus();
public slots:
- void reloadStatus();
- void StatusChanged(const QMap<QString, QString> statuses);
- void StatusReloading(bool is_reloading);
+ void reloadStatus();
+ void StatusChanged(const QMap<QString, QString> statuses);
+ void StatusReloading(bool is_reloading);
private slots:
- void clicked();
+ void clicked();
private: /* methods */
- void addLine();
- void addStatus(QString key, QString name);
- void setStatus(QString key, int value);
+ void addLine();
+ void addStatus(QString key, QString name);
+ void setStatus(QString key, int value);
private: /* data */
- QHBoxLayout * layout = nullptr;
- QToolButton *m_statusRefresh = nullptr;
- QMap<QString, IconLabel *> serverLabels;
- QIcon goodIcon;
- QIcon yellowIcon;
- QIcon badIcon;
- std::shared_ptr<StatusChecker> m_statusChecker;
+ QHBoxLayout * layout = nullptr;
+ QToolButton *m_statusRefresh = nullptr;
+ QMap<QString, IconLabel *> serverLabels;
+ QIcon goodIcon;
+ QIcon yellowIcon;
+ QIcon badIcon;
+ std::shared_ptr<StatusChecker> m_statusChecker;
};
diff --git a/application/widgets/VersionListView.cpp b/application/widgets/VersionListView.cpp
index 8c80ecf3..09df75b7 100644
--- a/application/widgets/VersionListView.cpp
+++ b/application/widgets/VersionListView.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,155 +22,140 @@
#include "Common.h"
VersionListView::VersionListView(QWidget *parent)
- :QTreeView ( parent )
+ :QTreeView ( parent )
{
- m_emptyString = tr("No versions are currently available.");
+ m_emptyString = tr("No versions are currently available.");
}
void VersionListView::rowsInserted(const QModelIndex &parent, int start, int end)
{
- if(!m_itemCount)
- viewport()->update();
- m_itemCount += end-start+1;
- QTreeView::rowsInserted(parent, start, end);
+ m_itemCount += end-start+1;
+ updateEmptyViewPort();
+ QTreeView::rowsInserted(parent, start, end);
}
void VersionListView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
{
- m_itemCount -= end-start+1;
- if(!m_itemCount)
- viewport()->update();
- QTreeView::rowsInserted(parent, start, end);
+ m_itemCount -= end-start+1;
+ updateEmptyViewPort();
+ QTreeView::rowsInserted(parent, start, end);
}
void VersionListView::setModel(QAbstractItemModel *model)
{
- m_itemCount = model->rowCount();
- if(!m_itemCount)
- viewport()->update();
- QTreeView::setModel(model);
+ m_itemCount = model->rowCount();
+ updateEmptyViewPort();
+ QTreeView::setModel(model);
}
void VersionListView::reset()
{
- if(model())
- {
- m_itemCount = model()->rowCount();
- }
- viewport()->update();
- QTreeView::reset();
+ if(model())
+ {
+ m_itemCount = model()->rowCount();
+ }
+ else {
+ m_itemCount = 0;
+ }
+ updateEmptyViewPort();
+ QTreeView::reset();
}
void VersionListView::setEmptyString(QString emptyString)
{
- m_emptyString = emptyString;
- updateEmptyViewPort();
+ m_emptyString = emptyString;
+ updateEmptyViewPort();
}
void VersionListView::setEmptyErrorString(QString emptyErrorString)
{
- m_emptyErrorString = emptyErrorString;
- updateEmptyViewPort();
+ m_emptyErrorString = emptyErrorString;
+ updateEmptyViewPort();
}
void VersionListView::setEmptyMode(VersionListView::EmptyMode mode)
{
- m_emptyMode = mode;
- updateEmptyViewPort();
+ m_emptyMode = mode;
+ updateEmptyViewPort();
}
void VersionListView::updateEmptyViewPort()
{
- if(!m_itemCount)
- {
- viewport()->update();
- }
+ setAccessibleDescription(currentEmptyString());
+
+ if(!m_itemCount)
+ {
+ viewport()->update();
+ }
}
void VersionListView::paintEvent(QPaintEvent *event)
{
- if(m_itemCount)
- {
- QTreeView::paintEvent(event);
- }
- else
- {
- paintInfoLabel(event);
- }
+ if(m_itemCount)
+ {
+ QTreeView::paintEvent(event);
+ }
+ else
+ {
+ paintInfoLabel(event);
+ }
}
-void VersionListView::paintInfoLabel(QPaintEvent *event)
+QString VersionListView::currentEmptyString() const
{
- QString emptyString;
- switch(m_emptyMode)
- {
- case VersionListView::Empty:
- return;
- case VersionListView::String:
- emptyString = m_emptyString;
- break;
- case VersionListView::ErrorString:
- emptyString = m_emptyErrorString;
- break;
- }
+ if(m_itemCount) {
+ return QString();
+ }
+ switch(m_emptyMode)
+ {
+ default:
+ case VersionListView::Empty:
+ return QString();
+ case VersionListView::String:
+ return m_emptyString;
+ case VersionListView::ErrorString:
+ return m_emptyErrorString;
+ }
+}
+
+
+void VersionListView::paintInfoLabel(QPaintEvent *event) const
+{
+ QString emptyString = currentEmptyString();
+
//calculate the rect for the overlay
QPainter painter(viewport());
painter.setRenderHint(QPainter::Antialiasing, true);
- QFont font("sans", 20);
+ QFont font("sans", 20);
font.setBold(true);
-
- QRect bounds = viewport()->geometry();
- bounds.moveTop(0);
- QTextLayout layout(emptyString, font);
- qreal height = 0.0;
- qreal widthUsed = 0.0;
- QStringList lines = viewItemTextLayout(layout, bounds.width() - 20, height, widthUsed);
- QRect rect (0,0, widthUsed, height);
- rect.setWidth(rect.width()+20);
- rect.setHeight(rect.height()+20);
- rect.moveCenter(bounds.center());
+
+ QRect bounds = viewport()->geometry();
+ bounds.moveTop(0);
+ auto innerBounds = bounds;
+ innerBounds.adjust(10, 10, -10, -10);
+
+ QColor background = QApplication::palette().color(QPalette::Foreground);
+ QColor foreground = QApplication::palette().color(QPalette::Base);
+ foreground.setAlpha(190);
+ painter.setFont(font);
+ auto fontMetrics = painter.fontMetrics();
+ auto textRect = fontMetrics.boundingRect(innerBounds, Qt::AlignHCenter | Qt::TextWordWrap, emptyString);
+ textRect.moveCenter(bounds.center());
+
+ auto wrapRect = textRect;
+ wrapRect.adjust(-10, -10, 10, 10);
+
//check if we are allowed to draw in our area
- if (!event->rect().intersects(rect)) {
+ if (!event->rect().intersects(wrapRect)) {
return;
}
- //draw the letter of the topmost item semitransparent in the middle
- QColor background = QApplication::palette().color(QPalette::Foreground);
- QColor foreground = QApplication::palette().color(QPalette::Base);
- /*
- background.setAlpha(128 - scrollFade);
- foreground.setAlpha(128 - scrollFade);
- */
+
painter.setBrush(QBrush(background));
painter.setPen(foreground);
- painter.drawRoundedRect(rect, 5.0, 5.0);
- foreground.setAlpha(190);
+ painter.drawRoundedRect(wrapRect, 5.0, 5.0);
+
painter.setPen(foreground);
painter.setFont(font);
- painter.drawText(rect, Qt::AlignCenter, lines.join("\n"));
-
-}
-
-/*
-void ModListView::setModel ( QAbstractItemModel* model )
-{
- QTreeView::setModel ( model );
- auto head = header();
- head->setStretchLastSection(false);
- // HACK: this is true for the checkbox column of mod lists
- auto string = model->headerData(0,head->orientation()).toString();
- if(!string.size())
- {
- head->setSectionResizeMode(0, QHeaderView::ResizeToContents);
- head->setSectionResizeMode(1, QHeaderView::Stretch);
- for(int i = 2; i < head->count(); i++)
- head->setSectionResizeMode(i, QHeaderView::ResizeToContents);
- }
- else
- {
- head->setSectionResizeMode(0, QHeaderView::Stretch);
- for(int i = 1; i < head->count(); i++)
- head->setSectionResizeMode(i, QHeaderView::ResizeToContents);
- }
+ painter.drawText(textRect, Qt::AlignHCenter | Qt::TextWordWrap, emptyString);
}
-*/
diff --git a/application/widgets/VersionListView.h b/application/widgets/VersionListView.h
index b7a881e9..37f7b27e 100644
--- a/application/widgets/VersionListView.h
+++ b/application/widgets/VersionListView.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 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,42 +16,41 @@
#pragma once
#include <QTreeView>
-class Mod;
-
class VersionListView : public QTreeView
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit VersionListView(QWidget *parent = 0);
- virtual void paintEvent(QPaintEvent *event) override;
- virtual void setModel(QAbstractItemModel* model) override;
+ explicit VersionListView(QWidget *parent = 0);
+ virtual void paintEvent(QPaintEvent *event) override;
+ virtual void setModel(QAbstractItemModel* model) override;
- enum EmptyMode
- {
- Empty,
- String,
- ErrorString
- };
+ enum EmptyMode
+ {
+ Empty,
+ String,
+ ErrorString
+ };
- void setEmptyString(QString emptyString);
- void setEmptyErrorString(QString emptyErrorString);
- void setEmptyMode(EmptyMode mode);
+ void setEmptyString(QString emptyString);
+ void setEmptyErrorString(QString emptyErrorString);
+ void setEmptyMode(EmptyMode mode);
public slots:
- virtual void reset() override;
+ virtual void reset() override;
protected slots:
- virtual void rowsAboutToBeRemoved(const QModelIndex & parent, int start, int end) override;
- virtual void rowsInserted(const QModelIndex &parent, int start, int end) override;
+ virtual void rowsAboutToBeRemoved(const QModelIndex & parent, int start, int end) override;
+ virtual void rowsInserted(const QModelIndex &parent, int start, int end) override;
private: /* methods */
- void paintInfoLabel(QPaintEvent *event);
- void updateEmptyViewPort();
+ void paintInfoLabel(QPaintEvent *event) const;
+ void updateEmptyViewPort();
+ QString currentEmptyString() const;
private: /* variables */
- int m_itemCount = 0;
- QString m_emptyString;
- QString m_emptyErrorString;
- EmptyMode m_emptyMode = Empty;
+ int m_itemCount = 0;
+ QString m_emptyString;
+ QString m_emptyErrorString;
+ EmptyMode m_emptyMode = Empty;
};
diff --git a/application/widgets/VersionSelectWidget.cpp b/application/widgets/VersionSelectWidget.cpp
index ce1141b6..9925a6b4 100644
--- a/application/widgets/VersionSelectWidget.cpp
+++ b/application/widgets/VersionSelectWidget.cpp
@@ -7,50 +7,51 @@
#include <dialogs/CustomMessageBox.h>
VersionSelectWidget::VersionSelectWidget(QWidget* parent)
- : QWidget(parent)
+ : QWidget(parent)
{
- setObjectName(QStringLiteral("VersionSelectWidget"));
- verticalLayout = new QVBoxLayout(this);
- verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
- verticalLayout->setContentsMargins(0, 0, 0, 0);
+ setObjectName(QStringLiteral("VersionSelectWidget"));
+ verticalLayout = new QVBoxLayout(this);
+ verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
+ verticalLayout->setContentsMargins(0, 0, 0, 0);
- m_proxyModel = new VersionProxyModel(this);
+ m_proxyModel = new VersionProxyModel(this);
- listView = new VersionListView(this);
- listView->setObjectName(QStringLiteral("listView"));
- listView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- listView->setAlternatingRowColors(true);
- listView->setRootIsDecorated(false);
- listView->setItemsExpandable(false);
- listView->setWordWrap(true);
- listView->header()->setCascadingSectionResizes(true);
- listView->header()->setStretchLastSection(false);
- listView->setModel(m_proxyModel);
- verticalLayout->addWidget(listView);
+ listView = new VersionListView(this);
+ listView->setObjectName(QStringLiteral("listView"));
+ listView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ listView->setAlternatingRowColors(true);
+ listView->setRootIsDecorated(false);
+ listView->setItemsExpandable(false);
+ listView->setWordWrap(true);
+ listView->header()->setCascadingSectionResizes(true);
+ listView->header()->setStretchLastSection(false);
+ listView->setModel(m_proxyModel);
+ verticalLayout->addWidget(listView);
- sneakyProgressBar = new QProgressBar(this);
- sneakyProgressBar->setObjectName(QStringLiteral("sneakyProgressBar"));
- sneakyProgressBar->setFormat(QStringLiteral("%p%"));
- verticalLayout->addWidget(sneakyProgressBar);
- sneakyProgressBar->setHidden(true);
- connect(listView->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &VersionSelectWidget::currentRowChanged);
+ sneakyProgressBar = new QProgressBar(this);
+ sneakyProgressBar->setObjectName(QStringLiteral("sneakyProgressBar"));
+ sneakyProgressBar->setFormat(QStringLiteral("%p%"));
+ verticalLayout->addWidget(sneakyProgressBar);
+ sneakyProgressBar->setHidden(true);
+ connect(listView->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &VersionSelectWidget::currentRowChanged);
- QMetaObject::connectSlotsByName(this);
+ QMetaObject::connectSlotsByName(this);
}
void VersionSelectWidget::setCurrentVersion(const QString& version)
{
- m_currentVersion = version;
+ m_currentVersion = version;
+ m_proxyModel->setCurrentVersion(version);
}
void VersionSelectWidget::setEmptyString(QString emptyString)
{
- listView->setEmptyString(emptyString);
+ listView->setEmptyString(emptyString);
}
void VersionSelectWidget::setEmptyErrorString(QString emptyErrorString)
{
- listView->setEmptyErrorString(emptyErrorString);
+ listView->setEmptyErrorString(emptyErrorString);
}
VersionSelectWidget::~VersionSelectWidget()
@@ -59,143 +60,143 @@ VersionSelectWidget::~VersionSelectWidget()
void VersionSelectWidget::setResizeOn(int column)
{
- listView->header()->setSectionResizeMode(resizeOnColumn, QHeaderView::ResizeToContents);
- resizeOnColumn = column;
- listView->header()->setSectionResizeMode(resizeOnColumn, QHeaderView::Stretch);
+ listView->header()->setSectionResizeMode(resizeOnColumn, QHeaderView::ResizeToContents);
+ resizeOnColumn = column;
+ listView->header()->setSectionResizeMode(resizeOnColumn, QHeaderView::Stretch);
}
void VersionSelectWidget::initialize(BaseVersionList *vlist)
{
- m_vlist = vlist;
- m_proxyModel->setSourceModel(vlist);
- listView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
- listView->header()->setSectionResizeMode(resizeOnColumn, QHeaderView::Stretch);
-
- if (!m_vlist->isLoaded())
- {
- loadList();
- }
- else
- {
- if (m_proxyModel->rowCount() == 0)
- {
- listView->setEmptyMode(VersionListView::String);
- }
- preselect();
- }
+ m_vlist = vlist;
+ m_proxyModel->setSourceModel(vlist);
+ listView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
+ listView->header()->setSectionResizeMode(resizeOnColumn, QHeaderView::Stretch);
+
+ if (!m_vlist->isLoaded())
+ {
+ loadList();
+ }
+ else
+ {
+ if (m_proxyModel->rowCount() == 0)
+ {
+ listView->setEmptyMode(VersionListView::String);
+ }
+ preselect();
+ }
}
void VersionSelectWidget::closeEvent(QCloseEvent * event)
{
- QWidget::closeEvent(event);
+ QWidget::closeEvent(event);
}
void VersionSelectWidget::loadList()
{
- auto newTask = m_vlist->getLoadTask();
- if (!newTask)
- {
- return;
- }
- loadTask = newTask.get();
- connect(loadTask, &Task::succeeded, this, &VersionSelectWidget::onTaskSucceeded);
- connect(loadTask, &Task::failed, this, &VersionSelectWidget::onTaskFailed);
- connect(loadTask, &Task::progress, this, &VersionSelectWidget::changeProgress);
- if(!loadTask->isRunning())
- {
- loadTask->start();
- }
- sneakyProgressBar->setHidden(false);
+ auto newTask = m_vlist->getLoadTask();
+ if (!newTask)
+ {
+ return;
+ }
+ loadTask = newTask.get();
+ connect(loadTask, &Task::succeeded, this, &VersionSelectWidget::onTaskSucceeded);
+ connect(loadTask, &Task::failed, this, &VersionSelectWidget::onTaskFailed);
+ connect(loadTask, &Task::progress, this, &VersionSelectWidget::changeProgress);
+ if(!loadTask->isRunning())
+ {
+ loadTask->start();
+ }
+ sneakyProgressBar->setHidden(false);
}
void VersionSelectWidget::onTaskSucceeded()
{
- if (m_proxyModel->rowCount() == 0)
- {
- listView->setEmptyMode(VersionListView::String);
- }
- sneakyProgressBar->setHidden(true);
- preselect();
- loadTask = nullptr;
+ if (m_proxyModel->rowCount() == 0)
+ {
+ listView->setEmptyMode(VersionListView::String);
+ }
+ sneakyProgressBar->setHidden(true);
+ preselect();
+ loadTask = nullptr;
}
void VersionSelectWidget::onTaskFailed(const QString& reason)
{
- CustomMessageBox::selectable(this, tr("Error"), tr("List update failed:\n%1").arg(reason), QMessageBox::Warning)->show();
- onTaskSucceeded();
+ CustomMessageBox::selectable(this, tr("Error"), tr("List update failed:\n%1").arg(reason), QMessageBox::Warning)->show();
+ onTaskSucceeded();
}
void VersionSelectWidget::changeProgress(qint64 current, qint64 total)
{
- sneakyProgressBar->setMaximum(total);
- sneakyProgressBar->setValue(current);
+ sneakyProgressBar->setMaximum(total);
+ sneakyProgressBar->setValue(current);
}
void VersionSelectWidget::currentRowChanged(const QModelIndex& current, const QModelIndex&)
{
- auto variant = m_proxyModel->data(current, BaseVersionList::VersionPointerRole);
- emit selectedVersionChanged(variant.value<BaseVersionPtr>());
+ auto variant = m_proxyModel->data(current, BaseVersionList::VersionPointerRole);
+ emit selectedVersionChanged(variant.value<BaseVersionPtr>());
}
void VersionSelectWidget::preselect()
{
- if(preselectedAlready)
- return;
- selectCurrent();
- if(preselectedAlready)
- return;
- selectRecommended();
+ if(preselectedAlready)
+ return;
+ selectCurrent();
+ if(preselectedAlready)
+ return;
+ selectRecommended();
}
void VersionSelectWidget::selectCurrent()
{
- if(m_currentVersion.isEmpty())
- {
- return;
- }
- auto idx = m_proxyModel->getVersion(m_currentVersion);
- if(idx.isValid())
- {
- preselectedAlready = true;
- listView->selectionModel()->setCurrentIndex(idx,QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
- listView->scrollTo(idx, QAbstractItemView::PositionAtCenter);
- }
+ if(m_currentVersion.isEmpty())
+ {
+ return;
+ }
+ auto idx = m_proxyModel->getVersion(m_currentVersion);
+ if(idx.isValid())
+ {
+ preselectedAlready = true;
+ listView->selectionModel()->setCurrentIndex(idx,QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
+ listView->scrollTo(idx, QAbstractItemView::PositionAtCenter);
+ }
}
void VersionSelectWidget::selectRecommended()
{
- auto idx = m_proxyModel->getRecommended();
- if(idx.isValid())
- {
- preselectedAlready = true;
- listView->selectionModel()->setCurrentIndex(idx,QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
- listView->scrollTo(idx, QAbstractItemView::PositionAtCenter);
- }
+ auto idx = m_proxyModel->getRecommended();
+ if(idx.isValid())
+ {
+ preselectedAlready = true;
+ listView->selectionModel()->setCurrentIndex(idx,QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
+ listView->scrollTo(idx, QAbstractItemView::PositionAtCenter);
+ }
}
bool VersionSelectWidget::hasVersions() const
{
- return m_proxyModel->rowCount(QModelIndex()) != 0;
+ return m_proxyModel->rowCount(QModelIndex()) != 0;
}
BaseVersionPtr VersionSelectWidget::selectedVersion() const
{
- auto currentIndex = listView->selectionModel()->currentIndex();
- auto variant = m_proxyModel->data(currentIndex, BaseVersionList::VersionPointerRole);
- return variant.value<BaseVersionPtr>();
+ auto currentIndex = listView->selectionModel()->currentIndex();
+ auto variant = m_proxyModel->data(currentIndex, BaseVersionList::VersionPointerRole);
+ return variant.value<BaseVersionPtr>();
}
void VersionSelectWidget::setExactFilter(BaseVersionList::ModelRoles role, QString filter)
{
- m_proxyModel->setFilter(role, new ExactFilter(filter));
+ m_proxyModel->setFilter(role, new ExactFilter(filter));
}
void VersionSelectWidget::setFuzzyFilter(BaseVersionList::ModelRoles role, QString filter)
{
- m_proxyModel->setFilter(role, new ContainsFilter(filter));
+ m_proxyModel->setFilter(role, new ContainsFilter(filter));
}
void VersionSelectWidget::setFilter(BaseVersionList::ModelRoles role, Filter *filter)
{
- m_proxyModel->setFilter(role, filter);
+ m_proxyModel->setFilter(role, filter);
}
diff --git a/application/widgets/VersionSelectWidget.h b/application/widgets/VersionSelectWidget.h
index c134887f..701f568e 100644
--- a/application/widgets/VersionSelectWidget.h
+++ b/application/widgets/VersionSelectWidget.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,55 +27,55 @@ class Filter;
class VersionSelectWidget: public QWidget
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit VersionSelectWidget(QWidget *parent = 0);
- ~VersionSelectWidget();
+ explicit VersionSelectWidget(QWidget *parent = 0);
+ ~VersionSelectWidget();
- //! loads the list if needed.
- void initialize(BaseVersionList *vlist);
+ //! loads the list if needed.
+ void initialize(BaseVersionList *vlist);
- //! Starts a task that loads the list.
- void loadList();
+ //! Starts a task that loads the list.
+ void loadList();
- bool hasVersions() const;
- BaseVersionPtr selectedVersion() const;
- void selectRecommended();
- void selectCurrent();
+ bool hasVersions() const;
+ BaseVersionPtr selectedVersion() const;
+ void selectRecommended();
+ void selectCurrent();
- void setCurrentVersion(const QString & version);
- void setFuzzyFilter(BaseVersionList::ModelRoles role, QString filter);
- void setExactFilter(BaseVersionList::ModelRoles role, QString filter);
- void setFilter(BaseVersionList::ModelRoles role, Filter *filter);
- void setEmptyString(QString emptyString);
- void setEmptyErrorString(QString emptyErrorString);
- void setResizeOn(int column);
+ void setCurrentVersion(const QString & version);
+ void setFuzzyFilter(BaseVersionList::ModelRoles role, QString filter);
+ void setExactFilter(BaseVersionList::ModelRoles role, QString filter);
+ void setFilter(BaseVersionList::ModelRoles role, Filter *filter);
+ void setEmptyString(QString emptyString);
+ void setEmptyErrorString(QString emptyErrorString);
+ void setResizeOn(int column);
signals:
- void selectedVersionChanged(BaseVersionPtr version);
+ void selectedVersionChanged(BaseVersionPtr version);
protected:
- virtual void closeEvent ( QCloseEvent* );
+ virtual void closeEvent ( QCloseEvent* );
private slots:
- void onTaskSucceeded();
- void onTaskFailed(const QString &reason);
- void changeProgress(qint64 current, qint64 total);
- void currentRowChanged(const QModelIndex &current, const QModelIndex &);
+ void onTaskSucceeded();
+ void onTaskFailed(const QString &reason);
+ void changeProgress(qint64 current, qint64 total);
+ void currentRowChanged(const QModelIndex &current, const QModelIndex &);
private:
- void preselect();
+ void preselect();
private:
- QString m_currentVersion;
- BaseVersionList *m_vlist = nullptr;
- VersionProxyModel *m_proxyModel = nullptr;
- int resizeOnColumn = 0;
- Task * loadTask;
- bool preselectedAlready = false;
+ QString m_currentVersion;
+ BaseVersionList *m_vlist = nullptr;
+ VersionProxyModel *m_proxyModel = nullptr;
+ int resizeOnColumn = 0;
+ Task * loadTask;
+ bool preselectedAlready = false;
private:
- QVBoxLayout *verticalLayout = nullptr;
- VersionListView *listView = nullptr;
- QProgressBar *sneakyProgressBar = nullptr;
+ QVBoxLayout *verticalLayout = nullptr;
+ VersionListView *listView = nullptr;
+ QProgressBar *sneakyProgressBar = nullptr;
};
diff --git a/application/widgets/WideBar.cpp b/application/widgets/WideBar.cpp
new file mode 100644
index 00000000..cbd6c617
--- /dev/null
+++ b/application/widgets/WideBar.cpp
@@ -0,0 +1,116 @@
+#include "WideBar.h"
+#include <QToolButton>
+#include <QMenu>
+
+class ActionButton : public QToolButton
+{
+ Q_OBJECT
+public:
+ ActionButton(QAction * action, QWidget * parent = 0) : QToolButton(parent), m_action(action) {
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ connect(action, &QAction::changed, this, &ActionButton::actionChanged);
+ connect(this, &ActionButton::clicked, action, &QAction::trigger);
+ actionChanged();
+ };
+private slots:
+ void actionChanged() {
+ setEnabled(m_action->isEnabled());
+ setChecked(m_action->isChecked());
+ setCheckable(m_action->isCheckable());
+ setText(m_action->text());
+ setIcon(m_action->icon());
+ setToolTip(m_action->toolTip());
+ setHidden(!m_action->isVisible());
+ setFocusPolicy(Qt::NoFocus);
+ }
+private:
+ QAction * m_action;
+};
+
+
+WideBar::WideBar(const QString& title, QWidget* parent) : QToolBar(title, parent)
+{
+ setFloatable(false);
+ setMovable(false);
+}
+
+WideBar::WideBar(QWidget* parent) : QToolBar(parent)
+{
+ setFloatable(false);
+ setMovable(false);
+}
+
+struct WideBar::BarEntry {
+ enum Type {
+ None,
+ Action,
+ Separator,
+ Spacer
+ } type = None;
+ QAction *qAction = nullptr;
+ QAction *wideAction = nullptr;
+};
+
+
+WideBar::~WideBar()
+{
+ for(auto *iter: m_entries) {
+ delete iter;
+ }
+}
+
+void WideBar::addAction(QAction* action)
+{
+ auto entry = new BarEntry();
+ entry->qAction = addWidget(new ActionButton(action, this));
+ entry->wideAction = action;
+ entry->type = BarEntry::Action;
+ m_entries.push_back(entry);
+}
+
+void WideBar::addSeparator()
+{
+ auto entry = new BarEntry();
+ entry->qAction = QToolBar::addSeparator();
+ entry->type = BarEntry::Separator;
+ m_entries.push_back(entry);
+}
+
+void WideBar::insertSpacer(QAction* action)
+{
+ auto iter = std::find_if(m_entries.begin(), m_entries.end(), [action](BarEntry * entry) {
+ return entry->wideAction == action;
+ });
+ if(iter == m_entries.end()) {
+ return;
+ }
+ QWidget* spacer = new QWidget();
+ spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+
+ auto entry = new BarEntry();
+ entry->qAction = insertWidget((*iter)->qAction, spacer);
+ entry->type = BarEntry::Spacer;
+ m_entries.insert(iter, entry);
+}
+
+QMenu * WideBar::createContextMenu(QWidget *parent, const QString & title)
+{
+ QMenu *contextMenu = new QMenu(title, parent);
+ for(auto & item: m_entries) {
+ switch(item->type) {
+ default:
+ case BarEntry::None:
+ break;
+ case BarEntry::Separator:
+ case BarEntry::Spacer:
+ contextMenu->addSeparator();
+ break;
+ case BarEntry::Action:
+ contextMenu->addAction(item->wideAction);
+ break;
+ }
+ }
+ return contextMenu;
+}
+
+#include "WideBar.moc"
diff --git a/application/widgets/WideBar.h b/application/widgets/WideBar.h
new file mode 100644
index 00000000..d1b8cbe7
--- /dev/null
+++ b/application/widgets/WideBar.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <QToolBar>
+#include <QAction>
+#include <QMap>
+
+class QMenu;
+
+class WideBar : public QToolBar
+{
+ Q_OBJECT
+
+public:
+ explicit WideBar(const QString &title, QWidget * parent = nullptr);
+ explicit WideBar(QWidget * parent = nullptr);
+ virtual ~WideBar();
+
+ void addAction(QAction *action);
+ void addSeparator();
+ void insertSpacer(QAction *action);
+ QMenu *createContextMenu(QWidget *parent = nullptr, const QString & title = QString());
+
+private:
+ struct BarEntry;
+ QList<BarEntry *> m_entries;
+};