Compare commits

..

500 Commits
0.1 ... 0.4.4

Author SHA1 Message Date
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
Petr Mrázek
c51a993ff7 Add logging calls to the java checker. 2014-01-09 01:20:24 +01:00
Petr Mrázek
5650a28fc6 Hopefully fix OSX icon file 2014-01-08 21:06:31 +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
813 changed files with 37593 additions and 14071 deletions

View File

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

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

28
.travis.yml Normal file
View File

@@ -0,0 +1,28 @@
language: cpp
compiler:
- gcc
- clang
cache: apt
before_install:
- sudo apt-add-repository -y ppa:beineri/opt-qt521
- 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 qt52base qt52svg qt52tools qt52x11extras qt52webkit
- sudo apt-get install -y -qq g++-4.8
- if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi
before_script:
- mkdir build
- cd build
- cmake -DCMAKE_PREFIX_PATH=/opt/qt52/lib/cmake ..
script:
- make -j4
- make test
notifications:
irc:
channels:
- "irc.esper.net#MultiMC"
template:
- "%{build_number} (%{branch} - %{commit} : %{author}): %{message} (%{build_url})"
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)

63
BuildConfig.cpp.in Normal file
View File

@@ -0,0 +1,63 @@
#include "BuildConfig.h"
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_TYPE = "@MultiMC_VERSION_TYPE@";
if(VERSION_TYPE == "Release")
versionTypeEnum = Release;
else if(VERSION_TYPE == "ReleaseCandidate")
versionTypeEnum = ReleaseCandidate;
else if(VERSION_TYPE == "Development")
versionTypeEnum = Development;
else
versionTypeEnum = Custom;
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::versionTypeName() const
{
switch (versionTypeEnum)
{
case Release:
return "Stable Release";
case ReleaseCandidate:
return "Release Candidate";
case Development:
return "Development";
case Custom:
default:
return "Custom";
}
}
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 (versionTypeEnum == Development) vstr += "-dev" + QString::number(VERSION_BUILD);
else if (versionTypeEnum == ReleaseCandidate) vstr += "-rc" + QString::number(VERSION_BUILD);
return vstr;
}

86
BuildConfig.h Normal file
View File

@@ -0,0 +1,86 @@
#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 build type, as specified at build time.
QString VERSION_TYPE;
/// The build type, transformed.
enum Type
{
/// Version type for stable release builds.
Release,
/// Version type for release candidates.
ReleaseCandidate,
/// Version type for development builds.
Development,
/// Version type for custom builds. This is the default when no version type is specified.
Custom
} versionTypeEnum;
/**
* 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;
/**
* returns a string representation of the version channel type, suitable for printing.
*/
QString versionTypeName() const;
};
extern Config BuildConfig;

File diff suppressed because it is too large Load Diff

25
MMCError.h Normal file
View File

@@ -0,0 +1,25 @@
#pragma once
#include <exception>
#include <QString>
#include <logger/QsLog.h>
class MMCError : public std::exception
{
public:
MMCError(QString cause)
{
exceptionCause = cause;
QLOG_ERROR() << "Exception: " + cause;
};
virtual ~MMCError() noexcept {}
virtual const char *what() const noexcept
{
return exceptionCause.toLocal8Bit();
};
virtual QString cause() const
{
return exceptionCause;
}
private:
QString exceptionCause;
};

View File

@@ -1,5 +1,6 @@
#include "MultiMC.h"
#include "BuildConfig.h"
#include <iostream>
#include <QDir>
#include <QFileInfo>
@@ -11,41 +12,55 @@
#include <QDesktopServices>
#include "gui/dialogs/VersionSelectDialog.h"
#include "logic/lists/InstanceList.h"
#include "logic/InstanceList.h"
#include "logic/auth/MojangAccountList.h"
#include "logic/icons/IconList.h"
#include "logic/lists/LwjglVersionList.h"
#include "logic/lists/MinecraftVersionList.h"
#include "logic/lists/ForgeVersionList.h"
#include "logic/LwjglVersionList.h"
#include "logic/minecraft/MinecraftVersionList.h"
#include "logic/liteloader/LiteLoaderVersionList.h"
#include "logic/forge/ForgeVersionList.h"
#include "logic/news/NewsChecker.h"
#include "logic/status/StatusChecker.h"
#include "logic/InstanceLauncher.h"
#include "logic/net/HttpMetaCache.h"
#include "logic/net/URLConstants.h"
#include "logic/JavaUtils.h"
#include "logic/java/JavaUtils.h"
#include "logic/updater/UpdateChecker.h"
#include "logic/updater/NotificationChecker.h"
#include "logic/tools/JProfiler.h"
#include "logic/tools/JVisualVM.h"
#include "logic/tools/MCEditTool.h"
#include "logic/URNResolver.h"
#include "pathutils.h"
#include "cmdutils.h"
#include <inisettingsobject.h>
#include <setting.h>
#include "logic/settings/INISettingsObject.h"
#include "logic/settings/Setting.h"
#include "logger/QsLog.h"
#include <logger/QsLogDest.h>
#include "logger/QsLogDest.h"
#include "logic/trans/TranslationDownloader.h"
#ifdef Q_OS_WIN32
#include <windows.h>
static const int APPDATA_BUFFER_SIZE = 1024;
#endif
using namespace Util::Commandline;
MultiMC::MultiMC(int &argc, char **argv, bool root_override)
: QApplication(argc, argv), m_version{VERSION_MAJOR, VERSION_MINOR, VERSION_HOTFIX,
VERSION_BUILD, MultiMCVersion::VERSION_TYPE, VERSION_CHANNEL, BUILD_PLATFORM}
MultiMC::MultiMC(int &argc, char **argv, bool test_mode) : QApplication(argc, argv)
{
setOrganizationName("MultiMC");
setApplicationName("MultiMC5");
initTranslations();
setAttribute(Qt::AA_UseHighDpiPixmaps);
// Don't quit on hiding the last window
this->setQuitOnLastWindowClosed(false);
@@ -75,6 +90,7 @@ MultiMC::MultiMC(int &argc, char **argv, bool root_override)
parser.addShortOpt("launch", 'l');
parser.addDocumentation("launch", "tries to launch the given instance", "<inst>");
*/
// parse the arguments
try
{
@@ -100,8 +116,8 @@ MultiMC::MultiMC(int &argc, char **argv, bool root_override)
// display version and exit
if (args["version"].toBool())
{
std::cout << "Version " << VERSION_STR << std::endl;
std::cout << "Git " << GIT_COMMIT << std::endl;
std::cout << "Version " << BuildConfig.VERSION_STR.toStdString() << std::endl;
std::cout << "Git " << BuildConfig.GIT_COMMIT.toStdString() << std::endl;
m_status = MultiMC::Succeeded;
return;
}
@@ -124,7 +140,7 @@ MultiMC::MultiMC(int &argc, char **argv, bool root_override)
adjustedBy += "Fallback to binary path " + dataPath;
}
if(!ensureFolderPathExists(dataPath) || !QDir::setCurrent(dataPath))
if (!ensureFolderPathExists(dataPath) || !QDir::setCurrent(dataPath))
{
// BAD STUFF. WHAT DO?
initLogger();
@@ -133,29 +149,41 @@ MultiMC::MultiMC(int &argc, char **argv, bool root_override)
return;
}
if (root_override)
// in test mode, root path is the same as the binary path.
if (test_mode)
{
rootPath = binPath;
}
else
{
#ifdef Q_OS_LINUX
#ifdef Q_OS_LINUX
QDir foo(PathCombine(binPath, ".."));
rootPath = foo.absolutePath();
#elif defined(Q_OS_WIN32)
#elif defined(Q_OS_WIN32)
rootPath = binPath;
#elif defined(Q_OS_MAC)
#elif defined(Q_OS_MAC)
QDir foo(PathCombine(binPath, "../.."));
rootPath = foo.absolutePath();
#endif
#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();
QLOG_INFO() << "MultiMC 5, (c) 2013 MultiMC Contributors";
QLOG_INFO() << "Version : " << VERSION_STR;
QLOG_INFO() << "Git commit : " << GIT_COMMIT;
QLOG_INFO() << "MultiMC 5, (c) 2013-2014 MultiMC Contributors";
QLOG_INFO() << "Version : " << BuildConfig.VERSION_STR;
QLOG_INFO() << "Git commit : " << BuildConfig.GIT_COMMIT;
if (adjustedBy.size())
{
QLOG_INFO() << "Work dir before adjustment : " << origcwdPath;
@@ -168,9 +196,13 @@ MultiMC::MultiMC(int &argc, char **argv, bool root_override)
}
QLOG_INFO() << "Binary path : " << binPath;
QLOG_INFO() << "Application root path : " << rootPath;
QLOG_INFO() << "Static data path : " << staticDataPath;
// load settings
initGlobalSettings();
initGlobalSettings(test_mode);
// load translations
initTranslations();
// initialize the updater
m_updateChecker.reset(new UpdateChecker());
@@ -179,14 +211,28 @@ MultiMC::MultiMC(int &argc, char **argv, bool root_override)
m_notificationChecker.reset(new NotificationChecker());
// initialize the news checker
m_newsChecker.reset(new NewsChecker(NEWS_RSS_URL));
m_newsChecker.reset(new NewsChecker(BuildConfig.NEWS_RSS_URL));
// initialize the status checker
m_statusChecker.reset(new StatusChecker());
m_translationChecker.reset(new TranslationDownloader());
// 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 = MMC->settings()->get("InstanceDir").toString();
QLOG_INFO() << "Instance path : " << instDir;
if (checkProblemticPathJava(QDir(instDir)))
{
QLOG_WARN()
<< "Your instance path contains \'!\' and this is known to cause java problems";
}
m_instances.reset(new InstanceList(InstDirSetting->get().toString(), this));
QLOG_INFO() << "Loading Instances...";
m_instances->loadList();
connect(InstDirSetting.get(), SIGNAL(settingChanged(const Setting &, QVariant)),
connect(InstDirSetting.get(), SIGNAL(SettingChanged(const Setting &, QVariant)),
m_instances.get(), SLOT(on_InstFolderChanged(const Setting &, QVariant)));
// and accounts
@@ -201,9 +247,25 @@ MultiMC::MultiMC(int &argc, char **argv, bool root_override)
// create the global network manager
m_qnam.reset(new QNetworkAccessManager(this));
m_translationChecker->downloadTranslations();
// init proxy settings
updateProxySettings();
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);
}
m_tools.insert("mcedit", std::shared_ptr<BaseDetachedToolFactory>(new MCEditFactory()));
for (auto tool : m_tools.values())
{
tool->registerSettings(m_settings);
}
// launch instance, if that's what should be done
// WARNING: disabled until further notice
/*
@@ -234,18 +296,20 @@ MultiMC::~MultiMC()
void MultiMC::initTranslations()
{
QLocale locale(m_settings->get("Language").toString());
QLocale::setDefault(locale);
QLOG_INFO() << "Your language is" << locale.bcp47Name();
m_qt_translator.reset(new QTranslator());
if (m_qt_translator->load("qt_" + QLocale::system().name(),
if (m_qt_translator->load("qt_" + locale.bcp47Name(),
QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
{
std::cout << "Loading Qt Language File for "
<< QLocale::system().name().toLocal8Bit().constData() << "...";
QLOG_DEBUG() << "Loading Qt Language File for"
<< locale.bcp47Name().toLocal8Bit().constData() << "...";
if (!installTranslator(m_qt_translator.get()))
{
std::cout << " failed.";
QLOG_ERROR() << "Loading Qt Language File failed.";
m_qt_translator.reset();
}
std::cout << std::endl;
}
else
{
@@ -253,17 +317,16 @@ void MultiMC::initTranslations()
}
m_mmc_translator.reset(new QTranslator());
if (m_mmc_translator->load("mmc_" + QLocale::system().name(),
QDir("translations").absolutePath()))
if (m_mmc_translator->load("mmc_" + locale.bcp47Name(),
MMC->staticData() + "/translations"))
{
std::cout << "Loading MMC Language File for "
<< QLocale::system().name().toLocal8Bit().constData() << "...";
QLOG_DEBUG() << "Loading MMC Language File for"
<< locale.bcp47Name().toLocal8Bit().constData() << "...";
if (!installTranslator(m_mmc_translator.get()))
{
std::cout << " failed.";
QLOG_ERROR() << "Loading MMC Language File failed.";
m_mmc_translator.reset();
}
std::cout << std::endl;
}
else
{
@@ -290,34 +353,107 @@ void MultiMC::initLogger()
QsLogging::Logger &logger = QsLogging::Logger::instance();
logger.setLoggingLevel(QsLogging::TraceLevel);
m_fileDestination = QsLogging::DestinationFactory::MakeFileDestination(logBase.arg(0));
m_debugDestination = QsLogging::DestinationFactory::MakeQDebugDestination();
m_debugDestination = QsLogging::DestinationFactory::MakeDebugOutputDestination();
logger.addDestination(m_fileDestination.get());
logger.addDestination(m_debugDestination.get());
// log all the things
logger.setLoggingLevel(QsLogging::TraceLevel);
}
void MultiMC::initGlobalSettings()
void MultiMC::initGlobalSettings(bool test_mode)
{
m_settings.reset(new INISettingsObject("multimc.cfg", this));
// Updates
m_settings->registerSetting("UpdateChannel", version().channel);
m_settings->registerSetting("UpdateChannel", BuildConfig.VERSION_CHANNEL);
m_settings->registerSetting("AutoUpdate", true);
m_settings->registerSetting("IconTheme", QString("multimc"));
// Minecraft Sneaky Updates
m_settings->registerSetting("AutoUpdateMinecraftVersions", true);
// Notifications
m_settings->registerSetting("ShownNotifications", QString());
// Remembered state
m_settings->registerSetting("LastUsedGroupForNewInstance", QString());
QString defaultMonospace;
#ifdef Q_OS_WIN32
defaultMonospace = "Lucida Console";
#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);
QLOG_DEBUG() << "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", 11);
// FTB
m_settings->registerSetting("TrackFTBInstances", false);
QString ftbDataDefault;
#ifdef Q_OS_LINUX
QString ftbDefault = QDir::home().absoluteFilePath(".ftblauncher");
QString ftbDefault = ftbDataDefault = QDir::home().absoluteFilePath(".ftblauncher");
#elif defined(Q_OS_WIN32)
QString ftbDefault = PathCombine(QDir::homePath(), "AppData/Roaming/ftblauncher");
wchar_t buf[APPDATA_BUFFER_SIZE];
wchar_t newBuf[APPDATA_BUFFER_SIZE];
QString ftbDefault, newFtbDefault, oldFtbDefault;
if (!GetEnvironmentVariableW(L"LOCALAPPDATA", newBuf, APPDATA_BUFFER_SIZE))
{
QLOG_FATAL() << "Your LOCALAPPDATA folder is missing! If you are on windows, this "
"means your system is broken. If you aren't on windows, how the **** "
"are you running the windows build????";
}
else
{
newFtbDefault = QDir(QString::fromWCharArray(newBuf)).absoluteFilePath("ftblauncher");
}
if (!GetEnvironmentVariableW(L"APPDATA", buf, APPDATA_BUFFER_SIZE))
{
QLOG_FATAL() << "Your APPDATA folder is missing! If you are on windows, this means "
"your system is broken. If you aren't on windows, how the **** are you "
"running the windows build????";
}
else
{
oldFtbDefault = QDir(QString::fromWCharArray(buf)).absoluteFilePath("ftblauncher");
}
if (QFile::exists(QDir(newFtbDefault).absoluteFilePath("ftblaunch.cfg")))
{
QLOG_INFO() << "Old FTB setup";
ftbDefault = ftbDataDefault = oldFtbDefault;
}
else
{
QLOG_INFO() << "New FTB setup";
ftbDefault = oldFtbDefault;
ftbDataDefault = newFtbDefault;
}
#elif defined(Q_OS_MAC)
QString ftbDefault =
QString ftbDefault = ftbDataDefault =
PathCombine(QDir::homePath(), "Library/Application Support/ftblauncher");
#endif
m_settings->registerSetting("FTBLauncherDataRoot", ftbDataDefault);
m_settings->registerSetting("FTBLauncherRoot", ftbDefault);
QLOG_INFO() << "FTB Launcher paths:" << m_settings->get("FTBLauncherDataRoot").toString()
<< "and" << m_settings->get("FTBLauncherRoot").toString();
m_settings->registerSetting("FTBRoot");
if (m_settings->get("FTBRoot").isNull())
@@ -366,9 +502,14 @@ void MultiMC::initGlobalSettings()
// 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));
@@ -395,6 +536,7 @@ void MultiMC::initGlobalSettings()
// Java Settings
m_settings->registerSetting("JavaPath", "");
m_settings->registerSetting("LastHostname", "");
m_settings->registerSetting("JavaDetectionHack", "");
m_settings->registerSetting("JvmArgs", "");
// Custom Commands
@@ -415,6 +557,8 @@ void MultiMC::initGlobalSettings()
m_settings->registerSetting("ConsoleWindowGeometry", "");
m_settings->registerSetting("SettingsGeometry", "");
m_settings->registerSetting("PagedGeometry", "");
}
void MultiMC::initHttpMetaCache()
@@ -425,8 +569,11 @@ void MultiMC::initHttpMetaCache()
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("fmllibs", QDir("mods/minecraftforge/libs").absolutePath());
m_metacache->addBase("liteloader", QDir("mods/liteloader").absolutePath());
m_metacache->addBase("skins", QDir("accounts/skins").absolutePath());
m_metacache->addBase("root", QDir(root()).absolutePath());
m_metacache->addBase("translations", QDir(staticData() + "/translations").absolutePath());
m_metacache->Load();
}
@@ -443,11 +590,13 @@ void MultiMC::updateProxySettings()
// Set the application proxy settings.
if (proxyTypeStr == "SOCKS5")
{
QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, addr, port, user, pass));
QNetworkProxy::setApplicationProxy(
QNetworkProxy(QNetworkProxy::Socks5Proxy, addr, port, user, pass));
}
else if (proxyTypeStr == "HTTP")
{
QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::HttpProxy, addr, port, user, pass));
QNetworkProxy::setApplicationProxy(
QNetworkProxy(QNetworkProxy::HttpProxy, addr, port, user, pass));
}
else if (proxyTypeStr == "None")
{
@@ -462,7 +611,8 @@ void MultiMC::updateProxySettings()
QLOG_INFO() << "Detecting proxy settings...";
QNetworkProxy proxy = QNetworkProxy::applicationProxy();
if (m_qnam.get()) m_qnam->setProxy(proxy);
if (m_qnam.get())
m_qnam->setProxy(proxy);
QString proxyDesc;
if (proxy.type() == QNetworkProxy::NoProxy)
{
@@ -525,6 +675,15 @@ std::shared_ptr<ForgeVersionList> MultiMC::forgelist()
return m_forgelist;
}
std::shared_ptr<LiteLoaderVersionList> MultiMC::liteloaderlist()
{
if (!m_liteloaderlist)
{
m_liteloaderlist.reset(new LiteLoaderVersionList());
}
return m_liteloaderlist;
}
std::shared_ptr<MinecraftVersionList> MultiMC::minecraftlist()
{
if (!m_minecraftlist)
@@ -543,34 +702,43 @@ std::shared_ptr<JavaVersionList> MultiMC::javalist()
return m_javalist;
}
std::shared_ptr<URNResolver> MultiMC::resolver()
{
if (!m_resolver)
{
m_resolver.reset(new URNResolver());
}
return m_resolver;
}
void MultiMC::installUpdates(const QString updateFilesDir, UpdateFlags flags)
{
// if we are going to update on exit, save the params now
if(flags & OnExit)
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())
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
#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
@@ -579,7 +747,7 @@ void MultiMC::installUpdates(const QString updateFilesDir, UpdateFlags flags)
args << "--package-dir" << updateFilesDir;
args << "--script" << PathCombine(updateFilesDir, "file_list.xml");
args << "--wait" << QString::number(MMC->applicationPid());
if(flags & DryRun)
if (flags & DryRun)
args << "--dry-run";
if (flags & RestartOnFinish)
{
@@ -589,7 +757,7 @@ void MultiMC::installUpdates(const QString updateFilesDir, UpdateFlags flags)
QLOG_INFO() << "Running updater with command" << updaterBinary << args.join(" ");
QFile::setPermissions(updaterBinary, (QFileDevice::Permission)0x7755);
if (!QProcess::startDetached(updaterBinary, args/*, root()*/))
if (!QProcess::startDetached(updaterBinary, args /*, root()*/))
{
QLOG_ERROR() << "Failed to start the updater process!";
return;
@@ -601,7 +769,7 @@ void MultiMC::installUpdates(const QString updateFilesDir, UpdateFlags flags)
void MultiMC::onExit()
{
if(m_updateOnExitPath.size())
if (m_updateOnExitPath.size())
{
installUpdates(m_updateOnExitPath, m_updateOnExitFlags);
}

View File

@@ -1,8 +1,6 @@
#pragma once
#include "config.h"
#include <QApplication>
#include "MultiMCVersion.h"
#include <memory>
#include "logger/QsLog.h"
#include "logger/QsLogDest.h"
@@ -17,25 +15,22 @@ class MojangAccountList;
class IconList;
class QNetworkAccessManager;
class ForgeVersionList;
class LiteLoaderVersionList;
class JavaVersionList;
class UpdateChecker;
class NotificationChecker;
class NewsChecker;
class StatusChecker;
class BaseProfilerFactory;
class BaseDetachedToolFactory;
class URNResolver;
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,
@@ -58,7 +53,7 @@ public:
};
public:
MultiMC(int &argc, char **argv, bool root_override = false);
MultiMC(int &argc, char **argv, bool test_mode = false);
virtual ~MultiMC();
std::shared_ptr<SettingsObject> settings()
@@ -83,11 +78,6 @@ public:
return m_status;
}
MultiMCVersion version()
{
return m_version;
}
std::shared_ptr<QNetworkAccessManager> qnam()
{
return m_qnam;
@@ -113,14 +103,32 @@ public:
return m_newsChecker;
}
std::shared_ptr<StatusChecker> statusChecker()
{
return m_statusChecker;
}
std::shared_ptr<LWJGLVersionList> lwjgllist();
std::shared_ptr<ForgeVersionList> forgelist();
std::shared_ptr<LiteLoaderVersionList> liteloaderlist();
std::shared_ptr<MinecraftVersionList> minecraftlist();
std::shared_ptr<JavaVersionList> javalist();
std::shared_ptr<URNResolver> resolver();
QMap<QString, std::shared_ptr<BaseProfilerFactory>> profilers()
{
return m_profilers;
}
QMap<QString, std::shared_ptr<BaseDetachedToolFactory>> tools()
{
return m_tools;
}
void installUpdates(const QString updateFilesDir, UpdateFlags flags = None);
/*!
@@ -134,6 +142,11 @@ public:
*/
bool openJsonEditor(const QString &filename);
/// this is the static data. it stores things that don't move.
const QString &staticData()
{
return staticDataPath;
}
/// this is the root of the 'installation'. Used for automatic updates
const QString &root()
{
@@ -166,7 +179,7 @@ private slots:
private:
void initLogger();
void initGlobalSettings();
void initGlobalSettings(bool test_mode);
void initHttpMetaCache();
@@ -183,14 +196,22 @@ private:
std::shared_ptr<UpdateChecker> m_updateChecker;
std::shared_ptr<NotificationChecker> m_notificationChecker;
std::shared_ptr<NewsChecker> m_newsChecker;
std::shared_ptr<StatusChecker> m_statusChecker;
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;
std::shared_ptr<URNResolver> m_resolver;
std::shared_ptr<TranslationDownloader> m_translationChecker;
QMap<QString, std::shared_ptr<BaseProfilerFactory>> m_profilers;
QMap<QString, std::shared_ptr<BaseDetachedToolFactory>> m_tools;
QsLogging::DestinationPtr m_fileDestination;
QsLogging::DestinationPtr m_debugDestination;
@@ -198,10 +219,10 @@ private:
UpdateFlags m_updateOnExitFlags = None;
QString rootPath;
QString staticDataPath;
QString binPath;
QString dataPath;
QString origcwdPath;
Status m_status = MultiMC::Failed;
MultiMCVersion m_version;
};

Binary file not shown.

View File

@@ -1,96 +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.
*/
struct MultiMCVersion
{
enum Type
{
//! Version type for stable release builds.
Release,
//! Version type for release candidates.
ReleaseCandidate,
//! Version type for development builds.
Development,
//! Version type for custom builds. This is the default when no version type is specified.
Custom
};
/*!
* \brief Converts the Version to a string.
* \return The version number in string format (major.minor.revision.build).
*/
QString toString() const
{
QString vstr = QString("%1.%2").arg(
QString::number(major),
QString::number(minor));
if (hotfix > 0) vstr += "." + QString::number(hotfix);
// If the build is a development build or release candidate, add that info to the end.
if (type == Development) vstr += "-dev" + QString::number(build);
else if (type == ReleaseCandidate) vstr += "-rc" + QString::number(build);
return vstr;
}
QString typeName() const
{
switch (type)
{
case Release:
return "Stable Release";
case ReleaseCandidate:
return "Release Candidate";
case Development:
return "Development";
case Custom:
default:
return "Custom";
}
}
//! The major version number.
int major;
//! The minor version number.
int minor;
//! The hotfix number.
int hotfix;
//! The build number.
int build;
//! The build type.
Type type;
//! The build channel.
QString channel;
//! A short string identifying the platform that this version is for. For example, lin64 or win32.
QString platform;
};

View File

@@ -1,6 +1,6 @@
![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)
=========
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.
@@ -9,7 +9,7 @@ MultiMC is a custom launcher for Minecraft that allows you to easily manage mult
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-2014 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).

77
WinBacktrace.cpp Normal file
View File

@@ -0,0 +1,77 @@
/* Copyright 2013-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// CAUTION:
// This file contains all manner of hackery and insanity.
// I will not be responsible for any loss of sanity due to reading this code.
// Here be dragons!
#include "WinBacktrace.h"
#include <windows.h>
#ifndef __i386__
#error WinBacktrace is only supported on x86 architectures.
#endif
// We need to do some crazy shit to walk through the stack.
// Windows unwinds the stack when an exception is thrown, so we
// need to examine the EXCEPTION_POINTERS's CONTEXT.
size_t getBacktrace(StackFrame *stack, size_t size, CONTEXT ctx)
{
// Written using information and a bit of pseudocode from
// http://www.eptacom.net/pubblicazioni/pub_eng/except.html
// This is probably one of the most horrifying things I've ever written.
// This tracks whether the current EBP is valid.
// When an invalid EBP is encountered, we stop walking the stack.
bool validEBP = true;
DWORD ebp = ctx.Ebp; // The current EBP (Extended Base Pointer)
DWORD eip = ctx.Eip;
int i;
for (i = 0; i < size; i++)
{
if (ebp & 3)
validEBP = false;
// FIXME: This function is obsolete, according to MSDN.
else if (IsBadReadPtr((void*) ebp, 8))
validEBP = false;
if (!validEBP) break;
// Find the caller.
// On the first iteration, the caller is whatever EIP points to.
// On successive iterations, the caller is the byte after EBP.
BYTE* caller = !i ? (BYTE*)eip : *((BYTE**) ebp + 1);
// The first ebp is the EBP from the CONTEXT.
// On successive iterations, the EBP is the DWORD that the previous EBP points to.
ebp = !i ? ebp : *(DWORD*)ebp;
// Find the caller's module.
// We'll use VirtualQuery to get information about the caller's address.
MEMORY_BASIC_INFORMATION mbi;
VirtualQuery(caller, &mbi, sizeof(mbi));
// We can get the instance handle from the allocation base.
HINSTANCE hInst = (HINSTANCE)mbi.AllocationBase;
// If the handle is 0, then the EBP is invalid.
if (hInst == 0) validEBP = false;
// Otherwise, dump info about the caller.
else stack[i].address = (void*)caller;
}
return i;
}

44
WinBacktrace.h Normal file
View File

@@ -0,0 +1,44 @@
/* Copyright 2013-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <windows.h>
#ifndef SF_STR_LEN
// The max length of all strings in the StackFrame struct.
// Because it must be stack allocated, this must be known at compile time.
// Stuff longer than this will be truncated.
// Defaults to 4096 (4kB)
#define SF_STR_LEN 4096
#endif
// Data structure for holding information about a stack frame.
// There's some more hackery in here so it can be allocated on the stack.
struct StackFrame
{
// The address of this stack frame.
void* address;
// The name of the function at this address.
char funcName[SF_STR_LEN];
};
// This function walks through the given CONTEXT structure, extracting a
// backtrace from it.
// The backtrace will be put into the array given by the `stack` argument
// with a maximum length of `size`.
// This function returns the size of the backtrace retrieved.
size_t getBacktrace(StackFrame* stack, size_t size, CONTEXT ctx);

153
changelog.md Normal file
View File

@@ -0,0 +1,153 @@
#MultiMC Changelog
##0.4.4
- Other logs larger than 10MB will not load to prevent logs eating the whole available memory
- Translations are now updated independently from MultiMC
- Added new and reworked the old simple icon themes
- LWJGL on OSX should no longer clash with Java 8
- Update to newer Qt version
- Look and feel updated for latest OSX
- Fixed issues caused by Minecraft inheriting the environment variables from MultiMC
- Minecraft log improvements:
- Implemented search and pause
- Automated coloring is updated for log format used by Minecraft 1.7+
- Added settings for the font used in the console, using sensible defaults for the OS
- Removed MultiMC crash handler, it will be replaced by a better one in the future
##0.4.3
- Fix for issues with Minecraft version file updates
- Fix for console window related memory leak
- Fix for travis.ci build
##0.4.2
- Show a warning in the log if a library is missing
- Fixes for relocating instances to other MultiMC installs:
- Libraries now use full Gradle dependency specifiers
- Rework of forge installer (forge can reinstall itself using only the information already in the instance)
- Fixed bugs in rarely used library insertion rules
- Make the global settings dialog into a page dialog
- Check if the Java binary can be found before launch
- Show a warning for paths containing a '!' (Java can't handle that properly)
- Many smaller fixes
##0.4.1
- Fix LWJGL version list (SourceForge has changed the download API)
##0.4.0
- Jar support in 1.6+
- Deprecated legacy instances
- Legacy instances can still be used but not created
- All Minecraft versions are supported in the new instance format
- All instance editing and settings dialogs were turned into pages
- The edit instance dialog contains pages relevant to editing and settings
- The console window contains pages useful when playing the game
- Redone the screenshot management and upload (page)
- Added a way to display and manage log files and crash reports generated by Minecraft (page)
- Added measures to prevent corruption of version files
- Minecraft version files are no longer part of the instances by default
- Added help for the newly added dialog pages
- Made logs uploaded to paste.ee expire after a month
- Fixed a few bugs related to liteloader and forge (1.7.10 issues)
- Icon themes. Two new themes where added (work in progress)
- Changelog and update channel are now visible in the update dialog
- Several performance improvements to the group view
- Added keyboard navigation to the group view
##0.3.9
- Workaround for 1.7.10 Forge
##0.3.8
- Workaround for performance issues with Intel integrated graphics chips
##0.3.7
- Fixed forge for 1.7.10-pre4 (and any future prereleases)
##0.3.6
- New server status - now with more color
- Fix for FTB tracking issues
- Fix for translations on OSX not working
- Screenshot dialog should be harder to lose track of when used from the console window
- A crash handler implementation has been added.
##0.3.5
- More versions are now selectable when changing instance versions
- Fix for Forge/FML changing its mcmod.info metadata format
##0.3.4
- Show a list of Patreon patrons in credits section of the about dialog
- Make the console window raise itself after minecraft closes
- Add Control/Command+q shortcut to quit from the main window
- Add french translation
- Download and cache FML libs for legacy versions
- Update the OS X icon
- Fix FTB libraries not being used properly
##0.3.3
- Tweak context menu to prevent accidental clicks
- Fix adding icons to custom icon directories
- Added a Patreon button to the toolbar
- Minecraft authentication tasks now provide better error reports
##0.3.2
- Fix issues with libraries not getting replaced properly (fixes instance startup for new instances)
- Fix april fools
##0.3.1
- Fix copying of FTB instances (instance type is changed properly now)
- Customizing FTB pack versions will remove the FTB pack patch file
##0.3
- Improved instance view
- Overhauled 1.6+ version loading
- Added a patch system for instance modification
- There is no longer a single custom.json file that overrides version.json
- Instead there are now "patch" files in <instance>/patches/, one for each main tweaker (forge, liteloader etc.)
- These patches are applied after version.json in a customisable order,
- A list of these files is shown in the left most tab in the Edit Mods dialog, where a list of libraries was shown before.
- custom.json can still be used for overriding everything.
- Offline mode can be used even when online
- Show an "empty" message in version selector dialogs
- Fix FTB paths on windows
- Tooling support
- JProfiler
- JVisualVM
- MCEdit
- Don't assume forge in FTB instances and allow other libraries (liteloader, mcpatcher, etc.) in FTB instances
- Screenshot uploading/managing
- Instance badges
- Some pre/post command stuff (remove the timeout, variable substitution)
- Fix logging when the system language is not en_US
- Setting PermGen to 64 will now omit the java parameter because it is the default
- Fix encoding of escape sequences (tabs and newlines) in config files
##0.2.1
- Hotfix - move the native library extraction into the onesix launcher part.
##0.2
- Java memory settings have MB added to the number to make the units obvious.
- Complete rework of the launcher part. No more sensitive information in the process arguments.
- Cached downloads now do not destroy files on failure.
- Mojang service status is now on the MultiMC status bar.
- Java checker is no longer needed/used on instance launch.
- Support for private FTB packs.
- Fixed instance ID issues related to copying FTB packs without changing the instance name.
- Forge versions are better sorted (build numbers above 999 were sorted wrong).
- Fixed crash related to the MultiMC update channel picker in offline mode.
- Started using icon themes for the application icons, fixing many OSX graphical glitches.
- Icon sources have been located, along with icon licenses.
- Update to the German translation.
##0.1.1
- Hotfix - Changed the issue tracker URL to [GitHub issues](https://github.com/MultiMC/MultiMC5/issues).
##0.1
- Reworked the version numbering system to support our [new Git workflow](http://nvie.com/posts/a-successful-git-branching-model/).
- Added a tray icon for the console window.
- Fixed instances getting deselected after FTB instances are loaded (or whenever the model is reset).
- Implemented proxy settings.
- Fixed sorting of Java installations in the Java list.
- Jar files are now distributed separately, rather than being extracted from the binary at runtime.
- Added additional information to the about dialog.
##0.0
- Initial release.

View File

@@ -1,17 +0,0 @@
#
# This is MultiMC's changelog. It is formatted in YAML.
#
# Each key below represents a release version name. Each release key has several string entries under it, each containing information about a single change. Each of these entries may contain Markdown for formatting.
#
0.0:
- Initial release.
0.1:
- Reworked the version numbering system to support our [new Git workflow](http://nvie.com/posts/a-successful-git-branching-model/).
- Added a tray icon for the console window.
- Fixed instances getting deselected after FTB instances are loaded (or whenever the model is reset).
- Implemented proxy settings.
- Fixed sorting of Java installations in the Java list.
- Jar files are now distributed separately, rather than being extracted from the binary at runtime.
- Added additional information to the about dialog.

786
cmake/BundleUtilities.cmake Normal file
View File

@@ -0,0 +1,786 @@
# - Functions to help assemble a standalone bundle application.
# A collection of CMake utility functions useful for dealing with .app
# bundles on the Mac and bundle-like directories on any OS.
#
# The following functions are provided by this module:
# fixup_bundle
# copy_and_fixup_bundle
# verify_app
# get_bundle_main_executable
# get_dotapp_dir
# get_bundle_and_executable
# get_bundle_all_executables
# get_item_key
# clear_bundle_keys
# set_bundle_key_values
# get_bundle_keys
# copy_resolved_item_into_bundle
# copy_resolved_framework_into_bundle
# fixup_bundle_item
# verify_bundle_prerequisites
# verify_bundle_symlinks
# Requires CMake 2.6 or greater because it uses function, break and
# PARENT_SCOPE. Also depends on GetPrerequisites.cmake.
#
# FIXUP_BUNDLE(<app> <libs> <dirs>)
# Fix up a bundle in-place and make it standalone, such that it can be
# drag-n-drop copied to another machine and run on that machine as long as all
# of the system libraries are compatible.
#
# If you pass plugins to fixup_bundle as the libs parameter, you should install
# them or copy them into the bundle before calling fixup_bundle. The "libs"
# parameter is a list of libraries that must be fixed up, but that cannot be
# determined by otool output analysis. (i.e., plugins)
#
# Gather all the keys for all the executables and libraries in a bundle, and
# then, for each key, copy each prerequisite into the bundle. Then fix each one
# up according to its own list of prerequisites.
#
# Then clear all the keys and call verify_app on the final bundle to ensure
# that it is truly standalone.
#
# COPY_AND_FIXUP_BUNDLE(<src> <dst> <libs> <dirs>)
# Makes a copy of the bundle <src> at location <dst> and then fixes up the
# new copied bundle in-place at <dst>...
#
# VERIFY_APP(<app>)
# Verifies that an application <app> appears valid based on running analysis
# tools on it. Calls "message(FATAL_ERROR" if the application is not verified.
#
# GET_BUNDLE_MAIN_EXECUTABLE(<bundle> <result_var>)
# The result will be the full path name of the bundle's main executable file
# or an "error:" prefixed string if it could not be determined.
#
# GET_DOTAPP_DIR(<exe> <dotapp_dir_var>)
# Returns the nearest parent dir whose name ends with ".app" given the full
# path to an executable. If there is no such parent dir, then simply return
# the dir containing the executable.
#
# The returned directory may or may not exist.
#
# GET_BUNDLE_AND_EXECUTABLE(<app> <bundle_var> <executable_var> <valid_var>)
# Takes either a ".app" directory name or the name of an executable
# nested inside a ".app" directory and returns the path to the ".app"
# directory in <bundle_var> and the path to its main executable in
# <executable_var>
#
# GET_BUNDLE_ALL_EXECUTABLES(<bundle> <exes_var>)
# Scans the given bundle recursively for all executable files and accumulates
# them into a variable.
#
# GET_ITEM_KEY(<item> <key_var>)
# Given a file (item) name, generate a key that should be unique considering
# the set of libraries that need copying or fixing up to make a bundle
# standalone. This is essentially the file name including extension with "."
# replaced by "_"
#
# This key is used as a prefix for CMake variables so that we can associate a
# set of variables with a given item based on its key.
#
# CLEAR_BUNDLE_KEYS(<keys_var>)
# Loop over the list of keys, clearing all the variables associated with each
# key. After the loop, clear the list of keys itself.
#
# Caller of get_bundle_keys should call clear_bundle_keys when done with list
# of keys.
#
# SET_BUNDLE_KEY_VALUES(<keys_var> <context> <item> <exepath> <dirs>
# <copyflag>)
# Add a key to the list (if necessary) for the given item. If added,
# also set all the variables associated with that key.
#
# GET_BUNDLE_KEYS(<app> <libs> <dirs> <keys_var>)
# Loop over all the executable and library files within the bundle (and given
# as extra <libs>) and accumulate a list of keys representing them. Set
# values associated with each key such that we can loop over all of them and
# copy prerequisite libs into the bundle and then do appropriate
# install_name_tool fixups.
#
# COPY_RESOLVED_ITEM_INTO_BUNDLE(<resolved_item> <resolved_embedded_item>)
# Copy a resolved item into the bundle if necessary. Copy is not necessary if
# the resolved_item is "the same as" the resolved_embedded_item.
#
# COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE(<resolved_item> <resolved_embedded_item>)
# Copy a resolved framework into the bundle if necessary. Copy is not necessary
# if the resolved_item is "the same as" the resolved_embedded_item.
#
# By default, BU_COPY_FULL_FRAMEWORK_CONTENTS is not set. If you want full
# frameworks embedded in your bundles, set BU_COPY_FULL_FRAMEWORK_CONTENTS to
# ON before calling fixup_bundle. By default,
# COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE copies the framework dylib itself plus
# the framework Resources directory.
#
# FIXUP_BUNDLE_ITEM(<resolved_embedded_item> <exepath> <dirs>)
# Get the direct/non-system prerequisites of the resolved embedded item. For
# each prerequisite, change the way it is referenced to the value of the
# _EMBEDDED_ITEM keyed variable for that prerequisite. (Most likely changing to
# an "@executable_path" style reference.)
#
# This function requires that the resolved_embedded_item be "inside" the bundle
# already. In other words, if you pass plugins to fixup_bundle as the libs
# parameter, you should install them or copy them into the bundle before
# calling fixup_bundle. The "libs" parameter is a list of libraries that must
# be fixed up, but that cannot be determined by otool output analysis. (i.e.,
# plugins)
#
# Also, change the id of the item being fixed up to its own _EMBEDDED_ITEM
# value.
#
# Accumulate changes in a local variable and make *one* call to
# install_name_tool at the end of the function with all the changes at once.
#
# If the BU_CHMOD_BUNDLE_ITEMS variable is set then bundle items will be
# marked writable before install_name_tool tries to change them.
#
# VERIFY_BUNDLE_PREREQUISITES(<bundle> <result_var> <info_var>)
# Verifies that the sum of all prerequisites of all files inside the bundle
# are contained within the bundle or are "system" libraries, presumed to exist
# everywhere.
#
# VERIFY_BUNDLE_SYMLINKS(<bundle> <result_var> <info_var>)
# Verifies that any symlinks found in the bundle point to other files that are
# already also in the bundle... Anything that points to an external file causes
# this function to fail the verification.
#=============================================================================
# Copyright 2008-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
# The functions defined in this file depend on the get_prerequisites function
# (and possibly others) found in:
#
get_filename_component(BundleUtilities_cmake_dir "${CMAKE_CURRENT_LIST_FILE}" PATH)
include("${BundleUtilities_cmake_dir}/GetPrerequisites.cmake")
function(get_bundle_main_executable bundle result_var)
set(result "error: '${bundle}/Contents/Info.plist' file does not exist")
if(EXISTS "${bundle}/Contents/Info.plist")
set(result "error: no CFBundleExecutable in '${bundle}/Contents/Info.plist' file")
set(line_is_main_executable 0)
set(bundle_executable "")
# Read Info.plist as a list of lines:
#
set(eol_char "E")
file(READ "${bundle}/Contents/Info.plist" info_plist)
string(REGEX REPLACE ";" "\\\\;" info_plist "${info_plist}")
string(REGEX REPLACE "\n" "${eol_char};" info_plist "${info_plist}")
# Scan the lines for "<key>CFBundleExecutable</key>" - the line after that
# is the name of the main executable.
#
foreach(line ${info_plist})
if(line_is_main_executable)
string(REGEX REPLACE "^.*<string>(.*)</string>.*$" "\\1" bundle_executable "${line}")
break()
endif()
if(line MATCHES "^.*<key>CFBundleExecutable</key>.*$")
set(line_is_main_executable 1)
endif()
endforeach()
if(NOT "${bundle_executable}" STREQUAL "")
if(EXISTS "${bundle}/Contents/MacOS/${bundle_executable}")
set(result "${bundle}/Contents/MacOS/${bundle_executable}")
else()
# Ultimate goal:
# If not in "Contents/MacOS" then scan the bundle for matching files. If
# there is only one executable file that matches, then use it, otherwise
# it's an error...
#
#file(GLOB_RECURSE file_list "${bundle}/${bundle_executable}")
# But for now, pragmatically, it's an error. Expect the main executable
# for the bundle to be in Contents/MacOS, it's an error if it's not:
#
set(result "error: '${bundle}/Contents/MacOS/${bundle_executable}' does not exist")
endif()
endif()
else()
#
# More inclusive technique... (This one would work on Windows and Linux
# too, if a developer followed the typical Mac bundle naming convention...)
#
# If there is no Info.plist file, try to find an executable with the same
# base name as the .app directory:
#
endif()
set(${result_var} "${result}" PARENT_SCOPE)
endfunction()
function(get_dotapp_dir exe dotapp_dir_var)
set(s "${exe}")
if(s MATCHES "^.*/.*\\.app/.*$")
# If there is a ".app" parent directory,
# ascend until we hit it:
# (typical of a Mac bundle executable)
#
set(done 0)
while(NOT ${done})
get_filename_component(snamewe "${s}" NAME_WE)
get_filename_component(sname "${s}" NAME)
get_filename_component(sdir "${s}" PATH)
set(s "${sdir}")
if(sname MATCHES "\\.app$")
set(done 1)
set(dotapp_dir "${sdir}/${sname}")
endif()
endwhile()
else()
# Otherwise use a directory containing the exe
# (typical of a non-bundle executable on Mac, Windows or Linux)
#
is_file_executable("${s}" is_executable)
if(is_executable)
get_filename_component(sdir "${s}" PATH)
set(dotapp_dir "${sdir}")
else()
set(dotapp_dir "${s}")
endif()
endif()
set(${dotapp_dir_var} "${dotapp_dir}" PARENT_SCOPE)
endfunction()
function(get_bundle_and_executable app bundle_var executable_var valid_var)
set(valid 0)
if(EXISTS "${app}")
# Is it a directory ending in .app?
if(IS_DIRECTORY "${app}")
if(app MATCHES "\\.app$")
get_bundle_main_executable("${app}" executable)
if(EXISTS "${app}" AND EXISTS "${executable}")
set(${bundle_var} "${app}" PARENT_SCOPE)
set(${executable_var} "${executable}" PARENT_SCOPE)
set(valid 1)
#message(STATUS "info: handled .app directory case...")
else()
message(STATUS "warning: *NOT* handled - .app directory case...")
endif()
else()
message(STATUS "warning: *NOT* handled - directory but not .app case...")
endif()
else()
# Is it an executable file?
is_file_executable("${app}" is_executable)
if(is_executable)
get_dotapp_dir("${app}" dotapp_dir)
if(EXISTS "${dotapp_dir}")
set(${bundle_var} "${dotapp_dir}" PARENT_SCOPE)
set(${executable_var} "${app}" PARENT_SCOPE)
set(valid 1)
#message(STATUS "info: handled executable file in .app dir case...")
else()
get_filename_component(app_dir "${app}" PATH)
set(${bundle_var} "${app_dir}" PARENT_SCOPE)
set(${executable_var} "${app}" PARENT_SCOPE)
set(valid 1)
#message(STATUS "info: handled executable file in any dir case...")
endif()
else()
message(STATUS "warning: *NOT* handled - not .app dir, not executable file...")
endif()
endif()
else()
message(STATUS "warning: *NOT* handled - directory/file does not exist...")
endif()
if(NOT valid)
set(${bundle_var} "error: not a bundle" PARENT_SCOPE)
set(${executable_var} "error: not a bundle" PARENT_SCOPE)
endif()
set(${valid_var} ${valid} PARENT_SCOPE)
endfunction()
function(get_bundle_all_executables bundle exes_var)
set(exes "")
file(GLOB_RECURSE file_list "${bundle}/*")
foreach(f ${file_list})
is_file_executable("${f}" is_executable)
if(is_executable)
set(exes ${exes} "${f}")
endif()
endforeach()
set(${exes_var} "${exes}" PARENT_SCOPE)
endfunction()
function(get_item_key item key_var)
get_filename_component(item_name "${item}" NAME)
if(WIN32)
string(TOLOWER "${item_name}" item_name)
endif()
string(REGEX REPLACE "\\." "_" ${key_var} "${item_name}")
set(${key_var} ${${key_var}} PARENT_SCOPE)
endfunction()
function(clear_bundle_keys keys_var)
foreach(key ${${keys_var}})
set(${key}_ITEM PARENT_SCOPE)
set(${key}_RESOLVED_ITEM PARENT_SCOPE)
set(${key}_DEFAULT_EMBEDDED_PATH PARENT_SCOPE)
set(${key}_EMBEDDED_ITEM PARENT_SCOPE)
set(${key}_RESOLVED_EMBEDDED_ITEM PARENT_SCOPE)
set(${key}_COPYFLAG PARENT_SCOPE)
endforeach()
set(${keys_var} PARENT_SCOPE)
endfunction()
function(set_bundle_key_values keys_var context item exepath dirs copyflag)
get_filename_component(item_name "${item}" NAME)
get_item_key("${item}" key)
list(LENGTH ${keys_var} length_before)
gp_append_unique(${keys_var} "${key}")
list(LENGTH ${keys_var} length_after)
if(NOT length_before EQUAL length_after)
gp_resolve_item("${context}" "${item}" "${exepath}" "${dirs}" resolved_item)
gp_item_default_embedded_path("${item}" default_embedded_path)
if(item MATCHES "[^/]+\\.framework/")
# For frameworks, construct the name under the embedded path from the
# opening "${item_name}.framework/" to the closing "/${item_name}":
#
string(REGEX REPLACE "^.*(${item_name}.framework/.*/?${item_name}).*$" "${default_embedded_path}/\\1" embedded_item "${item}")
else()
# For other items, just use the same name as the original, but in the
# embedded path:
#
set(embedded_item "${default_embedded_path}/${item_name}")
endif()
# Replace @executable_path and resolve ".." references:
#
string(REPLACE "@executable_path" "${exepath}" resolved_embedded_item "${embedded_item}")
get_filename_component(resolved_embedded_item "${resolved_embedded_item}" ABSOLUTE)
# *But* -- if we are not copying, then force resolved_embedded_item to be
# the same as resolved_item. In the case of multiple executables in the
# original bundle, using the default_embedded_path results in looking for
# the resolved executable next to the main bundle executable. This is here
# so that exes in the other sibling directories (like "bin") get fixed up
# properly...
#
if(NOT copyflag)
set(resolved_embedded_item "${resolved_item}")
endif()
set(${keys_var} ${${keys_var}} PARENT_SCOPE)
set(${key}_ITEM "${item}" PARENT_SCOPE)
set(${key}_RESOLVED_ITEM "${resolved_item}" PARENT_SCOPE)
set(${key}_DEFAULT_EMBEDDED_PATH "${default_embedded_path}" PARENT_SCOPE)
set(${key}_EMBEDDED_ITEM "${embedded_item}" PARENT_SCOPE)
set(${key}_RESOLVED_EMBEDDED_ITEM "${resolved_embedded_item}" PARENT_SCOPE)
set(${key}_COPYFLAG "${copyflag}" PARENT_SCOPE)
else()
#message("warning: item key '${key}' already in the list, subsequent references assumed identical to first")
endif()
endfunction()
function(get_bundle_keys app libs dirs keys_var)
set(${keys_var} PARENT_SCOPE)
get_bundle_and_executable("${app}" bundle executable valid)
if(valid)
# Always use the exepath of the main bundle executable for @executable_path
# replacements:
#
get_filename_component(exepath "${executable}" PATH)
# But do fixups on all executables in the bundle:
#
get_bundle_all_executables("${bundle}" exes)
# For each extra lib, accumulate a key as well and then also accumulate
# any of its prerequisites. (Extra libs are typically dynamically loaded
# plugins: libraries that are prerequisites for full runtime functionality
# but that do not show up in otool -L output...)
#
foreach(lib ${libs})
set_bundle_key_values(${keys_var} "${lib}" "${lib}" "${exepath}" "${dirs}" 0)
set(prereqs "")
get_prerequisites("${lib}" prereqs 1 1 "${exepath}" "${dirs}")
foreach(pr ${prereqs})
set_bundle_key_values(${keys_var} "${lib}" "${pr}" "${exepath}" "${dirs}" 1)
endforeach()
endforeach()
# For each executable found in the bundle, accumulate keys as we go.
# The list of keys should be complete when all prerequisites of all
# binaries in the bundle have been analyzed.
#
foreach(exe ${exes})
# Add the exe itself to the keys:
#
set_bundle_key_values(${keys_var} "${exe}" "${exe}" "${exepath}" "${dirs}" 0)
# Add each prerequisite to the keys:
#
set(prereqs "")
get_prerequisites("${exe}" prereqs 1 1 "${exepath}" "${dirs}")
foreach(pr ${prereqs})
set_bundle_key_values(${keys_var} "${exe}" "${pr}" "${exepath}" "${dirs}" 1)
endforeach()
endforeach()
# Propagate values to caller's scope:
#
set(${keys_var} ${${keys_var}} PARENT_SCOPE)
foreach(key ${${keys_var}})
set(${key}_ITEM "${${key}_ITEM}" PARENT_SCOPE)
set(${key}_RESOLVED_ITEM "${${key}_RESOLVED_ITEM}" PARENT_SCOPE)
set(${key}_DEFAULT_EMBEDDED_PATH "${${key}_DEFAULT_EMBEDDED_PATH}" PARENT_SCOPE)
set(${key}_EMBEDDED_ITEM "${${key}_EMBEDDED_ITEM}" PARENT_SCOPE)
set(${key}_RESOLVED_EMBEDDED_ITEM "${${key}_RESOLVED_EMBEDDED_ITEM}" PARENT_SCOPE)
set(${key}_COPYFLAG "${${key}_COPYFLAG}" PARENT_SCOPE)
endforeach()
endif()
endfunction()
function(copy_resolved_item_into_bundle resolved_item resolved_embedded_item)
if(WIN32)
# ignore case on Windows
string(TOLOWER "${resolved_item}" resolved_item_compare)
string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare)
else()
set(resolved_item_compare "${resolved_item}")
set(resolved_embedded_item_compare "${resolved_embedded_item}")
endif()
if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}")
message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...")
else()
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}")
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}")
if(UNIX AND NOT APPLE)
file(RPATH_REMOVE FILE "${resolved_embedded_item}")
endif()
endif()
endfunction()
function(copy_resolved_framework_into_bundle resolved_item resolved_embedded_item)
if(WIN32)
# ignore case on Windows
string(TOLOWER "${resolved_item}" resolved_item_compare)
string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare)
else()
set(resolved_item_compare "${resolved_item}")
set(resolved_embedded_item_compare "${resolved_embedded_item}")
endif()
if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}")
message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...")
else()
if(BU_COPY_FULL_FRAMEWORK_CONTENTS)
# Full Framework (everything):
get_filename_component(resolved_dir "${resolved_item}" PATH)
get_filename_component(resolved_dir "${resolved_dir}/../.." ABSOLUTE)
get_filename_component(resolved_embedded_dir "${resolved_embedded_item}" PATH)
get_filename_component(resolved_embedded_dir "${resolved_embedded_dir}/../.." ABSOLUTE)
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_dir}' '${resolved_embedded_dir}'")
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_dir}" "${resolved_embedded_dir}")
else()
# Framework lib itself:
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}")
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}")
# Plus Resources, if they exist:
string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1/Resources" resolved_resources "${resolved_item}")
string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1/Resources" resolved_embedded_resources "${resolved_embedded_item}")
if(EXISTS "${resolved_resources}")
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_resources}' '${resolved_embedded_resources}'")
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_resources}" "${resolved_embedded_resources}")
endif()
endif()
if(UNIX AND NOT APPLE)
file(RPATH_REMOVE FILE "${resolved_embedded_item}")
endif()
endif()
endfunction()
function(fixup_bundle_item resolved_embedded_item exepath dirs)
# This item's key is "ikey":
#
get_item_key("${resolved_embedded_item}" ikey)
# Ensure the item is "inside the .app bundle" -- it should not be fixed up if
# it is not in the .app bundle... Otherwise, we'll modify files in the build
# tree, or in other varied locations around the file system, with our call to
# install_name_tool. Make sure that doesn't happen here:
#
get_dotapp_dir("${exepath}" exe_dotapp_dir)
string(LENGTH "${exe_dotapp_dir}/" exe_dotapp_dir_length)
string(LENGTH "${resolved_embedded_item}" resolved_embedded_item_length)
set(path_too_short 0)
set(is_embedded 0)
if(${resolved_embedded_item_length} LESS ${exe_dotapp_dir_length})
set(path_too_short 1)
endif()
if(NOT path_too_short)
string(SUBSTRING "${resolved_embedded_item}" 0 ${exe_dotapp_dir_length} item_substring)
if("${exe_dotapp_dir}/" STREQUAL "${item_substring}")
set(is_embedded 1)
endif()
endif()
if(NOT is_embedded)
message(" exe_dotapp_dir/='${exe_dotapp_dir}/'")
message(" item_substring='${item_substring}'")
message(" resolved_embedded_item='${resolved_embedded_item}'")
message("")
message("Install or copy the item into the bundle before calling fixup_bundle.")
message("Or maybe there's a typo or incorrect path in one of the args to fixup_bundle?")
message("")
message(FATAL_ERROR "cannot fixup an item that is not in the bundle...")
endif()
set(prereqs "")
get_prerequisites("${resolved_embedded_item}" prereqs 1 0 "${exepath}" "${dirs}")
set(changes "")
foreach(pr ${prereqs})
# Each referenced item's key is "rkey" in the loop:
#
get_item_key("${pr}" rkey)
if(NOT "${${rkey}_EMBEDDED_ITEM}" STREQUAL "")
set(changes ${changes} "-change" "${pr}" "${${rkey}_EMBEDDED_ITEM}")
else()
message("warning: unexpected reference to '${pr}'")
endif()
endforeach()
if(BU_CHMOD_BUNDLE_ITEMS)
execute_process(COMMAND chmod u+w "${resolved_embedded_item}")
endif()
# Change this item's id and all of its references in one call
# to install_name_tool:
#
execute_process(COMMAND install_name_tool
${changes} -id "${${ikey}_EMBEDDED_ITEM}" "${resolved_embedded_item}"
)
endfunction()
function(fixup_bundle app libs dirs)
message(STATUS "fixup_bundle")
message(STATUS " app='${app}'")
message(STATUS " libs='${libs}'")
message(STATUS " dirs='${dirs}'")
get_bundle_and_executable("${app}" bundle executable valid)
if(valid)
get_filename_component(exepath "${executable}" PATH)
message(STATUS "fixup_bundle: preparing...")
get_bundle_keys("${app}" "${libs}" "${dirs}" keys)
message(STATUS "fixup_bundle: copying...")
list(LENGTH keys n)
math(EXPR n ${n}*2)
set(i 0)
foreach(key ${keys})
math(EXPR i ${i}+1)
if(${${key}_COPYFLAG})
message(STATUS "${i}/${n}: copying '${${key}_RESOLVED_ITEM}'")
else()
message(STATUS "${i}/${n}: *NOT* copying '${${key}_RESOLVED_ITEM}'")
endif()
set(show_status 0)
if(show_status)
message(STATUS "key='${key}'")
message(STATUS "item='${${key}_ITEM}'")
message(STATUS "resolved_item='${${key}_RESOLVED_ITEM}'")
message(STATUS "default_embedded_path='${${key}_DEFAULT_EMBEDDED_PATH}'")
message(STATUS "embedded_item='${${key}_EMBEDDED_ITEM}'")
message(STATUS "resolved_embedded_item='${${key}_RESOLVED_EMBEDDED_ITEM}'")
message(STATUS "copyflag='${${key}_COPYFLAG}'")
message(STATUS "")
endif()
if(${${key}_COPYFLAG})
set(item "${${key}_ITEM}")
if(item MATCHES "[^/]+\\.framework/")
copy_resolved_framework_into_bundle("${${key}_RESOLVED_ITEM}"
"${${key}_RESOLVED_EMBEDDED_ITEM}")
else()
copy_resolved_item_into_bundle("${${key}_RESOLVED_ITEM}"
"${${key}_RESOLVED_EMBEDDED_ITEM}")
endif()
endif()
endforeach()
message(STATUS "fixup_bundle: fixing...")
foreach(key ${keys})
math(EXPR i ${i}+1)
if(APPLE)
message(STATUS "${i}/${n}: fixing up '${${key}_RESOLVED_EMBEDDED_ITEM}'")
fixup_bundle_item("${${key}_RESOLVED_EMBEDDED_ITEM}" "${exepath}" "${dirs}")
else()
message(STATUS "${i}/${n}: fix-up not required on this platform '${${key}_RESOLVED_EMBEDDED_ITEM}'")
endif()
endforeach()
message(STATUS "fixup_bundle: cleaning up...")
clear_bundle_keys(keys)
message(STATUS "fixup_bundle: verifying...")
verify_app("${app}")
else()
message(SEND_ERROR "error: fixup_bundle: not a valid bundle")
endif()
message(STATUS "fixup_bundle: done")
endfunction()
function(copy_and_fixup_bundle src dst libs dirs)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${src}" "${dst}")
fixup_bundle("${dst}" "${libs}" "${dirs}")
endfunction()
function(verify_bundle_prerequisites bundle result_var info_var)
set(result 1)
set(info "")
set(count 0)
get_bundle_main_executable("${bundle}" main_bundle_exe)
file(GLOB_RECURSE file_list "${bundle}/*")
foreach(f ${file_list})
is_file_executable("${f}" is_executable)
if(is_executable)
get_filename_component(exepath "${f}" PATH)
math(EXPR count "${count} + 1")
message(STATUS "executable file ${count}: ${f}")
set(prereqs "")
get_prerequisites("${f}" prereqs 1 1 "${exepath}" "")
# On the Mac,
# "embedded" and "system" prerequisites are fine... anything else means
# the bundle's prerequisites are not verified (i.e., the bundle is not
# really "standalone")
#
# On Windows (and others? Linux/Unix/...?)
# "local" and "system" prereqs are fine...
#
set(external_prereqs "")
foreach(p ${prereqs})
set(p_type "")
gp_file_type("${f}" "${p}" p_type)
if(APPLE)
if(NOT "${p_type}" STREQUAL "embedded" AND NOT "${p_type}" STREQUAL "system")
set(external_prereqs ${external_prereqs} "${p}")
endif()
else()
if(NOT "${p_type}" STREQUAL "local" AND NOT "${p_type}" STREQUAL "system")
set(external_prereqs ${external_prereqs} "${p}")
endif()
endif()
endforeach()
if(external_prereqs)
# Found non-system/somehow-unacceptable prerequisites:
set(result 0)
set(info ${info} "external prerequisites found:\nf='${f}'\nexternal_prereqs='${external_prereqs}'\n")
endif()
endif()
endforeach()
if(result)
set(info "Verified ${count} executable files in '${bundle}'")
endif()
set(${result_var} "${result}" PARENT_SCOPE)
set(${info_var} "${info}" PARENT_SCOPE)
endfunction()
function(verify_bundle_symlinks bundle result_var info_var)
set(result 1)
set(info "")
set(count 0)
# TODO: implement this function for real...
# Right now, it is just a stub that verifies unconditionally...
set(${result_var} "${result}" PARENT_SCOPE)
set(${info_var} "${info}" PARENT_SCOPE)
endfunction()
function(verify_app app)
set(verified 0)
set(info "")
get_bundle_and_executable("${app}" bundle executable valid)
message(STATUS "===========================================================================")
message(STATUS "Analyzing app='${app}'")
message(STATUS "bundle='${bundle}'")
message(STATUS "executable='${executable}'")
message(STATUS "valid='${valid}'")
# Verify that the bundle does not have any "external" prerequisites:
#
verify_bundle_prerequisites("${bundle}" verified info)
message(STATUS "verified='${verified}'")
message(STATUS "info='${info}'")
message(STATUS "")
if(verified)
# Verify that the bundle does not have any symlinks to external files:
#
verify_bundle_symlinks("${bundle}" verified info)
message(STATUS "verified='${verified}'")
message(STATUS "info='${info}'")
message(STATUS "")
endif()
if(NOT verified)
message(FATAL_ERROR "error: verify_app failed")
endif()
endfunction()

13
cmake/Coverage.cmake Normal file
View File

@@ -0,0 +1,13 @@
if(__COVERAGE_CMAKE__)
return()
endif()
set(__COVERAGE_CMAKE__ TRUE)
if(MultiMC_CODE_COVERAGE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 --coverage")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 --coverage")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 --coverage")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O0 --coverage")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -O0 --coverage")
set(CMAKE_BUILD_TYPE "Debug")
endif(MultiMC_CODE_COVERAGE)

35
cmake/Coverity.cmake Normal file
View File

@@ -0,0 +1,35 @@
if(__COVERITY_CMAKE__)
return()
endif()
set(__COVERITY_CMAKE__ TRUE)
include(GitFunctions)
git_run(COMMAND config --get user.email DEFAULT "" OUTPUT_VAR GIT_EMAIL)
git_run(COMMAND describe DEFAULT "" OUTPUT_VAR GIT_VERSION)
set(MultiMC_COVERITY_TOKEN "" CACHE STRING "Coverity access token")
set(MultiMC_COVERITY_EMAIL "${GIT_EMAIL}" CACHE STRING "Coverity email")
set(MultiMC_COVERITY_TOOLS_DIR "${CMAKE_BINARY_DIR}/coverity_tools" CACHE PATH "Path to the coverity tools")
find_program(CURL_EXECUTABLE NAMES curl PATHS /usr/bin)
if(NOT CURL_EXECUTABLE STREQUAL "" AND NOT MultiMC_COVERITY_TOKEN STREQUAL "" AND NOT MultiMC_COVERITY_EMAIL STREQUAL "")
add_custom_target(coverity_configure
COMMAND ${MultiMC_COVERITY_TOOLS_DIR}/bin/cov-configure --comptype gcc --compiler ${CMAKE_C_COMPILER}
)
add_custom_target(coverity_create_tarball
COMMAND ${CMAKE_COMMAND} -E echo "Cleaning..." && ${CMAKE_MAKE_PROGRAM} clean
COMMAND ${CMAKE_COMMAND} -E echo "Building..." && ${MultiMC_COVERITY_TOOLS_DIR}/bin/cov-build --dir cov-int ${CMAKE_MAKE_PROGRAM} -j3
COMMAND ${CMAKE_COMMAND} -E echo "Creating tarball..." && ${CMAKE_COMMAND} -E tar cfz multimc_coverity.tgz cov-int/
COMMENT "Creating coverity build..."
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
add_custom_target(coverity_upload
COMMAND ${CURL_EXECUTABLE} --form project=02JanDal/MultiMC5 --form token=${MultiMC_COVERITY_TOKEN} --form email=${MultiMC_COVERITY_EMAIL} --form file=@multimc_coverity.tgz --form version=${MultiMC_GIT_COMMIT} --form description=${GIT_VERSION} http://scan5.coverity.com/cgi-bin/upload.py
DEPENDS coverity_create_tarball
COMMENT "Uploading to coverity..."
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endif()

View File

@@ -0,0 +1,895 @@
# - Functions to analyze and list executable file prerequisites.
# This module provides functions to list the .dll, .dylib or .so
# files that an executable or shared library file depends on. (Its
# prerequisites.)
#
# It uses various tools to obtain the list of required shared library files:
# dumpbin (Windows)
# objdump (MinGW on Windows)
# ldd (Linux/Unix)
# otool (Mac OSX)
# The following functions are provided by this module:
# get_prerequisites
# list_prerequisites
# list_prerequisites_by_glob
# gp_append_unique
# is_file_executable
# gp_item_default_embedded_path
# (projects can override with gp_item_default_embedded_path_override)
# gp_resolve_item
# (projects can override with gp_resolve_item_override)
# gp_resolved_file_type
# (projects can override with gp_resolved_file_type_override)
# gp_file_type
# Requires CMake 2.6 or greater because it uses function, break, return and
# PARENT_SCOPE.
#
# GET_PREREQUISITES(<target> <prerequisites_var> <exclude_system> <recurse>
# <exepath> <dirs>)
# Get the list of shared library files required by <target>. The list in
# the variable named <prerequisites_var> should be empty on first entry to
# this function. On exit, <prerequisites_var> will contain the list of
# required shared library files.
#
# <target> is the full path to an executable file. <prerequisites_var> is the
# name of a CMake variable to contain the results. <exclude_system> must be 0
# or 1 indicating whether to include or exclude "system" prerequisites. If
# <recurse> is set to 1 all prerequisites will be found recursively, if set to
# 0 only direct prerequisites are listed. <exepath> is the path to the top
# level executable used for @executable_path replacment on the Mac. <dirs> is
# a list of paths where libraries might be found: these paths are searched
# first when a target without any path info is given. Then standard system
# locations are also searched: PATH, Framework locations, /usr/lib...
#
# LIST_PREREQUISITES(<target> [<recurse> [<exclude_system> [<verbose>]]])
# Print a message listing the prerequisites of <target>.
#
# <target> is the name of a shared library or executable target or the full
# path to a shared library or executable file. If <recurse> is set to 1 all
# prerequisites will be found recursively, if set to 0 only direct
# prerequisites are listed. <exclude_system> must be 0 or 1 indicating whether
# to include or exclude "system" prerequisites. With <verbose> set to 0 only
# the full path names of the prerequisites are printed, set to 1 extra
# informatin will be displayed.
#
# LIST_PREREQUISITES_BY_GLOB(<glob_arg> <glob_exp>)
# Print the prerequisites of shared library and executable files matching a
# globbing pattern. <glob_arg> is GLOB or GLOB_RECURSE and <glob_exp> is a
# globbing expression used with "file(GLOB" or "file(GLOB_RECURSE" to retrieve
# a list of matching files. If a matching file is executable, its prerequisites
# are listed.
#
# Any additional (optional) arguments provided are passed along as the
# optional arguments to the list_prerequisites calls.
#
# GP_APPEND_UNIQUE(<list_var> <value>)
# Append <value> to the list variable <list_var> only if the value is not
# already in the list.
#
# IS_FILE_EXECUTABLE(<file> <result_var>)
# Return 1 in <result_var> if <file> is a binary executable, 0 otherwise.
#
# GP_ITEM_DEFAULT_EMBEDDED_PATH(<item> <default_embedded_path_var>)
# Return the path that others should refer to the item by when the item
# is embedded inside a bundle.
#
# Override on a per-project basis by providing a project-specific
# gp_item_default_embedded_path_override function.
#
# GP_RESOLVE_ITEM(<context> <item> <exepath> <dirs> <resolved_item_var>)
# Resolve an item into an existing full path file.
#
# Override on a per-project basis by providing a project-specific
# gp_resolve_item_override function.
#
# GP_RESOLVED_FILE_TYPE(<original_file> <file> <exepath> <dirs> <type_var>)
# Return the type of <file> with respect to <original_file>. String
# describing type of prerequisite is returned in variable named <type_var>.
#
# Use <exepath> and <dirs> if necessary to resolve non-absolute <file>
# values -- but only for non-embedded items.
#
# Possible types are:
# system
# local
# embedded
# other
# Override on a per-project basis by providing a project-specific
# gp_resolved_file_type_override function.
#
# GP_FILE_TYPE(<original_file> <file> <type_var>)
# Return the type of <file> with respect to <original_file>. String
# describing type of prerequisite is returned in variable named <type_var>.
#
# Possible types are:
# system
# local
# embedded
# other
#=============================================================================
# Copyright 2008-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
function(gp_append_unique list_var value)
set(contains 0)
foreach(item ${${list_var}})
if("${item}" STREQUAL "${value}")
set(contains 1)
break()
endif()
endforeach()
if(NOT contains)
set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE)
endif()
endfunction()
function(is_file_executable file result_var)
#
# A file is not executable until proven otherwise:
#
set(${result_var} 0 PARENT_SCOPE)
get_filename_component(file_full "${file}" ABSOLUTE)
string(TOLOWER "${file_full}" file_full_lower)
# If file name ends in .exe on Windows, *assume* executable:
#
if(WIN32 AND NOT UNIX)
if("${file_full_lower}" MATCHES "\\.exe$")
set(${result_var} 1 PARENT_SCOPE)
return()
endif()
# A clause could be added here that uses output or return value of dumpbin
# to determine ${result_var}. In 99%+? practical cases, the exe name
# match will be sufficient...
#
endif()
# Use the information returned from the Unix shell command "file" to
# determine if ${file_full} should be considered an executable file...
#
# If the file command's output contains "executable" and does *not* contain
# "text" then it is likely an executable suitable for prerequisite analysis
# via the get_prerequisites macro.
#
if(UNIX)
if(NOT file_cmd)
find_program(file_cmd "file")
mark_as_advanced(file_cmd)
endif()
if(file_cmd)
execute_process(COMMAND "${file_cmd}" "${file_full}"
OUTPUT_VARIABLE file_ov
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# Replace the name of the file in the output with a placeholder token
# (the string " _file_full_ ") so that just in case the path name of
# the file contains the word "text" or "executable" we are not fooled
# into thinking "the wrong thing" because the file name matches the
# other 'file' command output we are looking for...
#
string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}")
string(TOLOWER "${file_ov}" file_ov)
#message(STATUS "file_ov='${file_ov}'")
if("${file_ov}" MATCHES "executable")
#message(STATUS "executable!")
if("${file_ov}" MATCHES "text")
#message(STATUS "but text, so *not* a binary executable!")
else()
set(${result_var} 1 PARENT_SCOPE)
return()
endif()
endif()
# Also detect position independent executables on Linux,
# where "file" gives "shared object ... (uses shared libraries)"
if("${file_ov}" MATCHES "shared object.*\(uses shared libs\)")
set(${result_var} 1 PARENT_SCOPE)
return()
endif()
else()
message(STATUS "warning: No 'file' command, skipping execute_process...")
endif()
endif()
endfunction()
function(gp_item_default_embedded_path item default_embedded_path_var)
# On Windows and Linux, "embed" prerequisites in the same directory
# as the executable by default:
#
set(path "@executable_path")
set(overridden 0)
# On the Mac, relative to the executable depending on the type
# of the thing we are embedding:
#
if(APPLE)
#
# The assumption here is that all executables in the bundle will be
# in same-level-directories inside the bundle. The parent directory
# of an executable inside the bundle should be MacOS or a sibling of
# MacOS and all embedded paths returned from here will begin with
# "@executable_path/../" and will work from all executables in all
# such same-level-directories inside the bundle.
#
# By default, embed things right next to the main bundle executable:
#
set(path "@executable_path/../../Contents/MacOS")
# Embed .dylibs right next to the main bundle executable:
#
if(item MATCHES "\\.dylib$")
set(path "@executable_path/../MacOS")
set(overridden 1)
endif()
# Embed frameworks in the embedded "Frameworks" directory (sibling of MacOS):
#
if(NOT overridden)
if(item MATCHES "[^/]+\\.framework/")
set(path "@executable_path/../Frameworks")
set(overridden 1)
endif()
endif()
endif()
# Provide a hook so that projects can override the default embedded location
# of any given library by whatever logic they choose:
#
if(COMMAND gp_item_default_embedded_path_override)
gp_item_default_embedded_path_override("${item}" path)
endif()
set(${default_embedded_path_var} "${path}" PARENT_SCOPE)
endfunction()
function(gp_resolve_item context item exepath dirs resolved_item_var)
set(resolved 0)
set(resolved_item "${item}")
# Is it already resolved?
#
if(IS_ABSOLUTE "${resolved_item}" AND EXISTS "${resolved_item}")
set(resolved 1)
endif()
if(NOT resolved)
if(item MATCHES "@executable_path")
#
# @executable_path references are assumed relative to exepath
#
string(REPLACE "@executable_path" "${exepath}" ri "${item}")
get_filename_component(ri "${ri}" ABSOLUTE)
if(EXISTS "${ri}")
#message(STATUS "info: embedded item exists (${ri})")
set(resolved 1)
set(resolved_item "${ri}")
else()
message(STATUS "warning: embedded item does not exist '${ri}'")
endif()
endif()
endif()
if(NOT resolved)
if(item MATCHES "@loader_path")
#
# @loader_path references are assumed relative to the
# PATH of the given "context" (presumably another library)
#
get_filename_component(contextpath "${context}" PATH)
string(REPLACE "@loader_path" "${contextpath}" ri "${item}")
get_filename_component(ri "${ri}" ABSOLUTE)
if(EXISTS "${ri}")
#message(STATUS "info: embedded item exists (${ri})")
set(resolved 1)
set(resolved_item "${ri}")
else()
message(STATUS "warning: embedded item does not exist '${ri}'")
endif()
endif()
endif()
if(NOT resolved)
if(item MATCHES "@rpath")
#
# @rpath references are relative to the paths built into the binaries with -rpath
# We handle this case like we do for other Unixes
#
string(REPLACE "@rpath/" "" norpath_item "${item}")
set(ri "ri-NOTFOUND")
find_file(ri "${norpath_item}" ${exepath} ${dirs} NO_DEFAULT_PATH)
if(ri)
#message(STATUS "info: 'find_file' in exepath/dirs (${ri})")
set(resolved 1)
set(resolved_item "${ri}")
set(ri "ri-NOTFOUND")
endif()
endif()
endif()
if(NOT resolved)
set(ri "ri-NOTFOUND")
find_file(ri "${item}" ${exepath} ${dirs} NO_DEFAULT_PATH)
find_file(ri "${item}" ${exepath} ${dirs} /usr/lib)
if(ri)
#message(STATUS "info: 'find_file' in exepath/dirs (${ri})")
set(resolved 1)
set(resolved_item "${ri}")
set(ri "ri-NOTFOUND")
endif()
endif()
if(NOT resolved)
if(item MATCHES "[^/]+\\.framework/")
set(fw "fw-NOTFOUND")
find_file(fw "${item}"
"~/Library/Frameworks"
"/Library/Frameworks"
"/System/Library/Frameworks"
)
if(fw)
#message(STATUS "info: 'find_file' found framework (${fw})")
set(resolved 1)
set(resolved_item "${fw}")
set(fw "fw-NOTFOUND")
endif()
endif()
endif()
# Using find_program on Windows will find dll files that are in the PATH.
# (Converting simple file names into full path names if found.)
#
if(WIN32 AND NOT UNIX)
if(NOT resolved)
set(ri "ri-NOTFOUND")
find_program(ri "${item}" PATHS "${exepath};${dirs}" NO_DEFAULT_PATH)
find_program(ri "${item}" PATHS "${exepath};${dirs}")
if(ri)
#message(STATUS "info: 'find_program' in exepath/dirs (${ri})")
set(resolved 1)
set(resolved_item "${ri}")
set(ri "ri-NOTFOUND")
endif()
endif()
endif()
# Provide a hook so that projects can override item resolution
# by whatever logic they choose:
#
if(COMMAND gp_resolve_item_override)
gp_resolve_item_override("${context}" "${item}" "${exepath}" "${dirs}" resolved_item resolved)
endif()
if(NOT resolved)
message(STATUS "
warning: cannot resolve item '${item}'
possible problems:
need more directories?
need to use InstallRequiredSystemLibraries?
run in install tree instead of build tree?
")
# message(STATUS "
#******************************************************************************
#warning: cannot resolve item '${item}'
#
# possible problems:
# need more directories?
# need to use InstallRequiredSystemLibraries?
# run in install tree instead of build tree?
#
# context='${context}'
# item='${item}'
# exepath='${exepath}'
# dirs='${dirs}'
# resolved_item_var='${resolved_item_var}'
#******************************************************************************
#")
endif()
set(${resolved_item_var} "${resolved_item}" PARENT_SCOPE)
endfunction()
function(gp_resolved_file_type original_file file exepath dirs type_var)
#message(STATUS "**")
if(NOT IS_ABSOLUTE "${original_file}")
message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file")
endif()
set(is_embedded 0)
set(is_local 0)
set(is_system 0)
set(resolved_file "${file}")
if("${file}" MATCHES "^@(executable|loader)_path")
set(is_embedded 1)
endif()
if(NOT is_embedded)
if(NOT IS_ABSOLUTE "${file}")
gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file)
endif()
string(TOLOWER "${original_file}" original_lower)
string(TOLOWER "${resolved_file}" lower)
if(UNIX)
if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11R6/|/usr/bin/)")
set(is_system 1)
endif()
endif()
if(APPLE)
if(resolved_file MATCHES "^(/System/Library/|/usr/lib/)")
set(is_system 1)
endif()
endif()
if(WIN32)
string(TOLOWER "$ENV{SystemRoot}" sysroot)
string(REGEX REPLACE "\\\\" "/" sysroot "${sysroot}")
string(TOLOWER "$ENV{windir}" windir)
string(REGEX REPLACE "\\\\" "/" windir "${windir}")
if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)")
set(is_system 1)
endif()
if(UNIX)
# if cygwin, we can get the properly formed windows paths from cygpath
find_program(CYGPATH_EXECUTABLE cygpath)
if(CYGPATH_EXECUTABLE)
execute_process(COMMAND ${CYGPATH_EXECUTABLE} -W
OUTPUT_VARIABLE env_windir
OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND ${CYGPATH_EXECUTABLE} -S
OUTPUT_VARIABLE env_sysdir
OUTPUT_STRIP_TRAILING_WHITESPACE)
string(TOLOWER "${env_windir}" windir)
string(TOLOWER "${env_sysdir}" sysroot)
if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)")
set(is_system 1)
endif()
endif()
endif()
endif()
if(NOT is_system)
get_filename_component(original_path "${original_lower}" PATH)
get_filename_component(path "${lower}" PATH)
if("${original_path}" STREQUAL "${path}")
set(is_local 1)
else()
string(LENGTH "${original_path}/" original_length)
string(LENGTH "${lower}" path_length)
if(${path_length} GREATER ${original_length})
string(SUBSTRING "${lower}" 0 ${original_length} path)
if("${original_path}/" STREQUAL "${path}")
set(is_embedded 1)
endif()
endif()
endif()
endif()
endif()
# Return type string based on computed booleans:
#
set(type "other")
if(is_system)
set(type "system")
elseif(is_embedded)
set(type "embedded")
elseif(is_local)
set(type "local")
endif()
#message(STATUS "gp_resolved_file_type: '${file}' '${resolved_file}'")
#message(STATUS " type: '${type}'")
if(NOT is_embedded)
if(NOT IS_ABSOLUTE "${resolved_file}")
if(lower MATCHES "^msvc[^/]+dll" AND is_system)
message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'")
else()
message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect")
endif()
endif()
endif()
# Provide a hook so that projects can override the decision on whether a
# library belongs to the system or not by whatever logic they choose:
#
if(COMMAND gp_resolved_file_type_override)
gp_resolved_file_type_override("${resolved_file}" type)
endif()
set(${type_var} "${type}" PARENT_SCOPE)
#message(STATUS "**")
endfunction()
function(gp_file_type original_file file type_var)
if(NOT IS_ABSOLUTE "${original_file}")
message(STATUS "warning: gp_file_type expects absolute full path for first arg original_file")
endif()
get_filename_component(exepath "${original_file}" PATH)
set(type "")
gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "" type)
set(${type_var} "${type}" PARENT_SCOPE)
endfunction()
function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs)
set(verbose 0)
set(eol_char "E")
if(NOT IS_ABSOLUTE "${target}")
message("warning: target '${target}' is not absolute...")
endif()
if(NOT EXISTS "${target}")
message("warning: target '${target}' does not exist...")
endif()
set(gp_cmd_paths ${gp_cmd_paths}
"C:/Program Files/Microsoft Visual Studio 9.0/VC/bin"
"C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin"
"C:/Program Files/Microsoft Visual Studio 8/VC/BIN"
"C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN"
"C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN"
"C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN"
"/usr/local/bin"
"/usr/bin"
)
# <setup-gp_tool-vars>
#
# Try to choose the right tool by default. Caller can set gp_tool prior to
# calling this function to force using a different tool.
#
if("${gp_tool}" STREQUAL "")
set(gp_tool "ldd")
if(APPLE)
set(gp_tool "otool")
endif()
if(WIN32 AND NOT UNIX) # This is how to check for cygwin, har!
find_program(gp_dumpbin "dumpbin" PATHS ${gp_cmd_paths})
if(gp_dumpbin)
set(gp_tool "dumpbin")
else() # Try harder. Maybe we're on MinGW
set(gp_tool "objdump")
endif()
endif()
endif()
find_program(gp_cmd ${gp_tool} PATHS ${gp_cmd_paths})
if(NOT gp_cmd)
message(FATAL_ERROR "FATAL ERROR: could not find '${gp_tool}' - cannot analyze prerequisites!")
return()
endif()
set(gp_tool_known 0)
if("${gp_tool}" STREQUAL "ldd")
set(gp_cmd_args "")
set(gp_regex "^[\t ]*[^\t ]+ => ([^\t\(]+) .*${eol_char}$")
set(gp_regex_error "not found${eol_char}$")
set(gp_regex_fallback "^[\t ]*([^\t ]+) => ([^\t ]+).*${eol_char}$")
set(gp_regex_cmp_count 1)
set(gp_tool_known 1)
endif()
if("${gp_tool}" STREQUAL "otool")
set(gp_cmd_args "-L")
set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$")
set(gp_regex_error "")
set(gp_regex_fallback "")
set(gp_regex_cmp_count 3)
set(gp_tool_known 1)
endif()
if("${gp_tool}" STREQUAL "dumpbin")
set(gp_cmd_args "/dependents")
set(gp_regex "^ ([^ ].*[Dd][Ll][Ll])${eol_char}$")
set(gp_regex_error "")
set(gp_regex_fallback "")
set(gp_regex_cmp_count 1)
set(gp_tool_known 1)
endif()
if("${gp_tool}" STREQUAL "objdump")
set(gp_cmd_args "-p")
set(gp_regex "^\t*DLL Name: (.*\\.[Dd][Ll][Ll])${eol_char}$")
set(gp_regex_error "")
set(gp_regex_fallback "")
set(gp_regex_cmp_count 1)
set(gp_tool_known 1)
endif()
if(NOT gp_tool_known)
message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...")
message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'")
message(STATUS "Valid gp_tool values are dumpbin, ldd, objdump and otool.")
return()
endif()
if("${gp_tool}" STREQUAL "dumpbin")
# When running dumpbin, it also needs the "Common7/IDE" directory in the
# PATH. It will already be in the PATH if being run from a Visual Studio
# command prompt. Add it to the PATH here in case we are running from a
# different command prompt.
#
get_filename_component(gp_cmd_dir "${gp_cmd}" PATH)
get_filename_component(gp_cmd_dlls_dir "${gp_cmd_dir}/../../Common7/IDE" ABSOLUTE)
# Use cmake paths as a user may have a PATH element ending with a backslash.
# This will escape the list delimiter and create havoc!
if(EXISTS "${gp_cmd_dlls_dir}")
# only add to the path if it is not already in the path
set(gp_found_cmd_dlls_dir 0)
file(TO_CMAKE_PATH "$ENV{PATH}" env_path)
foreach(gp_env_path_element ${env_path})
if("${gp_env_path_element}" STREQUAL "${gp_cmd_dlls_dir}")
set(gp_found_cmd_dlls_dir 1)
endif()
endforeach()
if(NOT gp_found_cmd_dlls_dir)
file(TO_NATIVE_PATH "${gp_cmd_dlls_dir}" gp_cmd_dlls_dir)
set(ENV{PATH} "$ENV{PATH};${gp_cmd_dlls_dir}")
endif()
endif()
endif()
#
# </setup-gp_tool-vars>
if("${gp_tool}" STREQUAL "ldd")
set(old_ld_env "$ENV{LD_LIBRARY_PATH}")
foreach(dir ${exepath} ${dirs})
set(ENV{LD_LIBRARY_PATH} "${dir}:$ENV{LD_LIBRARY_PATH}")
endforeach()
endif()
# Track new prerequisites at each new level of recursion. Start with an
# empty list at each level:
#
set(unseen_prereqs)
# Run gp_cmd on the target:
#
execute_process(
COMMAND ${gp_cmd} ${gp_cmd_args} ${target}
OUTPUT_VARIABLE gp_cmd_ov
)
if("${gp_tool}" STREQUAL "ldd")
set(ENV{LD_LIBRARY_PATH} "${old_ld_env}")
endif()
if(verbose)
message(STATUS "<RawOutput cmd='${gp_cmd} ${gp_cmd_args} ${target}'>")
message(STATUS "gp_cmd_ov='${gp_cmd_ov}'")
message(STATUS "</RawOutput>")
endif()
get_filename_component(target_dir "${target}" PATH)
# Convert to a list of lines:
#
string(REGEX REPLACE ";" "\\\\;" candidates "${gp_cmd_ov}")
string(REGEX REPLACE "\n" "${eol_char};" candidates "${candidates}")
# check for install id and remove it from list, since otool -L can include a
# reference to itself
set(gp_install_id)
if("${gp_tool}" STREQUAL "otool")
execute_process(
COMMAND otool -D ${target}
OUTPUT_VARIABLE gp_install_id_ov
)
# second line is install name
string(REGEX REPLACE ".*:\n" "" gp_install_id "${gp_install_id_ov}")
if(gp_install_id)
# trim
string(REGEX MATCH "[^\n ].*[^\n ]" gp_install_id "${gp_install_id}")
#message("INSTALL ID is \"${gp_install_id}\"")
endif()
endif()
# Analyze each line for file names that match the regular expression:
#
foreach(candidate ${candidates})
if("${candidate}" MATCHES "${gp_regex}")
# Extract information from each candidate:
if(gp_regex_error AND "${candidate}" MATCHES "${gp_regex_error}")
string(REGEX REPLACE "${gp_regex_fallback}" "\\1" raw_item "${candidate}")
else()
string(REGEX REPLACE "${gp_regex}" "\\1" raw_item "${candidate}")
endif()
if(gp_regex_cmp_count GREATER 1)
string(REGEX REPLACE "${gp_regex}" "\\2" raw_compat_version "${candidate}")
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" compat_major_version "${raw_compat_version}")
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" compat_minor_version "${raw_compat_version}")
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" compat_patch_version "${raw_compat_version}")
endif()
if(gp_regex_cmp_count GREATER 2)
string(REGEX REPLACE "${gp_regex}" "\\3" raw_current_version "${candidate}")
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" current_major_version "${raw_current_version}")
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" current_minor_version "${raw_current_version}")
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" current_patch_version "${raw_current_version}")
endif()
# Use the raw_item as the list entries returned by this function. Use the
# gp_resolve_item function to resolve it to an actual full path file if
# necessary.
#
set(item "${raw_item}")
# Add each item unless it is excluded:
#
set(add_item 1)
if("${item}" STREQUAL "${gp_install_id}")
set(add_item 0)
endif()
if(add_item AND ${exclude_system})
set(type "")
gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type)
if("${type}" STREQUAL "system")
set(add_item 0)
endif()
endif()
if(add_item)
list(LENGTH ${prerequisites_var} list_length_before_append)
gp_append_unique(${prerequisites_var} "${item}")
list(LENGTH ${prerequisites_var} list_length_after_append)
if(${recurse})
# If item was really added, this is the first time we have seen it.
# Add it to unseen_prereqs so that we can recursively add *its*
# prerequisites...
#
# But first: resolve its name to an absolute full path name such
# that the analysis tools can simply accept it as input.
#
if(NOT list_length_before_append EQUAL list_length_after_append)
gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item)
set(unseen_prereqs ${unseen_prereqs} "${resolved_item}")
endif()
endif()
endif()
else()
if(verbose)
message(STATUS "ignoring non-matching line: '${candidate}'")
endif()
endif()
endforeach()
list(LENGTH ${prerequisites_var} prerequisites_var_length)
if(prerequisites_var_length GREATER 0)
list(SORT ${prerequisites_var})
endif()
if(${recurse})
set(more_inputs ${unseen_prereqs})
foreach(input ${more_inputs})
get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}")
endforeach()
endif()
set(${prerequisites_var} ${${prerequisites_var}} PARENT_SCOPE)
endfunction()
function(list_prerequisites target)
if("${ARGV1}" STREQUAL "")
set(all 1)
else()
set(all "${ARGV1}")
endif()
if("${ARGV2}" STREQUAL "")
set(exclude_system 0)
else()
set(exclude_system "${ARGV2}")
endif()
if("${ARGV3}" STREQUAL "")
set(verbose 0)
else()
set(verbose "${ARGV3}")
endif()
set(count 0)
set(count_str "")
set(print_count "${verbose}")
set(print_prerequisite_type "${verbose}")
set(print_target "${verbose}")
set(type_str "")
get_filename_component(exepath "${target}" PATH)
set(prereqs "")
get_prerequisites("${target}" prereqs ${exclude_system} ${all} "${exepath}" "")
if(print_target)
message(STATUS "File '${target}' depends on:")
endif()
foreach(d ${prereqs})
math(EXPR count "${count} + 1")
if(print_count)
set(count_str "${count}. ")
endif()
if(print_prerequisite_type)
gp_file_type("${target}" "${d}" type)
set(type_str " (${type})")
endif()
message(STATUS "${count_str}${d}${type_str}")
endforeach()
endfunction()
function(list_prerequisites_by_glob glob_arg glob_exp)
message(STATUS "=============================================================================")
message(STATUS "List prerequisites of executables matching ${glob_arg} '${glob_exp}'")
message(STATUS "")
file(${glob_arg} file_list ${glob_exp})
foreach(f ${file_list})
is_file_executable("${f}" is_f_executable)
if(is_f_executable)
message(STATUS "=============================================================================")
list_prerequisites("${f}" ${ARGN})
message(STATUS "")
endif()
endforeach()
endfunction()

37
cmake/GitFunctions.cmake Normal file
View File

@@ -0,0 +1,37 @@
if(__GITFUNCTIONS_CMAKE__)
return()
endif()
set(__GITFUNCTIONS_CMAKE__ TRUE)
find_package(Git QUIET)
include(CMakeParseArguments)
if(GIT_FOUND)
function(git_run)
set(oneValueArgs OUTPUT_VAR DEFAULT)
set(multiValueArgs COMMAND)
cmake_parse_arguments(GIT_RUN "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
execute_process(COMMAND ${GIT_EXECUTABLE} ${GIT_RUN_COMMAND}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
RESULT_VARIABLE GIT_RESULTVAR
OUTPUT_VARIABLE GIT_OUTVAR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(GIT_RESULTVAR EQUAL 0)
set(${GIT_RUN_OUTPUT_VAR} "${GIT_OUTVAR}" PARENT_SCOPE)
else()
set(${GIT_RUN_OUTPUT_VAR} ${GIT_RUN_DEFAULT})
message(STATUS "Failed to run Git: ${GIT_OUTVAR}")
endif()
endfunction()
else()
function(git_run)
set(oneValueArgs OUTPUT_VAR DEFAULT)
set(multiValueArgs COMMAND)
cmake_parse_arguments(GIT_RUN "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
set(${GIT_RUN_OUTPUT_VAR} ${GIT_RUN_DEFAULT})
endfunction(git_run)
endif()

14
cmake/QMakeQuery.cmake Normal file
View File

@@ -0,0 +1,14 @@
if(__QMAKEQUERY_CMAKE__)
return()
endif()
set(__QMAKEQUERY_CMAKE__ TRUE)
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)

13
cmake/UseCXX11.cmake Normal file
View File

@@ -0,0 +1,13 @@
if(__USECXX11_CMAKE__)
return()
endif()
set(__USECXX11_CMAKE__ TRUE)
if(APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -std=c++11")
elseif(UNIX)
# assume GCC, add C++0x/C++11 stuff
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(MINGW)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
endif()

View File

@@ -1,40 +0,0 @@
#pragma once
// Version information
#define VERSION_MAJOR @MultiMC_VERSION_MAJOR@
#define VERSION_MINOR @MultiMC_VERSION_MINOR@
#define VERSION_HOTFIX @MultiMC_VERSION_HOTFIX@
#define VERSION_BUILD @MultiMC_VERSION_BUILD@
#define VERSION_TYPE @MultiMC_VERSION_TYPE@
// The version channel. This is used by the updater to determine what channel the current version came from.
#define VERSION_CHANNEL "@MultiMC_VERSION_CHANNEL@"
// A short string identifying this build's platform. For example, "lin64" or "win32".
#define BUILD_PLATFORM "@MultiMC_BUILD_PLATFORM@"
// URL for the updater's channel
#define CHANLIST_URL "@MultiMC_CHANLIST_URL@"
// URL for notifications
#define NOTIFICATION_URL "@MultiMC_NOTIFICATION_URL@"
// Used for matching notifications
#define FULL_VERSION_STR "@MultiMC_VERSION_MAJOR@.@MultiMC_VERSION_MINOR@.@MultiMC_VERSION_BUILD@"
// enabled for updater dry run
#cmakedefine MultiMC_UPDATER_DRY_RUN
// enabled for updater dry run
#cmakedefine MultiMC_UPDATER_FORCE_LOCAL
// The commit hash of this build
#define GIT_COMMIT "@MultiMC_GIT_COMMIT@"
// This is printed on start to standard output
#define VERSION_STR "@MultiMC_VERSION_STRING@"
// This is used to fetch the news RSS feed.
// It defaults in CMakeLists.txt to "http://multimc.org/rss.xml"
#define NEWS_RSS_URL "@MultiMC_NEWS_RSS_URL@"

View File

@@ -1,33 +0,0 @@
cmake_minimum_required(VERSION 2.8.9)
message(STATUS "Running install script...")
SET(Qt5_DIR @Qt5_DIR@)
IF(WIN32)
SET(LIB_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})
ELSE()
SET(LIB_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/lib)
ENDIF()
INCLUDE(GetPrerequisites)
GET_PREREQUISITES(@BINARY_LOCATION@ MULTIMC_PREREQS 1 1 "" "")
message(STATUS "Prerequisites: ${MULTIMC_PREREQS}")
FOREACH(PREREQ ${MULTIMC_PREREQS})
GET_FILENAME_COMPONENT(PREREQ_NAME "${PREREQ}" NAME)
GET_FILENAME_COMPONENT(PREREQ_ACTUAL "${PREREQ}" REALPATH)
IF(WIN32)
SET(PREREQ_ACTUAL "${Qt5_DIR}/bin/${PREREQ}")
ENDIF()
message(STATUS "Adding install prerequisite: ${PREREQ_NAME}")
FILE(INSTALL
DESTINATION "${LIB_INSTALL_PREFIX}"
TYPE PROGRAM
RENAME "${PREREQ_NAME}"
FILES "${PREREQ_ACTUAL}"
)
ENDFOREACH()

View File

@@ -0,0 +1,7 @@
project(LogicalGui)
# Set the include dir path.
set(LOGICALGUI_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE)
add_library(LogicalGui STATIC LogicalGui.h)
qt5_use_modules(LogicalGui Core)

View File

@@ -0,0 +1,254 @@
/* Copyright 2013-2014 Jan Dalheimer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <QObject>
#include <QMetaMethod>
#include <QThread>
#include <QCoreApplication>
#include <QSemaphore>
#include <memory>
#if QT_VERSION == QT_VERSION_CHECK(5, 1, 1)
#include <5.1.1/QtCore/private/qobject_p.h>
#elif QT_VERSION == QT_VERSION_CHECK(5, 2, 0)
#include <5.2.0/QtCore/private/qobject_p.h>
#elif QT_VERSION == QT_VERSION_CHECK(5, 2, 1)
#include <5.2.1/QtCore/private/qobject_p.h>
#elif QT_VERSION == QT_VERSION_CHECK(5, 3, 0)
#include <5.3.0/QtCore/private/qobject_p.h>
#elif QT_VERSION == QT_VERSION_CHECK(5, 3, 1)
#include <5.3.1/QtCore/private/qobject_p.h>
#else
#error Please add support for this version of Qt
#endif
class Bindable
{
friend class tst_LogicalGui;
public:
Bindable(Bindable *parent = 0) : m_parent(parent)
{
}
virtual ~Bindable()
{
}
void setBindableParent(Bindable *parent)
{
m_parent = parent;
}
void bind(const QString &id, const QObject *receiver, const char *methodSignature)
{
auto mo = receiver->metaObject();
Q_ASSERT_X(mo, "Bindable::bind",
"Invalid metaobject. Did you forget the QObject macro?");
const QMetaMethod method = mo->method(mo->indexOfMethod(
QMetaObject::normalizedSignature(methodSignature + 1).constData()));
Q_ASSERT_X(method.isValid(), "Bindable::bind", "Invalid method signature");
m_bindings.insert(id, Binding(receiver, method));
}
template <typename Func>
void bind(const QString &id,
const typename QtPrivate::FunctionPointer<Func>::Object *receiver, Func slot)
{
typedef QtPrivate::FunctionPointer<Func> SlotType;
m_bindings.insert(
id,
Binding(receiver, new QtPrivate::QSlotObject<Func, typename SlotType::Arguments,
typename SlotType::ReturnType>(slot)));
}
template <typename Func> void bind(const QString &id, Func slot)
{
typedef QtPrivate::FunctionPointer<Func> SlotType;
m_bindings.insert(
id,
Binding(nullptr, new QtPrivate::QSlotObject<Func, typename SlotType::Arguments,
typename SlotType::ReturnType>(slot)));
}
void unbind(const QString &id)
{
m_bindings.remove(id);
}
private:
struct Binding
{
Binding(const QObject *receiver, const QMetaMethod &method)
: receiver(receiver), method(method)
{
}
Binding(const QObject *receiver, QtPrivate::QSlotObjectBase *object)
: receiver(receiver), object(object)
{
}
Binding()
{
}
const QObject *receiver;
QMetaMethod method;
QtPrivate::QSlotObjectBase *object = nullptr;
};
QMap<QString, Binding> m_bindings;
Bindable *m_parent;
private:
inline Qt::ConnectionType connectionType(const QObject *receiver)
{
return receiver == nullptr ? Qt::DirectConnection
: (QThread::currentThread() == receiver->thread()
? Qt::DirectConnection
: Qt::BlockingQueuedConnection);
}
protected:
template <typename Ret, typename... Params> Ret wait(const QString &id, Params... params)
{
static_assert(!std::is_same<Ret, void>::value, "You need to use Bindable::waitVoid");
if (!m_bindings.contains(id) && m_parent)
{
return m_parent->wait<Ret, Params...>(id, params...);
}
Q_ASSERT(m_bindings.contains(id));
const auto binding = m_bindings[id];
const Qt::ConnectionType type = connectionType(binding.receiver);
Ret ret;
if (binding.object)
{
void *args[] = {&ret,
const_cast<void *>(reinterpret_cast<const void *>(&params))...};
if (type == Qt::BlockingQueuedConnection)
{
QSemaphore semaphore;
QMetaCallEvent *ev =
new QMetaCallEvent(binding.object, nullptr, -1, 0, 0, args, &semaphore);
QCoreApplication::postEvent(const_cast<QObject *>(binding.receiver), ev);
semaphore.acquire();
}
else
{
binding.object->call(const_cast<QObject *>(binding.receiver), args);
}
}
else
{
const QMetaMethod method = binding.method;
Q_ASSERT_X(method.parameterCount() == sizeof...(params), "Bindable::wait",
qPrintable(QString("Incompatible argument count (expected %1, got %2)")
.arg(method.parameterCount(), sizeof...(params))));
Q_ASSERT_X(
qMetaTypeId<Ret>() != QMetaType::UnknownType, "Bindable::wait",
"Requested return type is not registered, please use the Q_DECLARE_METATYPE "
"macro to make it known to Qt's meta-object system");
Q_ASSERT_X(
method.returnType() == qMetaTypeId<Ret>() ||
QMetaType::hasRegisteredConverterFunction(method.returnType(),
qMetaTypeId<Ret>()),
"Bindable::wait",
qPrintable(
QString(
"Requested return type (%1) is incompatible method return type (%2)")
.arg(QMetaType::typeName(qMetaTypeId<Ret>()),
QMetaType::typeName(method.returnType()))));
const auto retArg = QReturnArgument<Ret>(
QMetaType::typeName(qMetaTypeId<Ret>()),
ret); // because Q_RETURN_ARG doesn't work with templates...
method.invoke(const_cast<QObject *>(binding.receiver), type, retArg,
Q_ARG(Params, params)...);
}
return ret;
}
template <typename... Params>
typename std::enable_if<sizeof...(Params) != 0, void>::type waitVoid(const QString &id,
Params... params)
{
if (!m_bindings.contains(id) && m_parent)
{
m_parent->waitVoid<Params...>(id, params...);
return;
}
Q_ASSERT(m_bindings.contains(id));
const auto binding = m_bindings[id];
const Qt::ConnectionType type = connectionType(binding.receiver);
if (binding.object)
{
void *args[] = {0, const_cast<void *>(reinterpret_cast<const void *>(&params))...};
if (type == Qt::BlockingQueuedConnection)
{
QSemaphore semaphore;
QMetaCallEvent *ev =
new QMetaCallEvent(binding.object, nullptr, -1, 0, 0, args, &semaphore);
QCoreApplication::postEvent(const_cast<QObject *>(binding.receiver), ev);
semaphore.acquire();
}
else
{
binding.object->call(const_cast<QObject *>(binding.receiver), args);
}
}
else
{
const QMetaMethod method = binding.method;
Q_ASSERT_X(method.parameterCount() == sizeof...(params), "Bindable::wait",
qPrintable(QString("Incompatible argument count (expected %1, got %2)")
.arg(method.parameterCount(), sizeof...(params))));
method.invoke(const_cast<QObject *>(binding.receiver), type,
Q_ARG(Params, params)...);
}
}
void waitVoid(const QString &id)
{
if (!m_bindings.contains(id) && m_parent)
{
m_parent->waitVoid(id);
return;
}
Q_ASSERT(m_bindings.contains(id));
const auto binding = m_bindings[id];
const Qt::ConnectionType type = connectionType(binding.receiver);
if (binding.object)
{
void *args[] = {0};
if (type == Qt::BlockingQueuedConnection)
{
QSemaphore semaphore;
QMetaCallEvent *ev =
new QMetaCallEvent(binding.object, nullptr, -1, 0, 0, args, &semaphore);
QCoreApplication::postEvent(const_cast<QObject *>(binding.receiver), ev);
semaphore.acquire();
}
else
{
binding.object->call(const_cast<QObject *>(binding.receiver), args);
}
}
else
{
const QMetaMethod method = binding.method;
Q_ASSERT_X(method.parameterCount() == 0, "Bindable::wait",
qPrintable(QString("Incompatible argument count (expected %1, got %2)")
.arg(method.parameterCount(), 0)));
method.invoke(const_cast<QObject *>(binding.receiver), type);
}
}
};
// used frequently
Q_DECLARE_METATYPE(bool *)

View File

@@ -8,7 +8,7 @@ find_package(Qt5Core REQUIRED)
# Include Qt headers.
include_directories(${Qt5Base_INCLUDE_DIRS})
SET(CLASSPARSER_HEADERS
set(CLASSPARSER_HEADERS
include/classparser_config.h
# Public headers
@@ -23,13 +23,13 @@ src/javaendian.h
src/membuffer.h
)
SET(CLASSPARSER_SOURCES
set(CLASSPARSER_SOURCES
src/javautils.cpp
src/annotations.cpp
)
# Set the include dir path.
SET(LIBGROUPVIEW_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE)
set(LIBGROUPVIEW_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE)
# Include self.
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)

View File

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

View File

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

View File

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

View File

@@ -1,46 +0,0 @@
project(libGroupView)
set(CMAKE_AUTOMOC ON)
# Find Qt
find_package(Qt5Core REQUIRED)
find_package(Qt5Widgets REQUIRED)
# Include Qt headers.
include_directories(${Qt5Base_INCLUDE_DIRS})
SET(LIBGROUPVIEW_HEADERS
include/groupview_config.h
# Public headers
include/categorizedsortfilterproxymodel.h
include/categorizedview.h
include/categorydrawer.h
# Private headers
src/categorizedsortfilterproxymodel_p.h
src/categorizedview_p.h
)
SET(LIBGROUPVIEW_SOURCES
src/categorizedsortfilterproxymodel.cpp
src/categorizedview.cpp
src/categorydrawer.cpp
)
# Set the include dir path.
SET(LIBGROUPVIEW_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE)
# Include self.
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
include_directories(${CMAKE_BINARY_DIR}/include)
# Static link!
ADD_DEFINITIONS(-DLIBGROUPVIEW_STATIC)
add_definitions(-DLIBGROUPVIEW_LIBRARY)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
add_library(libGroupView STATIC ${LIBGROUPVIEW_SOURCES} ${LIBGROUPVIEW_HEADERS})
qt5_use_modules(libGroupView Core Widgets)

View File

@@ -1,175 +0,0 @@
/*
* This file is part of the KDE project
* Copyright (C) 2007 Rafael Fernández López <ereslibre@kde.org>
* Copyright (C) 2007 John Tapsell <tapsell@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef KCATEGORIZEDSORTFILTERPROXYMODEL_H
#define KCATEGORIZEDSORTFILTERPROXYMODEL_H
#include <QSortFilterProxyModel>
#include <groupview_config.h>
class QItemSelection;
/**
* This class lets you categorize a view. It is meant to be used along with
* KCategorizedView class.
*
* In general terms all you need to do is to reimplement subSortLessThan() and
* compareCategories() methods. In order to make categorization work, you need
* to also call setCategorizedModel() class to enable it, since the categorization
* is disabled by default.
*
* @see KCategorizedView
*
* @author Rafael Fernández López <ereslibre@kde.org>
*/
class LIBGROUPVIEW_EXPORT KCategorizedSortFilterProxyModel
: public QSortFilterProxyModel
{
public:
enum AdditionalRoles
{
// Note: use printf "0x%08X\n" $(($RANDOM*$RANDOM))
// to define additional roles.
CategoryDisplayRole = 0x17CE990A, ///< This role is used for asking the category to a given index
CategorySortRole = 0x27857E60 ///< This role is used for sorting categories. You can return a
///< string or a long long value. Strings will be sorted alphabetically
///< while long long will be sorted by their value. Please note that this
///< value won't be shown on the view, is only for sorting purposes. What will
///< be shown as "Category" on the view will be asked with the role
///< CategoryDisplayRole.
};
KCategorizedSortFilterProxyModel ( QObject *parent = 0 );
virtual ~KCategorizedSortFilterProxyModel();
/**
* Overridden from QSortFilterProxyModel. Sorts the source model using
* @p column for the given @p order.
*/
virtual void sort ( int column, Qt::SortOrder order = Qt::AscendingOrder );
/**
* @return whether the model is categorized or not. Disabled by default.
*/
bool isCategorizedModel() const;
/**
* Enables or disables the categorization feature.
*
* @param categorizedModel whether to enable or disable the categorization feature.
*/
void setCategorizedModel ( bool categorizedModel );
/**
* @return the column being used for sorting.
*/
int sortColumn() const;
/**
* @return the sort order being used for sorting.
*/
Qt::SortOrder sortOrder() const;
/**
* Set if the sorting using CategorySortRole will use a natural comparison
* in the case that strings were returned. If enabled, QString::localeAwareCompare
* will be used for sorting.
*
* @param sortCategoriesByNaturalComparison whether to sort using a natural comparison or not.
*/
void setSortCategoriesByNaturalComparison ( bool sortCategoriesByNaturalComparison );
/**
* @return whether it is being used a natural comparison for sorting. Enabled by default.
*/
bool sortCategoriesByNaturalComparison() const;
protected:
/**
* Overridden from QSortFilterProxyModel. If you are subclassing
* KCategorizedSortFilterProxyModel, you will probably not need to reimplement this
* method.
*
* It calls compareCategories() to sort by category. If the both items are in the
* same category (i.e. compareCategories returns 0), then subSortLessThan is called.
*
* @return Returns true if the item @p left is less than the item @p right when sorting.
*
* @warning You usually won't need to reimplement this method when subclassing
* from KCategorizedSortFilterProxyModel.
*/
virtual bool lessThan ( const QModelIndex &left, const QModelIndex &right ) const;
/**
* This method has a similar purpose as lessThan() has on QSortFilterProxyModel.
* It is used for sorting items that are in the same category.
*
* @return Returns true if the item @p left is less than the item @p right when sorting.
*/
virtual bool subSortLessThan ( const QModelIndex &left, const QModelIndex &right ) const;
/**
* This method compares the category of the @p left index with the category
* of the @p right index.
*
* Internally and if not reimplemented, this method will ask for @p left and
* @p right models for role CategorySortRole. In order to correctly sort
* categories, the data() metod of the model should return a qlonglong (or numeric) value, or
* a QString object. QString objects will be sorted with QString::localeAwareCompare if
* sortCategoriesByNaturalComparison() is true.
*
* @note Please have present that:
* QString(QChar(QChar::ObjectReplacementCharacter)) >
* QString(QChar(QChar::ReplacementCharacter)) >
* [ all possible strings ] >
* QString();
*
* This means that QString() will be sorted the first one, while
* QString(QChar(QChar::ObjectReplacementCharacter)) and
* QString(QChar(QChar::ReplacementCharacter)) will be sorted in last
* position.
*
* @warning Please note that data() method of the model should return always
* information of the same type. If you return a QString for an index,
* you should return always QStrings for all indexes for role CategorySortRole
* in order to correctly sort categories. You can't mix by returning
* a QString for one index, and a qlonglong for other.
*
* @note If you need a more complex layout, you will have to reimplement this
* method.
*
* @return A negative value if the category of @p left should be placed before the
* category of @p right. 0 if @p left and @p right are on the same category, and
* a positive value if the category of @p left should be placed after the
* category of @p right.
*/
virtual int compareCategories ( const QModelIndex &left, const QModelIndex &right ) const;
private:
class Private;
Private *const d;
};
#endif // KCATEGORIZEDSORTFILTERPROXYMODEL_H

View File

@@ -1,332 +0,0 @@
/**
* This file is part of the KDE project
* Copyright (C) 2007, 2009 Rafael Fernández López <ereslibre@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef KCATEGORIZEDVIEW_H
#define KCATEGORIZEDVIEW_H
#include <QListView>
#include <groupview_config.h>
class KCategoryDrawer;
/**
* @short Item view for listing items in a categorized fashion optionally
*
* KCategorizedView basically has the same functionality as QListView, only that it also lets you
* layout items in a way that they are categorized visually.
*
* For it to work you will need to set a KCategorizedSortFilterProxyModel and a KCategoryDrawer
* with methods setModel() and setCategoryDrawer() respectively. Also, the model will need to be
* flagged as categorized with KCategorizedSortFilterProxyModel::setCategorizedModel(true).
*
* The way it works (if categorization enabled):
*
* - When sorting, it does more things than QListView does. It will ask the model for the
* special role CategorySortRole (@see KCategorizedSortFilterProxyModel). This can return
* a QString or an int in order to tell the view the order of categories. In this sense, for
* instance, if we are sorting by name ascending, "A" would be before than "B". If we are
* sorting by size ascending, 512 bytes would be before 1024 bytes. This way categories are
* also sorted.
*
* - When the view has to paint, it will ask the model with the role CategoryDisplayRole
* (@see KCategorizedSortFilterProxyModel). It will for instance return "F" for "foo.pdf" if
* we are sorting by name ascending, or "Small" if a certain item has 100 bytes, for example.
*
* For drawing categories, KCategoryDrawer will be used. You can inherit this class to do your own
* drawing.
*
* @note All examples cited before talk about filesystems and such, but have present that this
* is a completely generic class, and it can be used for whatever your purpose is. For
* instance when talking about animals, you can separate them by "Mammal" and "Oviparous". In
* this very case, for example, the CategorySortRole and the CategoryDisplayRole could be the
* same ("Mammal" and "Oviparous").
*
* @note There is a really performance boost if CategorySortRole returns an int instead of a QString.
* Have present that this role is asked (n * log n) times when sorting and compared. Comparing
* ints is always faster than comparing strings, whithout mattering how fast the string
* comparison is. Consider thinking of a way of returning ints instead of QStrings if your
* model can contain a high number of items.
*
* @warning Note that for really drawing items in blocks you will need some things to be done:
* - The model set to this view has to be (or inherit if you want to do special stuff
* in it) KCategorizedSortFilterProxyModel.
* - This model needs to be set setCategorizedModel to true.
* - Set a category drawer by calling setCategoryDrawer.
*
* @see KCategorizedSortFilterProxyModel, KCategoryDrawer
*
* @author Rafael Fernández López <ereslibre@kde.org>
*/
class LIBGROUPVIEW_EXPORT KCategorizedView
: public QListView
{
Q_OBJECT
Q_PROPERTY ( int categorySpacing READ categorySpacing WRITE setCategorySpacing )
Q_PROPERTY ( bool alternatingBlockColors READ alternatingBlockColors WRITE setAlternatingBlockColors )
Q_PROPERTY ( bool collapsibleBlocks READ collapsibleBlocks WRITE setCollapsibleBlocks )
public:
KCategorizedView ( QWidget *parent = 0 );
~KCategorizedView();
/**
* Reimplemented from QAbstractItemView.
*/
virtual void setModel ( QAbstractItemModel *model );
/**
* Calls to setGridSizeOwn().
*/
void setGridSize ( const QSize &size );
/**
* @warning note that setGridSize is not virtual in the base class (QListView), so if you are
* calling to this method, make sure you have a KCategorizedView pointer around. This
* means that something like:
* @code
* QListView *lv = new KCategorizedView();
* lv->setGridSize(mySize);
* @endcode
*
* will not call to the expected setGridSize method. Instead do something like this:
*
* @code
* QListView *lv;
* ...
* KCategorizedView *cv = qobject_cast<KCategorizedView*>(lv);
* if (cv) {
* cv->setGridSizeOwn(mySize);
* } else {
* lv->setGridSize(mySize);
* }
* @endcode
*
* @note this method will call to QListView::setGridSize among other operations.
*
* @since 4.4
*/
void setGridSizeOwn ( const QSize &size );
/**
* Reimplemented from QAbstractItemView.
*/
virtual QRect visualRect ( const QModelIndex &index ) const;
/**
* Returns the current category drawer.
*/
KCategoryDrawer *categoryDrawer() const;
/**
* The category drawer that will be used for drawing categories.
*/
void setCategoryDrawer ( KCategoryDrawer *categoryDrawer );
/**
* @return Category spacing. The spacing between categories.
*
* @since 4.4
*/
int categorySpacing() const;
/**
* Stablishes the category spacing. This is the spacing between categories.
*
* @since 4.4
*/
void setCategorySpacing ( int categorySpacing );
/**
* @return Whether blocks should be drawn with alternating colors.
*
* @since 4.4
*/
bool alternatingBlockColors() const;
/**
* Sets whether blocks should be drawn with alternating colors.
*
* @since 4.4
*/
void setAlternatingBlockColors ( bool enable );
/**
* @return Whether blocks can be collapsed or not.
*
* @since 4.4
*/
bool collapsibleBlocks() const;
/**
* Sets whether blocks can be collapsed or not.
*
* @since 4.4
*/
void setCollapsibleBlocks ( bool enable );
/**
* @return Block of indexes that are into @p category.
*
* @since 4.5
*/
QModelIndexList block ( const QString &category );
/**
* @return Block of indexes that are represented by @p representative.
*
* @since 4.5
*/
QModelIndexList block ( const QModelIndex &representative );
/**
* Reimplemented from QAbstractItemView.
*/
virtual QModelIndex indexAt ( const QPoint &point ) const;
/**
* Reimplemented from QAbstractItemView.
*/
virtual void reset();
/**
* Signify that all item delegates size hints return the same fixed size
*/
void setUniformItemWidths(bool enable);
/**
* Do all item delegate size hints return the same fixed size?
*/
bool uniformItemWidths() const;
protected:
/**
* Reimplemented from QWidget.
*/
virtual void paintEvent ( QPaintEvent *event );
/**
* Reimplemented from QWidget.
*/
virtual void resizeEvent ( QResizeEvent *event );
/**
* Reimplemented from QAbstractItemView.
*/
virtual void setSelection ( const QRect &rect,
QItemSelectionModel::SelectionFlags flags );
/**
* Reimplemented from QWidget.
*/
virtual void mouseMoveEvent ( QMouseEvent *event );
/**
* Reimplemented from QWidget.
*/
virtual void mousePressEvent ( QMouseEvent *event );
/**
* Reimplemented from QWidget.
*/
virtual void mouseReleaseEvent ( QMouseEvent *event );
/**
* Reimplemented from QWidget.
*/
virtual void leaveEvent ( QEvent *event );
/**
* Reimplemented from QAbstractItemView.
*/
virtual void startDrag ( Qt::DropActions supportedActions );
/**
* Reimplemented from QAbstractItemView.
*/
virtual void dragMoveEvent ( QDragMoveEvent *event );
/**
* Reimplemented from QAbstractItemView.
*/
virtual void dragEnterEvent ( QDragEnterEvent *event );
/**
* Reimplemented from QAbstractItemView.
*/
virtual void dragLeaveEvent ( QDragLeaveEvent *event );
/**
* Reimplemented from QAbstractItemView.
*/
virtual void dropEvent ( QDropEvent *event );
/**
* Reimplemented from QAbstractItemView.
*/
virtual QModelIndex moveCursor ( CursorAction cursorAction,
Qt::KeyboardModifiers modifiers );
/**
* Reimplemented from QAbstractItemView.
*/
virtual void rowsAboutToBeRemoved ( const QModelIndex &parent,
int start,
int end );
/**
* Reimplemented from QAbstractItemView.
*/
virtual void updateGeometries();
/**
* Reimplemented from QAbstractItemView.
*/
virtual void currentChanged ( const QModelIndex &current,
const QModelIndex &previous );
/**
* Reimplemented from QAbstractItemView.
*/
virtual void dataChanged ( const QModelIndex &topLeft,
const QModelIndex &bottomRight );
/**
* Reimplemented from QAbstractItemView.
*/
virtual void rowsInserted ( const QModelIndex &parent,
int start,
int end );
protected Q_SLOTS:
/**
* @internal
* Reposition items as needed.
*/
virtual void slotLayoutChanged();
virtual void slotCollapseOrExpandClicked ( QModelIndex );
private:
class Private;
Private *const d;
};
#endif // KCATEGORIZEDVIEW_H

View File

@@ -1,179 +0,0 @@
/**
* This file is part of the KDE project
* Copyright (C) 2007, 2009 Rafael Fernández López <ereslibre@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef KCATEGORYDRAWER_H
#define KCATEGORYDRAWER_H
#include <groupview_config.h>
#include <QtCore/QObject>
#include <QtGui/QMouseEvent>
class QPainter;
class QModelIndex;
class QStyleOption;
class KCategorizedView;
/**
* @since 4.5
*/
class LIBGROUPVIEW_EXPORT KCategoryDrawer
: public QObject
{
friend class KCategorizedView;
Q_OBJECT
public:
KCategoryDrawer ( KCategorizedView *view );
virtual ~KCategoryDrawer();
/**
* @return The view this category drawer is associated with.
*/
KCategorizedView *view() const;
/**
* This method purpose is to draw a category represented by the given
* @param index with the given @param sortRole sorting role
*
* @note This method will be called one time per category, always with the
* first element in that category
*/
virtual void drawCategory ( const QModelIndex &index,
int sortRole,
const QStyleOption &option,
QPainter *painter ) const;
/**
* @return The category height for the category representated by index @p index with
* style options @p option.
*/
virtual int categoryHeight ( const QModelIndex &index, const QStyleOption &option ) const;
//TODO KDE5: make virtual as leftMargin
/**
* @note 0 by default
*
* @since 4.4
*/
int leftMargin() const;
/**
* @note call to this method on the KCategoryDrawer constructor to set the left margin
*
* @since 4.4
*/
void setLeftMargin ( int leftMargin );
//TODO KDE5: make virtual as rightMargin
/**
* @note 0 by default
*
* @since 4.4
*/
int rightMargin() const;
/**
* @note call to this method on the KCategoryDrawer constructor to set the right margin
*
* @since 4.4
*/
void setRightMargin ( int rightMargin );
KCategoryDrawer &operator= ( const KCategoryDrawer &cd );
protected:
/**
* Method called when the mouse button has been pressed.
*
* @param index The representative index of the block of items.
* @param blockRect The rect occupied by the block of items.
* @param event The mouse event.
*
* @warning You explicitly have to determine whether the event has been accepted or not. You
* have to call event->accept() or event->ignore() at all possible case branches in
* your code.
*/
virtual void mouseButtonPressed ( const QModelIndex &index, const QRect &blockRect, QMouseEvent *event );
/**
* Method called when the mouse button has been released.
*
* @param index The representative index of the block of items.
* @param blockRect The rect occupied by the block of items.
* @param event The mouse event.
*
* @warning You explicitly have to determine whether the event has been accepted or not. You
* have to call event->accept() or event->ignore() at all possible case branches in
* your code.
*/
virtual void mouseButtonReleased ( const QModelIndex &index, const QRect &blockRect, QMouseEvent *event );
/**
* Method called when the mouse has been moved.
*
* @param index The representative index of the block of items.
* @param blockRect The rect occupied by the block of items.
* @param event The mouse event.
*/
virtual void mouseMoved ( const QModelIndex &index, const QRect &blockRect, QMouseEvent *event );
/**
* Method called when the mouse button has been double clicked.
*
* @param index The representative index of the block of items.
* @param blockRect The rect occupied by the block of items.
* @param event The mouse event.
*
* @warning You explicitly have to determine whether the event has been accepted or not. You
* have to call event->accept() or event->ignore() at all possible case branches in
* your code.
*/
virtual void mouseButtonDoubleClicked ( const QModelIndex &index, const QRect &blockRect, QMouseEvent *event );
/**
* Method called when the mouse button has left this block.
*
* @param index The representative index of the block of items.
* @param blockRect The rect occupied by the block of items.
*/
virtual void mouseLeft ( const QModelIndex &index, const QRect &blockRect );
private:
class Private;
Private *const d;
Q_SIGNALS:
/**
* This signal becomes emitted when collapse or expand has been clicked.
*/
void collapseOrExpandClicked ( const QModelIndex &index );
/**
* Emit this signal on your subclass implementation to notify that something happened. Usually
* this will be triggered when you have received an event, and its position matched some "hot spot".
*
* You give this action the integer you want, and having connected this signal to your code,
* the connected slot can perform the needed changes (view, model, selection model, delegate...)
*/
void actionRequested ( int action, const QModelIndex &index );
};
#endif // KCATEGORYDRAWER_H

View File

@@ -1,168 +0,0 @@
/**
* This file is part of the KDE project
* Copyright (C) 2007 Rafael Fernández López <ereslibre@kde.org>
* Copyright (C) 2007 John Tapsell <tapsell@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "categorizedsortfilterproxymodel.h"
#include "categorizedsortfilterproxymodel_p.h"
#include <limits.h>
#include <QItemSelection>
#include <QStringList>
#include <QSize>
KCategorizedSortFilterProxyModel::KCategorizedSortFilterProxyModel ( QObject *parent )
: QSortFilterProxyModel ( parent )
, d ( new Private() )
{
}
KCategorizedSortFilterProxyModel::~KCategorizedSortFilterProxyModel()
{
delete d;
}
void KCategorizedSortFilterProxyModel::sort ( int column, Qt::SortOrder order )
{
d->sortColumn = column;
d->sortOrder = order;
QSortFilterProxyModel::sort ( column, order );
}
bool KCategorizedSortFilterProxyModel::isCategorizedModel() const
{
return d->categorizedModel;
}
void KCategorizedSortFilterProxyModel::setCategorizedModel ( bool categorizedModel )
{
if ( categorizedModel == d->categorizedModel )
{
return;
}
d->categorizedModel = categorizedModel;
invalidate();
}
int KCategorizedSortFilterProxyModel::sortColumn() const
{
return d->sortColumn;
}
Qt::SortOrder KCategorizedSortFilterProxyModel::sortOrder() const
{
return d->sortOrder;
}
void KCategorizedSortFilterProxyModel::setSortCategoriesByNaturalComparison ( bool sortCategoriesByNaturalComparison )
{
if ( sortCategoriesByNaturalComparison == d->sortCategoriesByNaturalComparison )
{
return;
}
d->sortCategoriesByNaturalComparison = sortCategoriesByNaturalComparison;
invalidate();
}
bool KCategorizedSortFilterProxyModel::sortCategoriesByNaturalComparison() const
{
return d->sortCategoriesByNaturalComparison;
}
bool KCategorizedSortFilterProxyModel::lessThan ( const QModelIndex &left, const QModelIndex &right ) const
{
if ( d->categorizedModel )
{
int compare = compareCategories ( left, right );
if ( compare > 0 ) // left is greater than right
{
return false;
}
else if ( compare < 0 ) // left is less than right
{
return true;
}
}
return subSortLessThan ( left, right );
}
bool KCategorizedSortFilterProxyModel::subSortLessThan ( const QModelIndex &left, const QModelIndex &right ) const
{
return QSortFilterProxyModel::lessThan ( left, right );
}
int KCategorizedSortFilterProxyModel::compareCategories ( const QModelIndex &left, const QModelIndex &right ) const
{
QVariant l = ( left.model() ? left.model()->data ( left, CategorySortRole ) : QVariant() );
QVariant r = ( right.model() ? right.model()->data ( right, CategorySortRole ) : QVariant() );
Q_ASSERT ( l.isValid() );
Q_ASSERT ( r.isValid() );
Q_ASSERT ( l.type() == r.type() );
if ( l.type() == QVariant::String )
{
QString lstr = l.toString();
QString rstr = r.toString();
/*
if ( d->sortCategoriesByNaturalComparison )
{
return KStringHandler::naturalCompare ( lstr, rstr );
}
else
{
*/
if ( lstr < rstr )
{
return -1;
}
if ( lstr > rstr )
{
return 1;
}
return 0;
//}
}
qlonglong lint = l.toLongLong();
qlonglong rint = r.toLongLong();
if ( lint < rint )
{
return -1;
}
if ( lint > rint )
{
return 1;
}
return 0;
}

View File

@@ -1,48 +0,0 @@
/**
* This file is part of the KDE project
* Copyright (C) 2007 Rafael Fernández López <ereslibre@kde.org>
* Copyright (C) 2007 John Tapsell <tapsell@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef KCATEGORIZEDSORTFILTERPROXYMODEL_P_H
#define KCATEGORIZEDSORTFILTERPROXYMODEL_P_H
class KCategorizedSortFilterProxyModel;
class KCategorizedSortFilterProxyModel::Private
{
public:
Private()
: sortColumn ( 0 )
, sortOrder ( Qt::AscendingOrder )
, categorizedModel ( false )
, sortCategoriesByNaturalComparison ( true )
{
}
~Private()
{
}
int sortColumn;
Qt::SortOrder sortOrder;
bool categorizedModel;
bool sortCategoriesByNaturalComparison;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,160 +0,0 @@
/**
* This file is part of the KDE project
* Copyright (C) 2007, 2009 Rafael Fernández López <ereslibre@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef KCATEGORIZEDVIEW_P_H
#define KCATEGORIZEDVIEW_P_H
class KCategorizedSortFilterProxyModel;
class KCategoryDrawer;
class KCategoryDrawerV2;
class KCategoryDrawerV3;
/**
* @internal
*/
class KCategorizedView::Private
{
public:
struct Block;
struct Item;
Private(KCategorizedView *q);
~Private();
/**
* @return whether this view has all required elements to be categorized.
*/
bool isCategorized() const;
/**
* @return the block rect for the representative @p representative.
*/
QStyleOptionViewItemV4 blockRect(const QModelIndex &representative);
/**
* Returns the first and last element that intersects with rect.
*
* @note see that here we cannot take out items between first and last (as we could
* do with the rubberband).
*
* Complexity: O(log(n)) where n is model()->rowCount().
*/
QPair<QModelIndex, QModelIndex> intersectingIndexesWithRect(const QRect &rect) const;
/**
* Returns the position of the block of @p category.
*
* Complexity: O(n) where n is the number of different categories when the block has been
* marked as in quarantine. O(1) the rest of the times (the vast majority).
*/
QPoint blockPosition(const QString &category);
/**
* Returns the height of the block determined by @p category.
*/
int blockHeight(const QString &category);
/**
* Returns the actual viewport width.
*/
int viewportWidth() const;
/**
* Marks all elements as in quarantine.
*
* Complexity: O(n) where n is model()->rowCount().
*
* @warning this is an expensive operation
*/
void regenerateAllElements();
/**
* Update internal information, and keep sync with the real information that the model contains.
*/
void rowsInserted(const QModelIndex &parent, int start, int end);
/**
* Returns @p rect in viewport terms, taking in count horizontal and vertical offsets.
*/
QRect mapToViewport(const QRect &rect) const;
/**
* Returns @p rect in absolute terms, converted from viewport position.
*/
QRect mapFromViewport(const QRect &rect) const;
/**
* Returns the height of the highest element in last row. This is only applicable if there is
* no grid set and uniformItemSizes is false.
*
* @param block in which block are we searching. Necessary to stop the search if we hit the
* first item in this block.
*/
int highestElementInLastRow(const Block &block) const;
/**
* Returns whether the view has a valid grid size.
*/
bool hasGrid() const;
/**
* Returns the category for the given index.
*/
QString categoryForIndex(const QModelIndex &index) const;
/**
* Updates the visual rect for item when flow is LeftToRight.
*/
void leftToRightVisualRect(const QModelIndex &index, Item &item,
const Block &block, const QPoint &blockPos) const;
/**
* Updates the visual rect for item when flow is TopToBottom.
* @note we only support viewMode == ListMode in this case.
*/
void topToBottomVisualRect(const QModelIndex &index, Item &item,
const Block &block, const QPoint &blockPos) const;
/**
* Called when expand or collapse has been clicked on the category drawer.
*/
void _k_slotCollapseOrExpandClicked(QModelIndex);
KCategorizedView *q = nullptr;
KCategorizedSortFilterProxyModel *proxyModel = nullptr;
KCategoryDrawer *categoryDrawer = nullptr;
int categorySpacing = 5;
bool alternatingBlockColors = false;
bool collapsibleBlocks = false;
bool constantItemWidth = false;
// FIXME: this is some really weird logic. Investigate.
Block *hoveredBlock;
QString hoveredCategory;
QModelIndex hoveredIndex;
QPoint pressedPosition;
QRect rubberBandRect;
QHash<QString, Block> blocks;
};
#endif // KCATEGORIZEDVIEW_P_H

View File

@@ -1,231 +0,0 @@
/**
* This file is part of the KDE project
* Copyright (C) 2007, 2009 Rafael Fernández López <ereslibre@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "categorydrawer.h"
#include <QPainter>
#include <QStyleOption>
#include <QApplication>
#include <categorizedview.h>
#include <categorizedsortfilterproxymodel.h>
#define HORIZONTAL_HINT 3
class KCategoryDrawer::Private
{
public:
Private(KCategorizedView *view)
: view(view)
, leftMargin(0)
, rightMargin(0)
{
}
~Private()
{
}
KCategorizedView *view;
int leftMargin;
int rightMargin;
};
KCategoryDrawer::KCategoryDrawer(KCategorizedView *view)
: QObject(view)
, d(new Private(view))
{
setLeftMargin(2);
setRightMargin(2);
}
KCategoryDrawer::~KCategoryDrawer()
{
delete d;
}
void KCategoryDrawer::drawCategory(const QModelIndex &index,
int /*sortRole*/,
const QStyleOption &option,
QPainter *painter) const
{
painter->setRenderHint(QPainter::Antialiasing);
const QString category = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
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: text
{
QRect textRect(option.rect);
textRect.setTop(textRect.top() + 7);
textRect.setLeft(textRect.left() + 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, category);
painter->restore();
}
//END: text
}
int KCategoryDrawer::categoryHeight(const QModelIndex &index, const QStyleOption &option) const
{
Q_UNUSED(index);
Q_UNUSED(option)
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 KCategoryDrawer::leftMargin() const
{
return d->leftMargin;
}
void KCategoryDrawer::setLeftMargin(int leftMargin)
{
d->leftMargin = leftMargin;
}
int KCategoryDrawer::rightMargin() const
{
return d->rightMargin;
}
void KCategoryDrawer::setRightMargin(int rightMargin)
{
d->rightMargin = rightMargin;
}
KCategoryDrawer &KCategoryDrawer::operator=(const KCategoryDrawer &cd)
{
d->leftMargin = cd.d->leftMargin;
d->rightMargin = cd.d->rightMargin;
d->view = cd.d->view;
return *this;
}
KCategorizedView *KCategoryDrawer::view() const
{
return d->view;
}
void KCategoryDrawer::mouseButtonPressed(const QModelIndex&, const QRect&, QMouseEvent *event)
{
event->ignore();
}
void KCategoryDrawer::mouseButtonReleased(const QModelIndex&, const QRect&, QMouseEvent *event)
{
event->ignore();
}
void KCategoryDrawer::mouseMoved(const QModelIndex&, const QRect&, QMouseEvent *event)
{
event->ignore();
}
void KCategoryDrawer::mouseButtonDoubleClicked(const QModelIndex&, const QRect&, QMouseEvent *event)
{
event->ignore();
}
void KCategoryDrawer::mouseLeft(const QModelIndex&, const QRect&)
{
}
#include "categorydrawer.moc"

6
depends/javacheck/.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
.idea
*.iml
out
.classpath
.idea
.project

View File

@@ -7,9 +7,9 @@ set(CMAKE_JAVA_JAR_ENTRY_POINT JavaCheck)
set(CMAKE_JAVA_COMPILE_FLAGS -target 1.6 -source 1.6 -Xlint:deprecation -Xlint:unchecked)
set(SRC
JavaCheck.java
JavaCheck.java
)
add_jar(JavaCheck ${SRC})
INSTALL_JAR(JavaCheck "${BINARY_DEST_DIR}/jars")
install_jar(JavaCheck "${BINARY_DEST_DIR}/jars")

6
depends/launcher/.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
.idea
*.iml
out
.classpath
.idea
.project

View File

@@ -3,20 +3,33 @@ project(launcher Java)
find_package(Java 1.6 REQUIRED COMPONENTS Development)
include(UseJava)
set(CMAKE_JAVA_JAR_ENTRY_POINT MultiMCLauncher)
set(CMAKE_JAVA_JAR_ENTRY_POINT org.multimc.EntryPoint)
set(CMAKE_JAVA_COMPILE_FLAGS -target 1.6 -source 1.6 -Xlint:deprecation -Xlint:unchecked)
set(SRC
MultiMCLauncher.java
org/simplericity/macify/eawt/Application.java
org/simplericity/macify/eawt/ApplicationAdapter.java
org/simplericity/macify/eawt/ApplicationEvent.java
org/simplericity/macify/eawt/ApplicationListener.java
org/simplericity/macify/eawt/DefaultApplication.java
net/minecraft/Launcher.java
MCFrame.java
# OSX things
org/simplericity/macify/eawt/Application.java
org/simplericity/macify/eawt/ApplicationAdapter.java
org/simplericity/macify/eawt/ApplicationEvent.java
org/simplericity/macify/eawt/ApplicationListener.java
org/simplericity/macify/eawt/DefaultApplication.java
# legacy applet wrapper thing.
# The launcher has to be there for silly FML/Forge relauncher.
net/minecraft/Launcher.java
org/multimc/legacy/LegacyLauncher.java
org/multimc/LegacyFrame.java
# onesix launcher
org/multimc/onesix/OneSixLauncher.java
# generic launcher
org/multimc/EntryPoint.java
org/multimc/Launcher.java
org/multimc/ParseException.java
org/multimc/Utils.java
org/multimc/IconLoader.java
)
add_jar(NewLaunch ${SRC})
add_jar(MultiMCLauncher ${SRC})
INSTALL_JAR(MultiMCLauncher "${BINARY_DEST_DIR}/jars")
install_jar(NewLaunch "${BINARY_DEST_DIR}/jars")

View File

@@ -1,331 +0,0 @@
//
// Copyright 2012 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.
//
import java.applet.Applet;
import java.awt.Dimension;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import org.simplericity.macify.eawt.Application;
import org.simplericity.macify.eawt.DefaultApplication;
public class MultiMCLauncher
{
/**
* @param args
* The arguments you want to launch Minecraft with. New path,
* Username, Session ID.
*/
public static void main(String[] args)
{
if (args.length < 3)
{
System.out.println("Not enough arguments.");
System.exit(-1);
}
// Set the OSX application icon first, if we are on OSX.
Application application = new DefaultApplication();
if(application.isMac())
{
try
{
BufferedImage image = ImageIO.read(new File("icon.png"));
application.setApplicationIconImage(image);
}
catch (IOException e)
{
e.printStackTrace();
}
}
String userName = args[0];
String sessionId = args[1];
String windowtitle = args[2];
String windowParams = args[3];
String lwjgl = args[4];
String cwd = System.getProperty("user.dir");
Dimension winSize = new Dimension(854, 480);
boolean maximize = false;
boolean compatMode = false;
String[] dimStrings = windowParams.split("x");
if (windowParams.equalsIgnoreCase("compatmode"))
{
compatMode = true;
}
else if (windowParams.equalsIgnoreCase("max"))
{
maximize = true;
}
else if (dimStrings.length == 2)
{
try
{
winSize = new Dimension(Integer.parseInt(dimStrings[0]),
Integer.parseInt(dimStrings[1]));
}
catch (NumberFormatException e)
{
System.out.println("Invalid Window size argument, " +
"using default.");
}
}
else
{
System.out.println("Invalid Window size argument, " +
"using default.");
}
try
{
File binDir = new File(cwd, "bin");
File lwjglDir;
if(lwjgl.equalsIgnoreCase("Mojang"))
lwjglDir = binDir;
else
lwjglDir = new File(lwjgl);
System.out.println("Loading jars...");
String[] lwjglJars = new String[] {
"lwjgl.jar", "lwjgl_util.jar", "jinput.jar"
};
URL[] urls = new URL[4];
try
{
File f = new File(binDir, "minecraft.jar");
urls[0] = f.toURI().toURL();
System.out.println("Loading URL: " + urls[0].toString());
for (int i = 1; i < urls.length; i++)
{
File jar = new File(lwjglDir, lwjglJars[i-1]);
urls[i] = jar.toURI().toURL();
System.out.println("Loading URL: " + urls[i].toString());
}
}
catch (MalformedURLException e)
{
System.err.println("MalformedURLException, " + e.toString());
System.exit(5);
}
System.out.println("Loading natives...");
String nativesDir = new File(lwjglDir, "natives").toString();
System.setProperty("org.lwjgl.librarypath", nativesDir);
System.setProperty("net.java.games.input.librarypath", nativesDir);
URLClassLoader cl =
new URLClassLoader(urls, MultiMCLauncher.class.getClassLoader());
// Get the Minecraft Class.
Class<?> mc = null;
try
{
mc = cl.loadClass("net.minecraft.client.Minecraft");
Field f = getMCPathField(mc);
if (f == null)
{
System.err.println("Could not find Minecraft path field. Launch failed.");
System.exit(-1);
}
f.setAccessible(true);
f.set(null, new File(cwd));
// And set it.
System.out.println("Fixed Minecraft Path: Field was " + f.toString());
}
catch (ClassNotFoundException e)
{
System.err.println("Can't find main class. Searching...");
// Look for any class that looks like the main class.
File mcJar = new File(new File(cwd, "bin"), "minecraft.jar");
ZipFile zip = null;
try
{
zip = new ZipFile(mcJar);
} catch (ZipException e1)
{
e1.printStackTrace();
System.err.println("Search failed.");
System.exit(-1);
} catch (IOException e1)
{
e1.printStackTrace();
System.err.println("Search failed.");
System.exit(-1);
}
Enumeration<? extends ZipEntry> entries = zip.entries();
ArrayList<String> classes = new ArrayList<String>();
while (entries.hasMoreElements())
{
ZipEntry entry = entries.nextElement();
if (entry.getName().endsWith(".class"))
{
String entryName = entry.getName().substring(0, entry.getName().lastIndexOf('.'));
entryName = entryName.replace('/', '.');
System.out.println("Found class: " + entryName);
classes.add(entryName);
}
}
for (String clsName : classes)
{
try
{
Class<?> cls = cl.loadClass(clsName);
if (!Runnable.class.isAssignableFrom(cls))
{
continue;
}
else
{
System.out.println("Found class implementing runnable: " +
cls.getName());
}
if (getMCPathField(cls) == null)
{
continue;
}
else
{
System.out.println("Found class implementing runnable " +
"with mcpath field: " + cls.getName());
}
mc = cls;
break;
}
catch (ClassNotFoundException e1)
{
// Ignore
continue;
}
}
if (mc == null)
{
System.err.println("Failed to find Minecraft main class.");
System.exit(-1);
}
else
{
System.out.println("Found main class: " + mc.getName());
}
}
System.setProperty("minecraft.applet.TargetDirectory", cwd);
String[] mcArgs = new String[2];
mcArgs[0] = userName;
mcArgs[1] = sessionId;
if (compatMode)
{
System.out.println("Launching in compatibility mode...");
mc.getMethod("main", String[].class).invoke(null, (Object) mcArgs);
}
else
{
System.out.println("Launching with applet wrapper...");
try
{
Class<?> MCAppletClass = cl.loadClass(
"net.minecraft.client.MinecraftApplet");
Applet mcappl = (Applet) MCAppletClass.newInstance();
MCFrame mcWindow = new MCFrame(windowtitle);
mcWindow.start(mcappl, userName, sessionId, winSize, maximize);
} catch (InstantiationException e)
{
System.out.println("Applet wrapper failed! Falling back " +
"to compatibility mode.");
mc.getMethod("main", String[].class).invoke(null, (Object) mcArgs);
}
}
} catch (ClassNotFoundException e)
{
e.printStackTrace();
System.exit(1);
} catch (IllegalArgumentException e)
{
e.printStackTrace();
System.exit(2);
} catch (IllegalAccessException e)
{
e.printStackTrace();
System.exit(2);
} catch (InvocationTargetException e)
{
e.printStackTrace();
System.exit(3);
} catch (NoSuchMethodException e)
{
e.printStackTrace();
System.exit(3);
} catch (SecurityException e)
{
e.printStackTrace();
System.exit(4);
}
}
public static Field getMCPathField(Class<?> mc)
{
Field[] fields = mc.getDeclaredFields();
for (int i = 0; i < fields.length; i++)
{
Field f = fields[i];
if (f.getType() != File.class)
{
// Has to be File
continue;
}
if (f.getModifiers() != (Modifier.PRIVATE + Modifier.STATIC))
{
// And Private Static.
continue;
}
return f;
}
return null;
}
}

View File

@@ -1,18 +1,18 @@
//
// Copyright 2012 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.
//
/*
* Copyright 2012-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.minecraft;
@@ -24,6 +24,7 @@ import java.awt.BorderLayout;
import java.awt.Graphics;
import java.applet.Applet;
import java.applet.AppletStub;
import java.net.MalformedURLException;
public class Launcher extends Applet implements AppletStub
{
@@ -38,7 +39,7 @@ public class Launcher extends Applet implements AppletStub
this.setLayout(new BorderLayout());
this.add(applet, "Center");
this.wrappedApplet = applet;
this.wrappedApplet = applet;
this.documentBase = documentBase;
}
@@ -46,17 +47,17 @@ public class Launcher extends Applet implements AppletStub
{
params.put(name, value);
}
public void replace(Applet applet)
{
this.wrappedApplet = applet;
applet.setStub(this);
applet.setSize(getWidth(), getHeight());
this.setLayout(new BorderLayout());
this.add(applet, "Center");
applet.init();
active = true;
applet.start();
@@ -99,7 +100,7 @@ public class Launcher extends Applet implements AppletStub
{
wrappedApplet.resize(d);
}
@Override
public void init()
{
@@ -127,16 +128,26 @@ public class Launcher extends Applet implements AppletStub
{
wrappedApplet.destroy();
}
@Override
public URL getCodeBase() {
return wrappedApplet.getCodeBase();
try {
return new URL("http://www.minecraft.net/game/");
} catch (MalformedURLException e) {
e.printStackTrace();
}
return null;
}
@Override
public URL getDocumentBase()
{
return documentBase;
try {
return new URL("http://www.minecraft.net/game/");
} catch (MalformedURLException e) {
e.printStackTrace();
}
return null;
}
@Override

View File

@@ -0,0 +1,173 @@
package org.multimc;/*
* Copyright 2012-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.multimc.legacy.LegacyLauncher;
import org.multimc.onesix.OneSixLauncher;
import org.simplericity.macify.eawt.Application;
import org.simplericity.macify.eawt.DefaultApplication;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.charset.Charset;
public class EntryPoint
{
private enum Action
{
Proceed,
Launch,
Abort
}
public static void main(String[] args)
{
// Set the OSX application icon first, if we are on OSX.
Application application = new DefaultApplication();
if(application.isMac())
{
try
{
BufferedImage image = ImageIO.read(new File("icon.png"));
application.setApplicationIconImage(image);
}
catch (IOException e)
{
e.printStackTrace();
}
}
EntryPoint listener = new EntryPoint();
int retCode = listener.listen();
if (retCode != 0)
{
System.out.println("Exiting with " + retCode);
System.exit(retCode);
}
}
private Action parseLine(String inData) throws ParseException
{
String[] pair = inData.split(" ", 2);
if(pair.length == 1)
{
String command = pair[0];
if (pair[0].equals("launch"))
return Action.Launch;
else if (pair[0].equals("abort"))
return Action.Abort;
else throw new ParseException();
}
if(pair.length != 2)
throw new ParseException();
String command = pair[0];
String param = pair[1];
if(command.equals("launcher"))
{
if(param.equals("legacy"))
{
m_launcher = new LegacyLauncher();
Utils.log("Using legacy launcher.");
Utils.log();
return Action.Proceed;
}
if(param.equals("onesix"))
{
m_launcher = new OneSixLauncher();
Utils.log("Using onesix launcher.");
Utils.log();
return Action.Proceed;
}
else
throw new ParseException();
}
m_params.add(command, param);
//System.out.println(command + " : " + param);
return Action.Proceed;
}
public int listen()
{
BufferedReader buffer;
try
{
buffer = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
} catch (UnsupportedEncodingException e)
{
System.err.println("For some reason, your java does not support UTF-8. Consider living in the current century.");
e.printStackTrace();
return 1;
}
boolean isListening = true;
boolean isAborted = false;
// Main loop
while (isListening)
{
String inData;
try
{
// Read from the pipe one line at a time
inData = buffer.readLine();
if (inData != null)
{
Action a = parseLine(inData);
if(a == Action.Abort)
{
isListening = false;
isAborted = true;
}
if(a == Action.Launch)
{
isListening = false;
}
}
}
catch (IOException e)
{
System.err.println("Launcher ABORT due to IO exception:");
e.printStackTrace();
return 1;
}
catch (ParseException e)
{
System.err.println("Launcher ABORT due to PARSE exception:");
e.printStackTrace();
return 1;
}
}
if(isAborted)
{
System.err.println("Launch aborted by MultiMC.");
return 1;
}
if(m_launcher != null)
{
return m_launcher.launch(m_params);
}
System.err.println("No valid launcher implementation specified.");
return 1;
}
private ParamBucket m_params = new ParamBucket();
private org.multimc.Launcher m_launcher;
}

View File

@@ -0,0 +1,132 @@
package org.multimc;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
/*****************************************************************************
* A convenience class for loading icons from images.
*
* Icons loaded from this class are formatted to fit within the required
* dimension (16x16, 32x32, or 128x128). If the source image is larger than the
* target dimension, it is shrunk down to the minimum size that will fit. If it
* is smaller, then it is only scaled up if the new scale can be a per-pixel
* linear scale (i.e., x2, x3, x4, etc). In both cases, the image's width/height
* ratio is kept the same as the source image.
*
* @author Chris Molini
*****************************************************************************/
public class IconLoader
{
/*************************************************************************
* Loads an icon in ByteBuffer form.
*
* @param filepath
* The location of the Image to use as an icon.
*
* @return An array of ByteBuffers containing the pixel data for the icon in
* various sizes (as recommended by the OS).
*************************************************************************/
public static ByteBuffer[] load(String filepath)
{
BufferedImage image;
try {
image = ImageIO.read ( new File( filepath ) );
} catch ( IOException e ) {
e.printStackTrace();
return new ByteBuffer[0];
}
ByteBuffer[] buffers;
buffers = new ByteBuffer[1];
buffers[0] = loadInstance(image, 128);
return buffers;
}
/*************************************************************************
* Copies the supplied image into a square icon at the indicated size.
*
* @param image
* The image to place onto the icon.
* @param dimension
* The desired size of the icon.
*
* @return A ByteBuffer of pixel data at the indicated size.
*************************************************************************/
private static ByteBuffer loadInstance(BufferedImage image, int dimension)
{
BufferedImage scaledIcon = new BufferedImage(dimension, dimension,
BufferedImage.TYPE_INT_ARGB_PRE);
Graphics2D g = scaledIcon.createGraphics();
double ratio = getIconRatio(image, scaledIcon);
double width = image.getWidth() * ratio;
double height = image.getHeight() * ratio;
g.drawImage(image, (int) ((scaledIcon.getWidth() - width) / 2),
(int) ((scaledIcon.getHeight() - height) / 2), (int) (width),
(int) (height), null);
g.dispose();
return convertToByteBuffer(scaledIcon);
}
/*************************************************************************
* Gets the width/height ratio of the icon. This is meant to simplify
* scaling the icon to a new dimension.
*
* @param src
* The base image that will be placed onto the icon.
* @param icon
* The icon that will have the image placed on it.
*
* @return The amount to scale the source image to fit it onto the icon
* appropriately.
*************************************************************************/
private static double getIconRatio(BufferedImage src, BufferedImage icon)
{
double ratio = 1;
if (src.getWidth() > icon.getWidth())
ratio = (double) (icon.getWidth()) / src.getWidth();
else
ratio = (int) (icon.getWidth() / src.getWidth());
if (src.getHeight() > icon.getHeight())
{
double r2 = (double) (icon.getHeight()) / src.getHeight();
if (r2 < ratio)
ratio = r2;
}
else
{
double r2 = (int) (icon.getHeight() / src.getHeight());
if (r2 < ratio)
ratio = r2;
}
return ratio;
}
/*************************************************************************
* Converts a BufferedImage into a ByteBuffer of pixel data.
*
* @param image
* The image to convert.
*
* @return A ByteBuffer that contains the pixel data of the supplied image.
*************************************************************************/
public static ByteBuffer convertToByteBuffer(BufferedImage image)
{
byte[] buffer = new byte[image.getWidth() * image.getHeight() * 4];
int counter = 0;
for (int i = 0; i < image.getHeight(); i++)
for (int j = 0; j < image.getWidth(); j++)
{
int colorSpace = image.getRGB(j, i);
buffer[counter + 0] = (byte) ((colorSpace << 8) >> 24);
buffer[counter + 1] = (byte) ((colorSpace << 16) >> 24);
buffer[counter + 2] = (byte) ((colorSpace << 24) >> 24);
buffer[counter + 3] = (byte) (colorSpace >> 24);
counter += 4;
}
return ByteBuffer.wrap(buffer);
}
}

View File

@@ -1,4 +1,5 @@
/* Copyright 2013 MultiMC Contributors
/*
* Copyright 2012-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,16 +14,9 @@
* limitations under the License.
*/
#pragma once
package org.multimc;
#include <QtCore/QtGlobal>
#ifdef LIBGROUPVIEW_STATIC
#define LIBGROUPVIEW_EXPORT
#else
#ifdef LIBGROUPVIEW_LIBRARY
#define LIBGROUPVIEW_EXPORT Q_DECL_EXPORT
#else
#define LIBGROUPVIEW_EXPORT Q_DECL_IMPORT
#endif
#endif
public interface Launcher
{
abstract int launch(ParamBucket params);
}

View File

@@ -1,40 +1,39 @@
//
// Copyright 2012 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.
//
package org.multimc;/*
* Copyright 2012-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import net.minecraft.Launcher;
import javax.imageio.ImageIO;
import java.applet.Applet;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Toolkit;
import java.awt.*;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.io.IOException;
import java.io.File;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
public class MCFrame extends Frame implements WindowListener
public class LegacyFrame extends Frame implements WindowListener
{
private Launcher appletWrap = null;
public MCFrame ( String title )
public LegacyFrame(String title)
{
super ( title );
BufferedImage image = null;
BufferedImage image;
try {
image = ImageIO.read ( new File ( "icon.png" ) );
setIconImage ( image );
@@ -47,14 +46,14 @@ public class MCFrame extends Frame implements WindowListener
public void start ( Applet mcApplet, String user, String session, Dimension winSize, boolean maximize )
{
try {
appletWrap = new Launcher ( mcApplet, new URL ( "http://www.minecraft.net/game" ) );
appletWrap = new Launcher( mcApplet, new URL ( "http://www.minecraft.net/game" ) );
} catch ( MalformedURLException ignored ) {}
appletWrap.setParameter ( "username", user );
appletWrap.setParameter ( "sessionid", session );
appletWrap.setParameter ( "stand-alone", "true" ); // Show the quit button.
mcApplet.setStub ( appletWrap );
appletWrap.setParameter ( "demo", "false" );
appletWrap.setParameter("fullscreen", "false");
mcApplet.setStub(appletWrap);
this.add ( appletWrap );
appletWrap.setPreferredSize ( winSize );
this.pack();
@@ -63,7 +62,6 @@ public class MCFrame extends Frame implements WindowListener
if ( maximize ) {
this.setExtendedState ( MAXIMIZED_BOTH );
}
validate();
appletWrap.init();
appletWrap.start();

View File

@@ -1,4 +1,5 @@
/* Copyright 2013 MultiMC Contributors
/*
* Copyright 2012-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,16 +14,8 @@
* limitations under the License.
*/
#pragma once
package org.multimc;
#include "OneSixInstance.h"
class NostalgiaInstance : public OneSixInstance
public class NotFoundException extends Exception
{
Q_OBJECT
public:
explicit NostalgiaInstance(const QString &rootDir, SettingsObject *settings,
QObject *parent = 0);
virtual QString getStatusbarDescription();
virtual bool menuActionEnabled(QString action_name) const;
};
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright 2012-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.multimc;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class ParamBucket
{
public void add(String key, String value)
{
List<String> coll = null;
if(!m_params.containsKey(key))
{
coll = new ArrayList<String>();
m_params.put(key, coll);
}
else
{
coll = m_params.get(key);
}
coll.add(value);
}
public List<String> all(String key) throws NotFoundException
{
if(!m_params.containsKey(key))
throw new NotFoundException();
return m_params.get(key);
}
public List<String> allSafe(String key, List<String> def)
{
if(!m_params.containsKey(key) || m_params.get(key).size() < 1)
{
return def;
}
return m_params.get(key);
}
public List<String> allSafe(String key)
{
return allSafe(key, new ArrayList<String>());
}
public String first(String key) throws NotFoundException
{
List<String> list = all(key);
if(list.size() < 1)
{
throw new NotFoundException();
}
return list.get(0);
}
public String firstSafe(String key, String def)
{
if(!m_params.containsKey(key) || m_params.get(key).size() < 1)
{
return def;
}
return m_params.get(key).get(0);
}
public String firstSafe(String key)
{
return firstSafe(key, "");
}
private HashMap<String, List<String>> m_params = new HashMap<String, List<String>>();
}

View File

@@ -1,4 +1,5 @@
/* Copyright 2013 MultiMC Contributors
/*
* Copyright 2012-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,17 +14,9 @@
* limitations under the License.
*/
#pragma once
package org.multimc;
#include <QtCore/QtGlobal>
#ifdef LIBSETTINGS_STATIC
#define LIBSETTINGS_EXPORT
#else
#ifdef LIBSETTINGS_LIBRARY
#define LIBSETTINGS_EXPORT Q_DECL_EXPORT
#else
#define LIBSETTINGS_EXPORT Q_DECL_IMPORT
#endif
#endif
public class ParseException extends java.lang.Exception
{
}

View File

@@ -0,0 +1,309 @@
/*
* Copyright 2012-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.multimc;
import java.io.*;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class Utils
{
/**
* Combine two parts of a path.
*
* @param path1
* @param path2
* @return the paths, combined
*/
public static String combine(String path1, String path2)
{
File file1 = new File(path1);
File file2 = new File(file1, path2);
return file2.getPath();
}
/**
* Join a list of strings into a string using a separator!
*
* @param strings the string list to join
* @param separator the glue
* @return the result.
*/
public static String join(List<String> strings, String separator)
{
StringBuilder sb = new StringBuilder();
String sep = "";
for (String s : strings)
{
sb.append(sep).append(s);
sep = separator;
}
return sb.toString();
}
/**
* Adds the specified library to the classpath
*
* @param s the path to add
* @throws Exception
*/
public static void addToClassPath(String s) throws Exception
{
File f = new File(s);
URL u = f.toURI().toURL();
URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class urlClass = URLClassLoader.class;
Method method = urlClass.getDeclaredMethod("addURL", new Class[]{URL.class});
method.setAccessible(true);
method.invoke(urlClassLoader, new Object[]{u});
}
/**
* Adds many libraries to the classpath
*
* @param jars the paths to add
*/
public static boolean addToClassPath(List<String> jars)
{
boolean pure = true;
// initialize the class path
for (String jar : jars)
{
try
{
Utils.addToClassPath(jar);
} catch (Exception e)
{
System.err.println("Unable to load: " + jar);
e.printStackTrace(System.err);
pure = false;
}
}
return pure;
}
/**
* Adds the specified path to the java library path
*
* @param pathToAdd the path to add
* @throws Exception
*/
@Deprecated
public static void addLibraryPath(String pathToAdd) throws Exception
{
final Field usrPathsField = ClassLoader.class.getDeclaredField("usr_paths");
usrPathsField.setAccessible(true);
//get array of paths
final String[] paths = (String[]) usrPathsField.get(null);
//check if the path to add is already present
for (String path : paths)
{
if (path.equals(pathToAdd))
{
return;
}
}
//add the new path
final String[] newPaths = Arrays.copyOf(paths, paths.length + 1);
newPaths[newPaths.length - 1] = pathToAdd;
usrPathsField.set(null, newPaths);
}
/**
* Finds a field that looks like a Minecraft base folder in a supplied class
*
* @param mc the class to scan
*/
public static Field getMCPathField(Class<?> mc)
{
Field[] fields = mc.getDeclaredFields();
for (Field f : fields)
{
if (f.getType() != File.class)
{
// Has to be File
continue;
}
if (f.getModifiers() != (Modifier.PRIVATE + Modifier.STATIC))
{
// And Private Static.
continue;
}
return f;
}
return null;
}
/**
* Log to the MultiMC console
*
* @param message A String containing the message
* @param level A String containing the level name. See MinecraftProcess::getLevel()
*/
public static void log(String message, String level)
{
// Kinda dirty
String tag = "!![" + level + "]!";
System.out.println(tag + message.replace("\n", "\n" + tag));
}
public static void log(String message)
{
log(message, "MultiMC");
}
public static void log()
{
System.out.println();
}
/**
* Pushes bytes from in to out. Closes both streams no matter what.
* @param in the input stream
* @param out the output stream
* @throws IOException
*/
private static void copyStream(InputStream in, OutputStream out) throws IOException
{
try
{
byte[] buffer = new byte[4096];
int len;
while((len = in.read(buffer)) >= 0)
out.write(buffer, 0, len);
} finally
{
in.close();
out.close();
}
}
/**
* Replace a 'target' string 'suffix' with 'replacement'
*/
public static String replaceSuffix (String target, String suffix, String replacement)
{
if (!target.endsWith(suffix))
{
return target;
}
String prefix = target.substring(0, target.length() - suffix.length());
return prefix + replacement;
}
/**
* Unzip zip file with natives 'source' into the folder 'targetFolder'
*
* Contains a hack for OSX. Yay.
* @param source
* @param targetFolder
* @throws IOException
*/
public static void unzipNatives(File source, File targetFolder) throws IOException
{
ZipFile zip = new ZipFile(source);
Set <String> toProcess = new HashSet<String>();
try
{
Enumeration entries = zip.entries();
while (entries.hasMoreElements())
{
ZipEntry entry = (ZipEntry) entries.nextElement();
String entryName = entry.getName();
File targetFile = new File(targetFolder, entryName);
if (targetFile.getParentFile() != null)
{
targetFile.getParentFile().mkdirs();
}
if (entry.isDirectory())
continue;
copyStream(zip.getInputStream(entry), new BufferedOutputStream(new FileOutputStream(targetFile)));
toProcess.add(entryName);
}
} finally
{
zip.close();
}
// For java <= 7, do not do symlink hackery below.
String[] javaVersionElements = System.getProperty("java.version").split("\\.");
int major = Integer.parseInt(javaVersionElements[1]);
if (major <= 7)
{
return;
}
// for >= 8, do hackery
for (String entryName : toProcess)
{
// check if we need a symlink
String suffixFrom = null;
String suffixTo = null;
if(entryName.endsWith(".dylib"))
{
suffixFrom = ".dylib";
suffixTo = ".jnilib";
}
else if(entryName.endsWith(".jnilib"))
{
suffixFrom = ".jnilib";
suffixTo = ".dylib";
}
else
{
continue;
}
String linkName = replaceSuffix(entryName, suffixFrom, suffixTo);
File targetFile = new File(targetFolder, entryName);
File symlinkFile = new File(targetFolder, linkName);
// if the link file exists already for whatever reason, do not create symlinks
if(symlinkFile.exists())
{
continue;
}
// create a symlink. This means we always have .jnilib and .dylib variants of the same libs.
Path linkLink = symlinkFile.toPath();
Path linkTarget = targetFile.toPath();
Files.createSymbolicLink(linkLink, linkTarget);
}
}
}

View File

@@ -0,0 +1,175 @@
package org.multimc.legacy;/*
* Copyright 2012-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.multimc.*;
import java.applet.Applet;
import java.awt.*;
import java.io.File;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
public class LegacyLauncher implements Launcher
{
@Override
public int launch(ParamBucket params)
{
String userName, sessionId, windowTitle, windowParams, lwjgl;
String mainClass = "net.minecraft.client.Minecraft";
try
{
userName = params.first("userName");
sessionId = params.first("sessionId");
windowTitle = params.first("windowTitle");
windowParams = params.first("windowParams");
lwjgl = params.first("lwjgl");
} catch (NotFoundException e)
{
System.err.println("Not enough arguments.");
return -1;
}
String cwd = System.getProperty("user.dir");
Dimension winSize = new Dimension(854, 480);
boolean maximize = false;
String[] dimStrings = windowParams.split("x");
if (windowParams.equalsIgnoreCase("max"))
{
maximize = true;
}
else if (dimStrings.length == 2)
{
try
{
winSize = new Dimension(Integer.parseInt(dimStrings[0]), Integer.parseInt(dimStrings[1]));
} catch (NumberFormatException ignored) {}
}
File binDir = new File(cwd, "bin");
File lwjglDir;
if (lwjgl.equalsIgnoreCase("Mojang"))
{
lwjglDir = binDir;
}
else
{
lwjglDir = new File(lwjgl);
}
URL[] classpath;
{
try
{
classpath = new URL[]
{
new File(binDir, "minecraft.jar").toURI().toURL(),
new File(lwjglDir, "lwjgl.jar").toURI().toURL(),
new File(lwjglDir, "lwjgl_util.jar").toURI().toURL(),
new File(lwjglDir, "jinput.jar").toURI().toURL(),
};
} catch (MalformedURLException e)
{
System.err.println("Class path entry is badly formed:");
e.printStackTrace(System.err);
return -1;
}
}
String nativesDir = new File(lwjglDir, "natives").toString();
System.setProperty("org.lwjgl.librarypath", nativesDir);
System.setProperty("net.java.games.input.librarypath", nativesDir);
// print the pretty things
{
Utils.log("Main Class:");
Utils.log(" " + mainClass);
Utils.log();
Utils.log("Class Path:");
for (URL s : classpath)
{
Utils.log(" " + s);
}
Utils.log();
Utils.log("Native Path:");
Utils.log(" " + nativesDir);
Utils.log();
}
URLClassLoader cl = new URLClassLoader(classpath, LegacyLauncher.class.getClassLoader());
// Get the Minecraft Class and set the base folder
Class<?> mc;
try
{
mc = cl.loadClass(mainClass);
Field f = Utils.getMCPathField(mc);
if (f == null)
{
System.err.println("Could not find Minecraft path field. Launch failed.");
return -1;
}
f.setAccessible(true);
f.set(null, new File(cwd));
} catch (Exception e)
{
System.err.println("Could not set base folder. Failed to find/access Minecraft main class:");
e.printStackTrace(System.err);
return -1;
}
System.setProperty("minecraft.applet.TargetDirectory", cwd);
String[] mcArgs = new String[2];
mcArgs[0] = userName;
mcArgs[1] = sessionId;
Utils.log("Launching with applet wrapper...");
try
{
Class<?> MCAppletClass = cl.loadClass("net.minecraft.client.MinecraftApplet");
Applet mcappl = (Applet) MCAppletClass.newInstance();
LegacyFrame mcWindow = new LegacyFrame(windowTitle);
mcWindow.start(mcappl, userName, sessionId, winSize, maximize);
} catch (Exception e)
{
Utils.log("Applet wrapper failed:", "Error");
e.printStackTrace(System.err);
Utils.log();
Utils.log("Falling back to compatibility mode.");
try
{
mc.getMethod("main", String[].class).invoke(null, (Object) mcArgs);
} catch (Exception e1)
{
Utils.log("Failed to invoke the Minecraft main class:", "Fatal");
e1.printStackTrace(System.err);
return -1;
}
}
return 0;
}
}

View File

@@ -0,0 +1,379 @@
/* Copyright 2012-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.multimc.onesix;
import org.multimc.*;
import java.applet.Applet;
import java.io.File;
import java.awt.*;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class OneSixLauncher implements Launcher
{
// parameters, separated from ParamBucket
private List<String> libraries;
private List<String> extlibs;
private List<String> mcparams;
private List<String> mods;
private List<String> traits;
private String appletClass;
private String mainClass;
private String natives;
private String userName, sessionId;
private String windowTitle;
private String windowParams;
// secondary parameters
private Dimension winSize;
private boolean maximize;
private String cwd;
// the much abused system classloader, for convenience (for further abuse)
private ClassLoader cl;
private void processParams(ParamBucket params) throws NotFoundException
{
libraries = params.all("cp");
extlibs = params.all("ext");
mcparams = params.allSafe("param", new ArrayList<String>() );
mainClass = params.firstSafe("mainClass", "net.minecraft.client.Minecraft");
appletClass = params.firstSafe("appletClass", "net.minecraft.client.MinecraftApplet");
mods = params.allSafe("mods", new ArrayList<String>());
traits = params.allSafe("traits", new ArrayList<String>());
natives = params.first("natives");
userName = params.first("userName");
sessionId = params.first("sessionId");
windowTitle = params.firstSafe("windowTitle", "Minecraft");
windowParams = params.firstSafe("windowParams", "854x480");
cwd = System.getProperty("user.dir");
winSize = new Dimension(854, 480);
maximize = false;
String[] dimStrings = windowParams.split("x");
if (windowParams.equalsIgnoreCase("max"))
{
maximize = true;
}
else if (dimStrings.length == 2)
{
try
{
winSize = new Dimension(Integer.parseInt(dimStrings[0]), Integer.parseInt(dimStrings[1]));
} catch (NumberFormatException ignored) {}
}
}
private void printStats()
{
Utils.log("Main Class:");
Utils.log(" " + mainClass);
Utils.log();
Utils.log("Native path:");
Utils.log(" " + natives);
Utils.log();
Utils.log("Traits:");
Utils.log(" " + traits);
Utils.log();
Utils.log("Libraries:");
for (String s : libraries)
{
File f = new File(s);
if (f.exists())
{
Utils.log(" " + s);
}
else
{
Utils.log(" " + s + " (missing)", "Warning");
}
}
Utils.log();
if(mods.size() > 0)
{
Utils.log("Class Path Mods:");
for (String s : mods)
{
Utils.log(" " + s);
}
Utils.log();
}
Utils.log("Params:");
Utils.log(" " + mcparams.toString());
Utils.log();
if(maximize)
Utils.log("Window size: max (if available)");
else
Utils.log("Window size: " + Integer.toString(winSize.width) + " x " + Integer.toString(winSize.height));
Utils.log();
}
int legacyLaunch()
{
// Get the Minecraft Class and set the base folder
Class<?> mc;
try
{
mc = cl.loadClass(mainClass);
Field f = Utils.getMCPathField(mc);
if (f == null)
{
System.err.println("Could not find Minecraft path field.");
}
else
{
f.setAccessible(true);
f.set(null, new File(cwd));
}
} catch (Exception e)
{
System.err.println("Could not set base folder. Failed to find/access Minecraft main class:");
e.printStackTrace(System.err);
return -1;
}
System.setProperty("minecraft.applet.TargetDirectory", cwd);
String[] mcArgs = new String[2];
mcArgs[0] = userName;
mcArgs[1] = sessionId;
Utils.log("Launching with applet wrapper...");
try
{
Class<?> MCAppletClass = cl.loadClass(appletClass);
Applet mcappl = (Applet) MCAppletClass.newInstance();
LegacyFrame mcWindow = new LegacyFrame(windowTitle);
mcWindow.start(mcappl, userName, sessionId, winSize, maximize);
} catch (Exception e)
{
Utils.log("Applet wrapper failed:", "Error");
e.printStackTrace(System.err);
Utils.log();
Utils.log("Falling back to compatibility mode.");
try
{
mc.getMethod("main", String[].class).invoke(null, (Object) mcArgs);
} catch (Exception e1)
{
Utils.log("Failed to invoke the Minecraft main class:", "Fatal");
e1.printStackTrace(System.err);
return -1;
}
}
return 0;
}
int launchWithMainClass()
{
// window size, title and state, onesix
if (maximize)
{
// FIXME: there is no good way to maximize the minecraft window in onesix.
// the following often breaks linux screen setups
// mcparams.add("--fullscreen");
}
else
{
mcparams.add("--width");
mcparams.add(Integer.toString(winSize.width));
mcparams.add("--height");
mcparams.add(Integer.toString(winSize.height));
}
// Get the Minecraft Class.
Class<?> mc;
try
{
mc = cl.loadClass(mainClass);
} catch (ClassNotFoundException e)
{
System.err.println("Failed to find Minecraft main class:");
e.printStackTrace(System.err);
return -1;
}
// get the main method.
Method meth;
try
{
meth = mc.getMethod("main", String[].class);
} catch (NoSuchMethodException e)
{
System.err.println("Failed to acquire the main method:");
e.printStackTrace(System.err);
return -1;
}
/*
final java.nio.ByteBuffer[] icons = IconLoader.load("icon.png");
new Thread() {
public void run() {
ClassLoader cl = ClassLoader.getSystemClassLoader();
try
{
Class<?> Display;
Method isCreated;
Method setTitle;
Method setIcon;
Field fieldWindowCreated;
Boolean created = false;
Display = cl.loadClass("org.lwjgl.opengl.Display");
fieldWindowCreated = Display.getDeclaredField("window_created");
fieldWindowCreated.setAccessible( true );
setTitle = Display.getMethod("setTitle", String.class);
setIcon = Display.getMethod("setIcon", java.nio.ByteBuffer[].class);
created = (Boolean) fieldWindowCreated.get( null );
// set the window title? Maybe?
while(!created)
{
try
{
Thread.sleep(150);
created = (Boolean) fieldWindowCreated.get( null );
} catch (InterruptedException ignored) {}
}
// Give it a bit more time ;)
Thread.sleep(150);
// set the title
setTitle.invoke(null,windowTitle);
// only set icon when there's actually something to set...
if(icons.length > 0)
{
setIcon.invoke(null,(Object)icons);
}
}
catch (Exception e)
{
System.err.println("Couldn't set window icon or title.");
e.printStackTrace(System.err);
}
}
}
.start();
*/
// init params for the main method to chomp on.
String[] paramsArray = mcparams.toArray(new String[mcparams.size()]);
try
{
// static method doesn't have an instance
meth.invoke(null, (Object) paramsArray);
} catch (Exception e)
{
System.err.println("Failed to start Minecraft:");
e.printStackTrace(System.err);
return -1;
}
return 0;
}
@Override
public int launch(ParamBucket params)
{
// get and process the launch script params
try
{
processParams(params);
} catch (NotFoundException e)
{
System.err.println("Not enough arguments.");
e.printStackTrace(System.err);
return -1;
}
// do some horrible black magic with the classpath
{
List<String> allJars = new ArrayList<String>();
allJars.addAll(mods);
allJars.addAll(libraries);
if(!Utils.addToClassPath(allJars))
{
System.err.println("Halting launch due to previous errors.");
return -1;
}
}
// print the pretty things
printStats();
// extract native libs (depending on platform here... java!)
Utils.log("Preparing native libraries...");
String property = System.getProperty("os.arch");
boolean is_64 = property.equalsIgnoreCase("x86_64") || property.equalsIgnoreCase("amd64");
for(String extlib: extlibs)
{
try
{
String cleanlib = extlib.replace("${arch}", is_64 ? "64" : "32");
File cleanlibf = new File(cleanlib);
Utils.log("Extracting " + cleanlibf.getName());
Utils.unzipNatives(cleanlibf, new File(natives));
} catch (IOException e)
{
System.err.println("Failed to extract native library:");
e.printStackTrace(System.err);
return -1;
}
}
Utils.log();
// set the native libs path... the brute force way
try
{
System.setProperty("java.library.path", natives);
System.setProperty("org.lwjgl.librarypath", natives);
System.setProperty("net.java.games.input.librarypath", natives);
// by the power of reflection, initialize native libs again. DIRTY!
// this is SO BAD. imagine doing that to ld
Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
fieldSysPath.setAccessible( true );
fieldSysPath.set( null, null );
} catch (Exception e)
{
System.err.println("Failed to set the native library path:");
e.printStackTrace(System.err);
return -1;
}
// grab the system classloader and ...
cl = ClassLoader.getSystemClassLoader();
if (traits.contains("legacyLaunch") || traits.contains("alphaLaunch") )
{
// legacy launch uses the applet wrapper
return legacyLaunch();
}
else
{
// normal launch just calls main()
return launchWithMainClass();
}
}
}

View File

@@ -1,59 +1,59 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
cmake_minimum_required(VERSION 2.6)
IF(WIN32)
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(unpack200)
# Find ZLIB for quazip
# Use system zlib on unix and Qt ZLIB on Windows
IF(UNIX)
if(UNIX)
find_package(ZLIB REQUIRED)
ELSE(UNIX)
get_filename_component (ZLIB_FOUND_DIR "${Qt5Core_DIR}/../../../include/QtZlib" ABSOLUTE)
SET(ZLIB_INCLUDE_DIRS ${ZLIB_FOUND_DIR} CACHE PATH "Path to ZLIB headers of Qt")
SET(ZLIB_LIBRARIES "")
IF(NOT EXISTS "${ZLIB_INCLUDE_DIRS}/zlib.h")
MESSAGE("Please specify a valid zlib include dir")
ENDIF(NOT EXISTS "${ZLIB_INCLUDE_DIRS}/zlib.h")
ENDIF(UNIX)
else(UNIX)
get_filename_component(ZLIB_FOUND_DIR "${Qt5Core_DIR}/../../../include/QtZlib" ABSOLUTE)
set(ZLIB_INCLUDE_DIRS ${ZLIB_FOUND_DIR} CACHE PATH "Path to ZLIB headers of Qt")
set(ZLIB_LIBRARIES "")
if(NOT EXISTS "${ZLIB_INCLUDE_DIRS}/zlib.h")
message("Please specify a valid zlib include dir")
endif(NOT EXISTS "${ZLIB_INCLUDE_DIRS}/zlib.h")
endif(UNIX)
SET(PACK200_SRC
include/unpack200.h
src/bands.cpp
src/bands.h
src/bytes.cpp
src/bytes.h
src/coding.cpp
src/coding.h
src/constants.h
src/defines.h
src/unpack200.cpp
src/unpack.cpp
src/unpack.h
src/utils.cpp
src/utils.h
src/zip.cpp
src/zip.h
set(PACK200_SRC
include/unpack200.h
src/bands.cpp
src/bands.h
src/bytes.cpp
src/bytes.h
src/coding.cpp
src/coding.h
src/constants.h
src/defines.h
src/unpack200.cpp
src/unpack.cpp
src/unpack.h
src/utils.cpp
src/utils.h
src/zip.cpp
src/zip.h
)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
SET(PACK200_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE)
set(PACK200_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE)
include_directories(
include
${ZLIB_INCLUDE_DIRS}
)
add_library(unpack200 STATIC ${PACK200_SRC})
IF(UNIX)
if(UNIX)
target_link_libraries(unpack200 ${ZLIB_LIBRARIES})
ELSE()
else()
# zlib is part of Qt on windows. use it.
QT5_USE_MODULES(unpack200 Core)
ENDIF()
qt5_use_modules(unpack200 Core)
endif()
add_executable(anti200 anti200.cpp)
target_link_libraries(anti200 unpack200)

View File

@@ -44,6 +44,9 @@
extern coding basic_codings[];
// CODING_PRIVATE causes a lot of them
#pragma GCC diagnostic ignored "-Wunused-variable"
#define CODING_PRIVATE(spec) \
int spec_ = spec; \
int B = CODING_B(spec_); \

View File

@@ -2,16 +2,16 @@ project(quazip)
# Find ZLIB for quazip
# Use system zlib on unix and Qt ZLIB on Windows
IF(UNIX)
if(UNIX)
find_package(ZLIB REQUIRED)
ELSE(UNIX)
get_filename_component (ZLIB_FOUND_DIR "${Qt5Core_DIR}/../../../include/QtZlib" ABSOLUTE)
SET(ZLIB_INCLUDE_DIRS ${ZLIB_FOUND_DIR} CACHE PATH "Path to ZLIB headers of Qt")
SET(ZLIB_LIBRARIES "")
IF(NOT EXISTS "${ZLIB_INCLUDE_DIRS}/zlib.h")
MESSAGE("Please specify a valid zlib include dir")
ENDIF(NOT EXISTS "${ZLIB_INCLUDE_DIRS}/zlib.h")
ENDIF(UNIX)
else(UNIX)
get_filename_component(ZLIB_FOUND_DIR "${Qt5Core_DIR}/../../../include/QtZlib" ABSOLUTE)
set(ZLIB_INCLUDE_DIRS ${ZLIB_FOUND_DIR} CACHE PATH "Path to ZLIB headers of Qt")
set(ZLIB_LIBRARIES "")
if(NOT EXISTS "${ZLIB_INCLUDE_DIRS}/zlib.h")
message("Please specify a valid zlib include dir")
endif(NOT EXISTS "${ZLIB_INCLUDE_DIRS}/zlib.h")
endif(UNIX)
# set all include directories for in and out of source builds
include_directories(
@@ -20,23 +20,12 @@ include_directories(
${ZLIB_INCLUDE_DIRS}
)
# include with QT_USE selected library parts
# INCLUDE(${QT_USE_FILE})
file(GLOB SRCS "*.c" "*.cpp")
file(GLOB PUBLIC_HEADERS "*.h")
# Static link!
ADD_DEFINITIONS(-DQUAZIP_STATIC)
#qt5_wrap_cpp(MOC_SRCS ${PUBLIC_HEADERS})
#set(SRCS ${SRCS} ${MOC_SRCS})
#set(CMAKE_POSITION_INDEPENDENT_CODE ON)
add_definitions(-DQUAZIP_STATIC)
add_library(quazip STATIC ${SRCS})
QT5_USE_MODULES(quazip Core)
qt5_use_modules(quazip Core)
target_link_libraries(quazip ${ZLIB_LIBRARIES})
#install(FILES ${PUBLIC_HEADERS} DESTINATION include/quazip)
#install(TARGETS quazip LIBRARY DESTINATION ${LIB_DESTINATION} ARCHIVE DESTINATION ${LIB_DESTINATION} RUNTIME DESTINATION ${LIB_DESTINATION})

View File

@@ -1245,7 +1245,7 @@ extern int ZEXPORT unzReadCurrentFile (file, buf, len)
return UNZ_PARAMERROR;
if ((pfile_in_zip_read_info->read_buffer == NULL))
if (pfile_in_zip_read_info->read_buffer == NULL)
return UNZ_END_OF_LIST_OF_FILE;
if (len==0)
return 0;

View File

@@ -777,9 +777,9 @@ extern int ZEXPORT zipOpenNewFileInZip3 (file, filename, zipfi,
zi->ci.flag = 0;
if ((level==8) || (level==9))
zi->ci.flag |= 2;
if ((level==2))
if (level==2)
zi->ci.flag |= 4;
if ((level==1))
if (level==1)
zi->ci.flag |= 6;
if (password != NULL)
{

View File

@@ -1,47 +0,0 @@
project(libSettings)
# Find Qt
find_package(Qt5Core REQUIRED)
# Include Qt headers.
include_directories(${Qt5Base_INCLUDE_DIRS})
SET(LIBSETTINGS_SOURCES
libsettings_config.h
inifile.h
inifile.cpp
settingsobject.h
settingsobject.cpp
inisettingsobject.h
inisettingsobject.cpp
setting.h
setting.cpp
overridesetting.h
overridesetting.cpp
)
# Set the include dir path.
SET(LIBSETTINGS_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE)
# Static link!
ADD_DEFINITIONS(-DLIBSETTINGS_STATIC)
add_definitions(-DLIBSETTINGS_LIBRARY)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
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)
add_library(libSettings STATIC ${LIBSETTINGS_SOURCES})
qt5_use_modules(libSettings Core)
target_link_libraries(libSettings)

View File

@@ -1,61 +1,42 @@
project(libUtil)
######## Set compiler flags ########
IF(APPLE)
# assume clang 4.1.0+, add C++0x/C++11 stuff
message(STATUS "Using APPLE CMAKE_CXX_FLAGS")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
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++0x")
ELSEIF(MINGW)
MESSAGE(STATUS "Using MINGW CMAKE_CXX_FLAGS")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x")
ENDIF()
include(UseCXX11)
include(Coverage)
# Find Qt
find_package(Qt5Core REQUIRED)
# Include Qt headers.
include_directories(${Qt5Base_INCLUDE_DIRS})
# include_directories(${Qt5Network_INCLUDE_DIRS})
SET(LIBUTIL_SOURCES
include/libutil_config.h
set(LIBUTIL_SOURCES
include/libutil_config.h
include/pathutils.h
src/pathutils.cpp
include/pathutils.h
src/pathutils.cpp
include/osutils.h
include/osutils.h
include/userutils.h
src/userutils.cpp
include/userutils.h
src/userutils.cpp
include/cmdutils.h
src/cmdutils.cpp
include/cmdutils.h
src/cmdutils.cpp
include/modutils.h
src/modutils.cpp
)
# Set the include dir path.
SET(LIBUTIL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE)
set(LIBUTIL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE)
# Static link!
ADD_DEFINITIONS(-DLIBUTIL_STATIC)
add_definitions(-DLIBUTIL_STATIC)
add_definitions(-DLIBUTIL_LIBRARY)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
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)
add_library(libUtil STATIC ${LIBUTIL_SOURCES})
# qt5_use_modules(libUtil Core Network)
qt5_use_modules(libUtil Core)
target_link_libraries(libUtil)

View File

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

View File

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

View File

@@ -0,0 +1,61 @@
#pragma once
#include <QString>
#include <QList>
#include "libutil_config.h"
class QUrl;
namespace Util
{
struct Version
{
Version(const QString &str);
Version() {}
bool operator<(const Version &other) const;
bool operator<=(const Version &other) const;
bool operator>(const Version &other) const;
bool operator>=(const Version &other) const;
bool operator==(const Version &other) const;
bool operator!=(const Version &other) const;
QString toString() const
{
return m_string;
}
private:
QString m_string;
struct Section
{
explicit Section(const QString &str, const int num) : numValid(true), number(num), string(str) {}
explicit Section(const QString &str) : numValid(false), string(str) {}
explicit Section() {}
bool numValid;
int number;
QString string;
inline bool operator!=(const Section &other) const
{
return (numValid && other.numValid) ? (number != other.number) : (string != other.string);
}
inline bool operator<(const Section &other) const
{
return (numValid && other.numValid) ? (number < other.number) : (string < other.string);
}
inline bool operator>(const Section &other) const
{
return (numValid && other.numValid) ? (number > other.number) : (string > other.string);
}
};
QList<Section> m_sections;
void parse();
};
LIBUTIL_EXPORT bool versionIsInInterval(const QString &version, const QString &interval);
LIBUTIL_EXPORT bool versionIsInInterval(const Version &version, const QString &interval);
}

View File

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

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
#pragma once
#include <QString>
#include <QDir>
#include "libutil_config.h"
@@ -57,3 +58,6 @@ LIBUTIL_EXPORT void openFileInDefaultProgram(QString filename);
/// Opens the given directory in the default application.
LIBUTIL_EXPORT void openDirInDefaultProgram(QString dirpath, bool ensureExists = false);
/// Checks if the a given Path contains "!"
LIBUTIL_EXPORT bool checkProblemticPathJava(QDir folder);

View File

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

View File

@@ -0,0 +1,150 @@
#include "include/modutils.h"
#include <QStringList>
#include <QUrl>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
Util::Version::Version(const QString &str) : m_string(str)
{
parse();
}
bool Util::Version::operator<(const Version &other) const
{
const int size = qMax(m_sections.size(), other.m_sections.size());
for (int i = 0; i < size; ++i)
{
const Section sec1 = (i >= m_sections.size()) ? Section("0", 0) : m_sections.at(i);
const Section sec2 =
(i >= other.m_sections.size()) ? Section("0", 0) : other.m_sections.at(i);
if (sec1 != sec2)
{
return sec1 < sec2;
}
}
return false;
}
bool Util::Version::operator<=(const Util::Version &other) const
{
return *this < other || *this == other;
}
bool Util::Version::operator>(const Version &other) const
{
const int size = qMax(m_sections.size(), other.m_sections.size());
for (int i = 0; i < size; ++i)
{
const Section sec1 = (i >= m_sections.size()) ? Section("0", 0) : m_sections.at(i);
const Section sec2 =
(i >= other.m_sections.size()) ? Section("0", 0) : other.m_sections.at(i);
if (sec1 != sec2)
{
return sec1 > sec2;
}
}
return false;
}
bool Util::Version::operator>=(const Version &other) const
{
return *this > other || *this == other;
}
bool Util::Version::operator==(const Version &other) const
{
const int size = qMax(m_sections.size(), other.m_sections.size());
for (int i = 0; i < size; ++i)
{
const Section sec1 = (i >= m_sections.size()) ? Section("0", 0) : m_sections.at(i);
const Section sec2 =
(i >= other.m_sections.size()) ? Section("0", 0) : other.m_sections.at(i);
if (sec1 != sec2)
{
return false;
}
}
return true;
}
bool Util::Version::operator!=(const Version &other) const
{
return !operator==(other);
}
void Util::Version::parse()
{
m_sections.clear();
QStringList parts = m_string.split('.');
for (const auto part : parts)
{
bool ok = false;
int num = part.toInt(&ok);
if (ok)
{
m_sections.append(Section(part, num));
}
else
{
m_sections.append(Section(part));
}
}
}
bool Util::versionIsInInterval(const QString &version, const QString &interval)
{
return versionIsInInterval(Util::Version(version), interval);
}
bool Util::versionIsInInterval(const Version &version, const QString &interval)
{
if (interval.isEmpty() || version.toString() == interval)
{
return true;
}
// Interval notation is used
QRegularExpression exp(
"(?<start>[\\[\\]\\(\\)])(?<bottom>.*?)(,(?<top>.*?))?(?<end>[\\[\\]\\(\\)]),?");
QRegularExpressionMatch match = exp.match(interval);
if (match.hasMatch())
{
const QChar start = match.captured("start").at(0);
const QChar end = match.captured("end").at(0);
const QString bottom = match.captured("bottom");
const QString top = match.captured("top");
// check if in range (bottom)
if (!bottom.isEmpty())
{
const auto bottomVersion = Util::Version(bottom);
if ((start == '[') && !(version >= bottomVersion))
{
return false;
}
else if ((start == '(') && !(version > bottomVersion))
{
return false;
}
}
// check if in range (top)
if (!top.isEmpty())
{
const auto topVersion = Util::Version(top);
if ((end == ']') && !(version <= topVersion))
{
return false;
}
else if ((end == ')') && !(version < topVersion))
{
return false;
}
}
return true;
}
return false;
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,7 +19,6 @@
#include <QDir>
#include <QDesktopServices>
#include <QUrl>
#include <QDebug>
QString PathCombine(QString path1, QString path2)
{
@@ -138,10 +137,18 @@ void openDirInDefaultProgram(QString path, bool ensureExists)
{
parentPath.mkpath(dir.absolutePath());
}
QDesktopServices::openUrl("file:///" + dir.absolutePath());
QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath()));
}
void openFileInDefaultProgram(QString filename)
{
QDesktopServices::openUrl("file:///" + QFileInfo(filename).absolutePath());
QDesktopServices::openUrl(QUrl::fromLocalFile(filename));
}
// Does the directory path contain any '!'? If yes, return true, otherwise false.
// (This is a problem for Java)
bool checkProblemticPathJava(QDir folder)
{
QString pathfoldername = folder.absolutePath();
return pathfoldername.contains("!", Qt::CaseInsensitive);
}

View File

@@ -75,7 +75,6 @@ bool Util::createShortCut(QString location, QString dest, QStringList args, QStr
{
#if LINUX
location = PathCombine(location, name + ".desktop");
qDebug("location: %s", qPrintable(location));
QFile f(location);
f.open(QIODevice::WriteOnly | QIODevice::Text);

View File

@@ -8,22 +8,22 @@ option(XZ_BUILD_MINIDEC "Build a tiny utility that decompresses xz streams" OFF)
set(CMAKE_C_FLAGS "-std=c99")
include_directories(include)
SET(XZ_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE)
set(XZ_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE)
# See include/xz.h for manual feature configuration
# tweak this list and xz.h to fit your needs
set(XZ_SOURCES
include/xz.h
src/xz_config.h
src/xz_crc32.c
src/xz_crc64.c
src/xz_dec_lzma2.c
src/xz_dec_stream.c
src/xz_lzma2.h
src/xz_private.h
src/xz_stream.h
# src/xz_dec_bcj.c
include/xz.h
src/xz_config.h
src/xz_crc32.c
src/xz_crc64.c
src/xz_dec_lzma2.c
src/xz_dec_stream.c
src/xz_lzma2.h
src/xz_private.h
src/xz_stream.h
# src/xz_dec_bcj.c
)
# TODO: look into what would be needed for plain old lzma

View File

@@ -1,8 +0,0 @@
<RCC>
<!--
<qresource prefix="/java">
<file alias="launcher.jar">@MMC_BIN@/depends/launcher/MultiMCLauncher.jar</file>
<file alias="checker.jar">@MMC_BIN@/depends/javacheck/JavaCheck.jar</file>
</qresource>
-->
</RCC>

View File

@@ -1,51 +0,0 @@
<RCC>
<qresource prefix="/icons/toolbar">
<file alias="about">resources/icons/toolbar/about.png</file>
<file alias="bug">resources/icons/toolbar/ReportBug.png</file>
<file alias="centralmods">resources/icons/toolbar/centralmods.png</file>
<file alias="checkupdate">resources/icons/toolbar/checkupdate.png</file>
<file alias="help">resources/icons/toolbar/help.png</file>
<file alias="new">resources/icons/toolbar/new.png</file>
<file alias="copy">resources/icons/toolbar/InstCopy.png</file>
<file alias="news">resources/icons/toolbar/NewsIcon.png</file>
<file alias="refresh">resources/icons/toolbar/refresh.png</file>
<file alias="settings">resources/icons/toolbar/settings.png</file>
<file alias="viewfolder">resources/icons/toolbar/viewfolder.png</file>
<file alias="cat">resources/icons/toolbar/Cat.png</file>
<file alias="noaccount">resources/icons/toolbar/NoAccount.png</file>
</qresource>
<qresource prefix="/icons/instances">
<file alias="brick">resources/icons/instances/brick.png</file>
<file alias="chicken">resources/icons/instances/chicken128.png</file>
<file alias="creeper">resources/icons/instances/creeper128.png</file>
<file alias="derp">resources/icons/instances/derp.png</file>
<file alias="diamond">resources/icons/instances/diamond.png</file>
<file alias="dirt">resources/icons/instances/dirt.png</file>
<file alias="enderman">resources/icons/instances/enderman.png</file>
<file alias="enderpearl">resources/icons/instances/enderpearl128.png</file>
<file alias="ftb-glow">resources/icons/instances/ftb_glow128.png</file>
<file alias="ftb-logo">resources/icons/instances/ftb_logo128.png</file>
<file alias="gear">resources/icons/instances/gear128.png</file>
<file alias="gold">resources/icons/instances/gold.png</file>
<file alias="grass">resources/icons/instances/grass.png</file>
<file alias="herobrine">resources/icons/instances/herobrine128.png</file>
<file alias="infinity">resources/icons/instances/infinity128.png</file>
<file alias="iron">resources/icons/instances/iron.png</file>
<file alias="magitech">resources/icons/instances/magitech128.png</file>
<file alias="meat">resources/icons/instances/meat128.png</file>
<file alias="netherstar">resources/icons/instances/netherstar128.png</file>
<file alias="planks">resources/icons/instances/planks.png</file>
<file alias="skeleton">resources/icons/instances/skeleton128.png</file>
<file alias="squarecreeper">resources/icons/instances/squarecreeper128.png</file>
<file alias="steve">resources/icons/instances/steve128.png</file>
<file alias="stone">resources/icons/instances/stone.png</file>
<file alias="tnt">resources/icons/instances/tnt.png</file>
</qresource>
<qresource prefix="/icons/multimc">
<file alias="scalable/apps/multimc.svg">resources/icons/multimc.svg</file>
<file alias="index.theme">resources/XdgIcon.theme</file>
</qresource>
<qresource prefix="/backgrounds">
<file alias="kitteh">resources/catbgrnd2.png</file>
</qresource>
</RCC>

202
gui/ColumnResizer.cpp Normal file
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

38
gui/ColumnResizer.h Normal file
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

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,61 +14,131 @@
*/
#include "ConsoleWindow.h"
#include "ui_ConsoleWindow.h"
#include "MultiMC.h"
#include <QScrollBar>
#include <QMessageBox>
#include <QSystemTrayIcon>
#include <QHBoxLayout>
#include <QPushButton>
#include <qlayoutitem.h>
#include <gui/Platform.h>
#include <gui/dialogs/CustomMessageBox.h>
#include <gui/dialogs/ProgressDialog.h>
#include "widgets/PageContainer.h"
#include "pages/LogPage.h"
#include "logic/net/PasteUpload.h"
#include "logic/icons/IconList.h"
class LogPageProvider : public BasePageProvider
{
public:
LogPageProvider(BasePageProviderPtr parent, BasePage * log_page)
{
m_parent = parent;
m_log_page = log_page;
}
virtual QString dialogTitle() {return "Fake";};
virtual QList<BasePage *> getPages()
{
auto pages = m_parent->getPages();
pages.prepend(m_log_page);
return pages;
}
private:
BasePageProviderPtr m_parent;
BasePage * m_log_page;
};
ConsoleWindow::ConsoleWindow(MinecraftProcess *mcproc, QWidget *parent)
: QMainWindow(parent), ui(new Ui::ConsoleWindow), proc(mcproc)
: QMainWindow(parent), m_proc(mcproc)
{
MultiMCPlatform::fixWM_CLASS(this);
ui->setupUi(this);
connect(mcproc, SIGNAL(log(QString, MessageLevel::Enum)), this,
SLOT(write(QString, MessageLevel::Enum)));
connect(mcproc, SIGNAL(ended(BaseInstance *, int, QProcess::ExitStatus)), this,
SLOT(onEnded(BaseInstance *, int, QProcess::ExitStatus)));
connect(mcproc, SIGNAL(prelaunch_failed(BaseInstance *, int, QProcess::ExitStatus)), this,
SLOT(onEnded(BaseInstance *, int, QProcess::ExitStatus)));
connect(mcproc, SIGNAL(launch_failed(BaseInstance *)), this,
SLOT(onLaunchFailed(BaseInstance *)));
setAttribute(Qt::WA_DeleteOnClose);
restoreState(
QByteArray::fromBase64(MMC->settings()->get("ConsoleWindowState").toByteArray()));
restoreGeometry(
QByteArray::fromBase64(MMC->settings()->get("ConsoleWindowGeometry").toByteArray()));
auto instance = m_proc->instance();
auto icon = MMC->icons()->getIcon(instance->iconKey());
QString windowTitle = tr("Console window for ") + instance->name();
QString iconKey = proc->instance()->iconKey();
QString name = proc->instance()->name();
auto icon = MMC->icons()->getIcon(iconKey);
setWindowIcon(icon);
m_trayIcon = new QSystemTrayIcon(icon, this);
QString consoleTitle = tr("Console window for ") + name;
m_trayIcon->setToolTip(consoleTitle);
setWindowTitle(consoleTitle);
// Set window properties
{
setWindowIcon(icon);
setWindowTitle(windowTitle);
}
// Add page container
{
auto mainLayout = new QVBoxLayout;
auto provider = std::dynamic_pointer_cast<BasePageProvider>(m_proc->instance());
auto proxy_provider = std::make_shared<LogPageProvider>(provider, new LogPage(m_proc));
m_container = new PageContainer(proxy_provider, "console", this);
mainLayout->addWidget(m_container);
mainLayout->setSpacing(0);
mainLayout->setContentsMargins(0,0,0,0);
setLayout(mainLayout);
setCentralWidget(m_container);
}
// Add custom buttons to the page container layout.
{
auto horizontalLayout = new QHBoxLayout();
horizontalLayout->setObjectName(QStringLiteral("horizontalLayout"));
horizontalLayout->setContentsMargins(6, -1, 6, -1);
auto btnHelp = new QPushButton();
btnHelp->setText(tr("Help"));
horizontalLayout->addWidget(btnHelp);
connect(btnHelp, SIGNAL(clicked(bool)), m_container, SLOT(help()));
auto spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
horizontalLayout->addSpacerItem(spacer);
m_killButton = new QPushButton();
m_killButton->setText(tr("Kill Minecraft"));
horizontalLayout->addWidget(m_killButton);
connect(m_killButton, SIGNAL(clicked(bool)), SLOT(on_btnKillMinecraft_clicked()));
m_closeButton = new QPushButton();
m_closeButton->setText(tr("Close"));
horizontalLayout->addWidget(m_closeButton);
connect(m_closeButton, SIGNAL(clicked(bool)), SLOT(on_closeButton_clicked()));
m_container->addButtons(horizontalLayout);
}
// restore window state
{
auto base64State = MMC->settings()->get("ConsoleWindowState").toByteArray();
restoreState(QByteArray::fromBase64(base64State));
auto base64Geometry = MMC->settings()->get("ConsoleWindowGeometry").toByteArray();
restoreGeometry(QByteArray::fromBase64(base64Geometry));
}
// Set up tray icon
{
m_trayIcon = new QSystemTrayIcon(icon, this);
m_trayIcon->setToolTip(windowTitle);
connect(m_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
m_trayIcon->show();
}
// Set up signal connections
connect(mcproc, SIGNAL(ended(InstancePtr, int, QProcess::ExitStatus)), this,
SLOT(onEnded(InstancePtr, int, QProcess::ExitStatus)));
connect(mcproc, SIGNAL(prelaunch_failed(InstancePtr, int, QProcess::ExitStatus)), this,
SLOT(onEnded(InstancePtr, int, QProcess::ExitStatus)));
connect(mcproc, SIGNAL(launch_failed(InstancePtr)), this,
SLOT(onLaunchFailed(InstancePtr)));
setMayClose(false);
connect(m_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
m_trayIcon->show();
if (mcproc->instance()->settings().get("ShowConsole").toBool())
{
show();
}
setMayClose(false);
}
ConsoleWindow::~ConsoleWindow()
{
delete ui;
}
void ConsoleWindow::iconActivated(QSystemTrayIcon::ActivationReason reason)
@@ -84,81 +154,6 @@ void ConsoleWindow::iconActivated(QSystemTrayIcon::ActivationReason reason)
}
}
void ConsoleWindow::writeColor(QString text, const char *color)
{
// append a paragraph
QString newtext;
newtext += "<span style=\"";
{
if (color)
newtext += QString("color:") + color + ";";
newtext += "font-family: monospace;";
}
newtext += "\">";
newtext += text.toHtmlEscaped();
newtext += "</span>";
ui->text->appendHtml(newtext);
}
void ConsoleWindow::write(QString data, MessageLevel::Enum mode)
{
QScrollBar *bar = ui->text->verticalScrollBar();
int max_bar = bar->maximum();
int val_bar = bar->value();
if(isVisible())
{
if (m_scroll_active)
{
m_scroll_active = (max_bar - val_bar) <= 1;
}
else
{
m_scroll_active = val_bar == max_bar;
}
}
if (data.endsWith('\n'))
data = data.left(data.length() - 1);
QStringList paragraphs = data.split('\n');
for (QString &paragraph : paragraphs)
{
paragraph = paragraph.trimmed();
}
QListIterator<QString> iter(paragraphs);
if (mode == MessageLevel::MultiMC)
while (iter.hasNext())
writeColor(iter.next(), "blue");
else if (mode == MessageLevel::Error)
while (iter.hasNext())
writeColor(iter.next(), "red");
else if (mode == MessageLevel::Warning)
while (iter.hasNext())
writeColor(iter.next(), "orange");
else if (mode == MessageLevel::Fatal)
while (iter.hasNext())
writeColor(iter.next(), "pink");
else if (mode == MessageLevel::Debug)
while (iter.hasNext())
writeColor(iter.next(), "green");
// TODO: implement other MessageLevels
else
while (iter.hasNext())
writeColor(iter.next());
if(isVisible())
{
if (m_scroll_active)
{
bar->setValue(bar->maximum());
}
m_last_scroll_value = bar->value();
}
}
void ConsoleWindow::clear()
{
ui->text->clear();
}
void ConsoleWindow::on_closeButton_clicked()
{
close();
@@ -166,22 +161,34 @@ void ConsoleWindow::on_closeButton_clicked()
void ConsoleWindow::setMayClose(bool mayclose)
{
if(mayclose)
m_closeButton->setText(tr("Close"));
else
m_closeButton->setText(tr("Hide"));
m_mayclose = mayclose;
}
void ConsoleWindow::toggleConsole()
{
QScrollBar *bar = ui->text->verticalScrollBar();
//QScrollBar *bar = ui->text->verticalScrollBar();
if (isVisible())
{
if(!isActiveWindow())
{
activateWindow();
return;
}
/*
int max_bar = bar->maximum();
int val_bar = m_last_scroll_value = bar->value();
m_scroll_active = (max_bar - val_bar) <= 1;
*/
hide();
}
else
{
show();
/*
if (m_scroll_active)
{
bar->setValue(bar->maximum());
@@ -190,6 +197,7 @@ void ConsoleWindow::toggleConsole()
{
bar->setValue(m_last_scroll_value);
}
*/
}
}
@@ -199,7 +207,7 @@ void ConsoleWindow::closeEvent(QCloseEvent *event)
{
toggleConsole();
}
else
else if(m_container->requestClose(event))
{
MMC->settings()->set("ConsoleWindowState", saveState().toBase64());
MMC->settings()->set("ConsoleWindowGeometry", saveGeometry().toBase64());
@@ -212,25 +220,23 @@ void ConsoleWindow::closeEvent(QCloseEvent *event)
void ConsoleWindow::on_btnKillMinecraft_clicked()
{
ui->btnKillMinecraft->setEnabled(false);
m_killButton->setEnabled(false);
auto response = CustomMessageBox::selectable(
this, tr("Kill Minecraft?"),
tr("This can cause the instance to get corrupted and should only be used if Minecraft "
"is frozen for some reason"),
QMessageBox::Question, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)->exec();
if (response == QMessageBox::Yes)
proc->killMinecraft();
m_proc->killMinecraft();
else
ui->btnKillMinecraft->setEnabled(true);
m_killButton->setEnabled(true);
}
void ConsoleWindow::onEnded(BaseInstance *instance, int code, QProcess::ExitStatus status)
void ConsoleWindow::onEnded(InstancePtr instance, int code, QProcess::ExitStatus status)
{
bool peacefulExit = code == 0 && status != QProcess::CrashExit;
ui->btnKillMinecraft->setEnabled(false);
m_killButton->setEnabled(false);
setMayClose(true);
if (instance->settings().get("AutoCloseConsole").toBool())
{
if (peacefulExit)
@@ -239,35 +245,26 @@ void ConsoleWindow::onEnded(BaseInstance *instance, int code, QProcess::ExitStat
return;
}
}
/*
if(!peacefulExit)
{
m_trayIcon->showMessage(tr("Oh no!"), tr("Minecraft crashed!"), QSystemTrayIcon::Critical);
}
*/
if (!isVisible())
show();
// Raise Window
if (MMC->settings()->get("RaiseConsole").toBool())
{
raise();
activateWindow();
}
}
void ConsoleWindow::onLaunchFailed(BaseInstance *instance)
void ConsoleWindow::onLaunchFailed(InstancePtr instance)
{
ui->btnKillMinecraft->setEnabled(false);
m_killButton->setEnabled(false);
setMayClose(true);
if (!isVisible())
show();
}
void ConsoleWindow::on_btnPaste_clicked()
ConsoleWindow::~ConsoleWindow()
{
auto text = ui->text->toPlainText();
ProgressDialog dialog(this);
PasteUpload *paste = new PasteUpload(this, text);
dialog.exec(paste);
if (!paste->successful())
{
CustomMessageBox::selectable(this, "Upload failed", paste->failReason(),
QMessageBox::Critical)->exec();
}
}

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,18 +19,15 @@
#include <QSystemTrayIcon>
#include "logic/MinecraftProcess.h"
namespace Ui
{
class ConsoleWindow;
}
class QPushButton;
class PageContainer;
class ConsoleWindow : public QMainWindow
{
Q_OBJECT
public:
explicit ConsoleWindow(MinecraftProcess *proc, QWidget *parent = 0);
~ConsoleWindow();
virtual ~ConsoleWindow();
/**
* @brief specify if the window is allowed to close
@@ -39,56 +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;
MinecraftProcess *m_proc = nullptr;
bool m_mayclose = true;
int m_last_scroll_value = 0;
bool m_scroll_active = true;
QSystemTrayIcon *m_trayIcon = nullptr;
int m_saved_offset = 0;
PageContainer *m_container = nullptr;
QPushButton *m_closeButton = nullptr;
QPushButton *m_killButton = nullptr;
};

View File

@@ -1,86 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ConsoleWindow</class>
<widget class="QMainWindow" name="ConsoleWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>640</width>
<height>440</height>
</rect>
</property>
<property name="windowTitle">
<string>MultiMC Console</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPlainTextEdit" name="text">
<property name="undoRedoEnabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="plainText">
<string notr="true"/>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
<property name="centerOnScroll">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<item>
<widget class="QPushButton" name="btnPaste">
<property name="text">
<string>Upload Log</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnKillMinecraft">
<property name="text">
<string>&amp;Kill Minecraft</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="closeButton">
<property name="text">
<string>&amp;Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

38
gui/GuiUtil.cpp Normal file
View File

@@ -0,0 +1,38 @@
#include "GuiUtil.h"
#include <QClipboard>
#include <QDesktopServices>
#include <QApplication>
#include "dialogs/ProgressDialog.h"
#include "logic/net/PasteUpload.h"
#include "dialogs/CustomMessageBox.h"
void GuiUtil::uploadPaste(const QString &text, QWidget *parentWidget)
{
ProgressDialog dialog(parentWidget);
PasteUpload *paste = new PasteUpload(parentWidget, text);
dialog.exec(paste);
if (!paste->successful())
{
CustomMessageBox::selectable(parentWidget, "Upload failed", paste->failReason(),
QMessageBox::Critical)->exec();
}
else
{
const QString link = paste->pasteLink();
setClipboardText(link);
QDesktopServices::openUrl(link);
CustomMessageBox::selectable(
parentWidget, QObject::tr("Upload finished"),
QObject::tr("The <a href=\"%1\">link to the uploaded log</a> has been opened in the default "
"browser and placed in your clipboard.").arg(link),
QMessageBox::Information)->exec();
}
delete paste;
}
void GuiUtil::setClipboardText(const QString &text)
{
QApplication::clipboard()->setText(text);
}

9
gui/GuiUtil.h Normal file
View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,20 +17,20 @@
#include <QMainWindow>
#include <QProcess>
#include <QTimer>
#include "logic/lists/InstanceList.h"
#include "logic/InstanceList.h"
#include "logic/BaseInstance.h"
#include "logic/auth/MojangAccount.h"
#include "logic/net/NetJob.h"
class QToolButton;
class LabeledToolButton;
class QLabel;
class InstanceProxyModel;
class KCategorizedView;
class KCategoryDrawer;
class MinecraftProcess;
class ConsoleWindow;
class BaseProfilerFactory;
class GenericPageProvider;
namespace Ui
{
@@ -52,6 +52,7 @@ public:
void checkSetDefaultJava();
void checkMigrateLegacyAssets();
void checkInstancePathForProblems();
private
slots:
@@ -81,10 +82,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,58 +100,50 @@ slots:
void on_actionLaunchInstance_triggered();
void on_actionLaunchInstanceOffline_triggered();
void on_actionDeleteInstance_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);
@@ -159,6 +156,8 @@ slots:
void updateAvailable(QString repo, QString versionName, int versionId);
void updateNotAvailable();
void notificationsChanged();
void activeAccountChanged();
@@ -168,11 +167,11 @@ slots:
void repopulateAccountsMenu();
void updateNewsLabel();
/*!
* Runs the DownloadUpdateTask and installs updates.
*/
void downloadUpdates(QString repo, int versionId, bool installOnExit=false);
void downloadUpdates(QString repo, int versionId, bool installOnExit = false);
protected:
bool eventFilter(QObject *obj, QEvent *ev);
@@ -183,21 +182,24 @@ protected:
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;
InstancePtr m_selectedInstance;
QString m_currentInstIcon;
Task *m_versionLoadTask;
QLabel *m_statusLeft;
class ServerStatus *m_statusRight;
QMenu *accountMenu;
QToolButton *accountMenuButton;

View File

@@ -6,16 +6,15 @@
<rect>
<x>0</x>
<y>0</y>
<width>688</width>
<height>460</height>
<width>694</width>
<height>563</height>
</rect>
</property>
<property name="windowTitle">
<string>MultiMC 5</string>
</property>
<property name="windowIcon">
<iconset resource="../graphics.qrc">
<normaloff>:/icons/multimc/scalable/apps/multimc.svg</normaloff>:/icons/multimc/scalable/apps/multimc.svg</iconset>
<iconset theme="multimc"/>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QHBoxLayout" name="horizontalLayout">
@@ -74,6 +73,7 @@
<addaction name="actionReportBug"/>
<addaction name="actionAbout"/>
<addaction name="separator"/>
<addaction name="actionPatreon"/>
<addaction name="actionCAT"/>
</widget>
<widget class="QStatusBar" name="statusBar"/>
@@ -107,14 +107,14 @@
</attribute>
<addaction name="actionChangeInstIcon"/>
<addaction name="actionLaunchInstance"/>
<addaction name="separator"/>
<addaction name="actionEditInstNotes"/>
<addaction name="actionLaunchInstanceOffline"/>
<addaction name="actionChangeInstGroup"/>
<addaction name="separator"/>
<addaction name="actionEditInstance"/>
<addaction name="actionInstanceSettings"/>
<addaction name="actionChangeInstMCVersion"/>
<addaction name="actionChangeInstLWJGLVersion"/>
<addaction name="actionEditInstMods"/>
<addaction name="actionEditInstNotes"/>
<addaction name="actionScreenshots"/>
<addaction name="separator"/>
<addaction name="actionViewSelectedInstFolder"/>
<addaction name="actionConfig_Folder"/>
<addaction name="separator"/>
@@ -152,8 +152,9 @@
</widget>
<action name="actionAddInstance">
<property name="icon">
<iconset resource="../graphics.qrc">
<normaloff>:/icons/toolbar/new</normaloff>:/icons/toolbar/new</iconset>
<iconset theme="new">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>Add Instance</string>
@@ -167,8 +168,9 @@
</action>
<action name="actionViewInstanceFolder">
<property name="icon">
<iconset resource="../graphics.qrc">
<normaloff>:/icons/toolbar/viewfolder</normaloff>:/icons/toolbar/viewfolder</iconset>
<iconset theme="viewfolder">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>View Instance Folder</string>
@@ -182,8 +184,9 @@
</action>
<action name="actionRefresh">
<property name="icon">
<iconset resource="../graphics.qrc">
<normaloff>:/icons/toolbar/refresh</normaloff>:/icons/toolbar/refresh</iconset>
<iconset theme="refresh">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>Refresh</string>
@@ -197,8 +200,9 @@
</action>
<action name="actionViewCentralModsFolder">
<property name="icon">
<iconset resource="../graphics.qrc">
<normaloff>:/icons/toolbar/centralmods</normaloff>:/icons/toolbar/centralmods</iconset>
<iconset theme="centralmods">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>View Central Mods Folder</string>
@@ -212,8 +216,9 @@
</action>
<action name="actionCheckUpdate">
<property name="icon">
<iconset resource="../graphics.qrc">
<normaloff>:/icons/toolbar/checkupdate</normaloff>:/icons/toolbar/checkupdate</iconset>
<iconset theme="checkupdate">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>Check for Updates</string>
@@ -227,8 +232,9 @@
</action>
<action name="actionSettings">
<property name="icon">
<iconset resource="../graphics.qrc">
<normaloff>:/icons/toolbar/settings</normaloff>:/icons/toolbar/settings</iconset>
<iconset theme="settings">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>Settings</string>
@@ -245,8 +251,9 @@
</action>
<action name="actionReportBug">
<property name="icon">
<iconset resource="../graphics.qrc">
<normaloff>:/icons/toolbar/bug</normaloff>:/icons/toolbar/bug</iconset>
<iconset theme="bug">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>Report a Bug</string>
@@ -258,10 +265,27 @@
<string>Open the bug tracker to report a bug with MultiMC.</string>
</property>
</action>
<action name="actionPatreon">
<property name="icon">
<iconset theme="patreon">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>Support us on Patreon!</string>
</property>
<property name="toolTip">
<string>Open the MultiMC Patreon page.</string>
</property>
<property name="statusTip">
<string>Open the MultiMC Patreon page.</string>
</property>
</action>
<action name="actionMoreNews">
<property name="icon">
<iconset resource="../graphics.qrc">
<normaloff>:/icons/toolbar/news</normaloff>:/icons/toolbar/news</iconset>
<iconset theme="news">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>More News</string>
@@ -278,8 +302,9 @@
</action>
<action name="actionAbout">
<property name="icon">
<iconset resource="../graphics.qrc">
<normaloff>:/icons/toolbar/about</normaloff>:/icons/toolbar/about</iconset>
<iconset theme="about">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>About MultiMC</string>
@@ -332,7 +357,7 @@
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../graphics.qrc">
<iconset resource="../resources/instances/instances.qrc">
<normaloff>:/icons/instances/infinity</normaloff>:/icons/instances/infinity</iconset>
</property>
<property name="text">
@@ -359,82 +384,18 @@
<string>Edit the notes for the selected instance.</string>
</property>
</action>
<action name="actionInstanceSettings">
<property name="enabled">
<bool>true</bool>
</property>
<action name="actionEditInstance">
<property name="text">
<string>Settings</string>
<string>Edit Instance</string>
</property>
<property name="iconText">
<string>Edit Instance</string>
</property>
<property name="toolTip">
<string>Change settings for the selected instance.</string>
<string>Change the instance settings, mods and versions.</string>
</property>
<property name="statusTip">
<string>Change settings for the selected instance.</string>
</property>
</action>
<action name="actionMakeDesktopShortcut">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Make Shortcut</string>
</property>
<property name="toolTip">
<string>Make a shortcut on the desktop for the selected instance.</string>
</property>
<property name="statusTip">
<string>Make a shortcut on the desktop for the selected instance.</string>
</property>
</action>
<action name="actionManageInstSaves">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Manage Saves</string>
</property>
<property name="toolTip">
<string>Manage saves for the selected instance.</string>
</property>
<property name="statusTip">
<string>Manage saves for the selected instance.</string>
</property>
</action>
<action name="actionEditInstMods">
<property name="text">
<string>Edit Mods</string>
</property>
<property name="toolTip">
<string>Edit the mods for the selected instance.</string>
</property>
<property name="statusTip">
<string>Edit the mods for the selected instance.</string>
</property>
</action>
<action name="actionChangeInstMCVersion">
<property name="text">
<string>Change Version</string>
</property>
<property name="toolTip">
<string>Change the selected instance's Minecraft version.</string>
</property>
<property name="statusTip">
<string>Change the selected instance's Minecraft version.</string>
</property>
</action>
<action name="actionChangeInstLWJGLVersion">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Change LWJGL</string>
</property>
<property name="toolTip">
<string>Change the version of LWJGL for the selected instance to use.</string>
</property>
<property name="statusTip">
<string>Change the version of LWJGL for the selected instance to use.</string>
<string>Change the instance settings, mods and versions.</string>
</property>
</action>
<action name="actionViewSelectedInstFolder">
@@ -472,20 +433,22 @@
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../graphics.qrc">
<normaloff>:/icons/toolbar/cat</normaloff>:/icons/toolbar/cat</iconset>
<iconset theme="cat">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>Meow</string>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-weight:600; color:#ff0004;&quot;&gt;Catnarok!&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;Or just a cat with a ball of yarn?&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;WHO KNOWS?!&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;:/icons/instances/tnt&quot;/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;It's a fluffy kitty :3&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</action>
<action name="actionCopyInstance">
<property name="icon">
<iconset resource="../graphics.qrc">
<normaloff>:/icons/toolbar/copy</normaloff>:/icons/toolbar/copy</iconset>
<iconset theme="copy">
<normaloff/>
</iconset>
</property>
<property name="text">
<string>Copy Instance</string>
@@ -505,10 +468,44 @@
<string>Manage your Mojang or Minecraft accounts.</string>
</property>
</action>
<action name="actionLaunchInstanceOffline">
<property name="text">
<string>Play Offline</string>
</property>
<property name="toolTip">
<string>Launch the selected instance in offline mode.</string>
</property>
<property name="statusTip">
<string>Launch the selected instance.</string>
</property>
</action>
<action name="actionScreenshots">
<property name="text">
<string>Manage Screenshots</string>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;View and upload screenshots for this instance&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</action>
<action name="actionInstanceSettings">
<property name="text">
<string>Instance Settings</string>
</property>
<property name="toolTip">
<string>Change the settings specific to the instance</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>
<include location="../graphics.qrc"/>
<include location="../resources/pe_dark/pe_dark.qrc"/>
<include location="../resources/pe_light/pe_light.qrc"/>
<include location="../resources/pe_blue/pe_blue.qrc"/>
<include location="../resources/pe_colored/pe_colored.qrc"/>
<include location="../resources/multimc/multimc.qrc"/>
<include location="../resources/instances/instances.qrc"/>
<include location="../resources/OSX/OSX.qrc"/>
<include location="../resources/iOS/iOS.qrc"/>
</resources>
<connections/>
</ui>

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,35 +18,111 @@
#include <QIcon>
#include "MultiMC.h"
#include "gui/Platform.h"
#include "BuildConfig.h"
#include <logic/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);
ui->icon->setPixmap(QIcon(":/icons/multimc/scalable/apps/multimc.svg").pixmap(64));
ui->title->setText("MultiMC 5 " + MMC->version().toString());
QString chtml = getCreditsHtml(QStringList());
ui->creditsText->setHtml(chtml);
ui->versionLabel->setText(tr("Version") +": " + MMC->version().toString());
ui->vtypeLabel->setText(tr("Version Type") +": " + MMC->version().typeName());
ui->platformLabel->setText(tr("Platform") +": " + MMC->version().platform);
ui->urlLabel->setOpenExternalLinks(true);
if (MMC->version().build >= 0)
ui->buildNumLabel->setText(tr("Build Number") +": " + QString::number(MMC->version().build));
ui->icon->setPixmap(QIcon::fromTheme("multimc").pixmap(64));
ui->title->setText("MultiMC 5 " + BuildConfig.printableVersionString());
ui->versionLabel->setText(tr("Version") +": " + BuildConfig.printableVersionString());
ui->vtypeLabel->setText(tr("Version Type") +": " + BuildConfig.versionTypeName());
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 (!MMC->version().channel.isEmpty())
ui->channelLabel->setText(tr("Channel") +": " + MMC->version().channel);
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()));
MMC->connect(ui->aboutQt, SIGNAL(clicked()), SLOT(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-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,8 @@
#include <QDialog>
#include <logic/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>
@@ -104,7 +101,7 @@
<x>0</x>
<y>0</y>
<width>689</width>
<height>331</height>
<height>311</height>
</rect>
</property>
<attribute name="label">
@@ -186,7 +183,7 @@
</font>
</property>
<property name="text">
<string>© 2013 MultiMC Contributors</string>
<string>© 2013-2014 MultiMC Contributors</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
@@ -201,7 +198,7 @@
</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>
@@ -229,7 +226,7 @@
<x>0</x>
<y>0</y>
<width>689</width>
<height>331</height>
<height>311</height>
</rect>
</property>
<attribute name="label">
@@ -245,22 +242,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:'Sans Serif'; font-size:9pt; 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:'MS Shell Dlg 2'; 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-family:'MS Shell Dlg 2'; 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-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;forkk@forkk.net&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; 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-family:'MS Shell Dlg 2'; 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-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;peterix@gmail.com&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; 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-family:'MS Shell Dlg 2'; 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-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;@drayshak&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; 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-family:'MS Shell Dlg 2'; 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-family:'MS Shell Dlg 2'; 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-family:'MS Shell Dlg 2'; 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-family:'MS Shell Dlg 2'; 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-family:'MS Shell Dlg 2'; 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-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;taksuyu@gmail.com&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; 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-family:'MS Shell Dlg 2'; 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-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;stiepen22@gmx.de&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; 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-family:'MS Shell Dlg 2'; 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-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;02jandal@gmail.com&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; 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-family:'MS Shell Dlg 2'; 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-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;@skylordelros&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; 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-family:'MS Shell Dlg 2'; 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-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;&quot;&gt;@rootbear75&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; 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:'Bitstream Vera 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>
@@ -282,7 +268,7 @@ p, li { white-space: pre-wrap; }
<x>0</x>
<y>0</y>
<width>689</width>
<height>331</height>
<height>311</height>
</rect>
</property>
<attribute name="label">
@@ -309,7 +295,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:9pt; 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;
@@ -370,7 +356,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;
@@ -430,8 +433,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>
@@ -442,7 +482,7 @@ p, li { white-space: pre-wrap; }
<x>0</x>
<y>0</y>
<width>689</width>
<height>331</height>
<height>311</height>
</rect>
</property>
<attribute name="label">
@@ -455,12 +495,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:'Sans Serif'; font-size:9pt; 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:'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;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;/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;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;/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;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 style=&quot; font-weight:600;&quot;&gt;without&lt;/span&gt; implying that you have our blessing.&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>
@@ -508,7 +548,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,160 +0,0 @@
/* Copyright 2013 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "AccountListDialog.h"
#include "ui_AccountListDialog.h"
#include <QItemSelectionModel>
#include <logger/QsLog.h>
#include <logic/net/NetJob.h>
#include <logic/net/URLConstants.h>
#include <gui/dialogs/EditAccountDialog.h>
#include <gui/dialogs/ProgressDialog.h>
#include <gui/dialogs/AccountSelectDialog.h>
#include "CustomMessageBox.h"
#include <logic/tasks/Task.h>
#include <logic/auth/YggdrasilTask.h>
#include <MultiMC.h>
AccountListDialog::AccountListDialog(QWidget *parent)
: QDialog(parent), ui(new Ui::AccountListDialog)
{
ui->setupUi(this);
m_accounts = MMC->accounts();
ui->listView->setModel(m_accounts.get());
ui->listView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
// Expand the account column
ui->listView->header()->setSectionResizeMode(1, QHeaderView::Stretch);
QItemSelectionModel* selectionModel = ui->listView->selectionModel();
connect(selectionModel, &QItemSelectionModel::selectionChanged,
[this] (const QItemSelection& sel, const QItemSelection& dsel) { updateButtonStates(); });
connect(m_accounts.get(), SIGNAL(listChanged()), SLOT(listChanged()));
connect(m_accounts.get(), SIGNAL(activeAccountChanged()), SLOT(listChanged()));
updateButtonStates();
}
AccountListDialog::~AccountListDialog()
{
delete ui;
}
void AccountListDialog::listChanged()
{
updateButtonStates();
}
void AccountListDialog::on_addAccountBtn_clicked()
{
addAccount(tr("Please enter your Mojang or Minecraft account username and password to add your account."));
}
void AccountListDialog::on_rmAccountBtn_clicked()
{
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
if (selection.size() > 0)
{
QModelIndex selected = selection.first();
m_accounts->removeAccount(selected);
}
}
void AccountListDialog::on_setDefaultBtn_clicked()
{
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
if (selection.size() > 0)
{
QModelIndex selected = selection.first();
MojangAccountPtr account = selected.data(MojangAccountList::PointerRole).value<MojangAccountPtr>();
m_accounts->setActiveAccount(account->username());
}
}
void AccountListDialog::on_noDefaultBtn_clicked()
{
m_accounts->setActiveAccount("");
}
void AccountListDialog::on_closeBtnBox_rejected()
{
close();
}
void AccountListDialog::updateButtonStates()
{
// If there is no selection, disable buttons that require something selected.
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
ui->rmAccountBtn->setEnabled(selection.size() > 0);
ui->setDefaultBtn->setEnabled(selection.size() > 0);
ui->noDefaultBtn->setDown(m_accounts->activeAccount().get() == nullptr);
}
void AccountListDialog::addAccount(const QString& errMsg)
{
// TODO: We can use the login dialog for this for now, but we'll have to make something better for it eventually.
EditAccountDialog loginDialog(errMsg, this, EditAccountDialog::UsernameField | EditAccountDialog::PasswordField);
loginDialog.exec();
if (loginDialog.result() == QDialog::Accepted)
{
QString username(loginDialog.username());
QString password(loginDialog.password());
MojangAccountPtr account = MojangAccount::createFromUsername(username);
ProgressDialog progDialog(this);
auto task = account->login(password);
progDialog.exec(task.get());
if(task->successful())
{
m_accounts->addAccount(account);
if (m_accounts->count() == 1)
m_accounts->setActiveAccount(account->username());
// Grab associated player skins
auto job = new NetJob("Player skins: " + account->username());
for(AccountProfile profile : account->profiles())
{
auto meta = MMC->metacache()->resolveEntry("skins", profile.name + ".png");
auto action = CacheDownload::make(
QUrl("http://" + URLConstants::SKINS_BASE + profile.name + ".png"),
meta);
job->addNetAction(action);
meta->stale = true;
}
job->start();
}
else
{
auto reason = task->failReason();
auto dlg = CustomMessageBox::selectable(this, tr("Login error."), reason, QMessageBox::Critical);
dlg->exec();
delete dlg;
}
}
}

View File

@@ -1,96 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AccountListDialog</class>
<widget class="QDialog" name="AccountListDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Manage Accounts</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="welcomeLabel">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Welcome! If you're new here, you can click the &amp;quot;Add&amp;quot; button to add your Mojang or Minecraft account.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QTreeView" name="listView"/>
</item>
<item>
<layout class="QVBoxLayout" name="manageAcctsBtnBox">
<item>
<widget class="QPushButton" name="addAccountBtn">
<property name="text">
<string>&amp;Add</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="rmAccountBtn">
<property name="text">
<string>&amp;Remove</string>
</property>
</widget>
</item>
<item>
<spacer name="buttonSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="setDefaultBtn">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set the currently selected account as the active account. The active account is the account that is used to log in (unless it is overridden in an instance-specific setting).&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>&amp;Set Default</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="noDefaultBtn">
<property name="toolTip">
<string>Set no default account. This will cause MultiMC to prompt you to select an account every time you launch an instance that doesn't have its own default set.</string>
</property>
<property name="text">
<string>&amp;No Default</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="closeBtnBox">
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -44,6 +44,8 @@ AccountSelectDialog::AccountSelectDialog(const QString &message, int flags, QWid
// 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-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,11 +28,11 @@
#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 <logic/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);
@@ -44,6 +44,19 @@ CopyInstanceDialog::CopyInstanceDialog(BaseInstance *original, QWidget *parent)
ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
ui->instNameTextBox->setText(original->name());
ui->instNameTextBox->setFocus();
auto groups = MMC->instances()->getGroups().toSet();
auto groupList = QStringList(groups.toList());
groupList.sort(Qt::CaseInsensitive);
groupList.removeOne("");
groupList.push_front("");
ui->groupBox->addItems(groupList);
int index = groupList.indexOf(m_original->group());
if(index == -1)
{
index = 0;
}
ui->groupBox->setCurrentIndex(index);
ui->groupBox->lineEdit()->setPlaceholderText(tr("No group"));
}
CopyInstanceDialog::~CopyInstanceDialog()
@@ -66,6 +79,11 @@ QString CopyInstanceDialog::iconKey() const
return InstIconKey;
}
QString CopyInstanceDialog::instGroup() const
{
return ui->groupBox->currentText();
}
void CopyInstanceDialog::on_iconButton_clicked()
{
IconPickerDialog dlg(this);

View File

@@ -1,4 +1,4 @@
/* Copyright 2013 MultiMC Contributors
/* Copyright 2013-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
#include <QDialog>
#include "logic/BaseVersion.h"
#include <logic/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-2014 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -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;
}

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