mirror of
https://github.com/UltimMC/Launcher.git
synced 2025-12-13 20:22:13 +00:00
Compare commits
500 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03a25c9a5d | ||
|
|
83b90d8bfb | ||
|
|
1d5c09051c | ||
|
|
940f160091 | ||
|
|
3d2de6add8 | ||
|
|
b7c4284019 | ||
|
|
2315bf7bc5 | ||
|
|
41bd2a6634 | ||
|
|
5711b1be95 | ||
|
|
90eea4f05c | ||
|
|
cbb1e0ea45 | ||
|
|
ec4805cce8 | ||
|
|
a2ac9c5a3a | ||
|
|
551e101146 | ||
|
|
1dd8978f8c | ||
|
|
24a0635b62 | ||
|
|
2e9284951c | ||
|
|
f9a7c1cf21 | ||
|
|
28eebc09fc | ||
|
|
cc19159f4d | ||
|
|
587fedce84 | ||
|
|
fa42a27525 | ||
|
|
84723add8f | ||
|
|
992ba0c3f8 | ||
|
|
7d1dd2a32f | ||
|
|
add23a9a0b | ||
|
|
d9b2f0ed42 | ||
|
|
9217d9263e | ||
|
|
a3a5afe119 | ||
|
|
7fb6cafe9e | ||
|
|
c1b6f42551 | ||
|
|
3d1426b559 | ||
|
|
095640ed01 | ||
|
|
9e8a74cc89 | ||
|
|
547f6f77d0 | ||
|
|
8f7aec032b | ||
|
|
92560bf0cd | ||
|
|
2dd2b7a291 | ||
|
|
b4122cff89 | ||
|
|
43b9706b5c | ||
|
|
bbdf5c1395 | ||
|
|
382e167d64 | ||
|
|
de2bb0c6f3 | ||
|
|
2083ac8cc1 | ||
|
|
16955c6188 | ||
|
|
b00e63dbe8 | ||
|
|
20cb97a35a | ||
|
|
36efcf8d3c | ||
|
|
a59e83cd12 | ||
|
|
febf3645d0 | ||
|
|
01ca3d6aad | ||
|
|
6deb41e32d | ||
|
|
74f7bd9a1c | ||
|
|
7d8c5ac9b5 | ||
|
|
d172daf3a9 | ||
|
|
56b16320dd | ||
|
|
376467740b | ||
|
|
814d5d3315 | ||
|
|
fd6706391b | ||
|
|
21597da33d | ||
|
|
c0254d9a75 | ||
|
|
151fbde8d0 | ||
|
|
03b13b0b3f | ||
|
|
9b82c87c92 | ||
|
|
75cb329f17 | ||
|
|
bef869ff76 | ||
|
|
0a64579401 | ||
|
|
d71697efb3 | ||
|
|
e5b393318f | ||
|
|
1ed90293ac | ||
|
|
bc05ad30aa | ||
|
|
e178284172 | ||
|
|
c91adfb3d1 | ||
|
|
77d9360d25 | ||
|
|
3403553d44 | ||
|
|
c767707c95 | ||
|
|
66fa241257 | ||
|
|
8a56ab6780 | ||
|
|
71575a5022 | ||
|
|
222c26f9cf | ||
|
|
ce68efa174 | ||
|
|
8bb906bbd7 | ||
|
|
e7f67a73b3 | ||
|
|
3821569363 | ||
|
|
d8d6f5929b | ||
|
|
977cc1cfbb | ||
|
|
4c0dc51110 | ||
|
|
5c43842359 | ||
|
|
aba1f89e2a | ||
|
|
cc6968e9a3 | ||
|
|
d570037331 | ||
|
|
6a8984a21d | ||
|
|
0d4046de39 | ||
|
|
24698fe85f | ||
|
|
40c238442f | ||
|
|
ff06489fed | ||
|
|
08fbfa7434 | ||
|
|
6f75009a80 | ||
|
|
7c51cc475b | ||
|
|
fc911add58 | ||
|
|
6349800f07 | ||
|
|
9b3ae29a36 | ||
|
|
19278c853b | ||
|
|
b3cf19190f | ||
|
|
842328df8e | ||
|
|
f72a38b06c | ||
|
|
d934e64831 | ||
|
|
15775bd30a | ||
|
|
cc499488db | ||
|
|
a218d7b7f6 | ||
|
|
b5d6f50fb1 | ||
|
|
252f375454 | ||
|
|
a75e64dd18 | ||
|
|
18a342ef14 | ||
|
|
8b86306d48 | ||
|
|
dd0752e69f | ||
|
|
d166340097 | ||
|
|
eb5699c835 | ||
|
|
b9fb718822 | ||
|
|
1f498266d8 | ||
|
|
e241c3625c | ||
|
|
421a46e3d3 | ||
|
|
5179aed3a0 | ||
|
|
77de2d1e54 | ||
|
|
e422eff959 | ||
|
|
828254dd11 | ||
|
|
1f3a840f3c | ||
|
|
56d91fda3a | ||
|
|
e8731c5d01 | ||
|
|
30b1f5e5cf | ||
|
|
7f4073840a | ||
|
|
f0d850e1ee | ||
|
|
d6e5c472b5 | ||
|
|
c31dbf13cb | ||
|
|
affb2fdd6c | ||
|
|
c081cd8021 | ||
|
|
1194ec9a8e | ||
|
|
d911c9908c | ||
|
|
702e00e059 | ||
|
|
478815dae6 | ||
|
|
c08bfce5f2 | ||
|
|
9ec6deea84 | ||
|
|
0bccc94471 | ||
|
|
a0a805735b | ||
|
|
171325d427 | ||
|
|
be73eb3322 | ||
|
|
bf7b070508 | ||
|
|
223a7aba7b | ||
|
|
84ae67fff5 | ||
|
|
694067c603 | ||
|
|
6b3d1101cb | ||
|
|
f485885757 | ||
|
|
48d3052ac1 | ||
|
|
e118b1f990 | ||
|
|
55a0d110b6 | ||
|
|
f3900f2966 | ||
|
|
db8b47e7f6 | ||
|
|
439e17b149 | ||
|
|
8c71a5d61f | ||
|
|
6d34411f54 | ||
|
|
68ef451be5 | ||
|
|
e993adaf44 | ||
|
|
ad1f2c530c | ||
|
|
69c3e7111f | ||
|
|
92abe4c603 | ||
|
|
9860d5ee12 | ||
|
|
8a3a0f5a52 | ||
|
|
69a9ca39ad | ||
|
|
825d31bf1a | ||
|
|
2590c6be15 | ||
|
|
4c3bd416c6 | ||
|
|
aade36860c | ||
|
|
3a0cdf2d3d | ||
|
|
d2b2d55aa9 | ||
|
|
eb9661370b | ||
|
|
e1f542b5b0 | ||
|
|
15920aa9d0 | ||
|
|
e17364de6b | ||
|
|
b911a3834c | ||
|
|
94c2c363b2 | ||
|
|
df82d8fadb | ||
|
|
851a77d5bb | ||
|
|
41caf7976d | ||
|
|
fc3c0b0971 | ||
|
|
94cb5c7d77 | ||
|
|
911ac19a56 | ||
|
|
7f2a16917e | ||
|
|
8a8c4193e6 | ||
|
|
927217c7f0 | ||
|
|
a6a5241e12 | ||
|
|
e6ca58a89e | ||
|
|
aefa73ad11 | ||
|
|
4f6cd65c13 | ||
|
|
5099964c67 | ||
|
|
9e80ddb040 | ||
|
|
489cb4dbf5 | ||
|
|
e3b9b30302 | ||
|
|
93ae21abfc | ||
|
|
cf616efb5d | ||
|
|
0902fd5bec | ||
|
|
de48f102bd | ||
|
|
0f3d88cb14 | ||
|
|
8fda1595f7 | ||
|
|
e9c8ca02ba | ||
|
|
95203df9ca | ||
|
|
27732d66b4 | ||
|
|
b3f717c582 | ||
|
|
cba22f7ee0 | ||
|
|
3d8f6ac640 | ||
|
|
605a334057 | ||
|
|
5fa36f67b3 | ||
|
|
0cd8ded4d4 | ||
|
|
9d724e0fe4 | ||
|
|
a9dfe6d7ec | ||
|
|
7de007502c | ||
|
|
e955b1c6f9 | ||
|
|
c8f468057e | ||
|
|
6ded1168b0 | ||
|
|
adecc53df8 | ||
|
|
c9465e9e86 | ||
|
|
f14c1888a9 | ||
|
|
ca60784a44 | ||
|
|
565dab24b5 | ||
|
|
eea347b82c | ||
|
|
0b60e50af8 | ||
|
|
0959aeb046 | ||
|
|
89edc3e15e | ||
|
|
f67ca674c4 | ||
|
|
3ed5b1570b | ||
|
|
4674aad125 | ||
|
|
bf1632e4ed | ||
|
|
b286b93281 | ||
|
|
632c087483 | ||
|
|
318a945d74 | ||
|
|
b6d7ffab47 | ||
|
|
04b36a3e55 | ||
|
|
3f2152c14d | ||
|
|
8a6c64ef62 | ||
|
|
6e42d51283 | ||
|
|
86830967b6 | ||
|
|
1657313105 | ||
|
|
a00fb1e8da | ||
|
|
50d18a06d5 | ||
|
|
3cd2b898e5 | ||
|
|
17d4947b30 | ||
|
|
dd7b6642a3 | ||
|
|
eb246c4fa7 | ||
|
|
6ef38d0873 | ||
|
|
482ad250a4 | ||
|
|
f9169654c5 | ||
|
|
e58e2643ca | ||
|
|
42e305bb9d | ||
|
|
8594cc8f6c | ||
|
|
ad9d082f57 | ||
|
|
52ff6a4140 | ||
|
|
1ef6ec4178 | ||
|
|
72bc860983 | ||
|
|
29b00eab31 | ||
|
|
a3c95d9bcc | ||
|
|
fbc29b6a06 | ||
|
|
e1e1d99102 | ||
|
|
7cb76788bd | ||
|
|
20eb5ac3cc | ||
|
|
5f4a364955 | ||
|
|
ff9f9dd629 | ||
|
|
5f7a48a35e | ||
|
|
1f677a3325 | ||
|
|
902dc50c87 | ||
|
|
a19aca0648 | ||
|
|
c069147f67 | ||
|
|
64ca8be101 | ||
|
|
f521a925be | ||
|
|
9617326cf8 | ||
|
|
b60fbf87ab | ||
|
|
0e6bc97bf3 | ||
|
|
4a24ea6c38 | ||
|
|
a01b1707de | ||
|
|
4901985db6 | ||
|
|
1705832feb | ||
|
|
4623c1b34f | ||
|
|
39d3739442 | ||
|
|
26b485d82f | ||
|
|
919dea0de6 | ||
|
|
c33e5ca62e | ||
|
|
00a945d84b | ||
|
|
55e4cb6fb5 | ||
|
|
4f452d5815 | ||
|
|
a74f3b553a | ||
|
|
ad9b16bd3d | ||
|
|
42a85def60 | ||
|
|
e95619fa67 | ||
|
|
e5b4dee1c0 | ||
|
|
de2eb3fc54 | ||
|
|
fcc5bc2ce0 | ||
|
|
d11f10ea1e | ||
|
|
73fc9c79cf | ||
|
|
5328cc7bbe | ||
|
|
b77f4eb144 | ||
|
|
df89183c10 | ||
|
|
d18b97ae3d | ||
|
|
7fd56a30bd | ||
|
|
b2c803a378 | ||
|
|
ffff2cd324 | ||
|
|
f1dc456802 | ||
|
|
44f21406e9 | ||
|
|
91faaa5b59 | ||
|
|
96ee20072f | ||
|
|
0cc682c629 | ||
|
|
737169d1d3 | ||
|
|
cc1de6a649 | ||
|
|
6e964acde5 | ||
|
|
bb6894893d | ||
|
|
97ad7d287c | ||
|
|
47bc7e5ee3 | ||
|
|
a4779d32b6 | ||
|
|
6b76af116e | ||
|
|
211a72e144 | ||
|
|
011ea84530 | ||
|
|
d66f2500a6 | ||
|
|
29cdc9364b | ||
|
|
28ad9befdc | ||
|
|
80d146866c | ||
|
|
5a344a2933 | ||
|
|
053b938beb | ||
|
|
7c24bcc834 | ||
|
|
7dfd6aa051 | ||
|
|
00f4f533aa | ||
|
|
3133bb3ea0 | ||
|
|
acff155624 | ||
|
|
9d4e840a6e | ||
|
|
cb5cfe7242 | ||
|
|
b1cddb4600 | ||
|
|
55e21737dd | ||
|
|
da33fa4090 | ||
|
|
a8811a27f7 | ||
|
|
226c1bdae5 | ||
|
|
49dc9695f5 | ||
|
|
5e33da258c | ||
|
|
f7c97efcf3 | ||
|
|
e3d2e5fd74 | ||
|
|
4a77524b05 | ||
|
|
a354e8bfae | ||
|
|
4883d15262 | ||
|
|
f54705e1c5 | ||
|
|
43881b9cdb | ||
|
|
7146724607 | ||
|
|
0b56b5efaf | ||
|
|
4e8be668cb | ||
|
|
8d0ff99089 | ||
|
|
549198031d | ||
|
|
16d378687c | ||
|
|
dd2d8f48fa | ||
|
|
e4ecc31e07 | ||
|
|
9c87bc6c4b | ||
|
|
f26b7dedad | ||
|
|
f5273ae2b1 | ||
|
|
1dc34269bd | ||
|
|
c608841f77 | ||
|
|
2e64d0308c | ||
|
|
c88c639b8e | ||
|
|
616c372690 | ||
|
|
994972bf5d | ||
|
|
82b35b5445 | ||
|
|
7ceb2cacb1 | ||
|
|
8219dbf612 | ||
|
|
3b236483df | ||
|
|
c0e58fbfb2 | ||
|
|
6f6d912d07 | ||
|
|
efa8e26a3f | ||
|
|
5cf599673d | ||
|
|
65e30aa118 | ||
|
|
a59dbdcb38 | ||
|
|
725e6a36bb | ||
|
|
93ee6f9010 | ||
|
|
5a0e7877b0 | ||
|
|
2f0275c194 | ||
|
|
1f218bb8cd | ||
|
|
ba401922e1 | ||
|
|
1f6a484cb2 | ||
|
|
18f532b0d7 | ||
|
|
0d30a2655f | ||
|
|
9022042360 | ||
|
|
583786757a | ||
|
|
af33b96684 | ||
|
|
aa41b891f0 | ||
|
|
53069205fa | ||
|
|
6d9819cccf | ||
|
|
f8df07c327 | ||
|
|
573d4c8050 | ||
|
|
c84c51860d | ||
|
|
6206a241ea | ||
|
|
7839c4ecc0 | ||
|
|
b82eb5873e | ||
|
|
a17caba2c9 | ||
|
|
946d49675c | ||
|
|
ac2f64f337 | ||
|
|
ddedd077b6 | ||
|
|
2cd9b06476 | ||
|
|
eb0ed082d8 | ||
|
|
cdd35910c3 | ||
|
|
ece826bdbc | ||
|
|
b2bf50a6d7 | ||
|
|
790402bdce | ||
|
|
983a40698c | ||
|
|
866d7029af | ||
|
|
1936bd181f | ||
|
|
8637cce433 | ||
|
|
4a9e213238 | ||
|
|
179451d591 | ||
|
|
3fb7a0faf0 | ||
|
|
b4b6091372 | ||
|
|
556d8f0ec1 | ||
|
|
986141b503 | ||
|
|
176783c8ca | ||
|
|
f9ea3dbfde | ||
|
|
ffbc5bb62c | ||
|
|
966f9d1206 | ||
|
|
0f7b38c76b | ||
|
|
7d5787025a | ||
|
|
156bc8f276 | ||
|
|
d7113de3bd | ||
|
|
c39d26f445 | ||
|
|
2831ca94f8 | ||
|
|
0a592ab99b | ||
|
|
d166b48072 | ||
|
|
13ac46bc18 | ||
|
|
a1a06cc89f | ||
|
|
c46c508fc6 | ||
|
|
b182f12c20 | ||
|
|
222d3c0dc5 | ||
|
|
3a3c9ac951 | ||
|
|
130a790807 | ||
|
|
5eb9ef5d56 | ||
|
|
e9ed4b29bc | ||
|
|
58741d2df4 | ||
|
|
53f61bea71 | ||
|
|
498bb48338 | ||
|
|
2fe033c4a0 | ||
|
|
d8413fa5ec | ||
|
|
e6ab57b8b1 | ||
|
|
e71295d760 | ||
|
|
50c441a773 | ||
|
|
e9186d6d2c | ||
|
|
208209e4a7 | ||
|
|
3fabb11f4c | ||
|
|
8650aa81f0 | ||
|
|
ecc80bd763 | ||
|
|
188d0d5886 | ||
|
|
7b96d74d3b | ||
|
|
d85e820a07 | ||
|
|
555cbe00ce | ||
|
|
4744ea07a8 | ||
|
|
85ff1657fd | ||
|
|
afd1778fd7 | ||
|
|
54a9ee5eb0 | ||
|
|
f552366e03 | ||
|
|
b589a12d17 | ||
|
|
fca4441229 | ||
|
|
398167e8b0 | ||
|
|
500581d095 | ||
|
|
c51090dcff | ||
|
|
a774b3d248 | ||
|
|
498520446f | ||
|
|
d52079e734 | ||
|
|
43a39a3bfb | ||
|
|
c00946c855 | ||
|
|
088ad07a80 | ||
|
|
8e286c2b5c | ||
|
|
9ddf2aec31 | ||
|
|
3c189a6553 | ||
|
|
86b6cdfcb3 | ||
|
|
e6201f9ff7 | ||
|
|
52c9cd5497 | ||
|
|
0e22e4b399 | ||
|
|
48b587e7b6 | ||
|
|
7d74c9bc25 | ||
|
|
0b1e0221f0 | ||
|
|
c51a993ff7 | ||
|
|
5650a28fc6 | ||
|
|
7d76fd57e9 | ||
|
|
6961525faa | ||
|
|
8950953d91 | ||
|
|
7f6b344b49 | ||
|
|
9bbbb05060 | ||
|
|
0885668292 | ||
|
|
0f1a3329e4 | ||
|
|
998a14c95d | ||
|
|
3b97e3c363 | ||
|
|
c47933d95c | ||
|
|
8cfd0881ac | ||
|
|
e6be883d14 | ||
|
|
1e1b2342f4 | ||
|
|
4662fbd298 | ||
|
|
0109220678 | ||
|
|
f8d835cd22 | ||
|
|
53db8edb85 | ||
|
|
acbbdf319a | ||
|
|
c71808446b | ||
|
|
525f508d94 | ||
|
|
ccbf341dc8 |
@@ -9,6 +9,7 @@ NamespaceIndentation: None
|
||||
|
||||
BreakBeforeBraces: Allman
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
ColumnLimit: 96
|
||||
MaxEmptyLinesToKeep: 1
|
||||
|
||||
|
||||
16
.gitignore
vendored
16
.gitignore
vendored
@@ -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
28
.travis.yml
Normal 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
|
||||
10
BUILD.md
10
BUILD.md
@@ -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
63
BuildConfig.cpp.in
Normal 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
86
BuildConfig.h
Normal 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;
|
||||
1201
CMakeLists.txt
1201
CMakeLists.txt
File diff suppressed because it is too large
Load Diff
25
MMCError.h
Normal file
25
MMCError.h
Normal 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;
|
||||
};
|
||||
300
MultiMC.cpp
300
MultiMC.cpp
@@ -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);
|
||||
}
|
||||
|
||||
59
MultiMC.h
59
MultiMC.h
@@ -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;
|
||||
};
|
||||
|
||||
BIN
MultiMC.icns
BIN
MultiMC.icns
Binary file not shown.
@@ -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;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||

|
||||
|
||||
MultiMC 5
|
||||
MultiMC 5 [](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 © 2013 MultiMC Contributors
|
||||
Copyright © 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
77
WinBacktrace.cpp
Normal 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
44
WinBacktrace.h
Normal 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
153
changelog.md
Normal 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.
|
||||
@@ -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
786
cmake/BundleUtilities.cmake
Normal 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
13
cmake/Coverage.cmake
Normal 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
35
cmake/Coverity.cmake
Normal 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()
|
||||
895
cmake/GetPrerequisites.cmake
Normal file
895
cmake/GetPrerequisites.cmake
Normal 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
37
cmake/GitFunctions.cmake
Normal 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
14
cmake/QMakeQuery.cmake
Normal 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
13
cmake/UseCXX11.cmake
Normal 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()
|
||||
40
config.h.in
40
config.h.in
@@ -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@"
|
||||
|
||||
@@ -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()
|
||||
7
depends/LogicalGui/CMakeLists.txt
Normal file
7
depends/LogicalGui/CMakeLists.txt
Normal 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)
|
||||
254
depends/LogicalGui/LogicalGui.h
Normal file
254
depends/LogicalGui/LogicalGui.h
Normal 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 *>(¶ms))...};
|
||||
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 *>(¶ms))...};
|
||||
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 *)
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
/* Copyright 2013-2014 MultiMC Contributors
|
||||
*
|
||||
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
/* Copyright 2013-2014 MultiMC Contributors
|
||||
*
|
||||
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
*
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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 ¤t,
|
||||
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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
6
depends/javacheck/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
.idea
|
||||
*.iml
|
||||
out
|
||||
.classpath
|
||||
.idea
|
||||
.project
|
||||
@@ -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
6
depends/launcher/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
.idea
|
||||
*.iml
|
||||
out
|
||||
.classpath
|
||||
.idea
|
||||
.project
|
||||
@@ -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")
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
173
depends/launcher/org/multimc/EntryPoint.java
Normal file
173
depends/launcher/org/multimc/EntryPoint.java
Normal 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;
|
||||
}
|
||||
132
depends/launcher/org/multimc/IconLoader.java
Normal file
132
depends/launcher/org/multimc/IconLoader.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
86
depends/launcher/org/multimc/ParamBucket.java
Normal file
86
depends/launcher/org/multimc/ParamBucket.java
Normal 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>>();
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
|
||||
}
|
||||
309
depends/launcher/org/multimc/Utils.java
Normal file
309
depends/launcher/org/multimc/Utils.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
175
depends/launcher/org/multimc/legacy/LegacyLauncher.java
Normal file
175
depends/launcher/org/multimc/legacy/LegacyLauncher.java
Normal 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;
|
||||
}
|
||||
}
|
||||
379
depends/launcher/org/multimc/onesix/OneSixLauncher.java
Normal file
379
depends/launcher/org/multimc/onesix/OneSixLauncher.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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_); \
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -1245,7 +1245,7 @@ extern int ZEXPORT unzReadCurrentFile (file, buf, len)
|
||||
return UNZ_PARAMERROR;
|
||||
|
||||
|
||||
if ((pfile_in_zip_read_info->read_buffer == NULL))
|
||||
if (pfile_in_zip_read_info->read_buffer == NULL)
|
||||
return UNZ_END_OF_LIST_OF_FILE;
|
||||
if (len==0)
|
||||
return 0;
|
||||
|
||||
@@ -777,9 +777,9 @@ extern int ZEXPORT zipOpenNewFileInZip3 (file, filename, zipfi,
|
||||
zi->ci.flag = 0;
|
||||
if ((level==8) || (level==9))
|
||||
zi->ci.flag |= 2;
|
||||
if ((level==2))
|
||||
if (level==2)
|
||||
zi->ci.flag |= 4;
|
||||
if ((level==1))
|
||||
if (level==1)
|
||||
zi->ci.flag |= 6;
|
||||
if (password != NULL)
|
||||
{
|
||||
|
||||
@@ -1,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)
|
||||
@@ -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)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
/* Copyright 2013-2014 MultiMC Contributors
|
||||
*
|
||||
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
|
||||
61
depends/util/include/modutils.h
Normal file
61
depends/util/include/modutils.h
Normal 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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
/* Copyright 2013-2014 MultiMC Contributors
|
||||
*
|
||||
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
*
|
||||
|
||||
150
depends/util/src/modutils.cpp
Normal file
150
depends/util/src/modutils.cpp
Normal 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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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>
|
||||
51
graphics.qrc
51
graphics.qrc
@@ -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
202
gui/ColumnResizer.cpp
Normal 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
38
gui/ColumnResizer.h
Normal 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;
|
||||
};
|
||||
@@ -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 ¶graph : 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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>&Kill Minecraft</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="closeButton">
|
||||
<property name="text">
|
||||
<string>&Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
38
gui/GuiUtil.cpp
Normal file
38
gui/GuiUtil.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#include "GuiUtil.h"
|
||||
|
||||
#include <QClipboard>
|
||||
#include <QDesktopServices>
|
||||
#include <QApplication>
|
||||
|
||||
#include "dialogs/ProgressDialog.h"
|
||||
#include "logic/net/PasteUpload.h"
|
||||
#include "dialogs/CustomMessageBox.h"
|
||||
|
||||
void GuiUtil::uploadPaste(const QString &text, QWidget *parentWidget)
|
||||
{
|
||||
ProgressDialog dialog(parentWidget);
|
||||
PasteUpload *paste = new PasteUpload(parentWidget, text);
|
||||
dialog.exec(paste);
|
||||
if (!paste->successful())
|
||||
{
|
||||
CustomMessageBox::selectable(parentWidget, "Upload failed", paste->failReason(),
|
||||
QMessageBox::Critical)->exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
const QString link = paste->pasteLink();
|
||||
setClipboardText(link);
|
||||
QDesktopServices::openUrl(link);
|
||||
CustomMessageBox::selectable(
|
||||
parentWidget, QObject::tr("Upload finished"),
|
||||
QObject::tr("The <a href=\"%1\">link to the uploaded log</a> has been opened in the default "
|
||||
"browser and placed in your clipboard.").arg(link),
|
||||
QMessageBox::Information)->exec();
|
||||
}
|
||||
delete paste;
|
||||
}
|
||||
|
||||
void GuiUtil::setClipboardText(const QString &text)
|
||||
{
|
||||
QApplication::clipboard()->setText(text);
|
||||
}
|
||||
9
gui/GuiUtil.h
Normal file
9
gui/GuiUtil.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace GuiUtil
|
||||
{
|
||||
void uploadPaste(const QString &text, QWidget *parentWidget);
|
||||
void setClipboardText(const QString &text);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
@@ -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><html><head/><body><p align="center"><span style=" font-weight:600; color:#ff0004;">Catnarok!</span></p><p align="center">Or just a cat with a ball of yarn?</p><p align="center"><span style=" font-style:italic;">WHO KNOWS?!</span></p><p align="center"><img src=":/icons/instances/tnt"/></p></body></html></string>
|
||||
<string><html><head/><body><p align="center">It's a fluffy kitty :3</p></body></html></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><html><head/><body><p>View and upload screenshots for this instance</p></body></html></string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionInstanceSettings">
|
||||
<property name="text">
|
||||
<string>Instance Settings</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Change the settings specific to the instance</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources>
|
||||
<include location="../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>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
/* Copyright 2013-2014 MultiMC Contributors
|
||||
*
|
||||
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
/* Copyright 2013-2014 MultiMC Contributors
|
||||
*
|
||||
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
/* Copyright 2013-2014 MultiMC Contributors
|
||||
*
|
||||
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
*
|
||||
|
||||
@@ -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 <<a href='mailto:forkk@forkk.net'>forkk@forkk.net</a>></p>"
|
||||
"<p>Petr Mrázek <<a href='mailto:peterix@gmail.com'>peterix@gmail.com</a>></p>"
|
||||
"<p>Sky Welch <<a href='mailto:multimc@bunnies.io'>multimc@bunnies.io</a>></p>"
|
||||
"<p>Jan (02JanDal) <<a href='mailto:02jandal@gmail.com'>02jandal@gmail.com</a>></p>"
|
||||
""
|
||||
"<h3>With thanks to</h3>"
|
||||
"<p>Orochimarufan <<a href='mailto:orochimarufan.x3@gmail.com'>orochimarufan.x3@gmail.com</a>></p>"
|
||||
"<p>TakSuyu <<a href='mailto:taksuyu@gmail.com'>taksuyu@gmail.com</a>></p>"
|
||||
"<p>Kilobyte <<a href='mailto:stiepen22@gmx.de'>stiepen22@gmx.de</a>></p>"
|
||||
"<p>Robotbrain <<a href='https://twitter.com/skylordelros'>@skylordelros</a>></p>"
|
||||
"<p>Rootbear75 <<a href='https://twitter.com/rootbear75'>@rootbear75</a>> (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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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><html><head/><body><p><a href="http://github.com/Forkk/MultiMC5"><span style=" text-decoration: underline; color:#0000ff;">http://github.com/MultiMC/MultiMC5</span></a></p></body></html></string>
|
||||
<string><html><head/><body><p><a href="http://github.com/MultiMC/MultiMC5"><span style=" text-decoration: underline; color:#0000ff;">http://github.com/MultiMC/MultiMC5</span></a></p></body></html></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><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt; font-weight:600;">MultiMC</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt;">Andrew Okin &lt;</span><a href="mailto:forkk@forkk.net"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;">forkk@forkk.net</span></a><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt;">&gt;</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt;">Petr Mrázek &lt;</span><a href="mailto:peterix@gmail.com"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;">peterix@gmail.com</span></a><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt;">&gt;</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt;">Sky &lt;</span><a href="https://www.twitter.com/drayshak"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;">@drayshak</span></a><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt;">&gt;</span></p>
|
||||
<p style="-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;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu'; font-size:10pt; font-weight:600;">With thanks to</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt;">Orochimarufan &lt;</span><a href="mailto:orochimarufan.x3@gmail.com"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;">orochimarufan.x3@gmail.com</span></a><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt;">&gt;</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt;">TakSuyu &lt;</span><a href="mailto:taksuyu@gmail.com"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;">taksuyu@gmail.com</span></a><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt;">&gt;</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt;">Kilobyte &lt;</span><a href="mailto:stiepen22@gmx.de"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;">stiepen22@gmx.de</span></a><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt;">&gt;</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt;">Jan (02JanDal) &lt;</span><a href="mailto:02jandal@gmail.com"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;">02jandal@gmail.com</span></a><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt;">&gt;</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt;">Robotbrain &lt;</span><a href="https://twitter.com/skylordelros"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;">@skylordelros</span></a><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt;">&gt;</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt;">Rootbear75 &lt;</span><a href="https://twitter.com/rootbear75"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt; text-decoration: underline; color:#0000ff;">@rootbear75</span></a><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt;">&gt; (build server)</span></p></body></html></string>
|
||||
</style></head><body style=" font-family:'Bitstream Vera Sans'; font-size:11pt; font-weight:400; font-style:normal;">
|
||||
<p style="-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;"><br /></p></body></html></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><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'DejaVu Sans Mono'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
</style></head><body style=" font-family:'DejaVu Sans Mono'; font-size:11pt; font-weight:400; font-style:normal;">
|
||||
<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Bitstream Vera Sans'; font-size:18pt; font-weight:600;">MultiMC</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Copyright 2012-2014 MultiMC Contributors</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);</span></p>
|
||||
@@ -370,7 +356,24 @@ p, li { white-space: pre-wrap; }
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> * Boston, MA 02110-1301, USA.</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> */</span></p>
|
||||
<p align="center" style="-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;"><br /></p>
|
||||
<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Bitstream Vera Sans'; font-size:18pt; font-weight:600;">Batch icon set</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You are free to use Batch (the &quot;icon set&quot;) or any part thereof (the &quot;icons&quot;)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">in any personal, open-source or commercial work without obligation of payment</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">(monetary or otherwise) or attribution. Do not sell the icon set, host</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">the icon set or rent the icon set (either in existing or modified form).</span></p>
|
||||
<p style="-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;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">While attribution is optional, it is always appreciated.</span></p>
|
||||
<p style="-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;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Intellectual property rights are not transferred with the download of the icons.</span></p>
|
||||
<p style="-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;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL ADAM WHITCROFT</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL,</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THE USE OF THE ICONS,</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</span></p>
|
||||
<p style="-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;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://adamwhitcroft.com/batch/"><span style=" text-decoration: underline; color:#68a0df;">http://adamwhitcroft.com/batch/</span></a></p>
|
||||
<p style="-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;"><br /></p>
|
||||
<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Bitstream Vera Sans'; font-size:18pt; font-weight:600;">Pack200</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The GNU General Public License (GPL)</span></p>
|
||||
<p style="-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;"><br /></p>
|
||||
@@ -430,8 +433,45 @@ p, li { white-space: pre-wrap; }
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> *</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> * This file has been put into the public domain.</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> * You can do whatever you want with this file.</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> */</span></p>
|
||||
<p style="-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;"><br /></p>
|
||||
<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Bitstream Vera Sans'; font-size:18pt; font-weight:600;">Java IconLoader class</span></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Copyright (c) 2011, Chris Molini</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">All rights reserved.</span></p>
|
||||
<p style="-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;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Redistribution and use in source and binary forms, with or without</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">modification, are permitted provided that the following conditions are met:</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> * Redistributions of source code must retain the above copyright</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> notice, this list of conditions and the following disclaimer.</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> * Redistributions in binary form must reproduce the above copyright</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> notice, this list of conditions and the following disclaimer in the</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> documentation and/or other materials provided with the distribution.</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> * Neither the name of the &lt;organization&gt; nor the</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> names of its contributors may be used to endorse or promote products</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> derived from this software without specific prior written permission.</span></p>
|
||||
<p style="-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;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS IS&quot; AND</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">DISCLAIMED. IN NO EVENT SHALL &lt;COPYRIGHT HOLDER&gt; BE LIABLE FOR ANY</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</span></p>
|
||||
<p align="center" style="-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;"><br /></p>
|
||||
<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Bitstream Vera Sans'; font-size:18pt; font-weight:600;">ColumnResizer</span></p>
|
||||
<p style="-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;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">/*</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> * Copyright 2011 Aurélien Gâteau &lt;agateau@kde.org&gt;</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> * License: LGPL v2.1 or later (see COPYING)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> */</span></p></body></html></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><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Bitstream Vera Sans'; font-size:11pt;">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.</span></p>
|
||||
<p style="-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;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Bitstream Vera Sans'; font-size:11pt;">Part of the reason for using the Apache license is we don't want people using the &quot;MultiMC&quot; name when redistributing the project. This means people must take the time to go through the source code and remove all references to &quot;MultiMC&quot;, including but not limited to the project icon and the title of windows, (no *MultiMC-fork* in the title).</span></p>
|
||||
<p style="-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;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Bitstream Vera Sans'; font-size:11pt;">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 </span><span style=" font-family:'Bitstream Vera Sans'; font-size:11pt; font-weight:600;">without</span><span style=" font-family:'Bitstream Vera Sans'; font-size:11pt;"> implying that you have our blessing.</span></p></body></html></string>
|
||||
</style></head><body style=" font-family:'Bitstream Vera Sans'; font-size:11pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">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.</p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Part of the reason for using the Apache license is we don't want people using the &quot;MultiMC&quot; name when redistributing the project. This means people must take the time to go through the source code and remove all references to &quot;MultiMC&quot;, including but not limited to the project icon and the title of windows, (no *MultiMC-fork* in the title).</p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">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 <span style=" font-weight:600;">without</span> implying that you have our blessing.</p></body></html></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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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><html><head/><body><p>Welcome! If you're new here, you can click the &quot;Add&quot; button to add your Mojang or Minecraft account.</p></body></html></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>&Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="rmAccountBtn">
|
||||
<property name="text">
|
||||
<string>&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><html><head/><body><p>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).</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&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>&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>
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user