+ added replaceTrailingBraces() to ExpressionFormat context

+ added Undo/Redo support in EpisodeListDialog
* refactoring
This commit is contained in:
Reinhard Pointner 2009-05-16 11:58:28 +00:00
parent 216dd4d383
commit 9aad7deae2
16 changed files with 178 additions and 104 deletions

View File

@ -31,7 +31,11 @@ String.prototype.space = function(replacement) {
* Remove trailing parenthesis including any leading whitespace.
*
* e.g. "Doctor Who (2005)" -> "Doctor Who"
* "Bad Wolf (1)" -> "Bad Wolf, Part 1"
*/
String.prototype.removeTrailingBraces = function() {
return this.replace(/\s*\([^\)]*\)$/, "");
String.prototype.replaceTrailingBraces = function(replacement) {
// use empty string as default replacement
var r = replacement ? replacement : "";
return this.replace(/\s*\(([^\)]*)\)$/, r);
}

View File

@ -117,7 +117,7 @@ public class ExpressionFormat extends Format {
ScriptContext context = new SimpleScriptContext();
// use privileged bindings so we are not restricted by the script sandbox
context.setBindings(PrivilegedBindings.newProxy(bindings), ScriptContext.GLOBAL_SCOPE);
context.setBindings(PrivilegedBindings.newProxy(bindings, AccessController.getContext()), ScriptContext.GLOBAL_SCOPE);
for (Object snipped : compilation) {
if (snipped instanceof CompiledScript) {
@ -161,7 +161,7 @@ public class ExpressionFormat extends Format {
Object snipped = compilation[i];
if (snipped instanceof CompiledScript) {
compilation[i] = new SecureCompiledScript(sandbox, (CompiledScript) snipped);
compilation[i] = new SecureCompiledScript((CompiledScript) snipped, sandbox);
}
}
@ -184,10 +184,12 @@ public class ExpressionFormat extends Format {
private static class PrivilegedBindings implements InvocationHandler {
private final Bindings bindings;
private final AccessControlContext context;
private PrivilegedBindings(Bindings bindings) {
private PrivilegedBindings(Bindings bindings, AccessControlContext context) {
this.bindings = bindings;
this.context = context;
}
@ -200,7 +202,7 @@ public class ExpressionFormat extends Format {
public Object run() throws Exception {
return method.invoke(bindings, args);
}
});
}, context);
} catch (PrivilegedActionException e) {
Throwable cause = e.getException();
@ -216,8 +218,8 @@ public class ExpressionFormat extends Format {
}
public static Bindings newProxy(Bindings bindings) {
PrivilegedBindings invocationHandler = new PrivilegedBindings(bindings);
public static Bindings newProxy(Bindings bindings, AccessControlContext context) {
InvocationHandler invocationHandler = new PrivilegedBindings(bindings, context);
// create dynamic invocation proxy
return (Bindings) Proxy.newProxyInstance(PrivilegedBindings.class.getClassLoader(), new Class[] { Bindings.class }, invocationHandler);
@ -227,13 +229,13 @@ public class ExpressionFormat extends Format {
private static class SecureCompiledScript extends CompiledScript {
private final AccessControlContext sandbox;
private final CompiledScript compiledScript;
private final AccessControlContext sandbox;
private SecureCompiledScript(AccessControlContext sandbox, CompiledScript compiledScript) {
this.sandbox = sandbox;
private SecureCompiledScript(CompiledScript compiledScript, AccessControlContext sandbox) {
this.compiledScript = compiledScript;
this.sandbox = sandbox;
}

View File

@ -96,7 +96,7 @@ public abstract class AbstractSearchPanel<S, E> extends JComponent {
AutoCompleteSupport.install(searchTextField.getEditor(), searchHistory).setFilterMode(TextMatcherEditor.CONTAINS);
TunedUtilities.putActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), searchAction);
TunedUtilities.installAction(this, KeyStroke.getKeyStroke("ENTER"), searchAction);
}

View File

@ -10,7 +10,6 @@ import java.awt.Color;
import java.awt.Font;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
@ -45,8 +44,8 @@ import javax.swing.SwingWorker;
import javax.swing.Timer;
import javax.swing.border.LineBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.undo.UndoManager;
import net.miginfocom.swing.MigLayout;
import net.sourceforge.filebot.ResourceManager;
@ -58,6 +57,7 @@ import net.sourceforge.filebot.web.EpisodeFormat;
import net.sourceforge.tuned.DefaultThreadFactory;
import net.sourceforge.tuned.ExceptionUtilities;
import net.sourceforge.tuned.ui.GradientStyle;
import net.sourceforge.tuned.ui.LazyDocumentListener;
import net.sourceforge.tuned.ui.LinkButton;
import net.sourceforge.tuned.ui.ProgressIndicator;
import net.sourceforge.tuned.ui.TunedUtilities;
@ -136,11 +136,18 @@ public class EpisodeFormatDialog extends JDialog {
header.setComponentPopupMenu(createPreviewSamplePopup());
// setup undo support
final UndoManager undo = new UndoManager();
editor.getDocument().addUndoableEditListener(undo);
// enable undo/redo
TunedUtilities.installUndoSupport(editor);
// update format on change
editor.getDocument().addDocumentListener(new LazyDocumentAdapter() {
editor.getDocument().addDocumentListener(new LazyDocumentListener() {
@Override
public void update() {
public void update(DocumentEvent e) {
checkFormatInBackground();
}
});
@ -207,7 +214,7 @@ public class EpisodeFormatDialog extends JDialog {
File mediaFile = fileChooser.getSelectedFile();
try {
MediaInfoComponent.showMessageDialog(EpisodeFormatDialog.this, mediaFile);
MediaInfoPane.showMessageDialog(EpisodeFormatDialog.this, mediaFile);
} catch (LinkageError e) {
// MediaInfo native library is missing -> notify user
Logger.getLogger("ui").log(Level.SEVERE, e.getMessage(), e);
@ -490,43 +497,4 @@ public class EpisodeFormatDialog extends JDialog {
firePropertyChange("previewSample", null, previewSample);
}
protected static abstract class LazyDocumentAdapter implements DocumentListener {
private final Timer timer = new Timer(200, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
update();
}
});
public LazyDocumentAdapter() {
timer.setRepeats(false);
}
@Override
public void changedUpdate(DocumentEvent e) {
timer.restart();
}
@Override
public void insertUpdate(DocumentEvent e) {
timer.restart();
}
@Override
public void removeUpdate(DocumentEvent e) {
timer.restart();
}
public abstract void update();
}
}

View File

@ -50,7 +50,7 @@ public class FileBotList<E> extends JComponent {
// Shortcut DELETE, disabled by default
removeAction.setEnabled(false);
TunedUtilities.putActionForKeystroke(this, KeyStroke.getKeyStroke("pressed DELETE"), removeAction);
TunedUtilities.installAction(this, KeyStroke.getKeyStroke("pressed DELETE"), removeAction);
}

View File

@ -12,6 +12,7 @@ import java.util.Map;
import java.util.Map.Entry;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
@ -26,18 +27,28 @@ import net.sourceforge.filebot.mediainfo.MediaInfo.StreamKind;
import net.sourceforge.tuned.ui.TunedUtilities;
public class MediaInfoComponent extends JTabbedPane {
public class MediaInfoPane extends JTabbedPane {
public MediaInfoComponent(Map<StreamKind, List<Map<String, String>>> mediaInfo) {
insert(mediaInfo);
public MediaInfoPane(File file) {
// get media info
MediaInfo mediaInfo = new MediaInfo();
if (!mediaInfo.open(file))
throw new IllegalArgumentException("Cannot open file: " + file);
// create tab for each stream
for (Entry<StreamKind, List<Map<String, String>>> entry : mediaInfo.snapshot().entrySet()) {
for (Map<String, String> parameters : entry.getValue()) {
addTableTab(entry.getKey().toString(), parameters);
}
}
mediaInfo.close();
}
public void insert(Map<StreamKind, List<Map<String, String>>> mediaInfo) {
// create tabs for all streams
for (Entry<StreamKind, List<Map<String, String>>> entry : mediaInfo.entrySet()) {
for (Map<String, String> parameters : entry.getValue()) {
JTable table = new JTable(new ParameterTableModel(parameters));
public void addTableTab(String title, Map<String, String> data) {
JTable table = new JTable(new ParameterTableModel(data));
// allow sorting
table.setAutoCreateRowSorter(true);
@ -45,42 +56,33 @@ public class MediaInfoComponent extends JTabbedPane {
// sort by parameter name
table.getRowSorter().toggleSortOrder(0);
addTab(entry.getKey().toString(), new JScrollPane(table));
}
}
addTab(title, new JScrollPane(table));
}
public static void showMessageDialog(Component parent, File file) {
final JDialog dialog = new JDialog(TunedUtilities.getWindow(parent), "MediaInfo", ModalityType.DOCUMENT_MODAL);
dialog.setLocation(TunedUtilities.getPreferredLocation(dialog));
dialog.setLocationByPlatform(true);
JComponent c = (JComponent) dialog.getContentPane();
c.setLayout(new MigLayout("fill", "[align center]", "[fill][pref!]"));
MediaInfo mediaInfo = new MediaInfo();
mediaInfo.open(file);
MediaInfoComponent mediaInfoComponent = new MediaInfoComponent(mediaInfo.snapshot());
mediaInfo.close();
c.add(mediaInfoComponent, "grow, wrap");
c.add(new JButton(new AbstractAction("OK") {
Action closeAction = new AbstractAction("OK") {
@Override
public void actionPerformed(ActionEvent e) {
dialog.setVisible(false);
}
}), "wmin 80px, hmin 25px");
};
JComponent c = (JComponent) dialog.getContentPane();
c.setLayout(new MigLayout("fill", "[align center]", "[fill][pref!]"));
c.add(new MediaInfoPane(file), "grow, wrap");
c.add(new JButton(closeAction), "wmin 80px, hmin 25px");
dialog.pack();
dialog.setVisible(true);
}
protected static class ParameterTableModel extends AbstractTableModel {
private static class ParameterTableModel extends AbstractTableModel {
private final List<Entry<String, String>> data;

View File

@ -53,8 +53,8 @@ public class SelectButtonTextField<T> extends JComponent {
editor.setRenderer(new CompletionCellRenderer());
editor.setUI(new TextFieldComboBoxUI());
TunedUtilities.putActionForKeystroke(this, KeyStroke.getKeyStroke("ctrl UP"), new SpinClientAction(-1));
TunedUtilities.putActionForKeystroke(this, KeyStroke.getKeyStroke("ctrl DOWN"), new SpinClientAction(1));
TunedUtilities.installAction(this, KeyStroke.getKeyStroke("ctrl UP"), new SpinClientAction(-1));
TunedUtilities.installAction(this, KeyStroke.getKeyStroke("ctrl DOWN"), new SpinClientAction(1));
}
@ -87,6 +87,7 @@ public class SelectButtonTextField<T> extends JComponent {
public SpinClientAction(int spin) {
super(String.format("Spin%+d", spin));
this.spin = spin;
}

View File

@ -66,7 +66,7 @@ public class SelectDialog<T> extends JDialog {
setLocation(TunedUtilities.getPreferredLocation(this));
// Shortcut Enter
TunedUtilities.putActionForKeystroke(list, KeyStroke.getKeyStroke("released ENTER"), selectAction);
TunedUtilities.installAction(list, KeyStroke.getKeyStroke("released ENTER"), selectAction);
}

View File

@ -53,7 +53,7 @@ class FileTreePanel extends JComponent {
});
// Shortcut DELETE
TunedUtilities.putActionForKeystroke(fileTree, KeyStroke.getKeyStroke("pressed DELETE"), removeAction);
TunedUtilities.installAction(fileTree, KeyStroke.getKeyStroke("pressed DELETE"), removeAction);
}

View File

@ -64,8 +64,8 @@ public class EpisodeListPanel extends AbstractSearchPanel<EpisodeListProvider, E
searchTextField.getSelectButton().addPropertyChangeListener(SelectButton.SELECTED_VALUE, selectButtonListener);
TunedUtilities.putActionForKeystroke(this, KeyStroke.getKeyStroke("shift UP"), new SpinSeasonAction(1));
TunedUtilities.putActionForKeystroke(this, KeyStroke.getKeyStroke("shift DOWN"), new SpinSeasonAction(-1));
TunedUtilities.installAction(this, KeyStroke.getKeyStroke("shift UP"), new SpinSeasonAction(1));
TunedUtilities.installAction(this, KeyStroke.getKeyStroke("shift DOWN"), new SpinSeasonAction(-1));
}
@ -122,6 +122,7 @@ public class EpisodeListPanel extends AbstractSearchPanel<EpisodeListProvider, E
private class SpinSeasonAction extends AbstractAction {
public SpinSeasonAction(int spin) {
super(String.format("Spin%+d", spin));
putValue("spin", spin);
}

View File

@ -88,7 +88,7 @@ public class ListPanel extends JComponent {
list.add(buttonPanel, BorderLayout.SOUTH);
TunedUtilities.putActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), createAction);
TunedUtilities.installAction(this, KeyStroke.getKeyStroke("ENTER"), createAction);
}
private AbstractAction createAction = new AbstractAction("Create") {

View File

@ -4,7 +4,6 @@ package net.sourceforge.filebot.ui.panel.rename;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map.Entry;
@ -84,7 +83,7 @@ class History {
public List<Sequence> sequences() {
return Collections.unmodifiableList(sequences);
return sequences;
}

View File

@ -72,7 +72,7 @@ class ValidateNamesDialog extends JDialog {
setSize(365, 280);
setLocation(TunedUtilities.getPreferredLocation(this));
TunedUtilities.putActionForKeystroke(c, KeyStroke.getKeyStroke("released ESCAPE"), cancelAction);
TunedUtilities.installAction(c, KeyStroke.getKeyStroke("released ESCAPE"), cancelAction);
}

View File

@ -91,7 +91,7 @@ public class SfvPanel extends JComponent {
putClientProperty("transferablePolicy", transferablePolicy);
// Shortcut DELETE
TunedUtilities.putActionForKeystroke(this, KeyStroke.getKeyStroke("pressed DELETE"), removeAction);
TunedUtilities.installAction(this, KeyStroke.getKeyStroke("pressed DELETE"), removeAction);
}

View File

@ -0,0 +1,60 @@
package net.sourceforge.tuned.ui;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public abstract class LazyDocumentListener implements DocumentListener {
private DocumentEvent lastEvent;
private final Timer timer = new Timer(200, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
update(lastEvent);
// we don't need it anymore
lastEvent = null;
}
});
public LazyDocumentListener() {
timer.setRepeats(false);
}
private void defer(DocumentEvent e) {
lastEvent = e;
timer.restart();
}
@Override
public void changedUpdate(DocumentEvent e) {
defer(e);
}
@Override
public void insertUpdate(DocumentEvent e) {
defer(e);
}
@Override
public void removeUpdate(DocumentEvent e) {
defer(e);
}
public abstract void update(DocumentEvent e);
}

View File

@ -18,6 +18,7 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Method;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.ImageIcon;
@ -29,6 +30,8 @@ import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.event.MouseInputListener;
import javax.swing.plaf.basic.BasicTableUI;
import javax.swing.text.JTextComponent;
import javax.swing.undo.UndoManager;
import net.sourceforge.tuned.ExceptionUtilities;
@ -50,13 +53,47 @@ public final class TunedUtilities {
}
public static void putActionForKeystroke(JComponent component, KeyStroke keystroke, Action action) {
Integer key = action.hashCode();
public static void installAction(JComponent component, 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.getActionMap().put(key, action);
}
public static UndoManager installUndoSupport(JTextComponent component) {
final UndoManager undoSupport = new UndoManager();
// install undo listener
component.getDocument().addUndoableEditListener(undoSupport);
// install undo action
installAction(component, KeyStroke.getKeyStroke("control Z"), new AbstractAction("Undo") {
@Override
public void actionPerformed(ActionEvent e) {
if (undoSupport.canUndo())
undoSupport.undo();
}
});
// install redo action
installAction(component, KeyStroke.getKeyStroke("control Y"), new AbstractAction("Redo") {
@Override
public void actionPerformed(ActionEvent e) {
if (undoSupport.canRedo())
undoSupport.redo();
}
});
return undoSupport;
}
public static Window getWindow(Component component) {
if (component == null)
return null;