├── .gitattributes
├── .gitignore
├── COPYING
├── README.md
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
└── main
├── java
└── de
│ └── haukerehfeld
│ └── quakeinjector
│ ├── BuildCommit.java
│ ├── Cancelable.java
│ ├── ChangeListenerList.java
│ ├── CheckCanceledProgressListener.java
│ ├── CheckInstalled.java
│ ├── CompressedProgressListener.java
│ ├── Configuration.java
│ ├── Download.java
│ ├── DownloadWorker.java
│ ├── DumpInputStream.java
│ ├── EngineConfigDialog.java
│ ├── EngineOutputDialog.java
│ ├── EngineStarter.java
│ ├── FileInfo.java
│ ├── FileNotWritableException.java
│ ├── HTTPException.java
│ ├── InspectZipWorker.java
│ ├── InstallQueuePanel.java
│ ├── InstallWorker.java
│ ├── InstalledPackageList.java
│ ├── InstalledPackages.java
│ ├── Installer.java
│ ├── Menu.java
│ ├── OnlineFileNotFoundException.java
│ ├── Package.java
│ ├── PackageDatabaseParser.java
│ ├── PackageDatabaseParserWorker.java
│ ├── PackageDetailPanel.java
│ ├── PackageFileList.java
│ ├── PackageInteractionPanel.java
│ ├── PackageList.java
│ ├── PackageListSelectionHandler.java
│ ├── PackageOverwriteDialog.java
│ ├── PackageTable.java
│ ├── PercentageProgressListener.java
│ ├── ProgressListener.java
│ ├── ProgressListenerInputStream.java
│ ├── QuakeInjector.java
│ ├── RelativePath.java
│ ├── Requirement.java
│ ├── RequirementList.java
│ ├── RuntimeExecutionException.java
│ ├── SaveInstalled.java
│ ├── SortableRequirement.java
│ ├── SumProgressListener.java
│ ├── ThreadedGetter.java
│ ├── UnavailableRequirement.java
│ ├── UninstallWorker.java
│ ├── UpdateRequirementListWorker.java
│ ├── Utils.java
│ ├── XmlUtils.java
│ ├── ZipInspect.java
│ ├── database
│ └── InstalledMapsParser.java
│ ├── gui
│ ├── BrowserLauncher.java
│ ├── ClosePanel.java
│ ├── ErrorEvent.java
│ ├── ErrorListener.java
│ ├── JPathPanel.java
│ ├── LabelFieldPanel.java
│ ├── LookAndFeelDefaults.java
│ ├── OkayCancelApplyPanel.java
│ ├── ProgressListener.java
│ ├── ProgressPopup.java
│ ├── ScrollablePanel.java
│ └── SimpleErrorEvent.java
│ └── packagelist
│ └── model
│ ├── Column.java
│ └── PackageListModel.java
└── resources
├── Inject2.ico
├── Inject2_16.png
├── Inject2_16_16colors.png
├── Inject2_16_256colors..png
├── Inject2_256.png
├── Inject2_32.png
├── Inject2_32_16colors.png
├── Inject2_32_256colors..png
├── Inject2_48.png
├── Inject2_48_16colors.png
├── Inject2_48_256colors..png
├── star_spirit_12.png
├── star_spirit_8.png
└── star_spirit_8_inactive.png
/.gitattributes:
--------------------------------------------------------------------------------
1 | #
2 | # https://help.github.com/articles/dealing-with-line-endings/
3 | #
4 | # These are explicitly windows files and should use crlf
5 | *.bat text eol=crlf
6 |
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | dist
3 | release
4 | build-info.properties
5 |
6 | # Ignore Gradle project-specific cache directory
7 | .gradle
8 | # Ignore Gradle build output directory
9 | build
10 |
11 |
12 | database.xml
13 | installedMaps.xml
14 | config.properties
15 | jre/
16 |
17 | # ide files
18 | # These can be regenerated with `gradlew eclipse` so they no longer need to be committed
19 | .classpath
20 | .project
21 | .settings/
22 |
23 | *.iml
24 | .idea/
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Quake Injector
2 | Quake Injector is a tool to *download, install and play* Quake (some call it "Quake 1") singleplayer maps from the "Quaddicted archive":https://www.quaddicted.com - basically the complete history of all quake singleplayer maps ever made. Ever been annoyed by an excruciating installation process? Could not figure out how to install a certain map? Well, this tool makes it a piece of cake. Simply pick a map and click Install.
3 |
4 | 
5 |
6 | ## Features
7 | - Simply pick a map, click install and play
8 | - [All Quake singleplayer maps ever made](https://www.quaddicted.com/reviews/)
9 | - Filter, sort, browse to find your favourite map
10 | - Automatically installs dependencies (e.g. Quoth)
11 | - Cross-Platform
12 | - [Free, Open Source Software](https://github.com/hrehfeld/QuakeInjector/), released under the GPL.
13 | - Scan your Quake directory for already installed maps
14 |
15 | ## Installation
16 | On Windows you can use a self-contained executable. On Linux and MacOS you need Java.
17 |
18 | ### Windows
19 | 1. Download the latest ["QuakeInjector.exe" release](https://github.com/hrehfeld/QuakeInjector/releases)
20 | 1. Extract the .zip file
21 | 1. Double click the QuakeInjector.exe
22 |
23 | ### Linux and MacOS
24 | 1. Make sure you have a recent Java installed
25 | 1. Download the latest [Quake Injector release](https://github.com/hrehfeld/QuakeInjector/releases)
26 | 1. Extract the .zip file
27 | 1. Double click `lib/quakeinjector.jar`, or start it with `java -jar lib/quakeinjector.jar`. On Windows, you can also use the supplied `quakeinjector.bat`.
28 |
29 | *Keep in mind this software is still in heavy development. The alpha tag hints at it not being feature complete, and possibly buggy.* See the included licence (`COPYING`) for more details on warranties, etc. (there are none).
30 |
31 | ## Basic Manual
32 | ### Filtering, Sorting and the Package Table
33 | Right above the table of available packages you see a filter field. Here you can specify a filter for the listing. Let's say you want to see only maps from 2001? Enter "`2001`" without the quotes. Or for all maps by Vondur, enter "`Vondur`". You can also enter multiple words, they will be connect by a logical AND. So "`czg 2000`" would show you all maps czg made in 2000. To reset the filter simply delete all text from it.
34 |
35 | At the top of the package list there are the table headers (duh!). Click on them to sort the table.
36 |
37 | This works well in combination with a filter. For example you could look at all maps from 2008 sorted by rating.
38 |
39 | ## Known Problems
40 | 1. On **Linux/MacOS** and other case-sensitive operating systems you won’t have much joy as there is no engine that can ignore the case of filenames *yet*. There will be one and it will be a good one, but for now you're pretty much on your own, as **a lot of maps were packed with mixed case filenames** by the original authors.
41 |
42 | 1. Also be aware that most engines cannot run some of the latest and greatest maps, because those **maps break the original quake engine limits**. A [modern Quake engine](https://neogeographica.com/site/pages/guides/engines.html#04) is recommended.
43 |
44 | ## Development
45 | ### Bugs and feedback
46 | If anything that feels weird occurs to you, or you find a definite bug, please [report it as an issue](https://github.com/hrehfeld/QuakeInjector/issues). Likewise, give us a shout if you want to help with development. Pull requests are what powers the project!
47 |
48 | ### Running from source
49 | To run the application for development, run the following command in the root directory.
50 |
51 | On Windows:
52 | ```
53 | gradlew.bat run
54 | ```
55 | On Unix:
56 | ```
57 | ./gradlew run
58 | ```
59 |
60 | ### Building
61 | To build a jar, grab the source and run the following command in the root directory. The jar will be in the `build/libs` directory.
62 |
63 | On Windows:
64 | ```
65 | gradlew.bat assemble
66 | ```
67 | On Unix:
68 | ```bash
69 | ./gradlew assemble
70 | ```
71 |
72 | ### Building a Windows EXE
73 | To build an EXE for Windows, grab the source and run the following command in the root directory. It will create a zip in the `build/distributions` directory.
74 |
75 | On Windows:
76 | ```
77 | gradlew.bat winDist
78 | ```
79 | On Unix:
80 | ```bash
81 | ./gradlew winDist
82 | ```
83 |
84 | ### Notes
85 | - Use an annotated Git tag to define the name of the resulting JAR: `git tag -a "alphaXX" -m "alphaXX"` will make gradlew compile `QuakeInjector-alphaXX.jar`.
86 |
87 | ## Credits
88 | - Hauke 'megaman' Rehfeld (initial programming)
89 | - Spirit (initial concept)
90 | - [These lovely people](https://github.com/hrehfeld/QuakeInjector/graphs/contributors) (updates, fixes, features, maintenance) ❤️
91 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | id 'eclipse'
4 | id 'application'
5 | // id 'com.palantir.graal' version '0.9.0'
6 | id "com.github.spotbugs" version "4.7.1"
7 | id 'edu.sc.seis.launch4j' version '2.5.0'
8 | }
9 |
10 | version = "git describe --tags".execute().text.trim()
11 | repositories {
12 | mavenCentral()
13 | }
14 |
15 | dependencies {
16 | implementation 'edu.stanford.ejalbert:BrowserLauncher2:1.3'
17 | }
18 |
19 | application {
20 | mainClass.set('de.haukerehfeld.quakeinjector.QuakeInjector')
21 | }
22 |
23 | jar {
24 | manifest {
25 | attributes["Main-Class"] = application.mainClass.get()
26 | }
27 | }
28 |
29 | //graal {
30 | // javaVersion "11"
31 | // graalVersion "21.1.0"
32 | // outputName "quake-injector"
33 | // mainClass application.mainClassName
34 | // option "--no-fallback"
35 | // option "--verbose"
36 | //}
37 |
38 | task readCommit(type: WriteProperties) {
39 | outputFile = file("${buildDir}/build-info.properties")
40 | comment = "Revision name"
41 | property("quake-injector.build-commit", version)
42 | }
43 |
44 | launch4j {
45 | mainClassName = application.mainClass.get()
46 | icon = "${projectDir}/src/main/resources/Inject2.ico"
47 | bundledJrePath "./runtime"
48 | bundledJre64Bit false
49 | }
50 |
51 | processResources {
52 | from(readCommit)
53 | }
54 |
55 | task downloadJre {
56 | def targetDir = "$buildDir/jre"
57 | def f = new File("$buildDir/jre.zip")
58 | f.parentFile.mkdir()
59 | if (!f.exists()) {
60 | new URL('https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.10%2B7/OpenJDK17U-jdk_x86-32_windows_hotspot_17.0.10_7.zip').withInputStream {i -> f.withOutputStream {it << i}}
61 | }
62 |
63 | copy {
64 | from zipTree("$buildDir/jre.zip")
65 | into(targetDir)
66 | fileMode 0777
67 | dirMode 0777
68 | }
69 | }
70 |
71 | task setupWinDist(type: Copy) {
72 | dependsOn("createExe", "downloadJre")
73 | group "distribution"
74 | def targetDir = "$buildDir/winDist"
75 | mkdir(targetDir)
76 | File jreDir
77 | doLast {
78 | copy {
79 | file("$buildDir/jre").eachDir {
80 | if (it.name.contains("jdk")) {
81 | jreDir = it
82 | }
83 | }
84 | if (jreDir) {
85 | from(jreDir)
86 | into("$targetDir/runtime")
87 | }
88 | }
89 | }
90 | from("$buildDir/launch4j")
91 | into(targetDir)
92 | }
93 |
94 | task winDist(type: Zip) {
95 | dependsOn "setupWinDist"
96 | group "distribution"
97 | def distDir = "$buildDir/winDist"
98 | from "$distDir"
99 | archiveFileName = "QuakeInjector.exe-${project.version}.zip"
100 | exclude("*-jre")
101 |
102 | }
103 | test {
104 | useJUnitPlatform()
105 | }
106 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hrehfeld/QuakeInjector/65fe5924c7703038e7e2eedc5ae2e17cda19560a/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Apr 12 17:48:37 EDT 2024
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto init
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto init
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :init
68 | @rem Get command-line arguments, handling Windows variants
69 |
70 | if not "%OS%" == "Windows_NT" goto win9xME_args
71 |
72 | :win9xME_args
73 | @rem Slurp the command line arguments.
74 | set CMD_LINE_ARGS=
75 | set _SKIP=2
76 |
77 | :win9xME_args_slurp
78 | if "x%~1" == "x" goto execute
79 |
80 | set CMD_LINE_ARGS=%*
81 |
82 | :execute
83 | @rem Setup the command line
84 |
85 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
86 |
87 |
88 | @rem Execute Gradle
89 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
90 |
91 | :end
92 | @rem End local scope for the variables with windows NT shell
93 | if "%ERRORLEVEL%"=="0" goto mainEnd
94 |
95 | :fail
96 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
97 | rem the _cmd.exe /c_ return code!
98 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
99 | exit /b 1
100 |
101 | :mainEnd
102 | if "%OS%"=="Windows_NT" endlocal
103 |
104 | :omega
105 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'QuakeInjector'
2 |
3 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/BuildCommit.java:
--------------------------------------------------------------------------------
1 | package de.haukerehfeld.quakeinjector;
2 |
3 | import java.io.IOException;
4 | import java.util.Properties;
5 |
6 | public final class BuildCommit {
7 | private static String buildCommit = "";
8 |
9 | public static String getBuildCommit(){
10 | if (buildCommit == null || buildCommit.isEmpty()){
11 | Properties properties = new Properties();
12 | try {
13 | System.out.println("No build commit found, attempting to read from props");
14 | properties.load(BuildCommit.class.getClassLoader().getResourceAsStream(
15 | "build-info.properties"));
16 |
17 | } catch (IOException e) {
18 | e.printStackTrace();
19 | }
20 |
21 | buildCommit = properties.getProperty("quake-injector.build-commit");
22 | System.out.println("Build commit is " + buildCommit);
23 | }
24 | return buildCommit;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/Cancelable.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 |
21 | package de.haukerehfeld.quakeinjector;
22 |
23 | public interface Cancelable {
24 | public void checkCancelled() throws Installer.CancelledException;
25 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/ChangeListenerList.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | import java.util.ArrayList;
23 |
24 | import javax.swing.event.ChangeEvent;
25 | import javax.swing.event.ChangeListener;
26 |
27 |
28 | /**
29 | * Helper class for easy changelistener lists
30 | */
31 | public class ChangeListenerList {
32 | private ArrayList listeners = new ArrayList();
33 |
34 | public void addChangeListener(ChangeListener l) {
35 |
36 | if (listeners.indexOf(l) >= 0) {
37 | return;
38 | }
39 | listeners.add(l);
40 | }
41 |
42 | public void removeChangeListener(ChangeListener l) {
43 | listeners.remove(l);
44 | }
45 |
46 | public void notifyChangeListeners(Object source) {
47 | ChangeEvent e = new ChangeEvent(source);
48 | for (ChangeListener l: listeners) {
49 | l.stateChanged(e);
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/CheckCanceledProgressListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 |
21 | package de.haukerehfeld.quakeinjector;
22 |
23 | /**
24 | * Check if canceledd on each write
25 | */
26 | public class CheckCanceledProgressListener implements ProgressListener {
27 | private final ProgressListener progress;
28 | private final Cancelable toCheck;
29 |
30 | public CheckCanceledProgressListener(Cancelable toCheck, ProgressListener progress) {
31 | this.progress = progress;
32 | this.toCheck = toCheck;
33 | }
34 |
35 | /**
36 | * tell the reporter of the size of uncompression
37 | */
38 | public void publish(long writtenBytes) {
39 | toCheck.checkCancelled();
40 | progress.publish(writtenBytes);
41 | }
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/CheckInstalled.java:
--------------------------------------------------------------------------------
1 | package de.haukerehfeld.quakeinjector;
2 |
3 | import javax.swing.SwingWorker;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 | import java.util.Collections;
8 |
9 | import java.io.File;
10 | import java.io.InputStream;
11 | import java.io.FileInputStream;
12 | import java.io.BufferedInputStream;
13 | import javax.swing.JOptionPane;
14 |
15 |
16 | class CheckInstalled extends SwingWorker, Void>
17 | implements ProgressListener {
18 |
19 | String zipContentsDatabaseUrl;
20 | String enginePath;
21 | RequirementList maps;
22 | SaveInstalled saveInstalled;
23 | QuakeInjector injector;
24 |
25 | public CheckInstalled(QuakeInjector injector,
26 | String zipContentsDatabaseUrl,
27 | String enginePath,
28 | RequirementList maps,
29 | SaveInstalled saveInstalled) {
30 | this.zipContentsDatabaseUrl = zipContentsDatabaseUrl;
31 | this.enginePath = enginePath;
32 | this.maps = maps;
33 | this.injector = injector;
34 | this.saveInstalled = saveInstalled;
35 | }
36 |
37 | @Override
38 | public List doInBackground() throws java.lang.InterruptedException,
39 | java.util.concurrent.ExecutionException,
40 | java.io.IOException {
41 |
42 | List packages = Collections.emptyList();
43 | {
44 | //get download stream
45 | Download d = Download.create(zipContentsDatabaseUrl);
46 | d.connect();
47 | final InputStream dl = d.getStream();
48 |
49 | try {
50 | packages = new InstalledPackageList().read(dl);
51 |
52 | Collections.sort(packages);
53 | }
54 | catch (java.io.FileNotFoundException e) {
55 | System.out.println("Notice: installed maps file doesn't exist yet,"
56 | + " no maps installed? " + e);
57 | }
58 | catch (java.io.IOException e) {
59 | System.err.println("Error: installed maps file couldn't be loaded: " + e);
60 | e.printStackTrace();
61 | }
62 | }
63 |
64 | int i = 0;
65 | List installed = new ArrayList();
66 | for (PackageFileList list: packages) {
67 | publish(i++ * 100 / packages.size());
68 | Requirement r = maps.get(list.getId());
69 | String basedir = enginePath + File.separator;
70 | if (r instanceof UnavailableRequirement) {
71 | continue;
72 | }
73 |
74 | List missingFiles = new ArrayList();
75 | for (FileInfo entry: list) {
76 | if (isCancelled()) {
77 | throw new java.util.concurrent.CancellationException();
78 | }
79 |
80 | if (list.size() > 7 && missingFiles.size() > 0.2f * list.size()) {
81 | System.out.println("Too many missing files for " + list.getId()
82 | + ", stopping search!");
83 | break;
84 | }
85 |
86 | String filename = entry.getName();
87 | //System.out.println("Basedir: " + basedir + "; filename: " + filename);
88 | String file = basedir + filename;
89 | long supposedCrc = entry.getChecksum();
90 | File f = new File(file);
91 | System.out.print("Checking for " + f + "...");
92 | if (!f.exists()) {
93 | if (entry.getEssential()) {
94 | missingFiles.add(file);
95 | System.out.println("missing!");
96 | }
97 | }
98 | else {
99 | System.out.println("found!");
100 | if (!f.isDirectory()) {
101 | long crc = Utils.getCrc32(new BufferedInputStream(new FileInputStream(f)), null);
102 | if (supposedCrc != 0 && crc != entry.getChecksum()) {
103 | System.err.println("Crc differs for file " + file);
104 | if (entry.getEssential()) {
105 | System.out.println("Counting as missing.");
106 | missingFiles.add(file);
107 | }
108 | }
109 | // else {
110 | // System.out.println("Crc matches for " + f + " (" + crc + ")");
111 | // }
112 | }
113 | }
114 | }
115 |
116 | if (missingFiles.isEmpty()) {
117 | System.out.println(list.getId() + " seems to be installed.");
118 | //if we would allow for missing files in an installed package, we'd need to have custom file lists!
119 | installed.add(list);
120 | }
121 | else {
122 | System.out.println(list.getId() + " has missing files, not installed.");
123 | }
124 | }
125 |
126 | return installed;
127 | }
128 |
129 |
130 | @Override
131 | public void done() {
132 | try {
133 | List list = get();
134 |
135 | injector.setInstalledStatus(list);
136 |
137 | synchronized (maps) {
138 | saveInstalled.write(maps);
139 | }
140 | }
141 | catch (java.lang.InterruptedException e) {
142 | System.err.println("Interrupted: " + e);
143 | e.printStackTrace();
144 | }
145 | catch (java.util.concurrent.ExecutionException e) {
146 | System.err.println("Exception: " + e);
147 | e.printStackTrace();
148 | try {
149 | throw e.getCause();
150 | }
151 | catch (java.net.ConnectException err) {
152 | String msg = "Downloading file database failed, " + err.getMessage() + "!";
153 | JOptionPane.showMessageDialog(injector,
154 | msg,
155 | "Downloading failed!",
156 | JOptionPane.ERROR_MESSAGE);
157 |
158 | }
159 | catch (Throwable err) {
160 | }
161 | }
162 | catch (java.util.concurrent.CancellationException e) {
163 | }
164 | catch (java.io.IOException e) {
165 | System.err.println("Couldn't write installedMapsFile: " + e);
166 | e.printStackTrace();
167 | }
168 | }
169 |
170 | public void publish(long progress) {
171 | if (progress <= 100) {
172 | setProgress((int) progress);
173 | }
174 | }
175 |
176 | }
177 |
178 |
179 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/CompressedProgressListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 |
21 | package de.haukerehfeld.quakeinjector;
22 |
23 | /**
24 | * Report progress from the uncompressed values where only the compressed size is known
25 | */
26 | public class CompressedProgressListener implements ProgressListener {
27 | private final double compressionRatio;
28 | private final ProgressListener progress;
29 |
30 | public CompressedProgressListener(double compressionRatio,
31 | ProgressListener progress) {
32 | this.compressionRatio = compressionRatio;
33 | this.progress = progress;
34 | }
35 |
36 | /**
37 | * tell the reporter of the size of uncompression
38 | */
39 | public void publish(long writtenBytes) {
40 | if (writtenBytes <= 0) {
41 | System.err.println("Progress <= 0 written bytes: " + writtenBytes);
42 | }
43 | long downloaded = (long) (writtenBytes * compressionRatio);
44 | progress.publish(downloaded);
45 | }
46 | }
47 |
48 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/Download.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 |
21 | package de.haukerehfeld.quakeinjector;
22 |
23 | import java.io.FileNotFoundException;
24 | import java.io.IOException;
25 | import java.io.InputStream;
26 | import java.net.HttpURLConnection;
27 | import java.net.MalformedURLException;
28 | import java.net.URI;
29 | import java.net.URISyntaxException;
30 | import java.net.URL;
31 | import java.net.URLConnection;
32 | import java.util.zip.GZIPInputStream;
33 | import java.util.zip.Inflater;
34 | import java.util.zip.InflaterInputStream;
35 |
36 | public class Download {
37 | private final URL url;
38 | private InputStream stream;
39 | private URLConnection connection;
40 |
41 | public static Download create(String urlString) throws IOException {
42 | URL cleanUrl;
43 | try {
44 | // URLs with spaces in the path need escaping to %20, not +. We can't use built in URLEncoder
45 | URL url= new URL(urlString);
46 | URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
47 |
48 | cleanUrl = new URL(uri.toASCIIString());
49 | }
50 | catch (MalformedURLException | URISyntaxException e) {
51 | throw new RuntimeException("Something is wrong with the way we construct URLs: "
52 | + e.getMessage());
53 | }
54 | return new Download(cleanUrl);
55 | }
56 |
57 | public Download(URL url) throws IOException {
58 | this.url = url;
59 | }
60 |
61 | public void connect() throws IOException {
62 | try {
63 | connection = url.openConnection();
64 |
65 | //http stuff, but url might be a different protocol
66 | HttpURLConnection con = null;
67 | if (connection instanceof HttpURLConnection) {
68 | con = (HttpURLConnection) connection;
69 | HttpURLConnection.setFollowRedirects(true);
70 | con.setRequestProperty("Accept-Encoding","gzip, deflate");
71 | con.setRequestProperty("User-Agent","Quakeinjector-" + BuildCommit.getBuildCommit());
72 | }
73 |
74 | connection.connect();
75 |
76 | if (con != null) {
77 | int response = con.getResponseCode();
78 | if (response != HttpURLConnection.HTTP_OK) {
79 | throw new HTTPException(response);
80 | }
81 | }
82 |
83 | //try getting the stream
84 | connection.getInputStream();
85 | }
86 | catch (FileNotFoundException e) {
87 | throw new OnlineFileNotFoundException(e.getMessage());
88 | }
89 | }
90 |
91 |
92 | public InputStream getStream() throws IOException {
93 | return getStream(null);
94 | }
95 |
96 | public InputStream getStream(ProgressListener progress) throws IOException {
97 | if (stream == null) {
98 | String encoding = connection.getContentEncoding();
99 |
100 |
101 | stream = connection.getInputStream();
102 | if (progress != null) {
103 | stream = new ProgressListenerInputStream(stream, progress);
104 | }
105 |
106 | /** @todo 2009-07-15 18:55 hrehfeld check what this does for non-http connections */
107 | if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
108 | stream = new GZIPInputStream(stream);
109 | }
110 | else if (encoding != null && encoding.equalsIgnoreCase("deflate")) {
111 | stream = new InflaterInputStream(stream, new Inflater(true));
112 | }
113 | }
114 |
115 | return stream;
116 | }
117 |
118 | public int getSize() {
119 | return connection.getContentLength();
120 | }
121 |
122 | public String toString() {
123 | return "<" + url.toString() + ">";
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/DownloadWorker.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | import java.io.FileNotFoundException;
23 | import java.io.IOException;
24 | import java.io.InputStream;
25 | import java.io.OutputStream;
26 | import javax.swing.SwingWorker;
27 |
28 | /**
29 | * Install maps in a worker thread
30 | * Init once and let swing start it - don't reuse
31 | */
32 | public class DownloadWorker extends SwingWorker implements ProgressListener, Cancelable {
33 | private final static int BUFFERSIZE = 1024;
34 |
35 | private final Download download;
36 | private final OutputStream out;
37 |
38 | public DownloadWorker(final Download download,
39 | final OutputStream out) {
40 | this.download = download;
41 | this.out = out;
42 | }
43 |
44 | @Override
45 | public Long doInBackground() throws
46 | IOException,
47 | FileNotFoundException,
48 | Installer.CancelledException {
49 |
50 | System.out.println("Downloading " + download);
51 |
52 |
53 | download.connect();
54 |
55 | //build progress filter chain
56 | final ProgressListener progress =
57 | new SumProgressListener(
58 | new PercentageProgressListener(download.getSize(),
59 | new CheckCanceledProgressListener(this,
60 | this)));
61 |
62 |
63 | final InputStream in = download.getStream();
64 | final byte data[] = new byte[BUFFERSIZE];
65 | long downloadSize = 0;
66 | int readcount;
67 | while ((readcount = in.read(data, 0, BUFFERSIZE)) != -1) {
68 | progress.publish(readcount);
69 | out.write(data, 0, readcount);
70 | downloadSize += readcount;
71 | }
72 | out.flush();
73 | return downloadSize;
74 | }
75 |
76 | public void publish(long progress) {
77 | if (progress <= 100) {
78 | setProgress((int) progress);
79 | }
80 | }
81 |
82 | public void checkCancelled() throws Installer.CancelledException {
83 | if (isCancelled()) {
84 | System.out.println("canceling...");
85 | throw new Installer.CancelledException();
86 | }
87 | }
88 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/DumpInputStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 |
21 | package de.haukerehfeld.quakeinjector;
22 |
23 | import java.io.IOException;
24 | import java.io.InputStream;
25 | import java.io.OutputStream;
26 |
27 | /**
28 | * Dump everything that's read to an OutputStream
29 |
30 | * Note that skipping doesn't add to the stream, and marking isn't supported
31 | */
32 | public class DumpInputStream extends InputStream {
33 | private final InputStream in;
34 | private final OutputStream out;
35 |
36 | public DumpInputStream(InputStream in, OutputStream out) {
37 | this.in = in;
38 | this.out = out;
39 | }
40 |
41 | @Override
42 | public int read() throws IOException {
43 | int r = in.read();
44 | out.write(r);
45 | return r;
46 | }
47 |
48 | @Override
49 | public int read(byte[] b) throws IOException {
50 | return read(b, 0, b.length);
51 | }
52 |
53 | @Override
54 | public int read(byte[] b, int off, int len) throws IOException {
55 | int readcount = in.read(b, off, len);
56 | if (readcount > 0) {
57 | out.write(b, off, readcount);
58 | }
59 | return readcount;
60 | }
61 |
62 | @Override
63 | public long skip(long n) throws IOException {
64 | return in.skip(n);
65 | }
66 |
67 | @Override
68 | public int available() throws IOException {
69 | return in.available();
70 | }
71 |
72 | @Override
73 | public void mark(int readlimit) {}
74 |
75 | @Override
76 | public void reset() throws IOException {
77 | throw new IOException("Reset not supported");
78 | }
79 |
80 | @Override
81 | public boolean markSupported() {
82 | return false;
83 | }
84 | }
85 |
86 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/EngineOutputDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | import java.awt.BorderLayout;
23 | import java.awt.Rectangle;
24 | import java.awt.event.ActionEvent;
25 | import java.awt.event.ActionListener;
26 | import java.awt.event.KeyEvent;
27 | import java.io.BufferedReader;
28 | import java.io.InputStream;
29 | import java.io.InputStreamReader;
30 |
31 | import javax.swing.JButton;
32 | import javax.swing.JDialog;
33 | import javax.swing.JFrame;
34 | import javax.swing.JScrollPane;
35 | import javax.swing.JTextArea;
36 | import javax.swing.SwingWorker;
37 | import javax.swing.KeyStroke;
38 | import javax.swing.JComponent;
39 |
40 | import de.haukerehfeld.quakeinjector.gui.OkayCancelApplyPanel;
41 |
42 | public class EngineOutputDialog extends JDialog {
43 | private final static String windowTitle = "Engine Output";
44 | private final static String outputQIPrefix = "[Quake Injector]: ";
45 |
46 | private final InputStream engineOut;
47 |
48 | private final JTextArea output;
49 |
50 | public EngineOutputDialog(final JFrame parent, final InputStream engineOut) {
51 | super(parent, windowTitle, true);
52 | this.engineOut = engineOut;
53 |
54 | output = new JTextArea(30, 80);
55 | output.setLineWrap(true);
56 |
57 | JScrollPane panelScroll = new JScrollPane(output);
58 | panelScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
59 | panelScroll.getViewport().setBackground(javax.swing.UIManager.getColor("TextPane.background"));
60 | add(panelScroll, BorderLayout.CENTER);
61 |
62 | final JButton close = new JButton("Close");
63 |
64 | close.addActionListener(new ActionListener() {
65 | public void actionPerformed(ActionEvent e) {
66 | setVisible(false);
67 | dispose();
68 | }
69 | });
70 |
71 | add(new OkayCancelApplyPanel(close, null, null, false), BorderLayout.PAGE_END);
72 |
73 | addEscapeListener(this); // this is probably not how you do it... -Spirit
74 |
75 | new SwingWorker() {
76 | @Override
77 | public Void doInBackground() {
78 | try {
79 | InputStreamReader in = new InputStreamReader(engineOut);
80 | BufferedReader b = new BufferedReader(in);
81 |
82 |
83 | output.append(outputQIPrefix+"Starting engine...\n");
84 | String line;
85 | int lineCount = 0;
86 | while ((line = b.readLine()) != null) {
87 | //append is thread safe
88 | output.append(line.trim() + "\n");
89 | lineCount++;
90 |
91 | //scroll on the event thread
92 | javax.swing.SwingUtilities.invokeLater(new SwingWorker() {
93 | public Void doInBackground() {
94 | output.scrollRectToVisible(new Rectangle(0, output.getHeight(), 0, 10));
95 | return null;
96 | }
97 | });
98 | }
99 | if (lineCount == 0) {
100 | output.append(outputQIPrefix+"Done with no output.\n");
101 | }
102 | else {
103 | output.append(outputQIPrefix+"Done.\n");
104 | }
105 |
106 | }
107 | catch (java.io.IOException e) {
108 | output.append(outputQIPrefix+"Error: Couldn't read engine output from stream");
109 | }
110 |
111 | return null;
112 | }
113 | @Override
114 | public void done() {
115 | }
116 | }.execute();
117 | }
118 |
119 | // from http://stackoverflow.com/questions/642925/swing-how-do-i-close-a-dialog-when-the-esc-key-is-pressed -Spirit
120 | public static void addEscapeListener(final JDialog dialog) {
121 | ActionListener escListener = new ActionListener() {
122 | @Override
123 | public void actionPerformed(ActionEvent e) {
124 | dialog.dispose();
125 | }
126 | };
127 |
128 | dialog.getRootPane().registerKeyboardAction(escListener,
129 | KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
130 | JComponent.WHEN_IN_FOCUSED_WINDOW);
131 |
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/EngineStarter.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | import java.io.File;
23 | import java.util.ArrayList;
24 |
25 | import javax.xml.parsers.DocumentBuilder;
26 | import javax.xml.parsers.DocumentBuilderFactory;
27 | import javax.xml.xpath.XPath;
28 | import javax.xml.xpath.XPathExpression;
29 | import javax.xml.xpath.XPathFactory;
30 |
31 | import org.w3c.dom.Document;
32 |
33 | public class EngineStarter {
34 | private File workingDir;
35 | private File quakeExe;
36 | private String quakeCmdline;
37 |
38 | private static boolean isMacOSX() {
39 | return System.getProperty("os.name").startsWith("Mac OS X");
40 | }
41 |
42 | /**
43 | * Checks whether the given File is a Mac OS X application bundle.
44 | */
45 | private static boolean isMacApplication(File app) {
46 | return app.isDirectory()
47 | && app.getName().endsWith(".app");
48 | }
49 |
50 | /**
51 | * Checks whether exe is an executable file.
52 | */
53 | private static boolean isExecutable(File exe) {
54 | return !exe.isDirectory() && exe.canExecute();
55 | }
56 |
57 | /**
58 | * Checks whether app is a valid application. On Mac OS X it can
59 | * either be an executable or an app bundle, on other platforms
60 | * it must be an executable.
61 | */
62 | public static boolean isValidApplication(File app) {
63 | if (!app.exists() || !app.canRead())
64 | return false;
65 |
66 | if (isMacOSX() && isMacApplication(app))
67 | return true;
68 |
69 | return isExecutable(app);
70 | }
71 |
72 | /**
73 | * Returns an error message to display when the user picks app
74 | * as the engine, or returns null if it is a valid application.
75 | *
76 | * @see #isValidApplication(File)
77 | */
78 | public static String errorMessageForApplication(File app) {
79 | if (!app.exists()) {
80 | return "Doesn't exist!";
81 | }
82 |
83 | if (isMacOSX()) {
84 | if (!isMacApplication(app) && !isExecutable(app)) {
85 | return "Must be an application or executable!";
86 | }
87 | return null;
88 |
89 | } else {
90 | if (app.isDirectory()) {
91 | return "Must be an executable file!";
92 | }
93 | else if (!app.canExecute()) {
94 | return "Cannot be executed!";
95 | }
96 | return null;
97 | }
98 | }
99 |
100 | /**
101 | * If app is a Mac OS X app bundle (e.g. ~/quake/QuakeSpasm.app), returns
102 | * the executable inside the app bundle (e.g. ~/quake/QuakeSpasm.app/Contents/MacOS/QuakeSpasm).
103 | * Otherwise, returns app.
104 | */
105 | private static File executableForApplication(File app) {
106 | if (app != null && isMacApplication(app)) {
107 | try {
108 | File contents = new File(app, "Contents");
109 | File plist = new File(contents, "Info.plist");
110 | File macOS = new File(contents, "MacOS");
111 |
112 | DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
113 | Document document = builder.parse(plist);
114 |
115 | XPath xpath = XPathFactory.newInstance().newXPath();
116 | XPathExpression expr = xpath.compile("/plist/dict/key/text()[.='CFBundleExecutable']/../following-sibling::string[1]/text()");
117 | String cfBundleExecutable = (String) expr.evaluate(document);
118 |
119 | File executable = new File(macOS, cfBundleExecutable);
120 | return executable;
121 | } catch (Exception e) {
122 | e.printStackTrace();
123 | return null;
124 | }
125 | }
126 |
127 | return app;
128 | }
129 |
130 | public EngineStarter(File workingDir, File quakeApp, Configuration.EngineCommandLine quakeCmdline) {
131 | this.workingDir = workingDir;
132 | setQuakeApplication(quakeApp);
133 | this.quakeCmdline = quakeCmdline.get();
134 | }
135 |
136 | public Process start(String mapCmdline, String startmap) throws java.io.IOException {
137 | ArrayList cmd = new ArrayList(5);
138 |
139 | cmd.add(quakeExe.getAbsolutePath());
140 | //processbuilder doesn't like arguments with spaces
141 | if (quakeCmdline != null) {
142 | for (String s: quakeCmdline.split(" ")) { cmd.add(s); }
143 | }
144 | if (mapCmdline != null) {
145 | for (String s: mapCmdline.split(" ")) { cmd.add(s); }
146 | }
147 | cmd.add("+map");
148 | cmd.add(startmap);
149 |
150 | ProcessBuilder pb = new ProcessBuilder(cmd);
151 | pb.directory(workingDir);
152 | pb.redirectErrorStream(true);
153 |
154 | System.out.println(cmd);
155 |
156 | Process p = pb.start();
157 | return p;
158 | }
159 |
160 | public void setWorkingDirectory(File dir) {
161 | this.workingDir = dir;
162 | }
163 |
164 | public void setQuakeApplication(File quakeApp) {
165 | this.quakeExe = executableForApplication(quakeApp);
166 | }
167 |
168 | public void setQuakeCommandline(Configuration.EngineCommandLine cmdline) {
169 | this.quakeCmdline = cmdline.get();
170 | }
171 |
172 | public boolean checkPaths() {
173 | return (quakeExe.exists()
174 | && !quakeExe.isDirectory()
175 | && quakeExe.canRead()
176 | && quakeExe.canExecute());
177 | }
178 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/FileInfo.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | public class FileInfo implements Comparable {
23 | private String name;
24 | private long checksum;
25 | private boolean essential;
26 |
27 | public FileInfo(String name, long checksum) {
28 | this(name, checksum, true);
29 | }
30 |
31 | public FileInfo(String name, long checksum, boolean essential) {
32 | this.name = name;
33 | this.checksum = checksum;
34 | this.essential = essential;
35 | }
36 |
37 | /**
38 | * get checksum
39 | */
40 | public long getChecksum() { return checksum; }
41 |
42 | /**
43 | * set checksum
44 | */
45 | public void setChecksum(long checksum) { this.checksum = checksum; }
46 |
47 | /**
48 | * get name
49 | */
50 | public String getName() { return name; }
51 |
52 | /**
53 | * set name
54 | */
55 | public void setName(String name) { this.name = name; }
56 |
57 | /**
58 | * get essential
59 | */
60 | public boolean getEssential() { return essential; }
61 |
62 | /**
63 | * set essential
64 | */
65 | public void setEssential(boolean essential) { this.essential = essential; }
66 |
67 |
68 | public int compareTo(FileInfo o) {
69 | int i = o.getName().compareTo(getName());
70 | if (i == 0) {
71 | i = Long.valueOf(o.getChecksum()).compareTo(Long.valueOf(getChecksum()));
72 | }
73 | return i;
74 | }
75 |
76 | public boolean equals(Object o) {
77 | return o instanceof FileInfo && ((FileInfo) o).getName().equals(getName()) && ((FileInfo) o).getChecksum() == getChecksum();
78 | }
79 |
80 | public int hashCode() {
81 | return name.hashCode() + 17 * Long.valueOf(checksum).hashCode();
82 | }
83 |
84 | public void clean() {
85 | name = name.replace('\\', '/');
86 | }
87 |
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/FileNotWritableException.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | import java.io.FileNotFoundException;
23 |
24 | public class FileNotWritableException extends FileNotFoundException {
25 | public FileNotWritableException() {
26 | super();
27 | }
28 | public FileNotWritableException(String message) {
29 | super(message);
30 | }
31 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/HTTPException.java:
--------------------------------------------------------------------------------
1 | package de.haukerehfeld.quakeinjector;
2 |
3 | public class HTTPException extends RuntimeException {
4 | private final int statusCode;
5 |
6 | public HTTPException(int statusCode) {
7 | super();
8 | this.statusCode = statusCode;
9 | }
10 |
11 | public int getStatusCode() {
12 | return statusCode;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/InspectZipWorker.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | import java.io.FileNotFoundException;
23 | import java.io.IOException;
24 | import java.io.InputStream;
25 | import java.io.BufferedInputStream;
26 | import java.util.List;
27 | import java.util.ArrayList;
28 | import java.util.zip.ZipEntry;
29 | import java.util.zip.ZipInputStream;
30 |
31 | import javax.swing.SwingWorker;
32 |
33 | /**
34 | * Inspect a zipfile and gather all zipentries
35 | */
36 | public class InspectZipWorker extends SwingWorker, Void> {
37 | private InputStream input;
38 |
39 | public InspectZipWorker(InputStream input) {
40 | this.input = input;
41 | }
42 |
43 | @Override
44 | public List doInBackground() throws IOException,
45 | FileNotFoundException {
46 | ZipInputStream zis = new ZipInputStream(new BufferedInputStream(input));
47 | List entries = new ArrayList();
48 |
49 | ZipEntry entry;
50 | while((entry = zis.getNextEntry()) != null) {
51 | entries.add(entry);
52 |
53 | }
54 | zis.close();
55 |
56 | return entries;
57 | }
58 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/InstallQueuePanel.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | import java.awt.Dimension;
23 | import java.awt.GridBagConstraints;
24 | import java.awt.GridBagLayout;
25 | import java.awt.Rectangle;
26 | import java.awt.event.ActionListener;
27 | import java.beans.PropertyChangeEvent;
28 | import java.beans.PropertyChangeListener;
29 | import java.util.ArrayDeque;
30 | import java.util.Queue;
31 |
32 | import javax.swing.JButton;
33 | import javax.swing.JLabel;
34 | import javax.swing.JPanel;
35 | import javax.swing.JProgressBar;
36 | import javax.swing.Scrollable;
37 |
38 | import de.haukerehfeld.quakeinjector.gui.ProgressPopup;
39 |
40 |
41 | public class InstallQueuePanel extends JPanel implements Scrollable {
42 | private final static int size = 5;
43 | private final static int rowHeight = 20;
44 | private final static int MARGIN = 3;
45 |
46 | private GridBagLayout layout = new GridBagLayout();
47 |
48 | private Queue jobs = new ArrayDeque();
49 |
50 | public InstallQueuePanel() {
51 | setLayout(layout);
52 | }
53 |
54 | /**
55 | * @return PropertyChangeListener that listens on "progress" for the progressbar
56 | */
57 | public Job addJob(String description, ActionListener cancelAction) {
58 | Job progressListener = new Job(cancelAction, description);
59 | jobs.offer(progressListener);
60 |
61 | layoutComponents();
62 |
63 | scrollRectToVisible(new Rectangle(0, getHeight(), 0, 100));
64 | return progressListener;
65 | }
66 |
67 | private void layoutComponents() {
68 | int row = 0;
69 | for (Job j: jobs) {
70 | remove(j.progressBar);
71 | remove(j.cancelButton);
72 | remove(j.finishedLabel);
73 | //System.out.println("removing finishedlabel");
74 |
75 | final int row_ = row;
76 | if (!j.finished) {
77 | add(j.progressBar, new ProgressBarConstraints() {{ gridy = row_; }});
78 | add(j.cancelButton, new CancelButtonConstraints() {{ gridy = row_; }});
79 | }
80 | else {
81 | add(j.finishedLabel, new FinishedLabelConstraints() {{ gridy = row_; }});
82 | //System.out.println("adding finishedlabel");
83 | }
84 | row++;
85 | }
86 |
87 | revalidate();
88 | repaint();
89 | }
90 |
91 | public void finished(final Job j, String message) {
92 | j.finish(message);
93 |
94 | layoutComponents();
95 | }
96 |
97 | @Override
98 | public Dimension getPreferredScrollableViewportSize() {
99 | return getPreferredSize();
100 | }
101 |
102 | @Override
103 | public int getScrollableUnitIncrement(Rectangle visibleRect,
104 | int orientation,
105 | int direction) {
106 | return rowHeight;
107 | }
108 |
109 | @Override
110 | public int getScrollableBlockIncrement(Rectangle visibleRect,
111 | int orientation,
112 | int direction) {
113 | return rowHeight;
114 | }
115 |
116 | @Override
117 | public boolean getScrollableTracksViewportWidth() { return true; }
118 | @Override
119 | public boolean getScrollableTracksViewportHeight() { return false; }
120 |
121 | private class RowConstraints extends GridBagConstraints {{
122 | anchor = CENTER;
123 | fill = HORIZONTAL;
124 | insets = new java.awt.Insets(MARGIN, MARGIN, MARGIN, MARGIN);
125 | }}
126 |
127 | private class ProgressBarConstraints extends RowConstraints {{
128 | weightx = 1;
129 | weighty = 1;
130 | }}
131 |
132 | private class CancelButtonConstraints extends RowConstraints {{
133 | gridx = 1;
134 | }}
135 |
136 | private class FinishedLabelConstraints extends RowConstraints {{
137 | weightx = 1;
138 | gridwidth = 2;
139 | }}
140 |
141 | public static class Job implements PropertyChangeListener {
142 | private JProgressBar progressBar;
143 | private JButton cancelButton;
144 | private JLabel finishedLabel;
145 |
146 | private String description;
147 |
148 | private boolean finished = false;
149 |
150 | public Job(ActionListener cancelAction, String description) {
151 | this.description = description;
152 |
153 | progressBar = new JProgressBar();
154 | progressBar.setString(ProgressPopup.progressString(description, 0));
155 | progressBar.setValue(0);
156 | progressBar.setStringPainted(true);
157 |
158 | cancelButton = new JButton("Cancel");
159 | cancelButton.addActionListener(cancelAction);
160 |
161 | finishedLabel = new JLabel(description);
162 | }
163 |
164 | public void propertyChange(PropertyChangeEvent evt) {
165 | if ("progress" == evt.getPropertyName()) {
166 | int p = (Integer) evt.getNewValue();
167 | setProgress(p);
168 | }
169 | }
170 |
171 | public void setProgress(int progress) {
172 | progressBar.setString(ProgressPopup.progressString(description, progress));
173 | progressBar.setValue(progress);
174 | }
175 |
176 | private void finish(String message) {
177 | finished = true;
178 | progressBar.setEnabled(false);
179 | cancelButton.setEnabled(false);
180 | finishedLabel.setText(ProgressPopup.progressString(description, message));
181 | finishedLabel.setPreferredSize(new Dimension((int) finishedLabel
182 | .getPreferredSize().getWidth(),
183 | (int) cancelButton.getSize().getHeight()));
184 |
185 | }
186 | }
187 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/InstallWorker.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | import java.io.BufferedInputStream;
23 | import java.io.File;
24 | import java.io.FileNotFoundException;
25 | import java.io.IOException;
26 | import java.io.InputStream;
27 | import java.util.List;
28 | import java.util.zip.ZipEntry;
29 | import java.util.zip.ZipInputStream;
30 |
31 | import javax.swing.SwingWorker;
32 |
33 | /**
34 | * Install maps in a worker thread
35 | * Init once and let swing start it - don't reuse
36 | */
37 | public class InstallWorker extends SwingWorker implements
38 | ProgressListener,
39 | Cancelable {
40 | private final static int BUFFERSIZE = 1024;
41 |
42 | private File baseDirectory;
43 | private String unzipDirectory;
44 | private Package map;
45 | private InputStream input;
46 | private List overwrites;
47 |
48 | private long downloadSize = 0;
49 |
50 | /**
51 | * files that got installed
52 | */
53 | private PackageFileList files;
54 |
55 | /**
56 | * @param inputSize size of the input stream in bytes, for progress reporting
57 | * @param overwrites a list of files that we should overwrite, or
58 | * null if everything should be overwritten
59 | */
60 | public InstallWorker(InputStream input,
61 | long inputSize,
62 | Package map,
63 | File baseDirectory,
64 | String unzipDirectory,
65 | List overwrites) {
66 | this.map = map;
67 | this.input = input;
68 | this.downloadSize = inputSize;
69 | this.baseDirectory = baseDirectory;
70 | this.unzipDirectory = unzipDirectory;
71 | this.files = new PackageFileList(map.getId());
72 | this.overwrites = overwrites;
73 | }
74 |
75 | @Override
76 | public PackageFileList doInBackground() throws IOException,
77 | FileNotFoundException,
78 | Installer.CancelledException {
79 | System.out.println("Installing " + map.getId());
80 |
81 | unzip(input,
82 | baseDirectory,
83 | unzipDirectory,
84 | map.getId(),
85 | overwrites);
86 |
87 | map.setInstalled(true);
88 | return files;
89 | }
90 |
91 |
92 | /**
93 | * Unzip from the inputstream to the quake base dir
94 | */
95 | public void unzip(InputStream in,
96 | File basedir,
97 | String unzipdir,
98 | String mapid,
99 | List overwrites)
100 | throws IOException, FileNotFoundException, Installer.CancelledException {
101 | //build progress filter chain
102 | ProgressListener progress =
103 | new SumProgressListener(
104 | new PercentageProgressListener(downloadSize,
105 | new CheckCanceledProgressListener(this,
106 | this)));
107 |
108 |
109 | ZipInputStream zis = new ZipInputStream(new BufferedInputStream(in));
110 | ZipEntry entry;
111 |
112 | boolean extracted = false;
113 | while((entry = zis.getNextEntry()) != null) {
114 | File f = new File(unzipdir + File.separator + entry.getName());
115 | String filename = RelativePath.getRelativePath(basedir, f).toString();
116 |
117 | if (overwrites != null && overwrites.indexOf(f) < 0) {
118 | System.out.println("Skipping " + filename + ", because it isn't supposed to be overwritten.");
119 | continue;
120 | }
121 |
122 | //create dirs
123 | List createdDirs = Utils.mkdirs(f);
124 |
125 | //do nothing for directories other than creating them
126 | if (!entry.isDirectory()) {
127 | File original = f;
128 | if (f.exists()) {
129 | //create Temp file and rename later
130 | f = File.createTempFile("quakeinjector", ".tmp", f.getParentFile());
131 | System.out.println("create Temp file " + f);
132 | }
133 |
134 | System.out.println("Writing " + filename + " (" + entry.getCompressedSize() + "b)");
135 |
136 | long crc;
137 | try {
138 | crc = Utils.writeFile(zis,
139 | f,
140 | new CompressedProgressListener(entry.getCompressedSize()
141 | / (double) entry.getSize(),
142 | progress));
143 | }
144 | catch (FileNotFoundException e) {
145 | throw new FileNotWritableException(e.getMessage());
146 | }
147 |
148 | if (crc != entry.getCrc()) {
149 | System.err.println("Crc32 didn't match on extraction of " + original + ", removing...");
150 | f.delete();
151 | continue;
152 | }
153 |
154 | /** @todo 2009-12-19 03:03 hrehfeld add crc calculation */
155 | FileInfo info = new FileInfo(filename, crc);
156 | files.add(info);
157 |
158 |
159 | for (File dirname: createdDirs) {
160 | //save relative paths to files so we can delete dirs later
161 | files.add(new FileInfo(RelativePath.getRelativePath(basedir, dirname).toString(), 0));
162 | }
163 |
164 | //if we extracted to temp, rename
165 | if (!f.equals(original)) {
166 | original.delete();
167 | System.out.println("moving Temp file to " + original);
168 | f.renameTo(original);
169 | }
170 |
171 | extracted = true;
172 | }
173 | }
174 |
175 | if (!extracted) {
176 | throw new java.util.zip.ZipException("No files extracted from zip, is it an empty file?");
177 | }
178 | zis.close();
179 | }
180 |
181 | public void publish(long progress) {
182 | if (progress <= 100) {
183 | setProgress((int) progress);
184 | }
185 | }
186 |
187 | public void checkCancelled() throws Installer.CancelledException {
188 | if (isCancelled()) {
189 | System.out.println("canceling...");
190 | throw new Installer.CancelledException();
191 | }
192 | }
193 |
194 | public PackageFileList getInstalledFiles() {
195 | return files;
196 | }
197 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/InstalledPackageList.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | import java.io.InputStream;
23 | import java.io.OutputStream;
24 | import java.util.ArrayList;
25 | import java.util.Collections;
26 | import java.util.HashMap;
27 | import java.util.List;
28 | import java.util.Map;
29 |
30 | import javax.xml.parsers.DocumentBuilder;
31 | import javax.xml.parsers.DocumentBuilderFactory;
32 | import javax.xml.transform.OutputKeys;
33 | import javax.xml.transform.Transformer;
34 | import javax.xml.transform.TransformerFactory;
35 | import javax.xml.transform.dom.DOMSource;
36 | import javax.xml.transform.stream.StreamResult;
37 |
38 | import org.w3c.dom.Document;
39 | import org.w3c.dom.Element;
40 | import org.w3c.dom.Node;
41 | import org.w3c.dom.NodeList;
42 |
43 | public class InstalledPackageList {
44 | private final static String ROOTNODE = "maps";
45 |
46 | public void write(OutputStream out, Iterable extends Requirement> list)
47 | throws java.io.IOException {
48 | Map> files = new HashMap>();
49 |
50 | for (Requirement r: list) {
51 | if (!r.isInstalled()) {
52 | continue;
53 | }
54 |
55 | Iterable l = r.getFileList();
56 | if (l == null) {
57 | l = Collections.emptyList();
58 | }
59 |
60 | files.put(r.getId(), l);
61 | }
62 | if (files.isEmpty()) {
63 | System.out.println("WARNING: writing empty maplist");
64 | }
65 | write(out, files);
66 | }
67 |
68 | public void write(OutputStream out, Map> files)
69 | throws java.io.IOException {
70 |
71 | //try {
72 | DocumentBuilder docBuilder = null;
73 | try {
74 | docBuilder
75 | = DocumentBuilderFactory.newInstance().newDocumentBuilder();
76 | }
77 | catch (javax.xml.parsers.ParserConfigurationException e) {
78 | System.err.println("Couldn't instantiate Document Builder: " + e);
79 | e.printStackTrace();
80 | }
81 | Document doc = docBuilder.newDocument();
82 |
83 | //create the root element and add it to the document
84 | Element root = doc.createElement(ROOTNODE);
85 | doc.appendChild(root);
86 |
87 | for (Map.Entry> e: files.entrySet()) {
88 | String id = e.getKey();
89 | Iterable fileIterable = e.getValue();
90 |
91 | Element mapNode = doc.createElement("map");
92 | mapNode.setAttribute("id", id);
93 | root.appendChild(mapNode);
94 |
95 | for (FileInfo file: fileIterable) {
96 | Element fileNode = doc.createElement("file");
97 | //System.out.println("adding node " + file.getName());
98 | fileNode.setAttribute("name", file.getName());
99 | long crc = file.getChecksum();
100 | if (crc != 0) {
101 | fileNode.setAttribute("crc", Long.toString(crc));
102 | }
103 |
104 | if (!file.getEssential()) {
105 | fileNode.setAttribute("essential", Boolean.toString(false));
106 | }
107 |
108 | mapNode.appendChild(fileNode);
109 | }
110 | }
111 |
112 | //Output the XML
113 |
114 | //set up a transformer
115 | Transformer trans = null;
116 | try {
117 | trans = TransformerFactory.newInstance().newTransformer();
118 | }
119 | catch (javax.xml.transform.TransformerConfigurationException e) {
120 | System.err.println(e);
121 | e.printStackTrace();
122 | }
123 |
124 | trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
125 | trans.setOutputProperty(OutputKeys.INDENT, "yes");
126 |
127 | //create string from xml tree
128 | StreamResult result = new StreamResult(out);
129 | DOMSource source = new DOMSource(doc);
130 | try {
131 | trans.transform(source, result);
132 | }
133 | catch (javax.xml.transform.TransformerException e) {
134 | }
135 | }
136 |
137 | public List read(InputStream in) throws java.io.IOException {
138 | Document document;
139 | try {
140 | DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
141 | DocumentBuilder db = dbf.newDocumentBuilder();
142 |
143 | document = db.parse(in);
144 | }
145 | catch (javax.xml.parsers.ParserConfigurationException e) {
146 | throw new java.io.IOException("Couldn't parse installed package list: "
147 | + e.getMessage());
148 | }
149 | catch (org.xml.sax.SAXException e) {
150 | throw new java.io.IOException("Couldn't parse Installed Package List: "
151 | + e.getMessage());
152 | }
153 |
154 | Element root = document.getDocumentElement();
155 |
156 | NodeList installedMaps = root.getChildNodes();
157 |
158 |
159 | List files = new ArrayList(installedMaps.getLength());
160 |
161 | for (int i = 0; i < installedMaps.getLength(); ++i) {
162 | Node map = installedMaps.item(i);
163 |
164 | if (map.getNodeType() == Node.ELEMENT_NODE) {
165 | PackageFileList l = parseMapFileList((Element) map);
166 | files.add(l);
167 | }
168 | /** @todo 2009-03-29 01:36 hrehfeld find out why this happens */
169 | else {
170 | // System.out.println("node: " + file.getNodeName());
171 | // System.out.println("Whoops, i thought file is an element!");
172 | }
173 | }
174 |
175 | return files;
176 | }
177 |
178 | private PackageFileList parseMapFileList(Element map) {
179 | String id = map.getAttribute("id");
180 | PackageFileList fileList = new PackageFileList(id);
181 |
182 | NodeList files = map.getChildNodes();
183 |
184 | for (int i = 0; i < files.getLength(); ++i) {
185 | Node file = files.item(i);
186 | if (file.getNodeType() == Node.ELEMENT_NODE) {
187 | Element e = (Element) file;
188 | String name = e.getAttribute("name");
189 |
190 | long crc = 0;
191 | if (e.hasAttribute("crc")) {
192 | crc = Long.parseLong(e.getAttribute("crc"));
193 | }
194 | boolean essential = true;
195 | if (e.hasAttribute("essential") && e.getAttribute("essential").equals(Boolean.toString(false))) {
196 | essential = false;
197 | }
198 | fileList.add(new FileInfo(name, crc, essential));
199 | }
200 | }
201 |
202 | return fileList;
203 |
204 | }
205 | }
206 |
207 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/InstalledPackages.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | import java.util.concurrent.Future;
23 | import java.util.concurrent.ExecutionException;
24 | import java.util.List;
25 | import java.util.Collections;
26 | import java.io.InputStream;
27 | import java.io.BufferedInputStream;
28 | import java.io.FileInputStream;
29 | import java.io.File;
30 | import java.io.FileNotFoundException;
31 | import java.io.IOException;
32 |
33 | import javax.swing.SwingWorker;
34 |
35 | public class InstalledPackages {
36 | private Future> installedPackages;
37 |
38 | public void parse(File installedPackagesXml) {
39 | ParseInstalledPackagesWorker parseInstalled
40 | = new ParseInstalledPackagesWorker(installedPackagesXml);
41 | parseInstalled.execute();
42 | installedPackages = parseInstalled;
43 | }
44 |
45 | public List get() throws InterruptedException, ExecutionException {
46 | try {
47 | return installedPackages.get();
48 | }
49 | catch (InterruptedException e) {
50 | throw e;
51 | }
52 | catch (ExecutionException e) {
53 | throw e;
54 | }
55 | }
56 |
57 |
58 | public List getDefaultErrorHandling() {
59 | try {
60 | return get();
61 | }
62 | catch (InterruptedException e) {
63 | System.err.println("Error: couldn't set installedPackages, interrupted!" + e);
64 | e.printStackTrace();
65 | }
66 | catch (ExecutionException err) {
67 | try {
68 | throw err.getCause();
69 | }
70 | catch (java.io.FileNotFoundException e) {
71 | System.out.println("Notice: installed packages file doesn't exist yet,"
72 | + " no packages installed? " + e);
73 | }
74 | catch (java.io.IOException e) {
75 | System.err.println("Error: installed packages file couldn't be "
76 | + "loaded: " + e);
77 | e.printStackTrace();
78 | }
79 | }
80 | finally {
81 | return Collections.emptyList();
82 | }
83 | }
84 |
85 |
86 | class ParseInstalledPackagesWorker extends SwingWorker,Void> {
87 | public final File xml;
88 |
89 | public ParseInstalledPackagesWorker(File xml) {
90 | this.xml = xml;
91 | }
92 |
93 | @Override
94 | public List doInBackground() throws FileNotFoundException, IOException {
95 | return parseInstalledPackagesFile(xml);
96 | }
97 | }
98 |
99 | /**
100 | * Thrown if no installed packages xml exists
101 | */
102 | public static class NoInstalledPackagesFileException extends FileNotFoundException {
103 | public NoInstalledPackagesFileException(String msg) { super(msg); }
104 | public NoInstalledPackagesFileException() { super(); }
105 | }
106 |
107 | private List parseInstalledPackagesFile(File installedPackagesFile)
108 | throws NoInstalledPackagesFileException, FileNotFoundException, IOException {
109 | if (!installedPackagesFile.exists()) {
110 | throw new NoInstalledPackagesFileException("No Installed packages file (" + installedPackagesFile + ")"
111 | + ", no packages installed?");
112 | }
113 |
114 | final InputStream in = new BufferedInputStream(new FileInputStream(installedPackagesFile));
115 |
116 | List result = new InstalledPackageList().read(in);
117 |
118 | //close the stream after parsing is finished
119 | Exception error = null;
120 | try {
121 | in.close();
122 | }
123 | catch (java.io.FileNotFoundException e) {
124 | error = e;
125 | }
126 | catch (java.io.IOException e) {
127 | error = e;
128 | }
129 | if (error != null ) {
130 | System.err.println("Error: couldn't close filestream " + installedPackagesFile + ": " + error);
131 | }
132 | return result;
133 | }
134 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/Menu.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | //import java.awt.*;
23 | import java.awt.event.ActionEvent;
24 | import java.awt.event.ActionListener;
25 | import java.awt.event.KeyEvent;
26 |
27 | import javax.swing.JMenu;
28 | import javax.swing.JMenuBar;
29 | import javax.swing.JMenuItem;
30 | import javax.swing.JCheckBoxMenuItem;
31 | import javax.swing.KeyStroke;
32 |
33 | public class Menu extends JMenuBar {
34 | private JCheckBoxMenuItem enableOfflineMode;
35 |
36 | public Menu(ActionListener databaseParser,
37 | ActionListener checkForInstalledMaps,
38 | ActionListener quitter,
39 | ActionListener showEngineConfig,
40 | ActionListener offlineAction) {
41 | setOpaque(true);
42 | // setPreferredSize(new Dimension(200, 20));
43 |
44 | JMenu fileMenu = new JMenu("File");
45 | add(fileMenu);
46 |
47 | JMenuItem reparseDatabase = new JMenuItem("Reload database", KeyEvent.VK_R);
48 | reparseDatabase.addActionListener(databaseParser);
49 | fileMenu.add(reparseDatabase);
50 |
51 | JMenuItem checkInstalled = new JMenuItem("Check for installed maps (experimental!)", KeyEvent.VK_C);
52 | checkInstalled.addActionListener(checkForInstalledMaps);
53 | fileMenu.add(checkInstalled);
54 |
55 | enableOfflineMode = new JCheckBoxMenuItem("Offline Mode");
56 | checkInstalled.addActionListener(offlineAction);
57 | fileMenu.add(enableOfflineMode);
58 |
59 |
60 | JMenuItem quit = new JMenuItem("Quit", KeyEvent.VK_T);
61 | quit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_1, ActionEvent.ALT_MASK));
62 | quit.getAccessibleContext().setAccessibleDescription("This doesn't really do anything");
63 | quit.addActionListener(quitter);
64 | fileMenu.add(quit);
65 |
66 | JMenu configM = new JMenu("Configuration");
67 | add(configM);
68 |
69 | JMenuItem engine = new JMenuItem("Engine Configuration");
70 | configM.add(engine);
71 | engine.addActionListener(showEngineConfig);
72 | }
73 |
74 | public void setOfflineMode(boolean offline) {
75 | enableOfflineMode.setSelected(offline);
76 | }
77 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/OnlineFileNotFoundException.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | import java.io.FileNotFoundException;
23 |
24 | public class OnlineFileNotFoundException extends FileNotFoundException {
25 | public OnlineFileNotFoundException() {
26 | super();
27 | }
28 | public OnlineFileNotFoundException(String message) {
29 | super(message);
30 | }
31 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/Package.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | import java.util.ArrayList;
23 | import java.util.Date;
24 | import java.util.List;
25 |
26 | import javax.swing.event.ChangeListener;
27 |
28 | /**
29 | * A requirement that has an installation candidate available.
30 | */
31 | public class Package extends SortableRequirement implements Requirement {
32 |
33 | /**
34 | * easily have change listeners
35 | */
36 | private ChangeListenerList listeners = new ChangeListenerList();
37 |
38 | private String author;
39 |
40 | private String title;
41 |
42 | private Rating rating;
43 |
44 | private float normalizedUsersRating;
45 |
46 | private String description;
47 |
48 | /**
49 | * Size in kb?
50 | */
51 | private int size;
52 |
53 | private Date date;
54 |
55 | private String relativeBaseDir;
56 |
57 | private String commandline;
58 |
59 | private List startmaps;
60 |
61 | private List requirements;
62 |
63 | private PackageFileList fileList;
64 | private PackageFileList supposedFileList;
65 |
66 | public Package(String id,
67 | String author,
68 | String title,
69 | int size,
70 | Date date,
71 | boolean isInstalled,
72 | Rating rating,
73 | float normalizedUsersRating,
74 | String description) {
75 | this(id, author, title, size, date, isInstalled, rating, normalizedUsersRating, description, null, null, null, null);
76 | }
77 |
78 | public Package(String id,
79 | String author,
80 | String title,
81 | int size,
82 | Date date,
83 | boolean isInstalled,
84 | Rating rating,
85 | float normalizedUsersRating,
86 | String description,
87 | String relativeBaseDir,
88 | String commandline,
89 | List startmaps,
90 | List requirements) {
91 | super(id);
92 | this.author = author;
93 | this.title = title;
94 | this.size = size;
95 | this.date = date;
96 | super.setInstalled(isInstalled);
97 | this.rating = rating;
98 | this.normalizedUsersRating = normalizedUsersRating;
99 | this.description = description;
100 | this.relativeBaseDir = relativeBaseDir;
101 | this.commandline = commandline;
102 | this.startmaps = startmaps;
103 | this.requirements = requirements;
104 | }
105 |
106 | @Override
107 | public void addChangeListener(ChangeListener l) {
108 | listeners.addChangeListener(l);
109 | }
110 |
111 |
112 | @Override
113 | public void removeChangeListener(ChangeListener l) {
114 | listeners.removeChangeListener(l);
115 | }
116 |
117 | public String getAuthor() {
118 | return author;
119 | }
120 | public String getTitle() {
121 | return title;
122 | }
123 | public int getSize() {
124 | return size;
125 | }
126 | public Date getDate() {
127 | return date;
128 | }
129 |
130 | /**
131 | * get rating
132 | */
133 | public Rating getRating() { return rating; }
134 |
135 | public float getNormalizedUsersRating() { return normalizedUsersRating; }
136 |
137 |
138 | /**
139 | * get description
140 | */
141 | public String getDescription() { return description; }
142 |
143 |
144 | public String getRelativeBaseDir() {
145 | return relativeBaseDir;
146 | }
147 |
148 | public String getCommandline() {
149 | return commandline;
150 | }
151 |
152 | public List getStartmaps() {
153 | return startmaps;
154 | }
155 |
156 | public void setRequirements(List requirements) {
157 | this.requirements = requirements;
158 | }
159 |
160 | public List getRequirements() {
161 | return this.requirements;
162 | }
163 |
164 |
165 | public List getAvailableRequirements() {
166 | List avails = new ArrayList();
167 | for (Requirement r: requirements) {
168 | if (r instanceof Package) {
169 | avails.add((Package) r);
170 | }
171 | }
172 | return avails;
173 | }
174 |
175 |
176 | public List getUnavailableRequirements() {
177 | List unavails = new ArrayList();
178 |
179 | for (Requirement r: requirements) {
180 | if (!r.isInstalled() && !(r instanceof Package)) {
181 | unavails.add(r);
182 | }
183 | }
184 | return unavails;
185 | }
186 |
187 | public List getUnmetRequirements() {
188 | List unmet = new ArrayList();
189 | for (Requirement requirement: requirements) {
190 | if (!requirement.isInstalled()) {
191 | unmet.add(requirement);
192 | }
193 | }
194 |
195 | return unmet;
196 | }
197 |
198 | @Override
199 | protected void notifyChangeListeners() {
200 | listeners.notifyChangeListeners(this);
201 | }
202 |
203 | @Override
204 | public String toString() {
205 | return getId() + " (" + isInstalled() + ")";
206 | }
207 |
208 | /**
209 | * get fileList
210 | */
211 | public PackageFileList getFileList() { return fileList; }
212 |
213 | /**
214 | * set fileList
215 | */
216 | public void setFileList(PackageFileList fileList) { this.fileList = fileList; }
217 |
218 | /**
219 | * get supposedFileList
220 | */
221 | public PackageFileList getSupposedFileList() { return supposedFileList; }
222 |
223 | /**
224 | * set supposedFileList
225 | */
226 | public void setSupposedFileList(PackageFileList supposedFileList) { this.supposedFileList = supposedFileList; }
227 |
228 | public static enum Rating {
229 | Unrated(0),
230 | Crap(1),
231 | Poor(2),
232 | Average(3),
233 | Nice(4),
234 | Excellent(5);
235 |
236 | private int rating;
237 | Rating(int rating) {
238 | this.rating = rating;
239 | }
240 |
241 | public int getRating() {
242 | return rating;
243 | }
244 | }
245 | }
246 |
247 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/PackageDatabaseParser.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | import java.io.IOException;
23 | import java.util.ArrayList;
24 | import java.util.Date;
25 | import java.util.GregorianCalendar;
26 | import java.util.HashMap;
27 | import java.util.List;
28 | import java.util.Map;
29 |
30 | import org.w3c.dom.Document;
31 | import org.w3c.dom.Element;
32 | import org.w3c.dom.Node;
33 |
34 | import de.haukerehfeld.quakeinjector.Package.Rating;
35 |
36 | public class PackageDatabaseParser implements java.io.Serializable {
37 | private final static Rating[] ratingTable = { Rating.Unrated,
38 | Rating.Crap,
39 | Rating.Poor,
40 | Rating.Average,
41 | Rating.Nice,
42 | Rating.Excellent
43 | };
44 |
45 |
46 | /**
47 | * Parse the complete document
48 | */
49 | public List parse(Document document) throws IOException,
50 | org.xml.sax.SAXException {
51 | HashMap packages = new HashMap();
52 | Map> unresolvedRequirements = new HashMap>();
53 |
54 | Element files = document.getDocumentElement();
55 |
56 | for (Node file: XmlUtils.iterate(files.getChildNodes())) {
57 | if (XmlUtils.isElement(file)) {
58 | Package currentPackage = parsePackage((Element) file, unresolvedRequirements);
59 | packages.put(currentPackage.getId(), currentPackage);
60 | }
61 | /** @todo 2009-03-29 01:36 hrehfeld find out why this happens */
62 | else {
63 | // System.out.println("node: " + file.getNodeName());
64 | // System.out.println("Whoops, i thought file is an element!");
65 | }
66 | }
67 |
68 | resolveRequirements(unresolvedRequirements, packages);
69 |
70 | List packageList = new ArrayList(packages.values());
71 | return packageList;
72 | }
73 |
74 | private void resolveRequirements(Map> unresolvedRequirements,
75 | Map packages) {
76 | for (Map.Entry> entry: unresolvedRequirements.entrySet()) {
77 | Package current = entry.getKey();
78 | List reqs = entry.getValue();
79 |
80 | // if (reqs.size() > 1) {
81 | // System.out.println(current.getId() + " has more than one requirement");
82 | // }
83 |
84 | List resolvedRequirements = new ArrayList(reqs.size());
85 | for (String id: reqs) {
86 | Requirement resolved = packages.get(id);
87 | if (resolved == null) {
88 | resolved = new UnavailableRequirement(id);
89 | packages.put(id, resolved);
90 | }
91 | resolvedRequirements.add(resolved);
92 | }
93 | current.setRequirements(resolvedRequirements);
94 | }
95 | }
96 |
97 |
98 | /**
99 | * Parse a single Package/file entry
100 | */
101 | private Package parsePackage(Element file, Map> reqResolve) {
102 | String id = file.getAttribute("id");
103 | Rating rating;
104 | {
105 | String ratingString = file.getAttribute("rating");
106 | int ratingNumber = 0;
107 | if (!ratingString.equals("")) {
108 | try {
109 | ratingNumber = Integer.parseInt(ratingString);
110 |
111 | if (ratingNumber < 0 || ratingNumber > 5) {
112 | System.out.println("Rating of " + id + " is broken");
113 | ratingNumber = 0;
114 | }
115 | }
116 | catch (java.lang.NumberFormatException e) {
117 | System.out.println("Rating of " + id + " is broken");
118 | }
119 | }
120 | rating = ratingTable[ratingNumber];
121 | }
122 |
123 | float normalizedUsersRating;
124 | {
125 | String normalizedUsersRatingString = file.getAttribute("normalized_users_rating");
126 | try {
127 | normalizedUsersRating = Float.parseFloat(normalizedUsersRatingString);
128 | } catch (java.lang.NumberFormatException e) {
129 | System.out.println("Users' rating of " + id + " is broken");
130 | normalizedUsersRating = Float.NEGATIVE_INFINITY;
131 | }
132 | }
133 |
134 | String title = XmlUtils.getFirstElement(file, "title").getTextContent().trim();
135 | String author = XmlUtils.getFirstElement(file, "author").getTextContent().trim();
136 | int size;
137 | try {
138 | size = Integer.parseInt(XmlUtils.getFirstElement(file, "size").getTextContent().trim());
139 | }
140 | catch (java.lang.NumberFormatException e) {
141 | System.out.println("XML Parsing Error: malformed tag on record \"" + id + "\"");
142 | size = 0;
143 | }
144 |
145 | String date = XmlUtils.getFirstElement(file, "date").getTextContent().trim();
146 |
147 | String description = XmlUtils.getTextForNode(XmlUtils.getFirstElement(file, "description"))
148 | .trim();
149 |
150 |
151 | String relativeBaseDir = null;
152 | String cmdline = null;
153 | ArrayList startmaps = new ArrayList();
154 |
155 | ArrayList requirements = new ArrayList();
156 |
157 | // parse techinfo stuff
158 | Element techinfo = XmlUtils.getFirstElement(file, "techinfo");
159 | if (techinfo != null) {
160 | for (Node node: XmlUtils.iterate(techinfo.getChildNodes())) {
161 | if (!XmlUtils.isElement(node)) {
162 | continue;
163 | }
164 | Element info = (Element) node;
165 |
166 | if (info.getTagName().equals("zipbasedir")) {
167 | relativeBaseDir = info.getTextContent();
168 | }
169 | else if (info.getTagName().equals("commandline")) {
170 | cmdline = info.getTextContent();
171 | }
172 | else if (info.getTagName().equals("startmap")) {
173 | startmaps.add(info.getTextContent());
174 | }
175 | else if (info.getTagName().equals("requirements")) {
176 | for (Node reqFile: XmlUtils.iterate(info.getChildNodes())) {
177 | if (XmlUtils.isElement(reqFile)) {
178 | String r = ((Element) reqFile).getAttribute("id");
179 | requirements.add(r);
180 | }
181 | }
182 | }
183 | }
184 | }
185 |
186 | // System.out.println("id: " + id
187 | // + ", title: " + title
188 | // + ", size: " + size);
189 |
190 | //if there's no startmap tag, use the id
191 | if (startmaps.isEmpty()) {
192 | startmaps.add(id);
193 | }
194 |
195 | Package result = new Package(id,
196 | author,
197 | title,
198 | size,
199 | PackageDatabaseParser.parseDate(date),
200 | false,
201 | rating,
202 | normalizedUsersRating,
203 | description,
204 | relativeBaseDir,
205 | cmdline,
206 | startmaps,
207 | null);
208 | reqResolve.put(result, requirements);
209 | return result;
210 | }
211 |
212 | /**
213 | * Parses the date that's in dd.mm.yyyy format
214 | */
215 | public static Date parseDate(String date) {
216 | String[] components = date.split("\\.");
217 | if (components.length < 3) {
218 | throw new RuntimeException("Xml Parsing error: date malformed");
219 | }
220 | int day = Integer.parseInt(components[0]);
221 | int month = Integer.parseInt(components[1]) - 1;
222 | int year = Integer.parseInt(components[2]);
223 | return new GregorianCalendar(year, month, day).getTime();
224 | }
225 | }
226 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/PackageDatabaseParserWorker.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | //import java.awt.*;
23 | import java.io.InputStream;
24 | import java.util.List;
25 |
26 | import javax.swing.SwingWorker;
27 |
28 | /**
29 | * Parse database xml and set database in background
30 | */
31 | public class PackageDatabaseParserWorker extends SwingWorker, Void>
32 | implements ProgressListener {
33 | private final String databaseUrl;
34 |
35 | public PackageDatabaseParserWorker(String databaseUrl) {
36 | this.databaseUrl = databaseUrl;
37 | }
38 |
39 | @Override
40 | public List doInBackground() throws java.io.IOException, org.xml.sax.SAXException {
41 | InputStream dl = getDownloadStream(this.databaseUrl);
42 |
43 | final PackageDatabaseParser parser = new PackageDatabaseParser();
44 | List all = parser.parse(XmlUtils.getDocument(dl));
45 |
46 | return all;
47 | }
48 |
49 |
50 | @Override
51 | public void done() {
52 | }
53 |
54 | private InputStream getDownloadStream(final String databaseUrl) throws java.io.IOException {
55 | //get download stream
56 | Download d = Download.create(databaseUrl);
57 | d.connect();
58 | int size = d.getSize();
59 | InputStream dl;
60 | if (size > 0) {
61 | ProgressListener progress =
62 | new SumProgressListener(new PercentageProgressListener(size, this));
63 | dl = d.getStream(progress);
64 | }
65 | else {
66 | dl = d.getStream(null);
67 | }
68 | return dl;
69 | }
70 |
71 |
72 | public void publish(long progress) {
73 | if (progress <= 100) {
74 | setProgress((int) progress);
75 | }
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/PackageFileList.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | import java.util.Iterator;
23 | import java.util.TreeSet;
24 |
25 | public class PackageFileList implements Iterable, Comparable {
26 | /**
27 | * other classes rely on the sorted iteration this provides
28 | */
29 | private TreeSet files = new TreeSet();
30 |
31 | private String id;
32 |
33 | public PackageFileList(String id) {
34 | this.id = id;
35 | }
36 |
37 | public boolean isEmpty() {
38 | return files.isEmpty();
39 | }
40 |
41 | public void add(FileInfo file) {
42 | file.clean();
43 | files.add(file);
44 | }
45 |
46 | public void remove(FileInfo file) {
47 | file.clean();
48 | files.remove(file);
49 | }
50 |
51 | public int size() {
52 | return files.size();
53 | }
54 |
55 | /**
56 | * iterate the files in ascending order by their filename
57 | */
58 | public Iterator iterator() {
59 | return files.iterator();
60 | }
61 |
62 | public Iterator descendingIterator() {
63 | return files.descendingIterator();
64 | }
65 |
66 | public String getId() {
67 | return id;
68 | }
69 |
70 | @Override public int compareTo(PackageFileList o) {
71 | return -(o.id.compareTo(id));
72 | }
73 | @Override public boolean equals(Object o) {
74 | if (!(o instanceof PackageFileList)) {
75 | return false;
76 | }
77 | return ((PackageFileList) o).id.equals(id);
78 | }
79 | @Override public int hashCode() {
80 | return id.hashCode();
81 | }
82 |
83 |
84 | @Override public String toString() {
85 | return id + "[" + files.toString() + "]";
86 | }
87 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/PackageList.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | import java.util.ArrayList;
23 | import java.util.Iterator;
24 | import java.util.List;
25 |
26 | import javax.swing.event.ChangeEvent;
27 | import javax.swing.event.ChangeListener;
28 |
29 | /**
30 | * Only the Package s in a RequirementsList
31 | */
32 | public class PackageList implements Iterable, ChangeListener {
33 | private List packages = new ArrayList();
34 | private RequirementList requirements;
35 |
36 | public PackageList(RequirementList requirements) {
37 | this.requirements = requirements;
38 | setRequirements(requirements);
39 | }
40 |
41 | private void setRequirements(RequirementList requirements) {
42 |
43 | packages.clear();
44 | for (Requirement r: requirements) {
45 | if (r instanceof Package) {
46 | packages.add((Package) r);
47 | }
48 | }
49 |
50 | this.requirements = requirements;
51 | this.requirements.addChangeListener(this);
52 | notifyChangeListeners();
53 | }
54 |
55 | public void sort() {
56 | java.util.Collections.sort(packages);
57 | }
58 |
59 | public Package get(int i) {
60 | return packages.get(i);
61 | }
62 |
63 | public Package get(String id) {
64 | Requirement r = requirements.get(id);
65 | if (!(r instanceof Package)) {
66 | return null;
67 | }
68 | return (Package) r;
69 | }
70 |
71 |
72 | public Iterator iterator() {
73 | return packages.iterator();
74 | }
75 |
76 | public int size() {
77 | return packages.size();
78 | }
79 |
80 | public int indexOf(Package r) {
81 | return packages.indexOf(r);
82 | }
83 |
84 |
85 | /**
86 | * easily have change listeners
87 | */
88 | private ChangeListenerList listeners = new ChangeListenerList();
89 |
90 | public void addChangeListener(ChangeListener l) {
91 | listeners.addChangeListener(l);
92 | }
93 | public void removeChangeListener(ChangeListener l) {
94 | listeners.removeChangeListener(l);
95 | }
96 | private void notifyChangeListeners() {
97 | listeners.notifyChangeListeners(this);
98 | }
99 |
100 | public void stateChanged(ChangeEvent e) {
101 | if (!(e.getSource() instanceof RequirementList)) {
102 | throw new RuntimeException("getting change events with source not a RequirementList");
103 | }
104 |
105 | setRequirements((RequirementList) e.getSource());
106 | }
107 |
108 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/PackageListSelectionHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | import java.util.ArrayList;
23 |
24 | import javax.swing.JTable;
25 | import javax.swing.ListSelectionModel;
26 | import javax.swing.event.ListSelectionEvent;
27 | import javax.swing.event.ListSelectionListener;
28 |
29 | import de.haukerehfeld.quakeinjector.packagelist.model.PackageListModel;
30 |
31 | class PackageListSelectionHandler implements ListSelectionListener {
32 | private PackageListModel list;
33 |
34 | private JTable table;
35 |
36 | private ArrayList listeners = new ArrayList();
37 |
38 | private int lastSelection = -1;
39 |
40 | public PackageListSelectionHandler(PackageListModel list,
41 | JTable table) {
42 | this.list = list;
43 | this.table = table;
44 | }
45 |
46 | /**
47 | * Listen on selection changes
48 | */
49 | @Override
50 | public void valueChanged(ListSelectionEvent e) {
51 | ListSelectionModel lsm = (ListSelectionModel) e.getSource();
52 |
53 | if (!lsm.isSelectionEmpty()) {
54 | int selection = table.convertRowIndexToModel(getSelection(lsm));
55 | if (lastSelection == selection) {
56 | return;
57 | }
58 | notifySelectionListeners(list.getPackage(selection));
59 | lastSelection = selection;
60 | }
61 | }
62 |
63 | /**
64 | * Find out what entry was selected
65 | */
66 | public int getSelection(ListSelectionModel lsm) {
67 | int selection = -1;
68 | // Find out which indexes are selected.
69 | int minIndex = lsm.getMinSelectionIndex();
70 | int maxIndex = lsm.getMaxSelectionIndex();
71 | for (int i = minIndex; i <= maxIndex; i++) {
72 | if (lsm.isSelectedIndex(i)) {
73 | selection = i;
74 | break;
75 | }
76 | }
77 | return selection;
78 | }
79 |
80 | public void addSelectionListener(SelectionListener l) {
81 | listeners.add(l);
82 | }
83 |
84 | private void notifySelectionListeners(Package selection) {
85 | for (SelectionListener l: listeners) {
86 | l.selectionChanged(selection);
87 | }
88 | }
89 |
90 | public interface SelectionListener {
91 | public void selectionChanged(Package selection);
92 | }
93 | }
94 |
95 |
96 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/PackageOverwriteDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | import java.awt.BorderLayout;
23 | import java.awt.Dimension;
24 | import java.awt.GridBagConstraints;
25 | import java.awt.GridBagLayout;
26 | import java.awt.event.ActionEvent;
27 | import java.awt.event.ActionListener;
28 | import java.util.ArrayList;
29 | import java.util.HashMap;
30 | import java.util.List;
31 | import java.util.Map;
32 |
33 | import javax.swing.BorderFactory;
34 | import javax.swing.Box;
35 | import javax.swing.JButton;
36 | import javax.swing.JCheckBox;
37 | import javax.swing.JDialog;
38 | import javax.swing.JFrame;
39 | import javax.swing.JLabel;
40 | import javax.swing.JPanel;
41 | import javax.swing.JScrollPane;
42 | import javax.swing.border.Border;
43 |
44 | import de.haukerehfeld.quakeinjector.gui.OkayCancelApplyPanel;
45 | import de.haukerehfeld.quakeinjector.gui.ScrollablePanel;
46 |
47 | public class PackageOverwriteDialog extends JDialog {
48 | private final static String windowTitle = "Overwrite Package Files?";
49 |
50 | private final static int BUTTONMARGIN = 6;
51 |
52 | private final static int MARGINWIDTH = 5;
53 |
54 | private final static int DESCRIPTIONMARGINWIDTH = 5 + MARGINWIDTH;
55 | private final static int DESCRIPTIONMARGINHEIGHT = 10;
56 | private final static Border DESCRIPTIONMARGIN
57 | = BorderFactory.createEmptyBorder(DESCRIPTIONMARGINHEIGHT,
58 | DESCRIPTIONMARGINWIDTH,
59 | DESCRIPTIONMARGINHEIGHT,
60 | DESCRIPTIONMARGINWIDTH);
61 |
62 | private final static int LINEENTRYMARGINWIDTH = 4 + MARGINWIDTH;
63 | private final static int LINEENTRYMARGINHEIGHT = 2;
64 | private final static Border LINEENTRYMARGIN
65 | = BorderFactory.createEmptyBorder(LINEENTRYMARGINHEIGHT,
66 | LINEENTRYMARGINWIDTH,
67 | LINEENTRYMARGINHEIGHT,
68 | LINEENTRYMARGINWIDTH);
69 |
70 | private final static int CHECKBOXINDENT = 17;
71 | private final static int CHECKBOXEXTRAMARGIN = 0;
72 | private final static Border NOCHECKBOXLINEENTRYMARGIN
73 | = BorderFactory.createEmptyBorder(LINEENTRYMARGINHEIGHT + CHECKBOXEXTRAMARGIN,
74 | LINEENTRYMARGINWIDTH + CHECKBOXINDENT,
75 | LINEENTRYMARGINHEIGHT + CHECKBOXEXTRAMARGIN,
76 | LINEENTRYMARGINWIDTH);
77 |
78 | private final static int SECTIONMARGIN = 15;
79 |
80 | private final JFrame parent;
81 |
82 | private final JPanel panel;
83 |
84 | private boolean canceled = true;
85 |
86 | private ArrayList overwriteList = new ArrayList();
87 | private ArrayList alwaysWriteList = new ArrayList();
88 |
89 | private final Map overwriteBoxes = new HashMap();
90 |
91 | public PackageOverwriteDialog(final JFrame frame) {
92 | super(frame, windowTitle, true);
93 | this.parent = frame;
94 |
95 | panel = new ScrollablePanel(50, 50);
96 | panel.setLayout(new GridBagLayout());
97 | panel.setOpaque(false);
98 |
99 | JScrollPane panelScroll = new JScrollPane(panel);
100 | panelScroll.getViewport().setBackground(javax.swing.UIManager.getColor("TextPane.background"));
101 | add(panelScroll, BorderLayout.CENTER);
102 |
103 | final JButton okay = new JButton("Write files");
104 | final JButton cancel = new JButton("Cancel");
105 |
106 | okay.addActionListener(new ActionListener() {
107 | public void actionPerformed(ActionEvent e) {
108 | canceled = false;
109 |
110 | setVisible(false);
111 | dispose();
112 | }
113 | });
114 | cancel.addActionListener(new ActionListener() {
115 | public void actionPerformed(ActionEvent e) {
116 | setVisible(false);
117 | dispose();
118 | }
119 | });
120 |
121 | {
122 |
123 |
124 | add(new OkayCancelApplyPanel(okay, cancel, null, false), BorderLayout.PAGE_END);
125 | }
126 |
127 | }
128 |
129 | private void addDescriptionLabel(final String text, final int line) {
130 | JLabel description = new JLabel(text);
131 | description.setLabelFor(this);
132 | description.setOpaque(true);
133 | description.setBorder(DESCRIPTIONMARGIN);
134 | panel.add(description, new GridBagConstraints() {{
135 | gridy = line;
136 |
137 | gridwidth = 2;
138 | fill = BOTH;
139 | anchor = LINE_START;
140 | }});
141 | }
142 |
143 | private void addDescription() {
144 | addDescriptionLabel(windowTitle, 0);
145 | }
146 |
147 | private void addAlwaysWriteDescription(final int line) {
148 | addDescriptionLabel("Files that need to be installed:", line);
149 | }
150 |
151 |
152 | public void addFile(String name, boolean overwrite) {
153 | List list = (overwrite ? overwriteList : alwaysWriteList);
154 | list.add(name);
155 | }
156 |
157 | public List getOverwritten() {
158 | List overwritten = new ArrayList(alwaysWriteList);
159 | for (Map.Entry e: overwriteBoxes.entrySet()) {
160 | String name = e.getKey();
161 | JCheckBox box = e.getValue();
162 | if (box.isSelected()) {
163 | overwritten.add(name);
164 | }
165 | }
166 |
167 | return overwritten;
168 | }
169 |
170 | public boolean isCanceled() {
171 | return canceled;
172 | }
173 |
174 | /**
175 | * Only call once
176 | */
177 | public void packAndShow() {
178 | addDescription();
179 | int lines = 1;
180 |
181 | java.util.Collections.sort(overwriteList);
182 | for (String name: overwriteList) {
183 | JCheckBox overwrite = new JCheckBox(name);
184 | overwrite.setSelected(true);
185 | overwrite.setOpaque(false);
186 | overwrite.setBorder(LINEENTRYMARGIN);
187 | final int finalLines = lines;
188 | panel.add(overwrite, new OverwriteBoxConstraints() {{
189 | gridy = finalLines;
190 | }});
191 | overwriteBoxes.put(name, overwrite);
192 | ++lines;
193 | }
194 |
195 | if (!alwaysWriteList.isEmpty()) {
196 | {
197 | final int finalLines = lines++;
198 | panel.add(Box.createRigidArea(new Dimension(0,SECTIONMARGIN)),
199 | new GridBagConstraints() {{
200 | gridy = finalLines;
201 | }});
202 | }
203 | java.util.Collections.sort(alwaysWriteList);
204 | addAlwaysWriteDescription(lines++);
205 |
206 | for (String name: alwaysWriteList) {
207 | JLabel listEntry = new JLabel(name);
208 | listEntry.setOpaque(false);
209 | listEntry.setBorder(NOCHECKBOXLINEENTRYMARGIN);
210 | final int finalLines = lines;
211 | panel.add(listEntry, new OverwriteBoxConstraints() {{
212 | gridy = finalLines;
213 | }});
214 | ++lines;
215 | }
216 | }
217 | pack();
218 | setLocationRelativeTo(parent);
219 | setVisible(true);
220 | }
221 |
222 | class OverwriteBoxConstraints extends GridBagConstraints {{
223 | anchor = LINE_START;
224 | fill = HORIZONTAL;
225 | weightx = 1;
226 | }};
227 |
228 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/PackageTable.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | import java.awt.Dimension;
23 | import java.awt.Color;
24 | import java.awt.Component;
25 |
26 | import javax.swing.UIManager;
27 |
28 | import javax.swing.JTable;
29 | import javax.swing.JComponent;
30 | import javax.swing.border.EmptyBorder;
31 | import javax.swing.table.TableCellRenderer;
32 | import javax.swing.table.TableRowSorter;
33 |
34 | import de.haukerehfeld.quakeinjector.packagelist.model.PackageListModel;
35 |
36 | /**
37 | * @todo check if dependency on de.haukerehfeld.quakeinjector.packagelist.model.PackageListModel is necessary
38 | */
39 | public class PackageTable extends JTable {
40 | private static final int ALTERNATING = 10;
41 | private static final Color NORMALROWCOLOR = UIManager.getColor("Table.background");
42 | private static final Color ALTERNATINGROWCOLOR = createAlternatingColor(NORMALROWCOLOR, ALTERNATING);
43 | private static final int CELLPADDING = 2;
44 |
45 | private final EmptyBorder border = new EmptyBorder(0, CELLPADDING, 0, CELLPADDING);
46 |
47 |
48 | public PackageTable(PackageListModel maplist) {
49 | super(maplist);
50 |
51 | final TableRowSorter sorter = new TableRowSorter(maplist);
52 | setRowSorter(sorter);
53 |
54 | setPreferredScrollableViewportSize(new Dimension(500, 500));
55 | setFillsViewportHeight(true);
56 | setColumnSelectionAllowed(false);
57 | //setCellSelectionEnabled(false);
58 | setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
59 | setShowGrid(false);
60 | setIntercellSpacing(new Dimension(0, 0));
61 | setRowHeight(getFontMetrics(getFont()).getHeight());
62 |
63 | setDefaultRenderer(Package.Rating.class, new PackageListModel.RatingRenderer());
64 | }
65 |
66 | /**
67 | * Shades alternate rows in different colors.
68 | */
69 | public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
70 | Component c = super.prepareRenderer(renderer, row, column);
71 | if (isCellSelected(row, column) == false) {
72 | c.setBackground(colorForRow(row));
73 | c.setForeground(UIManager.getColor("Table.foreground"));
74 | } else {
75 | c.setBackground(UIManager.getColor("Table.selectionBackground"));
76 | c.setForeground(UIManager.getColor("Table.selectionForeground"));
77 | }
78 | //disable cell focus
79 | if (c instanceof JComponent) {
80 | if (!(c instanceof PackageListModel.RatingRenderer)) {
81 | ((JComponent) c).setBorder(border);
82 | }
83 | else {
84 | ((JComponent) c).setBorder(new EmptyBorder(0, 0, 0, 0));
85 | }
86 | }
87 | return c;
88 | }
89 |
90 | /**
91 | * Returns the appropriate background color for the given row.
92 | */
93 | protected Color colorForRow(int row) {
94 | return (row % 2 == 0) ? NORMALROWCOLOR : ALTERNATINGROWCOLOR;
95 | }
96 |
97 | @Override
98 | @SuppressWarnings("unchecked")
99 | public TableRowSorter getRowSorter() {
100 | return (TableRowSorter) super.getRowSorter();
101 | }
102 |
103 | /**
104 | * Calculate a darker or brighter version of a certain color
105 | */
106 | public static Color createAlternatingColor(Color c, int amount) {
107 | int r = c.getRed();
108 | int g = c.getGreen();
109 | int b = c.getBlue();
110 |
111 |
112 | return new Color(r > 127 ? r - amount : r + amount,
113 | g > 127 ? g - amount : g + amount,
114 | b > 127 ? b - amount : b + amount);
115 | }
116 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/PercentageProgressListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 |
21 | package de.haukerehfeld.quakeinjector;
22 |
23 | /**
24 | * Report Percentages instaedd of absolute values
25 | */
26 | public class PercentageProgressListener implements ProgressListener {
27 | private final long size;
28 | private final ProgressListener progress;
29 |
30 | public PercentageProgressListener(long size, ProgressListener progress) {
31 | // if (size <= 0) {
32 | // throw new IllegalArgumentException("Size must be > 0: was " + size);
33 | // }
34 |
35 | this.progress = progress;
36 | this.size = size;
37 | }
38 |
39 | /**
40 | * tell the reporter of the size of uncompression
41 | */
42 | public void publish(long writtenBytes) {
43 | long per;
44 | if (size == 0) {
45 | per = 0;
46 | }
47 | else {
48 | per = Math.round(100 * writtenBytes / (double) size);
49 | }
50 | progress.publish(per);
51 | }
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/ProgressListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 |
21 | package de.haukerehfeld.quakeinjector;
22 |
23 | public interface ProgressListener {
24 | /**
25 | * tell the reporter how much got written
26 | */
27 | public void publish(long writtenBytes);
28 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/ProgressListenerInputStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 |
21 | package de.haukerehfeld.quakeinjector;
22 |
23 | import java.io.IOException;
24 | import java.io.InputStream;
25 |
26 | /**
27 | * report progress while reading InputStream
28 | *
29 | * Note that skipping doesn't add to the progress, and marking isn't supported
30 | */
31 | public class ProgressListenerInputStream extends InputStream {
32 | private final InputStream in;
33 | private final ProgressListener progress;
34 |
35 | public ProgressListenerInputStream(InputStream in, ProgressListener progress) {
36 | this.in = in;
37 | this.progress = progress;
38 | }
39 |
40 | @Override
41 | public int read() throws IOException {
42 | progress.publish(1);
43 | return in.read();
44 | }
45 |
46 | @Override
47 | public int read(byte[] b) throws IOException {
48 | return read(b, 0, b.length);
49 | }
50 |
51 | @Override
52 | public int read(byte[] b, int off, int len) throws IOException {
53 | int readcount = in.read(b, off, len);
54 |
55 | if (readcount > 0) {
56 | progress.publish(readcount);
57 | }
58 | return readcount;
59 | }
60 |
61 | @Override
62 | public long skip(long n) throws IOException {
63 | return in.skip(n);
64 | }
65 |
66 | @Override
67 | public int available() throws IOException {
68 | return in.available();
69 | }
70 |
71 | @Override
72 | public void mark(int readlimit) {
73 |
74 | }
75 |
76 | @Override
77 | public void reset() throws IOException {
78 | in.reset();
79 | }
80 |
81 | @Override
82 | public boolean markSupported() {
83 | return false;
84 | }
85 | }
86 |
87 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/RelativePath.java:
--------------------------------------------------------------------------------
1 | package de.haukerehfeld.quakeinjector;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | /**
9 | * this class provides functions used to generate a relative path
10 | * from two absolute paths
11 | * @see http://www.devx.com/tips/Tip/13737
12 | */
13 | public class RelativePath {
14 | /**
15 | * break a path down into individual elements and add to a list.
16 | * example : if a path is /a/b/c/d.txt, the breakdown will be [d.txt,c,b,a]
17 | * @param f input file
18 | * @return a List collection with the individual elements of the path in
19 | reverse order
20 | */
21 | private static List getPathList(File f) {
22 | List list = new ArrayList();
23 | File parent;
24 | try {
25 | parent = f.getCanonicalFile();
26 | while (parent != null) {
27 | list.add(parent);
28 | parent = parent.getParentFile();
29 | }
30 | }
31 | catch (IOException e) {
32 | e.printStackTrace();
33 | list = null;
34 | }
35 | return list;
36 | }
37 |
38 | private static int getFirstRootPosition(List file) {
39 | File[] roots = File.listRoots();
40 | for (File root: roots) {
41 | // System.out.println("Root: " + root);
42 | }
43 | int i = 0;
44 | done: while (i < file.size() - 1) {
45 | for (File root: roots) {
46 | if (file.get(i).equals(root)) {
47 | break done;
48 | }
49 | // System.out.println(root + " isn't " + file.get(i));
50 | }
51 | i++;
52 | }
53 | // System.out.println("Root is " + file.get(i));
54 | return i;
55 | }
56 | /**
57 | * figure out a string representing the relative path of
58 | * 'f' with respect to 'r'
59 | * @param home home path list
60 | * @param file path of file list
61 | */
62 | private static File matchPathLists(List home, List file) {
63 | if (file.size() <= 0) {
64 | return new File("");
65 | }
66 | if (home.size() <= 0) {
67 | return file.get(0);
68 | }
69 |
70 | // start at the beginning of the lists
71 | // iterate while both lists are equal
72 | final int homeLast = home.size() - 1;
73 | final int fileLast = file.size() - 1;
74 |
75 |
76 |
77 |
78 | int i = getFirstRootPosition(home);
79 | int j = getFirstRootPosition(file);
80 |
81 | //the root isn't identical (common on win32) - just return an absolute path
82 | if (!home.get(i).equals(file.get(j))) {
83 | // System.out.println(home);
84 | // System.out.println(file);
85 | // System.out.println(home.get(i) + " != " + file.get(j));
86 | return file.get(0);
87 | }
88 |
89 | // first eliminate common root
90 | while((i >= 0) && (j >= 0) && (home.get(i).equals(file.get(j)))) {
91 | i--;
92 | j--;
93 | }
94 |
95 | StringBuilder result = new StringBuilder();
96 | // for each remaining level in the home path, add a ..
97 | for(; i >= 0; i--) {
98 | result.append(".." + File.separator);
99 | }
100 |
101 | // for each level in the file path, add the path
102 | for(; j >= 1; j--) {
103 | result.append(file.get(j).getName() + File.separator);
104 | }
105 |
106 | if (j >= 0) {
107 | // file name doesn't need separator at the end
108 | result.append(file.get(j).getName());
109 | }
110 | return new File(result.toString());
111 | }
112 |
113 | /**
114 | * get relative path of File 'f' with respect to 'home' directory
115 | * example : home = /a/b/c
116 | * f = /a/d/e/x.txt
117 | * s = getRelativePath(home,f) = ../../d/e/x.txt
118 | * @param home base path, should be a directory, not a file, or it doesn't
119 | make sense
120 | * @param file file to generate path for
121 | * @return path from home to f as a string
122 | */
123 | public static File getRelativePath(File home, File file){
124 | List homelist;
125 | List filelist;
126 |
127 | //System.out.println("home: " + home);
128 | //System.out.println("file: " + file);
129 | homelist = getPathList(home);
130 | filelist = getPathList(file);
131 |
132 | File result = matchPathLists(homelist,filelist);
133 | //System.out.println("getName(): " + result.getName());
134 | //System.out.println("getToString(): " + result.toString());
135 |
136 | return result;
137 | }
138 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/Requirement.java:
--------------------------------------------------------------------------------
1 | package de.haukerehfeld.quakeinjector;
2 |
3 | import javax.swing.event.ChangeListener;
4 |
5 | /**
6 | * Base class for everything that might ever be referenced as a package.
7 | */
8 | public interface Requirement extends java.lang.Comparable {
9 | public void addChangeListener(ChangeListener l);
10 | public void removeChangeListener(ChangeListener l);
11 |
12 | /**
13 | * The name of the Requirement
14 | */
15 | public String getId();
16 | public boolean isInstalled();
17 | public void setInstalled(boolean installed);
18 |
19 | /**
20 | * A list of files this requirement installed
21 | */
22 | public PackageFileList getFileList();
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/RequirementList.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | import java.util.Collections;
23 | import java.util.HashMap;
24 | import java.util.Iterator;
25 | import java.util.List;
26 |
27 | import javax.swing.event.ChangeListener;
28 |
29 | public class RequirementList implements Iterable {
30 |
31 | private HashMap names = new HashMap();
32 | private List requirements;
33 |
34 | public RequirementList() {
35 | this.requirements = Collections.emptyList();
36 | }
37 | public RequirementList(List requirements) {
38 | setRequirements(requirements);
39 | }
40 |
41 | public void setRequirements(List requirements) {
42 | names.clear();
43 | for (int i = 0; i < requirements.size(); ++i) {
44 | names.put(requirements.get(i).getId(), i);
45 | }
46 | this.requirements = requirements;
47 |
48 | }
49 |
50 | public void setInstalled(PackageFileList l) {
51 | Requirement r = get(l.getId());
52 | if (r instanceof UnavailableRequirement) {
53 | System.err.println("Can't set installed on UnavailableRequirement " + l.getId());
54 | return;
55 | }
56 | r.setInstalled(true);
57 | if (r instanceof Package) {
58 | ((Package) r).setFileList(l);
59 | }
60 | }
61 |
62 | public Requirement get(int i) {
63 | return requirements.get(i);
64 | }
65 |
66 | public Requirement get(String id) {
67 | Integer i = names.get(id);
68 | if (i == null) {
69 | return new UnavailableRequirement(id);
70 | }
71 | return requirements.get(i);
72 | }
73 |
74 | public Iterator iterator() {
75 | return requirements.iterator();
76 | }
77 |
78 | public int size() {
79 | return requirements.size();
80 | }
81 |
82 | public int indexOf(Requirement r) {
83 | return requirements.indexOf(r);
84 | }
85 |
86 |
87 | /**
88 | * easily have change listeners
89 | */
90 | private ChangeListenerList listeners = new ChangeListenerList();
91 |
92 | public void addChangeListener(ChangeListener l) {
93 | listeners.addChangeListener(l);
94 | }
95 | public void removeChangeListener(ChangeListener l) {
96 | listeners.removeChangeListener(l);
97 | }
98 | public void notifyChangeListeners() {
99 | listeners.notifyChangeListeners(this);
100 | }
101 |
102 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/RuntimeExecutionException.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | /**
23 | * Like java.util.concurrent.ExecutionException , but at runtime
24 | *
25 | */
26 | public class RuntimeExecutionException extends RuntimeException {
27 | public RuntimeExecutionException(Throwable cause) {
28 | super(cause);
29 | }
30 |
31 | public RuntimeExecutionException(String msg, Throwable cause) {
32 | super(msg, cause);
33 | }
34 |
35 |
36 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/SaveInstalled.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | import java.io.BufferedInputStream;
23 | import java.io.BufferedOutputStream;
24 | import java.io.File;
25 | import java.io.FileInputStream;
26 | import java.io.FileOutputStream;
27 | import java.io.InputStream;
28 | import java.io.OutputStream;
29 | import java.util.List;
30 | import java.util.Map;
31 |
32 |
33 | public class SaveInstalled {
34 | private final File file;
35 |
36 | public SaveInstalled(File file) {
37 | this.file = file;
38 | }
39 |
40 | private OutputStream getOutputStream() throws java.io.IOException {
41 | if (!file.exists()) {
42 | file.createNewFile();
43 | }
44 | return new BufferedOutputStream(new FileOutputStream(file));
45 | }
46 |
47 | private InputStream getInputStream() throws java.io.IOException {
48 | return new BufferedInputStream(new FileInputStream(file));
49 | }
50 |
51 |
52 | public void write(Iterable extends Requirement> list) throws java.io.IOException {
53 | OutputStream out = getOutputStream();
54 | new InstalledPackageList().write(out, list);
55 | out.close();
56 | }
57 |
58 | public void write(Map> files) throws java.io.IOException {
59 | OutputStream out = getOutputStream();
60 | new InstalledPackageList().write(out, files);
61 | out.close();
62 | }
63 |
64 | public List read() throws java.io.IOException {
65 | InputStream in = getInputStream();
66 | List result = new InstalledPackageList().read(in);
67 | in.close();
68 | return result;
69 | }
70 |
71 | }
72 |
73 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/SortableRequirement.java:
--------------------------------------------------------------------------------
1 | package de.haukerehfeld.quakeinjector;
2 |
3 | /**
4 | * Requirements that can be sorted alphabetically by id
5 | */
6 | public abstract class SortableRequirement implements Requirement {
7 | private final String id;
8 | private boolean isInstalled = false;
9 |
10 |
11 | public SortableRequirement(String id) {
12 | this.id = id;
13 | }
14 |
15 | /**
16 | * get id
17 | */
18 | public String getId() { return id; }
19 |
20 | public boolean isInstalled() {
21 | return isInstalled;
22 | }
23 |
24 | public void setInstalled(boolean installed) {
25 | isInstalled = installed;
26 |
27 | notifyChangeListeners();
28 | }
29 |
30 | protected abstract void notifyChangeListeners();
31 |
32 | public int compareTo(Requirement o) {
33 | return getId().compareTo(((Requirement) o).getId());
34 | }
35 |
36 | @Override
37 | public String toString() {
38 | return getId();
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/SumProgressListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 |
21 | package de.haukerehfeld.quakeinjector;
22 |
23 | /**
24 | * Accumulate progress and report it
25 | */
26 | public class SumProgressListener implements ProgressListener {
27 | private final ProgressListener progress;
28 | private long currentSize = 0;
29 |
30 | public SumProgressListener(ProgressListener progress) {
31 | this.progress = progress;
32 | }
33 |
34 | /**
35 | * tell the reporter of the size of uncompression
36 | */
37 | public void publish(long writtenBytes) {
38 | currentSize += writtenBytes;
39 | progress.publish(currentSize);
40 | }
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/ThreadedGetter.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 |
23 |
24 | /**
25 | * Get something that a different thread creates. Will block until available.
26 | */
27 | public interface ThreadedGetter {
28 | public T get()
29 | throws java.util.concurrent.ExecutionException,
30 | java.lang.InterruptedException;
31 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/UnavailableRequirement.java:
--------------------------------------------------------------------------------
1 | package de.haukerehfeld.quakeinjector;
2 |
3 | import javax.swing.event.ChangeListener;
4 |
5 | /**
6 | * A requirement that doesn't have a package available and thus can't be installed (like the quake mission packs)
7 | *
8 | * Immutable.
9 | */
10 | public class UnavailableRequirement extends SortableRequirement implements Requirement {
11 | public UnavailableRequirement(String id) {
12 | super(id);
13 | }
14 | @Override
15 | public void addChangeListener(ChangeListener l) {}
16 | @Override
17 | protected void notifyChangeListeners() {}
18 |
19 | public PackageFileList getFileList() {
20 | return new PackageFileList(getId());
21 | }
22 | @Override
23 | public void removeChangeListener(ChangeListener l) {}
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/UninstallWorker.java:
--------------------------------------------------------------------------------
1 | package de.haukerehfeld.quakeinjector;
2 |
3 | import java.io.File;
4 | import java.io.FileInputStream;
5 | import java.io.BufferedInputStream;
6 | import java.util.Iterator;
7 |
8 | import javax.swing.SwingWorker;
9 |
10 |
11 | /**
12 | * Install maps in a worker thread
13 | * Init once and let swing start it - don't reuse
14 | */
15 | public class UninstallWorker extends SwingWorker {
16 | private String baseDirectory;
17 | private PackageFileList files;
18 |
19 | public UninstallWorker(PackageFileList files, String baseDirectory) {
20 | this.files = files;
21 | this.baseDirectory = baseDirectory;
22 | }
23 |
24 | @Override
25 | public Void doInBackground() {
26 | uninstall(files);
27 | return null;
28 | }
29 |
30 | public void uninstall(PackageFileList files) {
31 | //we rely on the descending order of paths in the file list here!
32 | //otherwise, dirs wouldn't get deleted last
33 | final int fileCount = files.size();
34 | int i = 1;
35 | Iterator it = files.descendingIterator();
36 | while (it.hasNext()) {
37 | FileInfo file = it.next();
38 |
39 |
40 | File f = new File(baseDirectory + File.separator + file.getName());
41 |
42 | long supposedCrc = file.getChecksum();
43 | String skipMsg = "Couldn't check CRC for " + f + ", deleting...";
44 | if (supposedCrc != 0) {
45 | try {
46 | BufferedInputStream in = new BufferedInputStream(new FileInputStream(f));
47 | long crc = Utils.getCrc32(in, null);
48 | in.close();
49 | if (crc != supposedCrc) {
50 | System.err.println("CRC for " + f + " didn't match, not deleting");
51 | continue;
52 | }
53 | }
54 | catch (java.io.IOException e) {
55 | System.err.println(skipMsg);
56 | }
57 | }
58 | else {
59 | System.err.println(skipMsg);
60 | }
61 |
62 | if (!f.delete()) {
63 | System.out.println("Couldn't delete " + f);
64 | }
65 | else {
66 | System.out.println("Deleted file " + f);
67 | }
68 | int progress = i * 100 / fileCount;
69 | setProgress(progress);
70 | i++;
71 | }
72 | }
73 |
74 | @Override
75 | public void done() {
76 | }
77 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/UpdateRequirementListWorker.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | //import java.awt.*;
23 | import java.util.List;
24 |
25 | import javax.swing.SwingWorker;
26 |
27 | public class UpdateRequirementListWorker extends SwingWorker {
28 | private final RequirementList requirementList;
29 | private final ThreadedGetter> requirementGetter;
30 | private final ThreadedGetter> installedGetter;
31 |
32 | private List requirement;
33 | private List installed;
34 |
35 |
36 | public UpdateRequirementListWorker(RequirementList requirementList,
37 | ThreadedGetter> requirements,
38 | ThreadedGetter> installed) {
39 | this.requirementList = requirementList;
40 | this.requirementGetter = requirements;
41 | this.installedGetter = installed;
42 | }
43 |
44 | @Override
45 | public Void doInBackground() {
46 | try {
47 |
48 | requirement = requirementGetter.get();
49 | installed = installedGetter.get();
50 | }
51 | catch (java.util.concurrent.ExecutionException e) {
52 | System.err.println(e.getMessage());
53 | e.printStackTrace();
54 | }
55 | catch (java.lang.InterruptedException e) {
56 | System.err.println("Couldn't wait for results!" + e.getMessage());
57 | e.printStackTrace();
58 |
59 | }
60 | return null;
61 | }
62 |
63 |
64 | @Override
65 | public void done() {
66 | synchronized (requirementList) {
67 | requirementList.setRequirements(requirement);
68 |
69 | for (PackageFileList l: installed) {
70 | requirementList.setInstalled(l);
71 | }
72 |
73 | requirementList.notifyChangeListeners();
74 |
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/Utils.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 |
21 | package de.haukerehfeld.quakeinjector;
22 |
23 |
24 | import java.io.BufferedOutputStream;
25 | import java.io.File;
26 | import java.io.FileOutputStream;
27 | import java.io.IOException;
28 | import java.io.InputStream;
29 | import java.io.OutputStream;
30 | import java.util.ArrayList;
31 | import java.util.Iterator;
32 | import java.util.List;
33 |
34 | import java.util.zip.CRC32;
35 |
36 | public class Utils {
37 | public static final int BUFFERSIZE = 4096;
38 |
39 | public static String join(final Iterable objs, final String delimiter) {
40 | Iterator iter = objs.iterator();
41 | if (!iter.hasNext())
42 | return "";
43 | StringBuffer buffer = new StringBuffer(String.valueOf(iter.next()));
44 | while (iter.hasNext()) {
45 | buffer.append(delimiter).append(String.valueOf(iter.next()));
46 | }
47 | return buffer.toString();
48 | }
49 |
50 | /**
51 | * Like File.mkdirs() this creates all parent directories of f, but returns them in a list
52 | */
53 | public static List mkdirs(File f) {
54 | ArrayList files = new ArrayList();
55 |
56 | if (f.isDirectory()) {
57 | files.add(f);
58 | }
59 |
60 | File parentDir = f.getParentFile();
61 | while (parentDir != null && !parentDir.exists()) {
62 | files.add(parentDir);
63 | parentDir = parentDir.getParentFile();
64 | }
65 |
66 | java.util.Collections.reverse(files);
67 |
68 | for (File dir: files) {
69 | System.out.println("Creating dir " + dir);
70 | dir.mkdir();
71 | }
72 |
73 | return files;
74 | }
75 |
76 | /**
77 | * Write stream to file in chunks of 2048 bytes
78 | *
79 | * doesn't do any checks.
80 | */
81 | public static long writeFile(InputStream in, File file, ProgressListener progress)
82 | throws IOException {
83 | return writeFile(in, file, 2048, progress);
84 | }
85 |
86 | /**
87 | * Write stream to file
88 | * @return crc32 checksum
89 | */
90 | public static long writeFile(final InputStream in,
91 | final File file,
92 | final int BUFFERSIZE,
93 | final ProgressListener progress) throws IOException {
94 | final BufferedOutputStream dest = new BufferedOutputStream(new FileOutputStream(file),
95 | BUFFERSIZE);
96 |
97 | long crc = copy(in, dest, BUFFERSIZE, progress);
98 | dest.close();
99 |
100 | return crc;
101 | }
102 |
103 | public static long copy(final InputStream in,
104 | final OutputStream out,
105 | final int BUFFERSIZE,
106 | final ProgressListener progress) throws IOException {
107 | byte data[] = new byte[BUFFERSIZE];
108 | CRC32 crc = new CRC32();
109 |
110 | int readcount;
111 | while ((readcount = in.read(data, 0, BUFFERSIZE)) != -1) {
112 | if (progress != null) {
113 | progress.publish(readcount);
114 | }
115 | out.write(data, 0, readcount);
116 | crc.update(data, 0, readcount);
117 | }
118 | out.flush();
119 | return crc.getValue();
120 | }
121 |
122 |
123 | public static long getCrc32(final InputStream in, final ProgressListener progress) throws IOException {
124 | return copy(in, new NoOutputStream(), BUFFERSIZE, progress);
125 | }
126 |
127 | public static class NoOutputStream extends OutputStream {
128 | public void write(int b) {}
129 | public void write(byte[] b) {}
130 | public void write(byte[] b, int off, int len) {}
131 | }
132 |
133 |
134 | /**
135 | Check if files can indeed be written inside a certain directory
136 |
137 | Tries to write a temp file in a dir.
138 | @param directory The directory to test
139 | */
140 | public static boolean canWriteToDirectory(File directory) {
141 | try {
142 | File tmp = File.createTempFile("writeTest", null, directory);
143 | tmp.delete();
144 | }
145 | catch (IOException e) {
146 | System.out.println(e);
147 | return false;
148 | }
149 | return true;
150 | }
151 |
152 | public static javax.swing.ImageIcon createImageIcon(String path, String description) throws java.io.IOException {
153 | java.net.URL imgURL = Utils.class.getResource(path);
154 | if (imgURL != null) {
155 | return new javax.swing.ImageIcon(imgURL, description);
156 | } else {
157 | throw new java.io.IOException("Couldn't find file: " + path);
158 | }
159 | }
160 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/XmlUtils.java:
--------------------------------------------------------------------------------
1 | package de.haukerehfeld.quakeinjector;
2 |
3 | import java.io.InputStream;
4 | import java.util.Iterator;
5 |
6 | import javax.xml.parsers.DocumentBuilder;
7 | import javax.xml.parsers.DocumentBuilderFactory;
8 |
9 | import org.w3c.dom.Document;
10 | import org.w3c.dom.Element;
11 | import org.w3c.dom.Node;
12 | import org.w3c.dom.NodeList;
13 |
14 | public class XmlUtils {
15 | /**
16 | * get the first element in the parent element that's named name or null if no such element exists
17 | */
18 | public static Element getFirstElement(Element parent, String name) {
19 | NodeList list = parent.getElementsByTagName(name);
20 |
21 | Node node = list.item(0);
22 | if (node == null) {
23 | //throw new RuntimeException("Malformed XML: No such node: " + name);
24 | return null;
25 | }
26 |
27 | if (!isElement(node)) {
28 | throw new RuntimeException("XML Parsing error: " + name + " is not an Element");
29 | }
30 |
31 | return (Element) node;
32 | }
33 |
34 | public static Document getDocument(InputStream xml)
35 | throws java.io.IOException,
36 | org.xml.sax.SAXException {
37 | DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
38 | dbf.setIgnoringElementContentWhitespace(true);
39 | DocumentBuilder db;
40 | try {
41 | db = dbf.newDocumentBuilder();
42 | }
43 | catch (javax.xml.parsers.ParserConfigurationException e) {
44 | throw new RuntimeException("Parser misconfiguration");
45 | }
46 |
47 | Document doc = db.parse(xml);
48 | return doc;
49 | }
50 |
51 |
52 | public static java.lang.Iterable iterate(NodeList list) {
53 | return new NodeListIterator(list);
54 | }
55 |
56 | public static class NodeListIterator implements Iterator,
57 | java.lang.Iterable {
58 | private NodeList list;
59 | private int i = 0;
60 |
61 | public NodeListIterator(NodeList list) {
62 | this.list = list;
63 | }
64 |
65 | public Node next() {
66 | i++;
67 |
68 | return list.item(i);
69 | }
70 |
71 | public boolean hasNext() {
72 | return i + 1 < list.getLength();
73 | }
74 |
75 | public void remove() {
76 | throw new java.lang.UnsupportedOperationException();
77 | }
78 |
79 | public Iterator iterator() {
80 | return this;
81 | }
82 | }
83 |
84 | public static boolean isElement(Node n) {
85 | return (n.getNodeType() == Node.ELEMENT_NODE);
86 | }
87 |
88 | /**
89 | * Gets the String value of the node.
90 | If the node does not contain text then an empty String is returned
91 | * @param node the node of interest
92 | * @return the value of that node
93 | */
94 | public static String getTextForNode(Node node)
95 | {
96 | NodeList children = node.getChildNodes();
97 | if (children == null) {
98 | return "";
99 | }
100 |
101 | for (int i = 0; i < children.getLength(); i++) {
102 | Node childNode = children.item(i);
103 | if ((childNode.getNodeType() == Node.TEXT_NODE)
104 | || (childNode.getNodeType() == Node.CDATA_SECTION_NODE)) {
105 | return childNode.getNodeValue();
106 | }
107 | }
108 |
109 | return "";
110 | }
111 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/ZipInspect.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector;
21 |
22 | import java.io.BufferedOutputStream;
23 | import java.io.BufferedReader;
24 | import java.io.BufferedWriter;
25 | import java.io.Console;
26 | import java.io.File;
27 | import java.io.FileInputStream;
28 | import java.io.FileOutputStream;
29 | import java.io.FileReader;
30 | import java.io.FileWriter;
31 | import java.util.AbstractMap;
32 | import java.util.ArrayList;
33 | import java.util.HashMap;
34 | import java.util.List;
35 | import java.util.Map;
36 | import java.util.SortedMap;
37 | import java.util.TreeMap;
38 | import java.util.zip.ZipEntry;
39 |
40 | /**
41 | * Create an xml of all the files in the zips
42 | */
43 | public class ZipInspect {
44 | private final static String file = "zipFiles.xml";
45 | private final static String oldSelectionsFile = "essentialfiles.cfg";
46 |
47 | public static void main(String[] args) {
48 | Console con = System.console();
49 | if (con == null) {
50 | System.err.println("Don't start from ant, it doesn't support an interactive console!");
51 | System.exit(1);
52 | }
53 |
54 | if (args.length < 1) {
55 | System.err.println("First parameter need's to be a valid directory!");
56 | System.exit(1);
57 | }
58 | String parentDir = args[0];
59 |
60 | if (!(new File(parentDir).exists())) {
61 | System.err.println("First parameter need's to be a valid directory!");
62 | System.exit(1);
63 | }
64 |
65 | Configuration config = new Configuration(QuakeInjector.configFile);
66 |
67 | List requirements = null;
68 | {
69 | final PackageDatabaseParserWorker requirementsParser
70 | = new PackageDatabaseParserWorker(config.RepositoryDatabasePath.get());
71 | requirementsParser.execute();
72 |
73 |
74 | try {
75 | requirements = requirementsParser.get();
76 | }
77 | catch (Exception e) {
78 | System.err.println("Couldn't get packages " + e);
79 | e.printStackTrace();
80 | System.exit(1);
81 | }
82 | }
83 | java.util.Collections.sort(requirements);
84 |
85 | Map> packageFiles = new TreeMap>();
86 | SortedMap>> duplicateFiles
87 | = new TreeMap>>();
88 |
89 | for (Requirement r: requirements) {
90 | //only check where package exists
91 | if (!(r instanceof Package)) {
92 | continue;
93 | }
94 |
95 | Package p = (Package) r;
96 | p.setInstalled(true);
97 |
98 | File f = new File(parentDir + File.separator + r.getId() + ".zip");
99 | if (!f.exists()) {
100 | System.out.println("WARNING: " + f + " doesn't exist!");
101 | continue;
102 | }
103 | System.out.println(f);
104 |
105 | try {
106 | FileInputStream in = new FileInputStream(f);
107 | InspectZipWorker inspector = new InspectZipWorker(in);
108 | inspector.execute();
109 |
110 | final List entries = inspector.get();
111 |
112 | final PackageFileList zipFiles = new PackageFileList(p.getId());
113 | String dir = p.getRelativeBaseDir();
114 |
115 | for (ZipEntry e: entries) {
116 | String file = "";
117 | if (dir != null) {
118 | file = dir;
119 | }
120 | file += e.getName();
121 |
122 | FileInfo info = new FileInfo(file, e.getCrc());
123 | zipFiles.add(info);
124 |
125 | List> dupMaps =
126 | duplicateFiles.get(file.toLowerCase());
127 | if (dupMaps == null) {
128 | dupMaps = new ArrayList>();
129 | duplicateFiles.put(file.toLowerCase(), dupMaps);
130 | }
131 | dupMaps.add(new AbstractMap.SimpleEntry(p, info));
132 |
133 | }
134 | p.setFileList(zipFiles);
135 | packageFiles.put(p, zipFiles);
136 | }
137 | catch (Exception e) {
138 | e.printStackTrace();
139 | }
140 | }
141 |
142 | Map oldSelections = new HashMap();
143 | if (new File(oldSelectionsFile).exists()) {
144 | //load old selections
145 | try {
146 | BufferedReader in = new BufferedReader(new FileReader(oldSelectionsFile));
147 | String line;
148 | while ((line = in.readLine()) != null) {
149 | String[] l = line.split(",");
150 | oldSelections.put(l[0], Boolean.parseBoolean(l[1]));
151 | }
152 | in.close();
153 | } catch (java.io.IOException e) {
154 | System.err.println("Couldn't read old selections file");
155 | }
156 | }
157 |
158 | StringBuilder selectionsFile = new StringBuilder();
159 |
160 | for (String file: duplicateFiles.keySet()) {
161 |
162 | List> dups = duplicateFiles.get(file);
163 | int count = dups.size();
164 | if (count > 1) {
165 | List packages = new ArrayList();
166 | boolean crcDiffers = false;
167 | long crc = -1;
168 | for (Map.Entry e: dups) {
169 | if (crc != -1 && crc != e.getValue().getChecksum()) {
170 | crcDiffers = true;
171 | }
172 | crc = e.getValue().getChecksum();
173 |
174 | packages.add(e.getKey().getId() + " (crc: " + crc + ")");
175 | }
176 |
177 | boolean essential = true;
178 | if (!crcDiffers && crc == 0) {
179 | System.out.println(file
180 | + " has duplicates, but all with crc == 0,"
181 | + " setting to inessential");
182 | essential = false;
183 | }
184 | else if (oldSelections.get(file) != null) {
185 | essential = oldSelections.get(file);
186 | System.out.println(file
187 | + " has duplicates, but was previously declared:"
188 | + " essential = " + essential);
189 | }
190 | else {
191 | System.out.println(file
192 | + " has "
193 | + (crcDiffers ? " differing CRC " : " equal ")
194 | + "duplicates in "
195 | + Utils.join(packages, ", "));
196 |
197 | System.out.println("Is this an essential file? (No: n + RETURN, Yes: RETURN)");
198 | String yes = con.readLine();
199 | if (yes != null && yes.equals("n")) {
200 | essential = false;
201 | }
202 | }
203 |
204 | for (Map.Entry e: dups) {
205 | e.getValue().setEssential(essential);
206 | }
207 |
208 | selectionsFile.append(file + "," + essential + "\n");
209 | }
210 | }
211 |
212 | //write old selections
213 | try {
214 | BufferedWriter out = new BufferedWriter(new FileWriter(oldSelectionsFile));
215 | out.write(selectionsFile.toString());
216 | out.close();
217 | }
218 | catch (java.io.IOException e) {
219 | System.err.println("Couldn't write selections to outfile! " + e);
220 | }
221 |
222 | try {
223 | new InstalledPackageList().write(new BufferedOutputStream(new FileOutputStream(file)),
224 | packageFiles.keySet());
225 | }
226 | catch (Exception e) {
227 | e.printStackTrace();
228 | }
229 | }
230 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/database/InstalledMapsParser.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 |
21 | package de.haukerehfeld.quakeinjector.database;
22 |
23 | import java.io.InputStream;
24 | import java.util.Collections;
25 | import java.util.List;
26 |
27 | import de.haukerehfeld.quakeinjector.InstalledPackageList;
28 | import de.haukerehfeld.quakeinjector.PackageFileList;
29 |
30 |
31 | /**
32 | * Thread worker to parse the installed maps in background
33 | */
34 | public class InstalledMapsParser {
35 | public List parse(final InputStream in) {
36 | List files;
37 | try {
38 | files = new InstalledPackageList().read(in);
39 | }
40 | catch (java.io.FileNotFoundException e) {
41 | System.out.println("Notice: installed maps file doesn't exist yet,"
42 | + " no maps installed? " + e);
43 | files = Collections.emptyList();
44 | }
45 | catch (java.io.IOException e) {
46 | System.err.println("Error: installed maps file couldn't be loaded: " + e);
47 | e.printStackTrace();
48 | files = Collections.emptyList();
49 | }
50 | return files;
51 | }
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/gui/BrowserLauncher.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2014 Eric Wasylishen
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector.gui;
21 |
22 | import java.awt.Desktop;
23 | import java.net.URI;
24 |
25 | public class BrowserLauncher {
26 | private static edu.stanford.ejalbert.BrowserLauncher fallback = null;
27 |
28 | public static void openURL(String url) {
29 | try {
30 | Desktop.getDesktop().browse(URI.create(url));
31 | } catch (Exception e) {
32 | System.err.println("Error calling Desktop#browse(URI): " + e.getMessage());
33 |
34 | if (fallback == null) {
35 | try {
36 | fallback = new edu.stanford.ejalbert.BrowserLauncher();
37 | } catch (Exception e2) {
38 | System.err.println("Couldn't init browserlauncher: " + e2.getMessage());
39 | }
40 | }
41 |
42 | if (fallback != null) {
43 | fallback.openURLinBrowser(url);
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/gui/ClosePanel.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector.gui;
21 |
22 | import java.awt.GridLayout;
23 | import java.awt.event.ActionEvent;
24 | import java.awt.event.ActionListener;
25 |
26 | import javax.swing.JButton;
27 | import javax.swing.JDialog;
28 | import javax.swing.JPanel;
29 |
30 | /**
31 | * The typical okay/cancel area
32 | */
33 | public class ClosePanel extends JPanel {
34 | public ClosePanel(final JDialog dialog, final ActionListener action) {
35 | super();
36 | setLayout(new GridLayout(0,2));
37 |
38 | add(makeCloseButton(dialog, "Okay", action));
39 | add(makeCloseButton(dialog, "Cancel"));
40 | }
41 |
42 | public static JButton makeCloseButton(final JDialog dialog,
43 | final String text) {
44 | return makeCloseButton(dialog, text, null);
45 | }
46 |
47 | /**
48 | * Make a button that closes the dialog and executes another action.
49 | *
50 | * You still have to add it to the frame.
51 | *
52 | * Action may be null.
53 | */
54 | public static JButton makeCloseButton(final JDialog dialog,
55 | final String text,
56 | final ActionListener action) {
57 | JButton okay = new JButton(text);
58 | okay.addActionListener(new ActionListener() {
59 | public void actionPerformed(ActionEvent e) {
60 | if (action != null) {
61 | action.actionPerformed(e);
62 | }
63 | dialog.setVisible(false);
64 | dialog.dispose();
65 | }
66 | });
67 | return okay;
68 | }
69 |
70 |
71 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/gui/ErrorEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector.gui;
21 |
22 | public interface ErrorEvent {
23 | public Object getSource();
24 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/gui/ErrorListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector.gui;
21 |
22 | public interface ErrorListener {
23 | public void errorOccured(ErrorEvent e);
24 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/gui/JPathPanel.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector.gui;
21 |
22 | import java.awt.event.ActionEvent;
23 | import java.awt.event.ActionListener;
24 | import java.io.File;
25 | import java.util.ArrayList;
26 |
27 | import javax.swing.BoxLayout;
28 | import javax.swing.InputVerifier;
29 | import javax.swing.JButton;
30 | import javax.swing.JComponent;
31 | import javax.swing.JFileChooser;
32 | import javax.swing.JLabel;
33 | import javax.swing.JPanel;
34 | import javax.swing.JTextField;
35 | import javax.swing.event.ChangeListener;
36 | import javax.swing.event.DocumentEvent;
37 | import javax.swing.event.DocumentListener;
38 |
39 | import de.haukerehfeld.quakeinjector.ChangeListenerList;
40 | import de.haukerehfeld.quakeinjector.RelativePath;
41 | import de.haukerehfeld.quakeinjector.Utils;
42 |
43 | /**
44 | * A Panel to input paths
45 | */
46 | public class JPathPanel extends JPanel {
47 | private final ArrayList errorListeners = new ArrayList();
48 | private final ChangeListenerList changeListeners = new ChangeListenerList();
49 |
50 | private final static int inputLength = 32;
51 |
52 | private File basePath;
53 |
54 | private final JTextField path;
55 | private final JLabel errorLabel;
56 | private final JButton fileChooserButton;
57 | private final JFileChooser chooser;
58 |
59 |
60 | private final Verifier check;
61 |
62 | /**
63 | * If the saved path is absolute although we have a basepath - happens on windows when the basepath is
64 | * on a different drive
65 | */
66 | private boolean absolute = false;
67 |
68 | /**
69 | * @param filesAndOrDirectories what kind of files can be selected with the filechooser:
70 | * one of JFileChooser.DIRECTORIES_ONLY,
71 | * JFileChooser.FILES_AND_DIRECTORIES,
72 | * JFileChooser.FILES_ONLY
73 | */
74 | public JPathPanel(Verifier check, File defaultPath, int filesAndOrDirectories) {
75 | this(check, defaultPath, null, filesAndOrDirectories);
76 | }
77 |
78 | /**
79 | * @param filesAndOrDirectories what kind of files can be selected with the filechooser:
80 | * one of JFileChooser.DIRECTORIES_ONLY,
81 | * JFileChooser.FILES_AND_DIRECTORIES,
82 | * JFileChooser.FILES_ONLY
83 | */
84 | public JPathPanel(Verifier check,
85 | File defaultPath,
86 | File basePath,
87 | int filesAndOrDirectories) {
88 | this.check = check;
89 | this.basePath = basePath;
90 |
91 | if (defaultPath == null) {
92 | defaultPath = new File("");
93 | }
94 |
95 |
96 | setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
97 |
98 |
99 |
100 | absolute = defaultPath.isAbsolute();
101 |
102 | this.path = new JTextField(defaultPath.toString(), inputLength);
103 | PathVerifier verifier = new PathVerifier();
104 | path.setInputVerifier(verifier);
105 | path.getDocument().addDocumentListener(verifier);
106 | add(path);
107 |
108 | this.errorLabel = new JLabel();
109 | add(errorLabel);
110 |
111 | this.chooser = new JFileChooser(getPath());
112 | chooser.setFileSelectionMode(filesAndOrDirectories);
113 |
114 | this.fileChooserButton = new JButton("Select");
115 | fileChooserButton.addActionListener(new ActionListener() {
116 | public void actionPerformed(ActionEvent e) {
117 | int returnVal = chooser.showOpenDialog(JPathPanel.this);
118 |
119 | if (returnVal == JFileChooser.APPROVE_OPTION) {
120 | File file = chooser.getSelectedFile();
121 |
122 | setPath(file);
123 | }
124 | }
125 | });
126 | add(fileChooserButton);
127 | }
128 |
129 | /**
130 | * Just checks if the current path is valid without notifying listeners
131 | */
132 | public boolean verifies() {
133 | return check();
134 | }
135 |
136 | /**
137 | * Check if current path is valid and notify listeners
138 | */
139 | public boolean verify() {
140 | if (!check()) {
141 | notifyErrorListeners();
142 | return false;
143 | }
144 | else {
145 | chooser.setCurrentDirectory(getPath());
146 | notifyChangeListeners();
147 | return true;
148 | }
149 | }
150 |
151 |
152 | private boolean check() {
153 | File f = getPath();
154 | //System.out.println(f);
155 | errorLabel.setText(check.errorMessage(f));
156 | return this.check.verify(f);
157 | }
158 |
159 | public void setBasePath(File basePath) {
160 | File oldFile = getPath();
161 | boolean verifies = verifies();
162 | this.basePath = basePath;
163 | //System.out.println("Changing basePath: " + oldFile + " to " + basePath);
164 | if (verifies) {
165 | setPath(oldFile);
166 | }
167 | //put this above the if (verifies) to change chooser to the new basedir
168 | this.chooser.setCurrentDirectory(getPath());
169 | verify();
170 | }
171 |
172 | public void setPath(String path) {
173 | setPath(new File(path));
174 | }
175 |
176 | public void setPath(File path) {
177 | String pathString;
178 | if (basePath != null) {
179 | File relative = RelativePath.getRelativePath(basePath, path);
180 | //may return absolute path if no relative path possible
181 | absolute = relative.isAbsolute();
182 | pathString = relative.toString();
183 | }
184 | else {
185 | pathString = path.getAbsolutePath();
186 | }
187 |
188 | this.path.setText(pathString);
189 | }
190 |
191 | /**
192 | * get a file representing what this pathpanel is pointing to
193 | */
194 | public File getPath() {
195 | /*
196 | * Build a file object from - if set - the basepath and the textfield content
197 | */
198 | String path = this.path.getText();
199 | if (path == null) {
200 | path = "";
201 | }
202 |
203 | File file;
204 | if (basePath != null && !absolute) {
205 | file = new File(basePath.getAbsolutePath() + File.separator + path);
206 | }
207 | else {
208 | file = new File(path);
209 | }
210 | return file;
211 | }
212 |
213 |
214 | public void addErrorListener(ErrorListener e) {
215 | errorListeners.add(e);
216 | }
217 |
218 | private void notifyErrorListeners() {
219 | ErrorEvent e = new SimpleErrorEvent(this);
220 | for (ErrorListener l: errorListeners) {
221 | l.errorOccured(e);
222 | }
223 | }
224 |
225 | public void addChangeListener(ChangeListener l) {
226 | changeListeners.addChangeListener(l);
227 | }
228 |
229 | private void notifyChangeListeners() {
230 | changeListeners.notifyChangeListeners(this);
231 | }
232 |
233 | /**
234 | * Hack: Because i can't call verify() from the inner class that has @Override verify(Stuff s);
235 | */
236 | private boolean verify_() {
237 | return verify();
238 | }
239 |
240 |
241 |
242 | public interface Verifier {
243 | public boolean verify(File file);
244 | public String errorMessage(File file);
245 | }
246 |
247 | public static class WritableDirectoryVerifier implements Verifier {
248 | public boolean verify(File f) {
249 | return (f.exists()
250 | && f.isDirectory()
251 | && f.canRead()
252 | && Utils.canWriteToDirectory(f));
253 | }
254 | public String errorMessage(File f) {
255 | if (!f.exists()) {
256 | return "Doesn't exist!";
257 | }
258 | else if (!f.isDirectory()) {
259 | return "Is not a directory!";
260 | }
261 | else if (!Utils.canWriteToDirectory(f)) {
262 | return "Cannot be written to!";
263 | }
264 | return null;
265 | }
266 | }
267 |
268 |
269 | private class PathVerifier extends InputVerifier implements DocumentListener {
270 | @Override
271 | public void insertUpdate(DocumentEvent e) {
272 | verify_();
273 | }
274 | @Override
275 | public void removeUpdate(DocumentEvent e) {
276 | verify_();
277 | }
278 | @Override
279 | public void changedUpdate(DocumentEvent e) {
280 | verify_();
281 | }
282 | @Override
283 | public boolean verify(JComponent input) {
284 | return verify_();
285 | }
286 | @Override
287 | public boolean shouldYieldFocus(JComponent input) {
288 | verify_();
289 | return true;
290 | }
291 | }
292 |
293 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/gui/LabelFieldPanel.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector.gui;
21 |
22 | import javax.swing.BoxLayout;
23 | import javax.swing.JComponent;
24 | import javax.swing.JLabel;
25 | import javax.swing.JPanel;
26 | import javax.swing.SwingConstants;
27 |
28 | /**
29 | * A Panel with a label and a field
30 | */
31 | public class LabelFieldPanel extends JPanel {
32 | public LabelFieldPanel(String labelText, JComponent field) {
33 | setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
34 |
35 | JLabel label = new JLabel(labelText, SwingConstants.RIGHT);
36 |
37 | label.setLabelFor(field);
38 | add(label);
39 | add(field);
40 | }
41 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/gui/LookAndFeelDefaults.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector.gui;
21 |
22 | import javax.swing.BorderFactory;
23 | import javax.swing.JPanel;
24 | import javax.swing.border.Border;
25 |
26 | public class LookAndFeelDefaults extends JPanel {
27 | public static final int FRAMEPADDING = 7;
28 |
29 | public static final Border PADDINGBORDER = BorderFactory.createEmptyBorder(FRAMEPADDING,
30 | FRAMEPADDING,
31 | 0,
32 | FRAMEPADDING);
33 |
34 | public static final int DIALOGDESCRIPTIONMARGIN = 7;
35 |
36 | public static final Border DIALOGDESCRIPTIONBORDER = BorderFactory.createEmptyBorder(DIALOGDESCRIPTIONMARGIN,
37 | 0,
38 | DIALOGDESCRIPTIONMARGIN,
39 | 0);
40 |
41 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/gui/OkayCancelApplyPanel.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector.gui;
21 |
22 | import java.awt.GridBagConstraints;
23 | import java.awt.GridBagLayout;
24 | import java.awt.Insets;
25 | import java.util.ArrayList;
26 | import java.util.List;
27 |
28 | import javax.swing.Box;
29 | import javax.swing.JButton;
30 | import javax.swing.JComponent;
31 | import javax.swing.JPanel;
32 |
33 | public class OkayCancelApplyPanel extends JPanel {
34 | private static final Insets LEFTBORDER = new Insets(LookAndFeelDefaults.FRAMEPADDING,
35 | LookAndFeelDefaults.FRAMEPADDING,
36 | LookAndFeelDefaults.FRAMEPADDING,
37 | LookAndFeelDefaults.FRAMEPADDING);
38 |
39 | private static final Insets OTHERBORDER = new Insets(LookAndFeelDefaults.FRAMEPADDING,
40 | 0,
41 | LookAndFeelDefaults.FRAMEPADDING,
42 | LookAndFeelDefaults.FRAMEPADDING);
43 |
44 | private final JButton okay;
45 | private final JButton cancel;
46 | private final JButton apply;
47 |
48 | public OkayCancelApplyPanel(JButton okay, JButton cancel, JButton apply, boolean useApply) {
49 | setLayout(new GridBagLayout());
50 |
51 | this.okay = okay;
52 | this.cancel = cancel;
53 | this.apply = apply;
54 |
55 |
56 | List components = new ArrayList(3);
57 |
58 | components.add(okay);
59 |
60 | if (cancel != null) {
61 | components.add(cancel);
62 | }
63 |
64 | if (apply != null) {
65 | apply.setEnabled(false);
66 | components.add(apply);
67 | }
68 |
69 | OkayCancelApplyPanel.addRow(this, 0, components);
70 | }
71 |
72 | public void setApplyEnabled(boolean enabled) {
73 | this.apply.setEnabled(enabled);
74 | }
75 |
76 | /**
77 | * Add some components right aligned to a gridbaglayout container
78 | * at a specific row, with proper borders.
79 | */
80 | public static void addRow(final java.awt.Container container,
81 | final int row,
82 | final List components) {
83 | //right aligned
84 | container.add(Box.createHorizontalGlue(), new LeftConstraints());
85 |
86 | int col = 1;
87 | for (JComponent c: components) {
88 | final int col_ = col;
89 | container.add(c, new RightConstraints() {{ gridx = col_; gridy = row; }});
90 | col++;
91 | }
92 | }
93 |
94 | static class LeftConstraints extends GridBagConstraints {{
95 | insets = LEFTBORDER;
96 | gridx = 0;
97 | weightx = 1;
98 | }}
99 |
100 | static class RightConstraints extends GridBagConstraints {{
101 | insets = OTHERBORDER;
102 | anchor = LINE_END;
103 | fill = NONE;
104 | }}
105 |
106 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/gui/ProgressListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector.gui;
21 |
22 | /**
23 | * A class that gets called everytime something that progresses is able to
24 | */
25 | public interface ProgressListener {
26 | /**
27 | * @param progress Progress from 0 (did nothing) to 1 (completed)
28 | */
29 | public void reportProgress(float progress);
30 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/gui/ProgressPopup.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector.gui;
21 |
22 | //import java.awt.*;
23 | import java.awt.GridBagConstraints;
24 | import java.awt.GridBagLayout;
25 | import java.awt.event.ActionListener;
26 |
27 | import javax.swing.JButton;
28 | import javax.swing.JDialog;
29 | import javax.swing.JFrame;
30 | import javax.swing.JProgressBar;
31 |
32 | public class ProgressPopup extends JDialog {
33 | private JProgressBar progress;
34 | private JButton cancelButton;
35 | private String description;
36 |
37 | public ProgressPopup(String description, ActionListener cancel, JFrame frame) {
38 | super(frame, description, true);
39 | setLocationRelativeTo(frame);
40 |
41 | this.description = description;
42 |
43 | setLayout(new GridBagLayout());
44 |
45 | progress = new JProgressBar();
46 | progress.setString(description);
47 | progress.setValue(0);
48 | progress.setIndeterminate(true);
49 | progress.setStringPainted(true);
50 |
51 | add(progress, new GridBagConstraints() {{
52 | anchor = CENTER;
53 | gridx = 0;
54 | fill = BOTH;
55 | weightx = 1;
56 | }});
57 |
58 | JButton cancelButton;
59 | cancelButton = new JButton("Cancel");
60 | cancelButton.addActionListener(cancel);
61 | add(cancelButton, new GridBagConstraints() {{
62 | anchor = CENTER;
63 | fill = BOTH;
64 | gridy = 1;
65 | }});
66 | }
67 |
68 | /**
69 | * Change progress
70 | *
71 | * @param percent percent [0, 100]
72 | */
73 | public void setProgress(int percent) {
74 | progress.setIndeterminate(false);
75 | progress.setValue(percent);
76 | progress.setString(progressString(description, percent));
77 |
78 | }
79 |
80 | public void close() {
81 | setVisible(false);
82 | dispose();
83 | }
84 |
85 | public static String progressString(String description, String status) {
86 | return description + ": " + status;
87 | }
88 |
89 | public static String progressString(String description, int progress) {
90 | return progressString(description, progress + "%");
91 | }
92 |
93 | }
94 |
95 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/gui/ScrollablePanel.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector.gui;
21 |
22 | import java.awt.Dimension;
23 | import java.awt.FlowLayout;
24 | import java.awt.GridBagConstraints;
25 | import java.awt.GridBagLayout;
26 | import java.text.DateFormat;
27 | import java.text.SimpleDateFormat;
28 | import java.util.Date;
29 | import java.util.List;
30 | import java.util.ArrayList;
31 | import java.util.TimeZone;
32 |
33 | import javax.swing.JEditorPane;
34 | import javax.swing.text.html.HTMLEditorKit;
35 | import javax.swing.text.html.StyleSheet;
36 | import javax.swing.text.Style;
37 | import java.util.Enumeration;
38 |
39 |
40 | import javax.swing.JLabel;
41 | import javax.swing.JPanel;
42 | import javax.swing.JScrollPane;
43 | import javax.swing.SwingConstants;
44 | import javax.swing.event.ChangeEvent;
45 | import javax.swing.event.ChangeListener;
46 |
47 | import javax.swing.ImageIcon;
48 | import javax.swing.border.EmptyBorder;
49 | import java.net.URL;
50 |
51 | import javax.swing.Scrollable;
52 | import java.awt.Rectangle;
53 |
54 |
55 | import javax.swing.event.HyperlinkListener;
56 | import javax.swing.event.HyperlinkEvent;
57 |
58 | import javax.swing.SwingWorker;
59 | import java.util.concurrent.Future;
60 |
61 | /**
62 | * JPanel that supports Scrollable
63 | * @see javax.swing.Scrollable
64 | */
65 | public class ScrollablePanel extends JPanel implements Scrollable {
66 | private int scrollUnitIncrement;
67 | private int scrollBlockincrement;
68 | private boolean tracksWidth;
69 | private boolean tracksHeight;
70 |
71 | public ScrollablePanel(int scrollUnitIncrement,
72 | int scrollBlockincrement,
73 | boolean tracksWidth,
74 | boolean tracksHeight) {
75 | this.scrollUnitIncrement = scrollUnitIncrement;
76 | this.scrollBlockincrement = scrollBlockincrement;
77 | this.tracksWidth = tracksWidth;
78 | this.tracksHeight = tracksHeight;
79 | }
80 |
81 | /**
82 | * Defaults for viewport size tracking: track width, but not height
83 | */
84 | public ScrollablePanel(int scrollUnitIncrement,
85 | int scrollBlockincrement) {
86 | this(scrollUnitIncrement, scrollBlockincrement, true, false);
87 | }
88 |
89 |
90 | @Override
91 | public Dimension getPreferredScrollableViewportSize() {
92 | return getPreferredSize();
93 | }
94 |
95 | @Override
96 | public int getScrollableUnitIncrement(Rectangle visibleRect,
97 | int orientation,
98 | int direction) {
99 | return scrollUnitIncrement;
100 | }
101 |
102 | @Override
103 | public int getScrollableBlockIncrement(Rectangle visibleRect,
104 | int orientation,
105 | int direction) {
106 | return scrollBlockincrement;
107 | }
108 |
109 | @Override
110 | public boolean getScrollableTracksViewportWidth() { return tracksWidth; }
111 | @Override
112 | public boolean getScrollableTracksViewportHeight() { return tracksHeight; }
113 | }
114 |
115 |
116 |
117 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/gui/SimpleErrorEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector.gui;
21 |
22 | public class SimpleErrorEvent implements ErrorEvent {
23 | private Object source;
24 |
25 | public SimpleErrorEvent(Object source) {
26 | this.source = source;
27 | }
28 |
29 | public Object getSource() {
30 | return source;
31 | }
32 | }
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/packagelist/model/Column.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector.packagelist.model;
21 | import de.haukerehfeld.quakeinjector.Package;
22 | import java.util.Date;
23 |
24 | /**
25 | * Enum for the table columns. Saves all info about them.
26 | */
27 | public enum Column {
28 | INSTALLED("") {
29 | public Object getData(Package p) {
30 | return Boolean.valueOf(p.isInstalled());
31 | }
32 | public Class extends Object> getColumnClass() { return Boolean.class; }
33 | },
34 | NAME("Name") {
35 | public Object getData(Package p) {
36 | return p.getId();
37 | }
38 |
39 | public Class extends Object> getColumnClass() { return String.class; }
40 | },
41 | TITLE("Title") {
42 | public Object getData(Package p) {
43 | return p.getTitle();
44 | }
45 | public Class extends Object> getColumnClass() { return String.class; }
46 | },
47 | AUTHOR("Author") {
48 | public Object getData(Package p) {
49 | return p.getAuthor();
50 | }
51 | public Class extends Object> getColumnClass() { return String.class; }
52 | },
53 | RELEASEDATE("Released") {
54 | public Object getData(Package p) {
55 | return p.getDate();
56 | }
57 | public Class extends Object> getColumnClass() { return Date.class; }
58 | },
59 | RATING("Rating") {
60 | public Object getData(Package p) {
61 | return p.getRating();
62 | }
63 | public Class extends Object> getColumnClass() { return Package.Rating.class; }
64 | },
65 | NORMALIZEDUSERSRATING("Users'") {
66 | public Object getData(Package p) {
67 | return String.format("%.2f", p.getNormalizedUsersRating());
68 | }
69 | public Class extends Object> getColumnClass() { return Integer.class; }
70 | }
71 | ;
72 |
73 |
74 | public String header;
75 |
76 | private Column(String header) {
77 | this.header = header;
78 | }
79 |
80 | public abstract Object getData(Package p);
81 |
82 | public abstract Class extends Object> getColumnClass();
83 |
84 | public static int getColumnNumber(Column c) {
85 | return java.util.Arrays.binarySearch(values(), c);
86 | }
87 |
88 | public static Column getColumn(int column) {
89 | Column[] values = values();
90 | if (values.length <= column) {
91 | throw new RuntimeException("Unknown Column");
92 | }
93 | return values[column];
94 | }
95 |
96 | public static int count() {
97 | return values().length;
98 | }
99 | }
100 |
101 |
102 |
--------------------------------------------------------------------------------
/src/main/java/de/haukerehfeld/quakeinjector/packagelist/model/PackageListModel.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2009 Hauke Rehfeld
3 |
4 |
5 | This file is part of QuakeInjector.
6 |
7 | QuakeInjector is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | (at your option) any later version.
11 |
12 | QuakeInjector is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with QuakeInjector. If not, see .
19 | */
20 | package de.haukerehfeld.quakeinjector.packagelist.model;
21 |
22 | import java.awt.Component;
23 | import java.awt.FlowLayout;
24 | import java.util.ArrayList;
25 | import java.util.ArrayList;
26 | import java.util.List;
27 | import java.util.List;
28 | import java.util.regex.Pattern;
29 |
30 | import javax.swing.ImageIcon;
31 | import javax.swing.JLabel;
32 | import javax.swing.JPanel;
33 | import javax.swing.JTable;
34 | import javax.swing.RowFilter;
35 | import javax.swing.border.EmptyBorder;
36 | import javax.swing.event.ChangeEvent;
37 | import javax.swing.event.ChangeListener;
38 | import javax.swing.event.TableModelEvent;
39 | import javax.swing.table.AbstractTableModel;
40 | import javax.swing.table.TableCellRenderer;
41 | import javax.swing.table.TableColumnModel;
42 |
43 | import de.haukerehfeld.quakeinjector.ChangeListenerList;
44 | import de.haukerehfeld.quakeinjector.PackageList;
45 | import de.haukerehfeld.quakeinjector.Utils;
46 | import de.haukerehfeld.quakeinjector.Package;
47 |
48 | public class PackageListModel extends AbstractTableModel implements ChangeListener {
49 | private ChangeListenerList listeners = new ChangeListenerList();
50 |
51 | private PackageList data;
52 |
53 |
54 | public PackageListModel(PackageList data) {
55 | setMapList(data);
56 | }
57 |
58 | public void size(JTable table) {
59 | TableColumnModel m = table.getColumnModel();
60 |
61 | m.getColumn(Column.getColumnNumber(Column.NAME)).setPreferredWidth(80);
62 | m.getColumn(Column.getColumnNumber(Column.TITLE)).setPreferredWidth(150);
63 | m.getColumn(Column.getColumnNumber(Column.AUTHOR)).setPreferredWidth(100);
64 | m.getColumn(Column.getColumnNumber(Column.INSTALLED)).setResizable(false);
65 | m.getColumn(Column.getColumnNumber(Column.INSTALLED)).setMaxWidth(16);
66 | m.getColumn(Column.getColumnNumber(Column.INSTALLED)).setMinWidth(16);
67 |
68 | int ratingSize = 5 * (RatingRenderer.ICONSIZE + RatingRenderer.HORIZONTALGAP)
69 | + RatingRenderer.HORIZONTALGAP;
70 | m.getColumn(Column.getColumnNumber(Column.RATING)).setMinWidth(ratingSize);
71 | m.getColumn(Column.getColumnNumber(Column.RATING)).setMaxWidth(ratingSize);
72 | m.getColumn(Column.getColumnNumber(Column.RATING)).setResizable(false);
73 |
74 | m.getColumn(Column.getColumnNumber(Column.NORMALIZEDUSERSRATING)).setMinWidth(48);
75 | m.getColumn(Column.getColumnNumber(Column.NORMALIZEDUSERSRATING)).setMaxWidth(48);
76 | m.getColumn(Column.getColumnNumber(Column.NORMALIZEDUSERSRATING)).setResizable(false);
77 |
78 | m.getColumn(Column.getColumnNumber(Column.RELEASEDATE)).setMinWidth(75);
79 | m.getColumn(Column.getColumnNumber(Column.RELEASEDATE)).setPreferredWidth(80);
80 | //m.getColumn(Column.getColumnNumber(Column.RELEASEDATE)).setMaxWidth(80);
81 |
82 | }
83 |
84 | // public List getPackageList() {
85 | // return this.data;
86 | // }
87 |
88 |
89 | public void setMapList(PackageList data) {
90 | if (this.data != null) {
91 | //remove from all old
92 | this.data.removeChangeListener(this);
93 | for (Package map: this.data) {
94 | map.removeChangeListener(this);
95 | }
96 | }
97 |
98 | data.sort();
99 |
100 | //add to new
101 | this.data = data;
102 | data.addChangeListener(this);
103 |
104 | for (Package map: data) {
105 | map.addChangeListener(this);
106 | }
107 |
108 | fireTableChanged(new TableModelEvent(this));
109 | }
110 |
111 | public int getColumnCount() {
112 | return Column.count();
113 | }
114 |
115 | @Override
116 | public String getColumnName(int col) {
117 | return Column.getColumn(col).header;
118 | }
119 |
120 | /*
121 | * data
122 | */
123 | @Override
124 | public int getRowCount() {
125 | return data.size();
126 | }
127 |
128 |
129 | public Object getColumnData(int col, Package info) {
130 | return Column.getColumn(col).getData(info);
131 | }
132 |
133 | public boolean isPackageInstalled(Package info){
134 | return (boolean) getColumnData(0, info);
135 | }
136 |
137 | @Override
138 | public Class extends Object> getColumnClass(int c) {
139 | return Column.getColumn(c).getColumnClass();
140 | }
141 |
142 | @Override
143 | public Object getValueAt(int row, int col) {
144 | return getColumnData(col, data.get(row));
145 | }
146 |
147 | @Override
148 | public boolean isCellEditable(int row, int col) {
149 | return false;
150 | }
151 |
152 | public Package getPackage(int row) {
153 | return data.get(row);
154 | }
155 |
156 | public void addChangeListener(ChangeListener l) {
157 | listeners.addChangeListener(l);
158 | }
159 |
160 | public void stateChanged(ChangeEvent e) {
161 | if (e.getSource() instanceof PackageList) {
162 | setMapList((PackageList) e.getSource());
163 | listeners.notifyChangeListeners(e.getSource());
164 | return;
165 | }
166 |
167 | if (e.getSource() instanceof Package) {
168 | Package r = (Package) e.getSource();
169 | listeners.notifyChangeListeners(r);
170 | int i = data.indexOf(r);
171 | super.fireTableRowsUpdated(i, i);
172 | return;
173 | }
174 |
175 | throw new RuntimeException("didn't recognise what changed!");
176 | }
177 |
178 |
179 | /**
180 | * Update the row filter regular expression from the expression in
181 | * the text box.
182 | */
183 | public RowFilter filter(final String filterText) {
184 | final int[] columnsToCheck = { Column.getColumnNumber(Column.NAME),
185 | Column.getColumnNumber(Column.AUTHOR),
186 | Column.getColumnNumber(Column.TITLE),
187 | Column.getColumnNumber(Column.RELEASEDATE)
188 | };
189 |
190 | String[] filterTexts = filterText.split(" ");
191 |
192 | final List patterns = new ArrayList(filterTexts.length);
193 | for (String filter: filterTexts) {
194 | try {
195 | patterns.add(Pattern.compile(".*" + filter + ".*",
196 | Pattern.CASE_INSENSITIVE + Pattern.UNICODE_CASE));
197 | } catch (java.util.regex.PatternSyntaxException e) {
198 | continue;
199 | }
200 | }
201 |
202 | RowFilter rf = new RowFilter() {
203 | @Override
204 | public boolean include(Entry extends PackageListModel, ? extends Integer> entry) {
205 | //match all patters in at least one column
206 | for (Pattern pattern: patterns) {
207 | boolean matches = false;
208 | for (int i: columnsToCheck) {
209 | if (pattern.matcher(entry.getStringValue(i)).matches()) {
210 | matches = true;
211 | }
212 | }
213 | if (!matches) {
214 | return false;
215 | }
216 | }
217 | return true;
218 | }
219 | };
220 |
221 | return rf;
222 | }
223 |
224 | public static class RatingRenderer extends JPanel implements TableCellRenderer {
225 | private static final int HORIZONTALGAP = 2;
226 | private static final int ICONSIZE = 8;
227 |
228 | private ImageIcon activeIcon;
229 | private ImageIcon inactiveIcon;
230 |
231 | private List ratingLabels = new ArrayList(5);
232 |
233 | public RatingRenderer() {
234 | super();
235 |
236 | try {
237 | activeIcon = Utils.createImageIcon("/star_spirit_8.png", "activeStar");
238 | inactiveIcon = Utils.createImageIcon("/star_spirit_8_inactive.png", "inactiveStar");
239 | }
240 | catch (java.io.IOException e) {
241 | System.err.println("WARNING: Couldn't load rating image!");
242 | }
243 |
244 | EmptyBorder border = new EmptyBorder(0,0,0,0);
245 | setBorder(border);
246 | ((FlowLayout) getLayout()).setHgap(HORIZONTALGAP);
247 | ((FlowLayout) getLayout()).setVgap(4);
248 |
249 | for (int i = 0; i < 5; ++i) {
250 | JLabel label = new JLabel(activeIcon);
251 | label.setDisabledIcon(inactiveIcon);
252 | label.setBorder(border);
253 | label.setOpaque(false);
254 | add(label);
255 | ratingLabels.add(label);
256 | }
257 | }
258 |
259 | public Component getTableCellRendererComponent(JTable table,
260 | Object value,
261 | boolean isSelected,
262 | boolean hasFocus,
263 | int row,
264 | int column) {
265 | if (value instanceof Package.Rating) {
266 | Package.Rating rating = (Package.Rating) value;
267 | int i = 0;
268 | for (JLabel label: ratingLabels) {
269 | boolean enabled = true;
270 | if (i >= rating.getRating()) {
271 | enabled = false;
272 | }
273 | label.setEnabled(enabled);
274 | ++i;
275 | }
276 | }
277 | return this;
278 | }
279 | }
280 |
281 | // /*
282 | // * Don't need to implement this method unless your table's
283 | // * data can change.
284 | // */
285 | // public void setValueAt(Object value, int row, int col) {
286 | // data[row][col] = value;
287 | // fireTableCellUpdated(row, col);
288 | // }{
289 |
290 | }
291 |
--------------------------------------------------------------------------------
/src/main/resources/Inject2.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hrehfeld/QuakeInjector/65fe5924c7703038e7e2eedc5ae2e17cda19560a/src/main/resources/Inject2.ico
--------------------------------------------------------------------------------
/src/main/resources/Inject2_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hrehfeld/QuakeInjector/65fe5924c7703038e7e2eedc5ae2e17cda19560a/src/main/resources/Inject2_16.png
--------------------------------------------------------------------------------
/src/main/resources/Inject2_16_16colors.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hrehfeld/QuakeInjector/65fe5924c7703038e7e2eedc5ae2e17cda19560a/src/main/resources/Inject2_16_16colors.png
--------------------------------------------------------------------------------
/src/main/resources/Inject2_16_256colors..png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hrehfeld/QuakeInjector/65fe5924c7703038e7e2eedc5ae2e17cda19560a/src/main/resources/Inject2_16_256colors..png
--------------------------------------------------------------------------------
/src/main/resources/Inject2_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hrehfeld/QuakeInjector/65fe5924c7703038e7e2eedc5ae2e17cda19560a/src/main/resources/Inject2_256.png
--------------------------------------------------------------------------------
/src/main/resources/Inject2_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hrehfeld/QuakeInjector/65fe5924c7703038e7e2eedc5ae2e17cda19560a/src/main/resources/Inject2_32.png
--------------------------------------------------------------------------------
/src/main/resources/Inject2_32_16colors.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hrehfeld/QuakeInjector/65fe5924c7703038e7e2eedc5ae2e17cda19560a/src/main/resources/Inject2_32_16colors.png
--------------------------------------------------------------------------------
/src/main/resources/Inject2_32_256colors..png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hrehfeld/QuakeInjector/65fe5924c7703038e7e2eedc5ae2e17cda19560a/src/main/resources/Inject2_32_256colors..png
--------------------------------------------------------------------------------
/src/main/resources/Inject2_48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hrehfeld/QuakeInjector/65fe5924c7703038e7e2eedc5ae2e17cda19560a/src/main/resources/Inject2_48.png
--------------------------------------------------------------------------------
/src/main/resources/Inject2_48_16colors.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hrehfeld/QuakeInjector/65fe5924c7703038e7e2eedc5ae2e17cda19560a/src/main/resources/Inject2_48_16colors.png
--------------------------------------------------------------------------------
/src/main/resources/Inject2_48_256colors..png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hrehfeld/QuakeInjector/65fe5924c7703038e7e2eedc5ae2e17cda19560a/src/main/resources/Inject2_48_256colors..png
--------------------------------------------------------------------------------
/src/main/resources/star_spirit_12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hrehfeld/QuakeInjector/65fe5924c7703038e7e2eedc5ae2e17cda19560a/src/main/resources/star_spirit_12.png
--------------------------------------------------------------------------------
/src/main/resources/star_spirit_8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hrehfeld/QuakeInjector/65fe5924c7703038e7e2eedc5ae2e17cda19560a/src/main/resources/star_spirit_8.png
--------------------------------------------------------------------------------
/src/main/resources/star_spirit_8_inactive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hrehfeld/QuakeInjector/65fe5924c7703038e7e2eedc5ae2e17cda19560a/src/main/resources/star_spirit_8_inactive.png
--------------------------------------------------------------------------------