diff --git a/pom.xml b/pom.xml
index 5c46cb4..babbbbf 100644
--- a/pom.xml
+++ b/pom.xml
@@ -46,6 +46,11 @@
zsyncer
1de0d3f651
+
+ com.jgoodies
+ jgoodies-forms
+ 1.9.0
+
diff --git a/src/main/java/de/mc8051/arma3launcher/LauncherGUI.form b/src/main/java/de/mc8051/arma3launcher/LauncherGUI.form
index 93864aa..d7f9864 100644
--- a/src/main/java/de/mc8051/arma3launcher/LauncherGUI.form
+++ b/src/main/java/de/mc8051/arma3launcher/LauncherGUI.form
@@ -42,10 +42,14 @@
+
-
+
+
+
+
@@ -64,8 +68,11 @@
+
+
+
@@ -75,8 +82,11 @@
+
+
+
@@ -168,8 +178,11 @@
+
+
+
@@ -180,8 +193,11 @@
+
+
+
@@ -445,20 +461,24 @@
-
+
-
+
-
+
-
+
-
+
+
+
+
+
@@ -561,23 +581,25 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
@@ -585,31 +607,17 @@
-
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -617,15 +625,44 @@
-
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -793,7 +830,7 @@
-
+
@@ -945,10 +982,78 @@
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1033,7 +1138,9 @@
-
+
+
+
diff --git a/src/main/java/de/mc8051/arma3launcher/LauncherGUI.java b/src/main/java/de/mc8051/arma3launcher/LauncherGUI.java
index f5d67a9..a14b39a 100644
--- a/src/main/java/de/mc8051/arma3launcher/LauncherGUI.java
+++ b/src/main/java/de/mc8051/arma3launcher/LauncherGUI.java
@@ -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());
+
+ 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("https://gurkengewuerz.de");
- aboutProjectLabel.setText(""+ArmA3Launcher.config.getString("social.github")+"");
+ aboutProjectLabel.setText("" + ArmA3Launcher.config.getString("social.github") + "");
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 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 model = (DefaultComboBoxModel) syncPresetCombo.getModel();
+ Modset elementAt = model.getElementAt(((JComboBox) e.getItemSelectable()).getSelectedIndex());
+ repoTree.setCheckboxesChecked(false);
+ if(elementAt.getType() == Modset.Type.PLACEHOLDER) return;
+
+ List 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 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 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 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 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)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 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;
+ }
+ }
}
diff --git a/src/main/java/de/mc8051/arma3launcher/model/JCheckBoxTree.java b/src/main/java/de/mc8051/arma3launcher/model/JCheckBoxTree.java
index 6fd9d19..ef6eb4a 100644
--- a/src/main/java/de/mc8051/arma3launcher/model/JCheckBoxTree.java
+++ b/src/main/java/de/mc8051/arma3launcher/model/JCheckBoxTree.java
@@ -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();
diff --git a/src/main/java/de/mc8051/arma3launcher/model/ModListRenderer.java b/src/main/java/de/mc8051/arma3launcher/model/ModListRenderer.java
index 32805ac..616b4fd 100644
--- a/src/main/java/de/mc8051/arma3launcher/model/ModListRenderer.java
+++ b/src/main/java/de/mc8051/arma3launcher/model/ModListRenderer.java
@@ -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 extends JCheckBox implements
+ ListCellRenderer {
- 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;
}
-}
+
+}
\ No newline at end of file
diff --git a/src/main/java/de/mc8051/arma3launcher/model/MultiSelectModel.java b/src/main/java/de/mc8051/arma3launcher/model/MultiSelectModel.java
new file mode 100644
index 0000000..bef32ec
--- /dev/null
+++ b/src/main/java/de/mc8051/arma3launcher/model/MultiSelectModel.java
@@ -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);
+ }
+ }
+
+}
diff --git a/src/main/java/de/mc8051/arma3launcher/model/TabbedPaneUI.java b/src/main/java/de/mc8051/arma3launcher/model/TabbedPaneUI.java
new file mode 100644
index 0000000..be7d07d
--- /dev/null
+++ b/src/main/java/de/mc8051/arma3launcher/model/TabbedPaneUI.java
@@ -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;
+ }
+}
diff --git a/src/main/java/de/mc8051/arma3launcher/objects/Mod.java b/src/main/java/de/mc8051/arma3launcher/objects/Mod.java
index 8cd32a7..fd5e6f6 100644
--- a/src/main/java/de/mc8051/arma3launcher/objects/Mod.java
+++ b/src/main/java/de/mc8051/arma3launcher/objects/Mod.java
@@ -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());
+ }
}
diff --git a/src/main/java/de/mc8051/arma3launcher/objects/Modset.java b/src/main/java/de/mc8051/arma3launcher/objects/Modset.java
index 1df8f63..b1b28de 100644
--- a/src/main/java/de/mc8051/arma3launcher/objects/Modset.java
+++ b/src/main/java/de/mc8051/arma3launcher/objects/Modset.java
@@ -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 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 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 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();
}
}
diff --git a/src/main/java/de/mc8051/arma3launcher/repo/FileChecker.java b/src/main/java/de/mc8051/arma3launcher/repo/FileChecker.java
index 1787827..e2fbee0 100644
--- a/src/main/java/de/mc8051/arma3launcher/repo/FileChecker.java
+++ b/src/main/java/de/mc8051/arma3launcher/repo/FileChecker.java
@@ -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 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 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()) {
diff --git a/src/main/java/de/mc8051/arma3launcher/repo/RepositoryManger.java b/src/main/java/de/mc8051/arma3launcher/repo/RepositoryManger.java
index aa202f8..dffd8a4 100644
--- a/src/main/java/de/mc8051/arma3launcher/repo/RepositoryManger.java
+++ b/src/main/java/de/mc8051/arma3launcher/repo/RepositoryManger.java
@@ -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++) {
diff --git a/src/main/resources/arma3launcher.json b/src/main/resources/arma3launcher.json
index ce1dec0..749a833 100644
--- a/src/main/resources/arma3launcher.json
+++ b/src/main/resources/arma3launcher.json
@@ -1,6 +1,6 @@
{
"name": "TheTown Client",
- "title": "Welcome! :P",
+ "title": "Willkommen!",
"subtitle": "${name} v${version}",
"sync": {
"useragent": "TheTownSyncer",
diff --git a/src/main/resources/disclaimer.html b/src/main/resources/disclaimer.html
index 9ead04c..1a6b68a 100644
--- a/src/main/resources/disclaimer.html
+++ b/src/main/resources/disclaimer.html
@@ -29,7 +29,7 @@ nicht jeder Fehler unsererseits behoben werden kann.
Licenses
-de.mc8051.arma3launcher
+de.mc8051.arma3launcher
MIT License
@@ -54,7 +54,7 @@ nicht jeder Fehler unsererseits behoben werden kann.
SOFTWARE.
-com.formdev.flatlaf
+com.formdev.flatlaf
https://github.com/JFormDesigner/FlatLaf
Copyright 2019 FormDev Software GmbH
@@ -72,7 +72,7 @@ nicht jeder Fehler unsererseits behoben werden kann.
limitations under the License.
-co.bitshfted.xapps.zsync
+co.bitshfted.xapps.zsync
https://github.com/bitshifted/zsyncer
Copyright (c) 2015, Salesforce.com, Inc. All rights reserved.
@@ -99,7 +99,7 @@ nicht jeder Fehler unsererseits behoben werden kann.
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-com.github.RalleYTN.SimpleRegistry
+com.github.RalleYTN.SimpleRegistry
https://github.com/RalleYTN/SimpleRegistry
MIT License
@@ -125,7 +125,7 @@ nicht jeder Fehler unsererseits behoben werden kann.
SOFTWARE.
-com.typesafe.config
+com.typesafe.config
https://github.com/lightbend/config
Copyright (C) 2011-2012 Typesafe Inc. http://typesafe.com
@@ -143,7 +143,7 @@ nicht jeder Fehler unsererseits behoben werden kann.
limitations under the License.
-org.ini4j.ini4j
+org.ini4j.ini4j
https://github.com/facebookarchive/ini4j
Copyright 2005,2009 Ivan SZKIBA
@@ -160,7 +160,7 @@ nicht jeder Fehler unsererseits behoben werden kann.
See the License for the specific language governing permissions and
limitations under the License.
-org.json.json
+org.json.json
https://json.org
Copyright (c) 2018 JSON.org
@@ -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
SOFTWARE.
+com.jgoodies.forms
+
+ Copyright (c) 2002-2015 JGoodies Software GmbH. All Rights Reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ o Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ o Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ o Neither the name of JGoodies Software GmbH nor the names of
+ its contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+