config: add support for enum sets

This commit is contained in:
Adam
2021-11-29 17:50:35 -05:00
parent c3880a8c74
commit 095a0e6257
5 changed files with 116 additions and 45 deletions

View File

@@ -99,11 +99,9 @@ class ConfigInvocationHandler implements InvocationHandler
} }
// Convert value to return type // Convert value to return type
Class<?> returnType = method.getReturnType();
try try
{ {
Object objectValue = ConfigManager.stringToObject(value, returnType); Object objectValue = manager.stringToObject(value, method.getGenericReturnType());
cache.put(method, objectValue == null ? NULL : objectValue); cache.put(method, objectValue == null ? NULL : objectValue);
return objectValue; return objectValue;
} }
@@ -155,7 +153,7 @@ class ConfigInvocationHandler implements InvocationHandler
} }
else else
{ {
String newValueStr = ConfigManager.objectToString(newValue); String newValueStr = manager.objectToString(newValue);
manager.setConfiguration(group.value(), item.keyName(), newValueStr); manager.setConfiguration(group.value(), item.keyName(), newValueStr);
} }
return null; return null;

View File

@@ -24,13 +24,14 @@
*/ */
package net.runelite.client.config; package net.runelite.client.config;
import java.lang.reflect.Type;
import lombok.Value; import lombok.Value;
@Value @Value
public class ConfigItemDescriptor implements ConfigObject public class ConfigItemDescriptor implements ConfigObject
{ {
private final ConfigItem item; private final ConfigItem item;
private final Class<?> type; private final Type type;
private final Range range; private final Range range;
private final Alpha alpha; private final Alpha alpha;
private final Units units; private final Units units;

View File

@@ -30,6 +30,7 @@ import com.google.common.collect.ComparisonChain;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.hash.Hasher; import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing; import com.google.common.hash.Hashing;
import com.google.gson.Gson;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Point; import java.awt.Point;
@@ -43,7 +44,9 @@ import java.io.InputStreamReader;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.AtomicMoveNotSupportedException; import java.nio.file.AtomicMoveNotSupportedException;
@@ -120,6 +123,7 @@ public class ConfigManager
private final File settingsFileInput; private final File settingsFileInput;
private final EventBus eventBus; private final EventBus eventBus;
private final OkHttpClient okHttpClient; private final OkHttpClient okHttpClient;
private final Gson gson;
private AccountSession session; private AccountSession session;
private ConfigClient configClient; private ConfigClient configClient;
@@ -143,13 +147,15 @@ public class ConfigManager
ScheduledExecutorService scheduledExecutorService, ScheduledExecutorService scheduledExecutorService,
EventBus eventBus, EventBus eventBus,
OkHttpClient okHttpClient, OkHttpClient okHttpClient,
@Nullable Client client) @Nullable Client client,
Gson gson)
{ {
this.settingsFileInput = config; this.settingsFileInput = config;
this.eventBus = eventBus; this.eventBus = eventBus;
this.okHttpClient = okHttpClient; this.okHttpClient = okHttpClient;
this.client = client; this.client = client;
this.propertiesFile = getPropertiesFile(); this.propertiesFile = getPropertiesFile();
this.gson = gson;
scheduledExecutorService.scheduleWithFixedDelay(this::sendConfig, 30, 30, TimeUnit.SECONDS); scheduledExecutorService.scheduleWithFixedDelay(this::sendConfig, 30, 30, TimeUnit.SECONDS);
} }
@@ -449,12 +455,12 @@ public class ConfigManager
return properties.getProperty(getWholeKey(groupName, profile, key)); return properties.getProperty(getWholeKey(groupName, profile, key));
} }
public <T> T getConfiguration(String groupName, String key, Class<T> clazz) public <T> T getConfiguration(String groupName, String key, Type clazz)
{ {
return getConfiguration(groupName, null, key, clazz); return getConfiguration(groupName, null, key, clazz);
} }
public <T> T getRSProfileConfiguration(String groupName, String key, Class<T> clazz) public <T> T getRSProfileConfiguration(String groupName, String key, Type clazz)
{ {
String rsProfileKey = this.rsProfileKey; String rsProfileKey = this.rsProfileKey;
if (rsProfileKey == null) if (rsProfileKey == null)
@@ -465,14 +471,14 @@ public class ConfigManager
return getConfiguration(groupName, rsProfileKey, key, clazz); return getConfiguration(groupName, rsProfileKey, key, clazz);
} }
public <T> T getConfiguration(String groupName, String profile, String key, Class<T> clazz) public <T> T getConfiguration(String groupName, String profile, String key, Type type)
{ {
String value = getConfiguration(groupName, profile, key); String value = getConfiguration(groupName, profile, key);
if (!Strings.isNullOrEmpty(value)) if (!Strings.isNullOrEmpty(value))
{ {
try try
{ {
return (T) stringToObject(value, clazz); return (T) stringToObject(value, type);
} }
catch (Exception e) catch (Exception e)
{ {
@@ -525,17 +531,17 @@ public class ConfigManager
eventBus.post(configChanged); eventBus.post(configChanged);
} }
public void setConfiguration(String groupName, String profile, String key, Object value) public <T> void setConfiguration(String groupName, String profile, String key, T value)
{ {
setConfiguration(groupName, profile, key, objectToString(value)); setConfiguration(groupName, profile, key, objectToString(value));
} }
public void setConfiguration(String groupName, String key, Object value) public <T> void setConfiguration(String groupName, String key, T value)
{ {
setConfiguration(groupName, null, key, value); setConfiguration(groupName, null, key, value);
} }
public void setRSProfileConfiguration(String groupName, String key, Object value) public <T> void setRSProfileConfiguration(String groupName, String key, T value)
{ {
String rsProfileKey = this.rsProfileKey; String rsProfileKey = this.rsProfileKey;
if (rsProfileKey == null) if (rsProfileKey == null)
@@ -657,7 +663,7 @@ public class ConfigManager
.filter(m -> m.getParameterCount() == 0 && m.isAnnotationPresent(ConfigItem.class)) .filter(m -> m.getParameterCount() == 0 && m.isAnnotationPresent(ConfigItem.class))
.map(m -> new ConfigItemDescriptor( .map(m -> new ConfigItemDescriptor(
m.getDeclaredAnnotation(ConfigItem.class), m.getDeclaredAnnotation(ConfigItem.class),
m.getReturnType(), m.getGenericReturnType(),
m.getDeclaredAnnotation(Range.class), m.getDeclaredAnnotation(Range.class),
m.getDeclaredAnnotation(Alpha.class), m.getDeclaredAnnotation(Alpha.class),
m.getDeclaredAnnotation(Units.class) m.getDeclaredAnnotation(Units.class)
@@ -714,7 +720,7 @@ public class ConfigManager
{ {
// This checks if it is set and is also unmarshallable to the correct type; so // This checks if it is set and is also unmarshallable to the correct type; so
// we will overwrite invalid config values with the default // we will overwrite invalid config values with the default
Object current = getConfiguration(group.value(), item.keyName(), method.getReturnType()); Object current = getConfiguration(group.value(), item.keyName(), method.getGenericReturnType());
if (current != null) if (current != null)
{ {
continue; // something else is already set continue; // something else is already set
@@ -748,7 +754,7 @@ public class ConfigManager
} }
} }
static Object stringToObject(String str, Class<?> type) Object stringToObject(String str, Type type)
{ {
if (type == boolean.class || type == Boolean.class) if (type == boolean.class || type == Boolean.class)
{ {
@@ -789,7 +795,7 @@ public class ConfigManager
int height = Integer.parseInt(splitStr[3]); int height = Integer.parseInt(splitStr[3]);
return new Rectangle(x, y, width, height); return new Rectangle(x, y, width, height);
} }
if (type.isEnum()) if (type instanceof Class && ((Class<?>) type).isEnum())
{ {
return Enum.valueOf((Class<? extends Enum>) type, str); return Enum.valueOf((Class<? extends Enum>) type, str);
} }
@@ -824,11 +830,19 @@ public class ConfigManager
{ {
return Base64.getUrlDecoder().decode(str); return Base64.getUrlDecoder().decode(str);
} }
if (type instanceof ParameterizedType)
{
ParameterizedType parameterizedType = (ParameterizedType) type;
if (parameterizedType.getRawType() == Set.class)
{
return gson.fromJson(str, parameterizedType);
}
}
return str; return str;
} }
@Nullable @Nullable
static String objectToString(Object object) String objectToString(Object object)
{ {
if (object instanceof Color) if (object instanceof Color)
{ {
@@ -875,6 +889,10 @@ public class ConfigManager
{ {
return Base64.getUrlEncoder().encodeToString((byte[]) object); return Base64.getUrlEncoder().encodeToString((byte[]) object);
} }
if (object instanceof Set)
{
return gson.toJson(object, Set.class);
}
return object == null ? null : object.toString(); return object == null ? null : object.toString();
} }

View File

@@ -24,8 +24,10 @@
*/ */
package net.runelite.client.plugins.config; package net.runelite.client.plugins.config;
import com.google.common.base.MoreObjects;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.collect.ComparisonChain; import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Sets;
import com.google.common.primitives.Ints; import com.google.common.primitives.Ints;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.Color; import java.awt.Color;
@@ -37,8 +39,12 @@ import java.awt.event.ItemEvent;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.lang.reflect.ParameterizedType;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
import javax.inject.Inject; import javax.inject.Inject;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
@@ -49,6 +55,7 @@ import javax.swing.JCheckBox;
import javax.swing.JComboBox; import javax.swing.JComboBox;
import javax.swing.JFormattedTextField; import javax.swing.JFormattedTextField;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenuItem; import javax.swing.JMenuItem;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.JPanel; import javax.swing.JPanel;
@@ -56,6 +63,8 @@ import javax.swing.JPasswordField;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JSpinner; import javax.swing.JSpinner;
import javax.swing.JTextArea; import javax.swing.JTextArea;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import javax.swing.ScrollPaneConstants; import javax.swing.ScrollPaneConstants;
import javax.swing.SpinnerModel; import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel; import javax.swing.SpinnerNumberModel;
@@ -97,6 +106,7 @@ import net.runelite.client.util.ColorUtil;
import net.runelite.client.util.ImageUtil; import net.runelite.client.util.ImageUtil;
import net.runelite.client.util.SwingUtil; import net.runelite.client.util.SwingUtil;
import net.runelite.client.util.Text; import net.runelite.client.util.Text;
import org.apache.commons.lang3.ArrayUtils;
@Slf4j @Slf4j
class ConfigPanel extends PluginPanel class ConfigPanel extends PluginPanel
@@ -111,27 +121,6 @@ class ConfigPanel extends PluginPanel
private static final Map<ConfigSectionDescriptor, Boolean> sectionExpandStates = new HashMap<>(); private static final Map<ConfigSectionDescriptor, Boolean> sectionExpandStates = new HashMap<>();
private final FixedWidthPanel mainPanel;
private final JLabel title;
private final PluginToggleButton pluginToggle;
@Inject
private PluginListPanel pluginList;
@Inject
private ConfigManager configManager;
@Inject
private PluginManager pluginManager;
@Inject
private ExternalPluginManager externalPluginManager;
@Inject
private ColorPickerManager colorPickerManager;
private PluginConfigurationDescriptor pluginConfig = null;
static static
{ {
final BufferedImage backIcon = ImageUtil.loadImageResource(ConfigPanel.class, "config_back_icon.png"); final BufferedImage backIcon = ImageUtil.loadImageResource(ConfigPanel.class, "config_back_icon.png");
@@ -147,10 +136,32 @@ class ConfigPanel extends PluginPanel
SECTION_RETRACT_ICON_HOVER = new ImageIcon(ImageUtil.alphaOffset(sectionExpandIcon, -100)); SECTION_RETRACT_ICON_HOVER = new ImageIcon(ImageUtil.alphaOffset(sectionExpandIcon, -100));
} }
public ConfigPanel() private final PluginListPanel pluginList;
private final ConfigManager configManager;
private final PluginManager pluginManager;
private final ExternalPluginManager externalPluginManager;
private final ColorPickerManager colorPickerManager;
private final ListCellRenderer<Enum<?>> listCellRenderer = new ComboBoxListRenderer<>();
private final FixedWidthPanel mainPanel;
private final JLabel title;
private final PluginToggleButton pluginToggle;
private PluginConfigurationDescriptor pluginConfig = null;
@Inject
private ConfigPanel(PluginListPanel pluginList, ConfigManager configManager, PluginManager pluginManager,
ExternalPluginManager externalPluginManager, ColorPickerManager colorPickerManager)
{ {
super(false); super(false);
this.pluginList = pluginList;
this.configManager = configManager;
this.pluginManager = pluginManager;
this.externalPluginManager = externalPluginManager;
this.colorPickerManager = colorPickerManager;
setLayout(new BorderLayout()); setLayout(new BorderLayout());
setBackground(ColorScheme.DARK_GRAY_COLOR); setBackground(ColorScheme.DARK_GRAY_COLOR);
@@ -359,7 +370,7 @@ class ConfigPanel extends PluginPanel
{ {
item.add(createDimension(cd, cid), BorderLayout.EAST); item.add(createDimension(cd, cid), BorderLayout.EAST);
} }
else if (cid.getType().isEnum()) else if (cid.getType() instanceof Class && ((Class<?>) cid.getType()).isEnum())
{ {
item.add(createComboBox(cd, cid), BorderLayout.EAST); item.add(createComboBox(cd, cid), BorderLayout.EAST);
} }
@@ -367,6 +378,14 @@ class ConfigPanel extends PluginPanel
{ {
item.add(createKeybind(cd, cid), BorderLayout.EAST); item.add(createKeybind(cd, cid), BorderLayout.EAST);
} }
else if (cid.getType() instanceof ParameterizedType)
{
ParameterizedType parameterizedType = (ParameterizedType) cid.getType();
if (parameterizedType.getRawType() == Set.class)
{
item.add(createList(cd, cid), BorderLayout.EAST);
}
}
JPanel section = sectionWidgets.get(cid.getItem().section()); JPanel section = sectionWidgets.get(cid.getItem().section());
if (section == null) if (section == null)
@@ -581,7 +600,7 @@ class ConfigPanel extends PluginPanel
// set renderer prior to calling box.getPreferredSize(), since it will invoke the renderer // set renderer prior to calling box.getPreferredSize(), since it will invoke the renderer
// to build components for each combobox element in order to compute the display size of the // to build components for each combobox element in order to compute the display size of the
// combobox // combobox
box.setRenderer(new ComboBoxListRenderer<>()); box.setRenderer(listCellRenderer);
box.setPreferredSize(new Dimension(box.getPreferredSize().width, 25)); box.setPreferredSize(new Dimension(box.getPreferredSize().width, 25));
box.setForeground(Color.WHITE); box.setForeground(Color.WHITE);
box.setFocusable(false); box.setFocusable(false);
@@ -594,7 +613,7 @@ class ConfigPanel extends PluginPanel
} }
catch (IllegalArgumentException ex) catch (IllegalArgumentException ex)
{ {
log.debug("invalid seleced item", ex); log.debug("invalid selected item", ex);
} }
box.addItemListener(e -> box.addItemListener(e ->
{ {
@@ -628,6 +647,34 @@ class ConfigPanel extends PluginPanel
return button; return button;
} }
private JList<Enum<?>> createList(ConfigDescriptor cd, ConfigItemDescriptor cid)
{
ParameterizedType parameterizedType = (ParameterizedType) cid.getType();
Class<? extends Enum> type = (Class<? extends Enum>) parameterizedType.getActualTypeArguments()[0];
Set<? extends Enum> set = configManager.getConfiguration(cd.getGroup().value(), null,
cid.getItem().keyName(), parameterizedType);
JList<Enum<?>> list = new JList<Enum<?>>(type.getEnumConstants()); // NOPMD: UseDiamondOperator
list.setCellRenderer(listCellRenderer);
list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
list.setLayoutOrientation(JList.VERTICAL);
list.setSelectedIndices(
MoreObjects.firstNonNull(set, Collections.emptySet())
.stream()
.mapToInt(e -> ArrayUtils.indexOf(type.getEnumConstants(), e))
.toArray());
list.addFocusListener(new FocusAdapter()
{
@Override
public void focusLost(FocusEvent e)
{
changeConfiguration(list, cd, cid);
}
});
return list;
}
private void changeConfiguration(Component component, ConfigDescriptor cd, ConfigItemDescriptor cid) private void changeConfiguration(Component component, ConfigDescriptor cd, ConfigItemDescriptor cid)
{ {
final ConfigItem configItem = cid.getItem(); final ConfigItem configItem = cid.getItem();
@@ -675,6 +722,13 @@ class ConfigPanel extends PluginPanel
HotkeyButton hotkeyButton = (HotkeyButton) component; HotkeyButton hotkeyButton = (HotkeyButton) component;
configManager.setConfiguration(cd.getGroup().value(), cid.getItem().keyName(), hotkeyButton.getValue()); configManager.setConfiguration(cd.getGroup().value(), cid.getItem().keyName(), hotkeyButton.getValue());
} }
else if (component instanceof JList)
{
JList<?> list = (JList<?>) component;
List<?> selectedValues = list.getSelectedValuesList();
configManager.setConfiguration(cd.getGroup().value(), cid.getItem().keyName(), Sets.newHashSet(selectedValues));
}
} }
@Override @Override

View File

@@ -59,9 +59,9 @@ public final class ComboBoxListRenderer<T> extends JLabel implements ListCellRen
setBorder(new EmptyBorder(5, 5, 5, 0)); setBorder(new EmptyBorder(5, 5, 5, 0));
String text; String text;
if (o instanceof Enum) if (o instanceof Enum<?>)
{ {
text = Text.titleCase((Enum) o); text = Text.titleCase((Enum<?>) o);
} }
else else
{ {