+ added replaceTrailingBraces() to ExpressionFormat context
+ added Undo/Redo support in EpisodeListDialog * refactoring
This commit is contained in:
parent
216dd4d383
commit
9aad7deae2
|
@ -31,7 +31,11 @@ String.prototype.space = function(replacement) {
|
||||||
* Remove trailing parenthesis including any leading whitespace.
|
* Remove trailing parenthesis including any leading whitespace.
|
||||||
*
|
*
|
||||||
* e.g. "Doctor Who (2005)" -> "Doctor Who"
|
* e.g. "Doctor Who (2005)" -> "Doctor Who"
|
||||||
|
* "Bad Wolf (1)" -> "Bad Wolf, Part 1"
|
||||||
*/
|
*/
|
||||||
String.prototype.removeTrailingBraces = function() {
|
String.prototype.replaceTrailingBraces = function(replacement) {
|
||||||
return this.replace(/\s*\([^\)]*\)$/, "");
|
// use empty string as default replacement
|
||||||
|
var r = replacement ? replacement : "";
|
||||||
|
|
||||||
|
return this.replace(/\s*\(([^\)]*)\)$/, r);
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,7 +117,7 @@ public class ExpressionFormat extends Format {
|
||||||
ScriptContext context = new SimpleScriptContext();
|
ScriptContext context = new SimpleScriptContext();
|
||||||
|
|
||||||
// use privileged bindings so we are not restricted by the script sandbox
|
// 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) {
|
for (Object snipped : compilation) {
|
||||||
if (snipped instanceof CompiledScript) {
|
if (snipped instanceof CompiledScript) {
|
||||||
|
@ -161,7 +161,7 @@ public class ExpressionFormat extends Format {
|
||||||
Object snipped = compilation[i];
|
Object snipped = compilation[i];
|
||||||
|
|
||||||
if (snipped instanceof CompiledScript) {
|
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 static class PrivilegedBindings implements InvocationHandler {
|
||||||
|
|
||||||
private final Bindings bindings;
|
private final Bindings bindings;
|
||||||
|
private final AccessControlContext context;
|
||||||
|
|
||||||
|
|
||||||
private PrivilegedBindings(Bindings bindings) {
|
private PrivilegedBindings(Bindings bindings, AccessControlContext context) {
|
||||||
this.bindings = bindings;
|
this.bindings = bindings;
|
||||||
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -200,7 +202,7 @@ public class ExpressionFormat extends Format {
|
||||||
public Object run() throws Exception {
|
public Object run() throws Exception {
|
||||||
return method.invoke(bindings, args);
|
return method.invoke(bindings, args);
|
||||||
}
|
}
|
||||||
});
|
}, context);
|
||||||
} catch (PrivilegedActionException e) {
|
} catch (PrivilegedActionException e) {
|
||||||
Throwable cause = e.getException();
|
Throwable cause = e.getException();
|
||||||
|
|
||||||
|
@ -216,8 +218,8 @@ public class ExpressionFormat extends Format {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static Bindings newProxy(Bindings bindings) {
|
public static Bindings newProxy(Bindings bindings, AccessControlContext context) {
|
||||||
PrivilegedBindings invocationHandler = new PrivilegedBindings(bindings);
|
InvocationHandler invocationHandler = new PrivilegedBindings(bindings, context);
|
||||||
|
|
||||||
// create dynamic invocation proxy
|
// create dynamic invocation proxy
|
||||||
return (Bindings) Proxy.newProxyInstance(PrivilegedBindings.class.getClassLoader(), new Class[] { Bindings.class }, invocationHandler);
|
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 static class SecureCompiledScript extends CompiledScript {
|
||||||
|
|
||||||
private final AccessControlContext sandbox;
|
|
||||||
private final CompiledScript compiledScript;
|
private final CompiledScript compiledScript;
|
||||||
|
private final AccessControlContext sandbox;
|
||||||
|
|
||||||
|
|
||||||
private SecureCompiledScript(AccessControlContext sandbox, CompiledScript compiledScript) {
|
private SecureCompiledScript(CompiledScript compiledScript, AccessControlContext sandbox) {
|
||||||
this.sandbox = sandbox;
|
|
||||||
this.compiledScript = compiledScript;
|
this.compiledScript = compiledScript;
|
||||||
|
this.sandbox = sandbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@ public abstract class AbstractSearchPanel<S, E> extends JComponent {
|
||||||
|
|
||||||
AutoCompleteSupport.install(searchTextField.getEditor(), searchHistory).setFilterMode(TextMatcherEditor.CONTAINS);
|
AutoCompleteSupport.install(searchTextField.getEditor(), searchHistory).setFilterMode(TextMatcherEditor.CONTAINS);
|
||||||
|
|
||||||
TunedUtilities.putActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), searchAction);
|
TunedUtilities.installAction(this, KeyStroke.getKeyStroke("ENTER"), searchAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ import java.awt.Color;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.awt.event.WindowAdapter;
|
import java.awt.event.WindowAdapter;
|
||||||
import java.awt.event.WindowEvent;
|
import java.awt.event.WindowEvent;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
|
@ -45,8 +44,8 @@ import javax.swing.SwingWorker;
|
||||||
import javax.swing.Timer;
|
import javax.swing.Timer;
|
||||||
import javax.swing.border.LineBorder;
|
import javax.swing.border.LineBorder;
|
||||||
import javax.swing.event.DocumentEvent;
|
import javax.swing.event.DocumentEvent;
|
||||||
import javax.swing.event.DocumentListener;
|
|
||||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||||
|
import javax.swing.undo.UndoManager;
|
||||||
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
import net.sourceforge.filebot.ResourceManager;
|
import net.sourceforge.filebot.ResourceManager;
|
||||||
|
@ -58,6 +57,7 @@ import net.sourceforge.filebot.web.EpisodeFormat;
|
||||||
import net.sourceforge.tuned.DefaultThreadFactory;
|
import net.sourceforge.tuned.DefaultThreadFactory;
|
||||||
import net.sourceforge.tuned.ExceptionUtilities;
|
import net.sourceforge.tuned.ExceptionUtilities;
|
||||||
import net.sourceforge.tuned.ui.GradientStyle;
|
import net.sourceforge.tuned.ui.GradientStyle;
|
||||||
|
import net.sourceforge.tuned.ui.LazyDocumentListener;
|
||||||
import net.sourceforge.tuned.ui.LinkButton;
|
import net.sourceforge.tuned.ui.LinkButton;
|
||||||
import net.sourceforge.tuned.ui.ProgressIndicator;
|
import net.sourceforge.tuned.ui.ProgressIndicator;
|
||||||
import net.sourceforge.tuned.ui.TunedUtilities;
|
import net.sourceforge.tuned.ui.TunedUtilities;
|
||||||
|
@ -136,11 +136,18 @@ public class EpisodeFormatDialog extends JDialog {
|
||||||
|
|
||||||
header.setComponentPopupMenu(createPreviewSamplePopup());
|
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
|
// update format on change
|
||||||
editor.getDocument().addDocumentListener(new LazyDocumentAdapter() {
|
editor.getDocument().addDocumentListener(new LazyDocumentListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update() {
|
public void update(DocumentEvent e) {
|
||||||
checkFormatInBackground();
|
checkFormatInBackground();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -207,7 +214,7 @@ public class EpisodeFormatDialog extends JDialog {
|
||||||
File mediaFile = fileChooser.getSelectedFile();
|
File mediaFile = fileChooser.getSelectedFile();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
MediaInfoComponent.showMessageDialog(EpisodeFormatDialog.this, mediaFile);
|
MediaInfoPane.showMessageDialog(EpisodeFormatDialog.this, mediaFile);
|
||||||
} catch (LinkageError e) {
|
} catch (LinkageError e) {
|
||||||
// MediaInfo native library is missing -> notify user
|
// MediaInfo native library is missing -> notify user
|
||||||
Logger.getLogger("ui").log(Level.SEVERE, e.getMessage(), e);
|
Logger.getLogger("ui").log(Level.SEVERE, e.getMessage(), e);
|
||||||
|
@ -490,43 +497,4 @@ public class EpisodeFormatDialog extends JDialog {
|
||||||
firePropertyChange("previewSample", null, previewSample);
|
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();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ public class FileBotList<E> extends JComponent {
|
||||||
// Shortcut DELETE, disabled by default
|
// Shortcut DELETE, disabled by default
|
||||||
removeAction.setEnabled(false);
|
removeAction.setEnabled(false);
|
||||||
|
|
||||||
TunedUtilities.putActionForKeystroke(this, KeyStroke.getKeyStroke("pressed DELETE"), removeAction);
|
TunedUtilities.installAction(this, KeyStroke.getKeyStroke("pressed DELETE"), removeAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
|
import javax.swing.Action;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
|
@ -26,61 +27,62 @@ import net.sourceforge.filebot.mediainfo.MediaInfo.StreamKind;
|
||||||
import net.sourceforge.tuned.ui.TunedUtilities;
|
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) {
|
public MediaInfoPane(File file) {
|
||||||
insert(mediaInfo);
|
// 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) {
|
public void addTableTab(String title, Map<String, String> data) {
|
||||||
// create tabs for all streams
|
JTable table = new JTable(new ParameterTableModel(data));
|
||||||
for (Entry<StreamKind, List<Map<String, String>>> entry : mediaInfo.entrySet()) {
|
|
||||||
for (Map<String, String> parameters : entry.getValue()) {
|
|
||||||
JTable table = new JTable(new ParameterTableModel(parameters));
|
|
||||||
|
|
||||||
// allow sorting
|
// allow sorting
|
||||||
table.setAutoCreateRowSorter(true);
|
table.setAutoCreateRowSorter(true);
|
||||||
|
|
||||||
// sort by parameter name
|
// sort by parameter name
|
||||||
table.getRowSorter().toggleSortOrder(0);
|
table.getRowSorter().toggleSortOrder(0);
|
||||||
|
|
||||||
addTab(entry.getKey().toString(), new JScrollPane(table));
|
addTab(title, new JScrollPane(table));
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void showMessageDialog(Component parent, File file) {
|
public static void showMessageDialog(Component parent, File file) {
|
||||||
final JDialog dialog = new JDialog(TunedUtilities.getWindow(parent), "MediaInfo", ModalityType.DOCUMENT_MODAL);
|
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();
|
Action closeAction = new AbstractAction("OK") {
|
||||||
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") {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
dialog.setVisible(false);
|
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.pack();
|
||||||
dialog.setVisible(true);
|
dialog.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected static class ParameterTableModel extends AbstractTableModel {
|
private static class ParameterTableModel extends AbstractTableModel {
|
||||||
|
|
||||||
private final List<Entry<String, String>> data;
|
private final List<Entry<String, String>> data;
|
||||||
|
|
|
@ -53,8 +53,8 @@ public class SelectButtonTextField<T> extends JComponent {
|
||||||
editor.setRenderer(new CompletionCellRenderer());
|
editor.setRenderer(new CompletionCellRenderer());
|
||||||
editor.setUI(new TextFieldComboBoxUI());
|
editor.setUI(new TextFieldComboBoxUI());
|
||||||
|
|
||||||
TunedUtilities.putActionForKeystroke(this, KeyStroke.getKeyStroke("ctrl UP"), new SpinClientAction(-1));
|
TunedUtilities.installAction(this, KeyStroke.getKeyStroke("ctrl UP"), new SpinClientAction(-1));
|
||||||
TunedUtilities.putActionForKeystroke(this, KeyStroke.getKeyStroke("ctrl DOWN"), 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) {
|
public SpinClientAction(int spin) {
|
||||||
|
super(String.format("Spin%+d", spin));
|
||||||
this.spin = spin;
|
this.spin = spin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ public class SelectDialog<T> extends JDialog {
|
||||||
setLocation(TunedUtilities.getPreferredLocation(this));
|
setLocation(TunedUtilities.getPreferredLocation(this));
|
||||||
|
|
||||||
// Shortcut Enter
|
// Shortcut Enter
|
||||||
TunedUtilities.putActionForKeystroke(list, KeyStroke.getKeyStroke("released ENTER"), selectAction);
|
TunedUtilities.installAction(list, KeyStroke.getKeyStroke("released ENTER"), selectAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ class FileTreePanel extends JComponent {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Shortcut DELETE
|
// Shortcut DELETE
|
||||||
TunedUtilities.putActionForKeystroke(fileTree, KeyStroke.getKeyStroke("pressed DELETE"), removeAction);
|
TunedUtilities.installAction(fileTree, KeyStroke.getKeyStroke("pressed DELETE"), removeAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -64,8 +64,8 @@ public class EpisodeListPanel extends AbstractSearchPanel<EpisodeListProvider, E
|
||||||
|
|
||||||
searchTextField.getSelectButton().addPropertyChangeListener(SelectButton.SELECTED_VALUE, selectButtonListener);
|
searchTextField.getSelectButton().addPropertyChangeListener(SelectButton.SELECTED_VALUE, selectButtonListener);
|
||||||
|
|
||||||
TunedUtilities.putActionForKeystroke(this, KeyStroke.getKeyStroke("shift UP"), new SpinSeasonAction(1));
|
TunedUtilities.installAction(this, KeyStroke.getKeyStroke("shift UP"), new SpinSeasonAction(1));
|
||||||
TunedUtilities.putActionForKeystroke(this, KeyStroke.getKeyStroke("shift DOWN"), 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 {
|
private class SpinSeasonAction extends AbstractAction {
|
||||||
|
|
||||||
public SpinSeasonAction(int spin) {
|
public SpinSeasonAction(int spin) {
|
||||||
|
super(String.format("Spin%+d", spin));
|
||||||
putValue("spin", spin);
|
putValue("spin", spin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,7 @@ public class ListPanel extends JComponent {
|
||||||
|
|
||||||
list.add(buttonPanel, BorderLayout.SOUTH);
|
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") {
|
private AbstractAction createAction = new AbstractAction("Create") {
|
||||||
|
|
|
@ -4,7 +4,6 @@ package net.sourceforge.filebot.ui.panel.rename;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
@ -84,7 +83,7 @@ class History {
|
||||||
|
|
||||||
|
|
||||||
public List<Sequence> sequences() {
|
public List<Sequence> sequences() {
|
||||||
return Collections.unmodifiableList(sequences);
|
return sequences;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ class ValidateNamesDialog extends JDialog {
|
||||||
setSize(365, 280);
|
setSize(365, 280);
|
||||||
setLocation(TunedUtilities.getPreferredLocation(this));
|
setLocation(TunedUtilities.getPreferredLocation(this));
|
||||||
|
|
||||||
TunedUtilities.putActionForKeystroke(c, KeyStroke.getKeyStroke("released ESCAPE"), cancelAction);
|
TunedUtilities.installAction(c, KeyStroke.getKeyStroke("released ESCAPE"), cancelAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ public class SfvPanel extends JComponent {
|
||||||
putClientProperty("transferablePolicy", transferablePolicy);
|
putClientProperty("transferablePolicy", transferablePolicy);
|
||||||
|
|
||||||
// Shortcut DELETE
|
// Shortcut DELETE
|
||||||
TunedUtilities.putActionForKeystroke(this, KeyStroke.getKeyStroke("pressed DELETE"), removeAction);
|
TunedUtilities.installAction(this, KeyStroke.getKeyStroke("pressed DELETE"), removeAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
|
@ -29,6 +30,8 @@ import javax.swing.SwingUtilities;
|
||||||
import javax.swing.Timer;
|
import javax.swing.Timer;
|
||||||
import javax.swing.event.MouseInputListener;
|
import javax.swing.event.MouseInputListener;
|
||||||
import javax.swing.plaf.basic.BasicTableUI;
|
import javax.swing.plaf.basic.BasicTableUI;
|
||||||
|
import javax.swing.text.JTextComponent;
|
||||||
|
import javax.swing.undo.UndoManager;
|
||||||
|
|
||||||
import net.sourceforge.tuned.ExceptionUtilities;
|
import net.sourceforge.tuned.ExceptionUtilities;
|
||||||
|
|
||||||
|
@ -50,13 +53,47 @@ public final class TunedUtilities {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void putActionForKeystroke(JComponent component, KeyStroke keystroke, Action action) {
|
public static void installAction(JComponent component, KeyStroke keystroke, Action action) {
|
||||||
Integer key = action.hashCode();
|
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(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(keystroke, key);
|
||||||
component.getActionMap().put(key, action);
|
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) {
|
public static Window getWindow(Component component) {
|
||||||
if (component == null)
|
if (component == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
Loading…
Reference in New Issue