mirror of
https://github.com/UltimMC/Launcher.git
synced 2025-12-13 20:22:13 +00:00
Compare commits
422 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77d9360d25 | ||
|
|
3403553d44 | ||
|
|
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
|
||||
|
||||
|
||||
29
.travis.yml
Normal file
29
.travis.yml
Normal file
@@ -0,0 +1,29 @@
|
||||
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
|
||||
- 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
|
||||
after_script:
|
||||
- make test
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- "irc.esper.net#MultiMC"
|
||||
template:
|
||||
- "%{build_number} (%{branch} - %{commit} : %{author}): %{message} (%{build_url})"
|
||||
email: false
|
||||
2
BUILD.md
2
BUILD.md
@@ -56,7 +56,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)
|
||||
|
||||
65
BuildConfig.cpp.in
Normal file
65
BuildConfig.cpp.in
Normal file
@@ -0,0 +1,65 @@
|
||||
#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@";
|
||||
GIT_COMMIT_CSTR = "@MultiMC_GIT_COMMIT@";
|
||||
VERSION_STR = "@MultiMC_VERSION_STRING@";
|
||||
VERSION_CSTR = "@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;
|
||||
}
|
||||
90
BuildConfig.h
Normal file
90
BuildConfig.h
Normal file
@@ -0,0 +1,90 @@
|
||||
#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;
|
||||
const char* GIT_COMMIT_CSTR;
|
||||
|
||||
/// This is printed on start to standard output
|
||||
QString VERSION_STR;
|
||||
|
||||
/// Version string as a char string. Used by the crash handling system to avoid touching heap memory.
|
||||
const char* VERSION_CSTR;
|
||||
|
||||
/**
|
||||
* This is used to fetch the news RSS feed.
|
||||
* It defaults in CMakeLists.txt to "http://multimc.org/rss.xml"
|
||||
*/
|
||||
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;
|
||||
1162
CMakeLists.txt
1162
CMakeLists.txt
File diff suppressed because it is too large
Load Diff
375
HandleCrash.cpp
Normal file
375
HandleCrash.cpp
Normal file
@@ -0,0 +1,375 @@
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// This is the Unix implementation of MultiMC's crash handling system.
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <MultiMC.h>
|
||||
|
||||
#if defined Q_OS_UNIX
|
||||
#include <sys/utsname.h>
|
||||
#include <execinfo.h>
|
||||
#elif defined Q_OS_WIN32
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
#include <WinBacktrace.h>
|
||||
#endif
|
||||
|
||||
#include "BuildConfig.h"
|
||||
|
||||
#include "HandleCrash.h"
|
||||
|
||||
// The maximum number of frames to include in the backtrace.
|
||||
#define BT_SIZE 20
|
||||
|
||||
|
||||
#define DUMPF_NAME_FMT "mmc-crash-%X.bm" // Black magic? Bowel movement? Dump?
|
||||
// 1234567890 1234
|
||||
// The maximum number of digits in a unix timestamp when encoded in hexadecimal is about 17.
|
||||
// Our format string is ~14 characters long.
|
||||
// The maximum length of the dump file's filename should be well over both of these. 42 is a good number.
|
||||
#define DUMPF_NAME_LEN 42
|
||||
|
||||
// {{{ Platform hackery
|
||||
|
||||
#if defined Q_OS_UNIX
|
||||
|
||||
struct CrashData
|
||||
{
|
||||
int signal = 0;
|
||||
};
|
||||
|
||||
// This has to be declared here, after the CrashData struct, but before the function that uses it.
|
||||
void handleCrash(CrashData);
|
||||
|
||||
void handler(int sig)
|
||||
{
|
||||
CrashData cData;
|
||||
cData.signal = sig;
|
||||
handleCrash(cData);
|
||||
}
|
||||
|
||||
#elif defined Q_OS_WIN32
|
||||
|
||||
// Struct for storing platform specific crash information.
|
||||
// This gets passed into the generic handler, which will use
|
||||
// it to access platform specific information.
|
||||
struct CrashData
|
||||
{
|
||||
EXCEPTION_RECORD* exceptionInfo;
|
||||
CONTEXT* context;
|
||||
};
|
||||
|
||||
void handleCrash(CrashData);
|
||||
|
||||
LONG WINAPI ExceptionFilter(EXCEPTION_POINTERS* eInfo)
|
||||
{
|
||||
CrashData cData;
|
||||
cData.exceptionInfo = eInfo->ExceptionRecord;
|
||||
cData.context = eInfo->ContextRecord;
|
||||
handleCrash(cData);
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// }}}
|
||||
|
||||
// {{{ Handling
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
// #ThanksMicrosoft
|
||||
// Blame Microsoft for this atrocity.
|
||||
void dprintf(int fd, const char* fmt...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
char buffer[10240];
|
||||
// Just sprintf to a really long string and hope it works...
|
||||
// This is a hack, but I can't think of a better way to do it easily.
|
||||
int len = vsnprintf(buffer, 10240, fmt, args);
|
||||
printf(buffer, fmt, args);
|
||||
write(fd, buffer, len);
|
||||
va_end(args);
|
||||
}
|
||||
#endif
|
||||
|
||||
void getVsnType(char* out);
|
||||
void readFromTo(int from, int to);
|
||||
|
||||
void dumpErrorInfo(int dumpFile, CrashData crash)
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
// TODO: Moar unix
|
||||
dprintf(dumpFile, "Signal: %d\n", crash.signal);
|
||||
#elif defined Q_OS_WIN32
|
||||
EXCEPTION_RECORD* excInfo = crash.exceptionInfo;
|
||||
|
||||
dprintf(dumpFile, "Exception Code: %d\n", excInfo->ExceptionCode);
|
||||
dprintf(dumpFile, "Exception Address: 0x%0X\n", excInfo->ExceptionAddress);
|
||||
#endif
|
||||
}
|
||||
|
||||
void dumpMiscInfo(int dumpFile)
|
||||
{
|
||||
char vsnType[42]; // The version type. If it's more than 42 chars, the universe might implode...
|
||||
|
||||
// Get MMC info.
|
||||
getVsnType(vsnType);
|
||||
|
||||
// Get MMC info.
|
||||
getVsnType(vsnType);
|
||||
|
||||
dprintf(dumpFile, "MultiMC Version: %s\n", BuildConfig.VERSION_CSTR);
|
||||
dprintf(dumpFile, "MultiMC Version Type: %s\n", vsnType);
|
||||
}
|
||||
|
||||
void dumpBacktrace(int dumpFile, CrashData crash)
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
// Variables for storing crash info.
|
||||
void* trace[BT_SIZE]; // Backtrace frames
|
||||
size_t size; // The backtrace size
|
||||
|
||||
// Get the backtrace.
|
||||
size = backtrace(trace, BT_SIZE);
|
||||
|
||||
// Dump the backtrace
|
||||
dprintf(dumpFile, "---- BEGIN BACKTRACE ----\n");
|
||||
backtrace_symbols_fd(trace, size, dumpFile);
|
||||
dprintf(dumpFile, "---- END BACKTRACE ----\n");
|
||||
#elif defined Q_OS_WIN32
|
||||
dprintf(dumpFile, "---- BEGIN BACKTRACE ----\n");
|
||||
|
||||
StackFrame stack[BT_SIZE];
|
||||
size_t size;
|
||||
|
||||
SYMBOL_INFO *symbol;
|
||||
HANDLE process;
|
||||
|
||||
size = getBacktrace(stack, BT_SIZE, *crash.context);
|
||||
|
||||
// FIXME: Accessing heap memory is supposedly "dangerous",
|
||||
// but I can't find another way of doing this.
|
||||
|
||||
// Initialize
|
||||
process = GetCurrentProcess();
|
||||
if (!SymInitialize(process, NULL, true))
|
||||
{
|
||||
dprintf(dumpFile, "Failed to initialize symbol handler. Can't print stack trace.\n");
|
||||
dprintf(dumpFile, "Here's a list of addresses in the call stack instead:\n");
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
dprintf(dumpFile, "0x%0X\n", (DWORD64)stack[i].address);
|
||||
}
|
||||
} else {
|
||||
// Allocate memory... ._.
|
||||
symbol = (SYMBOL_INFO *) calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
|
||||
symbol->MaxNameLen = 255;
|
||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
|
||||
// Dump stacktrace
|
||||
for(int i = 0; i < size; i++)
|
||||
{
|
||||
DWORD64 addr = (DWORD64)stack[i].address;
|
||||
if (!SymFromAddr(process, (DWORD64)(addr), 0, symbol))
|
||||
dprintf(dumpFile, "?? - 0x%0X\n", addr);
|
||||
else
|
||||
dprintf(dumpFile, "%s - 0x%0X\n", symbol->Name, symbol->Address);
|
||||
}
|
||||
|
||||
free(symbol);
|
||||
}
|
||||
|
||||
dprintf(dumpFile, "---- END BACKTRACE ----\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void dumpSysInfo(int dumpFile)
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
utsname sysinfo; // System information
|
||||
|
||||
// Dump system info
|
||||
if (uname(&sysinfo) >= 0)
|
||||
{
|
||||
dprintf(dumpFile, "OS System: %s\n", sysinfo.sysname);
|
||||
dprintf(dumpFile, "OS Machine: %s\n", sysinfo.machine);
|
||||
dprintf(dumpFile, "OS Release: %s\n", sysinfo.release);
|
||||
dprintf(dumpFile, "OS Version: %s\n", sysinfo.version);
|
||||
} else {
|
||||
dprintf(dumpFile, "OS System: Unknown Unix");
|
||||
}
|
||||
#else
|
||||
// TODO: Get more information here.
|
||||
dprintf(dumpFile, "OS System: Windows");
|
||||
#endif
|
||||
}
|
||||
|
||||
void dumpLogs(int dumpFile)
|
||||
{
|
||||
int otherFile;
|
||||
|
||||
// Attempt to attach the log file if the logger was initialized.
|
||||
dprintf(dumpFile, "---- BEGIN LOGS ----\n");
|
||||
if (loggerInitialized)
|
||||
{
|
||||
otherFile = open("MultiMC-0.log", O_RDONLY);
|
||||
readFromTo(otherFile, dumpFile);
|
||||
} else {
|
||||
dprintf(dumpFile, "Logger not initialized.\n");
|
||||
}
|
||||
dprintf(dumpFile, "---- END LOGS ----\n");
|
||||
}
|
||||
|
||||
// The signal handler. If this function is called, it means shit has probably collided with some sort of device one might use to keep oneself cool.
|
||||
// This is the generic part of the code that will be called after platform specific handling is finished.
|
||||
void handleCrash(CrashData crash)
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
fprintf(stderr, "Fatal error! Received signal %d\n", crash.signal);
|
||||
#endif
|
||||
|
||||
time_t unixTime = 0; // Unix timestamp. Used to give our crash dumps "unique" names.
|
||||
|
||||
char dumpFileName[DUMPF_NAME_LEN]; // The name of the file we're dumping to.
|
||||
int dumpFile; // File descriptor for our dump file.
|
||||
|
||||
// Determine what our dump file should be called.
|
||||
// We'll just call it "mmc-crash-<unixtime>.dump"
|
||||
// First, check the time.
|
||||
time(&unixTime);
|
||||
|
||||
// Now we get to do some !!FUN!! hackery to ensure we don't use the stack when we convert
|
||||
// the timestamp from an int to a string. To do this, we just allocate a fixed size array
|
||||
// of chars on the stack, and sprintf into it. We know the timestamp won't ever be longer
|
||||
// than a certain number of digits, so this should work just fine.
|
||||
// sprintf doesn't support writing signed values as hex, so this breaks on negative timestamps.
|
||||
// It really shouldn't matter, though...
|
||||
sprintf(dumpFileName, DUMPF_NAME_FMT, unixTime);
|
||||
|
||||
// Now, we need to open the file.
|
||||
// Fail if it already exists. This should never happen.
|
||||
dumpFile = open(dumpFileName, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
|
||||
|
||||
if (dumpFile >= 0)
|
||||
{
|
||||
// If we opened the dump file successfully.
|
||||
// Dump everything we can and GTFO.
|
||||
fprintf(stderr, "Dumping crash report to %s\n", dumpFileName);
|
||||
|
||||
// Dump misc info
|
||||
dprintf(dumpFile, "Unix Time: %d\n", unixTime);
|
||||
dumpErrorInfo(dumpFile, crash);
|
||||
dumpMiscInfo(dumpFile);
|
||||
|
||||
dprintf(dumpFile, "\n");
|
||||
|
||||
dumpSysInfo(dumpFile);
|
||||
|
||||
dprintf(dumpFile, "\n");
|
||||
|
||||
dumpBacktrace(dumpFile, crash);
|
||||
|
||||
dprintf(dumpFile, "\n");
|
||||
|
||||
// DIE DIE DIE!
|
||||
exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Failed to open dump file %s to write crash info (ERRNO: %d)\n", dumpFileName, errno);
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Reads data from the file descriptor on the first argument into the second argument.
|
||||
void readFromTo(int from, int to)
|
||||
{
|
||||
char buffer[1024];
|
||||
size_t lastread = 1;
|
||||
while (lastread > 0)
|
||||
{
|
||||
lastread = read(from, buffer, 1024);
|
||||
if (lastread > 0) write(to, buffer, lastread);
|
||||
}
|
||||
}
|
||||
|
||||
// Writes the current version type to the given char buffer.
|
||||
void getVsnType(char* out)
|
||||
{
|
||||
switch (BuildConfig.versionTypeEnum)
|
||||
{
|
||||
case Config::Release:
|
||||
sprintf(out, "Release");
|
||||
break;
|
||||
case Config::ReleaseCandidate:
|
||||
sprintf(out, "ReleaseCandidate");
|
||||
break;
|
||||
case Config::Development:
|
||||
sprintf(out, "Development");
|
||||
break;
|
||||
default:
|
||||
sprintf(out, "Unknown");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
// {{{ Misc
|
||||
|
||||
#if defined TEST_SEGV
|
||||
// Causes a crash. For testing.
|
||||
void testCrash()
|
||||
{
|
||||
char* lol = (char*)MMC->settings().get();
|
||||
lol -= 8;
|
||||
|
||||
// Throw shit at the fan.
|
||||
for (int i = 0; i < 8; i++)
|
||||
lol[i] = 'f';
|
||||
}
|
||||
#endif
|
||||
|
||||
// Initializes the Unix crash handler.
|
||||
void initBlackMagic()
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
// Register the handler.
|
||||
signal(SIGSEGV, handler);
|
||||
signal(SIGABRT, handler);
|
||||
#elif defined Q_OS_WIN32
|
||||
// I hate Windows
|
||||
SetUnhandledExceptionFilter(ExceptionFilter);
|
||||
#endif
|
||||
|
||||
#ifdef TEST_SEGV
|
||||
testCrash();
|
||||
#endif
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
18
HandleCrash.h
Normal file
18
HandleCrash.h
Normal file
@@ -0,0 +1,18 @@
|
||||
// This is a simple header file for the crash handling system. It exposes only one method,
|
||||
// initBlackMagic, which initializes the system, registering signal handlers, or doing
|
||||
// whatever stupid things need to be done on Windows.
|
||||
// The platform specific implementations for this system are in UnixCrash.cpp and
|
||||
// WinCrash.cpp.
|
||||
|
||||
#if defined Q_OS_WIN
|
||||
#warning Crash handling is not yet implemented on Windows.
|
||||
#elif defined Q_OS_UNIX
|
||||
#else
|
||||
#warning Crash handling is not supported on this platform.
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initializes the crash handling system.
|
||||
*/
|
||||
void initBlackMagic();
|
||||
|
||||
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;
|
||||
};
|
||||
193
MultiMC.cpp
193
MultiMC.cpp
@@ -1,5 +1,6 @@
|
||||
|
||||
#include "MultiMC.h"
|
||||
#include "BuildConfig.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
@@ -11,41 +12,54 @@
|
||||
#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"
|
||||
|
||||
#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}
|
||||
: 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 +89,7 @@ MultiMC::MultiMC(int &argc, char **argv, bool root_override)
|
||||
parser.addShortOpt("launch", 'l');
|
||||
parser.addDocumentation("launch", "tries to launch the given instance", "<inst>");
|
||||
*/
|
||||
|
||||
// parse the arguments
|
||||
try
|
||||
{
|
||||
@@ -100,8 +115,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;
|
||||
}
|
||||
@@ -150,12 +165,23 @@ MultiMC::MultiMC(int &argc, char **argv, bool root_override)
|
||||
#endif
|
||||
}
|
||||
|
||||
// static data paths... mostly just for translations
|
||||
#ifdef Q_OS_LINUX
|
||||
QDir foo(PathCombine(binPath, ".."));
|
||||
staticDataPath = foo.absolutePath();
|
||||
#elif defined(Q_OS_WIN32)
|
||||
staticDataPath = binPath;
|
||||
#elif defined(Q_OS_MAC)
|
||||
QDir foo(PathCombine(rootPath, "Contents/Resources"));
|
||||
staticDataPath = foo.absolutePath();
|
||||
#endif
|
||||
|
||||
// init the logger
|
||||
initLogger();
|
||||
|
||||
QLOG_INFO() << "MultiMC 5, (c) 2013 MultiMC Contributors";
|
||||
QLOG_INFO() << "Version : " << VERSION_STR;
|
||||
QLOG_INFO() << "Git commit : " << GIT_COMMIT;
|
||||
QLOG_INFO() << "Version : " << BuildConfig.VERSION_STR;
|
||||
QLOG_INFO() << "Git commit : " << BuildConfig.GIT_COMMIT;
|
||||
if (adjustedBy.size())
|
||||
{
|
||||
QLOG_INFO() << "Work dir before adjustment : " << origcwdPath;
|
||||
@@ -168,10 +194,14 @@ 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();
|
||||
|
||||
// load translations
|
||||
initTranslations();
|
||||
|
||||
// initialize the updater
|
||||
m_updateChecker.reset(new UpdateChecker());
|
||||
|
||||
@@ -179,14 +209,17 @@ 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());
|
||||
|
||||
// and instances
|
||||
auto InstDirSetting = m_settings->getSetting("InstanceDir");
|
||||
m_instances.reset(new InstanceList(InstDirSetting->get().toString(), this));
|
||||
QLOG_INFO() << "Loading Instances...";
|
||||
m_instances->loadList();
|
||||
connect(InstDirSetting.get(), SIGNAL(settingChanged(const Setting &, QVariant)),
|
||||
connect(InstDirSetting.get(), SIGNAL(SettingChanged(const Setting &, QVariant)),
|
||||
m_instances.get(), SLOT(on_InstFolderChanged(const Setting &, QVariant)));
|
||||
|
||||
// and accounts
|
||||
@@ -204,6 +237,21 @@ MultiMC::MultiMC(int &argc, char **argv, bool root_override)
|
||||
// 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.get());
|
||||
}
|
||||
m_tools.insert("mcedit",
|
||||
std::shared_ptr<BaseDetachedToolFactory>(new MCEditFactory()));
|
||||
for (auto tool : m_tools.values())
|
||||
{
|
||||
tool->registerSettings(m_settings.get());
|
||||
}
|
||||
|
||||
// launch instance, if that's what should be done
|
||||
// WARNING: disabled until further notice
|
||||
/*
|
||||
@@ -234,18 +282,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 +303,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,41 +339,80 @@ void MultiMC::initLogger()
|
||||
QsLogging::Logger &logger = QsLogging::Logger::instance();
|
||||
logger.setLoggingLevel(QsLogging::TraceLevel);
|
||||
m_fileDestination = QsLogging::DestinationFactory::MakeFileDestination(logBase.arg(0));
|
||||
m_debugDestination = QsLogging::DestinationFactory::MakeQDebugDestination();
|
||||
m_debugDestination = QsLogging::DestinationFactory::MakeDebugOutputDestination();
|
||||
logger.addDestination(m_fileDestination.get());
|
||||
logger.addDestination(m_debugDestination.get());
|
||||
// log all the things
|
||||
logger.setLoggingLevel(QsLogging::TraceLevel);
|
||||
loggerInitialized = true;
|
||||
}
|
||||
|
||||
bool loggerInitialized = false;
|
||||
|
||||
void MultiMC::initGlobalSettings()
|
||||
{
|
||||
m_settings.reset(new INISettingsObject("multimc.cfg", this));
|
||||
// Updates
|
||||
m_settings->registerSetting("UpdateChannel", version().channel);
|
||||
m_settings->registerSetting("UpdateChannel", BuildConfig.VERSION_CHANNEL);
|
||||
m_settings->registerSetting("AutoUpdate", true);
|
||||
|
||||
m_settings->registerSetting("IconTheme", QString("multimc"));
|
||||
|
||||
// Notifications
|
||||
m_settings->registerSetting("ShownNotifications", QString());
|
||||
|
||||
// FTB
|
||||
m_settings->registerSetting("TrackFTBInstances", false);
|
||||
QString ftbDataDefault;
|
||||
#ifdef Q_OS_LINUX
|
||||
QString ftbDefault = QDir::home().absoluteFilePath(".ftblauncher");
|
||||
QString ftbDefault = ftbDataDefault = QDir::home().absoluteFilePath(".ftblauncher");
|
||||
#elif defined(Q_OS_WIN32)
|
||||
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 =
|
||||
PathCombine(QDir::homePath(), "Library/Application Support/ftblauncher");
|
||||
QString ftbDefault = ftbDataDefault =
|
||||
PathCombine(QDir::homePath(), "Library/Application Support/ftblauncher");
|
||||
#endif
|
||||
m_settings->registerSetting("FTBLauncherDataRoot", ftbDataDefault);
|
||||
m_settings->registerSetting("FTBLauncherRoot", ftbDefault);
|
||||
QLOG_INFO() << "FTB Launcher paths:"
|
||||
<< m_settings->get("FTBLauncherDataRoot").toString()
|
||||
<< "and"
|
||||
<< m_settings->get("FTBLauncherRoot").toString();
|
||||
|
||||
m_settings->registerSetting("FTBRoot");
|
||||
if (m_settings->get("FTBRoot").isNull())
|
||||
{
|
||||
QString ftbRoot;
|
||||
QFile f(QDir(m_settings->get("FTBLauncherRoot").toString())
|
||||
.absoluteFilePath("ftblaunch.cfg"));
|
||||
.absoluteFilePath("ftblaunch.cfg"));
|
||||
QLOG_INFO() << "Attempting to read" << f.fileName();
|
||||
if (f.open(QFile::ReadOnly))
|
||||
{
|
||||
@@ -366,9 +454,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 +488,7 @@ void MultiMC::initGlobalSettings()
|
||||
// Java Settings
|
||||
m_settings->registerSetting("JavaPath", "");
|
||||
m_settings->registerSetting("LastHostname", "");
|
||||
m_settings->registerSetting("JavaDetectionHack", "");
|
||||
m_settings->registerSetting("JvmArgs", "");
|
||||
|
||||
// Custom Commands
|
||||
@@ -415,6 +509,8 @@ void MultiMC::initGlobalSettings()
|
||||
m_settings->registerSetting("ConsoleWindowGeometry", "");
|
||||
|
||||
m_settings->registerSetting("SettingsGeometry", "");
|
||||
|
||||
m_settings->registerSetting("PagedGeometry", "");
|
||||
}
|
||||
|
||||
void MultiMC::initHttpMetaCache()
|
||||
@@ -425,6 +521,8 @@ 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->Load();
|
||||
@@ -525,6 +623,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,6 +650,16 @@ std::shared_ptr<JavaVersionList> MultiMC::javalist()
|
||||
return m_javalist;
|
||||
}
|
||||
|
||||
std::shared_ptr<URNResolver> MultiMC::resolver()
|
||||
{
|
||||
if (!m_resolver)
|
||||
{
|
||||
m_resolver.reset(new URNResolver());
|
||||
}
|
||||
return m_resolver;
|
||||
}
|
||||
|
||||
|
||||
void MultiMC::installUpdates(const QString updateFilesDir, UpdateFlags flags)
|
||||
{
|
||||
// if we are going to update on exit, save the params now
|
||||
|
||||
56
MultiMC.h
56
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,21 @@ 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;
|
||||
|
||||
#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,
|
||||
@@ -46,6 +40,9 @@ enum UpdateFlag
|
||||
Q_DECLARE_FLAGS(UpdateFlags, UpdateFlag);
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(UpdateFlags);
|
||||
|
||||
// Global var used by the crash handling system to determine if a log file should be included in a crash report.
|
||||
extern bool loggerInitialized;
|
||||
|
||||
class MultiMC : public QApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -83,11 +80,6 @@ public:
|
||||
return m_status;
|
||||
}
|
||||
|
||||
MultiMCVersion version()
|
||||
{
|
||||
return m_version;
|
||||
}
|
||||
|
||||
std::shared_ptr<QNetworkAccessManager> qnam()
|
||||
{
|
||||
return m_qnam;
|
||||
@@ -113,14 +105,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 +144,11 @@ public:
|
||||
*/
|
||||
bool openJsonEditor(const QString &filename);
|
||||
|
||||
/// this is the static data. it stores things that don't move.
|
||||
const QString &staticData()
|
||||
{
|
||||
return staticDataPath;
|
||||
}
|
||||
/// this is the root of the 'installation'. Used for automatic updates
|
||||
const QString &root()
|
||||
{
|
||||
@@ -183,14 +198,21 @@ 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;
|
||||
|
||||
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 +220,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.
|
||||
|
||||
77
WinBacktrace.cpp
Normal file
77
WinBacktrace.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// CAUTION:
|
||||
// This file contains all manner of hackery and insanity.
|
||||
// I will not be responsible for any loss of sanity due to reading this code.
|
||||
// Here be dragons!
|
||||
|
||||
#include "WinBacktrace.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#ifndef __i386__
|
||||
#error WinBacktrace is only supported on x86 architectures.
|
||||
#endif
|
||||
|
||||
// We need to do some crazy shit to walk through the stack.
|
||||
// Windows unwinds the stack when an exception is thrown, so we
|
||||
// need to examine the EXCEPTION_POINTERS's CONTEXT.
|
||||
size_t getBacktrace(StackFrame *stack, size_t size, CONTEXT ctx)
|
||||
{
|
||||
// Written using information and a bit of pseudocode from
|
||||
// http://www.eptacom.net/pubblicazioni/pub_eng/except.html
|
||||
// This is probably one of the most horrifying things I've ever written.
|
||||
|
||||
// This tracks whether the current EBP is valid.
|
||||
// When an invalid EBP is encountered, we stop walking the stack.
|
||||
bool validEBP = true;
|
||||
DWORD ebp = ctx.Ebp; // The current EBP (Extended Base Pointer)
|
||||
DWORD eip = ctx.Eip;
|
||||
int i;
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
if (ebp & 3)
|
||||
validEBP = false;
|
||||
// FIXME: This function is obsolete, according to MSDN.
|
||||
else if (IsBadReadPtr((void*) ebp, 8))
|
||||
validEBP = false;
|
||||
|
||||
if (!validEBP) break;
|
||||
|
||||
// Find the caller.
|
||||
// On the first iteration, the caller is whatever EIP points to.
|
||||
// On successive iterations, the caller is the byte after EBP.
|
||||
BYTE* caller = !i ? (BYTE*)eip : *((BYTE**) ebp + 1);
|
||||
// The first ebp is the EBP from the CONTEXT.
|
||||
// On successive iterations, the EBP is the DWORD that the previous EBP points to.
|
||||
ebp = !i ? ebp : *(DWORD*)ebp;
|
||||
|
||||
// Find the caller's module.
|
||||
// We'll use VirtualQuery to get information about the caller's address.
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
VirtualQuery(caller, &mbi, sizeof(mbi));
|
||||
|
||||
// We can get the instance handle from the allocation base.
|
||||
HINSTANCE hInst = (HINSTANCE)mbi.AllocationBase;
|
||||
|
||||
// If the handle is 0, then the EBP is invalid.
|
||||
if (hInst == 0) validEBP = false;
|
||||
// Otherwise, dump info about the caller.
|
||||
else stack[i].address = (void*)caller;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
44
WinBacktrace.h
Normal file
44
WinBacktrace.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#ifndef SF_STR_LEN
|
||||
// The max length of all strings in the StackFrame struct.
|
||||
// Because it must be stack allocated, this must be known at compile time.
|
||||
// Stuff longer than this will be truncated.
|
||||
// Defaults to 4096 (4kB)
|
||||
#define SF_STR_LEN 4096
|
||||
#endif
|
||||
|
||||
// Data structure for holding information about a stack frame.
|
||||
// There's some more hackery in here so it can be allocated on the stack.
|
||||
struct StackFrame
|
||||
{
|
||||
// The address of this stack frame.
|
||||
void* address;
|
||||
|
||||
// The name of the function at this address.
|
||||
char funcName[SF_STR_LEN];
|
||||
};
|
||||
|
||||
// This function walks through the given CONTEXT structure, extracting a
|
||||
// backtrace from it.
|
||||
// The backtrace will be put into the array given by the `stack` argument
|
||||
// with a maximum length of `size`.
|
||||
// This function returns the size of the backtrace retrieved.
|
||||
size_t getBacktrace(StackFrame* stack, size_t size, CONTEXT ctx);
|
||||
123
changelog.md
Normal file
123
changelog.md
Normal file
@@ -0,0 +1,123 @@
|
||||
#MultiMC Changelog
|
||||
|
||||
##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()
|
||||
@@ -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,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 "OneSixInstance.h"
|
||||
|
||||
class NostalgiaInstance : public OneSixInstance
|
||||
public interface Launcher
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit NostalgiaInstance(const QString &rootDir, SettingsObject *settings,
|
||||
QObject *parent = 0);
|
||||
virtual QString getStatusbarDescription();
|
||||
virtual bool menuActionEnabled(QString action_name) const;
|
||||
};
|
||||
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();
|
||||
21
depends/launcher/org/multimc/NotFoundException.java
Normal file
21
depends/launcher/org/multimc/NotFoundException.java
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class NotFoundException extends Exception
|
||||
{
|
||||
}
|
||||
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,16 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
package org.multimc;
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
public class ParseException extends java.lang.Exception
|
||||
{
|
||||
|
||||
#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
|
||||
}
|
||||
242
depends/launcher/org/multimc/Utils.java
Normal file
242
depends/launcher/org/multimc/Utils.java
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* 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.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unzip zip file 'source' into the folder 'targetFolder'
|
||||
* @param source
|
||||
* @param targetFolder
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void unzip(File source, File targetFolder) throws IOException
|
||||
{
|
||||
ZipFile zip = new ZipFile(source);
|
||||
try
|
||||
{
|
||||
Enumeration entries = zip.entries();
|
||||
|
||||
while (entries.hasMoreElements())
|
||||
{
|
||||
ZipEntry entry = (ZipEntry) entries.nextElement();
|
||||
|
||||
File targetFile = new File(targetFolder, entry.getName());
|
||||
if (targetFile.getParentFile() != null)
|
||||
{
|
||||
targetFile.getParentFile().mkdirs();
|
||||
}
|
||||
|
||||
if (entry.isDirectory())
|
||||
continue;
|
||||
|
||||
copyStream(zip.getInputStream(entry), new BufferedOutputStream(new FileOutputStream(targetFile)));
|
||||
}
|
||||
} finally
|
||||
{
|
||||
zip.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
366
depends/launcher/org/multimc/onesix/OneSixLauncher.java
Normal file
366
depends/launcher/org/multimc/onesix/OneSixLauncher.java
Normal file
@@ -0,0 +1,366 @@
|
||||
/* 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)
|
||||
{
|
||||
Utils.log(" " + s);
|
||||
}
|
||||
Utils.log();
|
||||
|
||||
if(mods.size() > 0)
|
||||
{
|
||||
Utils.log("Class Path Mods:");
|
||||
for (String s : mods)
|
||||
{
|
||||
Utils.log(" " + s);
|
||||
}
|
||||
Utils.log();
|
||||
}
|
||||
|
||||
Utils.log("Params:");
|
||||
Utils.log(" " + mcparams.toString());
|
||||
Utils.log();
|
||||
}
|
||||
|
||||
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.unzip(cleanlibf, new File(natives));
|
||||
} catch (IOException e)
|
||||
{
|
||||
System.err.println("Failed to extract native library:");
|
||||
e.printStackTrace(System.err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
Utils.log();
|
||||
|
||||
// set the native libs path... the brute force way
|
||||
try
|
||||
{
|
||||
System.setProperty("java.library.path", natives);
|
||||
System.setProperty("org.lwjgl.librarypath", natives);
|
||||
System.setProperty("net.java.games.input.librarypath", natives);
|
||||
// by the power of reflection, initialize native libs again. DIRTY!
|
||||
// this is SO BAD. imagine doing that to ld
|
||||
Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
|
||||
fieldSysPath.setAccessible( true );
|
||||
fieldSysPath.set( null, null );
|
||||
} catch (Exception e)
|
||||
{
|
||||
System.err.println("Failed to set the native library path:");
|
||||
e.printStackTrace(System.err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// grab the system classloader and ...
|
||||
cl = ClassLoader.getSystemClassLoader();
|
||||
|
||||
if (traits.contains("legacyLaunch") || traits.contains("alphaLaunch") )
|
||||
{
|
||||
// legacy launch uses the applet wrapper
|
||||
return legacyLaunch();
|
||||
}
|
||||
else
|
||||
{
|
||||
// normal launch just calls main()
|
||||
return launchWithMainClass();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
32
depends/util/include/modutils.h
Normal file
32
depends/util/include/modutils.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include "libutil_config.h"
|
||||
|
||||
class QUrl;
|
||||
|
||||
namespace Util
|
||||
{
|
||||
struct Version
|
||||
{
|
||||
Version(const QString &str);
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
LIBUTIL_EXPORT QUrl expandQMURL(const QString &in);
|
||||
LIBUTIL_EXPORT bool versionIsInInterval(const QString &version, const QString &interval);
|
||||
}
|
||||
|
||||
216
depends/util/src/modutils.cpp
Normal file
216
depends/util/src/modutils.cpp
Normal file
@@ -0,0 +1,216 @@
|
||||
#include "include/modutils.h"
|
||||
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
#include <QRegularExpression>
|
||||
#include <QRegularExpressionMatch>
|
||||
|
||||
Util::Version::Version(const QString &str) : m_string(str)
|
||||
{
|
||||
}
|
||||
|
||||
bool Util::Version::operator<(const Version &other) const
|
||||
{
|
||||
QStringList parts1 = m_string.split('.');
|
||||
QStringList parts2 = other.m_string.split('.');
|
||||
|
||||
while (!parts1.isEmpty() && !parts2.isEmpty())
|
||||
{
|
||||
QString part1 = parts1.isEmpty() ? "0" : parts1.takeFirst();
|
||||
QString part2 = parts2.isEmpty() ? "0" : parts2.takeFirst();
|
||||
bool ok1 = false;
|
||||
bool ok2 = false;
|
||||
int int1 = part1.toInt(&ok1);
|
||||
int int2 = part2.toInt(&ok2);
|
||||
if (ok1 && ok2)
|
||||
{
|
||||
if (int1 == int2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return int1 < int2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (part1 == part2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return part1 < part2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
bool Util::Version::operator<=(const Util::Version &other) const
|
||||
{
|
||||
return *this < other || *this == other;
|
||||
}
|
||||
bool Util::Version::operator>(const Version &other) const
|
||||
{
|
||||
QStringList parts1 = m_string.split('.');
|
||||
QStringList parts2 = other.m_string.split('.');
|
||||
|
||||
while (!parts1.isEmpty() && !parts2.isEmpty())
|
||||
{
|
||||
QString part1 = parts1.isEmpty() ? "0" : parts1.takeFirst();
|
||||
QString part2 = parts2.isEmpty() ? "0" : parts2.takeFirst();
|
||||
bool ok1 = false;
|
||||
bool ok2 = false;
|
||||
int int1 = part1.toInt(&ok1);
|
||||
int int2 = part2.toInt(&ok2);
|
||||
if (ok1 && ok2)
|
||||
{
|
||||
if (int1 == int2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return int1 > int2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (part1 == part2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return part1 > part2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
bool Util::Version::operator==(const Version &other) const
|
||||
{
|
||||
QStringList parts1 = m_string.split('.');
|
||||
QStringList parts2 = other.m_string.split('.');
|
||||
|
||||
while (!parts1.isEmpty() && !parts2.isEmpty())
|
||||
{
|
||||
QString part1 = parts1.isEmpty() ? "0" : parts1.takeFirst();
|
||||
QString part2 = parts2.isEmpty() ? "0" : parts2.takeFirst();
|
||||
bool ok1 = false;
|
||||
bool ok2 = false;
|
||||
int int1 = part1.toInt(&ok1);
|
||||
int int2 = part2.toInt(&ok2);
|
||||
if (ok1 && ok2)
|
||||
{
|
||||
if (int1 == int2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (part1 == part2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
bool Util::Version::operator!=(const Version &other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
QUrl Util::expandQMURL(const QString &in)
|
||||
{
|
||||
QUrl inUrl(in);
|
||||
if (inUrl.scheme() == "github")
|
||||
{
|
||||
// needed because QUrl makes the host all lower cases
|
||||
const QString repo = in.mid(in.indexOf(inUrl.host(), 0, Qt::CaseInsensitive), inUrl.host().size());
|
||||
QUrl out;
|
||||
out.setScheme("https");
|
||||
out.setHost("raw.github.com");
|
||||
out.setPath(QString("/%1/%2/%3%4")
|
||||
.arg(inUrl.userInfo(), repo,
|
||||
inUrl.fragment().isEmpty() ? "master" : inUrl.fragment(), inUrl.path()));
|
||||
return out;
|
||||
}
|
||||
else if (inUrl.scheme() == "mcf")
|
||||
{
|
||||
QUrl out;
|
||||
out.setScheme("http");
|
||||
out.setHost("www.minecraftforum.net");
|
||||
out.setPath(QString("/topic/%1-").arg(inUrl.path()));
|
||||
return out;
|
||||
}
|
||||
else
|
||||
{
|
||||
return in;
|
||||
}
|
||||
}
|
||||
|
||||
bool Util::versionIsInInterval(const QString &version, const QString &interval)
|
||||
{
|
||||
if (interval.isEmpty() || version == 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())
|
||||
{
|
||||
if ((start == '[') && !(version >= bottom))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if ((start == '(') && !(version > bottom))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// check if in range (top)
|
||||
if (!top.isEmpty())
|
||||
{
|
||||
if ((end == ']') && !(version <= top))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if ((end == ')') && !(version < top))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <QDir>
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
#include <QDebug>
|
||||
|
||||
QString PathCombine(QString path1, QString path2)
|
||||
{
|
||||
@@ -138,10 +137,10 @@ void openDirInDefaultProgram(QString path, bool ensureExists)
|
||||
{
|
||||
parentPath.mkpath(dir.absolutePath());
|
||||
}
|
||||
QDesktopServices::openUrl("file:///" + dir.absolutePath());
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath()));
|
||||
}
|
||||
|
||||
void openFileInDefaultProgram(QString filename)
|
||||
{
|
||||
QDesktopServices::openUrl("file:///" + QFileInfo(filename).absolutePath());
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(filename));
|
||||
}
|
||||
|
||||
@@ -75,7 +75,6 @@ bool Util::createShortCut(QString location, QString dest, QStringList args, QStr
|
||||
{
|
||||
#if LINUX
|
||||
location = PathCombine(location, name + ".desktop");
|
||||
qDebug("location: %s", qPrintable(location));
|
||||
|
||||
QFile f(location);
|
||||
f.open(QIODevice::WriteOnly | QIODevice::Text);
|
||||
|
||||
@@ -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>
|
||||
@@ -14,61 +14,130 @@
|
||||
*/
|
||||
|
||||
#include "ConsoleWindow.h"
|
||||
#include "ui_ConsoleWindow.h"
|
||||
#include "MultiMC.h"
|
||||
|
||||
#include <QScrollBar>
|
||||
#include <QMessageBox>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <qlayoutitem.h>
|
||||
|
||||
#include <gui/Platform.h>
|
||||
#include <gui/dialogs/CustomMessageBox.h>
|
||||
#include <gui/dialogs/ProgressDialog.h>
|
||||
#include "widgets/PageContainer.h"
|
||||
#include "pages/LogPage.h"
|
||||
|
||||
#include "logic/net/PasteUpload.h"
|
||||
#include "logic/icons/IconList.h"
|
||||
|
||||
class LogPageProvider : public BasePageProvider
|
||||
{
|
||||
public:
|
||||
LogPageProvider(BasePageProviderPtr parent, BasePage * log_page)
|
||||
{
|
||||
m_parent = parent;
|
||||
m_log_page = log_page;
|
||||
}
|
||||
virtual QString dialogTitle() {return "Fake";};
|
||||
virtual QList<BasePage *> getPages()
|
||||
{
|
||||
auto pages = m_parent->getPages();
|
||||
pages.prepend(m_log_page);
|
||||
return pages;
|
||||
}
|
||||
private:
|
||||
BasePageProviderPtr m_parent;
|
||||
BasePage * m_log_page;
|
||||
};
|
||||
|
||||
ConsoleWindow::ConsoleWindow(MinecraftProcess *mcproc, QWidget *parent)
|
||||
: QMainWindow(parent), ui(new Ui::ConsoleWindow), proc(mcproc)
|
||||
: QMainWindow(parent), m_proc(mcproc)
|
||||
{
|
||||
MultiMCPlatform::fixWM_CLASS(this);
|
||||
ui->setupUi(this);
|
||||
connect(mcproc, SIGNAL(log(QString, MessageLevel::Enum)), this,
|
||||
SLOT(write(QString, MessageLevel::Enum)));
|
||||
connect(mcproc, SIGNAL(ended(BaseInstance *, int, QProcess::ExitStatus)), this,
|
||||
SLOT(onEnded(BaseInstance *, int, QProcess::ExitStatus)));
|
||||
connect(mcproc, SIGNAL(prelaunch_failed(BaseInstance *, int, QProcess::ExitStatus)), this,
|
||||
SLOT(onEnded(BaseInstance *, int, QProcess::ExitStatus)));
|
||||
connect(mcproc, SIGNAL(launch_failed(BaseInstance *)), this,
|
||||
SLOT(onLaunchFailed(BaseInstance *)));
|
||||
|
||||
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 +153,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 +160,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 +196,7 @@ void ConsoleWindow::toggleConsole()
|
||||
{
|
||||
bar->setValue(m_last_scroll_value);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,7 +206,7 @@ void ConsoleWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
toggleConsole();
|
||||
}
|
||||
else
|
||||
else if(m_container->requestClose(event))
|
||||
{
|
||||
MMC->settings()->set("ConsoleWindowState", saveState().toBase64());
|
||||
MMC->settings()->set("ConsoleWindowGeometry", saveGeometry().toBase64());
|
||||
@@ -212,25 +219,23 @@ void ConsoleWindow::closeEvent(QCloseEvent *event)
|
||||
|
||||
void ConsoleWindow::on_btnKillMinecraft_clicked()
|
||||
{
|
||||
ui->btnKillMinecraft->setEnabled(false);
|
||||
m_killButton->setEnabled(false);
|
||||
auto response = CustomMessageBox::selectable(
|
||||
this, tr("Kill Minecraft?"),
|
||||
tr("This can cause the instance to get corrupted and should only be used if Minecraft "
|
||||
"is frozen for some reason"),
|
||||
QMessageBox::Question, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)->exec();
|
||||
if (response == QMessageBox::Yes)
|
||||
proc->killMinecraft();
|
||||
m_proc->killMinecraft();
|
||||
else
|
||||
ui->btnKillMinecraft->setEnabled(true);
|
||||
m_killButton->setEnabled(true);
|
||||
}
|
||||
|
||||
void ConsoleWindow::onEnded(BaseInstance *instance, int code, QProcess::ExitStatus status)
|
||||
void ConsoleWindow::onEnded(InstancePtr instance, int code, QProcess::ExitStatus status)
|
||||
{
|
||||
bool peacefulExit = code == 0 && status != QProcess::CrashExit;
|
||||
ui->btnKillMinecraft->setEnabled(false);
|
||||
|
||||
m_killButton->setEnabled(false);
|
||||
setMayClose(true);
|
||||
|
||||
if (instance->settings().get("AutoCloseConsole").toBool())
|
||||
{
|
||||
if (peacefulExit)
|
||||
@@ -239,35 +244,22 @@ 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()
|
||||
{
|
||||
auto text = ui->text->toPlainText();
|
||||
ProgressDialog dialog(this);
|
||||
PasteUpload *paste = new PasteUpload(this, text);
|
||||
dialog.exec(paste);
|
||||
if (!paste->successful())
|
||||
{
|
||||
CustomMessageBox::selectable(this, "Upload failed", paste->failReason(),
|
||||
QMessageBox::Critical)->exec();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,18 +19,15 @@
|
||||
#include <QSystemTrayIcon>
|
||||
#include "logic/MinecraftProcess.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class ConsoleWindow;
|
||||
}
|
||||
|
||||
class QPushButton;
|
||||
class PageContainer;
|
||||
class ConsoleWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConsoleWindow(MinecraftProcess *proc, QWidget *parent = 0);
|
||||
~ConsoleWindow();
|
||||
virtual ~ConsoleWindow() {};
|
||||
|
||||
/**
|
||||
* @brief specify if the window is allowed to close
|
||||
@@ -39,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
@@ -17,20 +17,19 @@
|
||||
|
||||
#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;
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
@@ -81,10 +80,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 +98,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 +154,8 @@ slots:
|
||||
|
||||
void updateAvailable(QString repo, QString versionName, int versionId);
|
||||
|
||||
void updateNotAvailable();
|
||||
|
||||
void notificationsChanged();
|
||||
|
||||
void activeAccountChanged();
|
||||
@@ -168,11 +165,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 +180,22 @@ 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;
|
||||
InstancePtr m_selectedInstance;
|
||||
QString m_currentInstIcon;
|
||||
|
||||
Task *m_versionLoadTask;
|
||||
|
||||
QLabel *m_statusLeft;
|
||||
class ServerStatus *m_statusRight;
|
||||
|
||||
QMenu *accountMenu;
|
||||
QToolButton *accountMenuButton;
|
||||
|
||||
@@ -6,15 +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">
|
||||
<iconset resource="../resources/multimc/multimc.qrc">
|
||||
<normaloff>:/icons/multimc/scalable/apps/multimc.svg</normaloff>:/icons/multimc/scalable/apps/multimc.svg</iconset>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget">
|
||||
@@ -74,6 +74,7 @@
|
||||
<addaction name="actionReportBug"/>
|
||||
<addaction name="actionAbout"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionPatreon"/>
|
||||
<addaction name="actionCAT"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar"/>
|
||||
@@ -107,14 +108,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 +153,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 +169,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 +185,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 +201,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 +217,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 +233,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 +252,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 +266,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 +303,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 +358,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 +385,18 @@
|
||||
<string>Edit the notes for the selected instance.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionInstanceSettings">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Settings</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Change settings for the selected instance.</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Change settings for the selected instance.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionMakeDesktopShortcut">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Make Shortcut</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Make a shortcut on the desktop for the selected instance.</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Make a shortcut on the desktop for the selected instance.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionManageInstSaves">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Manage Saves</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Manage saves for the selected instance.</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Manage saves for the selected instance.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionEditInstMods">
|
||||
<action name="actionEditInstance">
|
||||
<property name="text">
|
||||
<string>Edit Mods</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Edit the mods for the selected instance.</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Edit the mods for the selected instance.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionChangeInstMCVersion">
|
||||
<property name="text">
|
||||
<string>Change Version</string>
|
||||
<property name="iconText">
|
||||
<string>Edit Instance</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Change the selected instance's Minecraft version.</string>
|
||||
<string>Change the instance settings, mods and versions.</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Change the selected instance's Minecraft version.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionChangeInstLWJGLVersion">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Change LWJGL</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Change the version of LWJGL for the selected instance to use.</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Change the version of LWJGL for the selected instance to use.</string>
|
||||
<string>Change the instance settings, mods and versions.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionViewSelectedInstFolder">
|
||||
@@ -472,20 +434,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 +469,40 @@
|
||||
<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/multimc/multimc.qrc"/>
|
||||
<include location="../resources/instances/instances.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
||||
@@ -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 =
|
||||
"<!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("<p>Loading...</p>");
|
||||
else
|
||||
{
|
||||
QString patronsStr;
|
||||
for (QString patron : patrons)
|
||||
{
|
||||
patronsStr.append(QString("<p>%1</p>").arg(patron));
|
||||
}
|
||||
|
||||
return creditsHtml.arg(patronsStr);
|
||||
}
|
||||
}
|
||||
|
||||
AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent), ui(new Ui::AboutDialog)
|
||||
{
|
||||
MultiMCPlatform::fixWM_CLASS(this);
|
||||
ui->setupUi(this);
|
||||
|
||||
QString chtml = getCreditsHtml(QStringList());
|
||||
ui->creditsText->setHtml(chtml);
|
||||
|
||||
ui->urlLabel->setOpenExternalLinks(true);
|
||||
|
||||
ui->icon->setPixmap(QIcon(":/icons/multimc/scalable/apps/multimc.svg").pixmap(64));
|
||||
ui->title->setText("MultiMC 5 " + MMC->version().toString());
|
||||
ui->title->setText("MultiMC 5 " + BuildConfig.printableVersionString());
|
||||
|
||||
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->versionLabel->setText(tr("Version") +": " + BuildConfig.printableVersionString());
|
||||
ui->vtypeLabel->setText(tr("Version Type") +": " + BuildConfig.versionTypeName());
|
||||
ui->platformLabel->setText(tr("Platform") +": " + BuildConfig.BUILD_PLATFORM);
|
||||
|
||||
if (MMC->version().build >= 0)
|
||||
ui->buildNumLabel->setText(tr("Build Number") +": " + QString::number(MMC->version().build));
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="../../graphics.qrc">:/icons/multimc/scalable/apps/multimc.svg</pixmap>
|
||||
<pixmap resource="../../resources/multimc/multimc.qrc">:/icons/multimc/scalable/apps/multimc.svg</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -96,7 +96,7 @@
|
||||
<item>
|
||||
<widget class="QToolBox" name="toolBox">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="aboutPage">
|
||||
<property name="geometry">
|
||||
@@ -201,7 +201,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>
|
||||
@@ -246,18 +246,7 @@
|
||||
<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>
|
||||
<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></body></html></string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
@@ -430,7 +419,36 @@ 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></body></html></string>
|
||||
<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; 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-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 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="-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></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -508,7 +526,7 @@ p, li { white-space: pre-wrap; }
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../../graphics.qrc"/>
|
||||
<include location="../../resources/multimc/multimc.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <gui/dialogs/EditAccountDialog.h>
|
||||
#include <gui/dialogs/ProgressDialog.h>
|
||||
#include <gui/dialogs/AccountSelectDialog.h>
|
||||
#include <gui/dialogs/LoginDialog.h>
|
||||
#include "CustomMessageBox.h"
|
||||
#include <logic/tasks/Task.h>
|
||||
#include <logic/auth/YggdrasilTask.h>
|
||||
@@ -45,10 +46,11 @@ AccountListDialog::AccountListDialog(QWidget *parent)
|
||||
// Expand the account column
|
||||
ui->listView->header()->setSectionResizeMode(1, QHeaderView::Stretch);
|
||||
|
||||
QItemSelectionModel* selectionModel = ui->listView->selectionModel();
|
||||
QItemSelectionModel *selectionModel = ui->listView->selectionModel();
|
||||
|
||||
connect(selectionModel, &QItemSelectionModel::selectionChanged,
|
||||
[this] (const QItemSelection& sel, const QItemSelection& dsel) { updateButtonStates(); });
|
||||
connect(selectionModel, &QItemSelectionModel::selectionChanged,
|
||||
[this](const QItemSelection &sel, const QItemSelection &dsel)
|
||||
{ updateButtonStates(); });
|
||||
|
||||
connect(m_accounts.get(), SIGNAL(listChanged()), SLOT(listChanged()));
|
||||
connect(m_accounts.get(), SIGNAL(activeAccountChanged()), SLOT(listChanged()));
|
||||
@@ -68,7 +70,8 @@ void AccountListDialog::listChanged()
|
||||
|
||||
void AccountListDialog::on_addAccountBtn_clicked()
|
||||
{
|
||||
addAccount(tr("Please enter your Mojang or Minecraft account username and password to add your account."));
|
||||
addAccount(tr("Please enter your Mojang or Minecraft account username and password to add "
|
||||
"your account."));
|
||||
}
|
||||
|
||||
void AccountListDialog::on_rmAccountBtn_clicked()
|
||||
@@ -87,7 +90,8 @@ void AccountListDialog::on_setDefaultBtn_clicked()
|
||||
if (selection.size() > 0)
|
||||
{
|
||||
QModelIndex selected = selection.first();
|
||||
MojangAccountPtr account = selected.data(MojangAccountList::PointerRole).value<MojangAccountPtr>();
|
||||
MojangAccountPtr account =
|
||||
selected.data(MojangAccountList::PointerRole).value<MojangAccountPtr>();
|
||||
m_accounts->setActiveAccount(account->username());
|
||||
}
|
||||
}
|
||||
@@ -113,48 +117,29 @@ void AccountListDialog::updateButtonStates()
|
||||
ui->noDefaultBtn->setDown(m_accounts->activeAccount().get() == nullptr);
|
||||
}
|
||||
|
||||
void AccountListDialog::addAccount(const QString& errMsg)
|
||||
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();
|
||||
// TODO: The login dialog isn't quite done yet
|
||||
MojangAccountPtr account = LoginDialog::newAccount(this, errMsg);
|
||||
|
||||
if (loginDialog.result() == QDialog::Accepted)
|
||||
if (account != nullptr)
|
||||
{
|
||||
QString username(loginDialog.username());
|
||||
QString password(loginDialog.password());
|
||||
m_accounts->addAccount(account);
|
||||
if (m_accounts->count() == 1)
|
||||
m_accounts->setActiveAccount(account->username());
|
||||
|
||||
MojangAccountPtr account = MojangAccount::createFromUsername(username);
|
||||
ProgressDialog progDialog(this);
|
||||
auto task = account->login(password);
|
||||
progDialog.exec(task.get());
|
||||
if(task->successful())
|
||||
// Grab associated player skins
|
||||
auto job = new NetJob("Player skins: " + account->username());
|
||||
|
||||
for (AccountProfile profile : account->profiles())
|
||||
{
|
||||
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;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,11 +28,10 @@
|
||||
#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"
|
||||
|
||||
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);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <QDialog>
|
||||
#include "logic/BaseVersion.h"
|
||||
#include <logic/BaseInstance.h>
|
||||
|
||||
class BaseInstance;
|
||||
|
||||
@@ -30,7 +31,7 @@ class CopyInstanceDialog : public QDialog
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CopyInstanceDialog(BaseInstance *original, QWidget *parent = 0);
|
||||
explicit CopyInstanceDialog(InstancePtr original, QWidget *parent = 0);
|
||||
~CopyInstanceDialog();
|
||||
|
||||
void updateDialogState();
|
||||
@@ -46,5 +47,5 @@ slots:
|
||||
private:
|
||||
Ui::CopyInstanceDialog *ui;
|
||||
QString InstIconKey;
|
||||
BaseInstance *m_original;
|
||||
InstancePtr m_original;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "EditNotesDialog.h"
|
||||
#include "ui_EditNotesDialog.h"
|
||||
#include "gui/Platform.h"
|
||||
|
||||
#include <QIcon>
|
||||
#include <QApplication>
|
||||
|
||||
EditNotesDialog::EditNotesDialog(QString notes, QString name, QWidget *parent)
|
||||
: QDialog(parent), ui(new Ui::EditNotesDialog), m_instance_name(name),
|
||||
m_instance_notes(notes)
|
||||
{
|
||||
MultiMCPlatform::fixWM_CLASS(this);
|
||||
ui->setupUi(this);
|
||||
ui->noteEditor->setText(notes);
|
||||
setWindowTitle(tr("Edit notes of %1").arg(m_instance_name));
|
||||
// connect(ui->closeButton, SIGNAL(clicked()), SLOT(close()));
|
||||
}
|
||||
|
||||
EditNotesDialog::~EditNotesDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
QString EditNotesDialog::getText()
|
||||
{
|
||||
return ui->noteEditor->toPlainText();
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditNotesDialog</class>
|
||||
<widget class="QDialog" name="EditNotesDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>459</width>
|
||||
<height>399</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Edit Notes</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTextEdit" name="noteEditor">
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
</property>
|
||||
<property name="acceptRichText">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextEditable|Qt::TextEditorInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>EditNotesDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>EditNotesDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "ui_IconPickerDialog.h"
|
||||
|
||||
#include "gui/Platform.h"
|
||||
#include "gui/widgets/InstanceDelegate.h"
|
||||
#include "gui/groupview/InstanceDelegate.h"
|
||||
|
||||
#include "logic/icons/IconList.h"
|
||||
|
||||
|
||||
@@ -29,7 +29,10 @@ class IconPickerDialog : public QDialog
|
||||
public:
|
||||
explicit IconPickerDialog(QWidget *parent = 0);
|
||||
~IconPickerDialog();
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Woverloaded-virtual"
|
||||
int exec(QString selection);
|
||||
#pragma clang diagnostic pop
|
||||
QString selectedIconKey;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -1,243 +0,0 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Authors: Andrew Okin
|
||||
* Peterix
|
||||
* Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MultiMC.h"
|
||||
#include "InstanceSettings.h"
|
||||
#include "ui_InstanceSettings.h"
|
||||
#include "gui/Platform.h"
|
||||
#include "gui/dialogs/VersionSelectDialog.h"
|
||||
|
||||
#include "logic/JavaUtils.h"
|
||||
#include "logic/NagUtils.h"
|
||||
#include "logic/lists/JavaVersionList.h"
|
||||
#include "logic/JavaChecker.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
InstanceSettings::InstanceSettings(SettingsObject *obj, QWidget *parent)
|
||||
: QDialog(parent), ui(new Ui::InstanceSettings), m_obj(obj)
|
||||
{
|
||||
MultiMCPlatform::fixWM_CLASS(this);
|
||||
ui->setupUi(this);
|
||||
|
||||
restoreGeometry(QByteArray::fromBase64(MMC->settings()->get("SettingsGeometry").toByteArray()));
|
||||
|
||||
loadSettings();
|
||||
}
|
||||
|
||||
InstanceSettings::~InstanceSettings()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void InstanceSettings::showEvent(QShowEvent *ev)
|
||||
{
|
||||
QDialog::showEvent(ev);
|
||||
}
|
||||
|
||||
void InstanceSettings::closeEvent(QCloseEvent *ev)
|
||||
{
|
||||
MMC->settings()->set("SettingsGeometry", saveGeometry().toBase64());
|
||||
|
||||
QDialog::closeEvent(ev);
|
||||
}
|
||||
|
||||
void InstanceSettings::on_customCommandsGroupBox_toggled(bool state)
|
||||
{
|
||||
ui->labelCustomCmdsDescription->setEnabled(state);
|
||||
}
|
||||
|
||||
void InstanceSettings::on_buttonBox_accepted()
|
||||
{
|
||||
MMC->settings()->set("SettingsGeometry", saveGeometry().toBase64());
|
||||
|
||||
applySettings();
|
||||
accept();
|
||||
}
|
||||
|
||||
void InstanceSettings::on_buttonBox_rejected()
|
||||
{
|
||||
MMC->settings()->set("SettingsGeometry", saveGeometry().toBase64());
|
||||
|
||||
reject();
|
||||
}
|
||||
|
||||
void InstanceSettings::applySettings()
|
||||
{
|
||||
// Console
|
||||
bool console = ui->consoleSettingsBox->isChecked();
|
||||
m_obj->set("OverrideConsole", console);
|
||||
if (console)
|
||||
{
|
||||
m_obj->set("ShowConsole", ui->showConsoleCheck->isChecked());
|
||||
m_obj->set("AutoCloseConsole", ui->autoCloseConsoleCheck->isChecked());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_obj->reset("ShowConsole");
|
||||
m_obj->reset("AutoCloseConsole");
|
||||
}
|
||||
|
||||
// Window Size
|
||||
bool window = ui->windowSizeGroupBox->isChecked();
|
||||
m_obj->set("OverrideWindow", window);
|
||||
if (window)
|
||||
{
|
||||
m_obj->set("LaunchMaximized", ui->maximizedCheckBox->isChecked());
|
||||
m_obj->set("MinecraftWinWidth", ui->windowWidthSpinBox->value());
|
||||
m_obj->set("MinecraftWinHeight", ui->windowHeightSpinBox->value());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_obj->reset("LaunchMaximized");
|
||||
m_obj->reset("MinecraftWinWidth");
|
||||
m_obj->reset("MinecraftWinHeight");
|
||||
}
|
||||
|
||||
// Memory
|
||||
bool memory = ui->memoryGroupBox->isChecked();
|
||||
m_obj->set("OverrideMemory", memory);
|
||||
if (memory)
|
||||
{
|
||||
m_obj->set("MinMemAlloc", ui->minMemSpinBox->value());
|
||||
m_obj->set("MaxMemAlloc", ui->maxMemSpinBox->value());
|
||||
m_obj->set("PermGen", ui->permGenSpinBox->value());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_obj->reset("MinMemAlloc");
|
||||
m_obj->reset("MaxMemAlloc");
|
||||
m_obj->reset("PermGen");
|
||||
}
|
||||
|
||||
// Java Settings
|
||||
bool java = ui->javaSettingsGroupBox->isChecked();
|
||||
m_obj->set("OverrideJava", java);
|
||||
if (java)
|
||||
{
|
||||
m_obj->set("JavaPath", ui->javaPathTextBox->text());
|
||||
m_obj->set("JvmArgs", ui->jvmArgsTextBox->text());
|
||||
|
||||
NagUtils::checkJVMArgs(m_obj->get("JvmArgs").toString(), this->parentWidget());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_obj->reset("JavaPath");
|
||||
m_obj->reset("JvmArgs");
|
||||
}
|
||||
|
||||
// Custom Commands
|
||||
bool custcmd = ui->customCommandsGroupBox->isChecked();
|
||||
m_obj->set("OverrideCommands", custcmd);
|
||||
if (custcmd)
|
||||
{
|
||||
m_obj->set("PreLaunchCommand", ui->preLaunchCmdTextBox->text());
|
||||
m_obj->set("PostExitCommand", ui->postExitCmdTextBox->text());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_obj->reset("PreLaunchCommand");
|
||||
m_obj->reset("PostExitCommand");
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceSettings::loadSettings()
|
||||
{
|
||||
// Console
|
||||
ui->consoleSettingsBox->setChecked(m_obj->get("OverrideConsole").toBool());
|
||||
ui->showConsoleCheck->setChecked(m_obj->get("ShowConsole").toBool());
|
||||
ui->autoCloseConsoleCheck->setChecked(m_obj->get("AutoCloseConsole").toBool());
|
||||
|
||||
// Window Size
|
||||
ui->windowSizeGroupBox->setChecked(m_obj->get("OverrideWindow").toBool());
|
||||
ui->maximizedCheckBox->setChecked(m_obj->get("LaunchMaximized").toBool());
|
||||
ui->windowWidthSpinBox->setValue(m_obj->get("MinecraftWinWidth").toInt());
|
||||
ui->windowHeightSpinBox->setValue(m_obj->get("MinecraftWinHeight").toInt());
|
||||
|
||||
// Memory
|
||||
ui->memoryGroupBox->setChecked(m_obj->get("OverrideMemory").toBool());
|
||||
ui->minMemSpinBox->setValue(m_obj->get("MinMemAlloc").toInt());
|
||||
ui->maxMemSpinBox->setValue(m_obj->get("MaxMemAlloc").toInt());
|
||||
ui->permGenSpinBox->setValue(m_obj->get("PermGen").toInt());
|
||||
|
||||
// Java Settings
|
||||
ui->javaSettingsGroupBox->setChecked(m_obj->get("OverrideJava").toBool());
|
||||
ui->javaPathTextBox->setText(m_obj->get("JavaPath").toString());
|
||||
ui->jvmArgsTextBox->setText(m_obj->get("JvmArgs").toString());
|
||||
|
||||
// Custom Commands
|
||||
ui->customCommandsGroupBox->setChecked(m_obj->get("OverrideCommands").toBool());
|
||||
ui->preLaunchCmdTextBox->setText(m_obj->get("PreLaunchCommand").toString());
|
||||
ui->postExitCmdTextBox->setText(m_obj->get("PostExitCommand").toString());
|
||||
}
|
||||
|
||||
void InstanceSettings::on_javaDetectBtn_clicked()
|
||||
{
|
||||
JavaVersionPtr java;
|
||||
|
||||
VersionSelectDialog vselect(MMC->javalist().get(), tr("Select a Java version"), this, true);
|
||||
vselect.setResizeOn(2);
|
||||
vselect.exec();
|
||||
|
||||
if (vselect.result() == QDialog::Accepted && vselect.selectedVersion())
|
||||
{
|
||||
java = std::dynamic_pointer_cast<JavaVersion>(vselect.selectedVersion());
|
||||
ui->javaPathTextBox->setText(java->path);
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceSettings::on_javaBrowseBtn_clicked()
|
||||
{
|
||||
QString dir = QFileDialog::getOpenFileName(this, tr("Find Java executable"));
|
||||
if (!dir.isNull())
|
||||
{
|
||||
ui->javaPathTextBox->setText(dir);
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceSettings::on_javaTestBtn_clicked()
|
||||
{
|
||||
checker.reset(new JavaChecker());
|
||||
connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this,
|
||||
SLOT(checkFinished(JavaCheckResult)));
|
||||
checker->path = ui->javaPathTextBox->text();
|
||||
checker->performCheck();
|
||||
}
|
||||
|
||||
void InstanceSettings::checkFinished(JavaCheckResult result)
|
||||
{
|
||||
if (result.valid)
|
||||
{
|
||||
QString text;
|
||||
text += "Java test succeeded!\n";
|
||||
if (result.is_64bit)
|
||||
text += "Using 64bit java.\n";
|
||||
text += "\n";
|
||||
text += "Platform reported: " + result.realPlatform;
|
||||
QMessageBox::information(this, tr("Java test success"), text);
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(
|
||||
this, tr("Java test failure"),
|
||||
tr("The specified java binary didn't work. You should use the auto-detect feature, "
|
||||
"or set the path to the java executable."));
|
||||
}
|
||||
}
|
||||
@@ -1,393 +0,0 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MultiMC.h"
|
||||
#include "LegacyModEditDialog.h"
|
||||
#include "ModEditDialogCommon.h"
|
||||
#include "VersionSelectDialog.h"
|
||||
#include "ProgressDialog.h"
|
||||
#include "ui_LegacyModEditDialog.h"
|
||||
#include "logic/ModList.h"
|
||||
#include "logic/lists/ForgeVersionList.h"
|
||||
#include "gui/Platform.h"
|
||||
|
||||
#include <pathutils.h>
|
||||
#include <QFileDialog>
|
||||
//#include <QMessageBox>
|
||||
#include <QDebug>
|
||||
#include <QEvent>
|
||||
#include <QKeyEvent>
|
||||
|
||||
LegacyModEditDialog::LegacyModEditDialog(LegacyInstance *inst, QWidget *parent)
|
||||
: QDialog(parent), ui(new Ui::LegacyModEditDialog), m_inst(inst)
|
||||
{
|
||||
MultiMCPlatform::fixWM_CLASS(this);
|
||||
ui->setupUi(this);
|
||||
|
||||
// Jar mods
|
||||
{
|
||||
ensureFolderPathExists(m_inst->jarModsDir());
|
||||
m_jarmods = m_inst->jarModList();
|
||||
ui->jarModsTreeView->setModel(m_jarmods.get());
|
||||
#ifndef Q_OS_LINUX
|
||||
// FIXME: internal DnD causes segfaults later
|
||||
ui->jarModsTreeView->setDragDropMode(QAbstractItemView::DragDrop);
|
||||
// FIXME: DnD is glitched with contiguous (we move only first item in selection)
|
||||
ui->jarModsTreeView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
#endif
|
||||
ui->jarModsTreeView->installEventFilter(this);
|
||||
m_jarmods->startWatching();
|
||||
auto smodel = ui->jarModsTreeView->selectionModel();
|
||||
connect(smodel, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
|
||||
SLOT(jarCurrent(QModelIndex, QModelIndex)));
|
||||
}
|
||||
// Core mods
|
||||
{
|
||||
ensureFolderPathExists(m_inst->coreModsDir());
|
||||
m_coremods = m_inst->coreModList();
|
||||
ui->coreModsTreeView->setModel(m_coremods.get());
|
||||
ui->coreModsTreeView->installEventFilter(this);
|
||||
m_coremods->startWatching();
|
||||
auto smodel = ui->coreModsTreeView->selectionModel();
|
||||
connect(smodel, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
|
||||
SLOT(coreCurrent(QModelIndex, QModelIndex)));
|
||||
}
|
||||
// Loader mods
|
||||
{
|
||||
ensureFolderPathExists(m_inst->loaderModsDir());
|
||||
m_mods = m_inst->loaderModList();
|
||||
ui->loaderModTreeView->setModel(m_mods.get());
|
||||
ui->loaderModTreeView->installEventFilter(this);
|
||||
m_mods->startWatching();
|
||||
auto smodel = ui->loaderModTreeView->selectionModel();
|
||||
connect(smodel, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
|
||||
SLOT(loaderCurrent(QModelIndex, QModelIndex)));
|
||||
}
|
||||
// texture packs
|
||||
{
|
||||
ensureFolderPathExists(m_inst->texturePacksDir());
|
||||
m_texturepacks = m_inst->texturePackList();
|
||||
ui->texPackTreeView->setModel(m_texturepacks.get());
|
||||
ui->texPackTreeView->installEventFilter(this);
|
||||
m_texturepacks->startWatching();
|
||||
}
|
||||
}
|
||||
|
||||
LegacyModEditDialog::~LegacyModEditDialog()
|
||||
{
|
||||
m_mods->stopWatching();
|
||||
m_coremods->stopWatching();
|
||||
m_jarmods->stopWatching();
|
||||
m_texturepacks->stopWatching();
|
||||
delete ui;
|
||||
}
|
||||
|
||||
bool LegacyModEditDialog::coreListFilter(QKeyEvent *keyEvent)
|
||||
{
|
||||
switch (keyEvent->key())
|
||||
{
|
||||
case Qt::Key_Delete:
|
||||
on_rmCoreBtn_clicked();
|
||||
return true;
|
||||
case Qt::Key_Plus:
|
||||
on_addCoreBtn_clicked();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QDialog::eventFilter(ui->coreModsTreeView, keyEvent);
|
||||
}
|
||||
|
||||
bool LegacyModEditDialog::jarListFilter(QKeyEvent *keyEvent)
|
||||
{
|
||||
switch (keyEvent->key())
|
||||
{
|
||||
case Qt::Key_Up:
|
||||
{
|
||||
if (keyEvent->modifiers() & Qt::ControlModifier)
|
||||
{
|
||||
on_moveJarUpBtn_clicked();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Qt::Key_Down:
|
||||
{
|
||||
if (keyEvent->modifiers() & Qt::ControlModifier)
|
||||
{
|
||||
on_moveJarDownBtn_clicked();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Qt::Key_Delete:
|
||||
on_rmJarBtn_clicked();
|
||||
return true;
|
||||
case Qt::Key_Plus:
|
||||
on_addJarBtn_clicked();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QDialog::eventFilter(ui->jarModsTreeView, keyEvent);
|
||||
}
|
||||
|
||||
bool LegacyModEditDialog::loaderListFilter(QKeyEvent *keyEvent)
|
||||
{
|
||||
switch (keyEvent->key())
|
||||
{
|
||||
case Qt::Key_Delete:
|
||||
on_rmModBtn_clicked();
|
||||
return true;
|
||||
case Qt::Key_Plus:
|
||||
on_addModBtn_clicked();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QDialog::eventFilter(ui->loaderModTreeView, keyEvent);
|
||||
}
|
||||
|
||||
bool LegacyModEditDialog::texturePackListFilter(QKeyEvent *keyEvent)
|
||||
{
|
||||
switch (keyEvent->key())
|
||||
{
|
||||
case Qt::Key_Delete:
|
||||
on_rmTexPackBtn_clicked();
|
||||
return true;
|
||||
case Qt::Key_Plus:
|
||||
on_addTexPackBtn_clicked();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QDialog::eventFilter(ui->texPackTreeView, keyEvent);
|
||||
}
|
||||
|
||||
bool LegacyModEditDialog::eventFilter(QObject *obj, QEvent *ev)
|
||||
{
|
||||
if (ev->type() != QEvent::KeyPress)
|
||||
{
|
||||
return QDialog::eventFilter(obj, ev);
|
||||
}
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
|
||||
if (obj == ui->jarModsTreeView)
|
||||
return jarListFilter(keyEvent);
|
||||
if (obj == ui->coreModsTreeView)
|
||||
return coreListFilter(keyEvent);
|
||||
if (obj == ui->loaderModTreeView)
|
||||
return loaderListFilter(keyEvent);
|
||||
if (obj == ui->texPackTreeView)
|
||||
return texturePackListFilter(keyEvent);
|
||||
return QDialog::eventFilter(obj, ev);
|
||||
}
|
||||
|
||||
void LegacyModEditDialog::on_addCoreBtn_clicked()
|
||||
{
|
||||
//: Title of core mod selection dialog
|
||||
QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Select Core Mods"));
|
||||
for (auto filename : fileNames)
|
||||
{
|
||||
m_coremods->stopWatching();
|
||||
m_coremods->installMod(QFileInfo(filename));
|
||||
m_coremods->startWatching();
|
||||
}
|
||||
}
|
||||
void LegacyModEditDialog::on_addForgeBtn_clicked()
|
||||
{
|
||||
VersionSelectDialog vselect(MMC->forgelist().get(), tr("Select Forge version"), this);
|
||||
vselect.setFilter(1, m_inst->intendedVersionId());
|
||||
if (vselect.exec() && vselect.selectedVersion())
|
||||
{
|
||||
ForgeVersionPtr forge =
|
||||
std::dynamic_pointer_cast<ForgeVersion>(vselect.selectedVersion());
|
||||
if (!forge)
|
||||
return;
|
||||
auto entry = MMC->metacache()->resolveEntry("minecraftforge", forge->filename);
|
||||
if (entry->stale)
|
||||
{
|
||||
NetJob *fjob = new NetJob("Forge download");
|
||||
fjob->addNetAction(CacheDownload::make(forge->universal_url, entry));
|
||||
ProgressDialog dlg(this);
|
||||
dlg.exec(fjob);
|
||||
if (dlg.result() == QDialog::Accepted)
|
||||
{
|
||||
m_jarmods->stopWatching();
|
||||
m_jarmods->installMod(QFileInfo(entry->getFullPath()));
|
||||
m_jarmods->startWatching();
|
||||
}
|
||||
else
|
||||
{
|
||||
// failed to download forge :/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_jarmods->stopWatching();
|
||||
m_jarmods->installMod(QFileInfo(entry->getFullPath()));
|
||||
m_jarmods->startWatching();
|
||||
}
|
||||
}
|
||||
}
|
||||
void LegacyModEditDialog::on_addJarBtn_clicked()
|
||||
{
|
||||
//: Title of jar mod selection dialog
|
||||
QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Select Jar Mods"));
|
||||
for (auto filename : fileNames)
|
||||
{
|
||||
m_jarmods->stopWatching();
|
||||
m_jarmods->installMod(QFileInfo(filename));
|
||||
m_jarmods->startWatching();
|
||||
}
|
||||
}
|
||||
void LegacyModEditDialog::on_addModBtn_clicked()
|
||||
{
|
||||
//: Title of regular mod selection dialog
|
||||
QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Select Loader Mods"));
|
||||
for (auto filename : fileNames)
|
||||
{
|
||||
m_mods->stopWatching();
|
||||
m_mods->installMod(QFileInfo(filename));
|
||||
m_mods->startWatching();
|
||||
}
|
||||
}
|
||||
void LegacyModEditDialog::on_addTexPackBtn_clicked()
|
||||
{
|
||||
//: Title of texture pack selection dialog
|
||||
QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Select Texture Packs"));
|
||||
for (auto filename : fileNames)
|
||||
{
|
||||
m_texturepacks->stopWatching();
|
||||
m_texturepacks->installMod(QFileInfo(filename));
|
||||
m_texturepacks->startWatching();
|
||||
}
|
||||
}
|
||||
|
||||
void LegacyModEditDialog::on_moveJarDownBtn_clicked()
|
||||
{
|
||||
int first, last;
|
||||
auto list = ui->jarModsTreeView->selectionModel()->selectedRows();
|
||||
|
||||
if (!lastfirst(list, first, last))
|
||||
return;
|
||||
|
||||
m_jarmods->moveModsDown(first, last);
|
||||
}
|
||||
void LegacyModEditDialog::on_moveJarUpBtn_clicked()
|
||||
{
|
||||
int first, last;
|
||||
auto list = ui->jarModsTreeView->selectionModel()->selectedRows();
|
||||
|
||||
if (!lastfirst(list, first, last))
|
||||
return;
|
||||
m_jarmods->moveModsUp(first, last);
|
||||
}
|
||||
void LegacyModEditDialog::on_rmCoreBtn_clicked()
|
||||
{
|
||||
int first, last;
|
||||
auto list = ui->coreModsTreeView->selectionModel()->selectedRows();
|
||||
|
||||
if (!lastfirst(list, first, last))
|
||||
return;
|
||||
m_coremods->stopWatching();
|
||||
m_coremods->deleteMods(first, last);
|
||||
m_coremods->startWatching();
|
||||
}
|
||||
void LegacyModEditDialog::on_rmJarBtn_clicked()
|
||||
{
|
||||
int first, last;
|
||||
auto list = ui->jarModsTreeView->selectionModel()->selectedRows();
|
||||
|
||||
if (!lastfirst(list, first, last))
|
||||
return;
|
||||
m_jarmods->stopWatching();
|
||||
m_jarmods->deleteMods(first, last);
|
||||
m_jarmods->startWatching();
|
||||
}
|
||||
void LegacyModEditDialog::on_rmModBtn_clicked()
|
||||
{
|
||||
int first, last;
|
||||
auto list = ui->loaderModTreeView->selectionModel()->selectedRows();
|
||||
|
||||
if (!lastfirst(list, first, last))
|
||||
return;
|
||||
m_mods->stopWatching();
|
||||
m_mods->deleteMods(first, last);
|
||||
m_mods->startWatching();
|
||||
}
|
||||
void LegacyModEditDialog::on_rmTexPackBtn_clicked()
|
||||
{
|
||||
int first, last;
|
||||
auto list = ui->texPackTreeView->selectionModel()->selectedRows();
|
||||
|
||||
if (!lastfirst(list, first, last))
|
||||
return;
|
||||
m_texturepacks->stopWatching();
|
||||
m_texturepacks->deleteMods(first, last);
|
||||
m_texturepacks->startWatching();
|
||||
}
|
||||
void LegacyModEditDialog::on_viewCoreBtn_clicked()
|
||||
{
|
||||
openDirInDefaultProgram(m_inst->coreModsDir(), true);
|
||||
}
|
||||
void LegacyModEditDialog::on_viewModBtn_clicked()
|
||||
{
|
||||
openDirInDefaultProgram(m_inst->loaderModsDir(), true);
|
||||
}
|
||||
void LegacyModEditDialog::on_viewTexPackBtn_clicked()
|
||||
{
|
||||
openDirInDefaultProgram(m_inst->texturePacksDir(), true);
|
||||
}
|
||||
|
||||
void LegacyModEditDialog::on_buttonBox_rejected()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void LegacyModEditDialog::jarCurrent(QModelIndex current, QModelIndex previous)
|
||||
{
|
||||
if (!current.isValid())
|
||||
{
|
||||
ui->jarMIFrame->clear();
|
||||
return;
|
||||
}
|
||||
int row = current.row();
|
||||
Mod &m = m_jarmods->operator[](row);
|
||||
ui->jarMIFrame->updateWithMod(m);
|
||||
}
|
||||
|
||||
void LegacyModEditDialog::coreCurrent(QModelIndex current, QModelIndex previous)
|
||||
{
|
||||
if (!current.isValid())
|
||||
{
|
||||
ui->coreMIFrame->clear();
|
||||
return;
|
||||
}
|
||||
int row = current.row();
|
||||
Mod &m = m_coremods->operator[](row);
|
||||
ui->coreMIFrame->updateWithMod(m);
|
||||
}
|
||||
|
||||
void LegacyModEditDialog::loaderCurrent(QModelIndex current, QModelIndex previous)
|
||||
{
|
||||
if (!current.isValid())
|
||||
{
|
||||
ui->loaderMIFrame->clear();
|
||||
return;
|
||||
}
|
||||
int row = current.row();
|
||||
Mod &m = m_mods->operator[](row);
|
||||
ui->loaderMIFrame->updateWithMod(m);
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include "logic/LegacyInstance.h"
|
||||
#include <logic/net/NetJob.h>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class LegacyModEditDialog;
|
||||
}
|
||||
|
||||
class LegacyModEditDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit LegacyModEditDialog(LegacyInstance *inst, QWidget *parent = 0);
|
||||
~LegacyModEditDialog();
|
||||
|
||||
private
|
||||
slots:
|
||||
|
||||
void on_addJarBtn_clicked();
|
||||
void on_rmJarBtn_clicked();
|
||||
void on_addForgeBtn_clicked();
|
||||
void on_moveJarUpBtn_clicked();
|
||||
void on_moveJarDownBtn_clicked();
|
||||
|
||||
void on_addCoreBtn_clicked();
|
||||
void on_rmCoreBtn_clicked();
|
||||
void on_viewCoreBtn_clicked();
|
||||
|
||||
void on_addModBtn_clicked();
|
||||
void on_rmModBtn_clicked();
|
||||
void on_viewModBtn_clicked();
|
||||
|
||||
void on_addTexPackBtn_clicked();
|
||||
void on_rmTexPackBtn_clicked();
|
||||
void on_viewTexPackBtn_clicked();
|
||||
|
||||
// Questionable: SettingsDialog doesn't need this for some reason?
|
||||
void on_buttonBox_rejected();
|
||||
|
||||
void jarCurrent(QModelIndex current, QModelIndex previous);
|
||||
void coreCurrent(QModelIndex current, QModelIndex previous);
|
||||
void loaderCurrent(QModelIndex current, QModelIndex previous);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *ev);
|
||||
bool jarListFilter(QKeyEvent *ev);
|
||||
bool coreListFilter(QKeyEvent *ev);
|
||||
bool loaderListFilter(QKeyEvent *ev);
|
||||
bool texturePackListFilter(QKeyEvent *ev);
|
||||
|
||||
private:
|
||||
Ui::LegacyModEditDialog *ui;
|
||||
std::shared_ptr<ModList> m_mods;
|
||||
std::shared_ptr<ModList> m_coremods;
|
||||
std::shared_ptr<ModList> m_jarmods;
|
||||
std::shared_ptr<ModList> m_texturepacks;
|
||||
LegacyInstance *m_inst;
|
||||
NetJobPtr forgeJob;
|
||||
};
|
||||
@@ -1,321 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>LegacyModEditDialog</class>
|
||||
<widget class="QDialog" name="LegacyModEditDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>540</width>
|
||||
<height>420</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Edit Mods</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="jarTab">
|
||||
<attribute name="title">
|
||||
<string>Jar Mods</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="ModListView" name="jarModsTreeView">
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="jarModsButtonBox">
|
||||
<item>
|
||||
<widget class="QPushButton" name="addJarBtn">
|
||||
<property name="text">
|
||||
<string>&Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="rmJarBtn">
|
||||
<property name="text">
|
||||
<string>&Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="addForgeBtn">
|
||||
<property name="text">
|
||||
<string>MCForge</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="jarModsButtonSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="moveJarUpBtn">
|
||||
<property name="text">
|
||||
<string>Move &Up</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="moveJarDownBtn">
|
||||
<property name="text">
|
||||
<string>Move &Down</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="MCModInfoFrame" name="jarMIFrame">
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="coreTab">
|
||||
<attribute name="title">
|
||||
<string>Core Mods</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="ModListView" name="coreModsTreeView">
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DropOnly</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="coreModsButtonBox">
|
||||
<item>
|
||||
<widget class="QPushButton" name="addCoreBtn">
|
||||
<property name="text">
|
||||
<string>&Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="rmCoreBtn">
|
||||
<property name="text">
|
||||
<string>&Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="coreModsButtonSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="viewCoreBtn">
|
||||
<property name="text">
|
||||
<string>&View Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="MCModInfoFrame" name="coreMIFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="modTab">
|
||||
<attribute name="title">
|
||||
<string>Loader Mods</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="ModListView" name="loaderModTreeView">
|
||||
<property name="acceptDrops">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DropOnly</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="mlModsButtonBox">
|
||||
<item>
|
||||
<widget class="QPushButton" name="addModBtn">
|
||||
<property name="text">
|
||||
<string>&Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="rmModBtn">
|
||||
<property name="text">
|
||||
<string>&Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="mlModsButtonSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="viewModBtn">
|
||||
<property name="text">
|
||||
<string>&View Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="MCModInfoFrame" name="loaderMIFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="texPackTab">
|
||||
<property name="acceptDrops">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>Texture Packs</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="ModListView" name="texPackTreeView">
|
||||
<property name="acceptDrops">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DropOnly</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="texturePacksButtonBox">
|
||||
<item>
|
||||
<widget class="QPushButton" name="addTexPackBtn">
|
||||
<property name="text">
|
||||
<string>&Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="rmTexPackBtn">
|
||||
<property name="text">
|
||||
<string>&Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="texturePacksButtonSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="viewTexPackBtn">
|
||||
<property name="text">
|
||||
<string>&View Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ModListView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>gui/widgets/ModListView.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>MCModInfoFrame</class>
|
||||
<extends>QFrame</extends>
|
||||
<header>gui/widgets/MCModInfoFrame.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
110
gui/dialogs/LoginDialog.cpp
Normal file
110
gui/dialogs/LoginDialog.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "LoginDialog.h"
|
||||
#include "ui_LoginDialog.h"
|
||||
|
||||
#include "logic/auth/YggdrasilTask.h"
|
||||
|
||||
#include <QtWidgets/QPushButton>
|
||||
|
||||
LoginDialog::LoginDialog(QWidget *parent) : QDialog(parent), ui(new Ui::LoginDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->progressBar->setVisible(false);
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
|
||||
|
||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
}
|
||||
|
||||
LoginDialog::~LoginDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
// Stage 1: User interaction
|
||||
void LoginDialog::accept()
|
||||
{
|
||||
setUserInputsEnabled(false);
|
||||
ui->progressBar->setVisible(true);
|
||||
|
||||
// Setup the login task and start it
|
||||
m_account = MojangAccount::createFromUsername(ui->userTextBox->text());
|
||||
m_loginTask = m_account->login(nullptr, ui->passTextBox->text());
|
||||
connect(m_loginTask.get(), &ProgressProvider::failed, this, &LoginDialog::onTaskFailed);
|
||||
connect(m_loginTask.get(), &ProgressProvider::succeeded, this,
|
||||
&LoginDialog::onTaskSucceeded);
|
||||
connect(m_loginTask.get(), &ProgressProvider::status, this, &LoginDialog::onTaskStatus);
|
||||
connect(m_loginTask.get(), &ProgressProvider::progress, this, &LoginDialog::onTaskProgress);
|
||||
m_loginTask->start();
|
||||
}
|
||||
|
||||
void LoginDialog::setUserInputsEnabled(bool enable)
|
||||
{
|
||||
ui->userTextBox->setEnabled(enable);
|
||||
ui->passTextBox->setEnabled(enable);
|
||||
ui->buttonBox->setEnabled(enable);
|
||||
}
|
||||
|
||||
// Enable the OK button only when both textboxes contain something.
|
||||
void LoginDialog::on_userTextBox_textEdited(const QString &newText)
|
||||
{
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)
|
||||
->setEnabled(!newText.isEmpty() && !ui->passTextBox->text().isEmpty());
|
||||
}
|
||||
void LoginDialog::on_passTextBox_textEdited(const QString &newText)
|
||||
{
|
||||
ui->buttonBox->button(QDialogButtonBox::Ok)
|
||||
->setEnabled(!newText.isEmpty() && !ui->userTextBox->text().isEmpty());
|
||||
}
|
||||
|
||||
void LoginDialog::onTaskFailed(const QString &reason)
|
||||
{
|
||||
// Set message
|
||||
ui->label->setText("<span style='color:red'>" + reason + "</span>");
|
||||
|
||||
// Re-enable user-interaction
|
||||
setUserInputsEnabled(true);
|
||||
ui->progressBar->setVisible(false);
|
||||
}
|
||||
|
||||
void LoginDialog::onTaskSucceeded()
|
||||
{
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void LoginDialog::onTaskStatus(const QString &status)
|
||||
{
|
||||
ui->label->setText(status);
|
||||
}
|
||||
|
||||
void LoginDialog::onTaskProgress(qint64 current, qint64 total)
|
||||
{
|
||||
ui->progressBar->setMaximum(total);
|
||||
ui->progressBar->setValue(current);
|
||||
}
|
||||
|
||||
// Public interface
|
||||
MojangAccountPtr LoginDialog::newAccount(QWidget *parent, QString msg)
|
||||
{
|
||||
LoginDialog dlg(parent);
|
||||
dlg.ui->label->setText(msg);
|
||||
if (dlg.exec() == QDialog::Accepted)
|
||||
{
|
||||
return dlg.m_account;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
58
gui/dialogs/LoginDialog.h
Normal file
58
gui/dialogs/LoginDialog.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/* Copyright 2014 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets/QDialog>
|
||||
#include <QtCore/QEventLoop>
|
||||
|
||||
#include "logic/auth/MojangAccount.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class LoginDialog;
|
||||
}
|
||||
|
||||
class LoginDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
~LoginDialog();
|
||||
|
||||
static MojangAccountPtr newAccount(QWidget *parent, QString message);
|
||||
|
||||
private:
|
||||
explicit LoginDialog(QWidget *parent = 0);
|
||||
|
||||
void setUserInputsEnabled(bool enable);
|
||||
|
||||
protected
|
||||
slots:
|
||||
void accept();
|
||||
|
||||
void onTaskFailed(const QString &reason);
|
||||
void onTaskSucceeded();
|
||||
void onTaskStatus(const QString &status);
|
||||
void onTaskProgress(qint64 current, qint64 total);
|
||||
|
||||
void on_userTextBox_textEdited(const QString &newText);
|
||||
void on_passTextBox_textEdited(const QString &newText);
|
||||
|
||||
private:
|
||||
Ui::LoginDialog *ui;
|
||||
MojangAccountPtr m_account;
|
||||
std::shared_ptr<Task> m_loginTask;
|
||||
};
|
||||
77
gui/dialogs/LoginDialog.ui
Normal file
77
gui/dialogs/LoginDialog.ui
Normal file
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>LoginDialog</class>
|
||||
<widget class="QDialog" name="LoginDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>162</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Add Account</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Message label placeholder.</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="userTextBox">
|
||||
<property name="placeholderText">
|
||||
<string>Email / Username</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="passTextBox">
|
||||
<property name="echoMode">
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>Password</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="value">
|
||||
<number>24</number>
|
||||
</property>
|
||||
<property name="textVisible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "ui_LwjglSelectDialog.h"
|
||||
#include "gui/Platform.h"
|
||||
|
||||
#include "logic/lists/LwjglVersionList.h"
|
||||
#include "logic/LwjglVersionList.h"
|
||||
|
||||
LWJGLSelectDialog::LWJGLSelectDialog(QWidget *parent)
|
||||
: QDialog(parent), ui(new Ui::LWJGLSelectDialog)
|
||||
|
||||
@@ -1,24 +1,7 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ModEditDialogCommon.h"
|
||||
#include "CustomMessageBox.h"
|
||||
#include <QDesktopServices>
|
||||
#include <QMessageBox>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
bool lastfirst(QModelIndexList &list, int &first, int &last)
|
||||
{
|
||||
if (!list.size())
|
||||
@@ -50,8 +33,8 @@ void showWebsiteForMod(QWidget *parentDlg, Mod &m)
|
||||
else
|
||||
{
|
||||
CustomMessageBox::selectable(
|
||||
parentDlg, parentDlg->tr("How sad!"),
|
||||
parentDlg->tr("The mod author didn't provide a website link for this mod."),
|
||||
parentDlg, QObject::tr("How sad!"),
|
||||
QObject::tr("The mod author didn't provide a website link for this mod."),
|
||||
QMessageBox::Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,9 @@
|
||||
/* Copyright 2013 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <QAbstractItemModel>
|
||||
#include <QModelIndex>
|
||||
#include <QDesktopServices>
|
||||
#include <QWidget>
|
||||
#include <logic/Mod.h>
|
||||
|
||||
bool lastfirst(QModelIndexList &list, int &first, int &last);
|
||||
|
||||
void showWebsiteForMod(QWidget *parentDlg, Mod &m);
|
||||
void showWebsiteForMod(QWidget *parentDlg, Mod &m);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "logic/InstanceFactory.h"
|
||||
#include "logic/BaseVersion.h"
|
||||
#include "logic/icons/IconList.h"
|
||||
#include "logic/lists/MinecraftVersionList.h"
|
||||
#include "logic/minecraft/MinecraftVersionList.h"
|
||||
#include "logic/tasks/Task.h"
|
||||
|
||||
#include "gui/Platform.h"
|
||||
@@ -47,7 +47,7 @@ NewInstanceDialog::NewInstanceDialog(QWidget *parent)
|
||||
taskDlg->exec(loadTask);
|
||||
}
|
||||
*/
|
||||
setSelectedVersion(MMC->minecraftlist()->getLatestStable());
|
||||
setSelectedVersion(MMC->minecraftlist()->getLatestStable(), true);
|
||||
InstIconKey = "infinity";
|
||||
ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
|
||||
}
|
||||
@@ -63,13 +63,17 @@ void NewInstanceDialog::updateDialogState()
|
||||
->setEnabled(!instName().isEmpty() && m_selectedVersion);
|
||||
}
|
||||
|
||||
void NewInstanceDialog::setSelectedVersion(BaseVersionPtr version)
|
||||
void NewInstanceDialog::setSelectedVersion(BaseVersionPtr version, bool initial)
|
||||
{
|
||||
m_selectedVersion = version;
|
||||
|
||||
if (m_selectedVersion)
|
||||
{
|
||||
ui->versionTextBox->setText(version->name());
|
||||
if(ui->instNameTextBox->text().isEmpty() && !initial)
|
||||
{
|
||||
ui->instNameTextBox->setText(version->name());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
|
||||
void updateDialogState();
|
||||
|
||||
void setSelectedVersion(BaseVersionPtr version);
|
||||
void setSelectedVersion(BaseVersionPtr version, bool initial = false);
|
||||
|
||||
void loadVersionList();
|
||||
|
||||
|
||||
84
gui/dialogs/NotificationDialog.cpp
Normal file
84
gui/dialogs/NotificationDialog.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
#include "NotificationDialog.h"
|
||||
#include "ui_NotificationDialog.h"
|
||||
|
||||
#include <QTimerEvent>
|
||||
|
||||
NotificationDialog::NotificationDialog(const NotificationChecker::NotificationEntry &entry, QWidget *parent) :
|
||||
QDialog(parent, Qt::MSWindowsFixedSizeDialogHint | Qt::WindowTitleHint | Qt::CustomizeWindowHint),
|
||||
ui(new Ui::NotificationDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
QStyle::StandardPixmap icon;
|
||||
switch (entry.type)
|
||||
{
|
||||
case NotificationChecker::NotificationEntry::Critical:
|
||||
icon = QStyle::SP_MessageBoxCritical;
|
||||
break;
|
||||
case NotificationChecker::NotificationEntry::Warning:
|
||||
icon = QStyle::SP_MessageBoxWarning;
|
||||
break;
|
||||
case NotificationChecker::NotificationEntry::Information:
|
||||
icon = QStyle::SP_MessageBoxInformation;
|
||||
break;
|
||||
}
|
||||
ui->iconLabel->setPixmap(style()->standardPixmap(icon, 0, this));
|
||||
ui->messageLabel->setText(entry.message);
|
||||
|
||||
m_dontShowAgainText = tr("Don't show again");
|
||||
m_closeText = tr("Close");
|
||||
|
||||
ui->dontShowAgainBtn->setText(m_dontShowAgainText + QString(" (%1)").arg(m_dontShowAgainTime));
|
||||
ui->closeBtn->setText(m_closeText + QString(" (%1)").arg(m_closeTime));
|
||||
|
||||
startTimer(1000);
|
||||
}
|
||||
|
||||
NotificationDialog::~NotificationDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void NotificationDialog::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
if (m_dontShowAgainTime > 0)
|
||||
{
|
||||
m_dontShowAgainTime--;
|
||||
if (m_dontShowAgainTime == 0)
|
||||
{
|
||||
ui->dontShowAgainBtn->setText(m_dontShowAgainText);
|
||||
ui->dontShowAgainBtn->setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->dontShowAgainBtn->setText(m_dontShowAgainText + QString(" (%1)").arg(m_dontShowAgainTime));
|
||||
}
|
||||
}
|
||||
if (m_closeTime > 0)
|
||||
{
|
||||
m_closeTime--;
|
||||
if (m_closeTime == 0)
|
||||
{
|
||||
ui->closeBtn->setText(m_closeText);
|
||||
ui->closeBtn->setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->closeBtn->setText(m_closeText + QString(" (%1)").arg(m_closeTime));
|
||||
}
|
||||
}
|
||||
|
||||
if (m_closeTime == 0 && m_dontShowAgainTime == 0)
|
||||
{
|
||||
killTimer(event->timerId());
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationDialog::on_dontShowAgainBtn_clicked()
|
||||
{
|
||||
done(DontShowAgain);
|
||||
}
|
||||
void NotificationDialog::on_closeBtn_clicked()
|
||||
{
|
||||
done(Normal);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user