From 112bc228d42708ee35c0d368b64924c72df34725 Mon Sep 17 00:00:00 2001 From: Gurkengewuerz Date: Sun, 29 Mar 2020 01:54:40 +0100 Subject: [PATCH] =?UTF-8?q?w=C3=B6rk=20w=C3=B6rk=20(day=204)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 --- pom.xml | 5 + .../de/mc8051/arma3launcher/LauncherGUI.form | 195 ++++++-- .../de/mc8051/arma3launcher/LauncherGUI.java | 426 ++++++++++++++---- .../arma3launcher/model/JCheckBoxTree.java | 4 +- .../arma3launcher/model/ModListRenderer.java | 20 +- .../arma3launcher/model/MultiSelectModel.java | 35 ++ .../arma3launcher/model/TabbedPaneUI.java | 26 ++ .../de/mc8051/arma3launcher/objects/Mod.java | 7 +- .../mc8051/arma3launcher/objects/Modset.java | 93 +++- .../arma3launcher/repo/FileChecker.java | 43 +- .../arma3launcher/repo/RepositoryManger.java | 13 +- src/main/resources/arma3launcher.json | 2 +- src/main/resources/disclaimer.html | 44 +- src/main/resources/lang_de_DE.properties | 10 +- src/main/resources/lang_en_US.properties | 10 +- 15 files changed, 743 insertions(+), 190 deletions(-) create mode 100644 src/main/java/de/mc8051/arma3launcher/model/MultiSelectModel.java create mode 100644 src/main/java/de/mc8051/arma3launcher/model/TabbedPaneUI.java 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 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.
+
\ No newline at end of file diff --git a/src/main/resources/lang_de_DE.properties b/src/main/resources/lang_de_DE.properties index 3c8144b..7c59f9e 100644 --- a/src/main/resources/lang_de_DE.properties +++ b/src/main/resources/lang_de_DE.properties @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/src/main/resources/lang_en_US.properties b/src/main/resources/lang_en_US.properties index a430303..985be1e 100644 --- a/src/main/resources/lang_en_US.properties +++ b/src/main/resources/lang_en_US.properties @@ -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 \ No newline at end of file +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 \ No newline at end of file