Compare commits

..

699 Commits
0.0 ... 0.4.7

Author SHA1 Message Date
Petr Mrázek
678c4793f9 GH-980 finalize changelog 2015-06-01 01:29:09 +02:00
Petr Mrázek
405cea1778 GH-1031 include icon in exported instance if it is custom 2015-06-01 01:19:12 +02:00
Petr Mrázek
96c497f654 GH-980 more changelog tweakery 2015-06-01 00:18:52 +02:00
Petr Mrázek
10b3906b53 GH-980 Update changelog for 0.4.7 2015-06-01 00:12:46 +02:00
Petr Mrázek
6fd18a5cce GH-1016 print list of mods, coremods and jarmods
Includes a change to jar mods, where they gain an 'originalName' attribute used only for display
2015-05-31 21:50:01 +02:00
Petr Mrázek
9920062003 GH-1016 print mods, jar mods and core mods on start
Needs some work - jar mods just have the uuid name
2015-05-31 21:50:01 +02:00
Petr Mrázek
99f248ecd4 GH-1015 catch exceptions when doing profile reapply
This is a temporary solution.
2015-05-31 20:00:15 +02:00
Petr Mrázek
b9e06b5da0 GH-1021 make builtin versions not customizable
They use attributes not defined in the OneSix format.
2015-05-31 19:24:39 +02:00
Petr Mrázek
ff64b6cf1d GH-1020 use plain strings for library URLs
Because the URLs can contain {}, which are percent encoded in URLs and this breaks variable substitution
2015-05-31 17:51:20 +02:00
Petr Mrázek
84757f485b GH-1015 fix crash when version is incomplete and adding jar mods 2015-05-29 08:32:05 +02:00
Petr Mrázek
b7f8241968 GH-994 hopefully fix issue with people still using jar mods
Added an 'add mods' button to the version page
Add jar mods now has a very angry nag dialog until it's used successfully
Buttons on version page are rearranged to deemphasize jar mods
2015-05-29 02:22:02 +02:00
Petr Mrázek
a98e1df10c GH-1011 fetch missing versions when customizing/reverting Minecraft patches 2015-05-28 09:36:58 +02:00
Petr Mrázek
f9e186ab70 GH-967 make libraries handle their own path prefix
Makes it possible to mix libraries managed by FTB and MultiMC
Backport from unstable
2015-05-27 01:30:18 +02:00
Petr Mrázek
50a4a1e19e NOISSUE use -fPIC builds when the system Qt is derpy 2015-05-26 22:38:01 +02:00
Petr Mrázek
2f087b55b9 GH-997 fix saving of settings values with special characters
Values are now escaped properly
2015-05-26 08:33:10 +02:00
Petr Mrázek
2dcedcfde3 GH-997 add unit test for ini file save/load passthrough 2015-05-26 08:29:43 +02:00
Petr Mrázek
c1c23e47a7 GH-1003 Fix settings dialog delays 2015-05-26 08:14:33 +02:00
Petr Mrázek
8fb5d4add3 GH-1003 add some save locking for dialog pages that deal with settings 2015-05-25 08:21:35 +02:00
Petr Mrázek
185ff238c2 GH-992 GH-997 Do not rewrite values when loading FTB packs
name, icon and notes won't be overwritten when loading FTB packs
this also eliminates the file saving delay from setting the values
2015-05-25 07:35:43 +02:00
Petr Mrázek
09673cc16e GH-977 Initialize FTB icon properly (iconKey vs logo), remove debug prints 2015-05-24 19:48:22 +02:00
Petr Mrázek
dfb0a3b724 GH-991 implement wrapper commands 2015-05-24 14:49:54 +02:00
Petr Mrázek
ce99fabe13 GH-992 Add a transaction/locking mechanism to settings objects
This can cut the FTB loading by ~66% - worth it, but not ideal.
Real solution will have to be implemented later.
2015-05-23 16:07:47 +02:00
Petr Mrázek
0e0ddf5494 GH-977 Improve FTB loading and instance creation 2015-05-22 23:06:51 +02:00
Petr Mrázek
12b9a90c4c GH-980 update chengelog 2015-05-22 02:06:25 +02:00
Petr Mrázek
8715746774 GH-977 this isn't funny anymore... 2015-05-22 01:27:59 +02:00
Petr Mrázek
cfdfd0e811 GH-977 possibly fix FTB on windows. Maybe. Partially. Now maybe for real. 2015-05-22 01:08:37 +02:00
Petr Mrázek
81b37dae18 GH-977 possibly fix FTB on windows. Maybe. Partially. 2015-05-21 23:25:16 +02:00
Petr Mrázek
29ce36c7bc GH-983 use 'minecraft.jar' for ancient jar-modded versions
Fixes NEI in MC 1.4.7 and probably other obscure issues
2015-05-21 22:38:31 +02:00
Petr Mrázek
22a0294a33 GH-985 fix jar mods 2015-05-21 20:47:47 +02:00
Petr Mrázek
5334d88c1d GH-970 fix help page links some more 2015-05-21 20:33:15 +02:00
Petr Mrázek
06080108f3 GH-980 update version number and changelog for 0.4.7 2015-05-21 01:13:05 +02:00
Petr Mrázek
08898c7c63 GH-970 fix help page links 2015-05-21 01:12:18 +02:00
Petr Mrázek
1bc2fbef11 GH-794 add libstdc++ to build on linux. hopefully? 2015-05-21 00:28:30 +02:00
Benjamin Hoffmeyer
a296ec914b NOISSUE Link wiki feature list in readme 2015-05-20 04:00:14 +02:00
Petr Mrázek
53d8c9169d GH-972 fix 'temporaty' typo 2015-05-20 03:14:02 +02:00
Petr Mrázek
4c11ce8063 GH-932 Icon themes actually do not need a restart to be applied 2015-05-20 01:44:01 +02:00
Petr Mrázek
cff2e4823a GH-960 tweak changelog for the OSX SSL fix 2015-05-19 23:12:39 +02:00
Petr Mrázek
d0b31da4b5 GH-960 possible fix for missing OSX ca certs 2015-05-19 22:28:51 +02:00
Petr Mrázek
2ad9e6393f GH-952 Update changelog for hardcore version page tweakery 2015-05-18 00:51:47 +02:00
Petr Mrázek
743af4769e GH-952 Hardcore version page tweakery
Version patches get a lot of new flags that determine which actions are allowed
Version page respects the flags
Customize, revert and edit for version patches
Builting patches can be customized
2015-05-17 23:38:28 +02:00
Petr Mrázek
6ab6a450f6 GH-952 fix legacy edit instance 2015-05-16 23:52:11 +02:00
Petr Mrázek
3ed467e1fa NOISSUE do not dump minecraft version files into the log 2015-05-16 23:33:42 +02:00
Petr Mrázek
44d76f5d82 NOISSUE change travis to Qt 5.3 2015-05-16 23:19:33 +02:00
Petr Mrázek
ff715f7785 NOISSUE replace derpy merkdown thing with hoedown 2015-05-16 23:04:00 +02:00
Petr Mrázek
43c777f386 NOISSUE add some functionality to the derpy markdown changelog thing 2015-05-16 19:33:53 +02:00
Petr Mrázek
a39fb1ef17 GH-958 print PID when starting Minecraft 2015-05-16 18:42:17 +02:00
Petr Mrázek
c75cac684e GH-952 rearrange 0.4.6 changelog into sections so it's actually readable 2015-05-16 18:42:17 +02:00
Petr Mrázek
f2026df597 GH-952 do not remove {version,custom}.json files, rename them 2015-05-16 18:42:14 +02:00
Petr Mrázek
416e08f741 GH-952 flesh out {version,custom}.json upgrade step 2015-05-15 01:37:15 +02:00
Petr Mrázek
5bbe1c7132 GH-951 add .litemod to mod browse dialog 2015-05-12 23:43:11 +02:00
Petr Mrázek
bd1a28d863 GH-932 fix some changelog typos 2015-05-12 09:40:56 +02:00
Petr Mrázek
ffcb5ab1ef GH-932 update version and changelog for 0.4.6 2015-05-12 09:17:04 +02:00
Petr Mrázek
88f975eff7 NOISSUE only watch mod folders when the user is looking at them 2015-05-11 22:50:35 +02:00
Petr Mrázek
11c376f6f1 NOISSUE Remove PermGemn warning ignoring 2015-05-07 08:42:35 +02:00
Petr Mrázek
757b4e260b NOISSUE more logging 2015-05-06 22:16:52 +02:00
Petr Mrázek
2a4647125d GH-942 fix vanilla version list
Latest release gets the star
Latest snapshot, if it's newer than latest release gets the bug
2015-05-06 09:00:21 +02:00
Petr Mrázek
9598f80335 NOISSUE do not show file browse dialog twice 2015-05-06 07:22:24 +02:00
Petr Mrázek
34a5e59007 GH-835 show errors reported by the update download task to the user 2015-05-05 08:15:56 +02:00
Sky
1271188019 Fixed some Forge typos in dialogs. Fixes #940 2015-05-05 00:33:34 +01:00
Petr Mrázek
4c6edc9fd4 GH-907 fix location/java override for java detection 2015-05-05 01:09:28 +02:00
Petr Mrázek
49d3705d16 GH-899 clean up mod browse buttons and dead legacy forge 2015-05-05 00:42:04 +02:00
Petr Mrázek
c09dc85090 GH-899 fix add mod button not opening the central mods folder 2015-05-04 22:17:05 +02:00
Petr Mrázek
c10a4a54d9 NOISSUE windows hates me 2015-05-04 01:28:16 +02:00
Petr Mrázek
1b884d0a9d GH-907 improve Java testing and PermGen deprecation handling 2015-05-04 01:20:48 +02:00
Petr Mrázek
8e9d5f56b5 GH-933 map exit code -1 to 'crashed' 2015-05-02 23:48:18 +02:00
Petr Mrázek
5779ffd664 GH-922 improve version select dialogs 2015-05-02 23:42:33 +02:00
Petr Mrázek
4fc4a17256 NOISSUE handle recommended versions better
Moved constants to the version data file
Use recommended Minecraft instead of latest stable for new instances by default
2015-05-02 12:44:37 +02:00
Petr Mrázek
bb01c91469 NOISSUE do not propagate instance change events when nothing actually changed 2015-05-02 12:11:33 +02:00
Petr Mrázek
fb3c9efc8a NOISSUE launcher part should exit when MultiMC 'hangs up' 2015-05-02 12:08:18 +02:00
Petr Mrázek
55f9117ce3 NOISSUE do not remake instance tools menu, refill it instead 2015-05-02 12:07:18 +02:00
Petr Mrázek
994c815bb9 NOISSUE show errors for instance updates in edit instance window 2015-05-02 01:43:04 +02:00
Petr Mrázek
32f45578fd NOISSUE fix build issues
Hopefully all
2015-05-02 01:43:00 +02:00
Petr Mrázek
2af03ba0d9 GH-930 Improve wording of instance delete dialog 2015-05-01 21:27:16 +02:00
Petr Mrázek
aea51a0876 GH-328 overhaul all relevant version lists 2015-05-01 20:50:24 +02:00
Petr Mrázek
75dfbc61fc GH-925 add scroll to bottom button to LogPage 2015-04-29 01:28:58 +02:00
Petr Mrázek
f8650e3965 NOISSUE eliminate ProgressProvider 2015-04-26 23:04:50 +02:00
Petr Mrázek
84549ed807 GH-849 Further NetJob related fixes 2015-04-26 18:33:29 +02:00
Petr Mrázek
d5c79db12c GH-849 Fix failure signals not getting delivered from NetJob properly 2015-04-26 04:09:09 +02:00
Petr Mrázek
f623dc54ef GH-909 warn about MultiMC running from temporary folders 2015-04-26 00:01:41 +02:00
Petr Mrázek
dc279fbfdc Revert "NOISSUE Cleanup onesix launcher"
This reverts commit 07bebddac9.
2015-04-25 15:32:38 +02:00
Petr Mrázek
8fa58dc244 NOISSUE save group file after copying instance 2015-04-19 21:02:34 +02:00
robotbrain
07bebddac9 NOISSUE Cleanup onesix launcher 2015-04-19 19:07:39 +02:00
Petr Mrázek
4f417d527e GH-894 link server status widgets to help.mojang.com 2015-04-19 17:58:53 +02:00
Petr Mrázek
c7c81463fd GH-885 export dialog for filtering exported files
Includes implementation of a separator based prefix tree and some related bits
2015-04-19 16:14:32 +02:00
Petr Mrázek
6cfac115b1 NOISSUE add commented callgrind startup to linux script 2015-04-15 03:13:57 +02:00
Petr Mrázek
3507ccaf50 GH-866 load instance profile on launch and from version page 2015-04-15 03:12:57 +02:00
Petr Mrázek
28aa8f342e GH-887 fix patch file removal 2015-04-13 23:26:52 +02:00
Petr Mrázek
4d8f068f9c NOISSUE refactor and rearrange zip file utils 2015-04-13 00:53:59 +02:00
Petr Mrázek
1f9dd45e49 GH-329 update description text in MainWindow when instance Minecraft version changes 2015-04-13 00:25:55 +02:00
Petr Mrázek
f061bf7a27 NOISSUE use QObjectPtr for translations and screenshots 2015-04-13 00:21:55 +02:00
Petr Mrázek
d8ea3501eb NOISSUE add waffle.io badge to README
DONTBUILD
2015-04-13 00:20:45 +02:00
Petr Mrázek
9df2f1fa5c NOISSUE fix legacy edit instance 2015-04-13 00:15:23 +02:00
Petr Mrázek
fe540e5dda NOISSUE do not fail when updates don't have MultiMC.app prefix on OSX 2015-04-13 00:11:59 +02:00
Petr Mrázek
c7398dfdc5 GH-228 do not recurse into reparse points when deleting instances 2015-04-13 00:06:31 +02:00
Petr Mrázek
0220fe4f9d GH-228 do not follow symlinks during instance copy on unix
Windows will need a more complex solution.
2015-04-13 00:06:31 +02:00
Petr Mrázek
58840ac10c NOISSUE fix profilers 2015-04-13 00:04:08 +02:00
Petr Mrázek
3d3725f088 SCRATCH small cmake tweaks 2015-04-12 20:57:18 +02:00
Petr Mrázek
47bbc349eb SCRATCH remove more obsolete asset logic 2015-04-12 20:57:18 +02:00
Petr Mrázek
c8687a8d05 NOISSUE get rid of the obsolete version builder 2015-04-12 20:57:18 +02:00
Petr Mrázek
234f57b8e6 NOISSUE Add NullInstance for instances that can't be loaded 2015-04-12 20:57:18 +02:00
Petr Mrázek
d4d8cb4891 NOISSUE remove group sorting log spam 2015-04-12 20:57:18 +02:00
Petr Mrázek
d1ba972c59 SCRATCH move some cmake bits 2015-04-12 20:57:18 +02:00
Petr Mrázek
db877ba121 NOISSUE move everything. 2015-04-12 20:57:18 +02:00
Petr Mrázek
4730f54df7 SCRATCH separate the generic updater logic from the application 2015-04-12 20:57:17 +02:00
Petr Mrázek
7a71ecd8af NOISSUE fix notification checker 2015-04-12 20:57:17 +02:00
Petr Mrázek
4e94de413b SCRATCH no more gui includes in logic 2015-04-12 20:57:17 +02:00
Petr Mrázek
141e0a02a0 SCRATCH move things to the right places 2015-04-12 20:57:17 +02:00
Petr Mrázek
473971b6e7 NOISSUE fix overlap in instance settings registration 2015-04-12 20:57:17 +02:00
Petr Mrázek
b47e196b32 SCRATCH fix version file loading 2015-04-12 20:57:17 +02:00
Petr Mrázek
cd9d37aac4 SCRATCH nuke the overcomplicated logger, use a simple one. 2015-04-12 20:57:17 +02:00
Petr Mrázek
28a39ef7ac NOISSUE fix segfault when version list is null 2015-04-12 20:57:17 +02:00
Petr Mrázek
d313e9ab09 SCRATCH remove remaining references to MultiMC.h and fix legacy LWJGL 2015-04-12 20:57:17 +02:00
Petr Mrázek
382ae78a0b Fix NagUtils and hack GroupView to work 2015-04-12 20:57:17 +02:00
Petr Mrázek
aa70ed2244 SCRATCH move icons over to Env, instance proxy model to gui 2015-04-12 20:57:16 +02:00
Petr Mrázek
154d19bb74 SCRATCH eliminate InstanceFactory 2015-04-12 20:57:16 +02:00
Petr Mrázek
c088d3bef0 GH-881 Include a top-level directory in exported instances 2015-04-12 20:50:45 +02:00
Petr Mrázek
6775e3e72b NOISSUE Improve new instance dialog
Better layout, showing more of the modpack URL
Fixed logic for enabling OK button
2015-04-11 12:30:18 +02:00
Petr Mrázek
8b4e22bbb8 NOISSUE Move FTB logic out of generic code 2015-04-04 15:46:15 +02:00
Petr Mrázek
c7b39fe116 NOISSUE Remove special FTB logic from generic version patch code 2015-04-04 02:01:52 +02:00
Petr Mrázek
865b200571 GH-856 add profile strategy for FTB packs 2015-04-03 11:55:16 +02:00
Petr Mrázek
dc84ac3682 NOISSUE make slightly more compatible with current unstable
Recognize MinecraftVersion as IntendedVersion
2015-04-02 22:14:54 +02:00
Petr Mrázek
695bfd5f7c NOISSUE insert blatant self-promotion 2015-04-02 21:56:25 +02:00
Petr Mrázek
5ff2681da6 NOISSUE use QSaveFile for saving patch order 2015-04-02 21:56:25 +02:00
Petr Mrázek
5359f4499a NOISSUE remove obsolete EnabledItemFilter model 2015-04-02 20:22:52 +02:00
Petr Mrázek
04b45f3629 NOISSUE remove obsolete LWJGL selection dialog 2015-04-02 20:13:26 +02:00
Petr Mrázek
9249768db5 NOISSUE Make tests no longer use the MultiMC object
They do not require the application part anymore
2015-04-02 11:30:38 +02:00
Petr Mrázek
6f3aa65bd6 NOISSUE Split MultiMC app object into MultiMC and Env 2015-04-02 11:30:24 +02:00
Petr Mrázek
e508728246 NOISSUE remove obsolete assets migration task 2015-04-02 00:37:52 +02:00
Petr Mrázek
360ec557b2 NOISSUE remove notification checker form application object 2015-04-02 00:14:06 +02:00
Petr Mrázek
7334b8e520 NOISSUE remove status checker from application object 2015-04-02 00:14:06 +02:00
Petr Mrázek
791221e923 NOISSUE Refactors and moving of things 2015-04-02 00:14:06 +02:00
Petr Mrázek
593111b144 GH-813 Add 'mcedit2.exe' to the list of things the MCEdit tool looks for 2015-04-01 22:43:18 +02:00
Petr Mrázek
3b6574181e GH-853 evict asset index files from cache when they don't parse 2015-04-01 00:23:17 +02:00
Petr Mrázek
eae544f0eb GH-841 fix for modpack downloads on windows 2015-03-27 02:03:14 +01:00
Petr Mrázek
2eb3ec39bf NOISSUE tweak version display in the application to reflect recent changes 2015-03-24 22:40:49 +01:00
Petr Mrázek
a27c341781 SCRATCH more 2015-03-16 22:33:41 +01:00
Petr Mrázek
02f82e9694 NOISSUE Z_PREFIX for QuaZip 2015-03-16 21:56:27 +01:00
Petr Mrázek
405833bbbe NOISSUE eliminate qt5_use_modules from build 2015-03-16 08:43:00 +01:00
Petr Mrázek
8be865fb2a SCRATCH more experiments 2015-03-16 02:11:02 +01:00
Petr Mrázek
568a79e7b1 SCRATCH more quazip experiments 2015-03-16 01:53:19 +01:00
Petr Mrázek
06c9a64a87 NOISSUE fix bad export in iconfix 2015-03-16 00:27:06 +01:00
Petr Mrázek
ceec70e014 GH-796 Icon theme loading workaround
Replacing the Qt machinery with other Qt machinery under our control
2015-03-01 22:20:57 +01:00
Jan Dalheimer
ef34cafe17 Fix QuaZIP target dependency 2015-02-21 21:23:23 +01:00
Petr Mrázek
93b247592d NOISSUE actually make INI file saving work again... oops :P 2015-02-21 08:59:38 +01:00
Petr Mrázek
b8a8b09796 NOISSUE make sure saving config files is atomic 2015-02-21 00:21:19 +01:00
Jan Dalheimer
a53f8d506e GH-366: Plain and simple modpack export/import/download
Also removed the in-source QuaZIP in favour of upstream version
2015-02-19 21:04:27 +01:00
Jan Dalheimer
f9a17eb9de Fix the updater on OS X 2015-02-16 22:05:39 +01:00
Greenphlem
c6c5134398 Change copyright dates to 2015 2015-02-06 01:18:02 +01:00
Petr Mrázek
49ff31f131 NOISSUE do not use proxy by default 2015-02-06 00:41:36 +01:00
Petr Mrázek
e25e076d2e NOISSUE ignore PermGen warnings in log 2015-02-02 21:42:01 +01:00
Greenphlem
125ddc5f93 Change default PermGen from 64 to 128 mb
This will help users who run mods. Too many issues have been made over the lack of more permgen being assigned.
2015-02-02 00:42:36 -08:00
Petr Mrázek
d03dbea1b7 NOISSUE change icon themes without restart 2015-01-28 20:56:23 +01:00
Petr Mrázek
c6427caa9e GH-734: block more java env variable holes. 2015-01-17 23:05:34 +01:00
Petr Mrázek
0be0e822e4 GH-720 Add timestamps (since mmc start) to log 2015-01-12 22:18:26 +01:00
Petr Mrázek
55e5322fbe GH-721 Log errors in asset and MMC update downloads. 2015-01-11 22:30:54 +01:00
Petr Mrázek
0886786bb5 GH-721 Redo internal NetJob implementation.
NetJob is now using its own task queue and does not start more than 6 actions at the same time
2015-01-11 22:04:31 +01:00
Petr Mrázek
1151037f96 GH-719 Fix paste upload encoding and do not try to upload over limit 2015-01-11 03:08:41 +01:00
robotbrain
acb3346409 NOISSUE Update and sort modlist after adding mods 2015-01-06 21:23:02 +01:00
Alex Sieberer
85756d0e78 Remove IRC in favor of ElrosGem 2014-12-29 12:38:02 -05:00
Alex Sieberer
5c599d8658 Add translation badge to README 2014-12-29 10:44:23 -05:00
Petr Mrázek
4db31aacd6 NOISSUE Treat any forge downloads <= 4KB as stale. 2014-12-27 22:45:49 +01:00
Petr Mrázek
a30a9559c7 NOISSUE Fix jar mods for OnesSix 2014-12-27 20:50:33 +01:00
Petr Mrázek
01f44e0f39 NOISSUE Set minimum Minecraft window size to 1x1 2014-12-12 21:52:24 +01:00
Petr Mrázek
bbcd44a657 NOISSUE Always follow redirects for NetAction based downloads 2014-12-12 00:44:55 +01:00
Petr Mrázek
a060d79c12 GH-631, GH-658 Implement yellow status icon, refresh status icons in themes. 2014-12-07 22:55:29 +01:00
Petr Mrázek
28140b1db6 NOISSUE Change default font on Windows to Courier size 10 2014-12-03 21:48:27 +01:00
Petr Mrázek
5af1f0cf50 GH-640 Make legacy forge downloads follow redirects 2014-11-29 13:03:20 +01:00
Petr Mrázek
7778c84121 NOISSUE No more symlinks for LWJGL. 2014-11-29 13:03:08 +01:00
Petr Mrázek
4ae0d8e0af NOISSUE Update changelog for version 0.4.5 2014-11-21 11:20:18 +01:00
Petr Mrázek
9f14b319df NOISSUE Remove obsolete ReleaseCandidate logic from the build system 2014-11-21 10:53:59 +01:00
Petr Mrázek
a9af17eebb NOISSUE Remove remnant of crash handler 2014-11-21 10:34:38 +01:00
Petr Mrázek
d3c2230a24 NOISSUE fix OSX version number and (C) year 2014-11-20 19:07:10 +01:00
Petr Mrázek
f8bd687994 NOISSUE Fix console window hiding 2014-11-17 22:43:10 +01:00
Petr Mrázek
fa8d3c564d GH-618 Add updated light and dark simple icons 2014-11-17 22:10:58 +01:00
Petr Mrázek
80d3f734c6 GH-619 Add libraries missing in copies of 1.7.10 FTB packs 2014-11-17 22:01:32 +01:00
Petr Mrázek
9ad9826d08 GH-608 Re-detect java when the binary goes missing 2014-11-16 12:56:33 +01:00
Petr Mrázek
6a09fd2898 Set versions back to develop 2014-11-16 04:04:24 +01:00
Petr Mrázek
03a25c9a5d Do not do symlink hackery for java < 8 2014-11-16 04:04:24 +01:00
Petr Mrázek
83b90d8bfb Fix typo in changelog 2014-11-16 02:12:52 +01:00
Petr Mrázek
1d5c09051c VersionSelectDialog is for SELECTING versions.
Not blinking in and out of existence. That is not the job of a version SELECTION dialog.
2014-11-16 01:56:07 +01:00
Petr Mrázek
940f160091 Set version to 0.4.4 for release 2014-11-15 23:37:12 +01:00
Petr Mrázek
3d2de6add8 Add Batch icon set to the about dialog. 2014-11-15 23:37:12 +01:00
Petr Mrázek
b7c4284019 Remove crash handler 2014-11-15 23:35:24 +01:00
Jan Dalheimer
2315bf7bc5 Fix a OS X build error (missing a defined()) 2014-11-15 19:45:49 +01:00
Petr Mrázek
41bd2a6634 Add console font size setting and a preview\
Also moves the console settings from the minecraft page.
2014-11-15 19:45:49 +01:00
Petr Mrázek
5711b1be95 'Fix' instance group sorting 2014-11-10 08:51:24 +01:00
Petr Mrázek
90eea4f05c More pixels. 2014-11-10 07:37:30 +01:00
Petr Mrázek
cbb1e0ea45 HACK for scalable icons in QListView on Windows 2014-11-10 07:33:49 +01:00
Petr Mrázek
ec4805cce8 Default console font tweaks
* Lucida Console on Windows
* Menlo on OSX
* Monospace (resolved to whatever Monospace means) on linux
* Added ability to select proportional fonts in settings
2014-11-10 06:26:17 +01:00
Petr Mrázek
a2ac9c5a3a Fix coloring and processing of console output
* Removing \r
* Adding missing break statements for coloring
2014-11-10 05:10:58 +01:00
Petr Mrázek
551e101146 Follow redirects for skins 2014-11-10 05:10:23 +01:00
Petr Mrázek
1dd8978f8c Do not use QFont without Xorg 2014-11-09 20:49:23 +01:00
Petr Mrázek
24a0635b62 Allow changing the console font family 2014-11-09 19:48:35 +01:00
Petr Mrázek
2e9284951c Improve log formatting
* Updated log level detection for current Minecraft versions
* Better formatting: using a monospaced font and raw text instead of HTML (fixes #111)
2014-11-09 14:53:08 +01:00
Jan Dalheimer
f9a7c1cf21 Fix #208: Allow double clicking an account in the account selection dialog 2014-11-09 02:50:30 +01:00
Petr Mrázek
28eebc09fc Give paste upload a nice status message
Fixes #364
2014-11-09 02:09:01 +01:00
Petr Mrázek
cc19159f4d Document pre/post commands better
Fixes #398
2014-11-09 01:20:09 +01:00
Petr Mrázek
587fedce84 Implement search and logging pause in minecraft log
Fixes #47
2014-11-09 00:59:22 +01:00
Petr Mrázek
fa42a27525 Workaround for QTBUG-42500
Process has to have LD_LIBRARY_PATH set to empty string to not inherit it by default
2014-11-09 00:19:54 +01:00
Petr Mrázek
84723add8f Fix #537
Core Mods help now goes to Loader Mods
Fixed Minecraft Log -> Minecraft Logs problem
2014-11-08 21:47:51 +01:00
Petr Mrázek
992ba0c3f8 Implement #545
* Instance group can be selected when creating and copying instances
* Original group is pre-selected when copying
* Last used group is pre-selected when creating new instances
2014-11-08 21:17:28 +01:00
Jan Dalheimer
7d1dd2a32f Fix #474: Bad jvisualvm check 2014-11-02 20:29:09 +01:00
Jan Dalheimer
add23a9a0b Fix #220: Use .exe suffix on windows for jprofiler 2014-11-02 20:16:29 +01:00
Jan Dalheimer
d9b2f0ed42 Fix another bunch of copyright years, including fixing #397 2014-11-02 20:08:26 +01:00
Jan Dalheimer
9217d9263e Update copyright year (finally...) 2014-11-02 19:49:58 +01:00
Jan Dalheimer
a3a5afe119 Fix #231: Enable translation for more strings 2014-11-02 19:25:11 +01:00
Petr Mrázek
7fb6cafe9e Add LWJGL 2.9.2-nightly-20140822 2014-11-02 12:47:39 +01:00
Petr Mrázek
c1b6f42551 Also block other java-related env vars, for good measure
"JAVA_ARGS"
"CLASSPATH"
"CONFIGPATH"
"JAVA_HOME"
"JRE_HOME"
2014-11-02 11:13:18 +01:00
Petr Mrázek
3d1426b559 Filter env variables passed to Minecraft
QT_* and LD_* are not passed through
env variables are logged on launch
2014-11-01 14:11:20 +01:00
Petr Mrázek
095640ed01 Fix Java 8 issues with LWJGL native libs on OSX? 2014-11-01 10:39:32 +01:00
Petr Mrázek
9e8a74cc89 Fix some issues in the newly added themes 2014-10-27 00:41:40 +01:00
Petr Mrázek
547f6f77d0 Add iOS and OSX icon themes by pe 2014-10-27 00:15:52 +01:00
Petr Mrázek
8f7aec032b Add dark, light, blue and colored theme from pe.
Replaces the old dark and light themes
2014-10-26 23:44:20 +01:00
TakSuyu
92560bf0cd Merge pull request #561 from max96at/patch-1
One line change that was already attempted. Easy enough to revert if in the off chance it regresses.
2014-10-19 10:28:05 -07:00
max96at
2dd2b7a291 Finally with Qt5.3 this should work. :D 2014-10-19 18:19:37 +02:00
robotbrain
b4122cff89 Fix translation downloading 2014-10-05 11:37:49 -04:00
Petr Mrázek
43b9706b5c Fix translations path for the meta cache 2014-10-01 00:24:56 +02:00
robotbrain
bbdf5c1395 Translation downloading! 2014-09-30 16:22:39 -04:00
Petr Mrázek
382e167d64 Do not choke on large files when showing them in the 'other logs' page. 2014-09-21 00:05:48 +02:00
Sky
de2bb0c6f3 README tweaks 2014-09-15 15:53:20 +01:00
Petr Mrázek
2083ac8cc1 Add a dot. 2014-09-14 11:31:43 +02:00
Petr Mrázek
16955c6188 Delete old translations 2014-09-09 07:57:27 +02:00
Petr Mrázek
b00e63dbe8 More sync from quickmods
Also a small VersionSelectDialog refactor
2014-09-06 21:01:23 +02:00
Petr Mrázek
20cb97a35a Sync from quickmods 2014-09-06 19:03:05 +02:00
Petr Mrázek
36efcf8d3c Back to develop 2014-09-06 13:05:17 +02:00
Petr Mrázek
a59e83cd12 Update changelog
Conflicts:
	changelog.md
2014-08-21 00:48:14 +02:00
Petr Mrázek
febf3645d0 Fix version file problems, fix console window not being destroyed 2014-08-21 00:32:32 +02:00
Petr Mrázek
01ca3d6aad Add some logging to places where version updates might not trigger. 2014-08-21 00:32:32 +02:00
Mrazek, Petr
6deb41e32d Travis build: take negative test results as build errors 2014-08-21 00:32:32 +02:00
Petr Mrázek
74f7bd9a1c Add changelog pieces, version 2014-08-16 11:33:01 +02:00
Petr Mrázek
7d8c5ac9b5 Revert "Do not include jutils in LWJGL versions."
This reverts commit 376467740b.
2014-08-15 00:02:44 +02:00
Petr Mrázek
d172daf3a9 Include QtXml, we use it.
Fixes KDevelop semantic analysis magic.
2014-08-15 00:01:55 +02:00
Petr Mrázek
56b16320dd Print the Minecraft window size on launch. 2014-08-13 04:44:19 +02:00
Petr Mrázek
376467740b Do not include jutils in LWJGL versions. 2014-08-13 04:44:01 +02:00
Petr Mrázek
814d5d3315 Properly detect if the instance is vanilla and don't treat it as custom. 2014-08-11 02:17:48 +02:00
Petr Mrázek
fd6706391b Increase the java checker timeout from 5s to 15s 2014-08-10 15:13:35 +02:00
Jan Dalheimer
21597da33d Merge branch 'Loetkolben-pr_feature_warnProblematicInstPath' into develop
Closes #400
2014-07-30 21:45:12 +02:00
Loetkolben
c0254d9a75 Show a warning if the instance path contains a '!'
The checks and warnings happen the time MMC loads (via QLOG_INFO), the time the GUI starts (via a dialog) and when the user changes the instance path via the settings window.
2014-07-30 21:40:18 +02:00
Mrazek, Petr
151fbde8d0 Fix loading of Minecraft versions from FTB packs 2014-07-30 06:25:17 -04:00
Petr Mrázek
03b13b0b3f Rearrange RawLibrary and OneSixLibrary heavily.
Fix #396
2014-07-26 23:00:35 +02:00
Petr Mrázek
9b82c87c92 Tweak windows rc file description (Minecraft Launcher -> MultiMC Launcher) 2014-07-23 22:54:03 +02:00
Petr Mrázek
75cb329f17 Check if the java binary can be found before launch.
Fix #386
2014-07-23 00:16:31 +02:00
Petr Mrázek
bef869ff76 Add a note about MultiMC not working in system folders to build instructions.
Fix #185
2014-07-22 23:29:10 +02:00
Petr Mrázek
0a64579401 Merge branch 'pullrequest2' of https://github.com/p-schneider/MultiMC5 into develop 2014-07-22 23:21:17 +02:00
Petr Mrázek
d71697efb3 Do not deploy debug version of the svg icon lib in release builds. 2014-07-22 23:19:53 +02:00
Mrazek, Petr
e5b393318f Include the SVG icon engine. 2014-07-22 12:27:00 +02:00
Petr Mrázek
1ed90293ac Unify look of all pages.
Now they have a QTabWidget with no tabs as a background.
2014-07-21 00:10:13 +02:00
Petr Mrázek
bc05ad30aa Rework the settings dialog. Rework all of it. Thoroughly.
Also introduces the ColumnResizer from:
https://github.com/agateau/columnresizer/
2014-07-20 23:47:46 +02:00
Jan Dalheimer
e178284172 Merge global settings and accounts into a pagedialog
Also split external tools into it's own page
2014-07-20 15:01:02 +02:00
Petr Mrázek
c91adfb3d1 Merge branch 'master' into develop
Conflicts:
	CMakeLists.txt
	changelog.md
2014-07-20 14:23:14 +02:00
Petr Mrázek
77d9360d25 Bump version and add to changelog. 2014-07-20 13:01:21 +02:00
Petr Mrázek
3403553d44 Fix LWJGL version list loading.
SourceForge has changed its API again.
2014-07-20 12:59:44 +02:00
Petr Mrázek
c767707c95 Make forge work.
Using classifiers FTW.
2014-07-19 23:16:02 +02:00
p-schneider
66fa241257 Show a warning in the log if a library is missing 2014-07-19 15:46:55 +02:00
Petr Mrázek
8a56ab6780 Implement gradle spec reader/writer 2014-07-16 02:03:52 +02:00
Petr Mrázek
71575a5022 Fix #367 2014-07-14 20:48:51 +02:00
Petr Mrázek
222c26f9cf Bump dev version 2014-07-14 02:43:10 +02:00
Petr Mrázek
ce68efa174 Change one small thing
Bunnies!
2014-07-14 01:41:18 +02:00
Petr Mrázek
8bb906bbd7 Fix last minute derps
* Changelog formatting
* Update dialog popping up on start even when it shouldn't
2014-07-14 01:11:52 +02:00
Petr Mrázek
e7f67a73b3 Update changelog 2014-07-14 00:58:19 +02:00
Petr Mrázek
3821569363 Show changelog even when there are no new updates available. 2014-07-14 00:57:54 +02:00
Petr Mrázek
d8d6f5929b Fix #361 2014-07-13 15:26:26 +02:00
Petr Mrázek
977cc1cfbb Mess around with log UI. Herp Derp. 2014-07-13 01:49:46 +02:00
Jan Dalheimer
4c0dc51110 Finish of the OtherLogs page, and (re)format page related files 2014-07-12 23:31:06 +02:00
Jan Dalheimer
5c43842359 Add a new page that can show all sorts of logs 2014-07-12 23:31:05 +02:00
Petr Mrázek
aba1f89e2a Add home/end and fix navigation with collapsed groups (they are skipped) 2014-07-12 23:27:32 +02:00
Petr Mrázek
cc6968e9a3 Group view gets keyboard navigation back.
And a bunch of fixes.
2014-07-12 21:13:23 +02:00
Petr Mrázek
d570037331 Cache group view geometry -- speed up instance view by caching sizes of stuff 2014-07-12 12:49:07 +02:00
Petr Mrázek
6a8984a21d Fix #356 2014-07-11 01:51:07 +02:00
Petr Mrázek
0d4046de39 Add clear and copy buttons to the log page. 2014-07-11 01:50:36 +02:00
Petr Mrázek
24698fe85f Fix #355 2014-07-10 21:13:17 +02:00
Petr Mrázek
40c238442f Fix #354, make jar mods and patch files in general more resilient. 2014-07-10 01:26:45 +02:00
Petr Mrázek
ff06489fed Do not show core mods page for minecraft newer than 1.5.2. 2014-07-10 00:47:08 +02:00
Petr Mrázek
08fbfa7434 Make the auth timeout longer (30s) 2014-07-09 19:53:35 +02:00
Petr Mrázek
6f75009a80 Show update channel in the update dialog, actually show changelog for the selected update channel. 2014-07-09 19:48:46 +02:00
Petr Mrázek
7c51cc475b Better regexp for links 2014-07-09 01:17:59 +02:00
Petr Mrázek
fc911add58 Show changelog in the update dialog. 2014-07-09 00:49:37 +02:00
Petr Mrázek
6349800f07 Fix mod list sorting predicate, convert the changelog to markdown and reverse it. 2014-07-08 23:05:33 +02:00
Petr Mrázek
9b3ae29a36 Make the FTB packs a set instead of a list. 2014-07-08 08:42:48 +02:00
Petr Mrázek
19278c853b Merge branch 'master' into develop
Conflicts:
	CMakeLists.txt
	changelog.yaml
	logic/forge/ForgeInstaller.cpp
2014-07-08 01:10:45 +02:00
Petr Mrázek
b3cf19190f Bump version, update the changelog 2014-07-08 01:03:18 +02:00
Petr Mrázek
842328df8e Update the forge hacks.
Conflicts:
	logic/ForgeInstaller.cpp
2014-07-08 01:00:52 +02:00
Petr Mrázek
f72a38b06c Update the forge hacks. 2014-07-07 08:40:03 +02:00
Petr Mrázek
d934e64831 Tweak the response to successful uploads (screenshots, log pastes)
The url will now be shown as link, put into the clipboard AND opened in a browser.
At the same time. To avoid losing the URL.
2014-07-07 00:02:04 +02:00
Petr Mrázek
15775bd30a One more liteloader fix 2014-07-06 23:23:48 +02:00
Petr Mrázek
cc499488db Fix liteloader, some cleanups. 2014-07-06 11:15:15 +02:00
Petr Mrázek
a218d7b7f6 Improve screenshot view/model.
Changes to screenshots are tracked.
Thumbnails are generated in a thread pool.
2014-07-05 13:27:32 +02:00
Petr Mrázek
b5d6f50fb1 Make paste.ee logs expire after a month 2014-07-03 20:29:44 +02:00
Petr Mrázek
252f375454 fix the instance toolbar 2014-07-03 08:16:02 +02:00
Petr Mrázek
a75e64dd18 disable that upgrade page 2014-07-03 02:26:00 +02:00
Petr Mrázek
18a342ef14 Move settings lib into the main code, fixing error logging in it. 2014-07-01 01:48:09 +02:00
Petr Mrázek
8b86306d48 Handle a bunch more clang warnings 2014-07-01 01:23:49 +02:00
Taeyeon Mori
dd0752e69f [Clang Warnings] Silence Pack200 unused variable variable warnings
They're caused by a big define-everything-you-ever-need macro
2014-06-30 23:53:42 +02:00
Taeyeon Mori
d166340097 [Clang Warnings] Add empty default clause 2014-06-30 23:53:42 +02:00
Taeyeon Mori
eb5699c835 [Clang Warnings] Fix char* cast from string literal in Tests 2014-06-30 23:53:41 +02:00
Taeyeon Mori
b9fb718822 [Clang Warnings] Remove unused variables 2014-06-30 23:53:41 +02:00
Taeyeon Mori
1f498266d8 Fix bug in OneSixInstance's modification detection.
OneSixInstance would report all instances as custom because of a typo.
Thanks Clang :)
2014-06-30 23:51:40 +02:00
Petr Mrázek
e241c3625c Merge branch 'feature_theme_support' into develop
Conflicts:
	main.cpp
2014-06-30 22:22:09 +02:00
Petr Mrázek
421a46e3d3 Redo the console window. Log is now a page. Console window has relevant pages.
Dirty fix for screenshot thumbnail generation. Needs more QTimer.
2014-06-30 02:02:57 +02:00
Petr Mrázek
5179aed3a0 Separate page dialog into a page container and a dialog. 2014-06-29 19:59:08 +02:00
Petr Mrázek
77de2d1e54 Hack. 2014-06-29 13:11:13 +02:00
Petr Mrázek
e422eff959 Add screenshots icon 2014-06-29 11:27:24 +02:00
Petr Mrázek
828254dd11 ~_~_~_~ 2014-06-28 17:15:53 +02:00
Petr Mrázek
1f3a840f3c Derp^2!! 2014-06-28 17:11:50 +02:00
Petr Mrázek
56d91fda3a Derp! 2014-06-28 17:09:23 +02:00
Petr Mrázek
e8731c5d01 Turn screenshot management into a page. 2014-06-28 17:07:08 +02:00
Petr Mrázek
30b1f5e5cf Merge branch 'feature/fix_intel' into develop
Conflicts:
	CMakeLists.txt
	changelog.yaml
	gui/MainWindow.cpp
2014-06-28 08:49:18 +02:00
Petr Mrázek
7f4073840a Bump version, fix typo, update the changelog. 2014-06-28 00:21:36 +02:00
Petr Mrázek
f0d850e1ee Fix issues with intel drivers. Forced java re-detection on Windows. 2014-06-28 00:05:00 +02:00
Petr Mrázek
d6e5c472b5 Update changelog and bump version to 0.4.0 (no tag yet, not final) 2014-06-26 21:49:05 +02:00
Petr Mrázek
c31dbf13cb Bump version to 0.3.7, update changelog 2014-06-26 08:41:50 +02:00
Petr Mrázek
affb2fdd6c Merge branch 'feature/forge_pre4_fix' into develop
Conflicts:
	logic/forge/ForgeVersionList.cpp
	logic/forge/ForgeVersionList.h
2014-06-25 00:54:00 +02:00
Petr Mrázek
c081cd8021 Fix forge prerelease mess.
This adds a HACK that assumes Mojang will be consistent with their versioning. What could possibly go wrong?
2014-06-25 00:36:42 +02:00
Petr Mrázek
1194ec9a8e No more disabling of actions in the instance toolbar. It makes no sense. 2014-06-20 01:24:32 +02:00
Petr Mrázek
d911c9908c Replace notes dialog with a page. 2014-06-18 01:15:01 +02:00
Petr Mrázek
702e00e059 Fix #313 - used texture pack list instead of resource pack list 2014-06-11 19:35:21 +02:00
Petr Mrázek
478815dae6 Tweak version page: select first item by default, allow changing version of 'version.json'. 2014-06-10 08:39:11 +02:00
Petr Mrázek
c08bfce5f2 More github wiki friendly help page names 2014-06-10 02:05:31 +02:00
Petr Mrázek
9ec6deea84 Add close button to page dialog. Add help button to page dialog.
Smile.
2014-06-10 00:46:05 +02:00
Petr Mrázek
0bccc94471 Cleanup - QFileInfo derp and unused variables 2014-06-09 01:57:10 +02:00
Petr Mrázek
a0a805735b Remove margins from settings page. 2014-06-09 01:38:32 +02:00
Petr Mrázek
171325d427 Instance settings moved to a page. 2014-06-09 01:38:31 +02:00
Petr Mrázek
be73eb3322 Version revert logic improvements, colorful icons for mod lists and resource pack list.
Icons are from Oxygen.
2014-06-09 01:38:31 +02:00
Petr Mrázek
bf7b070508 Show texture/resource packs when appropriate. 2014-06-09 01:38:31 +02:00
Petr Mrázek
223a7aba7b Hardcode LWJGL 2.9.1 for OneSix, only allow chancging Minecraft versions for now. 2014-06-09 01:38:31 +02:00
Petr Mrázek
84ae67fff5 Page dialog for legacy instances. 2014-06-09 01:38:31 +02:00
Petr Mrázek
694067c603 Only enable move buttons for version patches that can move. HACK HACK 2014-06-09 01:38:31 +02:00
Petr Mrázek
6b3d1101cb Tweaks to page dialog and version page. 2014-06-09 01:38:31 +02:00
Petr Mrázek
f485885757 Add and implement pages and page dialog. 2014-06-09 01:38:31 +02:00
Petr Mrázek
48d3052ac1 New, simpler and versioned format for the patch load order. 2014-06-09 01:38:31 +02:00
Petr Mrázek
e118b1f990 Implement adding jar mods, break saving library order. 2014-06-09 01:38:31 +02:00
Petr Mrázek
55a0d110b6 Lock down the version cache. Just enough to make it annoying to corrupt the files. 2014-06-09 01:38:31 +02:00
Petr Mrázek
f3900f2966 Reduce startup logging verbosity 2014-06-09 01:38:31 +02:00
Petr Mrázek
db8b47e7f6 Break FTB. Yep. It has to be done better. 2014-06-09 01:38:30 +02:00
Petr Mrázek
439e17b149 Add back legacy mod edit, add checksums for all legacy jars 2014-06-09 01:38:30 +02:00
Petr Mrázek
8c71a5d61f Move instance settings back to the main window. 2014-06-09 01:38:30 +02:00
Petr Mrázek
6d34411f54 Fix last instance remaining selected when deleted 2014-06-09 01:38:30 +02:00
Petr Mrázek
68ef451be5 Small fixes, including release dates of some legacy versions 2014-06-09 01:38:30 +02:00
Petr Mrázek
e993adaf44 Disable window titles and isons again, windows build fixes 2014-06-09 01:38:30 +02:00
Petr Mrázek
ad1f2c530c Use window icons and titles in 1.6+ 2014-06-09 01:38:30 +02:00
Petr Mrázek
69c3e7111f Make 1.6+ work with new instance format. 2014-06-09 01:38:30 +02:00
Petr Mrázek
92abe4c603 All of the broken legacy things work. 2014-06-09 01:38:30 +02:00
Petr Mrázek
9860d5ee12 Introducing VersionPatch base class for version files and minecraft versions 2014-06-09 01:38:30 +02:00
Petr Mrázek
8a3a0f5a52 Reorganize logic code. 2014-06-09 01:38:30 +02:00
Petr Mrázek
69a9ca39ad Add builtin Minecraft versions for legacy 2014-06-09 01:38:29 +02:00
Petr Mrázek
825d31bf1a Set the window params inside the launcher part, depending on launcher type.
Also create/change the new internal version files.
2014-06-09 01:38:29 +02:00
Petr Mrázek
2590c6be15 Fix launcher part for legacy in onesix. 2014-06-09 01:38:29 +02:00
Petr Mrázek
4c3bd416c6 Much change, very jarmod. 2014-06-09 01:38:29 +02:00
Petr Mrázek
aade36860c Begin the transformation!
Nuke all the things.
2014-06-09 01:38:29 +02:00
Petr Mrázek
3a0cdf2d3d Tagging 0.3.6 2014-06-03 01:44:19 +02:00
Petr Mrázek
d2b2d55aa9 New flat icon themes from pexner
Squash and rework of commits from robotbrain
2014-05-25 04:01:38 +02:00
Petr Mrázek
eb9661370b Enable SVG icons 2014-05-25 03:38:45 +02:00
Jan Dalheimer
e1f542b5b0 Still trying to fix FTB 2014-05-23 18:41:22 +02:00
Jan Dalheimer
15920aa9d0 Attempt at fixing FTB 2014-05-23 18:19:20 +02:00
Jan Dalheimer
e17364de6b Fix FTB? 2014-05-23 16:39:14 +02:00
Jan Dalheimer
b911a3834c More FTB debug stuff 2014-05-23 16:16:44 +02:00
Jan Dalheimer
94c2c363b2 Some more FTB related debug info 2014-05-23 15:46:12 +02:00
Petr Mrázek
df82d8fadb QDir::exists is not static in Qt 5.1.1 2014-05-22 09:12:04 +02:00
Petr Mrázek
851a77d5bb Merge pull request #275 from MultiMC/feature_ftb_new_paths
Fix FTB paths on windows
2014-05-22 09:04:03 +02:00
Jan Dalheimer
41caf7976d FTB paths changed on windows. Fixes #255 2014-05-22 07:49:45 +02:00
Jan Dalheimer
fc3c0b0971 Merge branch 'feature_crashreport' into develop 2014-05-21 15:57:34 +02:00
Petr Mrázek
94cb5c7d77 Restore manage screenshots in main window. 2014-05-18 23:12:35 +02:00
Petr Mrázek
911ac19a56 Screenshot upload dialog(s) now have the console window as parent. 2014-05-18 19:07:01 +02:00
Petr Mrázek
7f2a16917e Add static data path for ... static data. Like translations. Move translations there. 2014-05-17 18:21:32 +02:00
Petr Mrázek
8a8c4193e6 Finish status pills. 2014-05-17 16:23:48 +02:00
Petr Mrázek
927217c7f0 Status pills. This doesn't build yet. 2014-05-15 23:20:38 +02:00
Petr Mrázek
a6a5241e12 Bump version to 0.3.5 2014-05-15 22:48:00 +02:00
Forkk
e6ca58a89e Add a missing letter 2014-05-10 15:10:24 -05:00
Forkk
aefa73ad11 Fix stupid tabs.
Thanks, QtCreator... ._.
2014-05-10 14:56:44 -05:00
Andrew
4f6cd65c13 Remove unused function 2014-05-10 14:19:13 -05:00
Andrew
5099964c67 Implement backtraces on Windows.
Much !!FUN!! was had
2014-05-10 14:16:27 -05:00
Andrew
9e80ddb040 Implement crash report system on Windows. 2014-05-09 20:08:07 -05:00
Forkk
489cb4dbf5 Change dump file extension 2014-05-09 18:21:15 -05:00
Forkk
e3b9b30302 Remove some unnecessary dummy functions. 2014-05-09 17:36:53 -05:00
Forkk
93ae21abfc Implement crash handling on Linux
This will allow us to generate crash dumps and have users report
crashes.
2014-05-09 17:33:32 -05:00
Petr Mrázek
cf616efb5d Fix for #257 2014-05-08 19:00:48 +02:00
Petr Mrázek
0902fd5bec Fix version select dialog filtering 2014-05-04 13:20:42 +02:00
Petr Mrázek
de48f102bd Merge pull request #248 from MultiMC/feature_fix_ftb_lib
Fix FTB local libraries bug
2014-05-03 15:47:57 +02:00
Jan Dalheimer
0f3d88cb14 Fix FTB local libraries bug 2014-05-03 15:40:46 +02:00
Petr Mrázek
8fda1595f7 Merge branch 'develop' into release-0.3.4 2014-05-03 04:12:38 +02:00
Petr Mrázek
e9c8ca02ba Inherit module path from main build environment in the prerequisites script. 2014-05-02 01:08:03 +02:00
Petr Mrázek
95203df9ca It's a fatal error to not find the dependency checker tool. 2014-05-02 00:52:08 +02:00
Petr Mrázek
27732d66b4 Add a safety net for missing dumpbin.exe 2014-05-02 00:37:29 +02:00
Forkk
b3f717c582 Include ICU in distributed builds. 2014-05-01 13:48:09 -05:00
Forkk
cba22f7ee0 Bump version and update changelog. 2014-05-01 13:10:46 -05:00
Forkk
3d8f6ac640 Merge branch 'feature_credits' into develop 2014-05-01 12:45:55 -05:00
Forkk
605a334057 Show Patreon patrons in the about dialog 2014-05-01 12:43:55 -05:00
Petr Mrázek
5fa36f67b3 Update the icon, again 2014-04-22 21:08:09 +02:00
Petr Mrázek
0cd8ded4d4 Update the OSX icon
Closes #230
2014-04-22 00:53:05 +02:00
Petr Mrázek
9d724e0fe4 Merge remote-tracking branch 'origin/feature_cmake_style' into develop
Conflicts:
	CMakeLists.txt
2014-04-21 23:33:00 +02:00
Petr Mrázek
a9dfe6d7ec Fix quit shortcut connect() call 2014-04-21 21:48:58 +02:00
Petr Mrázek
7de007502c Update FR translation some more. 2014-04-21 21:46:12 +02:00
Petr Mrázek
e955b1c6f9 Merge remote-tracking branch 'origin/feature_new_login_dialog2' into develop 2014-04-21 21:39:02 +02:00
Petr Mrázek
c8f468057e Merge remote-tracking branch 'origin/feature_close_shortcut' into develop 2014-04-21 21:38:24 +02:00
Petr Mrázek
6ded1168b0 Fix french translation. 2014-04-21 21:37:15 +02:00
Taeyeon Mori
adecc53df8 Add a quit shortcut to the main window (#200)
The shortcut is Ctrl+Q on every platform but windows, which doesn have one.
See also: http://qt-project.org/doc/qt-5/qkeysequence.html#details (StandardKey Quit)
2014-04-21 21:37:15 +02:00
Petr Mrázek
c9465e9e86 Merge remote-tracking branch 'origin/feature_raise_console' into develop 2014-04-21 21:25:39 +02:00
Petr Mrázek
f14c1888a9 Merge remote-tracking branch 'origin/feature_french' into develop 2014-04-21 21:24:24 +02:00
Petr Mrázek
ca60784a44 Add proper FML libs URL 2014-04-21 20:41:37 +02:00
Petr Mrázek
565dab24b5 Download and cache FML libs for legacy minecraft versions.
* minor fix for version filtering (1.5 no longer shows forge for 1.5.1 and 1.5.2)
* FML libs are downloaded to mods/minecraftforge/libs and cached
* FML libs are copied to instances which contain FML or forge
2014-04-19 21:24:11 +02:00
Elros
eea347b82c Add french translation from #217
Closes #217
2014-04-19 12:46:23 -04:00
Taeyeon Mori
0b60e50af8 Add a quit shortcut to the main window (#200)
The shortcut is Ctrl+Q on every platform but windows, which doesn have one.
See also: http://qt-project.org/doc/qt-5/qkeysequence.html#details (StandardKey Quit)
2014-04-17 14:49:03 +02:00
Taeyeon Mori
0959aeb046 Make the console window raise itself after minecraft closes (#193)
This needs further testing:
http://stackoverflow.com/questions/6087887/bring-window-to-front-raise-show-activatewindow-dont-work
2014-04-17 14:13:16 +02:00
Jan Dalheimer
89edc3e15e Comments and reformating
[ci skip]
2014-04-16 18:03:48 +02:00
Jan Dalheimer
f67ca674c4 Fix bug 2014-04-16 17:54:07 +02:00
Jan Dalheimer
3ed5b1570b LoginDialog changes 2014-04-16 17:38:26 +02:00
Taeyeon Mori
4674aad125 Create a new login dialog 2014-04-16 16:19:12 +02:00
Petr Mrázek
bf1632e4ed Add to the changelog 2014-04-16 01:05:03 +02:00
Petr Mrázek
b286b93281 Give more feedback for YggdrasilTask network errors. 2014-04-16 00:46:41 +02:00
Sky
632c087483 Put changelog additions under right version (0.3.3) 2014-04-15 23:34:51 +01:00
Sky
318a945d74 Update changelog 2014-04-15 23:31:46 +01:00
Petr Mrázek
b6d7ffab47 Detect and report missing local libraries. 2014-04-13 23:06:28 +02:00
Sky
04b36a3e55 Merge pull request #212 from MultiMC/feature_travis_clang
Get Travis to build GCC and Clang versions on Linux as we consider moving to Clang on Linux in general
2014-04-12 17:30:21 +01:00
Jan Dalheimer
3f2152c14d Let travis build a clang version 2014-04-12 18:11:30 +02:00
Sky
8a6c64ef62 Remove specific OpenSSL version from BUILD.md 2014-04-12 04:40:16 +01:00
Sky
6e42d51283 Merge pull request #211 from Drayshak/develop
Add Patreon button with logo
2014-04-12 02:11:51 +01:00
Sky
86830967b6 Give the Patreon button a logo 2014-04-12 02:05:42 +01:00
Sky
1657313105 Add Patreon button. Needs an icon (used I for now). 2014-04-11 02:59:30 +01:00
Jan Dalheimer
a00fb1e8da Only use tabs for intendention 2014-04-09 15:41:49 +02:00
Petr Mrázek
50d18a06d5 Context menu tweaks
* Add create/copy instance actions to the context menu.
* Context menu for the instance view background.
* Top of the context menu is now a header, fixing the misclick problems.
2014-04-08 00:16:49 +02:00
Jan Dalheimer
3cd2b898e5 Merge remote-tracking branch 'origin/develop' into feature_cmake_style
Conflicts:
	CMakeLists.txt
2014-04-07 17:44:52 +02:00
Petr Mrázek
17d4947b30 Merge remote-tracking branch 'origin/feature_dotcmake' into develop 2014-04-06 20:56:40 +02:00
Jan Dalheimer
dd7b6642a3 Use the same style of CMake files everywhere 2014-04-06 19:43:09 +02:00
Jan Dalheimer
eb246c4fa7 .cmake files to reduce "code" duplicate 2014-04-06 18:12:48 +02:00
Jan Dalheimer
6ef38d0873 Coverity build and upload target. Also GitFunctions. 2014-04-06 18:02:28 +02:00
Petr Mrázek
482ad250a4 Workaround for dirty build folders.
My disgust just turned into barely contained rage :<
2014-04-06 03:59:37 +02:00
Petr Mrázek
f9169654c5 Build fixage for the changed build config 2014-04-06 03:48:59 +02:00
Petr Mrázek
e58e2643ca Merge branch 'patch-1' of https://github.com/max96at/MultiMC5 into develop 2014-04-06 00:41:19 +02:00
Petr Mrázek
42e305bb9d Get rid of long rebuilds because of minor cmake config changes 2014-04-06 00:33:33 +02:00
max96at
8594cc8f6c Fix adding icons to custom icon directories. 2014-04-03 19:28:23 +02:00
Petr Mrázek
ad9d082f57 Do not spam logs too much, bump version and add to changelog. 2014-04-01 23:03:04 +02:00
Petr Mrázek
52ff6a4140 Deny april fools outside of first april. 2014-04-01 22:33:15 +02:00
Petr Mrázek
1ef6ec4178 Fix library replace issue 2014-04-01 21:58:15 +02:00
Petr Mrázek
72bc860983 Fix for invalid prelaunch commands 2014-04-01 00:04:26 +02:00
Petr Mrázek
29b00eab31 Fix FTB-related issues 2014-03-31 00:19:43 +02:00
Petr Mrázek
a3c95d9bcc Add a few default java paths on linux 2014-03-30 21:29:44 +02:00
Petr Mrázek
fbc29b6a06 Fix many memory leaks. 2014-03-30 20:11:41 +02:00
Petr Mrázek
e1e1d99102 Fix java checker crash, some memory leaks 2014-03-30 20:11:41 +02:00
Sky
7cb76788bd Try to read 'authorList' in mcmod.info for authors first, fall back to deprecated 'authors' if nothing is found. 2014-03-30 05:17:46 +01:00
Petr Mrázek
20eb5ac3cc Add mention of the config coding fix to the changelog. 2014-03-29 23:19:21 +01:00
Petr Mrázek
5f4a364955 Setting PermGen to 64 will omit the java param 2014-03-29 22:05:53 +01:00
Petr Mrázek
ff9f9dd629 Merge branch 'develop' of github.com:MultiMC/MultiMC5 into develop 2014-03-29 21:17:37 +01:00
Petr Mrázek
5f7a48a35e Fix issues with badly encoded escape sequences in config files. 2014-03-29 21:16:54 +01:00
Sky
1f677a3325 Tweak changelog 2014-03-29 16:29:38 +00:00
Petr Mrázek
902dc50c87 Merge branch 'release-0.3' into develop 2014-03-29 16:10:09 +01:00
Petr Mrázek
a19aca0648 Update changelog for 0.3 2014-03-29 15:55:19 +01:00
Petr Mrázek
c069147f67 Merge pull request #168 from max96at/patch-1
Add build status to README.md
2014-03-24 19:17:20 +01:00
max96at
64ca8be101 Add build status to README.md 2014-03-24 18:39:27 +01:00
Jan Dalheimer
f521a925be Add a travis config file 2014-03-24 17:23:52 +01:00
Petr Mrázek
9617326cf8 Raise console window when it's open, but hidden behind other windows. 2014-03-24 01:54:18 +01:00
Petr Mrázek
b60fbf87ab Bump version to 0.3.0 2014-03-23 23:25:55 +01:00
Petr Mrázek
0e6bc97bf3 Set permissions on the accounts.json file so other users can't access it. 2014-03-23 19:22:39 +01:00
Petr Mrázek
4a24ea6c38 Make some more error messages translateable. 2014-03-23 19:07:13 +01:00
Petr Mrázek
a01b1707de Actually start the forge install job. 2014-03-20 21:23:05 +01:00
Petr Mrázek
4901985db6 Finalize version on reload. 2014-03-19 23:23:59 +01:00
Petr Mrázek
1705832feb Merge remote-tracking branch 'origin/feature_notif_65449324' into develop 2014-03-19 22:28:04 +01:00
Petr Mrázek
4623c1b34f Merge remote-tracking branch 'origin/feature_fix_timeout' into develop 2014-03-19 22:26:50 +01:00
Petr Mrázek
39d3739442 Merge remote-tracking branch 'origin/feature_json_fixes' into develop 2014-03-19 22:26:25 +01:00
Petr Mrázek
26b485d82f Merge remote-tracking branch 'origin/feature_badges' into develop 2014-03-19 22:25:36 +01:00
Petr Mrázek
919dea0de6 Revert "Better right-click behaviour, context menu on mouse-up instead of mouse down"
This reverts commit 00a945d84b.

NOPE.
2014-03-17 07:48:50 +01:00
Sky
c33e5ca62e Merge pull request #153 from Drayshak/develop
Better right-click behaviour, context menu on mouse-up instead of down, fixes #151
2014-03-16 21:04:36 +00:00
Sky
00a945d84b Better right-click behaviour, context menu on mouse-up instead of mouse down 2014-03-16 20:34:30 +00:00
Jan Dalheimer
55e4cb6fb5 Allow reseting notifications 2014-03-15 14:35:35 +01:00
Jan Dalheimer
4f452d5815 Add a timer for clicking away the notification dialog 2014-03-15 14:18:29 +01:00
Jan Dalheimer
a74f3b553a Remove the timeout for pre/post commands. Fixes #107 2014-03-15 09:02:56 +01:00
Jan Dalheimer
ad9b16bd3d Nicer icons 2014-03-14 22:01:27 +01:00
Jan Dalheimer
42a85def60 Get rid of one reloadInstanceVersion 2014-03-14 21:18:17 +01:00
Jan Dalheimer
e95619fa67 Pull in BaseInstaller related changes from quickmod 2014-03-14 20:48:57 +01:00
Jan Dalheimer
e5b4dee1c0 Move version stuff to the model and reimplement reordering 2014-03-14 19:51:56 +01:00
Petr Mrázek
de2eb3fc54 Fix missing return in ensureDouble() 2014-03-10 20:18:01 +01:00
Jan Dalheimer
fcc5bc2ce0 Merge branch 'develop' into feature_badges
Conflicts:
	logic/OneSixInstance.cpp
2014-03-10 19:24:29 +01:00
Jan Dalheimer
d11f10ea1e Fix a compiling error by adding noexcept 2014-03-10 18:55:54 +01:00
Jan Dalheimer
73fc9c79cf Instance badges. Some easter eggs and one for broken so far. 2014-03-10 17:38:27 +01:00
Petr Mrázek
5328cc7bbe Add missing include for math.h 2014-03-10 00:14:30 +01:00
Petr Mrázek
b77f4eb144 Merge remote-tracking branch 'origin/feature_paste_66994990' into integration_butchery 2014-03-10 00:01:41 +01:00
Petr Mrázek
df89183c10 Merge remote-tracking branch 'origin/fix_ftb_again' into integration_butchery 2014-03-09 23:59:47 +01:00
Petr Mrázek
d18b97ae3d Merge remote-tracking branch 'origin/feature_fix_log' into integration_butchery
Conflicts:
	logic/MinecraftProcess.cpp
2014-03-09 23:59:30 +01:00
Petr Mrázek
7fd56a30bd Merge remote-tracking branch 'origin/feature_commands' into integration_butchery 2014-03-09 23:46:46 +01:00
Petr Mrázek
b2c803a378 Improve reporting of version file errors.x 2014-03-09 23:42:25 +01:00
Petr Mrázek
ffff2cd324 Remove version patch reordering. Remove the main class display from onesix edit mods. 2014-03-09 17:38:42 +01:00
Jan Dalheimer
f1dc456802 Also reload the instance cfg
While this should work, there don't seem to be any places where the signals are listened for, so changes probably will only be available when calling Setting::get
TODO: Fix that ^
2014-03-09 08:43:08 +01:00
Jan Dalheimer
44f21406e9 Some pre/post related stuff
Reload the onesix version config after the commands (addresses https://www.pivotaltracker.com/story/show/60360652)
Add a few more variables and also substitute them in the command (fixes https://www.pivotaltracker.com/story/show/66994828)
2014-03-09 08:18:50 +01:00
robotbrain
91faaa5b59 Fix logging when system language is not en_US. 2014-03-07 19:44:15 -05:00
robotbrain
96ee20072f Add project files I use to gitignore.
Its easier than opening a new pr for it. :P
2014-03-07 10:37:57 -05:00
Jan Dalheimer
0cc682c629 Fix a few paste upload bugs
Fixes https://www.pivotaltracker.com/story/show/66994990
2014-03-07 16:15:38 +01:00
Petr Mrázek
737169d1d3 Merge pull request #134 from MultiMC/feature_groupview
Fix another GroupView bug
2014-03-07 15:59:46 +01:00
Jan Dalheimer
cc1de6a649 Fix another GroupView bug 2014-03-07 15:46:56 +01:00
robotbrain
6e964acde5 Use a constant for the buffer size. 2014-03-05 16:35:35 -05:00
robotbrain
bb6894893d Fix it - it did it even if the op failed. 2014-03-05 16:27:18 -05:00
robotbrain
97ad7d287c Use windows api to prevent encoding problems. 2014-03-05 16:20:45 -05:00
Petr Mrázek
47bc7e5ee3 More refactor. 2014-03-05 01:50:05 +01:00
robotbrain
a4779d32b6 Fix ftb locations on old windows... again. 2014-03-03 17:22:23 -05:00
Petr Mrázek
6b76af116e Merge branch 'develop' into feature_version_json_butchery 2014-03-03 21:57:45 +01:00
Jan Dalheimer
211a72e144 Fix a GroupView crash that was triggered by the FTB tracking 2014-03-03 19:12:48 +01:00
Petr Mrázek
011ea84530 Fix missed version file assignment. 2014-03-03 09:08:32 +01:00
Petr Mrázek
d66f2500a6 No end in sight :< 2014-03-03 01:44:07 +01:00
Petr Mrázek
29cdc9364b More code butchery related to version files. No end in sight. 2014-03-03 01:23:10 +01:00
Petr Mrázek
28ad9befdc Remove a lot of error code and error handling madness. 2014-03-02 19:12:04 +01:00
Petr Mrázek
80d146866c Remove widgets from logic. 2014-03-02 02:17:55 +01:00
Petr Mrázek
5a344a2933 Gather and store liteloader metadata. 2014-03-02 02:08:01 +01:00
Petr Mrázek
053b938beb Get rid of parse flags 2014-03-02 01:51:40 +01:00
Petr Mrázek
7c24bcc834 Reorganize the version-related code. 2014-03-01 23:06:47 +01:00
Petr Mrázek
7dfd6aa051 Remove obsolete OneSixFTBInstanceForge 2014-03-01 18:18:51 +01:00
Jan Dalheimer
00f4f533aa Fix to the way translations are handled. Also updated the german translation with the new strings. 2014-02-25 18:46:50 +01:00
Petr Mrázek
3133bb3ea0 Fix missing includes in litaloader installer. 2014-02-25 02:15:14 +01:00
Petr Mrázek
acff155624 Merge branch 'feature_screenshots' into integration_json_and_tools
Conflicts:
	logic/net/URLConstants.h

Resolve issues with multiple definitions of URL constants by moving them to their own object file.
2014-02-25 01:52:58 +01:00
Petr Mrázek
9d4e840a6e Screenshots: Optimize image loading and memory use, fix list and button layout. 2014-02-25 01:23:33 +01:00
Petr Mrázek
cb5cfe7242 Reorganize all the screenshot files 2014-02-25 00:51:24 +01:00
robotbrain
b1cddb4600 Fix memory leak in system 2014-02-24 17:49:18 -05:00
robotbrain
55e21737dd Deleting screenshots. Needs fixing. 2014-02-24 17:40:05 -05:00
Jan Dalheimer
da33fa4090 Imgur album creation 2014-02-24 11:30:27 +01:00
Jan Dalheimer
a8811a27f7 Working screenshot upload 2014-02-24 10:34:51 +01:00
Jan Dalheimer
226c1bdae5 Screenshot fixes, move some code around, fix some stuff 2014-02-24 09:34:21 +01:00
Petr Mrázek
49dc9695f5 Merge branch 'fix_json_version' into integration_json_and_tools
Conflicts:
	logic/OneSixInstance.cpp
	logic/OneSixVersionBuilder.cpp

Some fixage. Yay for conflicts.
2014-02-24 02:35:01 +01:00
robotbrain
5e33da258c Close to finished. Need to fix the upload part. Viewing works (in grayscale) 2014-02-23 19:48:00 -05:00
Petr Mrázek
f7c97efcf3 Merge branch 'feature_profiling' into integration_json_and_tools 2014-02-24 00:29:13 +01:00
Petr Mrázek
e3d2e5fd74 Merge branch 'fix_ftb' into integration_json_and_tools 2014-02-24 00:28:59 +01:00
robotbrain
4a77524b05 Initial stuff. It doesnt work. 2014-02-23 16:14:24 -05:00
Jan Dalheimer
a354e8bfae Fix MCEdit on OSX 2014-02-21 20:13:12 +01:00
Jan Dalheimer
4883d15262 Copying of FTB instances working again 2014-02-21 19:15:59 +01:00
Jan Dalheimer
f54705e1c5 Don't assume forge for FTB instances. Fix FTB related stuff. 2014-02-21 18:01:06 +01:00
Jan Dalheimer
43881b9cdb Use FTB's libraries/ and versions/ folders for non-copied instances 2014-02-20 17:06:32 +01:00
Jan Dalheimer
7146724607 New, better, liteloader support 2014-02-19 22:34:17 +01:00
Jan Dalheimer
0b56b5efaf Instance flags. Currently used for marking instances as broken. Can later be used for badges. 2014-02-17 20:31:50 +01:00
Jan Dalheimer
4e8be668cb Different error message if it's a launcher version mismatch 2014-02-17 17:46:43 +01:00
Jan Dalheimer
8d0ff99089 Actually remove instances if they fail to load 2014-02-17 17:36:29 +01:00
Jan Dalheimer
549198031d Check if the json version is one we know how to handle
Also some formatting.
2014-02-17 17:19:58 +01:00
Petr Mrázek
16d378687c Fix some external tool related string sin the settings dialog. 2014-02-16 14:53:03 +01:00
Petr Mrázek
dd2d8f48fa Nicer way of selecting tool folders and executables 2014-02-16 14:42:44 +01:00
Jan Dalheimer
e4ecc31e07 Links to the tools 2014-02-16 13:02:59 +01:00
Jan Dalheimer
9c87bc6c4b Restructure 2014-02-16 12:52:35 +01:00
Jan Dalheimer
f26b7dedad Only show folders that really are worlds 2014-02-16 12:08:39 +01:00
Jan Dalheimer
f5273ae2b1 Merge remote-tracking branch 'origin/feature_profiling' into feature_profiling 2014-02-16 12:06:14 +01:00
Petr Mrázek
1dc34269bd Fix path selections for tools (settings dialog) 2014-02-16 12:04:26 +01:00
Jan Dalheimer
c608841f77 Attempt to find jvisualvm 2014-02-16 12:00:38 +01:00
Jan Dalheimer
2e64d0308c Use a combobox instead of a file dialog 2014-02-16 11:56:02 +01:00
Jan Dalheimer
c88c639b8e Fix for windows and update tool menu after closing settings dialog 2014-02-16 11:49:55 +01:00
Jan Dalheimer
616c372690 Fix more stuff. Detached tools, only MCEdit for now. 2014-02-16 10:46:14 +01:00
Jan Dalheimer
994972bf5d More fixes. 2014-02-16 09:30:38 +01:00
Jan Dalheimer
82b35b5445 Fix stuff. Make sure different ways of aborting profiling work. 2014-02-16 08:54:52 +01:00
Petr Mrázek
7ceb2cacb1 Fix a few bugs in profilers.
* Legacy was launching before the profiler.
* Some clarity changes.
* Report problem with empty strings as profiler paths.
2014-02-16 00:10:45 +01:00
Jan Dalheimer
8219dbf612 Underp. Don't depend on OneSix. Nicer "menu" style choosing. 2014-02-15 22:26:44 +01:00
Jan Dalheimer
3b236483df Another attempt at fixing windows build 2014-02-15 19:07:01 +01:00
Jan Dalheimer
c0e58fbfb2 Try to be cross-platform 2014-02-15 18:15:41 +01:00
Jan Dalheimer
6f6d912d07 Underp and fix some stuff. Works nicer now. 2014-02-15 15:20:12 +01:00
Jan Dalheimer
efa8e26a3f Profiler support. Currently JProfiler and JVisualVM are implemented. 2014-02-15 14:19:35 +01:00
Petr Mrázek
5cf599673d Merge https://github.com/p-schneider/MultiMC5 into develop 2014-02-14 21:00:48 +01:00
Petr Mrázek
65e30aa118 Merge https://github.com/robotbrain/MultiMC5 into develop 2014-02-14 20:59:23 +01:00
Petr Mrázek
a59dbdcb38 Merge https://github.com/max96at/MultiMC5 into develop 2014-02-14 20:58:09 +01:00
p-schneider
725e6a36bb fixed the destination (href) of the link http://github.com/MultiMC/MultiMC5 in AboutDialog.ui (+German translation) 2014-02-14 13:39:00 +01:00
robotbrain
93ee6f9010 Fix FTB paths on Windows XP 2014-02-13 16:00:51 -05:00
Petr Mrázek
5a0e7877b0 Fix groupview issues
* indexAt was using the wrong coordinate system
* model events now trigger a delayed layout update instead of immediate.
2014-02-10 00:51:52 +01:00
Petr Mrázek
2f0275c194 Fix kitty. Meow. 2014-02-09 22:55:44 +01:00
Petr Mrázek
1f218bb8cd Fix template magic in group view. 2014-02-09 21:14:34 +01:00
Petr Mrázek
ba401922e1 Do not divide by zero when the last group is collapsed. 2014-02-09 21:04:00 +01:00
Petr Mrázek
1f6a484cb2 Merge branch 'integration_derpstances_groupview' into develop 2014-02-09 20:49:48 +01:00
Petr Mrázek
18f532b0d7 Visual and scroll behavior changes to groupview
Scroll by rows, not pixels.
Paint the checkboxy thing again! Make0 it behave.
Set the group header height properly.
2014-02-09 20:45:18 +01:00
Petr Mrázek
0d30a2655f Blacklist the FTB voxel pack. 2014-02-09 19:10:56 +01:00
Petr Mrázek
9022042360 Only load instance list twice. 2014-02-09 11:00:34 +01:00
Petr Mrázek
583786757a Fix crash bug related to messageboxes interrupting model resets in the instance list. 2014-02-08 23:52:15 +01:00
Petr Mrázek
af33b96684 Merge branch 'feature_groupview' into integration_derpstances_groupview 2014-02-08 22:18:32 +01:00
Petr Mrázek
aa41b891f0 Group View: Use painting code from the previous group headers, small optimizations 2014-02-08 21:46:29 +01:00
Jan Dalheimer
53069205fa Allow overriding the order in which patches are applied 2014-02-08 17:22:26 +01:00
Jan Dalheimer
6d9819cccf Error if a patch file is for a different version of minecraft 2014-02-08 12:47:14 +01:00
Petr Mrázek
f8df07c327 Small tweaks to make things better. 2014-02-06 09:32:44 +01:00
Petr Mrázek
573d4c8050 Paint the headers nicer. 2014-02-05 01:34:50 +01:00
Petr Mrázek
c84c51860d Fix crash bug related to data changes in new group view. 2014-02-04 21:18:02 +01:00
Petr Mrázek
6206a241ea A try at fixing the instance delegate. A bit. Maybe. 2014-02-04 02:01:11 +01:00
Petr Mrázek
7839c4ecc0 Pave. 2014-02-04 01:40:51 +01:00
Petr Mrázek
b82eb5873e Add 'depends/groupview/' from commit '946d49675cb4725c31ab49a51f3bcae302f89a19'
git-subtree-dir: depends/groupview
git-subtree-mainline: a17caba2c9
git-subtree-split: 946d49675c
2014-02-04 00:53:05 +01:00
Petr Mrázek
a17caba2c9 Nuke. 2014-02-04 00:43:18 +01:00
Petr Mrázek
946d49675c Swap things around -- rename refactors, moving towards non-derpy design. Maybe. 2014-02-04 00:40:10 +01:00
Jan Dalheimer
ac2f64f337 Reload version after removing custom.json 2014-02-03 20:42:04 +01:00
Petr Mrázek
ddedd077b6 Oh my. 2014-02-02 18:30:52 +01:00
Petr Mrázek
2cd9b06476 Fix drag&drop pixmap rendering 2014-02-02 16:57:00 +01:00
Petr Mrázek
eb0ed082d8 Fix group mouse interaction issues 2014-02-02 14:27:43 +01:00
Jan Dalheimer
cdd35910c3 Fix installing forge after liteloader and then removing liteloader. Also formatting. 2014-02-02 14:17:44 +01:00
Jan Dalheimer
ece826bdbc Add a MMC-depend field (soft/hard) for version checking 2014-02-02 14:05:07 +01:00
Petr Mrázek
b2bf50a6d7 Small tweaks 2014-02-02 10:26:38 +01:00
Jan Dalheimer
790402bdce Disable anything related to user.json for now. Will be re-enabled once we have a gui for it. 2014-02-01 22:32:48 +01:00
Jan Dalheimer
983a40698c Merge remote-tracking branch 'upstream/feature_derpstances' into feature_derpstances 2014-02-01 19:58:13 +01:00
Jan Dalheimer
866d7029af Fix some bugs that got uncovered while trying to get liteloader 1.7 to work 2014-02-01 19:42:47 +01:00
Petr Mrázek
1936bd181f Merge branch 'feature_derpstances' of https://github.com/02JanDal/MultiMC5 into feature_derpstances
Conflicts:
	gui/dialogs/OneSixModEditDialog.cpp
	logic/OneSixUpdate.cpp
2014-02-01 19:37:16 +01:00
Jan Dalheimer
8637cce433 Fix a bug 2014-02-01 16:26:38 +01:00
Jan Dalheimer
4a9e213238 Change the OneSix library view. It now shows a list of patches. 2014-02-01 14:52:21 +01:00
Petr Mrázek
179451d591 More reformat. 2014-01-31 22:58:57 +01:00
Petr Mrázek
3fb7a0faf0 Reformat, Rename, Redo 2014-01-31 22:51:45 +01:00
Petr Mrázek
b4b6091372 Add 'empty text' to all the version selection dialogs.
Customize it for the Forge one so people finally shut up about 1.7.4
2014-01-29 01:20:19 +01:00
Jan Dalheimer
556d8f0ec1 custom.json overrides all. For user patching there now is instance.json 2014-01-28 07:39:43 +01:00
Jan Dalheimer
986141b503 Fix library ordering 2014-01-27 22:23:07 +01:00
Jan Dalheimer
176783c8ca Have the libraries tab show tweaker mods instead of libraries 2014-01-27 20:17:29 +01:00
Jan Dalheimer
f9ea3dbfde Split parsing/applying. Better error logging. Fix crash. 2014-01-27 19:20:07 +01:00
Petr Mrázek
ffbc5bb62c Offline mode can be used even when online.
Allow the user to pick a player name for offline mode.
Big auth refactor. Now using session objects instead of the accounts themselves.
Sessions only last for one instance start and hold all the auth and player data.
2014-01-27 03:00:49 +01:00
Jan Dalheimer
966f9d1206 Merge branch 'develop' into feature_derpstances 2014-01-24 22:00:34 +01:00
Jan Dalheimer
0f7b38c76b Fix some stuff 2014-01-24 18:17:26 +01:00
Jan Dalheimer
7d5787025a Change naming from Derp -> OneSix until the new instance type supports legacy 2014-01-24 18:12:02 +01:00
Jan Dalheimer
156bc8f276 Forge works now too, and so does forge+liteloader 2014-01-23 21:31:41 +01:00
Petr Mrázek
d7113de3bd Hotfix 0.2.1 for twitch.
Add to the changelog and tweak the version number.
2014-01-22 22:40:17 +01:00
Jan Dalheimer
c39d26f445 Got liteloader working. Patching more or less works 2014-01-22 22:15:50 +01:00
Noah Mayr
2831ca94f8 Added more possible java paths on OSX. 2014-01-22 18:28:56 +01:00
Jan Dalheimer
0a592ab99b Work towards liteloader support. Fix creating new instance 2014-01-22 15:20:48 +01:00
Jan Dalheimer
d166b48072 Merge branch 'develop' into feature_derpstances 2014-01-22 14:06:58 +01:00
Jan Dalheimer
13ac46bc18 Fix launching 2014-01-22 14:06:32 +01:00
Jan Dalheimer
a1a06cc89f Derpstances. Everything renamed. Launching does not yet work. 2014-01-22 07:33:32 +01:00
Petr Mrázek
c46c508fc6 Extract native libs in the launcher part. 2014-01-22 02:20:09 +01:00
Petr Mrázek
b182f12c20 Fix library path for 64bit natives 2014-01-21 00:50:18 +01:00
Petr Mrázek
222d3c0dc5 Merge branch 'release-0.2' 2014-01-20 01:32:38 +01:00
Petr Mrázek
3a3c9ac951 Update the changelog, version, scale the instance icon 2014-01-20 01:14:11 +01:00
Petr Mrázek
130a790807 Merge branch 'patch-1' of https://github.com/ACGaming/MultiMC5 into develop 2014-01-19 23:50:37 +01:00
Petr Mrázek
5eb9ef5d56 Scale faces to 64x64 2014-01-19 23:05:16 +01:00
Petr Mrázek
e9ed4b29bc Add 64x64 icon versions 2014-01-19 22:07:59 +01:00
ACGaming
58741d2df4 Complete revision of the German language file 2014-01-19 17:38:26 +01:00
Petr Mrázek
53f61bea71 Remove 24x24 icons :< 2014-01-19 15:16:32 +01:00
Petr Mrázek
498bb48338 Add more scales to toolbar icons 2014-01-19 13:52:44 +01:00
Petr Mrázek
2fe033c4a0 Move a bunch of resources into the resources folder.
Also, cat is no longer mysterious. It's just FLUFFY!
2014-01-19 05:21:09 +01:00
Petr Mrázek
d8413fa5ec Use icon theme so we can have more than one icon size per icon 2014-01-19 04:52:34 +01:00
Sky
e6ab57b8b1 Try to improve status arrows a bit 2014-01-19 01:33:32 +00:00
Petr Mrázek
e71295d760 Force using LF endlines while configuring tests 2014-01-18 22:51:04 +01:00
Petr Mrázek
50c441a773 Merge branch 'fix_tests' of https://github.com/02JanDal/MultiMC5 into develop 2014-01-18 22:30:36 +01:00
Petr Mrázek
e9186d6d2c DERP DERP DERP
DERP ALERT. DUCK AND COVER!
2014-01-18 22:20:36 +01:00
Petr Mrázek
208209e4a7 Fix derp: there is no static QFileInfo::exists in Qt 5.1.1 2014-01-18 22:16:47 +01:00
Petr Mrázek
3fabb11f4c Marginally improve OneSix offline mode launch
While reconstructing assets, skip files that don't exist.
Report missing OneSix native libraries.
2014-01-18 22:11:33 +01:00
Petr Mrázek
8650aa81f0 Fix settings dialog when offline 2014-01-18 10:31:34 +01:00
Petr Mrázek
ecc80bd763 Change the native extraction/loading logic. 2014-01-18 03:33:04 +01:00
Orochimarufan
188d0d5886 Improve Console window output.
-> Log Pre- and Post-Launch command happenings
-> Enable the java part to specify the level

TODO: fix logging with mc 1.7's log4j logging infrastructure

Signed-off-by: Orochimarufan <orochimarufan.x3@gmail.com>
2014-01-17 22:55:10 +01:00
Petr Mrázek
7b96d74d3b Sort forge versions right. Do not spam the multimc log with mc server status stuff. 2014-01-16 23:06:07 +01:00
Petr Mrázek
d85e820a07 Fix FTB.
Add support of private packs.
Fix instance ID problems related to FTB instances.
2014-01-15 22:49:37 +01:00
Petr Mrázek
555cbe00ce Do not use the java checker during instance update 2014-01-14 01:13:35 +01:00
Petr Mrázek
4744ea07a8 Small fix for stale files getting stuck in the cache 2014-01-13 02:19:20 +01:00
Petr Mrázek
85ff1657fd Merge branch 'feature_better_launch' into develop 2014-01-12 23:56:19 +01:00
Petr Mrázek
afd1778fd7 Fix window title problem on OSX. 2014-01-12 23:38:12 +01:00
Petr Mrázek
54a9ee5eb0 Merge branch 'feature_localization' of https://github.com/02JanDal/MultiMC5 into develop
Conflicts:
	gui/dialogs/SettingsDialog.cpp
	gui/dialogs/SettingsDialog.ui
2014-01-12 23:04:05 +01:00
Petr Mrázek
f552366e03 Merge branch 'feature_mojang_status' into develop 2014-01-12 22:34:53 +01:00
Petr Mrázek
b589a12d17 Merge branch 'feature_better_launch' into develop 2014-01-12 22:17:14 +01:00
Petr Mrázek
fca4441229 Replace old launcher part with a shiny new one. No more garbage on the command line. 2014-01-12 21:57:34 +01:00
Sky
398167e8b0 More space between status items 2014-01-12 18:44:54 +00:00
Sky
500581d095 More comments removal 2014-01-12 18:42:02 +00:00
Sky
c51090dcff Remove wrong comments 2014-01-12 18:34:43 +00:00
Sky
a774b3d248 Show Mojang service statuses in status bar 2014-01-12 18:28:42 +00:00
Petr Mrázek
498520446f Merge https://github.com/Drayshak/MultiMC5 into develop 2014-01-11 02:21:26 +01:00
Petr Mrázek
d52079e734 No more generated resources. 2014-01-11 02:17:51 +01:00
Petr Mrázek
43a39a3bfb Harden CacheDownload.
It's now super hard. SRSLY.
2014-01-11 02:06:22 +01:00
Sky
c00946c855 Merge branch 'develop' of github.com:MultiMC/MultiMC5 into develop 2014-01-11 00:22:21 +00:00
Sky
088ad07a80 Show active account skin whilst it's checked for updates 2014-01-11 00:22:08 +00:00
Petr Mrázek
8e286c2b5c Make CacheDownload use QSaveFile 2014-01-10 22:08:00 +01:00
Sky
9ddf2aec31 Add tooltips to Java memory spinboxes 2014-01-10 13:16:31 +00:00
Sky
3c189a6553 Hide user properties in the console too 2014-01-10 12:52:14 +00:00
Sky
86b6cdfcb3 Merge branch 'develop' of github.com:MultiMC/MultiMC5 into develop 2014-01-09 15:42:44 +00:00
Sky
e6201f9ff7 Add "MB" as a suffix to memory spinboxes 2014-01-09 15:30:21 +00:00
Forkk
52c9cd5497 Make the GitHub link in the about dialog clickable
Fixes #38
2014-01-08 23:38:34 -06:00
Forkk
0e22e4b399 Merge branch 'master' into develop 2014-01-08 22:52:49 -06:00
Forkk
48b587e7b6 Merge branch 'hotfix-0.1.1'
This is a quick hotfix to correct the issue tracker URL. Forgot to do
so in the last release.
2014-01-08 22:51:57 -06:00
Forkk
7d74c9bc25 Change the issue tracker URL to GitHub issues
Bump hotfix version number and add an entry in the changelog.
2014-01-08 22:51:21 -06:00
Forkk
0b1e0221f0 Merge branch 'develop' of github.com:MultiMC/MultiMC5 into develop 2014-01-08 21:50:58 -06:00
Forkk
06b5fa5dcc Merge branch 'release-0.1'
Release MultiMC version 0.1.
2014-01-08 21:45:13 -06:00
Petr Mrázek
c51a993ff7 Add logging calls to the java checker. 2014-01-09 01:20:24 +01:00
Forkk
b767d4b134 Fix the window title
The window title now says
"MultiMC 5 - Version <version> [on <platform>]"
2014-01-08 18:02:15 -06:00
Forkk
b4fcbab513 Word wrap the update channel description label
Previously, channel descriptions that were too long would mess up the
dialog.
2014-01-08 17:56:38 -06:00
Forkk
7ace682260 Remove lies from the changelog
There wasn't really an Optimus fix. LIES! ALL LIES!
2014-01-08 17:54:23 -06:00
Petr Mrázek
5650a28fc6 Hopefully fix OSX icon file 2014-01-08 21:06:31 +01:00
Forkk
87b12a63a1 Make CMake output version type info 2014-01-07 19:30:08 -06:00
Forkk
d7564a51ce Bump minor version number and update changelog. 2014-01-07 19:21:42 -06:00
Forkk
9bf4d08770 Add changelog. 2014-01-07 19:00:42 -06:00
Forkk
8dfc1028ee Merge branch 'new-version-system' into develop 2014-01-07 18:47:06 -06:00
Forkk
3629f9b999 Merge branch 'develop' of github.com:MultiMC/MultiMC5 into new-version-system 2014-01-07 18:31:49 -06:00
Forkk
a14eeab2d6 Add information to the about dialog. 2014-01-07 18:31:31 -06:00
Petr Mrázek
fb83299e59 Deploy jars instead of extracting them at runtime, remove non-working nvidia fix 2014-01-08 01:28:33 +01:00
Forkk
3202b972f8 Rework version numbering system.
Again...
2014-01-07 18:09:05 -06:00
Sky
28cb66e85c Merge pull request #35 from 02JanDal/fix_keep_selection
Fix instances getting deselected after FTB instances are loaded (or when ever the model is reset, like on a reload)
2014-01-07 05:02:35 -08:00
Sky
7773e77150 Don't include debugging messages :( 2014-01-07 03:18:26 +00:00
Sky
5fe0ed7e8f Return a properly sorted list of checked javas 2014-01-07 03:16:47 +00:00
Petr Mrázek
012b007e56 Do not log each and every possible update. Only the latest one. 2014-01-07 02:43:25 +01:00
Petr Mrázek
28c35ea0db Fix proxy settings radio buttons not triggering updates of the proxy settings. 2014-01-07 02:19:26 +01:00
Petr Mrázek
267f18ca81 Add hack for Nvidia 2014-01-06 22:05:45 +01:00
Forkk
0a312d3b08 Implement proxy settings 2014-01-06 15:02:58 -06:00
Jan Dalheimer
093143cfef Fix instances getting deselected after FTB instances are loaded (or whenever the model is reset) 2014-01-06 10:01:40 +01:00
Petr Mrázek
fcb8612c10 Implement console window tray icon, console window hiding, better scrolling 2014-01-06 02:52:51 +01:00
Petr Mrázek
ddb961fad5 Scroll console window for <= lines above the bottom instead of the very bottom. 2014-01-06 00:33:16 +01:00
Jan Dalheimer
7d76fd57e9 Get rid of some obsolete functions 2014-01-05 23:24:19 +01:00
Jan Dalheimer
6961525faa Unbreak and reactivate the some UpdateChecker tests 2014-01-05 23:24:05 +01:00
Jan Dalheimer
8950953d91 Hopefully fix Qt 5.1 compilation 2014-01-04 19:20:20 +01:00
Jan Dalheimer
7f6b344b49 Clean up/update translation code and made language selectable in the settings dialog 2014-01-04 16:13:28 +01:00
Jan Dalheimer
9bbbb05060 Add xnrand to the translation credits 2014-01-04 13:35:15 +01:00
xnrand
0885668292 Update mmc_de.ts
Fixed grammar, improved wording.
It's not perfect but definitely better.
2014-01-04 13:02:07 +01:00
Jan Dalheimer
0f1a3329e4 Du/Sie consistency 2014-01-04 12:58:47 +01:00
Jan Dalheimer
998a14c95d Update the german translation 2014-01-04 11:54:51 +01:00
Jan Dalheimer
3b97e3c363 Fix a few things related to the translations 2014-01-04 11:49:06 +01:00
Jan Dalheimer
c47933d95c Loads of changes and some refactorings 2013-12-31 17:26:36 +01:00
Jan Dalheimer
8cfd0881ac Progress indicators 2013-12-30 23:39:10 +01:00
Jan Dalheimer
e6be883d14 Fixing more bugs 2013-12-30 23:10:53 +01:00
Jan Dalheimer
1e1b2342f4 Loads of fixes 2013-12-30 18:46:12 +01:00
Jan Dalheimer
4662fbd298 Make the MultiMC delegate fully usable. Dynamic row heights. 2013-12-30 18:45:40 +01:00
Jan Dalheimer
0109220678 Take the spacing into account 2013-12-27 00:03:24 +01:00
Jan Dalheimer
f8d835cd22 Fix scrolling 2013-12-26 22:40:26 +01:00
Jan Dalheimer
53db8edb85 Fixing several d&d bugs 2013-12-26 22:02:25 +01:00
Jan Dalheimer
acbbdf319a Remove a debug message 2013-12-26 21:24:42 +01:00
Jan Dalheimer
c71808446b Fix a bug 2013-12-26 21:23:21 +01:00
Jan Dalheimer
525f508d94 Loads of stuff, amongst others d&d and many bug fixes 2013-12-26 21:16:03 +01:00
Jan Dalheimer
ccbf341dc8 Initial commit. Basics work. Next: Drag and Drop 2013-12-24 11:47:30 +01:00
963 changed files with 53982 additions and 29414 deletions

View File

@@ -9,6 +9,7 @@ NamespaceIndentation: None
BreakBeforeBraces: Allman
AllowShortIfStatementsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
ColumnLimit: 96
MaxEmptyLinesToKeep: 1

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
*.pem -crlf

16
.gitignore vendored
View File

@@ -1,17 +1,25 @@
Thumbs.db
.kdev4
MultiMC5.kdev4
MultiMC.pro.user
CMakeLists.txt.user
.user
.directory
build
resources/CMakeFiles
resources/MultiMCLauncher.jar
*~
*.swp
html/
# Project Files
MultiMC5.kdev4
MultiMC.pro.user
CMakeLists.txt.user
CMakeLists.txt.user.*
/.project
/.settings
# Build dirs
build
/build-*
# Ctags File
tags

23
.travis.yml Normal file
View File

@@ -0,0 +1,23 @@
language: cpp
compiler:
- gcc
- clang
cache: apt
before_install:
- sudo apt-add-repository -y ppa:beineri/opt-qt532
- sudo apt-add-repository -y ppa:kalakris/cmake
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- sudo apt-get update -qq
install:
- sudo apt-get install -y -qq cmake qt53base qt53svg qt53tools qt53x11extras qt53webkit
- sudo apt-get install -y -qq g++-4.8
- if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi
before_script:
- mkdir build
- cd build
- cmake -DCMAKE_PREFIX_PATH=/opt/qt53/lib/cmake ..
script:
- make -j4
- make test ARGS="-V"
notifications:
email: false

View File

@@ -2,10 +2,18 @@ Build Instructions
==================
# Contents
* [Note](#note)
* [Linux](#linux)
* [Windows](#windows)
* [OS X](#os-x)
# Note
MultiMC is a portable application and is not supposed to be installed into any system folders.
That would be anything outside your home folder. Before runing `make install`, make sure
you set the install path to something you have write access to. Never build this under
an administrator/root level account. Don't use `sudo`. It won't work and it's not supposed to work.
# Linux
Getting the project to build and run on Linux is easy if you use Ubuntu 13.10 (or 13.04) and Qt's IDE, Qt Creator.
@@ -56,7 +64,7 @@ Getting the project to build and run on Windows is easy if you use Qt's IDE, Qt
## Dependencies
* Qt 5.1.1+ Development tools (http://qt-project.org/downloads) ("Qt Online Installer for Windows")
* OpenSSL (http://slproweb.com/products/Win32OpenSSL.html) ("Win32 OpenSSL v1.0.1e Light")
* OpenSSL (http://slproweb.com/products/Win32OpenSSL.html) ("Win32 OpenSSL \<version\> Light")
- Microsoft Visual C++ 2008 Redist. is required for this, there's a link on the OpenSSL download page above next to the main download.
* CMake (http://www.cmake.org/cmake/resources/software.html) ("Windows (Win32 Installer)")
* A copy of the MultiMC source (clone it with git)

View File

@@ -1,85 +1,104 @@
cmake_minimum_required(VERSION 2.8.9)
IF(WIN32)
string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BUILD_DIR}" IS_IN_SOURCE_BUILD)
if(IS_IN_SOURCE_BUILD)
message(AUTHOR_WARNING "You are building MultiMC in-source. This is NOT recommended!")
endif()
if(WIN32)
# In Qt 5.1+ we have our own main() function, don't autolink to qtmain on Windows
cmake_policy(SET CMP0020 OLD)
ENDIF()
endif()
project(MultiMC)
project(Megatron)
enable_testing()
######## Set CMake options ########
SET(CMAKE_AUTOMOC ON)
SET(CMAKE_INCLUDE_CURRENT_DIR ON)
SET(FILES_TO_TRANSLATE )
set(CMAKE_AUTOMOC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
######## Set module path ########
SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/")
SET(MMC_SRC "${PROJECT_SOURCE_DIR}")
SET(MMC_BIN "${PROJECT_BINARY_DIR}")
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/")
set(MMC_SRC "${PROJECT_SOURCE_DIR}")
set(MMC_BIN "${PROJECT_BINARY_DIR}")
# Output all executables and shared libs in the main build folder, not in subfolders.
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
IF(UNIX)
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
ENDIF()
if(UNIX)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
endif()
set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${PROJECT_BINARY_DIR}/jars)
######## Set compiler flags ########
IF(APPLE)
message(STATUS "Using APPLE CMAKE_CXX_FLAGS")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
ELSEIF(UNIX)
# assume GCC, add C++0x/C++11 stuff
MESSAGE(STATUS "Using UNIX CMAKE_CXX_FLAGS")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
ELSEIF(MINGW)
MESSAGE(STATUS "Using MINGW CMAKE_CXX_FLAGS")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -Wall")
ENDIF()
include(UseCXX11)
include(Coverage)
set(CMAKE_CXX_FLAGS " -Wall ${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Werror=return-type")
################################ INCLUDE LIBRARIES ################################
# cmake code needed for the coverity scan upload
include(Coverity)
######## 3rd Party Libs ########
################################ 3rd Party Libs ################################
# Find the required Qt parts
find_package(Qt5Core REQUIRED)
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Concurrent REQUIRED)
find_package(Qt5Network REQUIRED)
find_package(Qt5Test REQUIRED)
find_package(Qt5Concurrent REQUIRED)
find_package(Qt5LinguistTools REQUIRED)
find_package(Qt5Xml REQUIRED)
include_directories(
${Qt5Core_INCLUDE_DIRS}
${Qt5Widgets_INCLUDE_DIRS}
${Qt5Concurrent_INCLUDE_DIRS}
${Qt5Network_INCLUDE_DIRS}
${Qt5Test_INCLUDE_DIRS}
)
${Qt5Network_INCLUDE_DIRS}
${Qt5Xml_INCLUDE_DIRS}
)
# The Qt5 cmake files don't provide its install paths, so ask qmake.
get_target_property(QMAKE_EXECUTABLE Qt5::qmake LOCATION)
function(QUERY_QMAKE VAR RESULT)
exec_program(${QMAKE_EXECUTABLE} ARGS "-query ${VAR}" RETURN_VALUE return_code OUTPUT_VARIABLE output )
if(NOT return_code)
file(TO_CMAKE_PATH "${output}" output)
set(${RESULT} ${output} PARENT_SCOPE)
endif(NOT return_code)
endfunction(QUERY_QMAKE)
include(QMakeQuery)
query_qmake(QT_INSTALL_PLUGINS QT_PLUGINS_DIR)
query_qmake(QT_INSTALL_IMPORTS QT_IMPORTS_DIR)
query_qmake(QT_INSTALL_LIBS QT_LIBS_DIR)
query_qmake(QT_INSTALL_LIBEXECS QT_LIBEXECS_DIR)
query_qmake(QT_HOST_DATA QT_DATA_DIR)
set(QT_MKSPECS_DIR ${QT_DATA_DIR}/mkspecs)
if (Qt5_POSITION_INDEPENDENT_CODE)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
######## Included Libs ########
################################ Included Libs ################################
include(ExternalProject)
set_directory_properties(PROPERTIES EP_BASE External)
# Add quazip
add_subdirectory(depends/quazip)
include_directories(depends/quazip)
add_definitions(-DQUAZIP_STATIC)
set(QUAZIP_VERSION "0.7.1")
if(NOT EXISTS ${CMAKE_BINARY_DIR}/quazip-${QUAZIP_VERSION}.tar.gz)
file(DOWNLOAD http://downloads.sourceforge.net/project/quazip/quazip/${QUAZIP_VERSION}/quazip-${QUAZIP_VERSION}.tar.gz ${CMAKE_BINARY_DIR}/quazip-${QUAZIP_VERSION}.tar.gz)
endif()
ExternalProject_Add(QuaZIP
SOURCE_DIR <BINARY_DIR>/../Source/quazip-${QUAZIP_VERSION}
DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E chdir <SOURCE_DIR>/.. ${CMAKE_COMMAND} -E tar xzf ${CMAKE_BINARY_DIR}/quazip-${QUAZIP_VERSION}.tar.gz
PATCH_COMMAND patch -p0 -i ${CMAKE_SOURCE_DIR}/quazip.patch
CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} -DCMAKE_CXX_FLAGS_DEBUG=${CMAKE_CXX_FLAGS_DEBUG} -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH} -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
)
include_directories("${CMAKE_BINARY_DIR}/External/Install/QuaZIP/include/quazip")
if(UNIX)
set(QUAZIP_LIBRARIES -L"${CMAKE_BINARY_DIR}/External/Install/QuaZIP/lib" quazip z)
else()
set(QUAZIP_LIBRARIES -L"${CMAKE_BINARY_DIR}/External/Install/QuaZIP/lib" quazip)
endif()
# Add the markdown parser thing
add_subdirectory(depends/hoedown)
include_directories(${HOEDOWN_INCLUDE_DIR})
# Add the java launcher and checker
add_subdirectory(depends/launcher)
@@ -96,624 +115,26 @@ include_directories(${PACK200_INCLUDE_DIR})
######## MultiMC Libs ########
# Add the util library.
add_definitions(-DLIBUTIL_STATIC)
add_subdirectory(depends/util)
include_directories(${LIBUTIL_INCLUDE_DIR})
# Add the settings library.
add_subdirectory(depends/settings)
include_directories(${LIBSETTINGS_INCLUDE_DIR})
# Add the GUI -> Logic connection header
add_subdirectory(depends/LogicalGui)
include_directories(${LOGICALGUI_INCLUDE_DIR})
# Add the group view library.
add_subdirectory(depends/groupview)
include_directories(${LIBGROUPVIEW_INCLUDE_DIR})
# Add the GUI -> Logic connection header
add_subdirectory(depends/iconfix)
include_directories(${ICONFIX_INCLUDE_DIR})
# Add the updater
add_subdirectory(mmc_updater)
include(Coverity)
################################ SET UP BUILD OPTIONS ################################
############################### Built Artifacts ###############################
######## Check endianness ########
INCLUDE(TestBigEndian)
TEST_BIG_ENDIAN(BIGENDIAN)
IF(${BIGENDIAN})
ADD_DEFINITIONS(-DMULTIMC_BIG_ENDIAN)
ENDIF(${BIGENDIAN})
######## Set URLs ########
SET(MultiMC_NEWS_RSS_URL "http://multimc.org/rss.xml" CACHE STRING "URL to fetch MultiMC's news RSS feed from.")
######## Set version numbers ########
SET(MultiMC_VERSION_MAJOR 0)
SET(MultiMC_VERSION_MINOR 0)
# Build number
SET(MultiMC_VERSION_BUILD -1 CACHE STRING "Build number. -1 for no build number.")
# Build type
SET(MultiMC_VERSION_BUILD_TYPE "custombuild" CACHE STRING "Build type. If this is set, it is appended to the end of the version string with a dash (<version string>-<build type>. It is not used for anything other than indicating in the version string what type of build this is (eg 'lin64').")
# Version channel
SET(MultiMC_VERSION_CHANNEL "" CACHE STRING "The current build's channel. Included in the version string.")
# Channel list URL
SET(MultiMC_CHANLIST_URL "" CACHE STRING "URL for the channel list.")
# Updater enabled?
SET(MultiMC_UPDATER false CACHE BOOL "Whether or not the update system is enabled. If this is enabled, you must also set MultiMC_CHANLIST_URL and MultiMC_VERSION_CHANNEL in order for it to work properly.")
# Notification URL
SET(MultiMC_NOTIFICATION_URL "" CACHE STRING "URL for checking for notifications.")
# Build a version string to display in the configure logs.
SET(MultiMC_VERSION_STRING "5.${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}")
IF (MultiMC_VERSION_BUILD GREATER -1)
SET(MultiMC_VERSION_STRING "${MultiMC_VERSION_STRING}.${MultiMC_VERSION_BUILD}")
ENDIF ()
IF (NOT MultiMC_VERSION_CHANNEL STREQUAL "")
SET(MultiMC_VERSION_STRING "${MultiMC_VERSION_STRING}-${MultiMC_VERSION_CHANNEL}")
ENDIF ()
IF (NOT MultiMC_VERSION_BUILD_TYPE STREQUAL "")
SET(MultiMC_VERSION_STRING "${MultiMC_VERSION_STRING}-${MultiMC_VERSION_BUILD_TYPE}")
ENDIF ()
MESSAGE(STATUS "MultiMC 5 version ${MultiMC_VERSION_STRING}")
# If the update system is enabled, make sure MultiMC_CHANLIST_URL and MultiMC_VERSION_CHANNEL are set.
IF (MultiMC_UPDATER)
IF (MultiMC_VERSION_CHANNEL STREQUAL "")
MESSAGE(FATAL_ERROR "Update system is enabled, but MultiMC_VERSION_CHANNEL is not set.\n"
"Please ensure the CMake variables MultiMC_VERSION_CHANNEL, MultiMC_CHANLIST_URL, and MultiMC_VERSION_BUILD are set.")
ENDIF ()
IF (MultiMC_CHANLIST_URL STREQUAL "")
MESSAGE(FATAL_ERROR "Update system is enabled, but MultiMC_CHANLIST_URL is not set.\n"
"Please ensure the CMake variables MultiMC_VERSION_CHANNEL, MultiMC_CHANLIST_URL, and MultiMC_VERSION_BUILD are set.")
ENDIF ()
IF (MultiMC_VERSION_BUILD LESS 0)
MESSAGE(FATAL_ERROR "Update system is enabled, but MultiMC_VERSION_BUILD is not set.\n"
"Please ensure the CMake variables MultiMC_VERSION_CHANNEL, MultiMC_CHANLIST_URL, and MultiMC_VERSION_BUILD are set.")
ENDIF ()
MESSAGE(STATUS "Updater is enabled. Channel list URL: ${MultiMC_CHANLIST_URL}")
ENDIF ()
#### Custom target to just print the version.
ADD_CUSTOM_TARGET(version echo "Version: ${MultiMC_VERSION_STRING}")
#### Check the current Git commit
execute_process(COMMAND git rev-parse HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
RESULT_VARIABLE GIT_COMMIT_CHECK_RESULTVAR
OUTPUT_VARIABLE GIT_COMMIT_CHECK_OUTVAR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
IF(GIT_COMMIT_CHECK_RESULTVAR EQUAL 0)
SET(MultiMC_GIT_COMMIT "${GIT_COMMIT_CHECK_OUTVAR}")
MESSAGE(STATUS "Git commit: ${MultiMC_GIT_COMMIT}")
ELSE()
SET(MultiMC_GIT_COMMIT "Unknown")
MESSAGE(STATUS "Failed to check Git commit. ${GIT_COMMIT_CHECK_RESULTVAR}")
ENDIF()
######## Configure header ########
configure_file("${PROJECT_SOURCE_DIR}/config.h.in" "${PROJECT_BINARY_DIR}/include/config.h")
######## Other Stuff ########
ADD_DEFINITIONS(-DQUAZIP_STATIC)
ADD_DEFINITIONS(-DLIBSETTINGS_STATIC)
ADD_DEFINITIONS(-DLIBUTIL_STATIC)
ADD_DEFINITIONS(-DLIBGROUPVIEW_STATIC)
################################ FILES ################################
######## Sources and headers ########
SET(MULTIMC_SOURCES
# Application base
MultiMC.h
MultiMC.cpp
MultiMCVersion.h
# Logging
logger/QsDebugOutput.cpp
logger/QsDebugOutput.h
logger/QsLog.cpp
logger/QsLog.h
logger/QsLogDest.cpp
logger/QsLogDest.h
# GUI - windows
gui/MainWindow.h
gui/MainWindow.cpp
gui/ConsoleWindow.h
gui/ConsoleWindow.cpp
# GUI - dialogs
gui/dialogs/SettingsDialog.h
gui/dialogs/SettingsDialog.cpp
gui/dialogs/CopyInstanceDialog.h
gui/dialogs/CopyInstanceDialog.cpp
gui/dialogs/dialogs/
gui/dialogs/NewInstanceDialog.cpp
gui/dialogs/ProgressDialog.h
gui/dialogs/ProgressDialog.cpp
gui/dialogs/AboutDialog.h
gui/dialogs/AboutDialog.cpp
gui/dialogs/VersionSelectDialog.h
gui/dialogs/VersionSelectDialog.cpp
gui/dialogs/LwjglSelectDialog.h
gui/dialogs/LwjglSelectDialog.cpp
gui/dialogs/InstanceSettings.h
gui/dialogs/InstanceSettings.cpp
gui/dialogs/IconPickerDialog.h
gui/dialogs/IconPickerDialog.cpp
gui/dialogs/LegacyModEditDialog.h
gui/dialogs/LegacyModEditDialog.cpp
gui/dialogs/OneSixModEditDialog.h
gui/dialogs/OneSixModEditDialog.cpp
gui/dialogs/ModEditDialogCommon.h
gui/dialogs/ModEditDialogCommon.cpp
gui/dialogs/EditNotesDialog.h
gui/dialogs/EditNotesDialog.cpp
gui/dialogs/CustomMessageBox.h
gui/dialogs/CustomMessageBox.cpp
gui/dialogs/EditAccountDialog.h
gui/dialogs/EditAccountDialog.cpp
gui/dialogs/AccountListDialog.h
gui/dialogs/AccountListDialog.cpp
gui/dialogs/AccountSelectDialog.h
gui/dialogs/AccountSelectDialog.cpp
gui/dialogs/UpdateDialog.h
gui/dialogs/UpdateDialog.cpp
# GUI - widgets
gui/widgets/InstanceDelegate.h
gui/widgets/InstanceDelegate.cpp
gui/widgets/ModListView.h
gui/widgets/ModListView.cpp
gui/widgets/LabeledToolButton.h
gui/widgets/LabeledToolButton.cpp
gui/widgets/MCModInfoFrame.h
gui/widgets/MCModInfoFrame.cpp
# Base classes and infrastructure
logic/BaseVersion.h
logic/MinecraftVersion.h
logic/InstanceFactory.h
logic/InstanceFactory.cpp
logic/BaseInstance.h
logic/BaseInstance.cpp
logic/BaseInstance_p.h
logic/MinecraftProcess.h
logic/MinecraftProcess.cpp
logic/Mod.h
logic/Mod.cpp
logic/ModList.h
logic/ModList.cpp
# Basic instance launcher for starting from terminal
logic/InstanceLauncher.h
logic/InstanceLauncher.cpp
# network stuffs
logic/net/NetAction.h
logic/net/MD5EtagDownload.h
logic/net/MD5EtagDownload.cpp
logic/net/ByteArrayDownload.h
logic/net/ByteArrayDownload.cpp
logic/net/CacheDownload.h
logic/net/CacheDownload.cpp
logic/net/ForgeMirrors.h
logic/net/ForgeMirrors.cpp
logic/net/ForgeXzDownload.h
logic/net/ForgeXzDownload.cpp
logic/net/NetJob.h
logic/net/NetJob.cpp
logic/net/HttpMetaCache.h
logic/net/HttpMetaCache.cpp
logic/net/PasteUpload.h
logic/net/PasteUpload.cpp
logic/net/URLConstants.h
# Yggdrasil login stuff
logic/auth/MojangAccountList.h
logic/auth/MojangAccountList.cpp
logic/auth/MojangAccount.h
logic/auth/MojangAccount.cpp
logic/auth/YggdrasilTask.h
logic/auth/YggdrasilTask.cpp
logic/auth/flows/AuthenticateTask.h
logic/auth/flows/AuthenticateTask.cpp
logic/auth/flows/RefreshTask.cpp
logic/auth/flows/RefreshTask.cpp
logic/auth/flows/ValidateTask.h
logic/auth/flows/ValidateTask.cpp
# Update system
logic/updater/UpdateChecker.h
logic/updater/UpdateChecker.cpp
logic/updater/DownloadUpdateTask.h
logic/updater/DownloadUpdateTask.cpp
logic/updater/NotificationChecker.h
logic/updater/NotificationChecker.cpp
# News System
logic/news/NewsChecker.h
logic/news/NewsChecker.cpp
logic/news/NewsEntry.h
logic/news/NewsEntry.cpp
# legacy instances
logic/LegacyInstance.h
logic/LegacyInstance.cpp
logic/LegacyInstance_p.h
logic/LegacyUpdate.h
logic/LegacyUpdate.cpp
logic/LegacyForge.h
logic/LegacyForge.cpp
# 1.6 instances
logic/OneSixInstance.h
logic/OneSixInstance.cpp
logic/OneSixInstance_p.h
logic/OneSixUpdate.h
logic/OneSixUpdate.cpp
logic/OneSixVersion.h
logic/OneSixVersion.cpp
logic/OneSixLibrary.h
logic/OneSixLibrary.cpp
logic/OneSixRule.h
logic/OneSixRule.cpp
logic/OpSys.h
logic/OpSys.cpp
logic/ForgeInstaller.h
logic/ForgeInstaller.cpp
logic/LiteLoaderInstaller.h
logic/LiteLoaderInstaller.cpp
# Nostalgia
logic/NostalgiaInstance.h
logic/NostalgiaInstance.cpp
# FTB
logic/OneSixFTBInstance.h
logic/OneSixFTBInstance.cpp
logic/LegacyFTBInstance.h
logic/LegacyFTBInstance.cpp
# Lists
logic/lists/InstanceList.h
logic/lists/InstanceList.cpp
logic/lists/BaseVersionList.h
logic/lists/BaseVersionList.cpp
logic/lists/MinecraftVersionList.h
logic/lists/MinecraftVersionList.cpp
logic/lists/LwjglVersionList.h
logic/lists/LwjglVersionList.cpp
logic/lists/ForgeVersionList.h
logic/lists/ForgeVersionList.cpp
logic/lists/JavaVersionList.h
logic/lists/JavaVersionList.cpp
# Icons
logic/icons/MMCIcon.h
logic/icons/MMCIcon.cpp
logic/icons/IconList.h
logic/icons/IconList.cpp
# misc model/view
logic/EnabledItemFilter.h
logic/EnabledItemFilter.cpp
# Tasks
logic/tasks/ProgressProvider.h
logic/tasks/Task.h
logic/tasks/Task.cpp
logic/tasks/ThreadTask.h
logic/tasks/ThreadTask.cpp
logic/tasks/SequentialTask.h
logic/tasks/SequentialTask.cpp
# Utilities
logic/JavaChecker.h
logic/JavaChecker.cpp
logic/JavaUtils.h
logic/JavaUtils.cpp
logic/NagUtils.h
logic/NagUtils.cpp
logic/SkinUtils.h
logic/SkinUtils.cpp
logic/JavaCheckerJob.h
logic/JavaCheckerJob.cpp
# Assets
logic/assets/AssetsMigrateTask.h
logic/assets/AssetsMigrateTask.cpp
logic/assets/AssetsUtils.h
logic/assets/AssetsUtils.cpp
)
######## UIs ########
SET(MULTIMC_UIS
# Windows
gui/MainWindow.ui
gui/ConsoleWindow.ui
# Dialogs
gui/dialogs/SettingsDialog.ui
gui/dialogs/CopyInstanceDialog.ui
gui/dialogs/NewInstanceDialog.ui
gui/dialogs/AboutDialog.ui
gui/dialogs/VersionSelectDialog.ui
gui/dialogs/LwjglSelectDialog.ui
gui/dialogs/InstanceSettings.ui
gui/dialogs/ProgressDialog.ui
gui/dialogs/IconPickerDialog.ui
gui/dialogs/LegacyModEditDialog.ui
gui/dialogs/OneSixModEditDialog.ui
gui/dialogs/EditNotesDialog.ui
gui/dialogs/AccountListDialog.ui
gui/dialogs/AccountSelectDialog.ui
gui/dialogs/EditAccountDialog.ui
gui/dialogs/UpdateDialog.ui
# Widgets/other
gui/widgets/MCModInfoFrame.ui
)
set (FILES_TO_TRANSLATE ${FILES_TO_TRANSLATE} ${MULTIMC_SOURCES} ${MULTIMC_UIS})
######## Windows resource files ########
IF(WIN32)
SET(MULTIMC_RCS multimc.rc)
ENDIF()
####### X11 Stuff #######
IF(UNIX AND NOT APPLE)
SET(MultiMC_QT_ADDITIONAL_MODULES ${MultiMC_QT_ADDITIONAL_MODULES} X11Extras)
SET(MultiMC_LINK_ADDITIONAL_LIBS ${MultiMC_LINK_ADDITIONAL_LIBS} xcb)
LIST(APPEND MULTIMC_SOURCES gui/Platform_X11.cpp)
ELSE()
LIST(APPEND MULTIMC_SOURCES gui/Platform_Other.cpp)
ENDIF()
################################ COMPILE ################################
# ICNS file for OS X
IF(APPLE)
SET(MACOSX_BUNDLE_ICON_FILE MultiMC.icns)
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/MultiMC.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
SET(MULTIMC_SOURCES ${MULTIMC_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/MultiMC.icns)
ENDIF(APPLE)
# Link additional libraries
IF(WIN32)
SET(MultiMC_LINK_ADDITIONAL_LIBS ${MultiMC_LINK_ADDITIONAL_LIBS}
Qt5::WinMain # Link WinMain
)
ENDIF(WIN32)
OPTION(MultiMC_UPDATER_DRY_RUN "Enable updater dry-run mode -- for updater development." OFF)
OPTION(MultiMC_UPDATER_FORCE_LOCAL "Do not download updated updater -- for updater development." OFF)
OPTION(MultiMC_CODE_COVERAGE "Compiles for code coverage" OFF)
IF(MultiMC_CODE_COVERAGE)
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 --coverage")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 --coverage")
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0 --coverage")
SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -g -O0 --coverage")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -O0 --coverage")
ENDIF(MultiMC_CODE_COVERAGE)
# Tell CMake that MultiMCLauncher.jar is generated.
SET_SOURCE_FILES_PROPERTIES(${PROJECT_BINARY_DIR}/depends/launcher/MultiMCLauncher.jar GENERATED)
SET_SOURCE_FILES_PROPERTIES(${PROJECT_BINARY_DIR}/depends/javacheck/JavaCheck.jar GENERATED)
# Qt 5 stuff
QT5_WRAP_UI(MULTIMC_UI ${MULTIMC_UIS})
CONFIGURE_FILE(generated.qrc.in generated.qrc)
QT5_ADD_RESOURCES(GENERATED_QRC ${CMAKE_CURRENT_BINARY_DIR}/generated.qrc)
QT5_ADD_RESOURCES(GRAPHICS_QRC graphics.qrc)
# Add common library
ADD_LIBRARY(MultiMC_common STATIC ${MULTIMC_SOURCES} ${MULTIMC_UI} ${GENERATED_QRC} ${GRAPHICS_QRC})
# Add executable
ADD_EXECUTABLE(MultiMC MACOSX_BUNDLE WIN32 main.cpp ${MULTIMC_RCS})
# Link
TARGET_LINK_LIBRARIES(MultiMC MultiMC_common)
TARGET_LINK_LIBRARIES(MultiMC_common xz-embedded unpack200 quazip libUtil libSettings libGroupView ${MultiMC_LINK_ADDITIONAL_LIBS})
QT5_USE_MODULES(MultiMC Core Widgets Network Xml Concurrent ${MultiMC_QT_ADDITIONAL_MODULES})
QT5_USE_MODULES(MultiMC_common Core Widgets Network Xml Concurrent ${MultiMC_QT_ADDITIONAL_MODULES})
ADD_DEPENDENCIES(MultiMC_common MultiMCLauncher JavaCheck)
################################ INSTALLATION AND PACKAGING ################################
######## Packaging/install paths setup ########
IF(UNIX AND APPLE)
SET(PLUGIN_DEST_DIR MultiMC.app/Contents/MacOS)
SET(QTCONF_DEST_DIR MultiMC.app/Contents/Resources)
SET(APPS "\${CMAKE_INSTALL_PREFIX}/MultiMC.app")
SET(MACOSX_BUNDLE_BUNDLE_NAME "MultiMC")
SET(MACOSX_BUNDLE_INFO_STRING "MultiMC Minecraft launcher and management utility.")
SET(MACOSX_BUNDLE_GUI_IDENTIFIER "org.multimc.MultiMC5")
SET(MACOSX_BUNDLE_BUNDLE_VERSION "${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}.${MultiMC_VERSION_REV}.${MultiMC_VERSION_BUILD}")
SET(MACOSX_BUNDLE_SHORT_VERSION_STRING "${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}.${MultiMC_VERSION_REV}.${MultiMC_VERSION_BUILD}")
SET(MACOSX_BUNDLE_LONG_VERSION_STRING "${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}.${MultiMC_VERSION_REV}.${MultiMC_VERSION_BUILD}")
SET(MACOSX_BUNDLE_ICON_FILE MultiMC.icns)
SET(MACOSX_BUNDLE_COPYRIGHT "Copyright 2013 MultiMC Contributors")
ELSEIF(UNIX)
SET(PLUGIN_DEST_DIR plugins)
SET(QTCONF_DEST_DIR .)
SET(APPS "\${CMAKE_INSTALL_PREFIX}/bin/MultiMC")
ELSEIF(WIN32)
SET(PLUGIN_DEST_DIR .)
SET(QTCONF_DEST_DIR .)
SET(APPS "\${CMAKE_INSTALL_PREFIX}/MultiMC.exe")
ENDIF()
# directories to look for dependencies
SET(DIRS "${QT_LIBS_DIR}")
######## Install ########
#### Executable ####
IF(APPLE AND UNIX) ## OSX
INSTALL(TARGETS MultiMC
BUNDLE DESTINATION . COMPONENT Runtime
RUNTIME DESTINATION MultiMC.app/Contents/MacOS COMPONENT Runtime
)
ELSEIF(UNIX) ## LINUX and similar
INSTALL(TARGETS MultiMC
BUNDLE DESTINATION . COMPONENT Runtime
RUNTIME DESTINATION bin COMPONENT Runtime
)
INSTALL(PROGRAMS package/linux/MultiMC DESTINATION .)
ELSEIF(WIN32) ## WINDOWS
INSTALL(TARGETS MultiMC
BUNDLE DESTINATION . COMPONENT Runtime
LIBRARY DESTINATION . COMPONENT Runtime
RUNTIME DESTINATION . COMPONENT Runtime
)
ENDIF()
#### Dist package logic ####
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|svg|tiff|mng" 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|svg|tiff|mng" EXCLUDE
REGEX "d\\." EXCLUDE
REGEX "_debug\\." 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
)
IF(APPLE)
# Accessible plugin to make buttons look decent on osx
INSTALL(
DIRECTORY "${QT_PLUGINS_DIR}/accessible"
DESTINATION ${PLUGIN_DEST_DIR}
COMPONENT Runtime
REGEX "quick" EXCLUDE
REGEX "d\\." EXCLUDE
REGEX "_debug\\." EXCLUDE
)
ENDIF()
endif()
# qtconf
INSTALL(
CODE "
FILE(WRITE \"\${CMAKE_INSTALL_PREFIX}/${QTCONF_DEST_DIR}/qt.conf\" \"\")
"
COMPONENT Runtime
)
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)
######## Package ########
# Package with CPack
IF(UNIX)
if(APPLE)
SET(CPACK_GENERATOR "ZIP")
else()
SET(CPACK_GENERATOR "TGZ")
endif()
ELSEIF(WIN32)
SET(CPACK_GENERATOR "ZIP")
ENDIF()
SET(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0)
SET(CPACK_PACKAGE_NAME "MultiMC 5")
SET(CPACK_PACKAGE_VENDOR "")
SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "MultiMC - Minecraft launcher and management tool.")
SET(CPACK_PACKAGE_VERSION "${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}.${MultiMC_VERSION_REV}.${MultiMC_VERSION_BUILD}")
SET(CPACK_PACKAGE_VERSION_MAJOR ${MultiMC_VERSION_MAJOR})
SET(CPACK_PACKAGE_VERSION_MINOR ${MultiMC_VERSION_MINOR})
SET(CPACK_PACKAGE_VERSION_PATCH ${MultiMC_VERSION_REV})
IF(CPACK_GENERATOR STREQUAL "NSIS")
SET(CPACK_PACKAGE_FILE_NAME "Setup-MultiMC")
ELSE()
SET(CPACK_PACKAGE_FILE_NAME "MultiMC")
ENDIF()
IF(WIN32)
SET(CPACK_PACKAGE_INSTALL_DIRECTORY "MultiMC 5")
ENDIF()
INCLUDE(CPack)
include_directories(${PROJECT_BINARY_DIR}/include)
### translation stuff
file (GLOB TRANSLATIONS_FILES translations/*.ts)
option (UPDATE_TRANSLATIONS "Update source translation translations/*.ts files (WARNING: make clean will delete the source .ts files! Danger!)")
IF(UPDATE_TRANSLATIONS)
qt5_create_translation(QM_FILES ${FILES_TO_TRANSLATE} ${TRANSLATIONS_FILES})
ELSE()
qt5_add_translation(QM_FILES ${TRANSLATIONS_FILES})
ENDIF()
add_custom_target (translations DEPENDS ${QM_FILES})
IF(APPLE AND UNIX) ## OSX
install(FILES ${QM_FILES} DESTINATION MultiMC.app/Contents/MacOS/translations)
ELSE()
install(FILES ${QM_FILES} DESTINATION translations)
ENDIF()
# Tests
add_subdirectory(tests)
add_subdirectory(logic)
add_subdirectory(application)
add_subdirectory(mmc_updater)

View File

@@ -1,593 +0,0 @@
#include "MultiMC.h"
#include <iostream>
#include <QDir>
#include <QFileInfo>
#include <QNetworkAccessManager>
#include <QTranslator>
#include <QLibraryInfo>
#include <QMessageBox>
#include <QStringList>
#include <QDesktopServices>
#include "gui/dialogs/VersionSelectDialog.h"
#include "logic/lists/InstanceList.h"
#include "logic/auth/MojangAccountList.h"
#include "logic/icons/IconList.h"
#include "logic/lists/LwjglVersionList.h"
#include "logic/lists/MinecraftVersionList.h"
#include "logic/lists/ForgeVersionList.h"
#include "logic/news/NewsChecker.h"
#include "logic/InstanceLauncher.h"
#include "logic/net/HttpMetaCache.h"
#include "logic/JavaUtils.h"
#include "logic/updater/UpdateChecker.h"
#include "logic/updater/NotificationChecker.h"
#include "pathutils.h"
#include "cmdutils.h"
#include <inisettingsobject.h>
#include <setting.h>
#include "logger/QsLog.h"
#include <logger/QsLogDest.h>
using namespace Util::Commandline;
MultiMC::MultiMC(int &argc, char **argv, bool root_override)
: QApplication(argc, argv), m_version{VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD,
VERSION_CHANNEL, VERSION_BUILD_TYPE}
{
setOrganizationName("MultiMC");
setApplicationName("MultiMC5");
initTranslations();
setAttribute(Qt::AA_UseHighDpiPixmaps);
// 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", applicationDirPath());
parser.addShortOpt("dir", 'd');
parser.addDocumentation("dir", "use the supplied directory as MultiMC root instead of "
"the binary location (use '.' for current)");
// WARNING: disabled until further notice
/*
// --launch
parser.addOption("launch");
parser.addShortOpt("launch", 'l');
parser.addDocumentation("launch", "tries to launch the given instance", "<inst>");
*/
// 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 " << VERSION_STR << std::endl;
std::cout << "Git " << GIT_COMMIT << std::endl;
m_status = MultiMC::Succeeded;
return;
}
}
origcwdPath = QDir::currentPath();
binPath = applicationDirPath();
QString adjustedBy;
// change directory
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
{
dataPath = applicationDirPath();
adjustedBy += "Fallback to binary path " + dataPath;
}
if(!ensureFolderPathExists(dataPath) || !QDir::setCurrent(dataPath))
{
// BAD STUFF. WHAT DO?
initLogger();
QLOG_ERROR() << "Failed to set work path. Will exit. NOW.";
m_status = MultiMC::Failed;
return;
}
if (root_override)
{
rootPath = binPath;
}
else
{
#ifdef Q_OS_LINUX
QDir foo(PathCombine(binPath, ".."));
rootPath = foo.absolutePath();
#elif defined(Q_OS_WIN32)
rootPath = binPath;
#elif defined(Q_OS_MAC)
QDir foo(PathCombine(binPath, "../.."));
rootPath = foo.absolutePath();
#endif
}
// init the logger
initLogger();
QLOG_INFO() << "MultiMC 5, (c) 2013 MultiMC Contributors";
QLOG_INFO() << "Version : " << VERSION_STR;
QLOG_INFO() << "Git commit : " << GIT_COMMIT;
if (adjustedBy.size())
{
QLOG_INFO() << "Work dir before adjustment : " << origcwdPath;
QLOG_INFO() << "Work dir after adjustment : " << QDir::currentPath();
QLOG_INFO() << "Adjusted by : " << adjustedBy;
}
else
{
QLOG_INFO() << "Work dir : " << QDir::currentPath();
}
QLOG_INFO() << "Binary path : " << binPath;
QLOG_INFO() << "Application root path : " << rootPath;
// load settings
initGlobalSettings();
// initialize the updater
m_updateChecker.reset(new UpdateChecker());
// initialize the notification checker
m_notificationChecker.reset(new NotificationChecker());
// initialize the news checker
m_newsChecker.reset(new NewsChecker(NEWS_RSS_URL));
// and instances
auto InstDirSetting = m_settings->getSetting("InstanceDir");
m_instances.reset(new InstanceList(InstDirSetting->get().toString(), this));
QLOG_INFO() << "Loading Instances...";
m_instances->loadList();
connect(InstDirSetting.get(), SIGNAL(settingChanged(const Setting &, QVariant)),
m_instances.get(), SLOT(on_InstFolderChanged(const Setting &, QVariant)));
// and accounts
m_accounts.reset(new MojangAccountList(this));
QLOG_INFO() << "Loading accounts...";
m_accounts->setListFilePath("accounts.json", true);
m_accounts->loadList();
// init the http meta cache
initHttpMetaCache();
// set up a basic autodetected proxy (system default)
QNetworkProxyFactory::setUseSystemConfiguration(true);
QLOG_INFO() << "Detecting system proxy settings...";
auto proxies = QNetworkProxyFactory::systemProxyForQuery();
if (proxies.size() == 1 && proxies[0].type() == QNetworkProxy::NoProxy)
{
QLOG_INFO() << "No proxy found.";
}
else
for (auto proxy : proxies)
{
QString proxyDesc;
if (proxy.type() == QNetworkProxy::NoProxy)
{
QLOG_INFO() << "Using no proxy is an option!";
continue;
}
switch (proxy.type())
{
case QNetworkProxy::DefaultProxy:
proxyDesc = "Default proxy: ";
break;
case QNetworkProxy::Socks5Proxy:
proxyDesc = "Socks5 proxy: ";
break;
case QNetworkProxy::HttpProxy:
proxyDesc = "HTTP proxy: ";
break;
case QNetworkProxy::HttpCachingProxy:
proxyDesc = "HTTP caching: ";
break;
case QNetworkProxy::FtpCachingProxy:
proxyDesc = "FTP caching: ";
break;
default:
proxyDesc = "DERP proxy: ";
break;
}
proxyDesc += QString("%3@%1:%2 pass %4")
.arg(proxy.hostName())
.arg(proxy.port())
.arg(proxy.user())
.arg(proxy.password());
QLOG_INFO() << proxyDesc;
}
// create the global network manager
m_qnam.reset(new QNetworkAccessManager(this));
// launch instance, if that's what should be done
// WARNING: disabled until further notice
/*
if (!args["launch"].isNull())
{
if (InstanceLauncher(args["launch"].toString()).launch())
m_status = MultiMC::Succeeded;
else
m_status = MultiMC::Failed;
return;
}
*/
connect(this, SIGNAL(aboutToQuit()), SLOT(onExit()));
m_status = MultiMC::Initialized;
}
MultiMC::~MultiMC()
{
if (m_mmc_translator)
{
removeTranslator(m_mmc_translator.get());
}
if (m_qt_translator)
{
removeTranslator(m_qt_translator.get());
}
}
void MultiMC::initTranslations()
{
m_qt_translator.reset(new QTranslator());
if (m_qt_translator->load("qt_" + QLocale::system().name(),
QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
{
std::cout << "Loading Qt Language File for "
<< QLocale::system().name().toLocal8Bit().constData() << "...";
if (!installTranslator(m_qt_translator.get()))
{
std::cout << " failed.";
m_qt_translator.reset();
}
std::cout << std::endl;
}
else
{
m_qt_translator.reset();
}
m_mmc_translator.reset(new QTranslator());
if (m_mmc_translator->load("mmc_" + QLocale::system().name(),
QDir("translations").absolutePath()))
{
std::cout << "Loading MMC Language File for "
<< QLocale::system().name().toLocal8Bit().constData() << "...";
if (!installTranslator(m_mmc_translator.get()))
{
std::cout << " failed.";
m_mmc_translator.reset();
}
std::cout << std::endl;
}
else
{
m_mmc_translator.reset();
}
}
void moveFile(const QString &oldName, const QString &newName)
{
QFile::remove(newName);
QFile::copy(oldName, newName);
QFile::remove(oldName);
}
void MultiMC::initLogger()
{
static const QString logBase = "MultiMC-%0.log";
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));
// init the logging mechanism
QsLogging::Logger &logger = QsLogging::Logger::instance();
logger.setLoggingLevel(QsLogging::TraceLevel);
m_fileDestination = QsLogging::DestinationFactory::MakeFileDestination(logBase.arg(0));
m_debugDestination = QsLogging::DestinationFactory::MakeQDebugDestination();
logger.addDestination(m_fileDestination.get());
logger.addDestination(m_debugDestination.get());
// log all the things
logger.setLoggingLevel(QsLogging::TraceLevel);
}
void MultiMC::initGlobalSettings()
{
m_settings.reset(new INISettingsObject("multimc.cfg", this));
// Updates
m_settings->registerSetting("UpdateChannel", version().channel);
m_settings->registerSetting("AutoUpdate", true);
// Notifications
m_settings->registerSetting("ShownNotifications", QString());
// FTB
m_settings->registerSetting("TrackFTBInstances", false);
#ifdef Q_OS_LINUX
QString ftbDefault = QDir::home().absoluteFilePath(".ftblauncher");
#elif defined(Q_OS_WIN32)
QString ftbDefault = PathCombine(QDir::homePath(), "AppData/Roaming/ftblauncher");
#elif defined(Q_OS_MAC)
QString ftbDefault =
PathCombine(QDir::homePath(), "Library/Application Support/ftblauncher");
#endif
m_settings->registerSetting("FTBLauncherRoot", ftbDefault);
m_settings->registerSetting("FTBRoot");
if (m_settings->get("FTBRoot").isNull())
{
QString ftbRoot;
QFile f(QDir(m_settings->get("FTBLauncherRoot").toString())
.absoluteFilePath("ftblaunch.cfg"));
QLOG_INFO() << "Attempting to read" << f.fileName();
if (f.open(QFile::ReadOnly))
{
const QString data = QString::fromLatin1(f.readAll());
QRegularExpression exp("installPath=(.*)");
ftbRoot = QDir::cleanPath(exp.match(data).captured(1));
#ifdef Q_OS_WIN32
if (!ftbRoot.isEmpty())
{
if (ftbRoot.at(0).isLetter() && ftbRoot.size() > 1 && ftbRoot.at(1) == '/')
{
ftbRoot.remove(1, 1);
}
}
#endif
if (ftbRoot.isEmpty())
{
QLOG_INFO() << "Failed to get FTB root path";
}
else
{
QLOG_INFO() << "FTB is installed at" << ftbRoot;
m_settings->set("FTBRoot", ftbRoot);
}
}
else
{
QLOG_WARN() << "Couldn't open" << f.fileName() << ":" << f.errorString();
QLOG_WARN() << "This is perfectly normal if you don't have FTB installed";
}
}
// Folders
m_settings->registerSetting("InstanceDir", "instances");
m_settings->registerSetting({"CentralModsDir", "ModsDir"}, "mods");
m_settings->registerSetting({"LWJGLDir", "LwjglDir"}, "lwjgl");
m_settings->registerSetting("IconsDir", "icons");
// Editors
m_settings->registerSetting("JsonEditor", QString());
// Console
m_settings->registerSetting("ShowConsole", true);
m_settings->registerSetting("AutoCloseConsole", true);
// Console Colors
// m_settings->registerSetting("SysMessageColor", QColor(Qt::blue));
// m_settings->registerSetting("StdOutColor", QColor(Qt::black));
// m_settings->registerSetting("StdErrColor", QColor(Qt::red));
// Window Size
m_settings->registerSetting({"LaunchMaximized", "MCWindowMaximize"}, false);
m_settings->registerSetting({"MinecraftWinWidth", "MCWindowWidth"}, 854);
m_settings->registerSetting({"MinecraftWinHeight", "MCWindowHeight"}, 480);
// Memory
m_settings->registerSetting({"MinMemAlloc", "MinMemoryAlloc"}, 512);
m_settings->registerSetting({"MaxMemAlloc", "MaxMemoryAlloc"}, 1024);
m_settings->registerSetting("PermGen", 64);
// Java Settings
m_settings->registerSetting("JavaPath", "");
m_settings->registerSetting("LastHostname", "");
m_settings->registerSetting("JvmArgs", "");
// 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", "");
}
void MultiMC::initHttpMetaCache()
{
m_metacache.reset(new HttpMetaCache("metacache"));
m_metacache->addBase("asset_indexes", QDir("assets/indexes").absolutePath());
m_metacache->addBase("asset_objects", QDir("assets/objects").absolutePath());
m_metacache->addBase("versions", QDir("versions").absolutePath());
m_metacache->addBase("libraries", QDir("libraries").absolutePath());
m_metacache->addBase("minecraftforge", QDir("mods/minecraftforge").absolutePath());
m_metacache->addBase("skins", QDir("accounts/skins").absolutePath());
m_metacache->addBase("root", QDir(root()).absolutePath());
m_metacache->Load();
}
std::shared_ptr<IconList> MultiMC::icons()
{
if (!m_icons)
{
m_icons.reset(new IconList);
}
return m_icons;
}
std::shared_ptr<LWJGLVersionList> MultiMC::lwjgllist()
{
if (!m_lwjgllist)
{
m_lwjgllist.reset(new LWJGLVersionList());
}
return m_lwjgllist;
}
std::shared_ptr<ForgeVersionList> MultiMC::forgelist()
{
if (!m_forgelist)
{
m_forgelist.reset(new ForgeVersionList());
}
return m_forgelist;
}
std::shared_ptr<MinecraftVersionList> MultiMC::minecraftlist()
{
if (!m_minecraftlist)
{
m_minecraftlist.reset(new MinecraftVersionList());
}
return m_minecraftlist;
}
std::shared_ptr<JavaVersionList> MultiMC::javalist()
{
if (!m_javalist)
{
m_javalist.reset(new JavaVersionList());
}
return m_javalist;
}
void MultiMC::installUpdates(const QString updateFilesDir, UpdateFlags flags)
{
// if we are going to update on exit, save the params now
if(flags & OnExit)
{
m_updateOnExitPath = updateFilesDir;
m_updateOnExitFlags = flags & ~OnExit;
return;
}
// otherwise if there already were some params for on exit update, clear them and continue
else if(m_updateOnExitPath.size())
{
m_updateOnExitFlags = None;
m_updateOnExitPath.clear();
}
QLOG_INFO() << "Installing updates.";
#ifdef WINDOWS
QString finishCmd = MMC->applicationFilePath();
QString updaterBinary = PathCombine(bin(), "updater.exe");
#elif LINUX
QString finishCmd = PathCombine(root(), "MultiMC");
QString updaterBinary = PathCombine(bin(), "updater");
#elif OSX
QString finishCmd = MMC->applicationFilePath();
QString updaterBinary = PathCombine(bin(), "updater");
#else
#error Unsupported operating system.
#endif
QStringList args;
// ./updater --install-dir $INSTALL_DIR --package-dir $UPDATEFILES_DIR --script
// $UPDATEFILES_DIR/file_list.xml --wait $PID --mode main
args << "--install-dir" << root();
args << "--package-dir" << updateFilesDir;
args << "--script" << PathCombine(updateFilesDir, "file_list.xml");
args << "--wait" << QString::number(MMC->applicationPid());
if(flags & DryRun)
args << "--dry-run";
if (flags & RestartOnFinish)
{
args << "--finish-cmd" << finishCmd;
args << "--finish-dir" << data();
}
QLOG_INFO() << "Running updater with command" << updaterBinary << args.join(" ");
QFile::setPermissions(updaterBinary, (QFileDevice::Permission)0x7755);
if (!QProcess::startDetached(updaterBinary, args/*, root()*/))
{
QLOG_ERROR() << "Failed to start the updater process!";
return;
}
// Now that we've started the updater, quit MultiMC.
MMC->quit();
}
void MultiMC::onExit()
{
if(m_updateOnExitPath.size())
{
installUpdates(m_updateOnExitPath, m_updateOnExitFlags);
}
}
bool MultiMC::openJsonEditor(const QString &filename)
{
const QString file = QDir::current().absoluteFilePath(filename);
if (m_settings->get("JsonEditor").toString().isEmpty())
{
return QDesktopServices::openUrl(QUrl::fromLocalFile(file));
}
else
{
return QProcess::startDetached(m_settings->get("JsonEditor").toString(), QStringList()
<< file);
}
}
#include "MultiMC.moc"

Binary file not shown.

View File

@@ -1,75 +0,0 @@
/* Copyright 2013 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <QString>
/*!
* \brief The Version class represents a MultiMC version number.
*/
struct MultiMCVersion
{
/*!
* \brief Converts the Version to a string.
* \return The version number in string format (major.minor.revision.build).
*/
QString toString() const
{
QString vstr = QString("5.%1.%2").arg(
QString::number(major),
QString::number(minor));
if (build >= 0) vstr += "." + QString::number(build);
if (!channel.isEmpty()) vstr += "-" + channel;
if (!buildType.isEmpty()) vstr += "-" + buildType;
return vstr;
}
/*!
* \brief The major version number.
* This is no longer going to always be 5 for MultiMC 5. Doing so is useless.
* Instead, we'll be starting major off at 1 and incrementing it with every major feature.
*/
int major;
/*!
* \brief The minor version number.
* This number is incremented for major features and bug fixes.
*/
int minor;
/*!
* \brief The build number.
* This number is automatically set by Buildbot it is set to the build number of the buildbot
* build that this build came from.
* If this build didn't come from buildbot and no build number was given to CMake, this will default
* to -1, causing it to not show in this version's string representation.
*/
int build;
/*!
* \brief This build's channel.
*/
QString channel;
/*!
* \brief The build type.
* This indicates the type of build that this is. For example, lin64 or custombuild.
*/
QString buildType;
};

View File

@@ -1,15 +1,15 @@
![MultiMC](http://i.imgur.com/QJXbz.png)
MultiMC 5
MultiMC 5 [![Build Status](https://travis-ci.org/MultiMC/MultiMC5.svg?branch=develop)](https://travis-ci.org/MultiMC/MultiMC5) [![Translation Status](http://weblate.robotbrain.info/widgets/multimc/-/shields-badge.svg)](http://weblate.robotbrain.info/engage/multimc/?utm_source=widget) [![Stories in Ready](https://badge.waffle.io/MultiMC/MultiMC5.svg?label=ready&title=Ready)](http://waffle.io/MultiMC/MultiMC5)
=========
MultiMC is a custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once. It also allows you to easily install and remove mods by simply dragging and dropping.
MultiMC is a custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once. It also allows you to easily install and remove mods by simply dragging and dropping. Here are the current [features](https://github.com/MultiMC/MultiMC5/wiki#features) of MultiMC.
## Building
Check [BUILD.md](BUILD.md) for build instructions.
## Contributing
The repository is currently managed by @peterix and @drayshak - we're the ones likely to review pull requests. If you'd like to contribute to the project please talk to us on IRC (Esper/#MultiMC) first! This helps us organise ideas and keep in contact with you, and we're unlikely to accept anything blindly.
The repository is currently managed by @peterix. If you'd like to contribute to the project please talk to us on IRC (Esper/#MultiMC) first! This helps us organise ideas and keep in contact with you, and we're unlikely to accept anything blindly.
We use [Clang Format](http://clang.llvm.org/docs/ClangFormat.html) to format the project. We highly recommend setting it up so the project stays well formatted, but there are issues with it on Windows. If you have trouble setting it up, check [.clang-format](.clang-format) manually. We don't accept pull requests with poor formatting. If you have questions, talk to us on IRC (Esper/#MultiMC) _before_ submitting a pull request.
@@ -22,7 +22,7 @@ Apache covers reasonable use for the name - a mention of the project's origins i
## License
Copyright &copy; 2013 MultiMC Contributors
Copyright &copy; 2013-2015 MultiMC Contributors
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this program except in compliance with the License. You may obtain a copy of the License at [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0).

View File

@@ -0,0 +1,56 @@
#include "BuildConfig.h"
#include <QObject>
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@;
VERSION_CHANNEL = "@MultiMC_VERSION_CHANNEL@";
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@";
UPDATER_DRY_RUN = @MultiMC_UPDATER_DRY_RUN_value@;
UPDATER_FORCE_LOCAL = @MultiMC_UPDATER_FORCE_LOCAL_value@;
GIT_COMMIT = "@MultiMC_GIT_COMMIT@";
VERSION_STR = "@MultiMC_VERSION_STRING@";
NEWS_RSS_URL = "@MultiMC_NEWS_RSS_URL@";
}
QString Config::printableVersionString() const
{
QString vstr = QString("%1.%2").arg(QString::number(VERSION_MAJOR), QString::number(VERSION_MINOR));
if (VERSION_HOTFIX > 0) vstr += "." + QString::number(VERSION_HOTFIX);
// If the build is a development build or release candidate, add that info to the end.
if(VERSION_CHANNEL == "stable")
{
return vstr;
}
else if(VERSION_CHANNEL == "develop")
{
vstr += "-dev-" + QString::number(VERSION_BUILD);
}
else if(VERSION_CHANNEL == "unstable")
{
vstr += "-nuke-" + QString::number(VERSION_BUILD);
}
else if(VERSION_CHANNEL == "custom")
{
vstr += "-local";
}
else
{
vstr += "-" + VERSION_CHANNEL + "-" + QString::number(VERSION_BUILD);
}
return vstr;
}

63
application/BuildConfig.h Normal file
View File

@@ -0,0 +1,63 @@
#pragma once
#include <QString>
/**
* \brief The Config class holds all the build-time information passed from the build system.
*/
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;
/**
* The version channel
* This is used by the updater to determine what channel the current version came from.
*/
QString VERSION_CHANNEL;
/// 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 notifications
QString NOTIFICATION_URL;
/// Used for matching notifications
QString FULL_VERSION_STR;
/// enabled for updater dry run
bool UPDATER_DRY_RUN;
/// enabled for updater dry run
bool UPDATER_FORCE_LOCAL;
/// The commit hash of this build
QString GIT_COMMIT;
/// 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;
/**
* \brief Converts the Version to a string.
* \return The version number in string format (major.minor.revision.build).
*/
QString printableVersionString() const;
};
extern Config BuildConfig;

494
application/CMakeLists.txt Normal file
View File

@@ -0,0 +1,494 @@
project(MultiMC-Application)
######## Set URLs ########
set(MultiMC_NEWS_RSS_URL "http://multimc.org/rss.xml" CACHE STRING "URL to fetch MultiMC's news RSS feed from.")
######## Set version numbers ########
set(MultiMC_VERSION_MAJOR 0)
set(MultiMC_VERSION_MINOR 4)
set(MultiMC_VERSION_HOTFIX 7)
# Build number
set(MultiMC_VERSION_BUILD -1 CACHE STRING "Build number. -1 for no build number.")
# Version type
set(MultiMC_VERSION_TYPE "Custom" CACHE STRING "MultiMC's version type. This should be one of 'Custom', 'Release', 'ReleaseCandidate', or 'Development', depending on what type of version this is.")
# Build platform.
set(MultiMC_BUILD_PLATFORM "" CACHE STRING "A short string identifying the platform that this build was built for. Only used by the notification system and to display in the about dialog.")
# Version channel
set(MultiMC_VERSION_CHANNEL "" CACHE STRING "The current build's channel. Included in the version string.")
# Channel list URL
set(MultiMC_CHANLIST_URL "" CACHE STRING "URL for the channel list.")
# Updater enabled?
set(MultiMC_UPDATER false CACHE BOOL "Whether or not the update system is enabled. If this is enabled, you must also set MultiMC_CHANLIST_URL and MultiMC_VERSION_CHANNEL in order for it to work properly.")
# Notification URL
set(MultiMC_NOTIFICATION_URL "" CACHE STRING "URL for checking for notifications.")
#### Check the current Git commit
include(GitFunctions)
git_run(COMMAND rev-parse HEAD DEFAULT "Unknown" OUTPUT_VAR MultiMC_GIT_COMMIT)
message(STATUS "Git commit: ${MultiMC_GIT_COMMIT}")
set(MultiMC_RELEASE_VERSION_NAME "${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}")
if(MultiMC_VERSION_HOTFIX GREATER 0)
set(MultiMC_RELEASE_VERSION_NAME "${MultiMC_RELEASE_VERSION_NAME}.${MultiMC_VERSION_HOTFIX}")
endif()
# Build a version string to display in the configure logs.
if(MultiMC_VERSION_TYPE STREQUAL "Custom")
message(STATUS "Version Type: Custom")
set(MultiMC_VERSION_STRING "${MultiMC_RELEASE_VERSION_NAME}")
elseif(MultiMC_VERSION_TYPE STREQUAL "Release")
message(STATUS "Version Type: Stable Release")
set(MultiMC_VERSION_STRING "${MultiMC_RELEASE_VERSION_NAME}")
elseif(MultiMC_VERSION_TYPE STREQUAL "Development")
message(STATUS "Version Type: Development")
set(MultiMC_VERSION_STRING "${MultiMC_RELEASE_VERSION_NAME}-dev${MultiMC_VERSION_BUILD}")
else()
message(ERROR "Invalid build type.")
endif()
message(STATUS "MultiMC 5 Version: ${MultiMC_VERSION_STRING}")
#### Custom target to just print the version.
add_custom_target(version echo "Version: ${MultiMC_VERSION_STRING}")
# If the update system is enabled, make sure MultiMC_CHANLIST_URL and MultiMC_VERSION_CHANNEL are set.
if(MultiMC_UPDATER)
if(MultiMC_VERSION_CHANNEL STREQUAL "")
message(FATAL_ERROR "Update system is enabled, but MultiMC_VERSION_CHANNEL is not set.\n"
"Please ensure the CMake variables MultiMC_VERSION_CHANNEL, MultiMC_CHANLIST_URL, and MultiMC_VERSION_BUILD are set.")
endif()
if(MultiMC_CHANLIST_URL STREQUAL "")
message(FATAL_ERROR "Update system is enabled, but MultiMC_CHANLIST_URL is not set.\n"
"Please ensure the CMake variables MultiMC_VERSION_CHANNEL, MultiMC_CHANLIST_URL, and MultiMC_VERSION_BUILD are set.")
endif()
if(MultiMC_VERSION_BUILD LESS 0)
message(FATAL_ERROR "Update system is enabled, but MultiMC_VERSION_BUILD is not set.\n"
"Please ensure the CMake variables MultiMC_VERSION_CHANNEL, MultiMC_CHANLIST_URL, and MultiMC_VERSION_BUILD are set.")
endif()
message(STATUS "Updater is enabled. Channel list URL: ${MultiMC_CHANLIST_URL}")
endif()
#### Updater-related build config options ####
option(MultiMC_UPDATER_DRY_RUN "Enable updater dry-run mode -- for updater development." OFF)
option(MultiMC_UPDATER_FORCE_LOCAL "Do not download updated updater -- for updater development." OFF)
if(MultiMC_UPDATER_DRY_RUN)
set(MultiMC_UPDATER_DRY_RUN_value "true")
else()
set(MultiMC_UPDATER_DRY_RUN_value "false")
endif()
if(MultiMC_UPDATER_FORCE_LOCAL)
set(MultiMC_UPDATER_FORCE_LOCAL_value "true")
else()
set(MultiMC_UPDATER_FORCE_LOCAL_value "false")
endif()
######## Configure header ########
configure_file("${PROJECT_SOURCE_DIR}/BuildConfig.cpp.in" "${PROJECT_BINARY_DIR}/BuildConfig.cpp")
######## Packaging/install paths setup ########
if(UNIX AND APPLE)
set(BINARY_DEST_DIR MultiMC.app/Contents/MacOS)
set(PLUGIN_DEST_DIR MultiMC.app/Contents/MacOS)
set(QTCONF_DEST_DIR MultiMC.app/Contents/Resources)
set(APPS "\${CMAKE_INSTALL_PREFIX}/MultiMC.app")
set(MACOSX_BUNDLE_BUNDLE_NAME "MultiMC")
set(MACOSX_BUNDLE_INFO_STRING "MultiMC Minecraft launcher and management utility.")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.multimc.MultiMC5")
set(MACOSX_BUNDLE_BUNDLE_VERSION "${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}.${MultiMC_VERSION_HOTFIX}.${MultiMC_VERSION_BUILD}")
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}.${MultiMC_VERSION_HOTFIX}.${MultiMC_VERSION_BUILD}")
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}.${MultiMC_VERSION_HOTFIX}.${MultiMC_VERSION_BUILD}")
set(MACOSX_BUNDLE_ICON_FILE MultiMC.icns)
set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2015 MultiMC Contributors")
elseif(UNIX)
set(BINARY_DEST_DIR bin)
set(PLUGIN_DEST_DIR plugins)
set(QTCONF_DEST_DIR .)
set(APPS "\${CMAKE_INSTALL_PREFIX}/bin/MultiMC")
elseif(WIN32)
set(BINARY_DEST_DIR .)
set(PLUGIN_DEST_DIR .)
set(QTCONF_DEST_DIR .)
set(APPS "\${CMAKE_INSTALL_PREFIX}/MultiMC.exe")
endif()
# directories to look for dependencies
set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR})
################################ FILES ################################
######## Sources and headers ########
SET(MULTIMC_SOURCES
# Application base
main.cpp
MultiMC.h
MultiMC.cpp
BuildConfig.h
${PROJECT_BINARY_DIR}/BuildConfig.cpp
# GUI - general utilities
GuiUtil.h
GuiUtil.cpp
ColumnResizer.h
ColumnResizer.cpp
InstanceProxyModel.h
InstanceProxyModel.cpp
VersionProxyModel.h
VersionProxyModel.cpp
# GUI - windows
MainWindow.h
MainWindow.cpp
ConsoleWindow.h
ConsoleWindow.cpp
# page provider for instances
InstancePageProvider.h
InstancePageProvider.cpp
# Common java checking UI
JavaCommon.h
JavaCommon.cpp
# GUI - page dialog pages
pages/BasePage.h
pages/BasePageContainer.h
pages/VersionPage.cpp
pages/VersionPage.h
pages/TexturePackPage.h
pages/ResourcePackPage.h
pages/ModFolderPage.cpp
pages/ModFolderPage.h
pages/NotesPage.cpp
pages/NotesPage.h
pages/LogPage.cpp
pages/LogPage.h
pages/InstanceSettingsPage.cpp
pages/InstanceSettingsPage.h
pages/ScreenshotsPage.cpp
pages/ScreenshotsPage.h
pages/OtherLogsPage.cpp
pages/OtherLogsPage.h
pages/LegacyJarModPage.cpp
pages/LegacyJarModPage.h
pages/LegacyUpgradePage.cpp
pages/LegacyUpgradePage.h
# GUI - global settings pages
pages/global/AccountListPage.cpp
pages/global/AccountListPage.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
# GUI - dialogs
dialogs/AboutDialog.cpp
dialogs/AboutDialog.h
dialogs/AccountSelectDialog.cpp
dialogs/AccountSelectDialog.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/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
# GUI - widgets
widgets/Common.cpp
widgets/Common.h
widgets/IconLabel.cpp
widgets/IconLabel.h
widgets/LabeledToolButton.cpp
widgets/LabeledToolButton.h
widgets/LineSeparator.cpp
widgets/LineSeparator.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
# 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
)
######## UIs ########
SET(MULTIMC_UIS
# Option pages
pages/VersionPage.ui
pages/ModFolderPage.ui
pages/LogPage.ui
pages/InstanceSettingsPage.ui
pages/NotesPage.ui
pages/ScreenshotsPage.ui
pages/OtherLogsPage.ui
pages/LegacyJarModPage.ui
pages/LegacyUpgradePage.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
# Dialogs
dialogs/CopyInstanceDialog.ui
dialogs/NewInstanceDialog.ui
dialogs/AboutDialog.ui
dialogs/VersionSelectDialog.ui
dialogs/ProgressDialog.ui
dialogs/IconPickerDialog.ui
dialogs/AccountSelectDialog.ui
dialogs/EditAccountDialog.ui
dialogs/ExportInstanceDialog.ui
dialogs/LoginDialog.ui
dialogs/UpdateDialog.ui
dialogs/NotificationDialog.ui
# Widgets/other
widgets/MCModInfoFrame.ui
)
set(MULTIMC_QRCS
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/instances/instances.qrc
resources/versions/versions.qrc
resources/certs/certs.qrc
)
######## Windows resource files ########
if(WIN32)
set(MULTIMC_RCS resources/multimc.rc)
endif()
####### X11 Stuff #######
if(UNIX AND NOT APPLE)
find_package(Qt5X11Extras REQUIRED)
set(MultiMC_LINK_ADDITIONAL_LIBS ${MultiMC_LINK_ADDITIONAL_LIBS} xcb Qt5::X11Extras)
list(APPEND MULTIMC_SOURCES Platform_X11.cpp)
else()
list(APPEND MULTIMC_SOURCES Platform_Other.cpp)
endif()
# Link additional libraries
if(WIN32)
set(MultiMC_LINK_ADDITIONAL_LIBS ${MultiMC_LINK_ADDITIONAL_LIBS} Qt5::WinMain)
endif(WIN32)
include_directories(../logic)
# Qt 5 stuff
qt5_wrap_ui(MULTIMC_UI ${MULTIMC_UIS})
qt5_add_resources(MULTIMC_RESOURCES ${MULTIMC_QRCS})
# Add executable
add_executable(MultiMC MACOSX_BUNDLE WIN32 ${MULTIMC_SOURCES} ${MULTIMC_UI} ${MULTIMC_RESOURCES} ${MULTIMC_RCS})
target_link_libraries(MultiMC MultiMC_logic xz-embedded unpack200 iconfix libUtil LogicalGui
${QUAZIP_LIBRARIES} Qt5::Core Qt5::Xml Qt5::Widgets Qt5::Network Qt5::Concurrent
hoedown
${MultiMC_LINK_ADDITIONAL_LIBS})
################################ INSTALLATION AND PACKAGING ################################
######## Install ########
#### Executable ####
if(APPLE AND UNIX) ## OSX
install(TARGETS MultiMC
BUNDLE DESTINATION . COMPONENT Runtime
RUNTIME DESTINATION MultiMC.app/Contents/MacOS COMPONENT Runtime
)
elseif(UNIX) ## LINUX and similar
install(TARGETS MultiMC
BUNDLE DESTINATION . COMPONENT Runtime
RUNTIME DESTINATION bin COMPONENT Runtime
)
install(PROGRAMS package/linux/MultiMC DESTINATION .)
elseif(WIN32) ## WINDOWS
install(TARGETS MultiMC
BUNDLE DESTINATION . COMPONENT Runtime
LIBRARY DESTINATION . COMPONENT Runtime
RUNTIME DESTINATION . COMPONENT Runtime
)
endif()
#### Java bits ####
install_jar(JavaCheck "${BINARY_DEST_DIR}/jars")
install_jar(NewLaunch "${BINARY_DEST_DIR}/jars")
#### Dist package logic ####
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" 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" EXCLUDE
REGEX "d\\." EXCLUDE
REGEX "_debug\\." EXCLUDE
)
# Icon engines
install(
DIRECTORY "${QT_PLUGINS_DIR}/iconengines"
DESTINATION ${PLUGIN_DEST_DIR}
COMPONENT Runtime
REGEX "fontawesome" EXCLUDE
REGEX "d\\." EXCLUDE
REGEX "_debug\\." 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
)
if(APPLE)
# Accessible plugin to make buttons look decent on osx
install(
DIRECTORY "${QT_PLUGINS_DIR}/accessible"
DESTINATION ${PLUGIN_DEST_DIR}
COMPONENT Runtime
REGEX "quick" EXCLUDE
REGEX "d\\." EXCLUDE
REGEX "_debug\\." EXCLUDE
)
endif()
endif()
# qtconf
install(
CODE "
file(WRITE \"\${CMAKE_INSTALL_PREFIX}/${QTCONF_DEST_DIR}/qt.conf\" \"\")
"
COMPONENT Runtime
)
# ICNS file for OS X
if(APPLE)
install(FILES resources/MultiMC.icns DESTINATION MultiMC.app/Contents/Resources)
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)
######## Package ########
# Package with CPack
if(UNIX)
if(APPLE)
set(CPACK_GENERATOR "ZIP")
else()
set(CPACK_GENERATOR "TGZ")
endif()
elseif(WIN32)
set(CPACK_GENERATOR "ZIP")
endif()
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0)
set(CPACK_PACKAGE_NAME "MultiMC 5")
set(CPACK_PACKAGE_VENDOR "")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "MultiMC - Minecraft launcher and management tool.")
set(CPACK_PACKAGE_VERSION "${MultiMC_VERSION_MAJOR}.${MultiMC_VERSION_MINOR}.${MultiMC_VERSION_REV}.${MultiMC_VERSION_BUILD}")
set(CPACK_PACKAGE_VERSION_MAJOR ${MultiMC_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${MultiMC_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${MultiMC_VERSION_REV})
set(CPACK_PACKAGE_FILE_NAME "MultiMC")
include(CPack)

View File

@@ -0,0 +1,202 @@
/*
* Copyright 2011 Aurélien Gâteau <agateau@kde.org>
* License: LGPL v2.1 or later (see COPYING)
*/
#include "ColumnResizer.h"
#include <QDebug>
#include <QEvent>
#include <QFormLayout>
#include <QGridLayout>
#include <QTimer>
#include <QWidget>
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;
}
private:
int m_width;
QFormLayout* m_formLayout;
QFormLayout::ItemRole m_itemRole;
};
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;
};
ColumnResizer::ColumnResizer(QObject* parent)
: QObject(parent)
, d(new ColumnResizerPrivate(this))
{}
ColumnResizer::~ColumnResizer()
{
delete d;
}
void ColumnResizer::addWidget(QWidget* widget)
{
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);
}
}
bool ColumnResizer::eventFilter(QObject*, QEvent* event)
{
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;
}
}
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);
}
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;
}
}
#include <ColumnResizer.moc>
// vi: ts=4 sw=4 et

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2011 Aurélien Gâteau <agateau@kde.org>
* License: LGPL v2.1 or later (see COPYING)
*/
#pragma once
#include <QFormLayout>
#include <QtCore/QObject>
#include <QtCore/QList>
class QEvent;
class QGridLayout;
class QLayout;
class QWidget;
class ColumnResizerPrivate;
class ColumnResizer : public QObject
{
Q_OBJECT
public:
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);
private Q_SLOTS:
void updateWidth();
protected:
bool eventFilter(QObject*, QEvent* event);
private:
ColumnResizerPrivate* const d;
};

View File

@@ -0,0 +1,260 @@
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ConsoleWindow.h"
#include "MultiMC.h"
#include <QScrollBar>
#include <QMessageBox>
#include <QSystemTrayIcon>
#include <QHBoxLayout>
#include <QPushButton>
#include <qlayoutitem.h>
#include <QCloseEvent>
#include <Platform.h>
#include <dialogs/CustomMessageBox.h>
#include <dialogs/ProgressDialog.h>
#include "widgets/PageContainer.h"
#include "pages/LogPage.h"
#include "InstancePageProvider.h"
#include "icons/IconList.h"
class LogPageProvider : public BasePageProvider
{
public:
LogPageProvider(BasePageProviderPtr parent, BasePage * log_page)
{
m_parent = parent;
m_log_page = log_page;
}
virtual QString dialogTitle() {return "Fake";};
virtual QList<BasePage *> getPages()
{
auto pages = m_parent->getPages();
pages.prepend(m_log_page);
return pages;
}
private:
BasePageProviderPtr m_parent;
BasePage * m_log_page;
};
ConsoleWindow::ConsoleWindow(BaseProcess *process, QWidget *parent)
: QMainWindow(parent), m_proc(process)
{
MultiMCPlatform::fixWM_CLASS(this);
setAttribute(Qt::WA_DeleteOnClose);
auto instance = m_proc->instance();
auto icon = ENV.icons()->getIcon(instance->iconKey());
QString windowTitle = tr("Console window for ") + instance->name();
// Set window properties
{
setWindowIcon(icon);
setWindowTitle(windowTitle);
}
// Add page container
{
auto mainLayout = new QVBoxLayout;
auto provider = std::make_shared<InstancePageProvider>(m_proc->instance());
auto baseprovider = std::dynamic_pointer_cast<BasePageProvider>(provider);
auto proxy_provider = std::make_shared<LogPageProvider>(baseprovider, new LogPage(m_proc));
m_container = new PageContainer(proxy_provider, "console", this);
mainLayout->addWidget(m_container);
mainLayout->setSpacing(0);
mainLayout->setContentsMargins(0,0,0,0);
setLayout(mainLayout);
setCentralWidget(m_container);
}
// Add custom buttons to the page container layout.
{
auto horizontalLayout = new QHBoxLayout();
horizontalLayout->setObjectName(QStringLiteral("horizontalLayout"));
horizontalLayout->setContentsMargins(6, -1, 6, -1);
auto btnHelp = new QPushButton();
btnHelp->setText(tr("Help"));
horizontalLayout->addWidget(btnHelp);
connect(btnHelp, SIGNAL(clicked(bool)), m_container, SLOT(help()));
auto spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
horizontalLayout->addSpacerItem(spacer);
m_killButton = new QPushButton();
m_killButton->setText(tr("Kill Minecraft"));
horizontalLayout->addWidget(m_killButton);
connect(m_killButton, SIGNAL(clicked(bool)), SLOT(on_btnKillMinecraft_clicked()));
m_closeButton = new QPushButton();
m_closeButton->setText(tr("Close"));
horizontalLayout->addWidget(m_closeButton);
connect(m_closeButton, SIGNAL(clicked(bool)), SLOT(on_closeButton_clicked()));
m_container->addButtons(horizontalLayout);
}
// restore window state
{
auto base64State = MMC->settings()->get("ConsoleWindowState").toByteArray();
restoreState(QByteArray::fromBase64(base64State));
auto base64Geometry = MMC->settings()->get("ConsoleWindowGeometry").toByteArray();
restoreGeometry(QByteArray::fromBase64(base64Geometry));
}
// Set up tray icon
{
m_trayIcon = new QSystemTrayIcon(icon, this);
m_trayIcon->setToolTip(windowTitle);
connect(m_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
m_trayIcon->show();
}
// Set up signal connections
connect(m_proc, SIGNAL(ended(InstancePtr, int, QProcess::ExitStatus)), this,
SLOT(onEnded(InstancePtr, int, QProcess::ExitStatus)));
connect(m_proc, SIGNAL(prelaunch_failed(InstancePtr, int, QProcess::ExitStatus)), this,
SLOT(onEnded(InstancePtr, int, QProcess::ExitStatus)));
connect(m_proc, SIGNAL(launch_failed(InstancePtr)), this,
SLOT(onLaunchFailed(InstancePtr)));
setMayClose(false);
if (m_proc->instance()->settings()->get("ShowConsole").toBool())
{
show();
}
}
void ConsoleWindow::iconActivated(QSystemTrayIcon::ActivationReason reason)
{
switch (reason)
{
case QSystemTrayIcon::Trigger:
{
toggleConsole();
}
default:
return;
}
}
void ConsoleWindow::on_closeButton_clicked()
{
close();
}
void ConsoleWindow::setMayClose(bool mayclose)
{
if(mayclose)
m_closeButton->setText(tr("Close"));
else
m_closeButton->setText(tr("Hide"));
m_mayclose = mayclose;
}
void ConsoleWindow::toggleConsole()
{
if (isVisible())
{
if(!isActiveWindow())
{
activateWindow();
return;
}
hide();
}
else
{
show();
}
}
void ConsoleWindow::closeEvent(QCloseEvent *event)
{
if (!m_mayclose)
{
toggleConsole();
event->ignore();
}
else if(m_container->requestClose(event))
{
MMC->settings()->set("ConsoleWindowState", saveState().toBase64());
MMC->settings()->set("ConsoleWindowGeometry", saveGeometry().toBase64());
emit isClosing();
m_trayIcon->hide();
event->accept();
}
}
void ConsoleWindow::on_btnKillMinecraft_clicked()
{
m_killButton->setEnabled(false);
auto response = CustomMessageBox::selectable(
this, tr("Kill Minecraft?"),
tr("This can cause the instance to get corrupted and should only be used if Minecraft "
"is frozen for some reason"),
QMessageBox::Question, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)->exec();
if (response == QMessageBox::Yes)
m_proc->killProcess();
else
m_killButton->setEnabled(true);
}
void ConsoleWindow::onEnded(InstancePtr instance, int code, QProcess::ExitStatus status)
{
bool peacefulExit = code == 0 && status != QProcess::CrashExit;
m_killButton->setEnabled(false);
setMayClose(true);
if (instance->settings()->get("AutoCloseConsole").toBool())
{
if (peacefulExit)
{
this->close();
return;
}
}
if (!isVisible())
{
show();
}
// Raise Window
if (MMC->settings()->get("RaiseConsole").toBool())
{
raise();
activateWindow();
}
}
void ConsoleWindow::onLaunchFailed(InstancePtr instance)
{
m_killButton->setEnabled(false);
setMayClose(true);
if (!isVisible())
show();
}
ConsoleWindow::~ConsoleWindow()
{
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,20 +16,18 @@
#pragma once
#include <QMainWindow>
#include "logic/MinecraftProcess.h"
namespace Ui
{
class ConsoleWindow;
}
#include <QSystemTrayIcon>
#include "BaseProcess.h"
class QPushButton;
class PageContainer;
class ConsoleWindow : public QMainWindow
{
Q_OBJECT
public:
explicit ConsoleWindow(MinecraftProcess *proc, QWidget *parent = 0);
~ConsoleWindow();
explicit ConsoleWindow(BaseProcess *proc, QWidget *parent = 0);
virtual ~ConsoleWindow();
/**
* @brief specify if the window is allowed to close
@@ -38,53 +36,30 @@ public:
*/
void setMayClose(bool mayclose);
private:
/**
* @brief write a colored paragraph
* @param data the string
* @param color the css color name
* this will only insert a single paragraph.
* \n are ignored. a real \n is always appended.
*/
void writeColor(QString data, const char *color = nullptr);
signals:
void isClosing();
public
slots:
/**
* @brief write a string
* @param data the string
* @param mode the WriteMode
* lines have to be put through this as a whole!
*/
void write(QString data, MessageLevel::Enum level = MessageLevel::MultiMC);
/**
* @brief clear the text widget
*/
void clear();
private
slots:
void on_closeButton_clicked();
void on_btnKillMinecraft_clicked();
void onEnded(BaseInstance *instance, int code, QProcess::ExitStatus status);
void onLaunchFailed(BaseInstance *instance);
void onEnded(InstancePtr instance, int code, QProcess::ExitStatus status);
void onLaunchFailed(InstancePtr instance);
// FIXME: add handlers for the other MinecraftProcess signals (pre/post launch command
// failures)
void on_btnPaste_clicked();
void iconActivated(QSystemTrayIcon::ActivationReason);
void toggleConsole();
protected:
void closeEvent(QCloseEvent *);
private:
Ui::ConsoleWindow *ui = nullptr;
MinecraftProcess *proc = nullptr;
BaseProcess *m_proc = nullptr;
bool m_mayclose = true;
int m_last_scroll_value = 0;
bool m_scroll_active = true;
QSystemTrayIcon *m_trayIcon = nullptr;
PageContainer *m_container = nullptr;
QPushButton *m_closeButton = nullptr;
QPushButton *m_killButton = nullptr;
};

101
application/GuiUtil.cpp Normal file
View File

@@ -0,0 +1,101 @@
#include "GuiUtil.h"
#include <QClipboard>
#include <QDesktopServices>
#include <QApplication>
#include <QFileDialog>
#include "dialogs/ProgressDialog.h"
#include "net/PasteUpload.h"
#include "dialogs/CustomMessageBox.h"
#include "MultiMC.h"
#include <settings/SettingsObject.h>
void GuiUtil::uploadPaste(const QString &text, QWidget *parentWidget)
{
ProgressDialog dialog(parentWidget);
std::unique_ptr<PasteUpload> paste(new PasteUpload(parentWidget, text));
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;
}
dialog.exec(paste.get());
if (!paste->successful())
{
CustomMessageBox::selectable(parentWidget, QObject::tr("Upload failed"),
paste->failReason(), QMessageBox::Critical)->exec();
}
else
{
const QString link = paste->pasteLink();
setClipboardText(link);
QDesktopServices::openUrl(link);
CustomMessageBox::selectable(
parentWidget, QObject::tr("Upload finished"),
QObject::tr("The <a href=\"%1\">link to the uploaded log</a> has been opened in "
"the default "
"browser and placed in your clipboard.").arg(link),
QMessageBox::Information)->exec();
}
}
void GuiUtil::setClipboardText(const QString &text)
{
QApplication::clipboard()->setText(text);
}
QStringList GuiUtil::BrowseForMods(QString context, QString caption, QString filter,
QWidget *parentWidget)
{
static QMap<QString, QString> savedPaths;
QFileDialog w(parentWidget, caption);
QSet<QString> locations;
QString modsFolder = MMC->settings()->get("CentralModsDir").toString();
auto f = [&](QStandardPaths::StandardLocation l)
{
QString location = QStandardPaths::writableLocation(l);
QFileInfo finfo(location);
if (!finfo.exists())
return;
locations.insert(location);
};
f(QStandardPaths::DesktopLocation);
f(QStandardPaths::DocumentsLocation);
f(QStandardPaths::DownloadLocation);
f(QStandardPaths::HomeLocation);
QList<QUrl> urls;
for (auto location : locations)
{
urls.append(QUrl::fromLocalFile(location));
}
urls.append(QUrl::fromLocalFile(modsFolder));
w.setFileMode(QFileDialog::ExistingFiles);
w.setAcceptMode(QFileDialog::AcceptOpen);
w.setNameFilter(filter);
if(savedPaths.contains(context))
{
w.setDirectory(savedPaths[context]);
}
else
{
w.setDirectory(modsFolder);
}
w.setSidebarUrls(urls);
if (w.exec())
{
savedPaths[context] = w.directory().absolutePath();
return w.selectedFiles();
}
savedPaths[context] = w.directory().absolutePath();
return {};
}

10
application/GuiUtil.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
#include <QWidget>
namespace GuiUtil
{
void uploadPaste(const QString &text, QWidget *parentWidget);
void setClipboardText(const QString &text);
QStringList BrowseForMods(QString context, QString caption, QString filter, QWidget *parentWidget);
}

View File

View File

@@ -0,0 +1,73 @@
#pragma once
#include "minecraft/OneSixInstance.h"
#include "minecraft/LegacyInstance.h"
#include "pages/BasePage.h"
#include "pages/VersionPage.h"
#include "pages/ModFolderPage.h"
#include "pages/ResourcePackPage.h"
#include "pages/TexturePackPage.h"
#include "pages/NotesPage.h"
#include "pages/ScreenshotsPage.h"
#include "pages/InstanceSettingsPage.h"
#include "pages/OtherLogsPage.h"
#include "pages/BasePageProvider.h"
#include "pages/LegacyJarModPage.h"
#include <pathutils.h>
class InstancePageProvider : public QObject, public BasePageProvider
{
Q_OBJECT
public:
explicit InstancePageProvider(InstancePtr parent)
{
inst = parent;
}
virtual ~InstancePageProvider() {};
virtual QList<BasePage *> getPages() override
{
QList<BasePage *> values;
std::shared_ptr<OneSixInstance> onesix = std::dynamic_pointer_cast<OneSixInstance>(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(tr("%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 ScreenshotsPage(PathCombine(onesix->minecraftRoot(), "screenshots")));
values.append(new InstanceSettingsPage(onesix.get()));
values.append(new OtherLogsPage(onesix->minecraftRoot()));
}
std::shared_ptr<LegacyInstance> legacy = std::dynamic_pointer_cast<LegacyInstance>(inst);
if(legacy)
{
QList<BasePage *> values;
// FIXME: actually implement the legacy instance upgrade, then enable this.
//values.append(new LegacyUpgradePage(this));
values.append(new LegacyJarModPage(legacy.get()));
auto modsPage = new ModFolderPage(legacy.get(), legacy->loaderModList(), "mods", "loadermods", tr("Loader mods"), "Loader-mods");
modsPage->setFilter(tr("%1 (*.zip *.jar *.litemod)"));
values.append(modsPage);
values.append(new ModFolderPage(legacy.get(), legacy->coreModList(), "coremods", "coremods", tr("Core mods"), "Loader-mods"));
values.append(new TexturePackPage(legacy.get()));
values.append(new NotesPage(legacy.get()));
values.append(new ScreenshotsPage(PathCombine(legacy->minecraftRoot(), "screenshots")));
values.append(new InstanceSettingsPage(legacy.get()));
values.append(new OtherLogsPage(legacy->minecraftRoot()));
return values;
}
return values;
}
virtual QString dialogTitle() override
{
return tr("Edit Instance (%1)").arg(inst->name());
}
protected:
InstancePtr inst;
};

View File

@@ -0,0 +1,23 @@
#include "InstanceProxyModel.h"
#include "MultiMC.h"
#include <BaseInstance.h>
InstanceProxyModel::InstanceProxyModel(QObject *parent) : GroupedProxyModel(parent)
{
}
bool InstanceProxyModel::subSortLessThan(const QModelIndex &left,
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;
}
}

View File

@@ -0,0 +1,13 @@
#include "groupview/GroupedProxyModel.h"
/**
* A proxy model that is responsible for sorting instances into groups
*/
class InstanceProxyModel : public GroupedProxyModel
{
public:
explicit InstanceProxyModel(QObject *parent = 0);
protected:
virtual bool subSortLessThan(const QModelIndex &left, const QModelIndex &right) const;
};

107
application/JavaCommon.cpp Normal file
View File

@@ -0,0 +1,107 @@
#include "JavaCommon.h"
#include "dialogs/CustomMessageBox.h"
#include <MMCStrings.h>
bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget *parent)
{
if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(QRegExp("-Xm[sx]")))
{
CustomMessageBox::selectable(
parent, QObject::tr("JVM arguments warning"),
QObject::tr("You tried to manually set a JVM memory option (using "
" \"-XX:PermSize\", \"-Xmx\" or \"-Xms\") - there"
" are dedicated boxes for these in the settings (Java"
" tab, in the Memory group at the top).\n"
"Your manual settings will be overridden by the"
" dedicated options.\n"
"This message will be displayed until you remove them"
" from the JVM arguments."),
QMessageBox::Warning)->exec();
return false;
}
return true;
}
void JavaCommon::TestCheck::javaWasOk(JavaCheckResult result)
{
QString text;
text += tr("Java test succeeded!<br />Platform reported: %1<br />Java version "
"reported: %2<br />").arg(result.realPlatform, result.javaVersion);
if (result.errorLog.size())
{
auto htmlError = result.errorLog;
htmlError.replace('\n', "<br />");
text += tr("<br />Warnings:<br /><font color=\"orange\">%1</font>").arg(htmlError);
}
CustomMessageBox::selectable(m_parent, tr("Java test success"), text,
QMessageBox::Information)->show();
}
void JavaCommon::TestCheck::javaArgsWereBad(JavaCheckResult result)
{
auto htmlError = result.errorLog;
QString text;
htmlError.replace('\n', "<br />");
text += tr("The specified java binary didn't work with the arguments you provided:<br />");
text += tr("<font color=\"red\">%1</font>").arg(htmlError);
CustomMessageBox::selectable(m_parent, tr("Java test failure"), text, QMessageBox::Warning)
->show();
}
void JavaCommon::TestCheck::javaBinaryWasBad(JavaCheckResult result)
{
QString text;
text += 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(m_parent, 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();
}
void JavaCommon::TestCheck::checkFinished(JavaCheckResult result)
{
if (!result.valid)
{
javaBinaryWasBad(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 (Strings::naturalCompare(result.javaVersion, "1.8", Qt::CaseInsensitive) < 0)
{
checker->m_permGen = m_permGen;
}
checker->performCheck();
}
void JavaCommon::TestCheck::checkFinishedWithArgs(JavaCheckResult result)
{
if (result.valid)
{
javaWasOk(result);
emit finished();
return;
}
javaArgsWereBad(result);
emit finished();
}

46
application/JavaCommon.h Normal file
View File

@@ -0,0 +1,46 @@
#pragma once
#include <java/JavaChecker.h>
class QWidget;
/**
* Common UI bits for the java pages to use.
*/
namespace JavaCommon
{
bool checkJVMArgs(QString args, QWidget *parent);
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:
void javaBinaryWasBad(JavaCheckResult result);
void javaArgsWereBad(JavaCheckResult result);
void javaWasOk(JavaCheckResult result);
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;
};
}

2022
application/MainWindow.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,20 +17,23 @@
#include <QMainWindow>
#include <QProcess>
#include <QTimer>
#include "logic/lists/InstanceList.h"
#include "logic/BaseInstance.h"
#include "logic/auth/MojangAccount.h"
#include "BaseInstance.h"
#include "auth/MojangAccount.h"
#include "net/NetJob.h"
#include "updater/GoUpdate.h"
class NewsChecker;
class NotificationChecker;
class QToolButton;
class InstanceProxyModel;
class LabeledToolButton;
class QLabel;
class InstanceProxyModel;
class KCategorizedView;
class KCategoryDrawer;
class MinecraftProcess;
class ConsoleWindow;
class BaseProfilerFactory;
class GenericPageProvider;
namespace Ui
{
@@ -51,7 +54,7 @@ public:
void openWebPage(QUrl url);
void checkSetDefaultJava();
void checkMigrateLegacyAssets();
void checkInstancePathForProblems();
private
slots:
@@ -81,10 +84,14 @@ slots:
void on_actionSettings_triggered();
void on_actionInstanceSettings_triggered();
void on_actionManageAccounts_triggered();
void on_actionReportBug_triggered();
void on_actionPatreon_triggered();
void on_actionMoreNews_triggered();
void newsButtonClicked();
@@ -95,69 +102,67 @@ slots:
void on_actionLaunchInstance_triggered();
void on_actionLaunchInstanceOffline_triggered();
void on_actionDeleteInstance_triggered();
void on_actionExportInstance_triggered();
void on_actionRenameInstance_triggered();
void on_actionMakeDesktopShortcut_triggered();
void on_actionChangeInstMCVersion_triggered();
void on_actionEditInstMods_triggered();
void on_actionEditInstance_triggered();
void on_actionEditInstNotes_triggered();
void on_actionScreenshots_triggered();
/*!
* Launches the currently selected instance with the default account.
* If no default account is selected, prompts the user to pick an account.
*/
void doLaunch();
/*!
* Opens an input dialog, allowing the user to input their password and refresh its access token.
* This function will execute the proper Yggdrasil task to refresh the access token.
* Returns true if successful. False if the user cancelled.
*/
bool loginWithPassword(MojangAccountPtr account, const QString& errorMsg="");
void doLaunch(bool online = true, BaseProfilerFactory *profiler = 0);
/*!
* Launches the given instance with the given account.
* This function assumes that the given account has a valid, usable access token.
*/
void launchInstance(BaseInstance* instance, MojangAccountPtr account);
void launchInstance(InstancePtr instance, AuthSessionPtr session, BaseProfilerFactory *profiler = 0);
/*!
* Prepares the given instance for launch with the given account.
*/
void updateInstance(BaseInstance* instance, MojangAccountPtr account);
void updateInstance(InstancePtr instance, AuthSessionPtr account, BaseProfilerFactory *profiler = 0);
void onGameUpdateError(QString error);
void taskStart();
void taskEnd();
void on_actionChangeInstLWJGLVersion_triggered();
void instanceEnded();
void on_actionInstanceSettings_triggered();
// called when an icon is changed in the icon model.
void iconUpdated(QString);
void showInstanceContextMenu(const QPoint&);
void showInstanceContextMenu(const QPoint &);
void updateToolsMenu();
void skinJobFinished();
public
slots:
void instanceActivated(QModelIndex);
void instanceChanged(const QModelIndex &current, const QModelIndex &previous);
void instanceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
void selectionBad();
void startTask(Task *task);
void updateAvailable(QString repo, QString versionName, int versionId);
void updateAvailable(GoUpdate::Status status);
void updateNotAvailable();
void notificationsChanged();
@@ -168,34 +173,46 @@ slots:
void repopulateAccountsMenu();
void updateNewsLabel();
/*!
* Runs the DownloadUpdateTask and installs updates.
* Runs the DownloadTask and installs updates.
*/
void downloadUpdates(QString repo, int versionId, bool installOnExit=false);
void downloadUpdates(GoUpdate::Status status, bool installOnExit = false);
protected:
bool eventFilter(QObject *obj, QEvent *ev);
void setCatBackground(bool enabled);
void updateInstanceToolIcon(QString new_icon);
void setSelectedInstanceById(const QString &id);
void waitForMinecraftVersions();
void instanceFromVersion(QString instName, QString instGroup, QString instIcon, BaseVersionPtr version);
void instanceFromZipPack(QString instName, QString instGroup, QString instIcon, QUrl url);
void finalizeInstance(InstancePtr inst);
private:
Ui::MainWindow *ui;
KCategoryDrawer *drawer;
KCategorizedView *view;
class GroupView *view;
InstanceProxyModel *proxymodel;
NetJobPtr skin_download_job;
MinecraftProcess *proc;
ConsoleWindow *console;
LabeledToolButton *renameButton;
QToolButton *changeIconButton;
QToolButton* newsLabel;
QToolButton *newsLabel;
BaseInstance *m_selectedInstance;
std::shared_ptr<GenericPageProvider> m_globalSettingsProvider;
std::shared_ptr<NewsChecker> m_newsChecker;
std::shared_ptr<NotificationChecker> m_notificationChecker;
InstancePtr m_selectedInstance;
QString m_currentInstIcon;
Task *m_versionLoadTask;
QLabel *m_statusLeft;
class ServerStatus *m_statusRight;
QMenu *accountMenu;
QToolButton *accountMenuButton;

652
application/MultiMC.cpp Normal file
View File

@@ -0,0 +1,652 @@
#include "MultiMC.h"
#include "BuildConfig.h"
#include <iostream>
#include <QDir>
#include <QFileInfo>
#include <QNetworkAccessManager>
#include <QTranslator>
#include <QLibraryInfo>
#include <QMessageBox>
#include <QStringList>
#include <QDesktopServices>
#include <QDebug>
#include "InstanceList.h"
#include "auth/MojangAccountList.h"
#include "icons/IconList.h"
#include "minecraft/LwjglVersionList.h"
#include "minecraft/MinecraftVersionList.h"
#include "liteloader/LiteLoaderVersionList.h"
#include "forge/ForgeVersionList.h"
#include "net/HttpMetaCache.h"
#include "net/URLConstants.h"
#include "Env.h"
#include "java/JavaUtils.h"
#include "updater/UpdateChecker.h"
#include "tools/JProfiler.h"
#include "tools/JVisualVM.h"
#include "tools/MCEditTool.h"
#include "pathutils.h"
#include "cmdutils.h"
#include <xdgicon.h>
#include "settings/INISettingsObject.h"
#include "settings/Setting.h"
#include "trans/TranslationDownloader.h"
#include "ftb/FTBPlugin.h"
using namespace Util::Commandline;
MultiMC::MultiMC(int &argc, char **argv, bool test_mode) : QApplication(argc, argv)
{
setOrganizationName("MultiMC");
setApplicationName("MultiMC5");
startTime = QDateTime::currentDateTime();
setAttribute(Qt::AA_UseHighDpiPixmaps);
// 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", applicationDirPath());
parser.addShortOpt("dir", 'd');
parser.addDocumentation("dir", "use the supplied directory as MultiMC root instead of "
"the binary location (use '.' for current)");
// 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.VERSION_STR.toStdString() << std::endl;
std::cout << "Git " << BuildConfig.GIT_COMMIT.toStdString() << std::endl;
m_status = MultiMC::Succeeded;
return;
}
}
QString origcwdPath = QDir::currentPath();
QString binPath = applicationDirPath();
QString adjustedBy;
// change directory
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
{
dataPath = applicationDirPath();
adjustedBy += "Fallback to binary path " + dataPath;
}
if (!ensureFolderPathExists(dataPath) || !QDir::setCurrent(dataPath))
{
// BAD STUFF. WHAT DO?
initLogger();
qCritical() << "Failed to set work path. Will exit. NOW.";
m_status = MultiMC::Failed;
return;
}
// in test mode, root path is the same as the binary path.
if (test_mode)
{
rootPath = binPath;
}
else
{
#ifdef Q_OS_LINUX
QDir foo(PathCombine(binPath, ".."));
rootPath = foo.absolutePath();
#elif defined(Q_OS_WIN32)
rootPath = binPath;
#elif defined(Q_OS_MAC)
QDir foo(PathCombine(binPath, "../.."));
rootPath = foo.absolutePath();
#endif
}
// static data paths... mostly just for translations
#ifdef Q_OS_LINUX
QDir foo(PathCombine(binPath, ".."));
staticDataPath = foo.absolutePath();
#elif defined(Q_OS_WIN32)
staticDataPath = binPath;
#elif defined(Q_OS_MAC)
QDir foo(PathCombine(rootPath, "Contents/Resources"));
staticDataPath = foo.absolutePath();
#endif
// init the logger
initLogger();
qDebug() << "MultiMC 5, (c) 2013-2015 MultiMC Contributors";
qDebug() << "Version : " << BuildConfig.VERSION_STR;
qDebug() << "Git commit : " << BuildConfig.GIT_COMMIT;
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 : " << rootPath;
qDebug() << "Static data path : " << staticDataPath;
// load settings
initGlobalSettings(test_mode);
// load translations
initTranslations();
// initialize the updater
m_updateChecker.reset(new UpdateChecker(BuildConfig.CHANLIST_URL, BuildConfig.VERSION_CHANNEL, BuildConfig.VERSION_BUILD));
m_translationChecker.reset(new TranslationDownloader());
// load icons
initIcons();
// and 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 = m_settings->get("InstanceDir").toString();
qDebug() << "Instance path : " << instDir;
if (checkProblemticPathJava(QDir(instDir)))
{
qWarning()
<< "Your instance path contains \'!\' and this is known to cause java problems";
}
m_instances.reset(new InstanceList(m_settings, InstDirSetting->get().toString(), this));
qDebug() << "Loading Instances...";
m_instances->loadList();
connect(InstDirSetting.get(), SIGNAL(SettingChanged(const Setting &, QVariant)),
m_instances.get(), SLOT(on_InstFolderChanged(const Setting &, QVariant)));
// and accounts
m_accounts.reset(new MojangAccountList(this));
qDebug() << "Loading accounts...";
m_accounts->setListFilePath("accounts.json", true);
m_accounts->loadList();
// init the http meta cache
ENV.initHttpMetaCache(rootPath, staticDataPath);
// create the global network manager
ENV.m_qnam.reset(new QNetworkAccessManager(this));
// 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);
}
initSSL();
m_translationChecker->downloadTranslations();
//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);
}
//FIXME: what to do with these?
m_tools.insert("mcedit", std::shared_ptr<BaseDetachedToolFactory>(new MCEditFactory()));
for (auto tool : m_tools.values())
{
tool->registerSettings(m_settings);
}
connect(this, SIGNAL(aboutToQuit()), SLOT(onExit()));
m_status = MultiMC::Initialized;
}
MultiMC::~MultiMC()
{
if (m_mmc_translator)
{
removeTranslator(m_mmc_translator.get());
}
if (m_qt_translator)
{
removeTranslator(m_qt_translator.get());
}
}
void MultiMC::initSSL()
{
#ifdef Q_OS_MAC
Q_INIT_RESOURCE(certs);
QFile equifaxFile(":/certs/Equifax_Secure_Certificate_Authority.pem");
equifaxFile.open(QIODevice::ReadOnly);
QSslCertificate equifaxCert(equifaxFile.readAll(), QSsl::Pem);
QSslSocket::addDefaultCaCertificate(equifaxCert);
#endif
}
void MultiMC::initTranslations()
{
QLocale locale(m_settings->get("Language").toString());
QLocale::setDefault(locale);
qDebug() << "Your language is" << locale.bcp47Name();
m_qt_translator.reset(new QTranslator());
if (m_qt_translator->load("qt_" + locale.bcp47Name(),
QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
{
qDebug() << "Loading Qt Language File for"
<< locale.bcp47Name().toLocal8Bit().constData() << "...";
if (!installTranslator(m_qt_translator.get()))
{
qCritical() << "Loading Qt Language File failed.";
m_qt_translator.reset();
}
}
else
{
m_qt_translator.reset();
}
m_mmc_translator.reset(new QTranslator());
if (m_mmc_translator->load("mmc_" + locale.bcp47Name(), staticDataPath + "/translations"))
{
qDebug() << "Loading MMC Language File for"
<< locale.bcp47Name().toLocal8Bit().constData() << "...";
if (!installTranslator(m_mmc_translator.get()))
{
qCritical() << "Loading MMC Language File failed.";
m_mmc_translator.reset();
}
}
else
{
m_mmc_translator.reset();
}
}
void MultiMC::initIcons()
{
auto setting = MMC->settings()->getSetting("IconsDir");
ENV.m_icons.reset(new IconList(QString(":/icons/instances/"), setting->get().toString()));
connect(setting.get(), &Setting::SettingChanged,[&](const Setting &, QVariant value)
{
ENV.m_icons->directoryChanged(value.toString());
});
}
void moveFile(const QString &oldName, const QString &newName)
{
QFile::remove(newName);
QFile::copy(oldName, newName);
QFile::remove(oldName);
}
void appDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
const char *levels = "DWCF";
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);
}
void MultiMC::initLogger()
{
static const QString logBase = "MultiMC-%0.log";
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));
qInstallMessageHandler(appDebugOutput);
logFile = std::make_shared<QFile>(logBase.arg(0));
logFile->open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
}
void MultiMC::initGlobalSettings(bool test_mode)
{
m_settings.reset(new INISettingsObject("multimc.cfg", this));
// Updates
m_settings->registerSetting("UpdateChannel", BuildConfig.VERSION_CHANNEL);
m_settings->registerSetting("AutoUpdate", true);
m_settings->registerSetting("IconTheme", QString("multimc"));
// Notifications
m_settings->registerSetting("ShownNotifications", QString());
// Remembered state
m_settings->registerSetting("LastUsedGroupForNewInstance", QString());
QString defaultMonospace;
int defaultSize = 11;
#ifdef Q_OS_WIN32
defaultMonospace = "Courier";
defaultSize = 10;
#elif defined(Q_OS_MAC)
defaultMonospace = "Menlo";
#else
defaultMonospace = "Monospace";
#endif
if(!test_mode)
{
// 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);
}
else
{
// in test mode, we don't have UI, so we don't do any font resolving
m_settings->registerSetting("ConsoleFont", defaultMonospace);
}
m_settings->registerSetting("ConsoleFontSize", defaultSize);
FTBPlugin::initialize(m_settings);
// Folders
m_settings->registerSetting("InstanceDir", "instances");
m_settings->registerSetting({"CentralModsDir", "ModsDir"}, "mods");
m_settings->registerSetting({"LWJGLDir", "LwjglDir"}, "lwjgl");
m_settings->registerSetting("IconsDir", "icons");
// Editors
m_settings->registerSetting("JsonEditor", QString());
// Language
m_settings->registerSetting("Language", QLocale(QLocale::system().language()).bcp47Name());
// Console
m_settings->registerSetting("ShowConsole", true);
m_settings->registerSetting("RaiseConsole", true);
m_settings->registerSetting("AutoCloseConsole", true);
m_settings->registerSetting("LogPrePostOutput", true);
// Console Colors
// m_settings->registerSetting("SysMessageColor", QColor(Qt::blue));
// m_settings->registerSetting("StdOutColor", QColor(Qt::black));
// m_settings->registerSetting("StdErrColor", QColor(Qt::red));
// 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("JavaVersion", "");
m_settings->registerSetting("LastHostname", "");
m_settings->registerSetting("JavaDetectionHack", "");
m_settings->registerSetting("JvmArgs", "");
// 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", "");
// Jar mod nag dialog in version page
m_settings->registerSetting("JarModNagSeen", false);
}
std::shared_ptr<LWJGLVersionList> MultiMC::lwjgllist()
{
if (!m_lwjgllist)
{
m_lwjgllist.reset(new LWJGLVersionList());
ENV.registerVersionList("org.lwjgl.legacy", m_lwjgllist);
}
return m_lwjgllist;
}
std::shared_ptr<ForgeVersionList> MultiMC::forgelist()
{
if (!m_forgelist)
{
m_forgelist.reset(new ForgeVersionList());
ENV.registerVersionList("net.minecraftforge", m_forgelist);
}
return m_forgelist;
}
std::shared_ptr<LiteLoaderVersionList> MultiMC::liteloaderlist()
{
if (!m_liteloaderlist)
{
m_liteloaderlist.reset(new LiteLoaderVersionList());
ENV.registerVersionList("com.mumfrey.liteloader", m_liteloaderlist);
}
return m_liteloaderlist;
}
std::shared_ptr<MinecraftVersionList> MultiMC::minecraftlist()
{
if (!m_minecraftlist)
{
m_minecraftlist.reset(new MinecraftVersionList());
ENV.registerVersionList("net.minecraft", m_minecraftlist);
}
return m_minecraftlist;
}
std::shared_ptr<JavaVersionList> MultiMC::javalist()
{
if (!m_javalist)
{
m_javalist.reset(new JavaVersionList());
ENV.registerVersionList("com.java", m_javalist);
}
return m_javalist;
}
void MultiMC::installUpdates(const QString updateFilesDir, UpdateFlags flags)
{
// if we are going to update on exit, save the params now
if (flags & OnExit)
{
m_updateOnExitPath = updateFilesDir;
m_updateOnExitFlags = flags & ~OnExit;
return;
}
// otherwise if there already were some params for on exit update, clear them and continue
else if (m_updateOnExitPath.size())
{
m_updateOnExitFlags = None;
m_updateOnExitPath.clear();
}
qDebug() << "Installing updates.";
#ifdef WINDOWS
QString finishCmd = applicationFilePath();
QString updaterBinary = PathCombine(applicationDirPath(), "updater.exe");
#elif LINUX
QString finishCmd = PathCombine(root(), "MultiMC");
QString updaterBinary = PathCombine(applicationDirPath(), "updater");
#elif OSX
QString finishCmd = applicationFilePath();
QString updaterBinary = PathCombine(applicationDirPath(), "updater");
#else
#error Unsupported operating system.
#endif
QStringList args;
// ./updater --install-dir $INSTALL_DIR --package-dir $UPDATEFILES_DIR --script
// $UPDATEFILES_DIR/file_list.xml --wait $PID --mode main
args << "--install-dir" << root();
args << "--package-dir" << updateFilesDir;
args << "--script" << PathCombine(updateFilesDir, "file_list.xml");
args << "--wait" << QString::number(applicationPid());
if (flags & DryRun)
args << "--dry-run";
if (flags & RestartOnFinish)
{
args << "--finish-cmd" << finishCmd;
args << "--finish-dir" << dataPath;
}
qDebug() << "Running updater with command" << updaterBinary << args.join(" ");
QFile::setPermissions(updaterBinary, (QFileDevice::Permission)0x7755);
if (!QProcess::startDetached(updaterBinary, args /*, root()*/))
{
qCritical() << "Failed to start the updater process!";
return;
}
ENV.destroy();
// Now that we've started the updater, quit MultiMC.
quit();
}
void MultiMC::setIconTheme(const QString& name)
{
XdgIcon::setThemeName(name);
}
QIcon MultiMC::getThemedIcon(const QString& name)
{
return XdgIcon::fromTheme(name);
}
void MultiMC::onExit()
{
if(m_instances)
{
m_instances->saveGroupList();
}
if (m_updateOnExitPath.size())
{
installUpdates(m_updateOnExitPath, m_updateOnExitFlags);
}
ENV.destroy();
if(logFile)
{
logFile->flush();
logFile->close();
}
}
bool MultiMC::openJsonEditor(const QString &filename)
{
const QString file = QDir::current().absoluteFilePath(filename);
if (m_settings->get("JsonEditor").toString().isEmpty())
{
return QDesktopServices::openUrl(QUrl::fromLocalFile(file));
}
else
{
return QProcess::startDetached(m_settings->get("JsonEditor").toString(), QStringList()
<< file);
}
}
#include "MultiMC.moc"

View File

@@ -1,13 +1,13 @@
#pragma once
#include "config.h"
#include <QApplication>
#include "MultiMCVersion.h"
#include <memory>
#include "logger/QsLog.h"
#include "logger/QsLogDest.h"
#include <QDebug>
#include <QFlag>
#include <QIcon>
#include <QDateTime>
class QFile;
class MinecraftVersionList;
class LWJGLVersionList;
class HttpMetaCache;
@@ -17,25 +17,18 @@ class MojangAccountList;
class IconList;
class QNetworkAccessManager;
class ForgeVersionList;
class LiteLoaderVersionList;
class JavaVersionList;
class UpdateChecker;
class NotificationChecker;
class NewsChecker;
class BaseProfilerFactory;
class BaseDetachedToolFactory;
class TranslationDownloader;
#if defined(MMC)
#undef MMC
#endif
#define MMC (static_cast<MultiMC *>(QCoreApplication::instance()))
// FIXME: possibly move elsewhere
enum InstSortMode
{
// Sort alphabetically by name.
Sort_Name,
// Sort by which instance was launched most recently.
Sort_LastLaunch
};
enum UpdateFlag
{
None = 0x0,
@@ -48,6 +41,9 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(UpdateFlags);
class MultiMC : public QApplication
{
// friends for the purpose of limiting access to deprecated stuff
friend class MultiMCPage;
friend class MainWindow;
Q_OBJECT
public:
enum Status
@@ -58,69 +54,67 @@ public:
};
public:
MultiMC(int &argc, char **argv, bool root_override = false);
MultiMC(int &argc, char **argv, bool test_mode = false);
virtual ~MultiMC();
// InstanceList, IconList, OneSixFTBInstance, LegacyUpdate, LegacyInstance, MCEditTool, JVisualVM, MinecraftInstance, JProfiler, BaseInstance
std::shared_ptr<SettingsObject> settings()
{
return m_settings;
}
std::shared_ptr<InstanceList> instances()
qint64 timeSinceStart() const
{
return m_instances;
return startTime.msecsTo(QDateTime::currentDateTime());
}
std::shared_ptr<MojangAccountList> accounts()
{
return m_accounts;
}
QIcon getThemedIcon(const QString& name);
std::shared_ptr<IconList> icons();
Status status()
{
return m_status;
}
MultiMCVersion version()
{
return m_version;
}
std::shared_ptr<QNetworkAccessManager> qnam()
{
return m_qnam;
}
std::shared_ptr<HttpMetaCache> metacache()
{
return m_metacache;
}
void setIconTheme(const QString& name);
// DownloadUpdateTask
std::shared_ptr<UpdateChecker> updateChecker()
{
return m_updateChecker;
}
std::shared_ptr<NotificationChecker> notificationChecker()
{
return m_notificationChecker;
}
std::shared_ptr<NewsChecker> newsChecker()
{
return m_newsChecker;
}
std::shared_ptr<LWJGLVersionList> lwjgllist();
std::shared_ptr<ForgeVersionList> forgelist();
std::shared_ptr<MinecraftVersionList> minecraftlist();
std::shared_ptr<LWJGLVersionList> lwjgllist();
std::shared_ptr<ForgeVersionList> forgelist();
std::shared_ptr<LiteLoaderVersionList> liteloaderlist();
std::shared_ptr<JavaVersionList> javalist();
// APPLICATION ONLY
std::shared_ptr<InstanceList> instances()
{
return m_instances;
}
// APPLICATION ONLY
std::shared_ptr<MojangAccountList> accounts()
{
return m_accounts;
}
// APPLICATION ONLY
Status status()
{
return m_status;
}
// APPLICATION ONLY
QMap<QString, std::shared_ptr<BaseProfilerFactory>> profilers()
{
return m_profilers;
}
// APPLICATION ONLY
QMap<QString, std::shared_ptr<BaseDetachedToolFactory>> tools()
{
return m_tools;
}
// APPLICATION ONLY
void installUpdates(const QString updateFilesDir, UpdateFlags flags = None);
/*!
@@ -129,28 +123,20 @@ public:
*/
bool openJsonEditor(const QString &filename);
protected: /* to be removed! */
// FIXME: remove. used by MultiMCPage to enumerate translations.
/// this is the static data. it stores things that don't move.
const QString &staticData()
{
return staticDataPath;
}
// FIXME: remove. used by MainWindow to create application update tasks
/// this is the root of the 'installation'. Used for automatic updates
const QString &root()
{
return rootPath;
}
/// this is the where the binary files reside
const QString &bin()
{
return binPath;
}
/// this is the work/data path. All user data is here.
const QString &data()
{
return dataPath;
}
/**
* this is the original work path before it was changed by the adjustment mechanism
*/
const QString &origcwd()
{
return origcwdPath;
}
private slots:
/**
@@ -161,42 +147,43 @@ private slots:
private:
void initLogger();
void initGlobalSettings();
void initIcons();
void initHttpMetaCache();
void initGlobalSettings(bool test_mode);
void initTranslations();
void initSSL();
private:
friend class UpdateCheckerTest;
friend class DownloadUpdateTaskTest;
friend class DownloadTaskTest;
QDateTime startTime;
std::shared_ptr<QTranslator> m_qt_translator;
std::shared_ptr<QTranslator> m_mmc_translator;
std::shared_ptr<SettingsObject> m_settings;
std::shared_ptr<InstanceList> m_instances;
std::shared_ptr<UpdateChecker> m_updateChecker;
std::shared_ptr<NotificationChecker> m_notificationChecker;
std::shared_ptr<NewsChecker> m_newsChecker;
std::shared_ptr<MojangAccountList> m_accounts;
std::shared_ptr<IconList> m_icons;
std::shared_ptr<QNetworkAccessManager> m_qnam;
std::shared_ptr<HttpMetaCache> m_metacache;
std::shared_ptr<LWJGLVersionList> m_lwjgllist;
std::shared_ptr<ForgeVersionList> m_forgelist;
std::shared_ptr<LiteLoaderVersionList> m_liteloaderlist;
std::shared_ptr<MinecraftVersionList> m_minecraftlist;
std::shared_ptr<JavaVersionList> m_javalist;
QsLogging::DestinationPtr m_fileDestination;
QsLogging::DestinationPtr m_debugDestination;
std::shared_ptr<TranslationDownloader> m_translationChecker;
QMap<QString, std::shared_ptr<BaseProfilerFactory>> m_profilers;
QMap<QString, std::shared_ptr<BaseDetachedToolFactory>> m_tools;
QString m_updateOnExitPath;
UpdateFlags m_updateOnExitFlags = None;
QString rootPath;
QString binPath;
QString staticDataPath;
QString dataPath;
QString origcwdPath;
Status m_status = MultiMC::Failed;
MultiMCVersion m_version;
public:
std::shared_ptr<QFile> logFile;
};

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
*

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
*
@@ -15,7 +15,7 @@
* limitations under the License.
*/
#include <gui/Platform.h>
#include <Platform.h>
/**
* Stub for non-X11 platforms
* @brief MultiMCPlatform::fixWM_CLASS

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
*
@@ -15,7 +15,7 @@
* limitations under the License.
*/
#include <gui/Platform.h>
#include <Platform.h>
#include <QtX11Extras/QX11Info>
#include <xcb/xcb.h>

View File

@@ -0,0 +1,412 @@
#include "VersionProxyModel.h"
#include "MultiMC.h"
#include <QSortFilterProxyModel>
#include <QPixmapCache>
#include <modutils.h>
class VersionFilterModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
VersionFilterModel(VersionProxyModel *parent) : QSortFilterProxyModel(parent)
{
m_parent = parent;
}
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 role = it.key();
auto idx = sourceModel()->index(source_row, 0, source_parent);
auto data = sourceModel()->data(idx, role);
switch(role)
{
case BaseVersionList::ParentGameVersionRole:
case BaseVersionList::VersionIdRole:
{
auto versionString = data.toString();
if(it.value().exact)
{
if (versionString != it.value().string)
{
return false;
}
}
else if (!Util::versionIsInInterval(versionString, it.value().string))
{
return false;
}
}
default:
{
auto match = data.toString();
if(it.value().exact)
{
if (match != it.value().string)
{
return false;
}
}
else if (match.contains(it.value().string))
{
return false;
}
}
}
}
return true;
}
private:
VersionProxyModel *m_parent;
};
VersionProxyModel::VersionProxyModel(QObject *parent) : QAbstractProxyModel(parent)
{
filterModel = new VersionFilterModel(this);
connect(filterModel, &QAbstractItemModel::dataChanged, this, &VersionProxyModel::sourceDataChanged);
// FIXME: implement when needed
/*
connect(replacing, &QAbstractItemModel::rowsAboutToBeInserted, this, &VersionProxyModel::sourceRowsAboutToBeInserted);
connect(replacing, &QAbstractItemModel::rowsInserted, this, &VersionProxyModel::sourceRowsInserted);
connect(replacing, &QAbstractItemModel::rowsAboutToBeRemoved, this, &VersionProxyModel::sourceRowsAboutToBeRemoved);
connect(replacing, &QAbstractItemModel::rowsRemoved, this, &VersionProxyModel::sourceRowsRemoved);
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");
}
}
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");
}
}
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::ParentGameVersionRole);
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);
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();
}
QModelIndex VersionProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
{
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();
}
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);
}
int VersionProxyModel::columnCount(const QModelIndex &parent) const
{
return m_columns.size();
}
int VersionProxyModel::rowCount(const QModelIndex &parent) const
{
if(sourceModel())
{
return sourceModel()->rowCount();
}
return 0;
}
void VersionProxyModel::sourceDataChanged(const QModelIndex &source_top_left,
const QModelIndex &source_bottom_right)
{
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);
}
void VersionProxyModel::setSourceModel(BaseVersionList *replacing)
{
beginResetModel();
if(!replacing)
{
m_columns.clear();
roles.clear();
filterModel->setSourceModel(replacing);
return;
}
roles = replacing->providesRoles();
if(roles.contains(BaseVersionList::VersionRole))
{
m_columns.push_back(Name);
}
/*
if(roles.contains(BaseVersionList::ParentGameVersionRole))
{
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(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);
}
void VersionProxyModel::clearFilters()
{
m_filters.clear();
filterModel->invalidate();
}
void VersionProxyModel::setFilter(const BaseVersionList::ModelRoles column, const QString &filter, const bool exact)
{
Filter f;
f.string = filter;
f.exact = exact;
m_filters[column] = f;
filterModel->invalidate();
}
const VersionProxyModel::FilterMap &VersionProxyModel::filters() const
{
return m_filters;
}
void VersionProxyModel::sourceAboutToBeReset()
{
beginResetModel();
}
void VersionProxyModel::sourceReset()
{
endResetModel();
}
#include "VersionProxyModel.moc"

View File

@@ -0,0 +1,58 @@
#pragma once
#include <QAbstractProxyModel>
#include "BaseVersionList.h"
class VersionFilterModel;
class VersionProxyModel: public QAbstractProxyModel
{
Q_OBJECT
public:
struct Filter
{
QString string;
bool exact = false;
};
enum Column
{
Name,
ParentVersion,
Branch,
Type,
Architecture,
Path
};
typedef QHash<BaseVersionList::ModelRoles, 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;
void setSourceModel(BaseVersionList *sourceModel);
const FilterMap &filters() const;
void setFilter(const BaseVersionList::ModelRoles column, const QString &filter, const bool exact);
void clearFilters();
QModelIndex getRecommended() const;
private slots:
void sourceDataChanged(const QModelIndex &source_top_left,const QModelIndex &source_bottom_right);
void sourceAboutToBeReset();
void sourceReset();
private:
QList<Column> m_columns;
FilterMap m_filters;
BaseVersionList::RoleList roles;
VersionFilterModel * filterModel;
bool hasRecommended = false;
bool hasLatest = false;
};

View File

@@ -0,0 +1,127 @@
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "AboutDialog.h"
#include "ui_AboutDialog.h"
#include <QIcon>
#include "MultiMC.h"
#include "Platform.h"
#include "BuildConfig.h"
#include <net/NetJob.h>
// Credits
// This is a hack, but I can't think of a better way to do this easily without screwing with QTextDocument...
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>"
""
"<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>Robotbrain &lt;<a href='https://twitter.com/skylordelros'>@skylordelros</a>&gt;</p>"
"<p>Rootbear75 &lt;<a href='https://twitter.com/rootbear75'>@rootbear75</a>&gt; (build server)</p>"
""
"<h3>Patreon 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);
}
}
AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent), ui(new Ui::AboutDialog)
{
MultiMCPlatform::fixWM_CLASS(this);
ui->setupUi(this);
QString chtml = getCreditsHtml(QStringList());
ui->creditsText->setHtml(chtml);
ui->urlLabel->setOpenExternalLinks(true);
ui->icon->setPixmap(MMC->getThemedIcon("multimc").pixmap(64));
ui->title->setText("MultiMC 5");
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_CHANNEL.isEmpty())
ui->channelLabel->setText(tr("Channel") +": " + BuildConfig.VERSION_CHANNEL);
else
ui->channelLabel->setVisible(false);
connect(ui->closeButton, SIGNAL(clicked()), SLOT(close()));
connect(ui->aboutQt, &QPushButton::clicked, &QApplication::aboutQt);
loadPatronList();
}
AboutDialog::~AboutDialog()
{
delete ui;
}
void AboutDialog::loadPatronList()
{
NetJob* job = new NetJob("Patreon Patron List");
patronListDownload = ByteArrayDownload::make(QUrl("http://files.multimc.org/patrons.txt"));
job->addNetAction(patronListDownload);
connect(job, &NetJob::succeeded, this, &AboutDialog::patronListLoaded);
job->start();
}
void AboutDialog::patronListLoaded()
{
QString patronListStr(patronListDownload->m_data);
QString html = getCreditsHtml(patronListStr.split("\n", QString::SkipEmptyParts));
ui->creditsText->setHtml(html);
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,8 @@
#include <QDialog>
#include <net/ByteArrayDownload.h>
namespace Ui
{
class AboutDialog;
@@ -30,6 +32,16 @@ public:
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();
private:
Ui::AboutDialog *ui;
ByteArrayDownloadPtr patronListDownload;
};

View File

@@ -58,9 +58,6 @@
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../../graphics.qrc">:/icons/multimc/scalable/apps/multimc.svg</pixmap>
</property>
</widget>
</item>
<item>
@@ -86,7 +83,7 @@
</font>
</property>
<property name="text">
<string>MultiMC</string>
<string>MultiMC 5</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
@@ -103,14 +100,54 @@
<rect>
<x>0</x>
<y>0</y>
<width>685</width>
<height>304</height>
<width>695</width>
<height>297</height>
</rect>
</property>
<attribute name="label">
<string>About</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="versionLabel">
<property name="text">
<string>Version:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="platformLabel">
<property name="text">
<string>Platform:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="buildNumLabel">
<property name="text">
<string>Build Number:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="channelLabel">
<property name="text">
<string>Channel:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="aboutLabel">
<property name="enabled">
@@ -136,7 +173,7 @@
</font>
</property>
<property name="text">
<string>© 2013 MultiMC Contributors</string>
<string>© 2013-2015 MultiMC Contributors</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
@@ -151,13 +188,26 @@
</font>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;http://github.com/Forkk/MultiMC5&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;http://github.com/MultiMC/MultiMC5&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;http://github.com/MultiMC/MultiMC5&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;http://github.com/MultiMC/MultiMC5&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</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>
</layout>
</widget>
<widget class="QWidget" name="creditsPage">
@@ -165,8 +215,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>685</width>
<height>304</height>
<width>695</width>
<height>297</height>
</rect>
</property>
<attribute name="label">
@@ -182,22 +232,11 @@
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.8pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt; font-weight:600;&quot;&gt;MultiMC&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Andrew Okin &amp;lt;&lt;/span&gt;&lt;a href=&quot;mailto:forkk@forkk.net&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;forkk@forkk.net&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Petr Mrázek &amp;lt;&lt;/span&gt;&lt;a href=&quot;mailto:peterix@gmail.com&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;peterix@gmail.com&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Sky &amp;lt;&lt;/span&gt;&lt;a href=&quot;https://www.twitter.com/drayshak&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;@drayshak&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt; font-weight:600;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Ubuntu'; font-size:10pt; font-weight:600;&quot;&gt;With thanks to&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Orochimarufan &amp;lt;&lt;/span&gt;&lt;a href=&quot;mailto:orochimarufan.x3@gmail.com&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;orochimarufan.x3@gmail.com&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;TakSuyu &amp;lt;&lt;/span&gt;&lt;a href=&quot;mailto:taksuyu@gmail.com&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;taksuyu@gmail.com&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Kilobyte &amp;lt;&lt;/span&gt;&lt;a href=&quot;mailto:stiepen22@gmx.de&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;stiepen22@gmx.de&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Jan (02JanDal) &amp;lt;&lt;/span&gt;&lt;a href=&quot;mailto:02jandal@gmail.com&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;02jandal@gmail.com&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Robotbrain &amp;lt;&lt;/span&gt;&lt;a href=&quot;https://twitter.com/skylordelros&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;@skylordelros&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Rootbear75 &amp;lt;&lt;/span&gt;&lt;a href=&quot;https://twitter.com/rootbear75&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;@rootbear75&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&amp;gt; (build server)&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Oxygen-Sans'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
<set>Qt::TextBrowserInteraction</set>
</property>
</widget>
</item>
@@ -218,8 +257,8 @@ p, li { white-space: pre-wrap; }
<rect>
<x>0</x>
<y>0</y>
<width>684</width>
<height>290</height>
<width>695</width>
<height>297</height>
</rect>
</property>
<attribute name="label">
@@ -246,7 +285,7 @@ p, li { white-space: pre-wrap; }
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'DejaVu Sans Mono'; font-size:7.8pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'DejaVu Sans Mono'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Bitstream Vera Sans'; font-size:18pt; font-weight:600;&quot;&gt;MultiMC&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Copyright 2012-2014 MultiMC Contributors&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;);&lt;/span&gt;&lt;/p&gt;
@@ -307,7 +346,24 @@ p, li { white-space: pre-wrap; }
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; * Boston, MA 02110-1301, USA.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; */&lt;/span&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot; style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Bitstream Vera Sans'; font-size:18pt; font-weight:600;&quot;&gt;Batch icon set&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;You are free to use Batch (the &amp;quot;icon set&amp;quot;) or any part thereof (the &amp;quot;icons&amp;quot;)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;in any personal, open-source or commercial work without obligation of payment&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;(monetary or otherwise) or attribution. Do not sell the icon set, host&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;the icon set or rent the icon set (either in existing or modified form).&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;While attribution is optional, it is always appreciated.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;Intellectual property rights are not transferred with the download of the icons.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL ADAM WHITCROFT&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THE USE OF THE ICONS,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://adamwhitcroft.com/batch/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#68a0df;&quot;&gt;http://adamwhitcroft.com/batch/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Bitstream Vera Sans'; font-size:18pt; font-weight:600;&quot;&gt;Pack200&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;The GNU General Public License (GPL)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
@@ -367,8 +423,45 @@ p, li { white-space: pre-wrap; }
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; *&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; * This file has been put into the public domain.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; * You can do whatever you want with this file.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; */&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Bitstream Vera Sans'; font-size:18pt; font-weight:600;&quot;&gt;Java IconLoader class&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;Copyright (c) 2011, Chris Molini&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;All rights reserved.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;Redistribution and use in source and binary forms, with or without&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;modification, are permitted provided that the following conditions are met:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; * Redistributions of source code must retain the above copyright&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; notice, this list of conditions and the following disclaimer.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; * Redistributions in binary form must reproduce the above copyright&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; notice, this list of conditions and the following disclaimer in the&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; documentation and/or other materials provided with the distribution.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; * Neither the name of the &amp;lt;organization&amp;gt; nor the&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; names of its contributors may be used to endorse or promote products&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; derived from this software without specific prior written permission.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &amp;quot;AS IS&amp;quot; AND&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;DISCLAIMED. IN NO EVENT SHALL &amp;lt;COPYRIGHT HOLDER&amp;gt; BE LIABLE FOR ANY&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.&lt;/span&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot; style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Bitstream Vera Sans'; font-size:18pt; font-weight:600;&quot;&gt;ColumnResizer&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;/*&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; * Copyright 2011 Aurélien Gâteau &amp;lt;agateau@kde.org&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; * License: LGPL v2.1 or later (see COPYING)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; */&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textInteractionFlags">
<set>Qt::TextBrowserInteraction</set>
</property>
</widget>
</item>
</layout>
@@ -378,8 +471,8 @@ p, li { white-space: pre-wrap; }
<rect>
<x>0</x>
<y>0</y>
<width>684</width>
<height>290</height>
<width>695</width>
<height>297</height>
</rect>
</property>
<attribute name="label">
@@ -392,12 +485,12 @@ p, li { white-space: pre-wrap; }
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.8pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Bitstream Vera Sans'; font-size:11pt;&quot;&gt;We keep MultiMC open source because we think it's important to be able to see the source code for a project like this, and we do so using the Apache license.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Bitstream Vera Sans'; font-size:11pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Bitstream Vera Sans'; font-size:11pt;&quot;&gt;Part of the reason for using the Apache license is we don't want people using the &amp;quot;MultiMC&amp;quot; name when redistributing the project. This means people must take the time to go through the source code and remove all references to &amp;quot;MultiMC&amp;quot;, including but not limited to the project icon and the title of windows, (no *MultiMC-fork* in the title).&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Bitstream Vera Sans'; font-size:11pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Bitstream Vera Sans'; font-size:11pt;&quot;&gt;The Apache license covers reasonable use for the name - a mention of the project's origins in the About dialog and the license is acceptable. However, it should be abundantly clear that the project is a fork &lt;/span&gt;&lt;span style=&quot; font-family:'Bitstream Vera Sans'; font-size:11pt; font-weight:600;&quot;&gt;without&lt;/span&gt;&lt;span style=&quot; font-family:'Bitstream Vera Sans'; font-size:11pt;&quot;&gt; implying that you have our blessing.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Oxygen-Sans'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Bitstream Vera Sans';&quot;&gt;We keep MultiMC open source because we think it's important to be able to see the source code for a project like this, and we do so using the Apache license.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Bitstream Vera Sans';&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Bitstream Vera Sans';&quot;&gt;Part of the reason for using the Apache license is we don't want people using the &amp;quot;MultiMC&amp;quot; name when redistributing the project. This means people must take the time to go through the source code and remove all references to &amp;quot;MultiMC&amp;quot;, including but not limited to the project icon and the title of windows, (no *MultiMC-fork* in the title).&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Bitstream Vera Sans';&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Bitstream Vera Sans';&quot;&gt;The Apache license covers reasonable use for the name - a mention of the project's origins in the About dialog and the license is acceptable. However, it should be abundantly clear that the project is a fork &lt;/span&gt;&lt;span style=&quot; font-family:'Bitstream Vera Sans'; font-weight:600;&quot;&gt;without&lt;/span&gt;&lt;span style=&quot; font-family:'Bitstream Vera Sans';&quot;&gt; implying that you have our blessing.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
@@ -445,7 +538,7 @@ p, li { white-space: pre-wrap; }
</layout>
</widget>
<resources>
<include location="../../graphics.qrc"/>
<include location="../../resources/multimc/multimc.qrc"/>
</resources>
<connections/>
</ui>

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,9 +18,9 @@
#include <QItemSelectionModel>
#include <logger/QsLog.h>
#include <QDebug>
#include <gui/dialogs/ProgressDialog.h>
#include <dialogs/ProgressDialog.h>
#include <MultiMC.h>
@@ -40,10 +40,12 @@ AccountSelectDialog::AccountSelectDialog(const QString &message, int flags, QWid
// Flags...
ui->globalDefaultCheck->setVisible(flags & GlobalDefaultCheckbox);
ui->instDefaultCheck->setVisible(flags & InstanceDefaultCheckbox);
QLOG_DEBUG() << flags;
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()));
}
AccountSelectDialog::~AccountSelectDialog()
@@ -72,8 +74,7 @@ void AccountSelectDialog::on_buttonBox_accepted()
if (selection.size() > 0)
{
QModelIndex selected = selection.first();
MojangAccountPtr account = selected.data(MojangAccountList::PointerRole).value<MojangAccountPtr>();
m_selected = account;
m_selected = selected.data(MojangAccountList::PointerRole).value<MojangAccountPtr>();
}
close();
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,7 +19,7 @@
#include <memory>
#include "logic/auth/MojangAccountList.h"
#include "auth/MojangAccountList.h"
namespace Ui
{

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,19 +20,16 @@
#include "CopyInstanceDialog.h"
#include "ui_CopyInstanceDialog.h"
#include "gui/Platform.h"
#include "gui/dialogs/VersionSelectDialog.h"
#include "gui/dialogs/ProgressDialog.h"
#include "gui/dialogs/IconPickerDialog.h"
#include "Platform.h"
#include "dialogs/IconPickerDialog.h"
#include "logic/InstanceFactory.h"
#include "logic/BaseVersion.h"
#include "logic/icons/IconList.h"
#include "logic/lists/MinecraftVersionList.h"
#include "logic/tasks/Task.h"
#include "logic/BaseInstance.h"
#include "BaseVersion.h"
#include "icons/IconList.h"
#include "tasks/Task.h"
#include "BaseInstance.h"
#include "InstanceList.h"
CopyInstanceDialog::CopyInstanceDialog(BaseInstance *original, QWidget *parent)
CopyInstanceDialog::CopyInstanceDialog(InstancePtr original, QWidget *parent)
:QDialog(parent), ui(new Ui::CopyInstanceDialog), m_original(original)
{
MultiMCPlatform::fixWM_CLASS(this);
@@ -41,9 +38,22 @@ CopyInstanceDialog::CopyInstanceDialog(BaseInstance *original, QWidget *parent)
layout()->setSizeConstraint(QLayout::SetFixedSize);
InstIconKey = original->iconKey();
ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
ui->iconButton->setIcon(ENV.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"));
}
CopyInstanceDialog::~CopyInstanceDialog()
@@ -66,6 +76,11 @@ QString CopyInstanceDialog::iconKey() const
return InstIconKey;
}
QString CopyInstanceDialog::instGroup() const
{
return ui->groupBox->currentText();
}
void CopyInstanceDialog::on_iconButton_clicked()
{
IconPickerDialog dlg(this);
@@ -74,7 +89,7 @@ void CopyInstanceDialog::on_iconButton_clicked()
if (dlg.result() == QDialog::Accepted)
{
InstIconKey = dlg.selectedIconKey;
ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
ui->iconButton->setIcon(ENV.icons()->getIcon(InstIconKey));
}
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,8 @@
#pragma once
#include <QDialog>
#include "logic/BaseVersion.h"
#include "BaseVersion.h"
#include <BaseInstance.h>
class BaseInstance;
@@ -30,12 +31,13 @@ class CopyInstanceDialog : public QDialog
Q_OBJECT
public:
explicit CopyInstanceDialog(BaseInstance *original, QWidget *parent = 0);
explicit CopyInstanceDialog(InstancePtr original, QWidget *parent = 0);
~CopyInstanceDialog();
void updateDialogState();
QString instName() const;
QString instGroup() const;
QString iconKey() const;
private
@@ -46,5 +48,5 @@ slots:
private:
Ui::CopyInstanceDialog *ui;
QString InstIconKey;
BaseInstance *m_original;
InstancePtr m_original;
};

View File

@@ -17,7 +17,7 @@
<string>Copy Instance</string>
</property>
<property name="windowIcon">
<iconset resource="../../graphics.qrc">
<iconset>
<normaloff>:/icons/toolbar/copy</normaloff>:/icons/toolbar/copy</iconset>
</property>
<property name="modal">
@@ -42,7 +42,7 @@
<item>
<widget class="QToolButton" name="iconButton">
<property name="icon">
<iconset resource="../../graphics.qrc">
<iconset>
<normaloff>:/icons/instances/infinity</normaloff>:/icons/instances/infinity</iconset>
</property>
<property name="iconSize">
@@ -82,6 +82,33 @@
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="labelVersion_3">
<property name="text">
<string>Group</string>
</property>
<property name="buddy">
<cstring>groupBox</cstring>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QComboBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@ QMessageBox *selectable(QWidget *parent, const QString &title, const QString &te
messageBox->setDefaultButton(defaultButton);
messageBox->setTextInteractionFlags(Qt::TextSelectableByMouse);
messageBox->setIcon(icon);
messageBox->setTextInteractionFlags(Qt::TextBrowserInteraction);
return messageBox;
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -0,0 +1,483 @@
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ExportInstanceDialog.h"
#include "ui_ExportInstanceDialog.h"
#include <BaseInstance.h>
#include <MMCZip.h>
#include <pathutils.h>
#include <QFileDialog>
#include <QMessageBox>
#include <qfilesystemmodel.h>
#include <QSortFilterProxyModel>
#include <QDebug>
#include <qstack.h>
#include <QSaveFile>
#include "MMCStrings.h"
#include "SeparatorPrefixTree.h"
#include "Env.h"
#include <icons/IconList.h>
class PackIgnoreProxy : public QSortFilterProxyModel
{
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(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)
// 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;
}
private:
InstancePtr m_instance;
SeparatorPrefixTree<'/'> blocked;
};
ExportInstanceDialog::ExportInstanceDialog(InstancePtr instance, QWidget *parent)
: 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)));
connect(proxyModel, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(rowsInserted(QModelIndex,int,int)));
model->setRootPath(root);
auto headerView = ui->treeView->header();
headerView->setSectionResizeMode(QHeaderView::ResizeToContents);
headerView->setSectionResizeMode(0, QHeaderView::Stretch);
}
ExportInstanceDialog::~ExportInstanceDialog()
{
delete ui;
}
/// Save icon to instance's folder is needed
void SaveIcon(InstancePtr m_instance)
{
auto iconKey = m_instance->iconKey();
auto iconList = ENV.icons();
auto mmcIcon = iconList->icon(iconKey);
if(mmcIcon)
{
bool saveIcon = false;
switch(mmcIcon->type())
{
case MMCIcon::FileBased:
case MMCIcon::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(PathCombine(m_instance->instanceRoot(), iconKey + ".png"));
}
}
}
bool ExportInstanceDialog::doExport()
{
auto name = RemoveInvalidFilenameChars(m_instance->name());
const QString output = QFileDialog::getSaveFileName(
this, tr("Export %1").arg(m_instance->name()),
PathCombine(QDir::homePath(), name + ".zip"), "Zip (*.zip)");
if (output.isNull())
{
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);
if (!MMCZip::compressDir(output, m_instance->instanceRoot(), name, &proxyModel->blockedPaths()))
{
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);
}
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);
}
}
}
QString ExportInstanceDialog::ignoreFileName()
{
return 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));
}
void ExportInstanceDialog::savePackIgnore()
{
auto filename = ignoreFileName();
QSaveFile ignoreFile(filename);
if(!ignoreFile.open(QIODevice::WriteOnly))
{
ignoreFile.cancelWriting();
}
auto data = proxyModel->blockedPaths().toStringList().join('\n').toUtf8();
ignoreFile.write(data);
ignoreFile.commit();
}
#include "ExportInstanceDialog.moc"

View File

@@ -0,0 +1,54 @@
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <QDialog>
#include <QModelIndex>
#include <memory>
class BaseInstance;
class PackIgnoreProxy;
typedef std::shared_ptr<BaseInstance> InstancePtr;
namespace Ui
{
class ExportInstanceDialog;
}
class ExportInstanceDialog : public QDialog
{
Q_OBJECT
public:
explicit ExportInstanceDialog(InstancePtr instance, QWidget *parent = 0);
~ExportInstanceDialog();
virtual void done(int result);
private:
bool doExport();
void loadPackIgnore();
void savePackIgnore();
QString ignoreFileName();
private:
Ui::ExportInstanceDialog *ui;
InstancePtr m_instance;
PackIgnoreProxy * proxyModel;
private slots:
void rowsInserted(QModelIndex parent, int top, int bottom);
};

View File

@@ -1,30 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EditNotesDialog</class>
<widget class="QDialog" name="EditNotesDialog">
<class>ExportInstanceDialog</class>
<widget class="QDialog" name="ExportInstanceDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>459</width>
<height>399</height>
<width>720</width>
<height>625</height>
</rect>
</property>
<property name="windowTitle">
<string>Edit Notes</string>
<string>Export Instance</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTextEdit" name="noteEditor">
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum>
<widget class="QTreeView" name="treeView">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="acceptRichText">
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="headerStretchLastSection">
<bool>false</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextEditable|Qt::TextEditorInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</attribute>
</widget>
</item>
<item>
@@ -39,12 +42,15 @@
</item>
</layout>
</widget>
<tabstops>
<tabstop>treeView</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>EditNotesDialog</receiver>
<receiver>ExportInstanceDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
@@ -60,7 +66,7 @@
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>EditNotesDialog</receiver>
<receiver>ExportInstanceDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,10 +22,10 @@
#include "IconPickerDialog.h"
#include "ui_IconPickerDialog.h"
#include "gui/Platform.h"
#include "gui/widgets/InstanceDelegate.h"
#include "Platform.h"
#include "groupview/InstanceDelegate.h"
#include "logic/icons/IconList.h"
#include "icons/IconList.h"
IconPickerDialog::IconPickerDialog(QWidget *parent)
: QDialog(parent), ui(new Ui::IconPickerDialog)
@@ -59,7 +59,7 @@ IconPickerDialog::IconPickerDialog(QWidget *parent)
contentsWidget->installEventFilter(this);
contentsWidget->setModel(MMC->icons().get());
contentsWidget->setModel(ENV.icons().get());
auto buttonAdd = ui->buttonBox->addButton(tr("Add Icon"), QDialogButtonBox::ResetRole);
auto buttonRemove =
@@ -104,12 +104,12 @@ void IconPickerDialog::addNewIcon()
//: The type of icon files
QStringList fileNames = QFileDialog::getOpenFileNames(this, selectIcons, QString(),
tr("Icons") + "(*.png *.jpg *.jpeg *.ico)");
MMC->icons()->installIcons(fileNames);
ENV.icons()->installIcons(fileNames);
}
void IconPickerDialog::removeSelectedIcon()
{
MMC->icons()->deleteIcon(selectedIconKey);
ENV.icons()->deleteIcon(selectedIconKey);
}
void IconPickerDialog::activated(QModelIndex index)
@@ -130,7 +130,7 @@ void IconPickerDialog::selectionChanged(QItemSelection selected, QItemSelection
int IconPickerDialog::exec(QString selection)
{
auto list = MMC->icons();
auto list = ENV.icons();
auto contentsWidget = ui->iconView;
selectedIconKey = selection;

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -0,0 +1,110 @@
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "LoginDialog.h"
#include "ui_LoginDialog.h"
#include "auth/YggdrasilTask.h"
#include <QtWidgets/QPushButton>
LoginDialog::LoginDialog(QWidget *parent) : QDialog(parent), ui(new Ui::LoginDialog)
{
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);
}
LoginDialog::~LoginDialog()
{
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();
}
void LoginDialog::setUserInputsEnabled(bool 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());
}
void LoginDialog::on_passTextBox_textEdited(const QString &newText)
{
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>");
// Re-enable user-interaction
setUserInputsEnabled(true);
ui->progressBar->setVisible(false);
}
void LoginDialog::onTaskSucceeded()
{
QDialog::accept();
}
void LoginDialog::onTaskStatus(const QString &status)
{
ui->label->setText(status);
}
void LoginDialog::onTaskProgress(qint64 current, qint64 total)
{
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;
}

View File

@@ -0,0 +1,58 @@
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <QtWidgets/QDialog>
#include <QtCore/QEventLoop>
#include "auth/MojangAccount.h"
namespace Ui
{
class LoginDialog;
}
class LoginDialog : public QDialog
{
Q_OBJECT
public:
~LoginDialog();
static MojangAccountPtr newAccount(QWidget *parent, QString message);
private:
explicit LoginDialog(QWidget *parent = 0);
void setUserInputsEnabled(bool enable);
protected
slots:
void accept();
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);
private:
Ui::LoginDialog *ui;
MojangAccountPtr m_account;
std::shared_ptr<Task> m_loginTask;
};

View File

@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LoginDialog</class>
<widget class="QDialog" name="LoginDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>162</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Add Account</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Message label placeholder.</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="userTextBox">
<property name="placeholderText">
<string>Email / Username</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="passTextBox">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
<property name="placeholderText">
<string>Password</string>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="progressBar">
<property name="value">
<number>24</number>
</property>
<property name="textVisible">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,40 @@
#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;
}
QDesktopServices::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);
}
}

View File

@@ -0,0 +1,9 @@
#pragma once
#include <QModelIndex>
#include <QDesktopServices>
#include <QWidget>
#include <minecraft/Mod.h>
bool lastfirst(QModelIndexList &list, int &first, int &last);
void showWebsiteForMod(QWidget *parentDlg, Mod &m);

View File

@@ -0,0 +1,207 @@
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "MultiMC.h"
#include "NewInstanceDialog.h"
#include "ui_NewInstanceDialog.h"
#include <BaseVersion.h>
#include <icons/IconList.h>
#include <minecraft/MinecraftVersionList.h>
#include <tasks/Task.h>
#include <InstanceList.h>
#include "Platform.h"
#include "VersionSelectDialog.h"
#include "ProgressDialog.h"
#include "IconPickerDialog.h"
#include <QLayout>
#include <QPushButton>
#include <QFileDialog>
#include <QValidator>
class UrlValidator : public QValidator
{
public:
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;
}
}
};
NewInstanceDialog::NewInstanceDialog(QWidget *parent)
: QDialog(parent), ui(new Ui::NewInstanceDialog)
{
MultiMCPlatform::fixWM_CLASS(this);
ui->setupUi(this);
resize(minimumSizeHint());
layout()->setSizeConstraint(QLayout::SetFixedSize);
setSelectedVersion(MMC->minecraftlist()->getRecommended(), true);
InstIconKey = "default";
ui->iconButton->setIcon(ENV.icons()->getIcon(InstIconKey));
ui->modpackEdit->setValidator(new UrlValidator(ui->modpackEdit));
connect(ui->modpackEdit, &QLineEdit::textChanged, this, &NewInstanceDialog::updateDialogState);
connect(ui->modpackBox, &QRadioButton::clicked, this, &NewInstanceDialog::updateDialogState);
connect(ui->versionBox, &QRadioButton::clicked, this, &NewInstanceDialog::updateDialogState);
auto groups = MMC->instances()->getGroups().toSet();
auto groupList = QStringList(groups.toList());
groupList.sort(Qt::CaseInsensitive);
groupList.removeOne("");
QString oldValue = MMC->settings()->get("LastUsedGroupForNewInstance").toString();
groupList.push_front(oldValue);
groupList.push_front("");
ui->groupBox->addItems(groupList);
int index = groupList.indexOf(oldValue);
if(index == -1)
{
index = 0;
}
ui->groupBox->setCurrentIndex(index);
ui->groupBox->lineEdit()->setPlaceholderText(tr("No group"));
}
NewInstanceDialog::~NewInstanceDialog()
{
delete ui;
}
void NewInstanceDialog::updateDialogState()
{
bool allowOK = !instName().isEmpty() &&
(ui->versionBox->isChecked() && m_selectedVersion ||
(ui->modpackBox->isChecked() && ui->modpackEdit->hasAcceptableInput()));
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(allowOK);
}
void NewInstanceDialog::setSelectedVersion(BaseVersionPtr version, bool initial)
{
m_selectedVersion = version;
if (m_selectedVersion)
{
ui->versionTextBox->setText(version->name());
if(ui->instNameTextBox->text().isEmpty() && !initial)
{
ui->instNameTextBox->setText(version->name());
}
}
else
{
ui->versionTextBox->setText("");
}
updateDialogState();
}
QString NewInstanceDialog::instName() const
{
return ui->instNameTextBox->text();
}
QString NewInstanceDialog::instGroup() const
{
return ui->groupBox->currentText();
}
QString NewInstanceDialog::iconKey() const
{
return InstIconKey;
}
QUrl NewInstanceDialog::modpackUrl() const
{
if (ui->modpackBox->isChecked())
{
const QUrl url(ui->modpackEdit->text());
if (url.isValid() && !url.isRelative() && !url.host().isEmpty())
{
return url;
}
else
{
return QUrl::fromLocalFile(ui->modpackEdit->text());
}
}
else
{
return QUrl();
}
}
BaseVersionPtr NewInstanceDialog::selectedVersion() const
{
return m_selectedVersion;
}
void NewInstanceDialog::on_btnChangeVersion_clicked()
{
VersionSelectDialog vselect(MMC->minecraftlist().get(), tr("Change Minecraft version"),
this);
vselect.exec();
if (vselect.result() == QDialog::Accepted)
{
BaseVersionPtr version = vselect.selectedVersion();
if (version)
setSelectedVersion(version);
}
}
void NewInstanceDialog::on_iconButton_clicked()
{
IconPickerDialog dlg(this);
dlg.exec(InstIconKey);
if (dlg.result() == QDialog::Accepted)
{
InstIconKey = dlg.selectedIconKey;
ui->iconButton->setIcon(ENV.icons()->getIcon(InstIconKey));
}
}
void NewInstanceDialog::on_instNameTextBox_textChanged(const QString &arg1)
{
updateDialogState();
}
void NewInstanceDialog::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());
}
}
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,8 @@
#pragma once
#include <QDialog>
#include "logic/BaseVersion.h"
#include "BaseVersion.h"
namespace Ui
{
@@ -33,18 +34,21 @@ public:
void updateDialogState();
void setSelectedVersion(BaseVersionPtr version);
void setSelectedVersion(BaseVersionPtr version, bool initial = false);
void loadVersionList();
QString instName() const;
QString instGroup() const;
QString iconKey() const;
QUrl modpackUrl() const;
BaseVersionPtr selectedVersion() const;
private
slots:
void on_btnChangeVersion_clicked();
void on_iconButton_clicked();
void on_modpackBtn_clicked();
void on_instNameTextBox_textChanged(const QString &arg1);
private:

View File

@@ -9,15 +9,15 @@
<rect>
<x>0</x>
<y>0</y>
<width>220</width>
<height>234</height>
<width>277</width>
<height>404</height>
</rect>
</property>
<property name="windowTitle">
<string>New Instance</string>
</property>
<property name="windowIcon">
<iconset resource="../../graphics.qrc">
<iconset>
<normaloff>:/icons/toolbar/new</normaloff>:/icons/toolbar/new</iconset>
</property>
<property name="modal">
@@ -41,10 +41,6 @@
</item>
<item>
<widget class="QToolButton" name="iconButton">
<property name="icon">
<iconset resource="../../graphics.qrc">
<normaloff>:/icons/instances/infinity</normaloff>:/icons/instances/infinity</iconset>
</property>
<property name="iconSize">
<size>
<width>80</width>
@@ -85,26 +81,83 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="labelVersion">
<widget class="QLabel" name="labelVersion_3">
<property name="text">
<string>Version:</string>
<string>&amp;Group:</string>
</property>
<property name="buddy">
<cstring>groupBox</cstring>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="4" column="2">
<widget class="QToolButton" name="modpackBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QLineEdit" name="modpackEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>http://</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLineEdit" name="versionTextBox">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<item row="2" column="2">
<widget class="QToolButton" name="btnChangeVersion">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="QRadioButton" name="modpackBox">
<property name="text">
<string>Impor&amp;t Modpack (local file or link):</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="3">
<widget class="QRadioButton" name="versionBox">
<property name="text">
<string>Vani&amp;lla Minecraft (select version):</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
@@ -139,9 +192,18 @@
</item>
</layout>
</widget>
<resources>
<include location="../../graphics.qrc"/>
</resources>
<tabstops>
<tabstop>instNameTextBox</tabstop>
<tabstop>groupBox</tabstop>
<tabstop>versionBox</tabstop>
<tabstop>versionTextBox</tabstop>
<tabstop>btnChangeVersion</tabstop>
<tabstop>modpackBox</tabstop>
<tabstop>modpackEdit</tabstop>
<tabstop>modpackBtn</tabstop>
<tabstop>iconButton</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
@@ -150,8 +212,8 @@
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
<x>257</x>
<y>333</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
@@ -166,8 +228,8 @@
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
<x>325</x>
<y>333</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
@@ -175,5 +237,69 @@
</hint>
</hints>
</connection>
<connection>
<sender>modpackBox</sender>
<signal>toggled(bool)</signal>
<receiver>modpackEdit</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>81</x>
<y>229</y>
</hint>
<hint type="destinationlabel">
<x>236</x>
<y>221</y>
</hint>
</hints>
</connection>
<connection>
<sender>modpackBox</sender>
<signal>toggled(bool)</signal>
<receiver>modpackBtn</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>129</x>
<y>225</y>
</hint>
<hint type="destinationlabel">
<x>328</x>
<y>229</y>
</hint>
</hints>
</connection>
<connection>
<sender>versionBox</sender>
<signal>toggled(bool)</signal>
<receiver>versionTextBox</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>93</x>
<y>195</y>
</hint>
<hint type="destinationlabel">
<x>213</x>
<y>191</y>
</hint>
</hints>
</connection>
<connection>
<sender>versionBox</sender>
<signal>toggled(bool)</signal>
<receiver>btnChangeVersion</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>104</x>
<y>198</y>
</hint>
<hint type="destinationlabel">
<x>322</x>
<y>192</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,84 @@
#include "NotificationDialog.h"
#include "ui_NotificationDialog.h"
#include <QTimerEvent>
NotificationDialog::NotificationDialog(const NotificationChecker::NotificationEntry &entry, QWidget *parent) :
QDialog(parent, Qt::MSWindowsFixedSizeDialogHint | Qt::WindowTitleHint | Qt::CustomizeWindowHint),
ui(new Ui::NotificationDialog)
{
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;
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");
ui->dontShowAgainBtn->setText(m_dontShowAgainText + QString(" (%1)").arg(m_dontShowAgainTime));
ui->closeBtn->setText(m_closeText + QString(" (%1)").arg(m_closeTime));
startTimer(1000);
}
NotificationDialog::~NotificationDialog()
{
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_closeTime == 0 && m_dontShowAgainTime == 0)
{
killTimer(event->timerId());
}
}
void NotificationDialog::on_dontShowAgainBtn_clicked()
{
done(DontShowAgain);
}
void NotificationDialog::on_closeBtn_clicked()
{
done(Normal);
}

View File

@@ -0,0 +1,44 @@
#ifndef NOTIFICATIONDIALOG_H
#define NOTIFICATIONDIALOG_H
#include <QDialog>
#include "notifications/NotificationChecker.h"
namespace Ui {
class NotificationDialog;
}
class NotificationDialog : public QDialog
{
Q_OBJECT
public:
explicit NotificationDialog(const NotificationChecker::NotificationEntry &entry, QWidget *parent = 0);
~NotificationDialog();
enum ExitCode
{
Normal,
DontShowAgain
};
protected:
void timerEvent(QTimerEvent *event);
private:
Ui::NotificationDialog *ui;
int m_dontShowAgainTime = 10;
int m_closeTime = 5;
QString m_dontShowAgainText;
QString m_closeText;
private
slots:
void on_dontShowAgainBtn_clicked();
void on_closeBtn_clicked();
};
#endif // NOTIFICATIONDIALOG_H

View File

@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NotificationDialog</class>
<widget class="QDialog" name="NotificationDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>320</width>
<height>240</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="1,0">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,1">
<item>
<widget class="QLabel" name="iconLabel">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="messageLabel">
<property name="text">
<string>TextLabel</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextBrowserInteraction</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="dontShowAgainBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Don't show again</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="closeBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,8 +18,8 @@
#include <QKeyEvent>
#include "logic/tasks/Task.h"
#include "gui/Platform.h"
#include "tasks/Task.h"
#include "Platform.h"
ProgressDialog::ProgressDialog(QWidget *parent) : QDialog(parent), ui(new Ui::ProgressDialog)
{
@@ -54,7 +54,7 @@ void ProgressDialog::updateSize()
resize(QSize(480, minimumSizeHint().height()));
}
int ProgressDialog::exec(ProgressProvider *task)
int ProgressDialog::exec(Task *task)
{
this->task = task;
@@ -71,10 +71,10 @@ int ProgressDialog::exec(ProgressProvider *task)
if(task->isRunning())
return QDialog::exec();
else
return 0;
return QDialog::Accepted;
}
ProgressProvider *ProgressDialog::getTask()
Task *ProgressDialog::getTask()
{
return task;
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,7 +17,7 @@
#include <QDialog>
class ProgressProvider;
class Task;
namespace Ui
{
@@ -34,10 +34,11 @@ public:
void updateSize();
int exec(ProgressProvider *task);
int exec(Task *task);
void setSkipButton(bool present, QString label = QString());
ProgressProvider *getTask();
Task *getTask();
public
slots:
@@ -48,7 +49,7 @@ slots:
void changeStatus(const QString &status);
void changeProgress(qint64 current, qint64 total);
private
slots:
void on_skipButton_clicked(bool checked);
@@ -60,5 +61,5 @@ protected:
private:
Ui::ProgressDialog *ui;
ProgressProvider *task;
Task *task;
};

View File

@@ -0,0 +1,136 @@
#include "UpdateDialog.h"
#include "ui_UpdateDialog.h"
#include "Platform.h"
#include <QDebug>
#include "MultiMC.h"
#include <settings/SettingsObject.h>
#include <hoedown/html.h>
#include <hoedown/document.h>
UpdateDialog::UpdateDialog(bool hasUpdate, QWidget *parent) : QDialog(parent), ui(new Ui::UpdateDialog)
{
MultiMCPlatform::fixWM_CLASS(this);
ui->setupUi(this);
auto channel = MMC->settings()->get("UpdateChannel").toString();
if(hasUpdate)
{
ui->label->setText(tr("A new %1 update is available!").arg(channel));
}
else
{
ui->label->setText(tr("No %1 updates found. You are running the latest version.").arg(channel));
ui->btnUpdateNow->setDisabled(true);
ui->btnUpdateOnExit->setDisabled(true);
}
loadChangelog();
}
UpdateDialog::~UpdateDialog()
{
}
void UpdateDialog::loadChangelog()
{
auto channel = MMC->settings()->get("UpdateChannel").toString();
dljob.reset(new NetJob("Changelog"));
auto url = QString("https://raw.githubusercontent.com/MultiMC/MultiMC5/%1/changelog.md").arg(channel);
changelogDownload = ByteArrayDownload::make(QUrl(url));
dljob->addNetAction(changelogDownload);
connect(dljob.get(), &NetJob::succeeded, this, &UpdateDialog::changelogLoaded);
connect(dljob.get(), &NetJob::failed, this, &UpdateDialog::changelogFailed);
dljob->start();
}
/**
* hoedown wrapper, because dealing with resource lifetime in C is stupid
*/
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();
}
private:
hoedown_document * document;
hoedown_renderer * renderer;
};
QString reprocessMarkdown(QByteArray 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;
}
void UpdateDialog::changelogLoaded()
{
auto html = reprocessMarkdown(changelogDownload->m_data);
ui->changelogBrowser->setHtml(html);
}
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));
}
void UpdateDialog::on_btnUpdateLater_clicked()
{
reject();
}
void UpdateDialog::on_btnUpdateNow_clicked()
{
done(UPDATE_NOW);
}
void UpdateDialog::on_btnUpdateOnExit_clicked()
{
done(UPDATE_ONEXIT);
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
#pragma once
#include <QDialog>
#include "net/ByteArrayDownload.h"
#include "net/NetJob.h"
namespace Ui
{
@@ -34,7 +36,7 @@ class UpdateDialog : public QDialog
Q_OBJECT
public:
explicit UpdateDialog(QWidget *parent = 0);
explicit UpdateDialog(bool hasUpdate = true, QWidget *parent = 0);
~UpdateDialog();
private:
@@ -43,4 +45,17 @@ public slots:
void on_btnUpdateNow_clicked();
void on_btnUpdateOnExit_clicked();
void on_btnUpdateLater_clicked();
/// Starts loading the changelog
void loadChangelog();
/// Slot for when the chengelog loads successfully.
void changelogLoaded();
/// Slot for when the chengelog fails to load...
void changelogFailed(QString reason);
private:
ByteArrayDownloadPtr changelogDownload;
NetJobPtr dljob;
};

View File

@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>UpdateDialog</class>
<widget class="QDialog" name="UpdateDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>657</width>
<height>673</height>
</rect>
</property>
<property name="windowTitle">
<string>MultiMC Update</string>
</property>
<property name="windowIcon">
<iconset>
<normaloff>:/icons/toolbar/checkupdate</normaloff>:/icons/toolbar/checkupdate</iconset>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>changelogBrowser</cstring>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTextBrowser" name="changelogBrowser">
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Bitstream Vera Sans'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p align=&quot;center&quot; style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:22pt;&quot;&gt;Loading changelog...&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="btnUpdateNow">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Update now</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnUpdateOnExit">
<property name="text">
<string>Update after MultiMC closes</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnUpdateLater">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Don't update yet</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<tabstops>
<tabstop>changelogBrowser</tabstop>
<tabstop>btnUpdateNow</tabstop>
<tabstop>btnUpdateOnExit</tabstop>
<tabstop>btnUpdateLater</tabstop>
</tabstops>
<resources>
<include location="../../resources/multimc/multimc.qrc"/>
</resources>
<connections/>
</ui>

View File

@@ -0,0 +1,194 @@
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "VersionSelectDialog.h"
#include "ui_VersionSelectDialog.h"
#include <QHeaderView>
#include <dialogs/ProgressDialog.h>
#include "CustomMessageBox.h"
#include "Platform.h"
#include <BaseVersion.h>
#include <BaseVersionList.h>
#include <tasks/Task.h>
#include <modutils.h>
#include <QDebug>
#include "MultiMC.h"
#include <VersionProxyModel.h>
VersionSelectDialog::VersionSelectDialog(BaseVersionList *vlist, QString title, QWidget *parent,
bool cancelable)
: QDialog(parent), ui(new Ui::VersionSelectDialog)
{
MultiMCPlatform::fixWM_CLASS(this);
ui->setupUi(this);
setWindowModality(Qt::WindowModal);
setWindowTitle(title);
m_vlist = vlist;
m_proxyModel = new VersionProxyModel(this);
m_proxyModel->setSourceModel(vlist);
ui->listView->setModel(m_proxyModel);
ui->listView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
ui->listView->header()->setSectionResizeMode(resizeOnColumn, QHeaderView::Stretch);
ui->sneakyProgressBar->setHidden(true);
if (!cancelable)
{
ui->buttonBox->button(QDialogButtonBox::Cancel)->setEnabled(false);
}
}
void VersionSelectDialog::setEmptyString(QString emptyString)
{
ui->listView->setEmptyString(emptyString);
}
void VersionSelectDialog::setEmptyErrorString(QString emptyErrorString)
{
ui->listView->setEmptyErrorString(emptyErrorString);
}
VersionSelectDialog::~VersionSelectDialog()
{
delete ui;
}
void VersionSelectDialog::setResizeOn(int column)
{
ui->listView->header()->setSectionResizeMode(resizeOnColumn, QHeaderView::ResizeToContents);
resizeOnColumn = column;
ui->listView->header()->setSectionResizeMode(resizeOnColumn, QHeaderView::Stretch);
}
int VersionSelectDialog::exec()
{
QDialog::open();
if (!m_vlist->isLoaded())
{
loadList();
}
else
{
if (m_proxyModel->rowCount() == 0)
{
ui->listView->setEmptyMode(VersionListView::String);
}
preselect();
}
return QDialog::exec();
}
void VersionSelectDialog::closeEvent(QCloseEvent * event)
{
if(loadTask)
{
loadTask->abort();
loadTask->deleteLater();
loadTask = nullptr;
}
QDialog::closeEvent(event);
}
void VersionSelectDialog::loadList()
{
if(loadTask)
{
return;
}
loadTask = m_vlist->getLoadTask();
if (!loadTask)
{
return;
}
connect(loadTask, &Task::finished, this, &VersionSelectDialog::onTaskFinished);
connect(loadTask, &Task::progress, this, &VersionSelectDialog::changeProgress);
loadTask->start();
ui->sneakyProgressBar->setHidden(false);
}
void VersionSelectDialog::onTaskFinished()
{
if (!loadTask->successful())
{
CustomMessageBox::selectable(this, tr("Error"),
tr("List update failed:\n%1").arg(loadTask->failReason()),
QMessageBox::Warning)->show();
if (m_proxyModel->rowCount() == 0)
{
ui->listView->setEmptyMode(VersionListView::ErrorString);
}
}
else if (m_proxyModel->rowCount() == 0)
{
ui->listView->setEmptyMode(VersionListView::String);
}
ui->sneakyProgressBar->setHidden(true);
loadTask->deleteLater();
loadTask = nullptr;
preselect();
}
void VersionSelectDialog::changeProgress(qint64 current, qint64 total)
{
ui->sneakyProgressBar->setMaximum(total);
ui->sneakyProgressBar->setValue(current);
}
void VersionSelectDialog::preselect()
{
if(preselectedAlready)
return;
preselectedAlready = true;
selectRecommended();
}
void VersionSelectDialog::selectRecommended()
{
auto idx = m_proxyModel->getRecommended();
if(idx.isValid())
{
ui->listView->selectionModel()->setCurrentIndex(idx,QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
ui->listView->scrollTo(idx, QAbstractItemView::PositionAtCenter);
}
}
BaseVersionPtr VersionSelectDialog::selectedVersion() const
{
auto currentIndex = ui->listView->selectionModel()->currentIndex();
auto variant = m_proxyModel->data(currentIndex, BaseVersionList::VersionPointerRole);
return variant.value<BaseVersionPtr>();
}
void VersionSelectDialog::on_refreshButton_clicked()
{
loadList();
}
void VersionSelectDialog::setExactFilter(BaseVersionList::ModelRoles role, QString filter)
{
m_proxyModel->setFilter(role, filter, true);
}
void VersionSelectDialog::setFuzzyFilter(BaseVersionList::ModelRoles role, QString filter)
{
m_proxyModel->setFilter(role, filter, false);
}
#include "VersionSelectDialog.moc"

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,15 +18,15 @@
#include <QDialog>
#include <QSortFilterProxyModel>
#include "logic/BaseVersion.h"
class BaseVersionList;
#include "BaseVersionList.h"
namespace Ui
{
class VersionSelectDialog;
}
class VersionProxyModel;
class VersionSelectDialog : public QDialog
{
Q_OBJECT
@@ -43,19 +43,37 @@ public:
BaseVersionPtr selectedVersion() const;
void setFilter(int column, QString filter);
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 setUseLatest(const bool useLatest);
protected:
virtual void closeEvent ( QCloseEvent* );
private
slots:
void on_refreshButton_clicked();
void onTaskFinished();
void changeProgress(qint64 current, qint64 total);
private:
Ui::VersionSelectDialog *ui;
void preselect();
void selectRecommended();
BaseVersionList *m_vlist;
private:
Ui::VersionSelectDialog *ui = nullptr;
QSortFilterProxyModel *m_proxyModel;
BaseVersionList *m_vlist = nullptr;
VersionProxyModel *m_proxyModel = nullptr;
int resizeOnColumn = 0;
Task * loadTask = nullptr;
bool preselectedAlready = false;
};

View File

@@ -15,7 +15,7 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTreeView" name="listView">
<widget class="VersionListView" name="listView">
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
@@ -39,6 +39,16 @@
</attribute>
</widget>
</item>
<item>
<widget class="QProgressBar" name="sneakyProgressBar">
<property name="value">
<number>24</number>
</property>
<property name="format">
<string notr="true">%p%</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
@@ -65,6 +75,13 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>VersionListView</class>
<extends>QTreeView</extends>
<header>widgets/VersionListView.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,125 @@
#pragma once
#include <QListView>
#include <QLineEdit>
#include <QScrollBar>
#include <QCache>
struct GroupViewRoles
{
enum
{
GroupRole = Qt::UserRole,
ProgressValueRole,
ProgressMaximumRole
};
};
struct VisualGroup;
class GroupView : public QAbstractItemView
{
Q_OBJECT
public:
GroupView(QWidget *parent = 0);
~GroupView();
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;
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 QModelIndex moveCursor(CursorAction cursorAction,
Qt::KeyboardModifiers modifiers) override;
virtual QRegion visualRegionForSelection(const QItemSelection &selection) const override;
int spacing() const
{
return m_spacing;
};
protected
slots:
virtual void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
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;
virtual void updateGeometries() override;
void modelReset();
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;
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;
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) 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;
bool isDragEventAccepted(QDropEvent *event);
QPair<VisualGroup *, int> rowDropPos(const QPoint &pos);
QPoint offset() const;
};

View File

@@ -0,0 +1,33 @@
#include "GroupedProxyModel.h"
#include "GroupView.h"
#include <QDebug>
GroupedProxyModel::GroupedProxyModel(QObject *parent) : QSortFilterProxyModel(parent)
{
}
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;
}
}
bool GroupedProxyModel::subSortLessThan(const QModelIndex &left, const QModelIndex &right) const
{
return left.row() < right.row();
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include <QSortFilterProxyModel>
class GroupedProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
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;
};

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +18,13 @@
#include <QTextOption>
#include <QTextLayout>
#include <QApplication>
#include <QtCore/qmath.h>
#include <QtMath>
#include "GroupView.h"
#include "BaseInstance.h"
#include "InstanceList.h"
QCache<QString, QPixmap> ListViewDelegate::m_pixmapCache;
// Origin: Qt
static void viewItemTextLayout(QTextLayout &textLayout, int lineWidth, qreal &height,
@@ -43,8 +49,6 @@ static void viewItemTextLayout(QTextLayout &textLayout, int lineWidth, qreal &he
textLayout.endLayout();
}
#define QFIXED_MAX (INT_MAX / 256)
ListViewDelegate::ListViewDelegate(QObject *parent) : QStyledItemDelegate(parent)
{
}
@@ -85,6 +89,85 @@ void drawFocusRect(QPainter *painter, const QStyleOptionViewItemV4 &option, cons
painter->setRenderHint(QPainter::Antialiasing);
}
// TODO this can be made a lot prettier
void drawProgressOverlay(QPainter *painter, const QStyleOptionViewItemV4 &option,
const int value, const int maximum)
{
if (maximum == 0 || value == maximum)
{
return;
}
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);
painter->restore();
}
void drawBadges(QPainter *painter, const QStyleOptionViewItemV4 &option, BaseInstance *instance)
{
QList<QString> pixmaps;
const BaseInstance::InstanceFlags flags = instance->flags();
if (flags & BaseInstance::VersionBrokenFlag)
{
pixmaps.append("broken");
}
if (flags & BaseInstance::UpdateAvailable)
{
pixmaps.append("updateavailable");
}
// begin easter eggs
if (instance->name().contains("btw", Qt::CaseInsensitive) ||
instance->name().contains("better then wolves", Qt::CaseInsensitive) ||
instance->name().contains("better than wolves", Qt::CaseInsensitive))
{
pixmaps.append("herobrine");
}
if (instance->name().contains("direwolf", Qt::CaseInsensitive))
{
pixmaps.append("enderman");
}
if (instance->name().contains("kitten", Qt::CaseInsensitive))
{
pixmaps.append("kitten");
}
if (instance->name().contains("derp", Qt::CaseInsensitive))
{
pixmaps.append("derp");
}
// end easter eggs
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;
}
const QPixmap pixmap = ListViewDelegate::requestBadgePixmap(it.next()).scaled(
itemSide, itemSide, Qt::KeepAspectRatio, Qt::FastTransformation);
painter->drawPixmap(option.rect.width() - x * itemSide + qMax(x - 1, 0) * spacing - itemSide,
y * itemSide + qMax(y - 1, 0) * spacing, itemSide, itemSide,
pixmap);
}
}
painter->translate(-option.rect.topLeft());
}
static QSize viewItemTextSize(const QStyleOptionViewItemV4 *option)
{
QStyle *style = option->widget ? option->widget->style() : QApplication::style();
@@ -150,6 +233,7 @@ void ListViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti
opt2.palette.setCurrentColorGroup(cg);
// fill in background, if any
if (opt.backgroundBrush.style() != Qt::NoBrush)
{
QPointF oldBO = painter->brushOrigin();
@@ -158,6 +242,9 @@ void ListViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti
painter->setBrushOrigin(oldBO);
}
drawSelectionRect(painter, opt2, textHighlightRect);
/*
if (opt.showDecorationSelected)
{
drawSelectionRect(painter, opt2, opt.rect);
@@ -177,6 +264,7 @@ void ListViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti
drawFocusRect(painter, opt2, textHighlightRect);
}
}
*/
}
// draw the icon
@@ -229,6 +317,17 @@ void ListViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti
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);
}
drawProgressOverlay(painter, opt, index.data(GroupViewRoles::ProgressValueRole).toInt(),
index.data(GroupViewRoles::ProgressMaximumRole).toInt());
painter->restore();
}
@@ -252,3 +351,12 @@ QSize ListViewDelegate::sizeHint(const QStyleOptionViewItem &option,
QSize sz(100, height);
return sz;
}
QPixmap ListViewDelegate::requestBadgePixmap(const QString &key)
{
if (!m_pixmapCache.contains(key))
{
m_pixmapCache.insert(key, new QPixmap(":/icons/badges/" + key + ".png"));
}
return *m_pixmapCache.object(key);
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,12 +16,20 @@
#pragma once
#include <QStyledItemDelegate>
#include <QCache>
class ListViewDelegate : public QStyledItemDelegate
{
public:
explicit ListViewDelegate ( QObject* parent = 0 );
explicit ListViewDelegate(QObject *parent = 0);
static QPixmap requestBadgePixmap(const QString &key);
protected:
void paint ( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const;
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
private:
static QCache<QString, QPixmap> m_pixmapCache;
};

View File

@@ -0,0 +1,301 @@
#include "VisualGroup.h"
#include <QModelIndex>
#include <QPainter>
#include <QtMath>
#include <QApplication>
#include "GroupView.h"
VisualGroup::VisualGroup(const QString &text, GroupView *view) : view(view), text(text), collapsed(false)
{
}
VisualGroup::VisualGroup(const VisualGroup *other)
: 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;
}
QPair<int, int> VisualGroup::positionOf(const QModelIndex &index) const
{
int x = 0;
int y = 0;
for (auto & row: rows)
{
for(auto x = 0; x < row.items.size(); x++)
{
if(row.items[x] == index)
{
return qMakePair(x,y);
}
}
y++;
}
return qMakePair(x, y);
}
int VisualGroup::rowTopOf(const QModelIndex &index) const
{
auto position = positionOf(index);
return rows[position.second].top;
}
int VisualGroup::rowHeightOf(const QModelIndex &index) const
{
auto position = positionOf(index);
return rows[position.second].height;
}
VisualGroup::HitResults VisualGroup::hitScan(const QPoint &pos) const
{
VisualGroup::HitResults results = VisualGroup::NoHit;
int y_start = verticalPosition();
int body_start = y_start + headerHeight();
int body_end = body_start + contentHeight() + 5; // FIXME: wtf is this 5?
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
}
int VisualGroup::totalHeight() const
{
return headerHeight() + 5 + contentHeight(); // FIXME: wtf is that '5'?
}
int VisualGroup::headerHeight() const
{
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 VisualGroup::contentHeight() const
{
if (collapsed)
{
return 0;
}
auto last = rows[numRows() - 1];
return last.top + last.height;
}
int VisualGroup::numRows() const
{
return rows.size();
}
int VisualGroup::verticalPosition() const
{
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;
}

View File

@@ -0,0 +1,91 @@
#pragma once
#include <QString>
#include <QRect>
#include <QVector>
#include <QStyleOption>
class GroupView;
class QPainter;
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];
}
};
struct VisualGroup
{
/* constructors */
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;
/* logic */
/// 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);
/// 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 content, in pixels
int contentHeight() const;
/// the number of visual rows this group has
int numRows() const;
/// actually calculate the above value
int calculateNumRows() const;
/// the height at which this group starts, in pixels
int verticalPosition() const;
/// relative geometry - top of the row of the given item
int rowTopOf(const QModelIndex &index) const;
/// height of the row of the given item
int rowHeightOf(const QModelIndex &index) const;
/// x/y position of the given item inside the group (in items!)
QPair<int, int> positionOf(const QModelIndex &index) const;
enum HitResult
{
NoHit = 0x0,
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;
QList<QModelIndex> items() const;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(VisualGroup::HitResults)

View File

@@ -1,4 +1,6 @@
FILE(GLOB_RECURSE QTPLUGINS "${CMAKE_INSTALL_PREFIX}/@PLUGIN_DEST_DIR@/*@CMAKE_SHARED_LIBRARY_SUFFIX@")
set(CMAKE_MODULE_PATH "@CMAKE_MODULE_PATH@")
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")
message("resolving ${resolved_file} as other")
@@ -6,12 +8,18 @@ function(gp_resolved_file_type_override resolved_file type_var)
elseif(resolved_file MATCHES "^/usr/lib(.+)?/libxcb")
message("resolving ${resolved_file} as other")
set(${type_var} other PARENT_SCOPE)
endif()
elseif(resolved_file MATCHES "^/usr/lib(.+)?/libicu")
message("resolving ${resolved_file} as other")
set(${type_var} other PARENT_SCOPE)
elseif((resolved_file MATCHES "^/usr/lib(.+)?/libstdc\\+\\+") AND (UNIX AND NOT APPLE))
message("resolving ${resolved_file} as other")
set(${type_var} other PARENT_SCOPE)
endif()
endfunction()
set(gp_tool "@CMAKE_GP_TOOL@")
set(gp_cmd_paths ${gp_cmd_paths}
"@CMAKE_GP_CMD_PATHS@"
"@CMAKE_GP_CMD_PATHS@"
)
include(BundleUtilities)

View File

@@ -1,15 +1,16 @@
#include "MultiMC.h"
#include "gui/MainWindow.h"
#include "MainWindow.h"
int main_gui(MultiMC &app)
{
// show main window
app.setIconTheme(MMC->settings()->get("IconTheme").toString());
MainWindow mainWin;
mainWin.restoreState(QByteArray::fromBase64(MMC->settings()->get("MainWindowState").toByteArray()));
mainWin.restoreGeometry(QByteArray::fromBase64(MMC->settings()->get("MainWindowGeometry").toByteArray()));
mainWin.show();
mainWin.checkMigrateLegacyAssets();
mainWin.checkSetDefaultJava();
mainWin.checkInstancePathForProblems();
return app.exec();
}
@@ -18,8 +19,17 @@ int main(int argc, char *argv[])
// initialize Qt
MultiMC app(argc, argv);
Q_INIT_RESOURCE(graphics);
Q_INIT_RESOURCE(generated);
Q_INIT_RESOURCE(instances);
Q_INIT_RESOURCE(multimc);
Q_INIT_RESOURCE(backgrounds);
Q_INIT_RESOURCE(versions);
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);
switch (app.status())
{

View File

@@ -34,6 +34,13 @@ if [ "x$DEPS_LIST" = "x" ]; then
# 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 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 $?
else

View File

@@ -0,0 +1,65 @@
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "PageDialog.h"
#include <QDialogButtonBox>
#include <QPushButton>
#include <QVBoxLayout>
#include <QKeyEvent>
#include "MultiMC.h"
#include "settings/SettingsObject.h"
#include "Platform.h"
#include "widgets/IconLabel.h"
#include "widgets/PageContainer.h"
PageDialog::PageDialog(BasePageProviderPtr pageProvider, QString defaultId, QWidget *parent)
: QDialog(parent)
{
MultiMCPlatform::fixWM_CLASS(this);
setWindowTitle(pageProvider->dialogTitle());
m_container = new PageContainer(pageProvider, defaultId, this);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(m_container);
mainLayout->setSpacing(0);
mainLayout->setContentsMargins(0, 0, 0, 0);
setLayout(mainLayout);
QDialogButtonBox *buttons =
new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Close);
buttons->button(QDialogButtonBox::Close)->setDefault(true);
m_container->addButtons(buttons);
connect(buttons->button(QDialogButtonBox::Close), SIGNAL(clicked()), this, SLOT(close()));
connect(buttons->button(QDialogButtonBox::Help), SIGNAL(clicked()), m_container,
SLOT(help()));
restoreGeometry(
QByteArray::fromBase64(MMC->settings()->get("PagedGeometry").toByteArray()));
}
void PageDialog::closeEvent(QCloseEvent *event)
{
qDebug() << "Paged dialog close requested";
if (m_container->requestClose(event))
{
qDebug() << "Paged dialog close approved";
MMC->settings()->set("PagedGeometry", saveGeometry().toBase64());
qDebug() << "Paged dialog geometry saved";
QDialog::closeEvent(event);
}
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,29 +16,21 @@
#pragma once
#include <QDialog>
#include "pages/BasePageProvider.h"
namespace Ui
{
class LWJGLSelectDialog;
}
class LWJGLSelectDialog : public QDialog
class PageContainer;
class PageDialog : public QDialog
{
Q_OBJECT
public:
explicit LWJGLSelectDialog(QWidget *parent = 0);
~LWJGLSelectDialog();
QString selectedVersion() const;
explicit PageDialog(BasePageProviderPtr pageProvider, QString defaultId = QString(),
QWidget *parent = 0);
virtual ~PageDialog() {}
private
slots:
void on_refreshButton_clicked();
void loadingStateUpdated(bool loading);
void loadingFailed(QString error);
virtual void closeEvent(QCloseEvent *event);
private:
Ui::LWJGLSelectDialog *ui;
PageContainer * m_container;
};

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,23 +14,30 @@
*/
#pragma once
#include <QString>
#include <QIcon>
#include <memory>
class OneSixVersion;
#include "BasePageContainer.h"
class ForgeInstaller
class BasePage
{
public:
ForgeInstaller(QString filename, QString universal_url);
virtual ~BasePage() {}
virtual QString id() const = 0;
virtual QString displayName() const = 0;
virtual QIcon icon() const = 0;
virtual bool apply() { return true; }
virtual bool shouldDisplay() const { return true; }
virtual QString helpPage() const { return QString(); }
virtual void opened() {}
virtual void closed() {}
virtual void setParentContainer(BasePageContainer *) {};
bool apply(std::shared_ptr<OneSixVersion> to);
private:
// the version, read from the installer
std::shared_ptr<OneSixVersion> m_forge_version;
QString internalPath;
QString finalPath;
QString realVersionId;
QString m_universal_url;
public:
int stackIndex = -1;
int listIndex = -1;
};
typedef std::shared_ptr<BasePage> BasePagePtr;

View File

@@ -0,0 +1,8 @@
#pragma once
class BasePageContainer
{
public:
virtual ~BasePageContainer(){};
virtual bool selectPage(QString pageId) = 0;
};

View File

@@ -0,0 +1,69 @@
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "BasePage.h"
#include <memory>
#include <functional>
class BasePageProvider
{
public:
virtual QList<BasePage *> getPages() = 0;
virtual QString dialogTitle() = 0;
};
class GenericPageProvider : public BasePageProvider
{
typedef std::function<BasePage *()> PageCreator;
public:
explicit GenericPageProvider(const QString &dialogTitle)
: m_dialogTitle(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);
}
template<typename PageClass>
void addPage()
{
addPageCreator([](){return new PageClass();});
}
private:
QList<PageCreator> m_creators;
QString m_dialogTitle;
};
typedef std::shared_ptr<BasePageProvider> BasePageProviderPtr;

View File

@@ -0,0 +1,207 @@
#include "InstanceSettingsPage.h"
#include "ui_InstanceSettingsPage.h"
#include <QFileDialog>
#include <QDialog>
#include <QMessageBox>
#include "dialogs/VersionSelectDialog.h"
#include "JavaCommon.h"
#include "MultiMC.h"
#include <java/JavaVersionList.h>
InstanceSettingsPage::InstanceSettingsPage(BaseInstance *inst, QWidget *parent)
: QWidget(parent), ui(new Ui::InstanceSettingsPage), m_instance(inst)
{
m_settings = inst->settings();
ui->setupUi(this);
loadSettings();
}
bool InstanceSettingsPage::shouldDisplay() const
{
return !m_instance->isRunning();
}
InstanceSettingsPage::~InstanceSettingsPage()
{
delete ui;
}
bool InstanceSettingsPage::apply()
{
applySettings();
return true;
}
void InstanceSettingsPage::applySettings()
{
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());
}
else
{
m_settings->reset("ShowConsole");
m_settings->reset("AutoCloseConsole");
}
// Window Size
bool window = ui->windowSizeGroupBox->isChecked();
m_settings->set("OverrideWindow", window);
if (window)
{
m_settings->set("LaunchMaximized", ui->maximizedCheckBox->isChecked());
m_settings->set("MinecraftWinWidth", ui->windowWidthSpinBox->value());
m_settings->set("MinecraftWinHeight", ui->windowHeightSpinBox->value());
}
else
{
m_settings->reset("LaunchMaximized");
m_settings->reset("MinecraftWinWidth");
m_settings->reset("MinecraftWinHeight");
}
// Memory
bool memory = ui->memoryGroupBox->isChecked();
m_settings->set("OverrideMemory", memory);
if (memory)
{
m_settings->set("MinMemAlloc", ui->minMemSpinBox->value());
m_settings->set("MaxMemAlloc", ui->maxMemSpinBox->value());
m_settings->set("PermGen", ui->permGenSpinBox->value());
}
else
{
m_settings->reset("MinMemAlloc");
m_settings->reset("MaxMemAlloc");
m_settings->reset("PermGen");
}
// Java Install Settings
bool javaInstall = ui->javaSettingsGroupBox->isChecked();
m_settings->set("OverrideJavaLocation", javaInstall);
if (javaInstall)
{
m_settings->set("JavaPath", ui->javaPathTextBox->text());
}
else
{
m_settings->reset("JavaPath");
}
// Java arguments
bool javaArgs = ui->javaArgumentsGroupBox->isChecked();
m_settings->set("OverrideJavaArgs", javaArgs);
if(javaArgs)
{
m_settings->set("JvmArgs", ui->jvmArgsTextBox->toPlainText().replace("\n", " "));
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->customCommandsGroupBox->isChecked();
m_settings->set("OverrideCommands", custcmd);
if (custcmd)
{
m_settings->set("PreLaunchCommand", ui->preLaunchCmdTextBox->text());
m_settings->set("PostExitCommand", ui->postExitCmdTextBox->text());
}
else
{
m_settings->reset("PreLaunchCommand");
m_settings->reset("PostExitCommand");
}
}
void InstanceSettingsPage::loadSettings()
{
// Console
ui->consoleSettingsBox->setChecked(m_settings->get("OverrideConsole").toBool());
ui->showConsoleCheck->setChecked(m_settings->get("ShowConsole").toBool());
ui->autoCloseConsoleCheck->setChecked(m_settings->get("AutoCloseConsole").toBool());
// Window Size
ui->windowSizeGroupBox->setChecked(m_settings->get("OverrideWindow").toBool());
ui->maximizedCheckBox->setChecked(m_settings->get("LaunchMaximized").toBool());
ui->windowWidthSpinBox->setValue(m_settings->get("MinecraftWinWidth").toInt());
ui->windowHeightSpinBox->setValue(m_settings->get("MinecraftWinHeight").toInt());
// Memory
ui->memoryGroupBox->setChecked(m_settings->get("OverrideMemory").toBool());
ui->minMemSpinBox->setValue(m_settings->get("MinMemAlloc").toInt());
ui->maxMemSpinBox->setValue(m_settings->get("MaxMemAlloc").toInt());
ui->permGenSpinBox->setValue(m_settings->get("PermGen").toInt());
// Java Settings
bool overrideJava = m_settings->get("OverrideJava").toBool();
bool overrideLocation = m_settings->get("OverrideJavaLocation").toBool() || overrideJava;
bool overrideArgs = m_settings->get("OverrideJavaArgs").toBool() || overrideJava;
ui->javaSettingsGroupBox->setChecked(overrideLocation);
ui->javaPathTextBox->setText(m_settings->get("JavaPath").toString());
ui->javaArgumentsGroupBox->setChecked(overrideArgs);
ui->jvmArgsTextBox->setPlainText(m_settings->get("JvmArgs").toString());
// Custom Commands
ui->customCommandsGroupBox->setChecked(m_settings->get("OverrideCommands").toBool());
ui->preLaunchCmdTextBox->setText(m_settings->get("PreLaunchCommand").toString());
ui->postExitCmdTextBox->setText(m_settings->get("PostExitCommand").toString());
}
void InstanceSettingsPage::on_javaDetectBtn_clicked()
{
JavaVersionPtr java;
VersionSelectDialog vselect(MMC->javalist().get(), tr("Select a Java version"), this, true);
vselect.setResizeOn(2);
vselect.exec();
if (vselect.result() == QDialog::Accepted && vselect.selectedVersion())
{
java = std::dynamic_pointer_cast<JavaVersion>(vselect.selectedVersion());
ui->javaPathTextBox->setText(java->path);
}
}
void InstanceSettingsPage::on_javaBrowseBtn_clicked()
{
QString dir = QFileDialog::getOpenFileName(this, tr("Find Java executable"));
if (!dir.isNull())
{
ui->javaPathTextBox->setText(dir);
}
}
void InstanceSettingsPage::on_javaTestBtn_clicked()
{
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();
}

View File

@@ -0,0 +1,74 @@
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <QWidget>
#include "java/JavaChecker.h"
#include "BaseInstance.h"
#include <QObjectPtr.h>
#include "BasePage.h"
#include "JavaCommon.h"
#include "MultiMC.h"
class JavaChecker;
namespace Ui
{
class InstanceSettingsPage;
}
class InstanceSettingsPage : public QWidget, public BasePage
{
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();
virtual QString helpPage() const override
{
return "Instance-settings";
}
virtual bool shouldDisplay() const;
private slots:
void on_javaDetectBtn_clicked();
void on_javaTestBtn_clicked();
void on_javaBrowseBtn_clicked();
void applySettings();
void loadSettings();
void checkerFinished();
private:
Ui::InstanceSettingsPage *ui;
BaseInstance *m_instance;
SettingsObjectPtr m_settings;
QObjectPtr<JavaCommon::TestCheck> checker;
};

View File

@@ -1,19 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>InstanceSettings</class>
<widget class="QDialog" name="InstanceSettings">
<class>InstanceSettingsPage</class>
<widget class="QWidget" name="InstanceSettingsPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>526</width>
<height>637</height>
<width>458</width>
<height>426</height>
</rect>
</property>
<property name="windowTitle">
<string>Instance Settings</string>
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QTabWidget" name="settingsTabs">
<property name="tabShape">
@@ -24,7 +36,195 @@
</property>
<widget class="QWidget" name="minecraftTab">
<attribute name="title">
<string>Minecraft</string>
<string>Java</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QGroupBox" name="javaSettingsGroupBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>Java installation</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="3">
<widget class="QLineEdit" name="javaPathTextBox"/>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="javaDetectBtn">
<property name="text">
<string>Auto-detect...</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="javaBrowseBtn">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="javaTestBtn">
<property name="text">
<string>Test</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="memoryGroupBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>Memory</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="1">
<widget class="QSpinBox" name="maxMemSpinBox">
<property name="toolTip">
<string>The maximum amount of memory Minecraft is allowed to use.</string>
</property>
<property name="suffix">
<string> MB</string>
</property>
<property name="minimum">
<number>512</number>
</property>
<property name="maximum">
<number>65536</number>
</property>
<property name="singleStep">
<number>128</number>
</property>
<property name="value">
<number>1024</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelMinMem">
<property name="text">
<string>Minimum memory allocation:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelMaxMem">
<property name="text">
<string>Maximum memory allocation:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="minMemSpinBox">
<property name="toolTip">
<string>The amount of memory Minecraft is started with.</string>
</property>
<property name="suffix">
<string> MB</string>
</property>
<property name="minimum">
<number>256</number>
</property>
<property name="maximum">
<number>65536</number>
</property>
<property name="singleStep">
<number>128</number>
</property>
<property name="value">
<number>256</number>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="permGenSpinBox">
<property name="toolTip">
<string>The amount of memory available to store loaded Java classes.</string>
</property>
<property name="suffix">
<string> MB</string>
</property>
<property name="minimum">
<number>64</number>
</property>
<property name="maximum">
<number>999999999</number>
</property>
<property name="singleStep">
<number>8</number>
</property>
<property name="value">
<number>64</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelPermGen">
<property name="text">
<string>PermGen:</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="javaArgumentsGroupBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>Java arguments</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="1" column="1">
<widget class="QPlainTextEdit" name="jvmArgsTextBox"/>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacerMinecraft">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="javaTab">
<attribute name="title">
<string>Game windows</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
@@ -33,7 +233,7 @@
<bool>true</bool>
</property>
<property name="title">
<string>Window Size</string>
<string>Game Window</string>
</property>
<property name="checkable">
<bool>true</bool>
@@ -68,7 +268,7 @@
<item row="0" column="1">
<widget class="QSpinBox" name="windowWidthSpinBox">
<property name="minimum">
<number>854</number>
<number>1</number>
</property>
<property name="maximum">
<number>65536</number>
@@ -84,7 +284,7 @@
<item row="1" column="1">
<widget class="QSpinBox" name="windowHeightSpinBox">
<property name="minimum">
<number>480</number>
<number>1</number>
</property>
<property name="maximum">
<number>65536</number>
@@ -132,171 +332,25 @@
</widget>
</item>
<item>
<spacer name="verticalSpacerMinecraft">
<spacer name="verticalSpacerMinecraft_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
<width>88</width>
<height>125</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="javaTab">
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Java</string>
<string>Custom commands</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QGroupBox" name="memoryGroupBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>Memory</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="1">
<widget class="QSpinBox" name="maxMemSpinBox">
<property name="minimum">
<number>512</number>
</property>
<property name="maximum">
<number>65536</number>
</property>
<property name="singleStep">
<number>128</number>
</property>
<property name="value">
<number>1024</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelMinMem">
<property name="text">
<string>Minimum memory allocation:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelMaxMem">
<property name="text">
<string>Maximum memory allocation:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="minMemSpinBox">
<property name="minimum">
<number>256</number>
</property>
<property name="maximum">
<number>65536</number>
</property>
<property name="singleStep">
<number>128</number>
</property>
<property name="value">
<number>256</number>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="permGenSpinBox">
<property name="minimum">
<number>64</number>
</property>
<property name="maximum">
<number>999999999</number>
</property>
<property name="singleStep">
<number>8</number>
</property>
<property name="value">
<number>64</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelPermGen">
<property name="text">
<string>PermGen:</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="javaSettingsGroupBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>Java Settings</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="2" column="4">
<widget class="QPushButton" name="javaTestBtn">
<property name="text">
<string>Test</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelJavaPath">
<property name="text">
<string>Java path:</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelJVMArgs">
<property name="text">
<string>JVM arguments:</string>
</property>
</widget>
</item>
<item row="3" column="2" colspan="3">
<widget class="QLineEdit" name="jvmArgsTextBox"/>
</item>
<item row="0" column="2" colspan="3">
<widget class="QLineEdit" name="javaPathTextBox"/>
</item>
<item row="2" column="3">
<widget class="QPushButton" name="javaBrowseBtn">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="javaDetectBtn">
<property name="text">
<string>Auto-detect...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QGroupBox" name="customCommandsGroupBox">
<property name="enabled">
@@ -337,17 +391,8 @@
</item>
<item>
<widget class="QLabel" name="labelCustomCmdsDescription">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Pre-launch command runs before the instance launches and post-exit command runs after it exits. Both will be run in MultiMC's working directory with INST_ID, INST_DIR, and INST_NAME as environment variables.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Pre-launch command runs before the instance launches and post-exit command runs after it exits.&lt;/p&gt;&lt;p&gt;Both will be run in MultiMC's working directory with extra environment variables:&lt;/p&gt;&lt;ul style=&quot;margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;&quot;&gt;&lt;li style=&quot; margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;INST_NAME - Name of the instance&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;INST_ID - ID of the instance&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;INST_DIR - absolute path of the instance&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;INST_MC_DIR - absolute path of minecraft&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;INST_JAVA - java binary used for launch&lt;/li&gt;&lt;li style=&quot; margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;INST_JAVA_ARGS - command-line parameters used for launch&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
@@ -360,25 +405,38 @@
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacerMinecraft_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>88</width>
<height>186</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>settingsTabs</tabstop>
<tabstop>buttonBox</tabstop>
<tabstop>javaSettingsGroupBox</tabstop>
<tabstop>javaPathTextBox</tabstop>
<tabstop>javaDetectBtn</tabstop>
<tabstop>javaBrowseBtn</tabstop>
<tabstop>javaTestBtn</tabstop>
<tabstop>memoryGroupBox</tabstop>
<tabstop>minMemSpinBox</tabstop>
<tabstop>maxMemSpinBox</tabstop>
<tabstop>permGenSpinBox</tabstop>
<tabstop>javaArgumentsGroupBox</tabstop>
<tabstop>jvmArgsTextBox</tabstop>
<tabstop>windowSizeGroupBox</tabstop>
<tabstop>maximizedCheckBox</tabstop>
<tabstop>windowWidthSpinBox</tabstop>
@@ -386,12 +444,6 @@
<tabstop>consoleSettingsBox</tabstop>
<tabstop>showConsoleCheck</tabstop>
<tabstop>autoCloseConsoleCheck</tabstop>
<tabstop>memoryGroupBox</tabstop>
<tabstop>minMemSpinBox</tabstop>
<tabstop>maxMemSpinBox</tabstop>
<tabstop>permGenSpinBox</tabstop>
<tabstop>javaSettingsGroupBox</tabstop>
<tabstop>jvmArgsTextBox</tabstop>
<tabstop>customCommandsGroupBox</tabstop>
<tabstop>preLaunchCmdTextBox</tabstop>
<tabstop>postExitCmdTextBox</tabstop>

View File

@@ -0,0 +1,163 @@
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "LegacyJarModPage.h"
#include "ui_LegacyJarModPage.h"
#include <QKeyEvent>
#include <QKeyEvent>
#include <pathutils.h>
#include "dialogs/VersionSelectDialog.h"
#include "dialogs/ProgressDialog.h"
#include "dialogs/ModEditDialogCommon.h"
#include "minecraft/ModList.h"
#include "minecraft/LegacyInstance.h"
#include "Env.h"
#include "MultiMC.h"
#include <GuiUtil.h>
LegacyJarModPage::LegacyJarModPage(LegacyInstance *inst, QWidget *parent)
: QWidget(parent), ui(new Ui::LegacyJarModPage), m_inst(inst)
{
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();
m_jarmods = m_inst->jarModList();
ui->jarModsTreeView->setModel(m_jarmods.get());
ui->jarModsTreeView->setDragDropMode(QAbstractItemView::DragDrop);
ui->jarModsTreeView->setSelectionMode(QAbstractItemView::SingleSelection);
ui->jarModsTreeView->installEventFilter(this);
m_jarmods->startWatching();
auto smodel = ui->jarModsTreeView->selectionModel();
connect(smodel, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
SLOT(jarCurrent(QModelIndex, QModelIndex)));
}
LegacyJarModPage::~LegacyJarModPage()
{
m_jarmods->stopWatching();
delete ui;
}
bool LegacyJarModPage::shouldDisplay() const
{
return !m_inst->isRunning();
}
bool LegacyJarModPage::eventFilter(QObject *obj, QEvent *ev)
{
if (ev->type() != QEvent::KeyPress || obj != ui->jarModsTreeView)
{
return QWidget::eventFilter(obj, ev);
}
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
switch (keyEvent->key())
{
case Qt::Key_Up:
{
if (keyEvent->modifiers() & Qt::ControlModifier)
{
on_moveJarUpBtn_clicked();
return true;
}
break;
}
case Qt::Key_Down:
{
if (keyEvent->modifiers() & Qt::ControlModifier)
{
on_moveJarDownBtn_clicked();
return true;
}
break;
}
case Qt::Key_Delete:
on_rmJarBtn_clicked();
return true;
case Qt::Key_Plus:
on_addJarBtn_clicked();
return true;
default:
break;
}
return QWidget::eventFilter(obj, ev);
}
void LegacyJarModPage::on_addJarBtn_clicked()
{
auto list = GuiUtil::BrowseForMods("jarmod", tr("Select jar mods"), tr("Minecraft.jar mods (*.zip *.jar)"), this->parentWidget());
if(!list.empty())
{
m_jarmods->stopWatching();
for (auto filename : list)
{
m_jarmods->installMod(QFileInfo(filename));
}
m_jarmods->startWatching();
}
}
void LegacyJarModPage::on_moveJarDownBtn_clicked()
{
int first, last;
auto list = ui->jarModsTreeView->selectionModel()->selectedRows();
if (!lastfirst(list, first, last))
return;
m_jarmods->moveModsDown(first, last);
}
void LegacyJarModPage::on_moveJarUpBtn_clicked()
{
int first, last;
auto list = ui->jarModsTreeView->selectionModel()->selectedRows();
if (!lastfirst(list, first, last))
return;
m_jarmods->moveModsUp(first, last);
}
void LegacyJarModPage::on_rmJarBtn_clicked()
{
int first, last;
auto list = ui->jarModsTreeView->selectionModel()->selectedRows();
if (!lastfirst(list, first, last))
return;
m_jarmods->stopWatching();
m_jarmods->deleteMods(first, last);
m_jarmods->startWatching();
}
void LegacyJarModPage::on_viewJarBtn_clicked()
{
openDirInDefaultProgram(m_inst->jarModsDir(), true);
}
void LegacyJarModPage::jarCurrent(QModelIndex current, QModelIndex previous)
{
if (!current.isValid())
{
ui->jarMIFrame->clear();
return;
}
int row = current.row();
Mod &m = m_jarmods->operator[](row);
ui->jarMIFrame->updateWithMod(m);
}

View File

@@ -0,0 +1,76 @@
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <QWidget>
#include "net/NetJob.h"
#include "BasePage.h"
#include <MultiMC.h>
class ModList;
class LegacyInstance;
namespace Ui
{
class LegacyJarModPage;
}
class LegacyJarModPage : public QWidget, public BasePage
{
Q_OBJECT
public:
explicit LegacyJarModPage(LegacyInstance *inst, QWidget *parent = 0);
virtual ~LegacyJarModPage();
virtual QString displayName() const
{
return tr("Jar Mods");
}
virtual QIcon icon() const
{
return MMC->getThemedIcon("jarmods");
}
virtual QString id() const
{
return "jarmods";
}
virtual QString helpPage() const override
{
return "Legacy-jar-mods";
}
virtual bool shouldDisplay() const;
private
slots:
void on_addJarBtn_clicked();
void on_rmJarBtn_clicked();
void on_moveJarUpBtn_clicked();
void on_moveJarDownBtn_clicked();
void on_viewJarBtn_clicked();
void jarCurrent(QModelIndex current, QModelIndex previous);
protected:
virtual bool eventFilter(QObject *obj, QEvent *ev) override;
private:
Ui::LegacyJarModPage *ui;
std::shared_ptr<ModList> m_jarmods;
LegacyInstance *m_inst;
NetJobPtr forgeJob;
};

View File

@@ -0,0 +1,165 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LegacyJarModPage</class>
<widget class="QWidget" name="LegacyJarModPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>659</width>
<height>593</height>
</rect>
</property>
<property name="windowTitle">
<string>LegacyJarModPage</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Tab 1</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="ModListView" name="jarModsTreeView">
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="jarModsButtonBox">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Selection</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="rmJarBtn">
<property name="text">
<string>&amp;Remove</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="moveJarUpBtn">
<property name="text">
<string>Move &amp;Up</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="moveJarDownBtn">
<property name="text">
<string>Move &amp;Down</string>
</property>
</widget>
</item>
<item>
<widget class="LineSeparator" name="separator" native="true"/>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Install</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="addJarBtn">
<property name="text">
<string>&amp;Add jar mod</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="viewJarBtn">
<property name="text">
<string>&amp;View Folder</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="MCModInfoFrame" name="jarMIFrame">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>ModListView</class>
<extends>QTreeView</extends>
<header>widgets/ModListView.h</header>
</customwidget>
<customwidget>
<class>MCModInfoFrame</class>
<extends>QFrame</extends>
<header>widgets/MCModInfoFrame.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>LineSeparator</class>
<extends>QWidget</extends>
<header>widgets/LineSeparator.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,25 @@
#include "LegacyUpgradePage.h"
#include "ui_LegacyUpgradePage.h"
#include "minecraft/LegacyInstance.h"
LegacyUpgradePage::LegacyUpgradePage(LegacyInstance *inst, QWidget *parent)
: QWidget(parent), ui(new Ui::LegacyUpgradePage), m_inst(inst)
{
ui->setupUi(this);
}
LegacyUpgradePage::~LegacyUpgradePage()
{
delete ui;
}
void LegacyUpgradePage::on_upgradeButton_clicked()
{
// now what?
}
bool LegacyUpgradePage::shouldDisplay() const
{
return !m_inst->isRunning();
}

View File

@@ -0,0 +1,60 @@
/* Copyright 2013-2015 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <QWidget>
#include "minecraft/OneSixInstance.h"
#include "pages/BasePage.h"
#include <MultiMC.h>
namespace Ui
{
class LegacyUpgradePage;
}
class LegacyUpgradePage : public QWidget, public BasePage
{
Q_OBJECT
public:
explicit LegacyUpgradePage(LegacyInstance *inst, QWidget *parent = 0);
virtual ~LegacyUpgradePage();
virtual QString displayName() const override
{
return tr("Upgrade");
}
virtual QIcon icon() const override
{
return MMC->getThemedIcon("checkupdate");
}
virtual QString id() const override
{
return "upgrade";
}
virtual QString helpPage() const override
{
return "Legacy-upgrade";
}
virtual bool shouldDisplay() const;
private
slots:
void on_upgradeButton_clicked();
private:
Ui::LegacyUpgradePage *ui;
LegacyInstance *m_inst;
};

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LegacyUpgradePage</class>
<widget class="QWidget" name="LegacyUpgradePage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>546</width>
<height>405</height>
</rect>
</property>
<property name="windowTitle">
<string>Upgrade</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QTextBrowser" name="textBrowser">
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Bitstream Vera Sans'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; &lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:18pt; font-weight:600;&quot;&gt;New format is available&lt;/span&gt; &lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;MultiMC now supports old Minecraft versions in the new (OneSix) instance format. The old format won't be getting any new features and only the most critical bugfixes. As a consequence, you should upgrade this instance. &lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The upgrade will create a new instance with the same contents as the current one, in the new format. The original instance will remain untouched, in case anything goes wrong in the process. &lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Please report any issues on our &lt;a href=&quot;https://github.com/MultiMC/MultiMC5/issues&quot;&gt;&lt;img src=&quot;:/icons/multimc/22x22/bug.png&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://github.com/MultiMC/MultiMC5/issues&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#68a0df;&quot;&gt;github issues page&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCommandLinkButton" name="upgradeButton">
<property name="text">
<string>Start the upgrade! (Not Yet Implemented, Coming Soon™)</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,227 @@
#include "LogPage.h"
#include "ui_LogPage.h"
#include "MultiMC.h"
#include <QIcon>
#include <QScrollBar>
#include <QShortcut>
#include "BaseProcess.h"
#include "GuiUtil.h"
LogPage::LogPage(BaseProcess *proc, QWidget *parent)
: QWidget(parent), ui(new Ui::LogPage), m_process(proc)
{
ui->setupUi(this);
ui->tabWidget->tabBar()->hide();
connect(m_process, SIGNAL(log(QString, MessageLevel::Enum)), this,
SLOT(write(QString, MessageLevel::Enum)));
// create the format and set its font
defaultFormat = new QTextCharFormat(ui->text->currentCharFormat());
QString fontFamily = MMC->settings()->get("ConsoleFont").toString();
bool conversionOk = false;
int fontSize = MMC->settings()->get("ConsoleFontSize").toInt(&conversionOk);
if(!conversionOk)
{
fontSize = 11;
}
defaultFormat->setFont(QFont(fontFamily, fontSize));
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 defaultFormat;
}
bool LogPage::apply()
{
return true;
}
bool LogPage::shouldDisplay() const
{
return m_process->instance()->isRunning();
}
void LogPage::on_btnPaste_clicked()
{
GuiUtil::uploadPaste(ui->text->toPlainText(), this);
}
void LogPage::on_btnCopy_clicked()
{
GuiUtil::setClipboardText(ui->text->toPlainText());
}
void LogPage::on_btnClear_clicked()
{
ui->text->clear();
}
void LogPage::on_btnBottom_clicked()
{
ui->text->verticalScrollBar()->setSliderPosition(ui->text->verticalScrollBar()->maximum());
}
void LogPage::on_trackLogCheckbox_clicked(bool checked)
{
m_write_active = checked;
}
void LogPage::on_findButton_clicked()
{
auto modifiers = QApplication::keyboardModifiers();
if (modifiers & Qt::ShiftModifier)
{
findPreviousActivated();
}
else
{
findNextActivated();
}
}
void LogPage::findActivated()
{
// focus the search bar if it doesn't have focus
if (!ui->searchBar->hasFocus())
{
auto searchForCursor = ui->text->textCursor();
auto searchForString = searchForCursor.selectedText();
if (searchForString.size())
{
ui->searchBar->setText(searchForString);
}
ui->searchBar->setFocus();
ui->searchBar->selectAll();
}
}
void LogPage::findNextActivated()
{
auto toSearch = ui->searchBar->text();
if (toSearch.size())
{
ui->text->find(toSearch);
}
}
void LogPage::findPreviousActivated()
{
auto toSearch = ui->searchBar->text();
if (toSearch.size())
{
ui->text->find(toSearch, QTextDocument::FindBackward);
}
}
void LogPage::write(QString data, MessageLevel::Enum mode)
{
if (!m_write_active)
{
if (mode != MessageLevel::PrePost && mode != MessageLevel::MultiMC)
{
return;
}
}
// save the cursor so it can be restored.
auto savedCursor = ui->text->cursor();
QScrollBar *bar = ui->text->verticalScrollBar();
int max_bar = bar->maximum();
int val_bar = bar->value();
if (isVisible())
{
if (m_scroll_active)
{
m_scroll_active = (max_bar - val_bar) <= 1;
}
else
{
m_scroll_active = val_bar == max_bar;
}
}
if (data.endsWith('\n'))
data = data.left(data.length() - 1);
QStringList paragraphs = data.split('\n');
QStringList filtered;
for (QString &paragraph : paragraphs)
{
//TODO: implement filtering here.
filtered.append(paragraph);
}
QListIterator<QString> iter(filtered);
QTextCharFormat format(*defaultFormat);
switch(mode)
{
case MessageLevel::MultiMC:
{
format.setForeground(QColor("blue"));
break;
}
case MessageLevel::Debug:
{
format.setForeground(QColor("green"));
break;
}
case MessageLevel::Warning:
{
format.setForeground(QColor("orange"));
break;
}
case MessageLevel::Error:
{
format.setForeground(QColor("red"));
break;
}
case MessageLevel::Fatal:
{
format.setForeground(QColor("red"));
format.setBackground(QColor("black"));
break;
}
case MessageLevel::PrePost:
{
format.setForeground(QColor("grey"));
break;
}
case MessageLevel::Info:
case MessageLevel::Message:
default:
{
// do nothing, keep original
}
}
while (iter.hasNext())
{
// append a paragraph/line
auto workCursor = ui->text->textCursor();
workCursor.movePosition(QTextCursor::End);
workCursor.insertText(iter.next(), format);
workCursor.insertBlock();
}
if (isVisible())
{
if (m_scroll_active)
{
bar->setValue(bar->maximum());
}
m_last_scroll_value = bar->value();
}
ui->text->setCursor(savedCursor);
}

Some files were not shown because too many files have changed in this diff Show More