From 5659719d536efde1f352d045dc713634c7862da3 Mon Sep 17 00:00:00 2001 From: Tomas Slusny Date: Sun, 4 Feb 2018 19:47:49 +0100 Subject: [PATCH] Enable/disable plugins in the ConfigPanel Add ability to enable and disable plugins in the config panel. Signed-off-by: Tomas Slusny --- .../client/plugins/PluginManager.java | 17 ++ .../client/plugins/config/ConfigPanel.java | 172 +++++++++++++++--- .../client/plugins/config/ConfigPlugin.java | 12 +- .../runelite/client/plugins/config/698-0.png | Bin 0 -> 335 bytes .../runelite/client/plugins/config/699-0.png | Bin 0 -> 417 bytes .../client/plugins/config/config_icon.png | Bin 623 -> 15487 bytes 6 files changed, 173 insertions(+), 28 deletions(-) create mode 100644 runelite-client/src/main/resources/net/runelite/client/plugins/config/698-0.png create mode 100644 runelite-client/src/main/resources/net/runelite/client/plugins/config/699-0.png diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java index bad42931ca..a554c9d090 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java @@ -124,6 +124,22 @@ public class PluginManager })); } + public Config getPluginConfigProxy(Plugin plugin) + { + final Injector injector = plugin.getInjector(); + + for (Key key : injector.getAllBindings().keySet()) + { + Class type = key.getTypeLiteral().getRawType(); + if (Config.class.isAssignableFrom(type)) + { + return (Config) injector.getInstance(key); + } + } + + return null; + } + public List getPluginConfigProxies() { List injectors = new ArrayList<>(); @@ -143,6 +159,7 @@ public class PluginManager } } } + return list; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java index 1580473440..0d94aec69b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java @@ -24,13 +24,11 @@ */ package net.runelite.client.plugins.config; -import static javax.swing.JOptionPane.WARNING_MESSAGE; -import static javax.swing.JOptionPane.YES_NO_OPTION; -import static javax.swing.JOptionPane.YES_OPTION; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; +import java.awt.GridLayout; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.ItemEvent; @@ -38,9 +36,14 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; -import java.util.AbstractMap; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.Comparator; import java.util.Map; import java.util.TreeMap; +import java.util.concurrent.ScheduledExecutorService; +import javax.imageio.ImageIO; +import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JColorChooser; @@ -50,6 +53,9 @@ import javax.swing.JFormattedTextField; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; +import static javax.swing.JOptionPane.WARNING_MESSAGE; +import static javax.swing.JOptionPane.YES_NO_OPTION; +import static javax.swing.JOptionPane.YES_OPTION; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSpinner; @@ -66,6 +72,10 @@ import net.runelite.client.config.ConfigDescriptor; import net.runelite.client.config.ConfigItem; import net.runelite.client.config.ConfigItemDescriptor; import net.runelite.client.config.ConfigManager; +import net.runelite.client.config.RuneLiteConfig; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginInstantiationException; import net.runelite.client.plugins.PluginManager; import net.runelite.client.ui.PluginPanel; @@ -74,18 +84,39 @@ public class ConfigPanel extends PluginPanel { private static final int TEXT_FIELD_WIDTH = 7; private static final int SPINNER_FIELD_WIDTH = 6; + private static BufferedImage CONFIG_ICON; + private static BufferedImage UNCHECK_ICON; + private static BufferedImage CHECK_ICON; + + static + { + try + { + CONFIG_ICON = ImageIO.read(ConfigPanel.class.getResourceAsStream("config_icon.png")); + UNCHECK_ICON = ImageIO.read(ConfigPanel.class.getResourceAsStream("698-0.png")); + CHECK_ICON = ImageIO.read(ConfigPanel.class.getResourceAsStream("699-0.png")); + } + catch (IOException e) + { + log.warn("Failed to read icon", e); + } + } private final PluginManager pluginManager; private final ConfigManager configManager; + private final ScheduledExecutorService executorService; + private final RuneLiteConfig runeLiteConfig; private final JTextField searchBar = new JTextField(); private Map children = new TreeMap<>(); private int scrollBarPosition = 0; - public ConfigPanel(PluginManager pluginManager, ConfigManager configManager) + public ConfigPanel(PluginManager pluginManager, ConfigManager configManager, ScheduledExecutorService executorService, RuneLiteConfig runeLiteConfig) { super(); this.pluginManager = pluginManager; this.configManager = configManager; + this.executorService = executorService; + this.runeLiteConfig = runeLiteConfig; searchBar.getDocument().addDocumentListener(new DocumentListener() { @@ -114,36 +145,125 @@ public class ConfigPanel extends PluginPanel final void rebuildPluginList() { + scrollBarPosition = getScrollPane().getVerticalScrollBar().getValue(); Map newChildren = new TreeMap<>(); - pluginManager.getPluginConfigProxies() - .stream() - // Convert config proxies to pair of config descriptors and config proxies - .map(c -> new AbstractMap.SimpleEntry<>(configManager.getConfigDescriptor(c), c)) - .filter(e -> e.getKey().getItems().stream().anyMatch(cid -> !cid.getItem().hidden())) - .forEach(e -> - { - ConfigDescriptor cd = e.getKey(); - Config config = e.getValue(); - String groupName = cd.getGroup().name(); - if (children.containsKey(groupName)) + pluginManager.getPlugins().stream() + .sorted(Comparator.comparing(left -> left.getClass().getAnnotation(PluginDescriptor.class).name())) + .forEach(plugin -> { - newChildren.put(groupName, children.get(groupName)); - return; - } + final Config pluginConfigProxy = pluginManager.getPluginConfigProxy(plugin); + final String pluginName = plugin.getClass().getAnnotation(PluginDescriptor.class).name(); - JPanel groupPanel = new JPanel(); - groupPanel.setLayout(new BorderLayout()); - JButton viewGroupItemsButton = new JButton(groupName); - viewGroupItemsButton.addActionListener(ae -> openGroupConfigPanel(config, cd, configManager)); - groupPanel.add(viewGroupItemsButton); - newChildren.put(groupName, groupPanel); - }); + final JPanel groupPanel = buildGroupPanel(); + groupPanel.add(new JLabel(pluginName), BorderLayout.CENTER); + + final JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new GridLayout(1, 2, 3, 0)); + groupPanel.add(buttonPanel, BorderLayout.LINE_END); + + final JButton editConfigButton = buildConfigButton(pluginConfigProxy); + buttonPanel.add(editConfigButton); + + final JButton toggleButton = buildToggleButton(plugin); + buttonPanel.add(toggleButton); + + newChildren.put(pluginName, groupPanel); + }); + + + final JPanel groupPanel = buildGroupPanel(); + groupPanel.add(new JLabel("RuneLite"), BorderLayout.CENTER); + + final JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new GridLayout(1, 2, 3, 0)); + groupPanel.add(buttonPanel, BorderLayout.LINE_END); + + final JButton editConfigButton = buildConfigButton(runeLiteConfig); + buttonPanel.add(editConfigButton); + + final JButton toggleButton = buildToggleButton(null); + buttonPanel.add(toggleButton); + newChildren.put("RuneLite", groupPanel); children = newChildren; openConfigList(); } + private JPanel buildGroupPanel() + { + // Create base panel for the config button and enabled/disabled button + final JPanel groupPanel = new JPanel(); + groupPanel.setLayout(new BorderLayout(3, 0)); + return groupPanel; + } + + private JButton buildConfigButton(Config config) + { + // Create edit config button and disable it by default + final JButton editConfigButton = new JButton(new ImageIcon(CONFIG_ICON)); + editConfigButton.setPreferredSize(new Dimension(32, 0)); + editConfigButton.setEnabled(false); + + // If we have configuration proxy enable the button and add edit config listener + if (config != null) + { + final ConfigDescriptor configDescriptor = configManager.getConfigDescriptor(config); + editConfigButton.addActionListener(ae -> openGroupConfigPanel(config, configDescriptor, configManager)); + editConfigButton.setEnabled(true); + editConfigButton.setToolTipText("Edit plugin configuration"); + } + + return editConfigButton; + } + + private JButton buildToggleButton(Plugin plugin) + { + // Create enabling/disabling button + final JButton toggleButton = new JButton(new ImageIcon(CHECK_ICON)); + toggleButton.setPreferredSize(new Dimension(32, 0)); + + if (plugin == null) + { + toggleButton.setEnabled(false); + return toggleButton; + } + + highlightButton(toggleButton, pluginManager.isPluginEnabled(plugin)); + + toggleButton.addActionListener(e -> executorService.submit(() -> + { + final boolean enabled = pluginManager.isPluginEnabled(plugin); + pluginManager.setPluginEnabled(plugin, !enabled); + + try + { + if (enabled) + { + pluginManager.stopPlugin(plugin); + } + else + { + pluginManager.startPlugin(plugin); + } + } + catch (PluginInstantiationException ex) + { + log.warn("Error during starting/stopping plugin {}", plugin.getClass().getSimpleName(), ex); + } + + highlightButton(toggleButton, !enabled); + })); + + return toggleButton; + } + + private void highlightButton(JButton button, boolean enabled) + { + button.setIcon(enabled ? new ImageIcon(CHECK_ICON) : new ImageIcon(UNCHECK_ICON)); + button.setToolTipText(enabled ? "Disable plugin" : "Enable plugin"); + } + private void onSearchBarChanged() { children.forEach((key, value) -> diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPlugin.java index 94978d843a..456f303ec3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPlugin.java @@ -25,10 +25,12 @@ package net.runelite.client.plugins.config; import com.google.common.eventbus.Subscribe; +import java.util.concurrent.ScheduledExecutorService; import javax.imageio.ImageIO; import javax.inject.Inject; import javax.swing.SwingUtilities; import net.runelite.client.config.ConfigManager; +import net.runelite.client.config.RuneLiteConfig; import net.runelite.client.events.PluginChanged; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; @@ -49,7 +51,13 @@ public class ConfigPlugin extends Plugin private ConfigManager configManager; @Inject - PluginManager pluginManager; + private PluginManager pluginManager; + + @Inject + private ScheduledExecutorService executorService; + + @Inject + private RuneLiteConfig runeLiteConfig; private ConfigPanel configPanel; private NavigationButton navButton; @@ -57,7 +65,7 @@ public class ConfigPlugin extends Plugin @Override protected void startUp() throws Exception { - configPanel = new ConfigPanel(pluginManager, configManager); + configPanel = new ConfigPanel(pluginManager, configManager, executorService, runeLiteConfig); navButton = new NavigationButton( "Configuration", diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/config/698-0.png b/runelite-client/src/main/resources/net/runelite/client/plugins/config/698-0.png new file mode 100644 index 0000000000000000000000000000000000000000..160d431a9512ba88d81280c55c0a6811b5233ef9 GIT binary patch literal 335 zcmeAS@N?(olHy`uVBq!ia0vp^{2?0v z(btiIVPjv-@4(4GzCyA`kS_y6l_~>6Lo)-z&;LOBB?CjL0RzLU1O^7H84L{K`IF+0 zx&hT5^>lFzskpTycsFmefxzC)8bW~zt;eKOC-zL_xad&Ky|MATgPelzf=5d?p3GSM6Ft;+aPHg<(rY!-9Tn7J+9W9hEe&okq{ a$})(|y=9e~bA=n|AqG!ZKbLh*2~7ZrZFdj= literal 0 HcmV?d00001 diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/config/699-0.png b/runelite-client/src/main/resources/net/runelite/client/plugins/config/699-0.png new file mode 100644 index 0000000000000000000000000000000000000000..a48cfcd5cced8f49f31dd8f8a17d735bd2f5c8b5 GIT binary patch literal 417 zcmV;S0bc%zP)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ-7fD1xRCwB?ld(zzQ4mGXUDg#Fi?o)0goR+0E`Onw zSljsn1}qFnIxDRd>}`ELI@$v!dj>?vCxeH8^nDHW?-6m_uMx#yeBi` zzoBtN-!G74aZT=|VCkYr5C%vxXA)_3ryjp#e8X**_k5jbxv{@00000 LNkvXXu0mjfT$7+V literal 0 HcmV?d00001 diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/config/config_icon.png b/runelite-client/src/main/resources/net/runelite/client/plugins/config/config_icon.png index 1cdacec3eb445029bd52e64c6418d1241429b5a9..540855fefe2abba99d2e9e77415fc018d4e22ed9 100644 GIT binary patch literal 15487 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 xvHeU