wörk wörk
This commit is contained in:
parent
9e1509872a
commit
11bd1c8269
@ -28,15 +28,15 @@ while IFS= read -r line; do
|
||||
mustgenerate=false
|
||||
zsyncfile="${line}.zsync"
|
||||
|
||||
filebyte=$(wc -c < ${line})
|
||||
filedate=$(stat -c %Y ${line})
|
||||
filebyte=$(wc -c < "${line}")
|
||||
filedate=$(stat -c %Y "${line}")
|
||||
|
||||
zsyncfiledate=$(strings ${zsyncfile} 2>/dev/null | grep -m 1 MTime | cut -d" " -f2-)
|
||||
zsyncfiledate=$(strings "${zsyncfile}" 2>/dev/null | grep -m 1 MTime | cut -d" " -f2-)
|
||||
|
||||
if [ ! -f "$zsyncfile" ]; then
|
||||
echo "$zsyncfile does not exist"
|
||||
mustgenerate=true
|
||||
elif [[ ! $(strings ${zsyncfile} | grep -m 1 Length | cut -d" " -f2) == $filebyte ]]; then # Check file length
|
||||
elif [[ ! $(strings "${zsyncfile}" | grep -m 1 Length | cut -d" " -f2) == $filebyte ]]; then # Check file length
|
||||
echo "$zsyncfile does not have corret length"
|
||||
mustgenerate=true
|
||||
elif [[ ! $filedate == $(date -d "${zsyncfiledate}" +"%s") ]]; then # Check date
|
||||
@ -46,11 +46,11 @@ while IFS= read -r line; do
|
||||
|
||||
if [ "$mustgenerate" = true ]; then
|
||||
echo "Generate $zsyncfile"
|
||||
rm ${zsyncfile} 2> /dev/null
|
||||
dirfile=$(dirname ${line})
|
||||
filename=$(basename ${line})
|
||||
filenamezsync=$(basename ${zsyncfile})
|
||||
$(cd ${dirfile} && zsyncmake -o ${filenamezsync} ${filename})
|
||||
rm "${zsyncfile}" 2> /dev/null
|
||||
dirfile=$(dirname "${line}")
|
||||
filename=$(basename "${line}")
|
||||
filenamezsync=$(basename "${zsyncfile}")
|
||||
$(cd "${dirfile}" && zsyncmake -o "${filenamezsync}" "${filename}")
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Success: Generated ${zsyncfile}"
|
||||
else
|
||||
@ -67,10 +67,10 @@ echo -e "===== ===== ===== ===== ===== =====\n"
|
||||
echo "===== ===== ===== DELETE SINGLE ZFILE WITHOUT FILE ===== ===== ====="
|
||||
ZSYNCLIST=$(find . -name "*.zsync")
|
||||
while IFS= read -r zfile; do
|
||||
ORIG=$(echo ${zfile} | rev | cut -c7- | rev)
|
||||
ORIG=$(echo "${zfile}" | rev | cut -c7- | rev)
|
||||
if [ ! -f "$ORIG" ]; then
|
||||
echo "$ORIG does not exist"
|
||||
rm ${zfile}
|
||||
rm "${zfile}"
|
||||
fi
|
||||
done <<< "$ZSYNCLIST"
|
||||
echo -e "===== ===== ===== ===== ===== =====\n"
|
||||
@ -85,18 +85,18 @@ while IFS= read -r folder; do
|
||||
echo "is dir"
|
||||
x=""
|
||||
foldersize=0
|
||||
FILEFOLDER=$(find ${folder} -type f ! -path "*.zsync" | sed 's|^./||')
|
||||
FILEFOLDER=$(find "${folder}" -type f ! -path "*.zsync" | sed 's|^./||')
|
||||
while IFS= read -r folderfile; do
|
||||
filebyte=$(wc -c < ${folderfile})
|
||||
filebyte=$(wc -c < "${folderfile}")
|
||||
foldersize=$(expr $foldersize + $filebyte)
|
||||
name=$(echo ${folderfile} | cut -d"/" -f2-)
|
||||
name=$(echo "${folderfile}" | cut -d"/" -f2-)
|
||||
x="\"${name}\":${filebyte},${x}"
|
||||
done <<< "$FILEFOLDER"
|
||||
x=$(echo ${x} | rev | cut -c2- | rev)
|
||||
JSONDATA+=( "\"${folder}\": {\"size\":${foldersize},\"content\":{${x}}}" )
|
||||
else
|
||||
echo "is file"
|
||||
filebyte=$(wc -c < ${folder})
|
||||
filebyte=$(wc -c < "${folder}")
|
||||
JSONDATA+=( "\"${folder}\": {\"size\":${filebyte}}" )
|
||||
fi
|
||||
done <<< "$FILELIST"
|
||||
|
5
pom.xml
5
pom.xml
@ -57,6 +57,11 @@
|
||||
<artifactId>zsyncer</artifactId>
|
||||
<version>-f69d844481-1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>4.4.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -3,7 +3,6 @@ package de.mc8051.arma3launcher;
|
||||
import com.formdev.flatlaf.FlatDarkLaf;
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
import de.mc8051.arma3launcher.repo.RepositoryManger;
|
||||
import de.mc8051.arma3launcher.steam.SteamTimer;
|
||||
import org.ini4j.Ini;
|
||||
|
||||
@ -12,7 +11,6 @@ import java.awt.*;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Timer;
|
||||
@ -81,7 +79,7 @@ public class ArmA3Launcher {
|
||||
frame.setLocationRelativeTo(null);
|
||||
|
||||
steamTimer.scheduleAtFixedRate(
|
||||
new SteamTimer(gui),
|
||||
new SteamTimer(),
|
||||
500, // run first occurrence immediately
|
||||
10000); // run every thirty seconds
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
<grid id="27dc6" binding="mainPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="20" y="20" width="1048" height="542"/>
|
||||
<xy x="20" y="20" width="1048" height="526"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
@ -237,6 +237,7 @@
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<enabled value="false"/>
|
||||
<font size="18" style="1"/>
|
||||
<margin top="15" left="0" bottom="15" right="0"/>
|
||||
<text resource-bundle="lang" key="play_now"/>
|
||||
@ -294,34 +295,73 @@
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
<component id="113bf" class="javax.swing.JTree" binding="tree1" default-binding="true">
|
||||
<constraints border-constraint="Center"/>
|
||||
<properties/>
|
||||
</component>
|
||||
<grid id="74882" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<grid id="74882" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints border-constraint="South"/>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="f4a5" class="javax.swing.JButton" binding="allesAuswählenButton" default-binding="true">
|
||||
<component id="13d22" class="javax.swing.JButton" binding="expandAllButton">
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="lang" key="select_all"/>
|
||||
<enabled value="false"/>
|
||||
<text resource-bundle="lang" key="expand_all"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="13d22" class="javax.swing.JButton" binding="allesAusklappenButton" default-binding="true">
|
||||
<component id="43543" class="javax.swing.JComboBox" binding="comboBox1" default-binding="true">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<component id="2b206" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="4" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="lang" key="expand_all"/>
|
||||
<text resource-bundle="lang" key="preset"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="c9d68" class="javax.swing.JButton" binding="refreshRepoButton">
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<enabled value="false"/>
|
||||
<text resource-bundle="lang" key="update_repository"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="4ec7b" class="javax.swing.JButton" binding="collapseAllButton">
|
||||
<constraints>
|
||||
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<enabled value="false"/>
|
||||
<text resource-bundle="lang" key="collapse_all"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
<scrollpane id="56725" binding="updateTreeScrolPane">
|
||||
<constraints border-constraint="Center"/>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<grid id="44d39" binding="updateTreePanel" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||
<constraints/>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="38143" class="javax.swing.JTree" binding="tree1" default-binding="true">
|
||||
<constraints border-constraint="Center"/>
|
||||
<properties/>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</children>
|
||||
</scrollpane>
|
||||
</children>
|
||||
</grid>
|
||||
<grid id="dc84b" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
@ -367,7 +407,7 @@
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
<grid id="3b45c" layout-manager="GridLayoutManager" row-count="4" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<grid id="3b45c" layout-manager="GridLayoutManager" row-count="6" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="3" bottom="0" right="0"/>
|
||||
<constraints border-constraint="Center"/>
|
||||
<properties/>
|
||||
@ -378,7 +418,7 @@
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="Label"/>
|
||||
<text resource-bundle="lang" key="check_local_addons"/>
|
||||
</properties>
|
||||
</component>
|
||||
<hspacer id="f47e0">
|
||||
@ -386,27 +426,23 @@
|
||||
<grid row="0" column="2" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</hspacer>
|
||||
<vspacer id="5a5d2">
|
||||
<constraints>
|
||||
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</vspacer>
|
||||
<component id="7b453" class="javax.swing.JLabel">
|
||||
<component id="7b453" class="javax.swing.JLabel" binding="syncCheckStatusLabel">
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="Label"/>
|
||||
<font style="2"/>
|
||||
<text value=""/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="c7b6" class="javax.swing.JProgressBar" binding="progressBar1" default-binding="true">
|
||||
<component id="c7b6" class="javax.swing.JProgressBar" binding="syncCheckProgress">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<string value=""/>
|
||||
<stringPainted value="true"/>
|
||||
<value value="50"/>
|
||||
<value value="0"/>
|
||||
</properties>
|
||||
</component>
|
||||
<grid id="c1d6e" layout-manager="GridLayoutManager" row-count="1" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
@ -417,19 +453,21 @@
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="c8876" class="javax.swing.JButton" binding="abbrechenButton" default-binding="true">
|
||||
<component id="c8876" class="javax.swing.JButton" binding="syncCheckAbortButton">
|
||||
<constraints>
|
||||
<grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<enabled value="false"/>
|
||||
<text resource-bundle="lang" key="abort"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="d7e4b" class="javax.swing.JButton" binding="überprüfenButton" default-binding="true">
|
||||
<component id="d7e4b" class="javax.swing.JButton" binding="syncCheckButton">
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<enabled value="false"/>
|
||||
<text resource-bundle="lang" key="check"/>
|
||||
</properties>
|
||||
</component>
|
||||
@ -440,6 +478,54 @@
|
||||
</hspacer>
|
||||
</children>
|
||||
</grid>
|
||||
<component id="c97ef" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="lang" key="changed_files"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="22374" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="lang" key="added_files"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="e3c92" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="5" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="lang" key="deleted_files"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="16f6a" class="javax.swing.JLabel" binding="syncChangedFilesLabel">
|
||||
<constraints>
|
||||
<grid row="3" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="0"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="929a5" class="javax.swing.JLabel" binding="syncAddedFilesLabel">
|
||||
<constraints>
|
||||
<grid row="4" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="0"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="f6ef3" class="javax.swing.JLabel" binding="syncDeletedFilesLabel">
|
||||
<constraints>
|
||||
<grid row="5" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="0"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</children>
|
||||
@ -516,7 +602,7 @@
|
||||
<text resource-bundle="lang" key="remaining_time"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="b28b6" class="javax.swing.JLabel">
|
||||
<component id="b28b6" class="javax.swing.JLabel" binding="syncSizeLabel">
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
@ -613,27 +699,30 @@
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="a5494" class="javax.swing.JButton" binding="downloadButton" default-binding="true">
|
||||
<component id="a5494" class="javax.swing.JButton" binding="syncDownloadButton">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<enabled value="false"/>
|
||||
<text resource-bundle="lang" key="download"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="f8be1" class="javax.swing.JButton" binding="abbrechenButton1" default-binding="true">
|
||||
<component id="f8be1" class="javax.swing.JButton" binding="syncDownloadAbortButton">
|
||||
<constraints>
|
||||
<grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<enabled value="false"/>
|
||||
<text resource-bundle="lang" key="abort"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="c94f5" class="javax.swing.JButton" binding="pauseButton" default-binding="true">
|
||||
<component id="c94f5" class="javax.swing.JButton" binding="syncPauseButton">
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<enabled value="false"/>
|
||||
<text resource-bundle="lang" key="pause"/>
|
||||
</properties>
|
||||
</component>
|
||||
@ -690,6 +779,7 @@
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<enabled value="false"/>
|
||||
<text resource-bundle="lang" key="play"/>
|
||||
</properties>
|
||||
</component>
|
||||
@ -1079,6 +1169,7 @@
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="SkipIntro"/>
|
||||
<toolTipText resource-bundle="lang" key="skipintro_desc"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="435dd" class="javax.swing.JLabel">
|
||||
|
@ -1,13 +1,19 @@
|
||||
package de.mc8051.arma3launcher;
|
||||
|
||||
import de.mc8051.arma3launcher.interfaces.Observer;
|
||||
import de.mc8051.arma3launcher.model.JCheckBoxTree;
|
||||
import de.mc8051.arma3launcher.model.ModListRenderer;
|
||||
import de.mc8051.arma3launcher.model.PresetListRenderer;
|
||||
import de.mc8051.arma3launcher.model.PresetTableModel;
|
||||
import de.mc8051.arma3launcher.model.ServerTableModel;
|
||||
import de.mc8051.arma3launcher.objects.AbstractMod;
|
||||
import de.mc8051.arma3launcher.objects.Mod;
|
||||
import de.mc8051.arma3launcher.objects.ModFile;
|
||||
import de.mc8051.arma3launcher.objects.Modset;
|
||||
import de.mc8051.arma3launcher.objects.Server;
|
||||
import de.mc8051.arma3launcher.repo.FileChecker;
|
||||
import de.mc8051.arma3launcher.repo.RepositoryManger;
|
||||
import de.mc8051.arma3launcher.steam.SteamTimer;
|
||||
import de.mc8051.arma3launcher.utils.Callback;
|
||||
import de.mc8051.arma3launcher.utils.LangUtils;
|
||||
|
||||
@ -16,6 +22,9 @@ import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.plaf.basic.BasicTabbedPaneUI;
|
||||
import javax.swing.text.DefaultFormatter;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
@ -28,6 +37,11 @@ import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Stream;
|
||||
@ -97,25 +111,50 @@ public class LauncherGUI implements Observer {
|
||||
private JScrollPane settingScrollPane;
|
||||
private JCheckBox settingsUseWorkshopBox;
|
||||
private JTree tree1;
|
||||
private JButton allesAuswählenButton;
|
||||
private JButton allesAusklappenButton;
|
||||
private JProgressBar progressBar1;
|
||||
private JButton abbrechenButton;
|
||||
private JButton überprüfenButton;
|
||||
private JButton expandAllButton;
|
||||
private JProgressBar syncCheckProgress;
|
||||
private JButton syncCheckAbortButton;
|
||||
private JButton syncCheckButton;
|
||||
private JProgressBar progressBar2;
|
||||
private JProgressBar progressBar3;
|
||||
private JButton downloadButton;
|
||||
private JButton abbrechenButton1;
|
||||
private JButton pauseButton;
|
||||
private JButton syncDownloadButton;
|
||||
private JButton syncDownloadAbortButton;
|
||||
private JButton syncPauseButton;
|
||||
private JComboBox comboBox1;
|
||||
private JButton refreshRepoButton;
|
||||
private JPanel updateTreePanel;
|
||||
private JScrollPane updateTreeScrolPane;
|
||||
private JButton collapseAllButton;
|
||||
private JLabel syncCheckStatusLabel;
|
||||
private JLabel syncDeletedFilesLabel;
|
||||
private JLabel syncAddedFilesLabel;
|
||||
private JLabel syncChangedFilesLabel;
|
||||
private JLabel syncSizeLabel;
|
||||
|
||||
private JCheckBoxTree repoTree;
|
||||
private FileChecker fileChecker;
|
||||
|
||||
// TODO: Updater
|
||||
/*
|
||||
Prüfung
|
||||
In eine Liste hinzufügen wenn Datei in modset.json (Neu runterladen), nicht in modset.json (zum Löschen) oder die Größe unterschiedlich ist (Geändert)
|
||||
Checkboxen beim Syncronisieren deaktivieren
|
||||
*/
|
||||
|
||||
public LauncherGUI() {
|
||||
fileChecker = new FileChecker(syncCheckProgress);
|
||||
|
||||
RepositoryManger.getInstance().addObserver(this);
|
||||
SteamTimer.addObserver(this);
|
||||
fileChecker.addObserver(this);
|
||||
|
||||
updateTreePanel.remove(tree1);
|
||||
|
||||
repoTree = new JCheckBoxTree();
|
||||
updateTreePanel.add(repoTree, BorderLayout.CENTER);
|
||||
|
||||
updateTreePanel.revalidate();
|
||||
updateTreePanel.repaint();
|
||||
|
||||
tabbedPane1.setUI(new BasicTabbedPaneUI() {
|
||||
private final Insets borderInsets = new Insets(0, 0, 0, 0);
|
||||
@ -226,8 +265,45 @@ public class LauncherGUI implements Observer {
|
||||
});
|
||||
|
||||
settingScrollPane.getVerticalScrollBar().setUnitIncrement(16);
|
||||
updateTreeScrolPane.getVerticalScrollBar().setUnitIncrement(16);
|
||||
|
||||
refreshRepoButton.addActionListener(e -> RepositoryManger.getInstance().refreshModset());
|
||||
expandAllButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
repoTree.expandAllNodes();
|
||||
}
|
||||
});
|
||||
collapseAllButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
repoTree.collapseAllNodes();
|
||||
}
|
||||
});
|
||||
|
||||
new Thread(() -> {
|
||||
RepositoryManger.getInstance().refreshMeta();
|
||||
RepositoryManger.getInstance().refreshModset();
|
||||
}).start();
|
||||
|
||||
syncCheckButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
syncCheckButton.setEnabled(false);
|
||||
syncCheckAbortButton.setEnabled(true);
|
||||
syncCheckStatusLabel.setText("Running!");
|
||||
new Thread(() -> fileChecker.check()).start();
|
||||
|
||||
// TODO: disable JTree Checkboxes
|
||||
}
|
||||
});
|
||||
|
||||
syncCheckAbortButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
fileChecker.stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void infoBox(String infoMessage, String titleBar) {
|
||||
@ -261,9 +337,53 @@ public class LauncherGUI implements Observer {
|
||||
}
|
||||
|
||||
public void techCheck() {
|
||||
// Arma Path set
|
||||
// Steam running
|
||||
// Arma not running
|
||||
boolean pathSet = ArmA3Launcher.user_config.get("client").containsKey("armaPath") && ArmA3Launcher.user_config.get("client").containsKey("modPath");
|
||||
if (SteamTimer.arma_running) {
|
||||
playButton.setEnabled(false);
|
||||
playPresetButton.setEnabled(false);
|
||||
syncCheckButton.setEnabled(false);
|
||||
refreshRepoButton.setEnabled(false);
|
||||
|
||||
playButton.setToolTipText(LangUtils.getInstance().getString("arma_running"));
|
||||
playPresetButton.setToolTipText(LangUtils.getInstance().getString("arma_running"));
|
||||
syncCheckButton.setToolTipText(LangUtils.getInstance().getString("arma_running"));
|
||||
} else {
|
||||
if (SteamTimer.steam_running) {
|
||||
if (pathSet) {
|
||||
playButton.setEnabled(true);
|
||||
playPresetButton.setEnabled(true);
|
||||
|
||||
playButton.setToolTipText(null);
|
||||
playPresetButton.setToolTipText(null);
|
||||
} else {
|
||||
playButton.setEnabled(false);
|
||||
playPresetButton.setEnabled(false);
|
||||
|
||||
playButton.setToolTipText(LangUtils.getInstance().getString("path_not_set"));
|
||||
playPresetButton.setToolTipText(LangUtils.getInstance().getString("path_not_set"));
|
||||
}
|
||||
} else {
|
||||
playButton.setEnabled(false);
|
||||
playPresetButton.setEnabled(false);
|
||||
|
||||
playButton.setToolTipText(LangUtils.getInstance().getString("steam_not_running"));
|
||||
playPresetButton.setToolTipText(LangUtils.getInstance().getString("steam_not_running"));
|
||||
}
|
||||
|
||||
if (pathSet) {
|
||||
syncCheckButton.setEnabled(true);
|
||||
refreshRepoButton.setEnabled(true);
|
||||
|
||||
syncCheckButton.setToolTipText(null);
|
||||
refreshRepoButton.setToolTipText(null);
|
||||
} else {
|
||||
syncCheckButton.setEnabled(true);
|
||||
refreshRepoButton.setEnabled(true);
|
||||
|
||||
syncCheckButton.setToolTipText(LangUtils.getInstance().getString("path_not_set"));
|
||||
refreshRepoButton.setToolTipText(LangUtils.getInstance().getString("path_not_set"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean checkArmaPath(String path) {
|
||||
@ -318,7 +438,15 @@ public class LauncherGUI implements Observer {
|
||||
SwingUtilities.invokeLater(() -> warnBox(LangUtils.getInstance().getString("not_arma_dir_msg"), LangUtils.getInstance().getString("not_arma_dir")));
|
||||
return false;
|
||||
}
|
||||
|
||||
String modPath = ArmA3Launcher.user_config.get("client", "modPath");
|
||||
if(sPath.equalsIgnoreCase(modPath)) {
|
||||
SwingUtilities.invokeLater(() -> errorBox(LangUtils.getInstance().getString("same_mod_arma_dir_msg"), LangUtils.getInstance().getString("same_mod_arma_dir")));
|
||||
return false;
|
||||
}
|
||||
|
||||
settingsArmaPathText.setText(sPath);
|
||||
techCheck();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
@ -326,7 +454,16 @@ public class LauncherGUI implements Observer {
|
||||
initFolderChooser(settingsModsPathText, settingsModsPathBtn, "modPath", Parameter.ParameterType.CLIENT, new Callback.JFileSelectCallback() {
|
||||
@Override
|
||||
public boolean allowSelection(File path) {
|
||||
settingsModsPathText.setText(path.getAbsolutePath());
|
||||
String sPath = path.getAbsolutePath();
|
||||
|
||||
String armaPath = ArmA3Launcher.user_config.get("client", "armaPath");
|
||||
if(sPath.equalsIgnoreCase(armaPath)) {
|
||||
SwingUtilities.invokeLater(() -> errorBox(LangUtils.getInstance().getString("same_mod_arma_dir_msg"), LangUtils.getInstance().getString("same_mod_arma_dir")));
|
||||
return false;
|
||||
}
|
||||
|
||||
settingsModsPathText.setText(sPath);
|
||||
RepositoryManger.getInstance().refreshModset();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
@ -413,9 +550,73 @@ public class LauncherGUI implements Observer {
|
||||
spinner.addChangeListener(new SettingsHandler.SpinnerListener(paraObj));
|
||||
}
|
||||
|
||||
public ArrayList<AbstractMod> getSyncList() {
|
||||
ArrayList<AbstractMod> modList = new ArrayList<>();
|
||||
|
||||
HashMap<String, ArrayList<String>> tempMap = new HashMap<>();
|
||||
for (TreePath checkedPath : repoTree.getCheckedPaths()) {
|
||||
DefaultMutableTreeNode tn = (DefaultMutableTreeNode)checkedPath.getLastPathComponent();
|
||||
|
||||
if(tn.getChildCount() > 0) continue;
|
||||
Object[] path = checkedPath.getPath();
|
||||
DefaultMutableTreeNode[] modifiedArray = Arrays.stream(Arrays.copyOfRange(path, 1, path.length)).toArray(DefaultMutableTreeNode[]::new);
|
||||
|
||||
ArrayList<String> strings = new ArrayList<>();
|
||||
if(tempMap.containsKey(String.valueOf(modifiedArray[0].getUserObject()))) {
|
||||
strings = tempMap.get(String.valueOf(modifiedArray[0].getUserObject()));
|
||||
}
|
||||
|
||||
String modPath = "";
|
||||
for (int i = 1; i < modifiedArray.length; i++) {
|
||||
modPath += String.valueOf(modifiedArray[i].getUserObject()) + "/";
|
||||
}
|
||||
modPath = modPath.isEmpty() ? "" : modPath.substring(0, modPath.length() - 1);
|
||||
strings.add(modPath);
|
||||
|
||||
tempMap.put((String) modifiedArray[0].getUserObject(), strings);
|
||||
}
|
||||
|
||||
for (Map.Entry<String, ArrayList<String>> entry : tempMap.entrySet()) {
|
||||
String modS = entry.getKey();
|
||||
ArrayList<String> modlistS = entry.getValue();
|
||||
|
||||
if(modlistS.isEmpty()) {
|
||||
for (AbstractMod abstractMod : RepositoryManger.MOD_LIST) {
|
||||
if (abstractMod.getName().equals(modS)) {
|
||||
modList.add(abstractMod);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (AbstractMod abstractMod : RepositoryManger.MOD_LIST) {
|
||||
if (abstractMod.getName().equals(modS)) {
|
||||
if(!(abstractMod instanceof Mod)) continue;
|
||||
Mod m = ((Mod) abstractMod).clone();
|
||||
|
||||
for (int i = 0; i < m.getFiles().size(); i++) {
|
||||
boolean found = false;
|
||||
for (String pathS : modlistS) {
|
||||
if(m.getFiles().get(i).getModfileString().equals(pathS)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found) {
|
||||
m.getFiles().remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
modList.add(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return modList;
|
||||
}
|
||||
|
||||
public void updateModList(Modset modset) {
|
||||
ListModel<String> model = (ListModel) modList.getModel();
|
||||
// TODO: RepositoryManger.downloadModlist
|
||||
// TODO: Show All Mods (keyname)
|
||||
// TODO: Show not installed Mods with red font
|
||||
// TODO: Select Mod if in modset.Mods
|
||||
@ -423,11 +624,126 @@ public class LauncherGUI implements Observer {
|
||||
// TODO: Wenn modset.type == Server alle Checkboxen deaktivieren!
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Object o) {
|
||||
String s = String.valueOf(o);
|
||||
public void updateRepoTree() {
|
||||
expandAllButton.setEnabled(false);
|
||||
collapseAllButton.setEnabled(false);
|
||||
|
||||
if (s.equals("refreshMeta")) {
|
||||
DefaultTreeModel model = (DefaultTreeModel) repoTree.getModel();
|
||||
DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
|
||||
root.setUserObject("Repository");
|
||||
root.removeAllChildren();
|
||||
|
||||
for (AbstractMod abstractMod : RepositoryManger.MOD_LIST) {
|
||||
if (abstractMod instanceof Mod) {
|
||||
// Whole Folder
|
||||
// TODO: Recursives Ordner Parsen und einzelne Treenodes erstellen
|
||||
Mod m = (Mod) abstractMod;
|
||||
DefaultMutableTreeNode modFolder = new DefaultMutableTreeNode(m.getName(), true);
|
||||
model.insertNodeInto(modFolder, root, root.getChildCount());
|
||||
|
||||
for (ModFile modfile : m.getFiles()) {
|
||||
|
||||
DefaultMutableTreeNode lastNode = modFolder;
|
||||
ArrayList<String> path = modfile.getPath();
|
||||
|
||||
for (int i = 0; i < path.size(); i++) {
|
||||
boolean found = false;
|
||||
|
||||
for (int j = 0; j < lastNode.getChildCount(); j++) {
|
||||
DefaultMutableTreeNode temp = (DefaultMutableTreeNode) lastNode.getChildAt(j);
|
||||
if (temp.getUserObject().equals(path.get(i))) {
|
||||
found = true;
|
||||
lastNode = temp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
DefaultMutableTreeNode temp = new DefaultMutableTreeNode(path.get(i));
|
||||
model.insertNodeInto(temp, lastNode, lastNode.getChildCount());
|
||||
lastNode = temp;
|
||||
}
|
||||
}
|
||||
|
||||
model.insertNodeInto(new DefaultMutableTreeNode(modfile.getName()), lastNode, lastNode.getChildCount());
|
||||
}
|
||||
sort(modFolder);
|
||||
} else if (abstractMod instanceof ModFile) {
|
||||
// Just a Single FIle
|
||||
ModFile m = (ModFile) abstractMod;
|
||||
model.insertNodeInto(new DefaultMutableTreeNode(m.getName(), false), root, root.getChildCount());
|
||||
}
|
||||
}
|
||||
|
||||
sort(root);
|
||||
|
||||
repoTree.clearCheckChangeEventListeners();
|
||||
|
||||
repoTree.resetCheckingState();
|
||||
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
model.nodeChanged(root);
|
||||
model.reload();
|
||||
repoTree.revalidate();
|
||||
repoTree.repaint();
|
||||
updateTreePanel.revalidate();
|
||||
updateTreePanel.repaint();
|
||||
});
|
||||
|
||||
expandAllButton.setEnabled(true);
|
||||
collapseAllButton.setEnabled(true);
|
||||
}
|
||||
|
||||
public DefaultMutableTreeNode sort(DefaultMutableTreeNode node) {
|
||||
|
||||
//sort alphabetically
|
||||
for(int i = 0; i < node.getChildCount() - 1; i++) {
|
||||
DefaultMutableTreeNode child = (DefaultMutableTreeNode) node.getChildAt(i);
|
||||
String nt = child.getUserObject().toString();
|
||||
|
||||
for(int j = i + 1; j <= node.getChildCount() - 1; j++) {
|
||||
DefaultMutableTreeNode prevNode = (DefaultMutableTreeNode) node.getChildAt(j);
|
||||
String np = prevNode.getUserObject().toString();
|
||||
|
||||
if(nt.compareToIgnoreCase(np) > 0) {
|
||||
node.insert(child, j);
|
||||
node.insert(prevNode, i);
|
||||
}
|
||||
}
|
||||
if(child.getChildCount() > 0) {
|
||||
sort(child);
|
||||
}
|
||||
}
|
||||
|
||||
//put folders first - normal on Windows and some flavors of Linux but not on Mac OS X.
|
||||
for(int i = 0; i < node.getChildCount() - 1; i++) {
|
||||
DefaultMutableTreeNode child = (DefaultMutableTreeNode) node.getChildAt(i);
|
||||
for(int j = i + 1; j <= node.getChildCount() - 1; j++) {
|
||||
DefaultMutableTreeNode prevNode = (DefaultMutableTreeNode) node.getChildAt(j);
|
||||
|
||||
if(!prevNode.isLeaf() && child.isLeaf()) {
|
||||
node.insert(child, j);
|
||||
node.insert(prevNode, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void update(String s) {
|
||||
System.out.println(s);
|
||||
if (s.equals(RepositoryManger.Type.METADATA.toString())) {
|
||||
switch (RepositoryManger.getInstance().getStatus(RepositoryManger.Type.METADATA)) {
|
||||
case ERROR:
|
||||
errorBox("Metadata download failed. Is the server availaible? Do you have an active internet connection?", "Download failed");
|
||||
System.exit(1);
|
||||
break;
|
||||
|
||||
case FINNISHED:
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
ServerTableModel model = (ServerTableModel) serverTable.getModel();
|
||||
|
||||
@ -444,6 +760,48 @@ public class LauncherGUI implements Observer {
|
||||
model.add(set);
|
||||
});
|
||||
});
|
||||
break;
|
||||
}
|
||||
} else if (s.equals("steamtimer")) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
updateLabels(SteamTimer.steam_running, SteamTimer.arma_running);
|
||||
techCheck();
|
||||
});
|
||||
} else if (s.equals(RepositoryManger.Type.MODSET.toString())) {
|
||||
switch (RepositoryManger.getInstance().getStatus(RepositoryManger.Type.METADATA)) {
|
||||
case FINNISHED:
|
||||
refreshRepoButton.setEnabled(true);
|
||||
updateRepoTree();
|
||||
break;
|
||||
|
||||
case RUNNING:
|
||||
refreshRepoButton.setEnabled(false);
|
||||
break;
|
||||
}
|
||||
} else if(s.equals("fileChecker")) {
|
||||
syncCheckButton.setEnabled(true);
|
||||
syncCheckAbortButton.setEnabled(false);
|
||||
syncCheckStatusLabel.setText("Finished!");
|
||||
updateRepoTree();
|
||||
// TODO: Label einfärben
|
||||
// TODO: Enable Tree Checkboxes
|
||||
syncDownloadButton.setEnabled(true);
|
||||
syncAddedFilesLabel.setText(String.valueOf(fileChecker.getAddedCount()));
|
||||
syncChangedFilesLabel.setText(String.valueOf(fileChecker.getChangedCount()));
|
||||
syncDeletedFilesLabel.setText(String.valueOf(fileChecker.getDeletedCount()));
|
||||
|
||||
syncSizeLabel.setText(String.valueOf(fileChecker.getSize())); // TODO: Make Humanreadable
|
||||
} else if (s.equals("fileCheckerStopped")) {
|
||||
syncCheckButton.setEnabled(true);
|
||||
syncCheckAbortButton.setEnabled(false);
|
||||
syncCheckProgress.setValue(0);
|
||||
syncCheckStatusLabel.setText("Failed!");
|
||||
|
||||
syncAddedFilesLabel.setText("" + 0);
|
||||
syncChangedFilesLabel.setText("" + 0);
|
||||
syncDeletedFilesLabel.setText("" + 0);
|
||||
|
||||
syncSizeLabel.setText("0.0 B");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,5 +7,5 @@ public interface Observable {
|
||||
|
||||
public void addObserver(Observer observer);
|
||||
public void removeObserver(Observer observer);
|
||||
public void notifyObservers(Object obj);
|
||||
public void notifyObservers(String obj);
|
||||
}
|
||||
|
@ -5,5 +5,5 @@ package de.mc8051.arma3launcher.interfaces;
|
||||
*/
|
||||
public interface Observer {
|
||||
|
||||
public void update(Object o);
|
||||
public void update(String o);
|
||||
}
|
||||
|
295
src/main/java/de/mc8051/arma3launcher/model/JCheckBoxTree.java
Normal file
295
src/main/java/de/mc8051/arma3launcher/model/JCheckBoxTree.java
Normal file
@ -0,0 +1,295 @@
|
||||
package de.mc8051.arma3launcher.model;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.EventListenerList;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeSelectionModel;
|
||||
import javax.swing.tree.TreeCellRenderer;
|
||||
import javax.swing.tree.TreeModel;
|
||||
import javax.swing.tree.TreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EventListener;
|
||||
import java.util.EventObject;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* Created by SomethingSomething https://stackoverflow.com/a/21851201/5605489
|
||||
*/
|
||||
public class JCheckBoxTree extends JTree {
|
||||
|
||||
private static final long serialVersionUID = -4194122328392241790L;
|
||||
|
||||
JCheckBoxTree selfPointer = this;
|
||||
|
||||
|
||||
// Defining data structure that will enable to fast check-indicate the state of each node
|
||||
// It totally replaces the "selection" mechanism of the JTree
|
||||
private class CheckedNode {
|
||||
boolean isSelected;
|
||||
boolean hasChildren;
|
||||
boolean allChildrenSelected;
|
||||
|
||||
public CheckedNode(boolean isSelected_, boolean hasChildren_, boolean allChildrenSelected_) {
|
||||
isSelected = isSelected_;
|
||||
hasChildren = hasChildren_;
|
||||
allChildrenSelected = allChildrenSelected_;
|
||||
}
|
||||
}
|
||||
|
||||
HashMap<TreePath, CheckedNode> nodesCheckingState;
|
||||
HashSet<TreePath> checkedPaths = new HashSet<TreePath>();
|
||||
|
||||
// Defining a new event type for the checking mechanism and preparing event-handling mechanism
|
||||
protected EventListenerList listenerList = new EventListenerList();
|
||||
|
||||
public class CheckChangeEvent extends EventObject {
|
||||
private static final long serialVersionUID = -8100230309044193368L;
|
||||
|
||||
public CheckChangeEvent(Object source) {
|
||||
super(source);
|
||||
}
|
||||
}
|
||||
|
||||
public interface CheckChangeEventListener extends EventListener {
|
||||
public void checkStateChanged(CheckChangeEvent event);
|
||||
}
|
||||
|
||||
public void addCheckChangeEventListener(CheckChangeEventListener listener) {
|
||||
listenerList.add(CheckChangeEventListener.class, listener);
|
||||
}
|
||||
|
||||
public void removeCheckChangeEventListener(CheckChangeEventListener listener) {
|
||||
listenerList.remove(CheckChangeEventListener.class, listener);
|
||||
}
|
||||
|
||||
public void clearCheckChangeEventListeners() {
|
||||
Object[] listeners = listenerList.getListenerList();
|
||||
for (int i = listeners.length - 1; i >= 0; i--) {
|
||||
if (listeners[i] == CheckChangeEventListener.class) {
|
||||
listenerList.remove(CheckChangeEventListener.class, ((CheckChangeEventListener) listeners[i + 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fireCheckChangeEvent(CheckChangeEvent evt) {
|
||||
Object[] listeners = listenerList.getListenerList();
|
||||
for (int i = 0; i < listeners.length; i++) {
|
||||
if (listeners[i] == CheckChangeEventListener.class) {
|
||||
((CheckChangeEventListener) listeners[i + 1]).checkStateChanged(evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Override
|
||||
public void setModel(TreeModel newModel) {
|
||||
super.setModel(newModel);
|
||||
resetCheckingState();
|
||||
}
|
||||
|
||||
public void createModel(Object[] value) {
|
||||
createTreeModel(value);
|
||||
}
|
||||
|
||||
// New method that returns only the checked paths (totally ignores original "selection" mechanism)
|
||||
public TreePath[] getCheckedPaths() {
|
||||
return checkedPaths.toArray(new TreePath[checkedPaths.size()]);
|
||||
}
|
||||
|
||||
// Returns true in case that the node is selected, has children but not all of them are selected
|
||||
public boolean isSelectedPartially(TreePath path) {
|
||||
CheckedNode cn = nodesCheckingState.get(path);
|
||||
return cn.isSelected && cn.hasChildren && !cn.allChildrenSelected;
|
||||
}
|
||||
|
||||
public void resetCheckingState() {
|
||||
nodesCheckingState = new HashMap<TreePath, CheckedNode>();
|
||||
checkedPaths = new HashSet<TreePath>();
|
||||
DefaultMutableTreeNode node = (DefaultMutableTreeNode) getModel().getRoot();
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
addSubtreeToCheckingStateTracking(node);
|
||||
}
|
||||
|
||||
// Creating data structure of the current model for the checking mechanism
|
||||
private void addSubtreeToCheckingStateTracking(DefaultMutableTreeNode node) {
|
||||
TreeNode[] path = node.getPath();
|
||||
TreePath tp = new TreePath(path);
|
||||
CheckedNode cn = new CheckedNode(false, node.getChildCount() > 0, false);
|
||||
nodesCheckingState.put(tp, cn);
|
||||
for (int i = 0; i < node.getChildCount(); i++) {
|
||||
addSubtreeToCheckingStateTracking((DefaultMutableTreeNode) tp.pathByAddingChild(node.getChildAt(i)).getLastPathComponent());
|
||||
}
|
||||
}
|
||||
|
||||
// Overriding cell renderer by a class that ignores the original "selection" mechanism
|
||||
// It decides how to show the nodes due to the checking-mechanism
|
||||
private class CheckBoxCellRenderer extends JPanel implements TreeCellRenderer {
|
||||
private static final long serialVersionUID = -7341833835878991719L;
|
||||
JCheckBox checkBox;
|
||||
|
||||
public CheckBoxCellRenderer() {
|
||||
super();
|
||||
this.setLayout(new BorderLayout());
|
||||
checkBox = new JCheckBox();
|
||||
add(checkBox, BorderLayout.CENTER);
|
||||
setOpaque(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTreeCellRendererComponent(JTree tree, Object value,
|
||||
boolean selected, boolean expanded, boolean leaf, int row,
|
||||
boolean hasFocus) {
|
||||
checkBox.setText(value.toString());
|
||||
DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
|
||||
TreePath tp = new TreePath(node.getPath());
|
||||
CheckedNode cn = nodesCheckingState.get(tp);
|
||||
if (cn == null) {
|
||||
return this;
|
||||
}
|
||||
checkBox.setSelected(cn.isSelected);
|
||||
checkBox.setOpaque(cn.isSelected && cn.hasChildren && !cn.allChildrenSelected);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public JCheckBoxTree() {
|
||||
super();
|
||||
// Disabling toggling by double-click
|
||||
this.setToggleClickCount(0);
|
||||
// Overriding cell renderer by new one defined above
|
||||
CheckBoxCellRenderer cellRenderer = new CheckBoxCellRenderer();
|
||||
this.setCellRenderer(cellRenderer);
|
||||
|
||||
// Overriding selection model by an empty one
|
||||
DefaultTreeSelectionModel dtsm = new DefaultTreeSelectionModel() {
|
||||
private static final long serialVersionUID = -8190634240451667286L;
|
||||
|
||||
// Totally disabling the selection mechanism
|
||||
public void setSelectionPath(TreePath path) {
|
||||
}
|
||||
|
||||
public void addSelectionPath(TreePath path) {
|
||||
}
|
||||
|
||||
public void removeSelectionPath(TreePath path) {
|
||||
}
|
||||
|
||||
public void setSelectionPaths(TreePath[] pPaths) {
|
||||
}
|
||||
};
|
||||
// Calling checking mechanism on mouse click
|
||||
this.addMouseListener(new MouseListener() {
|
||||
public void mouseClicked(MouseEvent arg0) {
|
||||
TreePath tp = selfPointer.getPathForLocation(arg0.getX(), arg0.getY());
|
||||
if (tp == null) {
|
||||
return;
|
||||
}
|
||||
boolean checkMode = !nodesCheckingState.get(tp).isSelected;
|
||||
checkSubTree(tp, checkMode);
|
||||
updatePredecessorsWithCheckMode(tp, checkMode);
|
||||
// Firing the check change event
|
||||
fireCheckChangeEvent(new CheckChangeEvent(new Object()));
|
||||
// Repainting tree after the data structures were updated
|
||||
selfPointer.repaint();
|
||||
}
|
||||
|
||||
public void mouseEntered(MouseEvent arg0) {
|
||||
}
|
||||
|
||||
public void mouseExited(MouseEvent arg0) {
|
||||
}
|
||||
|
||||
public void mousePressed(MouseEvent arg0) {
|
||||
}
|
||||
|
||||
public void mouseReleased(MouseEvent arg0) {
|
||||
}
|
||||
});
|
||||
this.setSelectionModel(dtsm);
|
||||
}
|
||||
|
||||
// When a node is checked/unchecked, updating the states of the predecessors
|
||||
protected void updatePredecessorsWithCheckMode(TreePath tp, boolean check) {
|
||||
TreePath parentPath = tp.getParentPath();
|
||||
// If it is the root, stop the recursive calls and return
|
||||
if (parentPath == null) {
|
||||
return;
|
||||
}
|
||||
CheckedNode parentCheckedNode = nodesCheckingState.get(parentPath);
|
||||
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) parentPath.getLastPathComponent();
|
||||
parentCheckedNode.allChildrenSelected = true;
|
||||
parentCheckedNode.isSelected = false;
|
||||
for (int i = 0; i < parentNode.getChildCount(); i++) {
|
||||
TreePath childPath = parentPath.pathByAddingChild(parentNode.getChildAt(i));
|
||||
CheckedNode childCheckedNode = nodesCheckingState.get(childPath);
|
||||
// It is enough that even one subtree is not fully selected
|
||||
// to determine that the parent is not fully selected
|
||||
if (!childCheckedNode.allChildrenSelected) {
|
||||
parentCheckedNode.allChildrenSelected = false;
|
||||
}
|
||||
// If at least one child is selected, selecting also the parent
|
||||
if (childCheckedNode.isSelected) {
|
||||
parentCheckedNode.isSelected = true;
|
||||
}
|
||||
}
|
||||
if (parentCheckedNode.isSelected) {
|
||||
checkedPaths.add(parentPath);
|
||||
} else {
|
||||
checkedPaths.remove(parentPath);
|
||||
}
|
||||
// Go to upper predecessor
|
||||
updatePredecessorsWithCheckMode(parentPath, check);
|
||||
}
|
||||
|
||||
// Recursively checks/unchecks a subtree
|
||||
protected void checkSubTree(TreePath tp, boolean check) {
|
||||
CheckedNode cn = nodesCheckingState.get(tp);
|
||||
cn.isSelected = check;
|
||||
DefaultMutableTreeNode node = (DefaultMutableTreeNode) tp.getLastPathComponent();
|
||||
for (int i = 0; i < node.getChildCount(); i++) {
|
||||
checkSubTree(tp.pathByAddingChild(node.getChildAt(i)), check);
|
||||
}
|
||||
cn.allChildrenSelected = check;
|
||||
if (check) {
|
||||
checkedPaths.add(tp);
|
||||
} else {
|
||||
checkedPaths.remove(tp);
|
||||
}
|
||||
}
|
||||
|
||||
public void expandAllNodes() {
|
||||
setTreeExpandedState(true);
|
||||
}
|
||||
|
||||
public void collapseAllNodes() {
|
||||
setTreeExpandedState(false);
|
||||
}
|
||||
|
||||
private void setTreeExpandedState(boolean expanded) {
|
||||
DefaultMutableTreeNode node = (DefaultMutableTreeNode) getModel().getRoot();
|
||||
setNodeExpandedState( node, expanded);
|
||||
}
|
||||
|
||||
private void setNodeExpandedState(DefaultMutableTreeNode node, boolean expanded) {
|
||||
ArrayList<TreeNode> list = Collections.list(node.children());
|
||||
for (TreeNode treeNode : list) {
|
||||
setNodeExpandedState((DefaultMutableTreeNode)treeNode, expanded);
|
||||
}
|
||||
if (!expanded && node.isRoot()) {
|
||||
return;
|
||||
}
|
||||
TreePath path = new TreePath(node.getPath());
|
||||
if (expanded) {
|
||||
expandPath(path);
|
||||
} else {
|
||||
collapsePath(path);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package de.mc8051.arma3launcher.objects;
|
||||
|
||||
/**
|
||||
* Created by gurkengewuerz.de on 25.03.2020.
|
||||
*/
|
||||
public interface AbstractMod {
|
||||
|
||||
public String getName();
|
||||
}
|
@ -1,17 +1,40 @@
|
||||
package de.mc8051.arma3launcher.objects;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Created by gurkengewuerz.de on 25.03.2020.
|
||||
*/
|
||||
public class Mod {
|
||||
public class Mod implements AbstractMod {
|
||||
|
||||
private String name;
|
||||
private long size;
|
||||
private ArrayList<ModFile> files;
|
||||
|
||||
public Mod(String name) {
|
||||
this(name, -1, new ArrayList<>());
|
||||
}
|
||||
|
||||
public Mod(String name, long size, ArrayList<ModFile> files) {
|
||||
this.name = name;
|
||||
this.size = size;
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
public ArrayList<ModFile> getFiles() {
|
||||
return files;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
public Mod clone() {
|
||||
return new Mod(name, size, new ArrayList<>(files));
|
||||
}
|
||||
}
|
||||
|
82
src/main/java/de/mc8051/arma3launcher/objects/ModFile.java
Normal file
82
src/main/java/de/mc8051/arma3launcher/objects/ModFile.java
Normal file
@ -0,0 +1,82 @@
|
||||
package de.mc8051.arma3launcher.objects;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Created by gurkengewuerz.de on 25.03.2020.
|
||||
*/
|
||||
public class ModFile implements AbstractMod {
|
||||
|
||||
private File f;
|
||||
private long size;
|
||||
private String folder;
|
||||
private String filename;
|
||||
private String extension;
|
||||
private String modfileString;
|
||||
|
||||
public ModFile(File f, String modfile, long size) {
|
||||
// File: Abosolut Path
|
||||
// modfile: addons/config/something.pbo
|
||||
// size: size as in metafile on server
|
||||
this.f = f;
|
||||
this.size = size;
|
||||
this.folder = FilenameUtils.getPath(modfile);
|
||||
this.filename = FilenameUtils.getBaseName(modfile);
|
||||
this.extension = FilenameUtils.getExtension(modfile);
|
||||
this.modfileString = modfile;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public String getReletaivePath() {
|
||||
return folder;
|
||||
}
|
||||
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
public String getExtension() {
|
||||
return extension;
|
||||
}
|
||||
|
||||
public ArrayList<String> getPath() {
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
File relativePath = new File("./"+ modfileString);
|
||||
do {
|
||||
list.add(relativePath.getName());
|
||||
relativePath = relativePath.getParentFile();
|
||||
} while (relativePath.getParentFile() != null);
|
||||
list.remove(0);
|
||||
Collections.reverse(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
public long getLocalSize() {
|
||||
if(!f.exists() || !f.isFile()) return -1;
|
||||
return f.length();
|
||||
}
|
||||
|
||||
public boolean exists() {
|
||||
if(!f.exists() || !f.isFile()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return filename + (extension.equals("") ? "" : "." + extension);
|
||||
}
|
||||
|
||||
public String getModfileString() {
|
||||
return modfileString;
|
||||
}
|
||||
|
||||
public File getLocaleFile() {
|
||||
return f;
|
||||
}
|
||||
}
|
@ -56,6 +56,10 @@ public class Modset {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void play() {
|
||||
// TODO: Implement play with this Modset
|
||||
}
|
||||
|
||||
public static enum Type {
|
||||
SERVER,
|
||||
CLIENT
|
||||
|
@ -0,0 +1,10 @@
|
||||
package de.mc8051.arma3launcher.repo;
|
||||
|
||||
/**
|
||||
* Created by gurkengewuerz.de on 25.03.2020.
|
||||
*/
|
||||
public enum DownloadStatus {
|
||||
RUNNING,
|
||||
FINNISHED,
|
||||
ERROR;
|
||||
}
|
203
src/main/java/de/mc8051/arma3launcher/repo/FileChecker.java
Normal file
203
src/main/java/de/mc8051/arma3launcher/repo/FileChecker.java
Normal file
@ -0,0 +1,203 @@
|
||||
package de.mc8051.arma3launcher.repo;
|
||||
|
||||
import de.mc8051.arma3launcher.ArmA3Launcher;
|
||||
import de.mc8051.arma3launcher.interfaces.Observable;
|
||||
import de.mc8051.arma3launcher.interfaces.Observer;
|
||||
import de.mc8051.arma3launcher.objects.AbstractMod;
|
||||
import de.mc8051.arma3launcher.objects.Mod;
|
||||
import de.mc8051.arma3launcher.objects.ModFile;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Created by gurkengewuerz.de on 26.03.2020.
|
||||
*/
|
||||
public class FileChecker implements Observable {
|
||||
|
||||
private List<Observer> observerList = new ArrayList<>();
|
||||
private JProgressBar pb;
|
||||
private boolean stop = false;
|
||||
|
||||
ArrayList<Path> deleted = new ArrayList<>();
|
||||
HashMap<String, ArrayList<ModFile>> changed = new HashMap<>();
|
||||
int changedCount = 0;
|
||||
HashMap<String, ArrayList<ModFile>> added = new HashMap<>();
|
||||
int addedCount = 0;
|
||||
|
||||
long size = 0;
|
||||
|
||||
public FileChecker(JProgressBar pb) {
|
||||
this.pb = pb;
|
||||
}
|
||||
|
||||
public void check() {
|
||||
deleted.clear();
|
||||
changed.clear();
|
||||
changedCount = 0;
|
||||
added.clear();
|
||||
addedCount = 0;
|
||||
size = 0;
|
||||
|
||||
int i = 0;
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
pb.setMaximum(RepositoryManger.MOD_LIST_SIZE);
|
||||
pb.setValue(0);
|
||||
});
|
||||
|
||||
for (AbstractMod abstractMod : RepositoryManger.MOD_LIST) {
|
||||
if(stop) {
|
||||
stop = false;
|
||||
notifyObservers("fileCheckerStopped");
|
||||
return;
|
||||
}
|
||||
if(abstractMod instanceof Mod) {
|
||||
Mod m = (Mod) abstractMod;
|
||||
|
||||
for (ModFile mf : m.getFiles()) {
|
||||
checkFile(mf.getName(), mf);
|
||||
i++;
|
||||
int finalI = i;
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
pb.setValue(finalI);
|
||||
});
|
||||
|
||||
if(stop) {
|
||||
stop = false;
|
||||
notifyObservers("fileCheckerStopped");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (abstractMod instanceof ModFile) {
|
||||
ModFile mf = (ModFile) abstractMod;
|
||||
checkFile(mf.getName(), mf);
|
||||
i++;
|
||||
int finalI1 = i;
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
pb.setValue(finalI1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
checkDeleted();
|
||||
notifyObservers("fileChecker");
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
stop = true;
|
||||
}
|
||||
|
||||
private void checkFile(String mod, ModFile mf) {
|
||||
// TODO: Add mf to Array if Array already exists
|
||||
if(!mf.exists()) {
|
||||
added.put(mod, mf);
|
||||
addedCount++;
|
||||
size += mf.getSize();
|
||||
return;
|
||||
}
|
||||
|
||||
if(mf.getLocalSize() != mf.getSize()) {
|
||||
changed.put(mod, mf);
|
||||
changedCount++;
|
||||
size += mf.getSize();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDeleted() {
|
||||
String modPath = ArmA3Launcher.user_config.get("client", "modPath");
|
||||
if(modPath == null) modPath = "";
|
||||
|
||||
try {
|
||||
List<Path> filePathList = Files.find(Paths.get(modPath),
|
||||
Integer.MAX_VALUE,
|
||||
(filePath, fileAttr) -> fileAttr.isRegularFile())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
||||
for (Path localPath : filePathList) {
|
||||
ModFile deleteable = null;
|
||||
|
||||
outerloop:
|
||||
for (AbstractMod abstractMod : RepositoryManger.MOD_LIST) {
|
||||
if(abstractMod instanceof Mod) {
|
||||
Mod m = (Mod) abstractMod;
|
||||
|
||||
for (ModFile mf : m.getFiles()) {
|
||||
if (mf.getLocaleFile().getPath().equals(localPath.toString())) {
|
||||
deleteable = mf;
|
||||
break outerloop;
|
||||
}
|
||||
}
|
||||
} else if (abstractMod instanceof ModFile) {
|
||||
ModFile mf = (ModFile) abstractMod;
|
||||
if (mf.getLocaleFile().getPath().equals(localPath.toString())) {
|
||||
deleteable = mf;
|
||||
break outerloop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (deleteable == null) {
|
||||
deleted.add(localPath);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e);
|
||||
}
|
||||
}
|
||||
|
||||
public ArrayList<Path> getDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public HashMap<String, ArrayList<ModFile>> getChanged() {
|
||||
return changed;
|
||||
}
|
||||
|
||||
public HashMap<String, ArrayList<ModFile>> getAdded() {
|
||||
return added;
|
||||
}
|
||||
|
||||
public int getDeletedCount() {
|
||||
return deleted.size();
|
||||
}
|
||||
|
||||
public int getChangedCount() {
|
||||
return changedCount;
|
||||
}
|
||||
|
||||
public int getAddedCount() {
|
||||
return addedCount;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addObserver(Observer observer) {
|
||||
observerList.add(observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeObserver(Observer observer) {
|
||||
observerList.remove(observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyObservers(String obj) {
|
||||
for (Observer obs : observerList) obs.update(obj);
|
||||
}
|
||||
}
|
@ -3,6 +3,9 @@ package de.mc8051.arma3launcher.repo;
|
||||
import de.mc8051.arma3launcher.ArmA3Launcher;
|
||||
import de.mc8051.arma3launcher.interfaces.Observable;
|
||||
import de.mc8051.arma3launcher.interfaces.Observer;
|
||||
import de.mc8051.arma3launcher.objects.AbstractMod;
|
||||
import de.mc8051.arma3launcher.objects.Mod;
|
||||
import de.mc8051.arma3launcher.objects.ModFile;
|
||||
import de.mc8051.arma3launcher.objects.Modset;
|
||||
import de.mc8051.arma3launcher.objects.Server;
|
||||
import de.mc8051.arma3launcher.utils.Callback;
|
||||
@ -12,8 +15,11 @@ import okhttp3.Response;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@ -24,19 +30,49 @@ import java.util.logging.Logger;
|
||||
public class RepositoryManger implements Observable {
|
||||
|
||||
private static RepositoryManger instance;
|
||||
|
||||
public static ArrayList<AbstractMod> MOD_LIST = new ArrayList<>();
|
||||
public static int MOD_LIST_SIZE = 0;
|
||||
private static HashMap<Type, DownloadStatus> statusMap = new HashMap<>();
|
||||
|
||||
private List<Observer> observerList = new ArrayList<>();
|
||||
private OkHttpClient client = new OkHttpClient();
|
||||
|
||||
private RepositoryManger() {
|
||||
statusMap.put(Type.METADATA, DownloadStatus.FINNISHED);
|
||||
statusMap.put(Type.MODSET, DownloadStatus.FINNISHED);
|
||||
}
|
||||
|
||||
private void getAsync(String url, Callback.HttpCallback callback) {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
Response r = client.newCall(request).execute();
|
||||
if (!r.isSuccessful()) {
|
||||
Logger.getLogger(getClass().getName()).log(Level.SEVERE, "Cant open " + r.request().url().toString() + " code " + r.code());
|
||||
return;
|
||||
}
|
||||
|
||||
callback.response(r);
|
||||
} catch (IOException e) {
|
||||
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e);
|
||||
callback.response(null);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
public void refreshMeta() {
|
||||
downloadMeta(new Callback.HttpCallback() {
|
||||
statusMap.replace(Type.METADATA, DownloadStatus.RUNNING);
|
||||
RepositoryManger.getInstance().notifyObservers(Type.METADATA.toString());
|
||||
getAsync(ArmA3Launcher.config.getString("sync.url") + "/.sync/server.json", new Callback.HttpCallback() {
|
||||
@Override
|
||||
public void response(Response r) {
|
||||
if (!r.isSuccessful()) {
|
||||
Logger.getLogger(getClass().getName()).log(Level.SEVERE, "Cant open " + r.request().url().toString() + " code " + r.code());
|
||||
RepositoryManger.getInstance().notifyObservers("refreshMetaFailed");
|
||||
statusMap.replace(Type.METADATA, DownloadStatus.ERROR);
|
||||
RepositoryManger.getInstance().notifyObservers(Type.METADATA.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -44,6 +80,7 @@ public class RepositoryManger implements Observable {
|
||||
JSONObject jsonObject = new JSONObject(r.body().string());
|
||||
|
||||
if (jsonObject.has("modsets")) {
|
||||
Modset.MODSET_LIST.clear();
|
||||
JSONArray modsets = jsonObject.getJSONArray("modsets");
|
||||
if (modsets.length() > 0) {
|
||||
for (int i = 0; i < modsets.length(); i++) {
|
||||
@ -55,6 +92,7 @@ public class RepositoryManger implements Observable {
|
||||
|
||||
// Init servers after modsets because server search preset string in modsets
|
||||
if (jsonObject.has("servers")) {
|
||||
Server.SERVER_LIST.clear();
|
||||
JSONArray servers = jsonObject.getJSONArray("servers");
|
||||
if (servers.length() > 0) {
|
||||
for (int i = 0; i < servers.length(); i++) {
|
||||
@ -64,7 +102,8 @@ public class RepositoryManger implements Observable {
|
||||
}
|
||||
}
|
||||
|
||||
RepositoryManger.getInstance().notifyObservers("refreshMeta");
|
||||
statusMap.replace(Type.METADATA, DownloadStatus.FINNISHED);
|
||||
RepositoryManger.getInstance().notifyObservers(Type.METADATA.toString());
|
||||
} catch (IOException | NullPointerException e) {
|
||||
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e);
|
||||
}
|
||||
@ -72,19 +111,68 @@ public class RepositoryManger implements Observable {
|
||||
});
|
||||
}
|
||||
|
||||
private void downloadMeta(Callback.HttpCallback callback) {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Request request = new Request.Builder()
|
||||
.url(ArmA3Launcher.config.getString("sync.url") + "/.sync/server.json")
|
||||
.build();
|
||||
|
||||
callback.response(client.newCall(request).execute());
|
||||
} catch (IOException e) {
|
||||
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e);
|
||||
callback.response(null);
|
||||
public void refreshModset() {
|
||||
statusMap.replace(Type.MODSET, DownloadStatus.RUNNING);
|
||||
RepositoryManger.getInstance().notifyObservers(Type.MODSET.toString());
|
||||
getAsync(ArmA3Launcher.config.getString("sync.url") + "/.sync/modset.json", new Callback.HttpCallback() {
|
||||
@Override
|
||||
public void response(Response r) {
|
||||
if (!r.isSuccessful()) {
|
||||
statusMap.replace(Type.MODSET, DownloadStatus.ERROR);
|
||||
RepositoryManger.getInstance().notifyObservers(Type.MODSET.toString());
|
||||
return;
|
||||
}
|
||||
}).start();
|
||||
|
||||
try {
|
||||
RepositoryManger.MOD_LIST.clear();
|
||||
RepositoryManger.MOD_LIST_SIZE = 0;
|
||||
JSONObject jsonObject = new JSONObject(r.body().string());
|
||||
|
||||
String modPath = ArmA3Launcher.user_config.get("client", "modPath");
|
||||
if(modPath == null) modPath = "";
|
||||
|
||||
String finalModPath = modPath;
|
||||
jsonObject.keySet().forEach(modname ->
|
||||
{
|
||||
Object keyvalue = jsonObject.get(modname);
|
||||
|
||||
if (!(keyvalue instanceof JSONObject)) return;
|
||||
|
||||
JSONObject jsonMod = (JSONObject)keyvalue;
|
||||
if(!jsonMod.has("size")) return;
|
||||
|
||||
long modsize = jsonMod.getLong("size");
|
||||
|
||||
if(jsonMod.has("content")) {
|
||||
// Mod Directory
|
||||
JSONObject content = jsonMod.getJSONObject("content");
|
||||
|
||||
ArrayList<ModFile> modFiles = new ArrayList<>();
|
||||
Iterator<String> keys = content.keys();
|
||||
while (keys.hasNext()) {
|
||||
String modfile = keys.next();
|
||||
long modfilesize = content.getLong(modfile);
|
||||
|
||||
modFiles.add(new ModFile(new File(finalModPath + File.separator + modname + File.separator + modfile), modfile, modfilesize));
|
||||
RepositoryManger.MOD_LIST_SIZE++;
|
||||
}
|
||||
|
||||
MOD_LIST.add(new Mod(modname, modsize, modFiles));
|
||||
} else {
|
||||
// Single File
|
||||
MOD_LIST.add(new ModFile(new File(finalModPath + File.separator + modname), modname, modsize));
|
||||
RepositoryManger.MOD_LIST_SIZE++;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
statusMap.replace(Type.MODSET, DownloadStatus.FINNISHED);
|
||||
RepositoryManger.getInstance().notifyObservers(Type.MODSET.toString());
|
||||
} catch (IOException | NullPointerException e) {
|
||||
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static RepositoryManger getInstance() {
|
||||
@ -92,6 +180,10 @@ public class RepositoryManger implements Observable {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public DownloadStatus getStatus(Type type) {
|
||||
return statusMap.get(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addObserver(Observer observer) {
|
||||
observerList.add(observer);
|
||||
@ -103,7 +195,24 @@ public class RepositoryManger implements Observable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyObservers(Object obj) {
|
||||
public void notifyObservers(String obj) {
|
||||
for (Observer obs : observerList) obs.update(obj);
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
|
||||
METADATA("metadata"),
|
||||
MODSET("modset");
|
||||
|
||||
private String modset;
|
||||
|
||||
Type(String modset) {
|
||||
this.modset = modset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return modset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
8
src/main/java/de/mc8051/arma3launcher/repo/Syncer.java
Normal file
8
src/main/java/de/mc8051/arma3launcher/repo/Syncer.java
Normal file
@ -0,0 +1,8 @@
|
||||
package de.mc8051.arma3launcher.repo;
|
||||
|
||||
/**
|
||||
* Created by gurkengewuerz.de on 25.03.2020.
|
||||
*/
|
||||
public class Syncer {
|
||||
// FilenameUtils.directoryContains
|
||||
}
|
@ -2,10 +2,12 @@ package de.mc8051.arma3launcher.steam;
|
||||
|
||||
import de.mc8051.arma3launcher.LauncherGUI;
|
||||
import de.mc8051.arma3launcher.SteamUtils;
|
||||
import de.mc8051.arma3launcher.interfaces.Observer;
|
||||
import de.ralleytn.simple.registry.Key;
|
||||
import de.ralleytn.simple.registry.Registry;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.TimerTask;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@ -15,24 +17,22 @@ import java.util.logging.Logger;
|
||||
*/
|
||||
public class SteamTimer extends TimerTask {
|
||||
|
||||
private static ArrayList<Observer> observers = new ArrayList<>();
|
||||
public static boolean steam_running = false;
|
||||
public static boolean arma_running = false;
|
||||
|
||||
private LauncherGUI gui;
|
||||
|
||||
public SteamTimer(LauncherGUI gui) {
|
||||
this.gui = gui;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
String OS = System.getProperty("os.name").toUpperCase();
|
||||
if (!OS.contains("WIN")) return;
|
||||
|
||||
boolean old_steamrunning = steam_running;
|
||||
boolean old_arma_running = arma_running;
|
||||
|
||||
try {
|
||||
if(!SteamUtils.findProcess("steam.exe")) {
|
||||
steam_running = false;
|
||||
gui.updateLabels(steam_running, arma_running);
|
||||
if(old_steamrunning != steam_running) notifyObservers("steamtimer");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -42,19 +42,28 @@ public class SteamTimer extends TimerTask {
|
||||
|
||||
if(activeSteamUser.equals("0x0")) {
|
||||
steam_running = false;
|
||||
gui.updateLabels(steam_running, arma_running);
|
||||
if(old_steamrunning != steam_running) notifyObservers("steamtimer");
|
||||
return;
|
||||
}
|
||||
|
||||
steam_running = true;
|
||||
|
||||
arma_running = SteamUtils.findProcess("arma3.exe") || SteamUtils.findProcess("arma3_x64.exe") || SteamUtils.findProcess("arma3launcher.exe");
|
||||
|
||||
if(old_steamrunning != steam_running || old_arma_running != arma_running) notifyObservers("steamtimer");
|
||||
} catch (IOException e) {
|
||||
steam_running = false;
|
||||
arma_running = false;
|
||||
notifyObservers("steamtimer");
|
||||
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e);
|
||||
}
|
||||
}
|
||||
|
||||
gui.updateLabels(steam_running, arma_running);
|
||||
public static void addObserver(Observer observer) {
|
||||
observers.add(observer);
|
||||
}
|
||||
|
||||
public void notifyObservers(String obj) {
|
||||
for(Observer o : observers) o.update(obj);
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
arma_running=ArmA läuft noch. Bitte beende ArmA.
|
||||
abort=Abbrechen
|
||||
arm33_parameter=ArmA 3 Startparameter
|
||||
arma3_installpath=ArmA 3 Installationspfad
|
||||
@ -65,7 +66,7 @@ showscripterrors_desc=Fehler in Scripten werden in einem Hinweistext signalisier
|
||||
signed_in=eingeloggt
|
||||
speed=Geschwindigkeit
|
||||
speed_up_game=Spielstart beschleunigen
|
||||
spikintro_desc=Die Intro-Sequenz wird übersprungen.
|
||||
skipintro_desc=Die Intro-Sequenz wird übersprungen.
|
||||
total_file_size=Gesamtgröße
|
||||
update=Update
|
||||
use64bitclient_desc=Startet Arma3 mit der für 64-Bit Betriebssysteme optimierten .exe-Datei (kann die Performance von Arma 3 verbessern und Probleme beheben (bspw. 3-FPS-Bug).
|
||||
@ -80,3 +81,13 @@ du sie deaktivieren und ohne diese Option erneut syncen.\
|
||||
Ebenfalls könnte es zu kurzen Performance einbußen kommen.
|
||||
window_desc=Ist diese Option aktiv, wird Arma 3 im Fenstermodus gestartet.
|
||||
world_desc=Hier kann eine Karte eingetragen werden, die geladen und in den Menüs als Hintergrund angezeigt werden soll (z.B. „altis“ oder „stratis“ – ohne Anführungszeichen!). Ist das Feld leer, wird keine Karte während des Startens geladen und der Start von Arma 3 ist entsprechend schneller.
|
||||
path_not_set=ArmA oder Mod Verzeichnis nicht gesetzt
|
||||
steam_not_running=Steam läuft nicht. Bitte starte Steam.
|
||||
update_repository=Repository aktualisieren
|
||||
collapse_all=Alles einklappen
|
||||
same_mod_arma_dir_msg=Das ArmA sowie Mod Verzeichnis dürfen nicht identisch sein.
|
||||
same_mod_arma_dir=Gleiches Verzeichnis
|
||||
check_local_addons=Lokale Dateien überprüfen
|
||||
changed_files=Veränderte Datien
|
||||
added_files=Hinzugefügte Datien
|
||||
deleted_files=Gelöschte Dateien
|
@ -1,6 +1,7 @@
|
||||
abort=Abort
|
||||
arm33_parameter=ArmA 3 Start parameters
|
||||
arma3_installpath=ArmA 3 Installation path
|
||||
arma_running=ArmA is still running. Please exit ArmA.
|
||||
backend_url=Backend URL
|
||||
behaviour_aafter_start=Behaviour after start
|
||||
beta_desc=Data from subdirectories can be started as well.
|
||||
@ -64,7 +65,7 @@ showscripterrors_desc=Errors in scripts are signaled in a message text.
|
||||
signed_in=signed in
|
||||
speed=Speed
|
||||
speed_up_game=Speed up game start
|
||||
spikintro_desc=The intro sequence is skipped.
|
||||
skipintro_desc=The intro sequence is skipped.
|
||||
total_file_size=Total file size
|
||||
update=Update
|
||||
use64bitclient_desc=Starts Arma3 with the .exe file optimized for 64-bit operating systems (can improve the performance of Arma 3 and fix problems (e.g. 3-FPS bug)
|
||||
@ -79,3 +80,9 @@ you deactivate it and sync again without this option.\
|
||||
This could also lead to short performance losses.
|
||||
window_desc=If this option is active, Arma 3 is started in windowed mode.
|
||||
world_desc=Here you can enter a card to be loaded and displayed as background in the menus (e.g. "altis" or "stratis" - without quotation marks!). If the field is empty, no map will be loaded during startup and the start of Arma 3 will be faster.
|
||||
path_not_set=ArmA or Mod directory not set
|
||||
steam_not_running=Steam not running. Please start Steam.
|
||||
repository_content=Repository Content
|
||||
collapse_all=Collapse All
|
||||
same_mod_arma_dir_msg=The ArmA and Mod directory must not be identical.
|
||||
same_mod_arma_dir=Same directory
|
Loading…
Reference in New Issue
Block a user