Refactor Presets and enable keyboard shortcuts for Presets 1..9 via number keys

This commit is contained in:
Reinhard Pointner 2016-08-11 07:06:18 +08:00
parent dcfcc91090
commit 824ce14c62
5 changed files with 102 additions and 83 deletions

View File

@ -16,6 +16,7 @@ import net.filebot.archive.Archive.Extractor;
import net.filebot.cli.ArgumentBean;
import net.filebot.util.PreferencesList;
import net.filebot.util.PreferencesMap;
import net.filebot.util.PreferencesMap.JsonAdapter;
import net.filebot.util.PreferencesMap.PreferencesEntry;
import net.filebot.util.PreferencesMap.StringAdapter;
@ -234,10 +235,18 @@ public final class Settings {
return PreferencesMap.map(prefs);
}
public <T> PreferencesMap<T> asTypedMap(Class<T> cls) {
return PreferencesMap.map(prefs, new JsonAdapter(cls));
}
public PreferencesList<String> asList() {
return PreferencesList.map(prefs);
}
public <T> PreferencesList<T> asTypedList(Class<T> cls) {
return PreferencesList.map(prefs, new JsonAdapter(cls));
}
public void clear() {
try {
// remove child nodes

View File

@ -41,12 +41,11 @@ import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.border.CompoundBorder;
import javax.swing.border.TitledBorder;
import com.cedarsoftware.util.io.JsonReader;
import com.cedarsoftware.util.io.JsonWriter;
import com.google.common.eventbus.Subscribe;
import ca.odell.glazedlists.EventList;
@ -110,6 +109,8 @@ public class RenamePanel extends JComponent {
private static final PreferencesEntry<String> persistentPreferredLanguage = Settings.forPackage(RenamePanel.class).entry("rename.language").defaultValue("en");
private static final PreferencesEntry<String> persistentPreferredEpisodeOrder = Settings.forPackage(RenamePanel.class).entry("rename.episode.order").defaultValue("Airdate");
private static final Map<String, Preset> persistentPresets = Settings.forPackage(RenamePanel.class).node("presets").asTypedMap(Preset.class);
public RenamePanel() {
namesList.setTitle("New Names");
namesList.setTransferablePolicy(new NamesListTransferablePolicy(renameModel.values()));
@ -241,9 +242,8 @@ public class RenamePanel extends JComponent {
filesList.getButtonPanel().add(createImageButton(openHistoryAction), "gap indent");
// create macros popup
final Action macrosAction = new ShowPresetsPopupAction("Presets", ResourceManager.getIcon("action.script"));
JButton macrosButton = createImageButton(macrosAction);
filesList.getButtonPanel().add(macrosButton, "gap 0");
JButton presetsButton = createImageButton(new ShowPresetsPopupAction("Presets", ResourceManager.getIcon("action.script")));
filesList.getButtonPanel().add(presetsButton, "gap 0");
// show popup on actionPerformed only when names list is empty
matchButton.addActionListener(evt -> {
@ -302,8 +302,13 @@ public class RenamePanel extends JComponent {
add(new LoadingOverlayPane(namesList, namesList, "37px", "30px"), "grow, sizegroupx list");
// install F2 and 1..9 keystroke actions
SwingUtilities.invokeLater(this::installKeyStrokeActions);
}
private void installKeyStrokeActions() {
// manual force name via F2
installAction(namesList.getListComponent(), getKeyStroke(VK_F2, 0), newAction("Force Name", evt -> {
installAction(this, WHEN_IN_FOCUSED_WINDOW, getKeyStroke(VK_F2, 0), newAction("Force Name", evt -> {
try {
if (namesList.getModel().isEmpty()) {
withWaitCursor(evt.getSource(), () -> {
@ -336,61 +341,72 @@ public class RenamePanel extends JComponent {
}
}
} catch (Exception e) {
debug.log(Level.WARNING, e.getMessage(), e);
debug.log(Level.WARNING, e::toString);
}
}));
// map 1..9 number keys to presets
try {
Preset[] presets = persistentPresets.values().toArray(new Preset[0]);
for (int i = 0; i < presets.length && i < 9; i++) {
Preset preset = presets[i];
int key = Character.forDigit(i + 1, 10);
installAction(this, WHEN_IN_FOCUSED_WINDOW, getKeyStroke(key, 0), newAction(preset.getName(), new ApplyPresetAction(preset)::actionPerformed));
}
} catch (Exception e) {
debug.log(Level.WARNING, e::toString);
}
}
private boolean isMatchModeStrict() {
return MATCH_MODE_STRICT.equalsIgnoreCase(persistentPreferredMatchMode.getValue());
}
protected ActionPopup createPresetsPopup() {
Map<String, String> persistentPresets = Settings.forPackage(RenamePanel.class).node("presets").asMap();
private ActionPopup createPresetsPopup() {
ActionPopup actionPopup = new ActionPopup("Presets", ResourceManager.getIcon("action.script"));
if (persistentPresets.size() > 0) {
for (String it : persistentPresets.values()) {
try {
Preset p = (Preset) JsonReader.jsonToJava(it);
actionPopup.add(new ApplyPresetAction(p));
} catch (Exception e) {
debug.log(Level.SEVERE, e.getMessage(), e);
try {
if (persistentPresets.size() > 0) {
for (Preset preset : persistentPresets.values()) {
actionPopup.add(new ApplyPresetAction(preset));
}
actionPopup.addSeparator();
}
actionPopup.addSeparator();
} catch (Exception e) {
debug.log(Level.WARNING, e, e::toString);
}
actionPopup.add(newAction("Edit Presets", ResourceManager.getIcon("script.add"), evt -> {
try {
String newPresetOption = "New Preset …";
String newPreset = "New Preset …";
List<String> presetNames = new ArrayList<String>(persistentPresets.keySet());
presetNames.add(newPresetOption);
presetNames.add(newPreset);
String selection = (String) showInputDialog(getWindow(evt.getSource()), "Edit or create a preset:", "Edit Preset", PLAIN_MESSAGE, null, presetNames.toArray(), newPresetOption);
if (selection == null)
String selection = (String) showInputDialog(getWindow(evt.getSource()), "Edit or create a preset:", "Edit Preset", PLAIN_MESSAGE, null, presetNames.toArray(), newPreset);
if (selection == null) {
return;
Preset preset = null;
if (selection == newPresetOption) {
selection = (String) showInputDialog(getWindow(evt.getSource()), "Preset Name:", newPresetOption, PLAIN_MESSAGE, null, null, "My Preset");
if (selection == null || selection.trim().isEmpty())
return;
preset = new Preset(selection.trim(), null, null, null, null, null, null, null, null);
} else {
preset = (Preset) JsonReader.jsonToJava(persistentPresets.get(selection.toString()));
}
PresetEditor presetEditor = new PresetEditor(getWindow(evt.getSource()));
if (selection == newPreset) {
selection = (String) showInputDialog(getWindow(evt.getSource()), "Preset Name:", newPreset, PLAIN_MESSAGE, null, null, "My Preset");
if (selection == null || selection.trim().isEmpty()) {
return;
}
presetEditor.setPreset(new Preset(selection.trim(), null, null, null, null, null, null, null, null));
} else {
presetEditor.setPreset(persistentPresets.get(selection));
}
presetEditor.setLocation(getOffsetLocation(presetEditor.getOwner()));
presetEditor.setPreset(preset);
presetEditor.setVisible(true);
switch (presetEditor.getResult()) {
case SET:
preset = presetEditor.getPreset();
persistentPresets.put(selection, JsonWriter.objectToJson(preset));
persistentPresets.put(selection, presetEditor.getPreset());
break;
case DELETE:
persistentPresets.remove(selection);
@ -399,14 +415,14 @@ public class RenamePanel extends JComponent {
break;
}
} catch (Exception e) {
debug.log(Level.WARNING, e.toString());
debug.log(Level.WARNING, e, e::toString);
}
}));
return actionPopup;
}
protected ActionPopup createFetchPopup() {
private ActionPopup createFetchPopup() {
ActionPopup actionPopup = new ActionPopup("Fetch & Match Data", ResourceManager.getIcon("action.fetch"));
actionPopup.addDescription(new JLabel("Episode Mode:"));
@ -508,7 +524,7 @@ public class RenamePanel extends JComponent {
return actionPopup;
}
protected ActionPopup createSettingsPopup() {
private ActionPopup createSettingsPopup() {
ActionPopup actionPopup = new ActionPopup("Rename Options", ResourceManager.getIcon("action.settings"));
actionPopup.addDescription(new JLabel("Extension:"));
@ -525,7 +541,7 @@ public class RenamePanel extends JComponent {
return actionPopup;
}
protected Mode getFormatEditorMode(MediaBindingBean binding) {
private Mode getFormatEditorMode(MediaBindingBean binding) {
if (binding != null) {
if (binding.getInfoObject() instanceof Episode) {
return Mode.Episode;
@ -549,7 +565,7 @@ public class RenamePanel extends JComponent {
return Mode.Episode; // default to Episode mode
}
protected void showFormatEditor(MediaBindingBean binding) {
private void showFormatEditor(MediaBindingBean binding) {
try {
withWaitCursor(this, () -> {
FormatDialog dialog = new FormatDialog(getWindowAncestor(RenamePanel.this), getFormatEditorMode(binding), binding);
@ -586,7 +602,7 @@ public class RenamePanel extends JComponent {
}
}
protected final Action clearFilesAction = newAction("Clear All", ResourceManager.getIcon("action.clear"), evt -> {
private final Action clearFilesAction = newAction("Clear All", ResourceManager.getIcon("action.clear"), evt -> {
if (isShiftOrAltDown(evt)) {
renameModel.files().clear();
} else {
@ -594,7 +610,7 @@ public class RenamePanel extends JComponent {
}
});
protected final Action openHistoryAction = newAction("Open History", ResourceManager.getIcon("action.report"), evt -> {
private final Action openHistoryAction = newAction("Open History", ResourceManager.getIcon("action.report"), evt -> {
try {
History model = HistorySpooler.getInstance().getCompleteHistory();
@ -619,7 +635,7 @@ public class RenamePanel extends JComponent {
}
}
protected static class ShowPopupAction extends AbstractAction {
private static class ShowPopupAction extends AbstractAction {
public ShowPopupAction(String name, Icon icon) {
super(name, icon);
@ -633,7 +649,7 @@ public class RenamePanel extends JComponent {
}
};
protected class ShowPresetsPopupAction extends AbstractAction {
private class ShowPresetsPopupAction extends AbstractAction {
public ShowPresetsPopupAction(String name, Icon icon) {
super(name, icon);
@ -647,7 +663,7 @@ public class RenamePanel extends JComponent {
}
};
protected class ApplyPresetAction extends AutoCompleteAction {
private class ApplyPresetAction extends AutoCompleteAction {
private Preset preset;
@ -724,7 +740,7 @@ public class RenamePanel extends JComponent {
}
}
protected class SetRenameMode extends AbstractAction {
private class SetRenameMode extends AbstractAction {
private final boolean activate;
@ -745,7 +761,7 @@ public class RenamePanel extends JComponent {
}
}
protected class SetRenameAction extends AbstractAction {
private class SetRenameAction extends AbstractAction {
private final StandardRenameAction action;
@ -766,7 +782,7 @@ public class RenamePanel extends JComponent {
}
}
protected class AutoCompleteAction extends AbstractAction {
private class AutoCompleteAction extends AbstractAction {
protected final Supplier<AutoCompleteMatcher> matcher;

View File

@ -2,12 +2,6 @@ package net.filebot.util;
import static net.filebot.Logging.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
@ -20,6 +14,9 @@ import java.util.logging.Level;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
import com.cedarsoftware.util.io.JsonReader;
import com.cedarsoftware.util.io.JsonWriter;
public class PreferencesMap<T> implements Map<String, T> {
private final Preferences prefs;
@ -220,40 +217,32 @@ public class PreferencesMap<T> implements Map<String, T> {
}
public static class SerializableAdapter<T extends Serializable> extends AbstractAdapter<T> {
public static class JsonAdapter<T> extends AbstractAdapter<T> {
private Class<T> type;
public JsonAdapter(Class<T> type) {
this.type = type;
}
@SuppressWarnings("unchecked")
@Override
public T get(Preferences prefs, String key) {
byte[] bytes = prefs.getByteArray(key, null);
String json = prefs.get(key, null);
if (bytes == null)
return null;
try {
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes));
Object object = in.readObject();
in.close();
return (T) object;
} catch (Exception e) {
throw new RuntimeException(e);
if (json != null) {
try {
return type.cast(JsonReader.jsonToJava(json));
} catch (Exception e) {
debug.log(Level.WARNING, e, e::getMessage);
}
}
return null;
}
@Override
public void put(Preferences prefs, String key, T value) {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try {
ObjectOutputStream out = new ObjectOutputStream(buffer);
out.writeObject(value);
out.close();
prefs.putByteArray(key, buffer.toByteArray());
} catch (IOException e) {
throw new RuntimeException(e);
}
prefs.put(key, JsonWriter.objectToJson(value));
}
}

View File

@ -139,20 +139,24 @@ public final class SwingUI {
}
public static void installAction(JComponent component, KeyStroke keystroke, Action action) {
installAction(component, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, keystroke, action);
}
public static void installAction(JComponent component, int condition, KeyStroke keystroke, Action action) {
Object key = action.getValue(Action.NAME);
if (key == null) {
throw new IllegalArgumentException("Action must have a name");
}
component.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(keystroke, key);
component.getInputMap(condition).put(keystroke, key);
component.getActionMap().put(key, action);
// automatically add Mac OS X compatibility (on Mac the BACKSPACE key is called DELETE, and there is no DELETE key)
if (keystroke.getKeyCode() == KeyEvent.VK_DELETE) {
KeyStroke macKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, keystroke.getModifiers(), keystroke.isOnKeyRelease());
Object macKey = "mac." + action.getValue(Action.NAME);
component.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(macKeyStroke, macKey);
component.getInputMap(condition).put(macKeyStroke, macKey);
component.getActionMap().put(macKey, action);
}
}

View File

@ -14,7 +14,7 @@ import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import net.filebot.util.PreferencesMap.SerializableAdapter;
import net.filebot.util.PreferencesMap.JsonAdapter;
import net.filebot.util.PreferencesMap.SimpleAdapter;
public class PreferencesMapTest {
@ -144,11 +144,12 @@ public class PreferencesMapTest {
}
@Test
public void serializableAdapter() {
Map<String, Color> map = PreferencesMap.map(temp, new SerializableAdapter<Color>());
public void jsonAdapter() {
Map<String, Color> map = PreferencesMap.map(temp, new JsonAdapter<Color>(Color.class));
Color color = new Color(0.25f, 0.50f, 1.00f);
map.put("color", color);
assertEquals(color, map.get("color"));
}
}