wörk wörk (day 4)

* added checkbox JList for preset mod list
* added multiselect of JList without pressing CTRL
* added compareable for Mod object
* added user modsets
* added functions to add/save/remove/clone Modset to user config
* added fast check (only detect byte size changes)
* added load user modsets
* added "focusing" correct button corresponding to the tab
* added JComboBox to select a preset in updater
* changed button alignment
* fixed synclist for single ModFile

#coronatime
This commit is contained in:
Niklas 2020-03-29 01:54:40 +01:00
parent 5eeffde3c3
commit 112bc228d4
15 changed files with 743 additions and 190 deletions

View File

@ -46,6 +46,11 @@
<artifactId>zsyncer</artifactId>
<version>1de0d3f651</version>
</dependency>
<dependency>
<groupId>com.jgoodies</groupId>
<artifactId>jgoodies-forms</artifactId>
<version>1.9.0</version>
</dependency>
</dependencies>
<build>

View File

@ -42,10 +42,14 @@
<properties>
<alignmentY value="0.0"/>
<borderPainted value="true"/>
<focusCycleRoot value="false"/>
<focusPainted value="false"/>
<focusable value="true"/>
<focusable value="false"/>
<font size="16"/>
<horizontalAlignment value="2"/>
<icon value="icons/settings_16.png"/>
<iconTextGap value="10"/>
<inheritsPopupMenu value="true"/>
<margin top="0" left="0" bottom="0" right="0"/>
<text resource-bundle="lang" key="settings"/>
</properties>
@ -64,8 +68,11 @@
</constraints>
<properties>
<focusPainted value="false"/>
<focusable value="false"/>
<font size="16"/>
<horizontalAlignment value="2"/>
<icon value="icons/download_16.png"/>
<iconTextGap value="10"/>
<text resource-bundle="lang" key="update"/>
</properties>
</component>
@ -75,8 +82,11 @@
</constraints>
<properties>
<focusPainted value="false"/>
<focusable value="false"/>
<font size="16"/>
<horizontalAlignment value="2"/>
<icon value="icons/play_16.png"/>
<iconTextGap value="10"/>
<margin top="0" left="0" bottom="0" right="0"/>
<text resource-bundle="lang" key="play"/>
</properties>
@ -168,8 +178,11 @@
</constraints>
<properties>
<focusPainted value="false"/>
<focusable value="false"/>
<font size="16"/>
<horizontalAlignment value="2"/>
<icon value="icons/preset_16.png"/>
<iconTextGap value="10"/>
<margin top="0" left="0" bottom="0" right="0"/>
<text resource-bundle="lang" key="presets"/>
</properties>
@ -180,8 +193,11 @@
</constraints>
<properties>
<focusPainted value="false"/>
<focusable value="false"/>
<font size="16"/>
<horizontalAlignment value="2"/>
<icon value="icons/changelog_16.png"/>
<iconTextGap value="10"/>
<text resource-bundle="lang" key="changelog"/>
</properties>
</component>
@ -445,20 +461,24 @@
<text resource-bundle="lang" key="abort"/>
</properties>
</component>
<component id="d7e4b" class="javax.swing.JButton" binding="syncCheckButton">
<component id="d7e4b" class="javax.swing.JButton" binding="syncIntensiveCheckButton">
<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"/>
<text resource-bundle="lang" key="intensive_check"/>
</properties>
</component>
<hspacer id="a2208">
<component id="df55f" class="javax.swing.JButton" binding="syncFastCheckButton">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
<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>
</hspacer>
<properties>
<enabled value="false"/>
<text resource-bundle="lang" key="fast_check"/>
</properties>
</component>
</children>
</grid>
<component id="c97ef" class="javax.swing.JLabel">
@ -561,23 +581,25 @@
</component>
</children>
</grid>
<grid id="b8ac" layout-manager="GridLayoutManager" row-count="4" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<grid id="b8ac" layout-manager="FormLayout">
<rowspec value="center:max(d;4px):noGrow"/>
<rowspec value="top:4dlu:noGrow"/>
<rowspec value="center:max(d;4px):noGrow"/>
<rowspec value="top:4dlu:noGrow"/>
<rowspec value="center:max(d;4px):noGrow"/>
<rowspec value="top:4dlu:noGrow"/>
<rowspec value="center:max(d;4px):noGrow"/>
<colspec value="fill:d:grow"/>
<colspec value="left:4dlu:noGrow"/>
<colspec value="fill:d:grow"/>
<constraints border-constraint="Center"/>
<properties/>
<border type="none"/>
<children>
<component id="e74aa" class="javax.swing.JLabel">
<constraints>
<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 resource-bundle="lang" key="total_file_size"/>
</properties>
</component>
<component id="f5997" class="javax.swing.JLabel">
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<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"/>
<forms/>
</constraints>
<properties>
<text resource-bundle="lang" key="speed"/>
@ -585,31 +607,17 @@
</component>
<component id="25551" 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"/>
<grid row="6" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<forms/>
</constraints>
<properties>
<text resource-bundle="lang" key="remaining_time"/>
</properties>
</component>
<component id="b28b6" class="javax.swing.JLabel" binding="syncSizeLabel">
<component id="9148" class="javax.swing.JLabel" binding="syncFileCountLabel">
<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="0.0 B"/>
</properties>
</component>
<component id="617c7" class="javax.swing.JLabel" binding="syncDownloadSpeedLabel">
<constraints>
<grid row="2" 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=""/>
</properties>
</component>
<component id="b64ac" class="javax.swing.JLabel">
<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"/>
<grid row="2" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<forms/>
</constraints>
<properties>
<text value=""/>
@ -617,15 +625,44 @@
</component>
<component id="28be3" class="javax.swing.JLabel">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<forms/>
</constraints>
<properties>
<text resource-bundle="lang" key="file_count"/>
</properties>
</component>
<component id="9148" class="javax.swing.JLabel" binding="syncFileCountLabel">
<component id="e74aa" class="javax.swing.JLabel">
<constraints>
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<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"/>
<forms/>
</constraints>
<properties>
<text resource-bundle="lang" key="total_file_size"/>
</properties>
</component>
<component id="b28b6" class="javax.swing.JLabel" binding="syncSizeLabel">
<constraints>
<grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<forms/>
</constraints>
<properties>
<text value="0.0 B/0.0 B"/>
</properties>
</component>
<component id="617c7" class="javax.swing.JLabel" binding="syncDownloadSpeedLabel">
<constraints>
<grid row="4" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<forms/>
</constraints>
<properties>
<text value=""/>
</properties>
</component>
<component id="63dca" class="javax.swing.JLabel">
<constraints>
<grid row="6" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<forms/>
</constraints>
<properties>
<text value=""/>
@ -793,7 +830,7 @@
<text resource-bundle="lang" key="expand_all"/>
</properties>
</component>
<component id="43543" class="javax.swing.JComboBox" binding="comboBox1" default-binding="true">
<component id="43543" class="javax.swing.JComboBox" binding="syncPresetCombo">
<constraints>
<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>
@ -945,10 +982,78 @@
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<verticalScrollBarPolicy value="22"/>
<horizontalScrollBarPolicy value="31"/>
<verticalScrollBarPolicy value="20"/>
</properties>
<border type="none"/>
<children/>
<border type="empty"/>
<children>
<grid id="87071" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="100" left="70" bottom="100" right="70"/>
<constraints/>
<properties/>
<border type="none"/>
<children>
<grid id="1679e" binding="presetNotePane" layout-manager="FormLayout">
<rowspec value="center:d:noGrow"/>
<rowspec value="top:4dlu:noGrow"/>
<rowspec value="center:max(d;4px):noGrow"/>
<rowspec value="top:4dlu:noGrow"/>
<rowspec value="center:max(d;4px):noGrow"/>
<colspec value="fill:d:grow"/>
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<visible value="false"/>
</properties>
<border type="none"/>
<children>
<component id="7b832" class="javax.swing.JLabel">
<constraints>
<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"/>
<forms/>
</constraints>
<properties>
<font size="14" style="1"/>
<text resource-bundle="lang" key="note"/>
</properties>
</component>
<component id="d466d" class="javax.swing.JButton" binding="presetNoteButton">
<constraints>
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
<forms/>
</constraints>
<properties>
<text resource-bundle="lang" key="clone_preset"/>
</properties>
</component>
<grid id="8f1ff" binding="presetNotePaneWrapper" 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>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<forms/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="862fc" class="javax.swing.JTextPane" binding="presetNoteTextPane">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false">
<preferred-size width="200" height="50"/>
</grid>
</constraints>
<properties>
<enabled value="true"/>
<text resource-bundle="lang" key="presets_note"/>
</properties>
</component>
</children>
</grid>
</children>
</grid>
</children>
</grid>
</children>
</scrollpane>
<component id="3960a" class="javax.swing.JLabel">
<constraints>
@ -1033,7 +1138,9 @@
<preferred-size width="150" height="50"/>
</grid>
</constraints>
<properties/>
<properties>
<selectionMode value="1"/>
</properties>
</component>
<component id="4fbf3" class="javax.swing.JList" binding="modList">
<constraints>

View File

@ -3,10 +3,12 @@ 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.MultiSelectModel;
import de.mc8051.arma3launcher.model.PresetListRenderer;
import de.mc8051.arma3launcher.model.PresetTableModel;
import de.mc8051.arma3launcher.model.RepositoryTreeNode;
import de.mc8051.arma3launcher.model.ServerTableModel;
import de.mc8051.arma3launcher.model.TabbedPaneUI;
import de.mc8051.arma3launcher.objects.AbstractMod;
import de.mc8051.arma3launcher.objects.Changelog;
import de.mc8051.arma3launcher.objects.Mod;
@ -24,10 +26,12 @@ import de.mc8051.arma3launcher.utils.Humanize;
import de.mc8051.arma3launcher.utils.ImageUtils;
import de.mc8051.arma3launcher.utils.LangUtils;
import de.mc8051.arma3launcher.utils.TaskBarUtils;
import org.json.JSONArray;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.basic.BasicTabbedPaneUI;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.text.DefaultFormatter;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
@ -37,12 +41,12 @@ import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.lang.management.ManagementFactory;
import java.net.URL;
@ -51,11 +55,12 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.Properties;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
@ -125,13 +130,13 @@ public class LauncherGUI implements Observer {
private JButton expandAllButton;
private JProgressBar syncCheckProgress;
private JButton syncCheckAbortButton;
private JButton syncCheckButton;
private JButton syncIntensiveCheckButton;
public JProgressBar syncDownloadProgress;
public JProgressBar syncFileProgress;
private JButton syncDownloadButton;
private JButton syncDownloadAbortButton;
private JButton syncPauseButton;
private JComboBox comboBox1;
private JComboBox syncPresetCombo;
private JButton refreshRepoButton;
private JPanel updateTreePanel;
private JScrollPane updateTreeScrolPane;
@ -161,6 +166,11 @@ public class LauncherGUI implements Observer {
private JLabel aboutProjectLabel;
private JLabel aboutDeveloperLabel;
private JLabel aboutCopyrightLabel;
private JButton syncFastCheckButton;
private JButton presetNoteButton;
private JTextPane presetNoteTextPane;
private JPanel presetNotePaneWrapper;
private JPanel presetNotePane;
private JCheckBoxTree repoTree;
private FileChecker fileChecker;
@ -186,7 +196,9 @@ public class LauncherGUI implements Observer {
RepositoryManger.getInstance().refreshModset();
}).start();
updateTreePanel.remove(tree1);
switchTab(Tab.PLAY);
updateTreePanel.removeAll();
repoTree = new JCheckBoxTree();
updateTreePanel.add(repoTree, BorderLayout.CENTER);
@ -197,25 +209,9 @@ public class LauncherGUI implements Observer {
updateTreePanel.revalidate();
updateTreePanel.repaint();
tabbedPane1.setUI(new BasicTabbedPaneUI() {
private final Insets borderInsets = new Insets(0, 0, 0, 0);
tabbedPane1.setUI(new TabbedPaneUI());
@Override
protected void paintContentBorder(Graphics g, int tabPlacement, int selectedIndex) {
}
@Override
protected Insets getContentBorderInsets(int tabPlacement) {
return borderInsets;
}
@Override
protected int calculateTabAreaHeight(int tab_placement, int run_count, int max_tab_height) {
return -5;
}
});
Insets x = new Insets(5, 5, 5, 5);
Insets x = new Insets(5, 15, 5, 0);
settingsPanelButton.setMargin(x);
updatePanelButton.setMargin(x);
playPanelButton.setMargin(x);
@ -228,7 +224,9 @@ public class LauncherGUI implements Observer {
presetList.setModel(new PresetTableModel());
presetList.setCellRenderer(new PresetListRenderer());
modList.setCellRenderer(new ModListRenderer());
modList.setCellRenderer(new ModListRenderer<String>());
modList.setSelectionModel(new MultiSelectModel());
subtitle.setText(
ArmA3Launcher.config.getString("subtitle")
@ -248,20 +246,26 @@ public class LauncherGUI implements Observer {
aboutClient.setText(ArmA3Launcher.config.getString("name") + " v" + ArmA3Launcher.VERSION);
aboutDeveloperLabel.setText("<html><a href=''>https://gurkengewuerz.de</a></html>");
aboutProjectLabel.setText("<html><a href=''>"+ArmA3Launcher.config.getString("social.github")+"</a></html>");
aboutProjectLabel.setText("<html><a href=''>" + ArmA3Launcher.config.getString("social.github") + "</a></html>");
InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream("disclaimer.html");
if(resourceAsStream != null) {
if (resourceAsStream != null) {
Scanner s = new Scanner(resourceAsStream).useDelimiter("\\A");
String result = s.hasNext() ? s.next() : "";
disclaimer.setText(result);
}
presetNoteTextPane.setHighlighter(null);
presetNoteTextPane.getCaret().setVisible(false);
presetNoteTextPane.setBackground(presetNotePaneWrapper.getBackground());
presetNoteTextPane.setCaretColor(presetNoteTextPane.getBackground());
presetNoteTextPane.setPreferredSize(new Dimension(-1, -1));
aboutCopyrightLabel.setText(aboutCopyrightLabel.getText().replace("{year}", "" + Calendar.getInstance().get(Calendar.YEAR)));
twitterIcon.setBorder(new EmptyBorder(2,2,2,2));
githubIcon.setBorder(new EmptyBorder(2,2,2,2));
twitterIcon.setBorder(new EmptyBorder(2, 2, 2, 2));
githubIcon.setBorder(new EmptyBorder(2, 2, 2, 2));
settingScrollPane.getVerticalScrollBar().setUnitIncrement(16);
updateTreeScrolPane.getVerticalScrollBar().setUnitIncrement(16);
@ -270,16 +274,17 @@ public class LauncherGUI implements Observer {
presetList.addListSelectionListener(e -> {
if (!e.getValueIsAdjusting()) {
PresetTableModel m = (PresetTableModel) presetList.getModel();
Modset modset = (Modset) m.getElementAt(presetList.getSelectedIndex());
Object elementAt = m.getElementAt(presetList.getSelectedIndex());
Modset modset = (Modset) elementAt;
if (modset.getType() == Modset.Type.SERVER) {
if (modset.getType() == Modset.Type.SERVER || modset.getType() == Modset.Type.PLACEHOLDER) {
renamePresetButton.setEnabled(false);
removePresetButtom.setEnabled(false);
} else {
renamePresetButton.setEnabled(true);
removePresetButtom.setEnabled(true);
}
clonePresetButton.setEnabled(true);
clonePresetButton.setEnabled(modset.getType() != Modset.Type.PLACEHOLDER);
updateModList(modset);
}
@ -300,14 +305,11 @@ public class LauncherGUI implements Observer {
collapseAllButton.addActionListener(e -> repoTree.collapseAllNodes());
playPanelButton.addActionListener(e -> tabbedPane1.setSelectedIndex(0));
updatePanelButton.addActionListener(e -> tabbedPane1.setSelectedIndex(1));
changelogButton.addActionListener(e -> {
tabbedPane1.setSelectedIndex(2);
Changelog.refresh();
});
presetPanelButton.addActionListener(e -> tabbedPane1.setSelectedIndex(3));
settingsPanelButton.addActionListener(e -> tabbedPane1.setSelectedIndex(4));
playPanelButton.addActionListener(e -> switchTab(Tab.PLAY));
updatePanelButton.addActionListener(e -> switchTab(Tab.UPDATE));
changelogButton.addActionListener(e -> switchTab(Tab.CHANGELOG));
presetPanelButton.addActionListener(e -> switchTab(Tab.PRESET));
settingsPanelButton.addActionListener(e -> switchTab(Tab.SETTING));
refreshRepoButton.addActionListener(e -> RepositoryManger.getInstance().refreshModset());
expandAllButton.addActionListener(e -> repoTree.expandAllNodes());
@ -315,24 +317,17 @@ public class LauncherGUI implements Observer {
syncCheckAbortButton.addActionListener(e -> fileChecker.stop());
syncCheckButton.addActionListener(e -> {
syncCheckButton.setEnabled(false);
syncCheckAbortButton.setEnabled(true);
syncCheckStatusLabel.setText("Running!");
new Thread(() -> fileChecker.check()).start();
refreshRepoButton.setEnabled(false);
repoTree.setCheckboxesEnabled(false);
repoTree.setCheckboxesChecked(false);
});
syncIntensiveCheckButton.addActionListener(e -> fileCheck(false));
syncFastCheckButton.addActionListener(e -> fileCheck(true));
syncDownloadButton.addActionListener(e -> {
if (!fileChecker.isChecked()) return;
if (lastSynclist == null) return;
syncDownloadButton.setEnabled(false);
syncDownloadAbortButton.setEnabled(true);
syncPauseButton.setEnabled(true);
syncCheckButton.setEnabled(false);
syncIntensiveCheckButton.setEnabled(false);
syncFastCheckButton.setEnabled(false);
refreshRepoButton.setEnabled(false);
new Thread(() -> syncer.sync(lastSynclist.clone())).start();
});
@ -350,7 +345,7 @@ public class LauncherGUI implements Observer {
@Override
public void mouseExited(MouseEvent e) {
twitterIcon.setBorder(new EmptyBorder(2,2,2,2));
twitterIcon.setBorder(new EmptyBorder(2, 2, 2, 2));
}
});
@ -362,14 +357,14 @@ public class LauncherGUI implements Observer {
@Override
public void mouseExited(MouseEvent e) {
githubIcon.setBorder(new EmptyBorder(2,2,2,2));
githubIcon.setBorder(new EmptyBorder(2, 2, 2, 2));
}
});
aboutLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
tabbedPane1.setSelectedIndex(5);
switchTab(Tab.ABOUT);
}
});
@ -400,6 +395,125 @@ public class LauncherGUI implements Observer {
openURL(ArmA3Launcher.config.getString("social.github"));
}
});
modList.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
if (presetList.getSelectedIndex() == -1) return;
JList<?> list = (JList<?>) e.getSource();
ListModel<?> model = list.getModel();
ListSelectionModel listSelectionModel = list.getSelectionModel();
int minSelectionIndex = listSelectionModel.getMinSelectionIndex();
int maxSelectionIndex = listSelectionModel.getMaxSelectionIndex();
List<String> selectedMods = new ArrayList<>();
for (int i = minSelectionIndex; i <= maxSelectionIndex; i++) {
if (listSelectionModel.isSelectedIndex(i)) {
selectedMods.add(String.valueOf(model.getElementAt(i)));
}
}
PresetTableModel model1 = (PresetTableModel) presetList.getModel();
if (presetList.getSelectedIndex() == -1) return;
Object elementAt = model1.getElementAt(presetList.getSelectedIndex());
Modset selectedModset = (Modset) elementAt;
if (selectedModset.getType() == Modset.Type.PLACEHOLDER) return;
selectedModset.getMods().clear();
selectedModset.setMods(selectedMods);
updateModsetList();
selectedModset.save();
}
});
newPresetButtom.addActionListener(e -> {
String modname = JOptionPane.showInputDialog(null, "", LangUtils.getInstance().getString("new_modset_name"));
if (modname.isEmpty()) return;
if (Modset.MODSET_LIST.containsKey(modname)) {
infoBox(LangUtils.getInstance().getString("modset_exists_msg"), LangUtils.getInstance().getString("modset_exists"));
return;
}
Modset ms = new Modset(modname, new JSONArray(), Modset.Type.CLIENT);
updateModsetList();
ms.save();
});
presetNoteButton.addActionListener(e -> clonePresetButton.doClick());
clonePresetButton.addActionListener(e -> {
if (presetList.getSelectedIndex() == -1) return;
String newName = JOptionPane.showInputDialog(null, "", LangUtils.getInstance().getString("new_modset_name"));
if (newName.isEmpty()) return;
if (Modset.MODSET_LIST.containsKey(newName)) {
infoBox(LangUtils.getInstance().getString("modset_exists_msg"), LangUtils.getInstance().getString("modset_exists"));
return;
}
PresetTableModel model1 = (PresetTableModel) presetList.getModel();
Modset selectedModset = ((Modset) model1.getElementAt(presetList.getSelectedIndex()));
Modset newModset = selectedModset.clone(newName, Modset.Type.CLIENT);
updateModsetList();
newModset.save();
});
removePresetButtom.addActionListener(e -> {
if (presetList.getSelectedIndex() == -1) return;
modList.setModel(new DefaultListModel<>());
PresetTableModel model1 = (PresetTableModel) presetList.getModel();
((Modset) model1.getElementAt(presetList.getSelectedIndex())).removeFromConfig();
updateModsetList();
});
renamePresetButton.addActionListener(e -> {
if (presetList.getSelectedIndex() == -1) return;
PresetTableModel model1 = (PresetTableModel) presetList.getModel();
Modset selectedModset = ((Modset) model1.getElementAt(presetList.getSelectedIndex()));
Object newNameO = JOptionPane.showInputDialog(null, "",
LangUtils.getInstance().getString("new_modset_name"), JOptionPane.QUESTION_MESSAGE, null, null, selectedModset.getName());
if(newNameO == null) return;
String newName = (String) newNameO;
if (newName.isEmpty()) return;
if (Modset.MODSET_LIST.containsKey(newName)) {
infoBox(LangUtils.getInstance().getString("modset_exists_msg"), LangUtils.getInstance().getString("modset_exists"));
return;
}
Modset newModset = selectedModset.clone(newName, Modset.Type.CLIENT);
updateModsetList();
selectedModset.removeFromConfig();
newModset.save();
});
syncPresetCombo.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
DefaultComboBoxModel<Modset> model = (DefaultComboBoxModel<Modset>) syncPresetCombo.getModel();
Modset elementAt = model.getElementAt(((JComboBox) e.getItemSelectable()).getSelectedIndex());
repoTree.setCheckboxesChecked(false);
if(elementAt.getType() == Modset.Type.PLACEHOLDER) return;
List<String> collect = elementAt.getMods().stream().map(Mod::getName).collect(Collectors.toList());
DefaultTreeModel repoModel = (DefaultTreeModel) repoTree.getModel();
RepositoryTreeNode root = (RepositoryTreeNode) repoModel.getRoot();
for (int i = 0; i < root.getChildCount(); i++) {
TreeNode childAt = root.getChildAt(i);
if(!collect.contains(childAt.toString())) continue;
final TreePath treePath = new TreePath(new TreeNode[]{root, childAt});
repoTree.checkSubTree(treePath, true);
repoTree.updatePredecessorsWithCheckMode(treePath, true);
}
repoTree.revalidate();
repoTree.repaint();
updateDownloadLabel();
}
}
});
}
public static void infoBox(String infoMessage, String titleBar) {
@ -438,13 +552,15 @@ public class LauncherGUI implements Observer {
if (SteamTimer.arma_running) {
playButton.setEnabled(false);
playPresetButton.setEnabled(false);
syncCheckButton.setEnabled(false);
syncIntensiveCheckButton.setEnabled(false);
syncFastCheckButton.setEnabled(false);
refreshRepoButton.setEnabled(false);
syncDownloadButton.setEnabled(false);
playButton.setToolTipText(LangUtils.getInstance().getString("arma_running"));
playPresetButton.setToolTipText(LangUtils.getInstance().getString("arma_running"));
syncCheckButton.setToolTipText(LangUtils.getInstance().getString("arma_running"));
syncIntensiveCheckButton.setToolTipText(LangUtils.getInstance().getString("arma_running"));
syncFastCheckButton.setToolTipText(LangUtils.getInstance().getString("arma_running"));
} else {
if (SteamTimer.steam_running) {
if (pathSet) {
@ -469,20 +585,23 @@ public class LauncherGUI implements Observer {
}
if (pathSet) {
syncCheckButton.setEnabled(true);
syncIntensiveCheckButton.setEnabled(true);
syncFastCheckButton.setEnabled(true);
refreshRepoButton.setEnabled(true);
syncDownloadButton.setEnabled(fileChecker.isChecked());
syncCheckButton.setToolTipText(null);
syncIntensiveCheckButton.setToolTipText(null);
refreshRepoButton.setToolTipText(null);
} else {
syncCheckButton.setEnabled(false);
syncIntensiveCheckButton.setEnabled(false);
syncFastCheckButton.setEnabled(false);
refreshRepoButton.setEnabled(false);
syncDownloadButton.setEnabled(false);
syncCheckButton.setToolTipText(LangUtils.getInstance().getString("path_not_set"));
syncIntensiveCheckButton.setToolTipText(LangUtils.getInstance().getString("path_not_set"));
syncFastCheckButton.setToolTipText(LangUtils.getInstance().getString("path_not_set"));
refreshRepoButton.setToolTipText(LangUtils.getInstance().getString("path_not_set"));
}
}
@ -664,7 +783,7 @@ public class LauncherGUI implements Observer {
if (!isSelected) continue;
ArrayList<String> treePathList = new ArrayList<>();
for (int i = 2; i < path.length; i++) {
for (int i = (path.length > 2 ? 2 : 1); i < path.length; i++) {
treePathList.add(String.valueOf(((DefaultMutableTreeNode) path[i]).getUserObject()));
}
String treePath = String.join("/", treePathList);
@ -693,14 +812,33 @@ public class LauncherGUI implements Observer {
return synclist;
}
public void updateModList(Modset modset) {
ListModel<String> model = (ListModel) modList.getModel();
// TODO: Show All Mods (keyname)
// Show not installed Mods with red font
// Select Mod if in modset.Mods
// Custom Checkbox Render
// Wenn modset.type == Server alle Checkboxen deaktivieren!
// Show hint that server modsets cant be edited
public void updateModList(final Modset modset) {
if (modset == null) return;
DefaultListModel<String> listModel = new DefaultListModel<>();
if (modset.getType() == Modset.Type.PLACEHOLDER) return;
int[] select = new int[modset.getMods().size()];
AtomicInteger selectCounter = new AtomicInteger(0);
RepositoryManger.MOD_LIST.stream()
.filter((am) -> am instanceof Mod)
.sorted()
.forEach((abstractMod) -> {
final int i = listModel.getSize();
listModel.add(i, abstractMod.getName());
for (Mod mod : modset.getMods()) {
if (mod.getName().equals(abstractMod.getName())) {
select[selectCounter.getAndIncrement()] = i;
break;
}
}
});
modList.setModel(listModel);
modList.setSelectedIndices(select);
modList.setEnabled(modset.getType() != Modset.Type.SERVER);
presetNotePane.setVisible(modset.getType() == Modset.Type.SERVER);
modList.revalidate();
}
public void updateRepoTree() {
@ -769,17 +907,9 @@ public class LauncherGUI implements Observer {
repoTree.addCheckChangeEventListener(new JCheckBoxTree.CheckChangeEventListener() {
@Override
public void checkStateChanged(JCheckBoxTree.CheckChangeEvent event) {
lastSynclist = getSyncList();
if (lastSynclist.getSize() != 0)
syncSizeLabel.setText("0.0 B/" + Humanize.binaryPrefix(lastSynclist.getSize()));
else syncSizeLabel.setText("0.0 B/0.0 B");
if (lastSynclist.getCount() != 0) {
syncDownloadButton.setEnabled(true);
syncFileCountLabel.setText("0/" + lastSynclist.getCount());
} else {
syncDownloadButton.setEnabled(false);
syncFileCountLabel.setText("");
}
syncPresetCombo.setSelectedIndex(0);
updateDownloadLabel();
}
});
@ -787,6 +917,20 @@ public class LauncherGUI implements Observer {
collapseAllButton.setEnabled(true);
}
public void updateDownloadLabel() {
lastSynclist = getSyncList();
if (lastSynclist.getSize() != 0)
syncSizeLabel.setText("0.0 B/" + Humanize.binaryPrefix(lastSynclist.getSize()));
else syncSizeLabel.setText("0.0 B/0.0 B");
if (lastSynclist.getCount() != 0) {
syncDownloadButton.setEnabled(true);
syncFileCountLabel.setText("0/" + lastSynclist.getCount());
} else {
syncDownloadButton.setEnabled(false);
syncFileCountLabel.setText("");
}
}
public Color getNodeColor(String mod, ModFile mf) {
if (fileChecker.getAdded().containsKey(mod)) {
ArrayList<ModFile> mfList = fileChecker.getAdded().get(mod);
@ -863,7 +1007,7 @@ public class LauncherGUI implements Observer {
@Override
public void update(String s) {
System.out.println(s);
Logger.getLogger(getClass().getName()).log(Level.INFO, "Observer received: " + s);
if (s.equals(RepositoryManger.Type.METADATA.toString())) {
switch (RepositoryManger.getInstance().getStatus(RepositoryManger.Type.METADATA)) {
case ERROR:
@ -878,16 +1022,7 @@ public class LauncherGUI implements Observer {
Server.SERVER_LIST.forEach((name, server) -> model.add(server));
});
SwingUtilities.invokeLater(() -> {
PresetTableModel model = (PresetTableModel) presetList.getModel();
model.clear();
model.add(new Modset("--Server", Modset.Type.CLIENT, null, false));
Modset.MODSET_LIST.forEach((name, set) -> {
model.add(set);
});
});
updateModsetList();
break;
}
} else if (s.equals("steamtimer")) {
@ -918,7 +1053,8 @@ public class LauncherGUI implements Observer {
});
}
} else if (s.equals("fileChecker")) {
syncCheckButton.setEnabled(true);
syncIntensiveCheckButton.setEnabled(true);
syncFastCheckButton.setEnabled(true);
syncCheckAbortButton.setEnabled(false);
syncCheckStatusLabel.setText("Finished!");
updateRepoTree();
@ -933,9 +1069,14 @@ public class LauncherGUI implements Observer {
syncDownloadButton.setEnabled(true);
syncPauseButton.setEnabled(false);
refreshRepoButton.setEnabled(true);
syncChangedFileSizeLabel.setText(Humanize.binaryPrefix(fileChecker.getSize()));
lastSynclist = null;
} else if (s.equals("fileCheckerStopped")) {
syncCheckButton.setEnabled(true);
syncIntensiveCheckButton.setEnabled(true);
syncFastCheckButton.setEnabled(true);
syncCheckAbortButton.setEnabled(false);
syncCheckProgress.setValue(0);
syncCheckStatusLabel.setText("Failed!");
@ -954,8 +1095,9 @@ public class LauncherGUI implements Observer {
syncChangedFileSizeLabel.setText("0.0 B");
lastSynclist = null;
} else if (s.equals("syncStopped")) {
new Thread(() -> fileChecker.check()).start();
new Thread(() -> fileChecker.check(true)).start();
SwingUtilities.invokeLater(() -> {
syncDownloadButton.setEnabled(false);
syncDownloadAbortButton.setEnabled(false);
@ -967,7 +1109,7 @@ public class LauncherGUI implements Observer {
TaskBarUtils.getInstance().off();
});
} else if (s.equals("syncComplete")) {
new Thread(() -> fileChecker.check()).start();
new Thread(() -> fileChecker.check(true)).start();
SwingUtilities.invokeLater(() -> {
syncDownloadButton.setEnabled(false);
syncDownloadAbortButton.setEnabled(false);
@ -1001,6 +1143,41 @@ public class LauncherGUI implements Observer {
}
}
private void updateModsetList() {
SwingUtilities.invokeLater(() -> {
if (((DefaultComboBoxModel<Modset>)syncPresetCombo.getModel()).getSize() > 0){
syncPresetCombo.setSelectedIndex(0);
}
PresetTableModel model = (PresetTableModel) presetList.getModel();
model.clear();
model.add(new Modset("--Server", Modset.Type.PLACEHOLDER, null, false));
Modset.MODSET_LIST.values().stream().filter((ms) -> ms.getType() == Modset.Type.SERVER).sorted().forEach(model::add);
model.add(new Modset("--User", Modset.Type.PLACEHOLDER, null, false));
Modset.MODSET_LIST.values().stream().filter((ms) -> ms.getType() == Modset.Type.CLIENT).sorted().forEach(model::add);
DefaultComboBoxModel<Modset> presetModel = new DefaultComboBoxModel<>();
presetModel.addElement(new Modset("", Modset.Type.PLACEHOLDER, null, false));
Modset.MODSET_LIST.values().stream().filter((ms) -> ms.getType() != Modset.Type.PLACEHOLDER).sorted().forEach(presetModel::addElement);
syncPresetCombo.setModel(presetModel);
});
}
public void fileCheck(boolean fastscan) {
syncIntensiveCheckButton.setEnabled(false);
syncFastCheckButton.setEnabled(false);
syncCheckAbortButton.setEnabled(true);
syncCheckStatusLabel.setText("Running!");
new Thread(() -> fileChecker.check(fastscan)).start();
refreshRepoButton.setEnabled(false);
repoTree.setCheckboxesEnabled(false);
repoTree.setCheckboxesChecked(false);
}
public void exit() {
fileChecker.stop();
syncer.stop();
@ -1012,4 +1189,59 @@ public class LauncherGUI implements Observer {
} catch (Exception ignored) {
}
}
public void switchTab(Tab tab) {
Color focusBackgroundColor = UIManager.getColor("Button.default.focusColor");
Color backgroundColor = UIManager.getColor("Button.background");
playPanelButton.setBackground(backgroundColor);
updatePanelButton.setBackground(backgroundColor);
changelogButton.setBackground(backgroundColor);
presetPanelButton.setBackground(backgroundColor);
settingsPanelButton.setBackground(backgroundColor);
switch (tab) {
case PLAY:
playPanelButton.setBackground(focusBackgroundColor);
break;
case UPDATE:
updatePanelButton.setBackground(focusBackgroundColor);
break;
case CHANGELOG:
changelogButton.setBackground(focusBackgroundColor);
Changelog.refresh();
break;
case PRESET:
presetPanelButton.setBackground(focusBackgroundColor);
break;
case SETTING:
settingsPanelButton.setBackground(focusBackgroundColor);
break;
}
tabbedPane1.setSelectedIndex(tab.getIndex());
}
private enum Tab {
PLAY(0),
UPDATE(1),
CHANGELOG(2),
PRESET(3),
SETTING(4),
ABOUT(5);
private int index;
Tab(int index) {
this.index = index;
}
public int getIndex() {
return index;
}
}
}

View File

@ -233,7 +233,7 @@ public class JCheckBoxTree extends JTree {
}
// When a node is checked/unchecked, updating the states of the predecessors
protected void updatePredecessorsWithCheckMode(TreePath tp, boolean check) {
public void updatePredecessorsWithCheckMode(TreePath tp, boolean check) {
TreePath parentPath = tp.getParentPath();
// If it is the root, stop the recursive calls and return
if (parentPath == null) {
@ -266,7 +266,7 @@ public class JCheckBoxTree extends JTree {
}
// Recursively checks/unchecks a subtree
protected void checkSubTree(TreePath tp, boolean check) {
public void checkSubTree(TreePath tp, boolean check) {
CheckedNode cn = nodesCheckingState.get(tp);
cn.isSelected = check;
DefaultMutableTreeNode node = (DefaultMutableTreeNode) tp.getLastPathComponent();

View File

@ -4,22 +4,28 @@ import javax.swing.*;
import java.awt.*;
/**
* Created by gurkengewuerz.de on 25.03.2020.
* Created by gurkengewuerz.de on 28.03.2020.
*/
public class ModListRenderer extends JCheckBox implements ListCellRenderer {
public class ModListRenderer<E> extends JCheckBox implements
ListCellRenderer<E> {
public Component getListCellRendererComponent(JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
private static final long serialVersionUID = 3734536442230283966L;
@Override
public Component getListCellRendererComponent(JList<? extends E> list,
E value, int index, boolean isSelected, boolean cellHasFocus) {
setComponentOrientation(list.getComponentOrientation());
setFont(list.getFont());
setText(String.valueOf(value));
setBackground(list.getBackground());
setForeground(list.getForeground());
setSelected(isSelected);
setEnabled(list.isEnabled());
setText(value == null ? "" : value.toString());
return this;
}
}
}

View File

@ -0,0 +1,35 @@
package de.mc8051.arma3launcher.model;
import javax.swing.*;
/**
* Created by gurkengewuerz.de on 28.03.2020.
*/
public class MultiSelectModel extends DefaultListSelectionModel {
private int i0 = -1;
private int i1 = -1;
public void setSelectionInterval(int index0, int index1) {
if (i0 == index0 && i1 == index1) {
if (getValueIsAdjusting()) {
setValueIsAdjusting(false);
setSelection(index0, index1);
}
} else {
i0 = index0;
i1 = index1;
setValueIsAdjusting(false);
setSelection(index0, index1);
}
}
private void setSelection(int index0, int index1) {
if (super.isSelectedIndex(index0)) {
super.removeSelectionInterval(index0, index1);
} else {
super.addSelectionInterval(index0, index1);
}
}
}

View File

@ -0,0 +1,26 @@
package de.mc8051.arma3launcher.model;
import javax.swing.plaf.basic.BasicTabbedPaneUI;
import java.awt.*;
/**
* Created by gurkengewuerz.de on 28.03.2020.
*/
public class TabbedPaneUI extends BasicTabbedPaneUI {
private final Insets borderInsets = new Insets(0, 0, 0, 0);
@Override
protected void paintContentBorder(Graphics g, int tabPlacement, int selectedIndex) {
}
@Override
protected Insets getContentBorderInsets(int tabPlacement) {
return borderInsets;
}
@Override
protected int calculateTabAreaHeight(int tab_placement, int run_count, int max_tab_height) {
return -5;
}
}

View File

@ -5,7 +5,7 @@ import java.util.ArrayList;
/**
* Created by gurkengewuerz.de on 25.03.2020.
*/
public class Mod implements AbstractMod {
public class Mod implements AbstractMod, Comparable {
private String name;
private long size;
@ -37,4 +37,9 @@ public class Mod implements AbstractMod {
public Mod clone() {
return new Mod(name, size, new ArrayList<>(files));
}
@Override
public int compareTo(Object o) {
return getName().compareToIgnoreCase(((Mod) o).getName());
}
}

View File

@ -1,16 +1,22 @@
package de.mc8051.arma3launcher.objects;
import de.mc8051.arma3launcher.ArmA3Launcher;
import org.ini4j.Ini;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.IOException;
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 25.03.2020.
*/
public class Modset {
public class Modset implements Comparable {
public static HashMap<String, Modset> MODSET_LIST = new HashMap<>();
@ -27,23 +33,69 @@ public class Modset {
this.type = type;
this.mods = mods;
if(add) MODSET_LIST.put(name, this);
if (add) MODSET_LIST.put(name, this);
}
public Modset(JSONObject o, Type type) {
if(!o.has("name") || !o.has("mods")) return;
name = o.getString("name");
JSONArray modlist = o.getJSONArray("mods");
for(int j = 0; j < modlist.length(); j++){
public Modset(String name, JSONArray modlist, Type type) {
for (int j = 0; j < modlist.length(); j++) {
mods.add(new Mod(modlist.getString(j)));
}
this.type = type;
this.name = name;
MODSET_LIST.put(name, this);
}
public Modset(JSONObject o, Type type) {
this(o.getString("name"), o.getJSONArray("mods"), type);
}
public void save() {
if (type != Type.CLIENT) return;
Ini.Section section = ArmA3Launcher.user_config.get("presets");
if (section == null) {
section = ArmA3Launcher.user_config.add("presets");
}
if (section != null) {
List<String> list = mods.stream()
.map(Mod::getName)
.collect(Collectors.toList());
JSONArray ja = new JSONArray(list);
if (section.containsKey(name))
section.replace(name, ja.toString());
else
section.add(name, ja.toString());
try {
ArmA3Launcher.user_config.store();
} catch (IOException e) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e);
}
}
}
public void removeFromConfig() {
MODSET_LIST.remove(name);
if (type != Type.CLIENT) return;
Ini.Section section = ArmA3Launcher.user_config.get("presets");
if (section != null) {
if (section.containsKey(name)) {
section.remove(name);
try {
ArmA3Launcher.user_config.store();
} catch (IOException e) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e);
}
}
}
}
public String getName() {
return name;
}
@ -60,8 +112,31 @@ public class Modset {
// TODO: Implement play with this Modset
}
public Modset clone(String newName, Type newType) {
return new Modset(newName, newType, new ArrayList<>(mods));
}
public Modset clone() {
return new Modset(name, type, mods, false);
}
public void setMods(List<String> selectedMods) {
mods.addAll(selectedMods.stream().map(Mod::new).collect(Collectors.toList()));
}
@Override
public int compareTo(Object o) {
return getName().compareToIgnoreCase(((Modset) o).getName());
}
public static enum Type {
SERVER,
CLIENT
CLIENT,
PLACEHOLDER;
}
@Override
public String toString() {
return getName();
}
}

View File

@ -8,9 +8,7 @@ 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;
@ -45,6 +43,10 @@ public class FileChecker implements Observable {
}
public void check() {
check(false);
}
public void check(boolean fastscan) {
deleted.clear();
changed.clear();
changedCount = 0;
@ -59,16 +61,16 @@ public class FileChecker implements Observable {
});
for (AbstractMod abstractMod : RepositoryManger.MOD_LIST) {
if(stop) {
if (stop) {
stop = false;
notifyObservers("fileCheckerStopped");
return;
}
if(abstractMod instanceof Mod) {
if (abstractMod instanceof Mod) {
Mod m = (Mod) abstractMod;
for (ModFile mf : m.getFiles()) {
checkFile(m.getName(), mf);
checkFile(m.getName(), mf, fastscan);
i++;
int finalI = i;
@ -76,7 +78,7 @@ public class FileChecker implements Observable {
pb.setValue(finalI);
});
if(stop) {
if (stop) {
stop = false;
notifyObservers("fileCheckerStopped");
return;
@ -84,7 +86,7 @@ public class FileChecker implements Observable {
}
} else if (abstractMod instanceof ModFile) {
ModFile mf = (ModFile) abstractMod;
checkFile(mf.getName(), mf);
checkFile(mf.getName(), mf, fastscan);
i++;
int finalI1 = i;
SwingUtilities.invokeLater(() -> {
@ -106,11 +108,11 @@ public class FileChecker implements Observable {
stop = true;
}
private void checkFile(String mod, ModFile mf) {
private void checkFile(String mod, ModFile mf, boolean fastscan) {
ArrayList<ModFile> temp = new ArrayList<>();
if(!mf.exists()) {
if(added.containsKey(mod)) temp =added.get(mod);
if (!mf.exists()) {
if (added.containsKey(mod)) temp = added.get(mod);
temp.add(mf);
added.put(mod, temp);
addedCount++;
@ -118,19 +120,22 @@ public class FileChecker implements Observable {
return;
}
if(mf.getLocalSize() != mf.getSize() || !mf.getSHA1Sum().equalsIgnoreCase(mf.getLocalGeneratedSHA1Sum())) {
if(changed.containsKey(mod)) temp =changed.get(mod);
temp.add(mf);
changed.put(mod, temp);
changedCount++;
size += mf.getSize();
return;
if (fastscan || !mf.getSHA1Sum().equalsIgnoreCase(mf.getLocalGeneratedSHA1Sum())) {
if (mf.getLocalSize() != mf.getSize()) {
if (changed.containsKey(mod)) temp = changed.get(mod);
temp.add(mf);
changed.put(mod, temp);
changedCount++;
size += mf.getSize();
return;
}
}
}
private void checkDeleted() {
String modPath = ArmA3Launcher.user_config.get("client", "modPath");
if(modPath == null) modPath = "";
if (modPath == null) modPath = "";
try {
List<Path> filePathList = Files.find(Paths.get(modPath),
@ -144,7 +149,7 @@ public class FileChecker implements Observable {
outerloop:
for (AbstractMod abstractMod : RepositoryManger.MOD_LIST) {
if(abstractMod instanceof Mod) {
if (abstractMod instanceof Mod) {
Mod m = (Mod) abstractMod;
for (ModFile mf : m.getFiles()) {

View File

@ -10,6 +10,7 @@ import de.mc8051.arma3launcher.objects.ModFile;
import de.mc8051.arma3launcher.objects.Modset;
import de.mc8051.arma3launcher.objects.Server;
import de.mc8051.arma3launcher.utils.Callback;
import org.ini4j.Ini;
import org.json.JSONArray;
import org.json.JSONObject;
@ -27,6 +28,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import static java.time.temporal.ChronoUnit.SECONDS;
@ -93,10 +95,19 @@ public class RepositoryManger implements Observable {
}
try {
Modset.MODSET_LIST.clear();
Ini.Section section = ArmA3Launcher.user_config.get("presets");
if (section != null) {
for (String key : section.keySet()) {
String jsonString = section.get(key);
JSONArray ja = new JSONArray(jsonString);
new Modset(key, ja, Modset.Type.CLIENT);
}
}
JSONObject jsonObject = new JSONObject(r.getBody());
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++) {

View File

@ -1,6 +1,6 @@
{
"name": "TheTown Client",
"title": "Welcome! :P",
"title": "Willkommen!",
"subtitle": "${name} v${version}",
"sync": {
"useragent": "TheTownSyncer",

View File

@ -29,7 +29,7 @@ nicht jeder Fehler unsererseits behoben werden kann.
<br/>
<br/>
<h1>Licenses</h1>
<h3>de.mc8051.arma3launcher</h3>
<h2>de.mc8051.arma3launcher</h2>
<tt>
MIT License<br/>
<br/>
@ -54,7 +54,7 @@ nicht jeder Fehler unsererseits behoben werden kann.
SOFTWARE.<br/>
</tt>
<br/>
<h3>com.formdev.flatlaf</h3>
<h2>com.formdev.flatlaf</h2>
<a href="">https://github.com/JFormDesigner/FlatLaf</a><br/>
<tt>
Copyright 2019 FormDev Software GmbH<br/>
@ -72,7 +72,7 @@ nicht jeder Fehler unsererseits behoben werden kann.
limitations under the License.<br/>
</tt>
<br/>
<h3>co.bitshfted.xapps.zsync</h3>
<h2>co.bitshfted.xapps.zsync</h2>
<a href="">https://github.com/bitshifted/zsyncer</a><br/>
<tt>
Copyright (c) 2015, Salesforce.com, Inc. All rights reserved.<br/>
@ -99,7 +99,7 @@ nicht jeder Fehler unsererseits behoben werden kann.
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.<br/>
</tt>
<br/>
<h3>com.github.RalleYTN.SimpleRegistry</h3>
<h2>com.github.RalleYTN.SimpleRegistry</h2>
<a href="">https://github.com/RalleYTN/SimpleRegistry</a><br/>
<tt>
MIT License<br/>
@ -125,7 +125,7 @@ nicht jeder Fehler unsererseits behoben werden kann.
SOFTWARE.<br/>
</tt>
<br/>
<h3>com.typesafe.config</h3>
<h2>com.typesafe.config</h2>
<a href="">https://github.com/lightbend/config</a><br/>
<tt>
Copyright (C) 2011-2012 Typesafe Inc. http://typesafe.com<br/>
@ -143,7 +143,7 @@ nicht jeder Fehler unsererseits behoben werden kann.
limitations under the License.<br/>
</tt>
<br/>
<h3>org.ini4j.ini4j</h3>
<h2>org.ini4j.ini4j</h2>
<a href="">https://github.com/facebookarchive/ini4j</a><br/>
<tt>
Copyright 2005,2009 Ivan SZKIBA<br/>
@ -160,7 +160,7 @@ nicht jeder Fehler unsererseits behoben werden kann.
See the License for the specific language governing permissions and<br/>
limitations under the License.<br/>
</tt>
<h3>org.json.json</h3>
<h2>org.json.json</h2>
<a href="">https://json.org</a><br/>
<tt>
Copyright (c) 2018 JSON.org<br/>
@ -185,5 +185,35 @@ nicht jeder Fehler unsererseits behoben werden kann.
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE<br/>
SOFTWARE.<br/>
</tt>
<h2>com.jgoodies.forms</h2>
<tt>
Copyright (c) 2002-2015 JGoodies Software GmbH. All Rights Reserved.<br/>
<br/>
Redistribution and use in source and binary forms, with or without<br/>
modification, are permitted provided that the following conditions are met:<br/>
<br/>
o Redistributions of source code must retain the above copyright notice,<br/>
this list of conditions and the following disclaimer.<br/>
<br/>
o Redistributions in binary form must reproduce the above copyright notice,<br/>
this list of conditions and the following disclaimer in the documentation<br/>
and/or other materials provided with the distribution.<br/>
<br/>
o Neither the name of JGoodies Software GmbH nor the names of<br/>
its contributors may be used to endorse or promote products derived<br/>
from this software without specific prior written permission.<br/>
<br/>
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"<br/>
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,<br/>
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR<br/>
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR<br/>
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,<br/>
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,<br/>
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;<br/>
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,<br/>
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE<br/>
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,<br/>
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.<br/>
</tt>
</body>
</html>

View File

@ -101,4 +101,12 @@ follow_on_twitter=Folgt und auf Twitter
star_on_github="Star us" auf GitHub
client_up_to_date=Client ist aktuell
developer_page=Entwickler-Seite
project_page=Projektseite
project_page=Projektseite
fast_check=Schnelle Prüfung
intensive_check=Intensive Prüfung
note=Hinweis
presets_note=Vorlagen können nur als Vorlage für neue User-Vorlagen verwendet werden. Du kannst eine eigene Vorlage auf Bases dieser Server Vorlage erstellen. Dabei wird die Liste aler Mods übernommen.
clone_preset=Vorlage klonen
new_modset_name=Modsset Name
modset_exists_msg=Bitte wähle ein anderen Namen für deine Vorlage.
modset_exists=Preset mit diesen Namen existiert bereits

View File

@ -99,4 +99,12 @@ follow_on_twitter=Follow us on Twitter
star_on_github=Star us on GitHub
client_up_to_date=Client is up to date
developer_page=Developer page
project_page=Project page
project_page=Project page
new_modset_name=Modsset name
intensive_check=Intensive check
fast_check=Fast check
note=Note
presets_note=Presets can only be used as preset for new user presents. You can create your own custom preset based on this server preset. The list of all mods will be used.
clone_preset=Clone preset
modset_exists_msg=Please choose another name for your preset.
modset_exists=Preset with these names already exists