mirror of
https://github.com/mitb-archive/filebot
synced 2024-12-23 08:18:52 -05:00
* added media info button in EpisodeBindingDialog
* improved dialog positioning * minor bugfixes * refactoring
This commit is contained in:
parent
f737e7c5fb
commit
3b147b325f
@ -18,9 +18,8 @@ public class AssociativeScriptObject implements Scriptable {
|
||||
private final Map<String, Object> properties;
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public AssociativeScriptObject(Map<String, ?> properties) {
|
||||
this.properties = new LenientLookup((Map<String, Object>) properties);
|
||||
this.properties = new LenientLookup(properties);
|
||||
}
|
||||
|
||||
|
||||
@ -156,15 +155,15 @@ public class AssociativeScriptObject implements Scriptable {
|
||||
* Map allowing look-up of values by a fault-tolerant key as specified by the defining key.
|
||||
*
|
||||
*/
|
||||
private class LenientLookup extends AbstractMap<String, Object> {
|
||||
private static class LenientLookup extends AbstractMap<String, Object> {
|
||||
|
||||
private final Map<String, Entry<String, Object>> source = new HashMap<String, Entry<String, Object>>();
|
||||
private final Map<String, Entry<String, ?>> lookup = new HashMap<String, Entry<String, ?>>();
|
||||
|
||||
|
||||
public LenientLookup(Map<String, Object> source) {
|
||||
// populate entry map
|
||||
for (Entry<String, Object> entry : source.entrySet()) {
|
||||
this.source.put(definingKey(entry.getKey()), entry);
|
||||
public LenientLookup(Map<String, ?> source) {
|
||||
// populate lookup map
|
||||
for (Entry<String, ?> entry : source.entrySet()) {
|
||||
lookup.put(definingKey(entry.getKey()), entry);
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,13 +176,13 @@ public class AssociativeScriptObject implements Scriptable {
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return source.containsKey(definingKey(key));
|
||||
return lookup.containsKey(definingKey(key));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
Entry<String, Object> entry = source.get(definingKey(key));
|
||||
Entry<String, ?> entry = lookup.get(definingKey(key));
|
||||
|
||||
if (entry != null)
|
||||
return entry.getValue();
|
||||
@ -198,13 +197,15 @@ public class AssociativeScriptObject implements Scriptable {
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<String, Object>> iterator() {
|
||||
return source.values().iterator();
|
||||
@SuppressWarnings("unchecked")
|
||||
Iterator<Entry<String, Object>> iterator = (Iterator) lookup.values().iterator();
|
||||
return iterator;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return source.size();
|
||||
return lookup.size();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -211,11 +211,11 @@ public class EpisodeBindingBean {
|
||||
private void checkMediaFile() throws RuntimeException {
|
||||
// make sure file is not null, and that it is an existing file
|
||||
if (mediaFile == null || !mediaFile.isFile())
|
||||
throw new RuntimeException(String.format("Illegal media file: %s", mediaFile));
|
||||
throw new RuntimeException(String.format("Invalid media file: %s", mediaFile));
|
||||
}
|
||||
|
||||
|
||||
private MediaInfo getMediaInfo() {
|
||||
private synchronized MediaInfo getMediaInfo() {
|
||||
if (mediaInfo == null) {
|
||||
// make sure media file is defined
|
||||
checkMediaFile();
|
||||
|
@ -41,7 +41,7 @@ public class MediaInfo implements Closeable {
|
||||
|
||||
|
||||
public synchronized boolean open(File file) {
|
||||
return MediaInfoLibrary.INSTANCE.Open(handle, new WString(file.getAbsolutePath())) > 0;
|
||||
return file.isFile() && MediaInfoLibrary.INSTANCE.Open(handle, new WString(file.getAbsolutePath())) > 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -3,6 +3,7 @@ package net.sourceforge.filebot.ui;
|
||||
|
||||
|
||||
import static javax.swing.ScrollPaneConstants.*;
|
||||
import static net.sourceforge.tuned.ui.TunedUtilities.*;
|
||||
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ActionEvent;
|
||||
@ -40,7 +41,6 @@ import net.sourceforge.filebot.web.SearchResult;
|
||||
import net.sourceforge.tuned.ExceptionUtilities;
|
||||
import net.sourceforge.tuned.ListChangeSynchronizer;
|
||||
import net.sourceforge.tuned.ui.LabelProvider;
|
||||
import net.sourceforge.tuned.ui.TunedUtilities;
|
||||
|
||||
|
||||
public abstract class AbstractSearchPanel<S, E> extends JComponent {
|
||||
@ -97,7 +97,7 @@ public abstract class AbstractSearchPanel<S, E> extends JComponent {
|
||||
|
||||
AutoCompleteSupport.install(searchTextField.getEditor(), searchHistory).setFilterMode(TextMatcherEditor.CONTAINS);
|
||||
|
||||
TunedUtilities.installAction(this, KeyStroke.getKeyStroke("ENTER"), searchAction);
|
||||
installAction(this, KeyStroke.getKeyStroke("ENTER"), searchAction);
|
||||
}
|
||||
|
||||
|
||||
@ -383,7 +383,6 @@ public abstract class AbstractSearchPanel<S, E> extends JComponent {
|
||||
protected SearchResult selectSearchResult(Collection<? extends SearchResult> searchResults, Window window) throws Exception {
|
||||
// multiple results have been found, user must select one
|
||||
SelectDialog<SearchResult> selectDialog = new SelectDialog<SearchResult>(window, searchResults);
|
||||
|
||||
configureSelectDialog(selectDialog);
|
||||
|
||||
selectDialog.setVisible(true);
|
||||
@ -394,7 +393,8 @@ public abstract class AbstractSearchPanel<S, E> extends JComponent {
|
||||
|
||||
|
||||
protected void configureSelectDialog(SelectDialog<SearchResult> selectDialog) {
|
||||
selectDialog.setIconImage(TunedUtilities.getImage(getIcon()));
|
||||
selectDialog.setLocation(getOffsetLocation(selectDialog.getOwner()));
|
||||
selectDialog.setIconImage(getImage(getIcon()));
|
||||
}
|
||||
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
package net.sourceforge.filebot.ui;
|
||||
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ActionEvent;
|
||||
@ -48,7 +49,14 @@ public class SelectDialog<T> extends JDialog {
|
||||
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
list.setSelectedIndex(0);
|
||||
|
||||
DefaultFancyListCellRenderer renderer = new DefaultFancyListCellRenderer(4);
|
||||
DefaultFancyListCellRenderer renderer = new DefaultFancyListCellRenderer(4) {
|
||||
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
return super.getListCellRendererComponent(list, convertValueToString(value), index, isSelected, cellHasFocus);
|
||||
}
|
||||
};
|
||||
|
||||
renderer.setHighlightingEnabled(false);
|
||||
|
||||
list.setCellRenderer(renderer);
|
||||
@ -66,7 +74,6 @@ public class SelectDialog<T> extends JDialog {
|
||||
|
||||
// set default size and location
|
||||
setSize(new Dimension(210, 210));
|
||||
setLocation(TunedUtilities.getPreferredLocation(this));
|
||||
|
||||
// Shortcut Enter
|
||||
TunedUtilities.installAction(list, KeyStroke.getKeyStroke("released ENTER"), selectAction);
|
||||
|
@ -3,6 +3,7 @@ package net.sourceforge.filebot.ui.panel.rename;
|
||||
|
||||
|
||||
import static net.sourceforge.filebot.FileBotUtilities.*;
|
||||
import static net.sourceforge.tuned.ui.TunedUtilities.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
@ -109,6 +110,7 @@ class AutoFetchEpisodeListMatcher extends SwingWorker<List<Match<File, Episode>>
|
||||
selectDialog.getCancelAction().putValue(Action.NAME, "Ignore");
|
||||
|
||||
// show dialog
|
||||
selectDialog.setLocation(getOffsetLocation(selectDialog.getOwner()));
|
||||
selectDialog.setVisible(true);
|
||||
|
||||
// selected value or null if the dialog was canceled by the user
|
||||
|
@ -14,8 +14,10 @@ import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.TreeMap;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
@ -38,6 +40,7 @@ import javax.swing.JScrollPane;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.RowFilter;
|
||||
import javax.swing.SwingWorker;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
@ -45,12 +48,15 @@ import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
import javax.swing.table.TableModel;
|
||||
import javax.swing.table.TableRowSorter;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import net.sourceforge.filebot.MediaTypes;
|
||||
import net.sourceforge.filebot.ResourceManager;
|
||||
import net.sourceforge.filebot.format.EpisodeBindingBean;
|
||||
import net.sourceforge.filebot.format.ExpressionFormat;
|
||||
import net.sourceforge.filebot.mediainfo.MediaInfo;
|
||||
import net.sourceforge.filebot.mediainfo.MediaInfo.StreamKind;
|
||||
import net.sourceforge.filebot.web.Episode;
|
||||
import net.sourceforge.filebot.web.EpisodeFormat;
|
||||
import net.sourceforge.tuned.DefaultThreadFactory;
|
||||
@ -76,11 +82,6 @@ class EpisodeBindingDialog extends JDialog {
|
||||
public EpisodeBindingDialog(Window owner) {
|
||||
super(owner, "Episode Bindings", ModalityType.DOCUMENT_MODAL);
|
||||
|
||||
// create image button from action
|
||||
JButton selectFileButton = new JButton(selectFileAction);
|
||||
selectFileButton.setHideActionText(true);
|
||||
selectFileButton.setOpaque(false);
|
||||
|
||||
JComponent root = (JComponent) getContentPane();
|
||||
root.setLayout(new MigLayout("nogrid, fill, insets dialog"));
|
||||
|
||||
@ -96,7 +97,8 @@ class EpisodeBindingDialog extends JDialog {
|
||||
|
||||
inputPanel.add(new JLabel("Media File:"), "wrap 2px");
|
||||
inputPanel.add(mediaFileTextField, "hmin 20px, growx");
|
||||
inputPanel.add(selectFileButton, "gap rel, w 26px!, h 24px!, wrap paragraph");
|
||||
inputPanel.add(createImageButton(mediaInfoAction), "gap rel, w 26px!, h 24px!");
|
||||
inputPanel.add(createImageButton(selectFileAction), "gap rel, w 26px!, h 24px!, wrap paragraph");
|
||||
|
||||
inputContainer.add("Episode Bindings", inputPanel);
|
||||
root.add(inputContainer, "growx, wrap paragraph");
|
||||
@ -120,9 +122,34 @@ class EpisodeBindingDialog extends JDialog {
|
||||
}
|
||||
};
|
||||
|
||||
// update example bindings on change
|
||||
episodeTextField.getDocument().addDocumentListener(changeListener);
|
||||
mediaFileTextField.getDocument().addDocumentListener(changeListener);
|
||||
|
||||
// disabled by default
|
||||
mediaInfoAction.setEnabled(false);
|
||||
|
||||
// disable media info action if media file is invalid
|
||||
mediaFileTextField.getDocument().addDocumentListener(new DocumentListener() {
|
||||
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
mediaInfoAction.setEnabled(getMediaFile() != null && getMediaFile().isFile());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
changedUpdate(e);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
changedUpdate(e);
|
||||
}
|
||||
});
|
||||
|
||||
// finish dialog and close window manually
|
||||
addWindowListener(new WindowAdapter() {
|
||||
|
||||
@ -134,15 +161,22 @@ class EpisodeBindingDialog extends JDialog {
|
||||
|
||||
// initialize window properties
|
||||
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
|
||||
setLocation(getPreferredLocation(this));
|
||||
setSize(420, 520);
|
||||
}
|
||||
|
||||
|
||||
private JButton createImageButton(Action action) {
|
||||
JButton button = new JButton(action);
|
||||
button.setHideActionText(true);
|
||||
button.setOpaque(false);
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
|
||||
private JTable createBindingTable(TableModel model) {
|
||||
JTable table = new JTable(model);
|
||||
table.setAutoCreateRowSorter(true);
|
||||
|
||||
table.setFillsViewportHeight(true);
|
||||
table.setBackground(Color.white);
|
||||
|
||||
@ -270,6 +304,87 @@ class EpisodeBindingDialog extends JDialog {
|
||||
}
|
||||
};
|
||||
|
||||
protected final Action mediaInfoAction = new AbstractAction("Info", ResourceManager.getIcon("action.properties")) {
|
||||
|
||||
private Map<StreamKind, List<Map<String, String>>> getMediaInfo(File file) {
|
||||
try {
|
||||
MediaInfo mediaInfo = new MediaInfo();
|
||||
|
||||
// read all media info
|
||||
if (mediaInfo.open(file)) {
|
||||
try {
|
||||
return mediaInfo.snapshot();
|
||||
} finally {
|
||||
mediaInfo.close();
|
||||
}
|
||||
}
|
||||
} catch (LinkageError e) {
|
||||
Logger.getLogger("ui").log(Level.SEVERE, "Unable to load native library 'mediainfo'", e);
|
||||
}
|
||||
|
||||
// could not retrieve media info
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
Map<StreamKind, List<Map<String, String>>> mediaInfo = getMediaInfo(getMediaFile());
|
||||
|
||||
// check if we could get some info
|
||||
if (mediaInfo == null)
|
||||
return;
|
||||
|
||||
// create table tab for each stream
|
||||
JTabbedPane tabbedPane = new JTabbedPane();
|
||||
|
||||
ResourceBundle bundle = ResourceBundle.getBundle(EpisodeBindingDialog.class.getName());
|
||||
RowFilter<Object, Object> excludeRowFilter = RowFilter.notFilter(RowFilter.regexFilter(bundle.getString("parameter.exclude")));
|
||||
|
||||
for (StreamKind streamKind : mediaInfo.keySet()) {
|
||||
for (Map<String, String> parameters : mediaInfo.get(streamKind)) {
|
||||
JPanel panel = new JPanel(new MigLayout("fill"));
|
||||
panel.setOpaque(false);
|
||||
|
||||
JTable table = new JTable(new ParameterTableModel(parameters));
|
||||
table.setAutoCreateRowSorter(true);
|
||||
table.setFillsViewportHeight(true);
|
||||
table.setBackground(Color.white);
|
||||
|
||||
// set media info exclude filter
|
||||
TableRowSorter<?> sorter = (TableRowSorter<?>) table.getRowSorter();
|
||||
sorter.setRowFilter(excludeRowFilter);
|
||||
|
||||
panel.add(new JScrollPane(table), "grow");
|
||||
tabbedPane.addTab(streamKind.toString(), panel);
|
||||
}
|
||||
}
|
||||
|
||||
// show media info dialog
|
||||
final JDialog dialog = new JDialog(getWindow(evt.getSource()), "MediaInfo", ModalityType.DOCUMENT_MODAL);
|
||||
|
||||
Action closeAction = new AbstractAction("OK") {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
dialog.setVisible(false);
|
||||
dialog.dispose();
|
||||
}
|
||||
};
|
||||
|
||||
JComponent c = (JComponent) dialog.getContentPane();
|
||||
c.setLayout(new MigLayout("fill", "[align center]", "[fill][pref!]"));
|
||||
c.add(tabbedPane, "grow, wrap");
|
||||
c.add(new JButton(closeAction), "wmin 80px, hmin 25px");
|
||||
|
||||
dialog.pack();
|
||||
dialog.setLocationRelativeTo(EpisodeBindingDialog.this);
|
||||
|
||||
dialog.setVisible(true);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
protected final Action selectFileAction = new AbstractAction("Select File", ResourceManager.getIcon("action.load")) {
|
||||
|
||||
@Override
|
||||
@ -287,24 +402,55 @@ class EpisodeBindingDialog extends JDialog {
|
||||
chooser.setMultiSelectionEnabled(false);
|
||||
|
||||
if (chooser.showOpenDialog(getWindow(evt.getSource())) == JFileChooser.APPROVE_OPTION) {
|
||||
File selectedFile = chooser.getSelectedFile();
|
||||
|
||||
if (selectedFile.isFile()) {
|
||||
try {
|
||||
// display media info
|
||||
MediaInfoPane.showMessageDialog(getWindow(evt.getSource()), selectedFile);
|
||||
} catch (LinkageError e) {
|
||||
Logger.getLogger("ui").log(Level.SEVERE, "Unable to load native library 'mediainfo'", e);
|
||||
}
|
||||
|
||||
// update text field
|
||||
mediaFileTextField.setText(selectedFile.getAbsolutePath());
|
||||
}
|
||||
// update text field
|
||||
mediaFileTextField.setText(chooser.getSelectedFile().getAbsolutePath());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private static class Evaluator extends SwingWorker<String, Void> {
|
||||
|
||||
private final String expression;
|
||||
private final Object bindingBean;
|
||||
|
||||
|
||||
private Evaluator(String expression, Object bindingBean) {
|
||||
this.expression = expression;
|
||||
this.bindingBean = bindingBean;
|
||||
}
|
||||
|
||||
|
||||
public String getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String doInBackground() throws Exception {
|
||||
ExpressionFormat format = new ExpressionFormat(expression) {
|
||||
|
||||
@Override
|
||||
protected Object[] compile(String expression, Compilable engine) throws ScriptException {
|
||||
// simple expression format, everything as one expression
|
||||
return new Object[] { engine.compile(expression) };
|
||||
}
|
||||
};
|
||||
|
||||
// evaluate expression with given bindings
|
||||
String value = format.format(bindingBean);
|
||||
|
||||
// check for script exceptions
|
||||
if (format.caughtScriptException() != null) {
|
||||
throw format.caughtScriptException();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static class BindingTableModel extends AbstractTableModel {
|
||||
|
||||
private final List<Evaluator> model = new ArrayList<Evaluator>();
|
||||
@ -410,45 +556,52 @@ class EpisodeBindingDialog extends JDialog {
|
||||
}
|
||||
|
||||
|
||||
private static class Evaluator extends SwingWorker<String, Void> {
|
||||
private static class ParameterTableModel extends AbstractTableModel {
|
||||
|
||||
private final String expression;
|
||||
private final Object bindingBean;
|
||||
private final List<Entry<?, ?>> data;
|
||||
|
||||
|
||||
private Evaluator(String expression, Object bindingBean) {
|
||||
this.expression = expression;
|
||||
this.bindingBean = bindingBean;
|
||||
}
|
||||
|
||||
|
||||
public String getExpression() {
|
||||
return expression;
|
||||
public ParameterTableModel(Map<?, ?> data) {
|
||||
this.data = new ArrayList<Entry<?, ?>>(data.entrySet());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String doInBackground() throws Exception {
|
||||
ExpressionFormat format = new ExpressionFormat(expression) {
|
||||
|
||||
@Override
|
||||
protected Object[] compile(String expression, Compilable engine) throws ScriptException {
|
||||
// simple expression format, everything as one expression
|
||||
return new Object[] { engine.compile(expression) };
|
||||
}
|
||||
};
|
||||
|
||||
// evaluate expression with given bindings
|
||||
String value = format.format(bindingBean);
|
||||
|
||||
// check for script exceptions
|
||||
if (format.caughtScriptException() != null) {
|
||||
throw format.caughtScriptException();
|
||||
}
|
||||
|
||||
return value;
|
||||
public int getRowCount() {
|
||||
return data.size();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getColumnName(int column) {
|
||||
switch (column) {
|
||||
case 0:
|
||||
return "Parameter";
|
||||
case 1:
|
||||
return "Value";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int row, int column) {
|
||||
switch (column) {
|
||||
case 0:
|
||||
return data.get(row).getKey();
|
||||
case 1:
|
||||
return data.get(row).getValue();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
# expressions are tagged so they can be sorted alphabetically
|
||||
# exclude pattern for media info dialog
|
||||
parameter.exclude: ^StreamKind|Count$
|
||||
|
||||
# preview expressions (keys are tagged so they can be sorted alphabetically)
|
||||
|
||||
# episode expressions
|
||||
expr[a1]: n
|
||||
@ -22,22 +25,22 @@ expr[c4]: crc32
|
||||
|
||||
# media info expressions [media]
|
||||
expr[d1]: media.title
|
||||
expr[d2]: media.DurationString
|
||||
expr[d3]: media.OverallBitRateString
|
||||
expr[d2]: media.durationString
|
||||
expr[d3]: media.overallBitRateString
|
||||
|
||||
# media info expressions [video]
|
||||
expr[e1]: video.Codec
|
||||
expr[e2]: video.FrameRate
|
||||
expr[e3]: video.DisplayAspectRatioString
|
||||
expr[e4]: video.Height
|
||||
expr[e5]: video.InterlacementString
|
||||
expr[e1]: video.codec
|
||||
expr[e2]: video.frameRate
|
||||
expr[e3]: video.displayAspectRatioString
|
||||
expr[e4]: video.height
|
||||
expr[e5]: video.interlacementString
|
||||
|
||||
# media info expressions [audio]
|
||||
expr[f1]: audio.Codec
|
||||
expr[f2]: audio.Channels
|
||||
expr[f3]: audio.BitRateString
|
||||
expr[f4]: audio.Language
|
||||
expr[f1]: audio.codec
|
||||
expr[f2]: audio.channels
|
||||
expr[f3]: audio.bitRateString
|
||||
expr[f4]: audio.language
|
||||
|
||||
# media info expressions [text]
|
||||
expr[g1]: text.CodecInfo
|
||||
expr[g2]: text.Language
|
||||
expr[g1]: text.codecInfo
|
||||
expr[g2]: text.language
|
||||
|
@ -7,6 +7,7 @@ import static javax.swing.BorderFactory.*;
|
||||
import static net.sourceforge.tuned.ui.TunedUtilities.*;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Font;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ActionEvent;
|
||||
@ -194,7 +195,6 @@ class EpisodeFormatDialog extends JDialog {
|
||||
|
||||
// initialize window properties
|
||||
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
|
||||
setLocation(getPreferredLocation(this));
|
||||
pack();
|
||||
}
|
||||
|
||||
@ -423,6 +423,7 @@ class EpisodeFormatDialog extends JDialog {
|
||||
dialog.setMediaFile(sample.getMediaFile());
|
||||
|
||||
// open dialog
|
||||
dialog.setLocationRelativeTo((Component) evt.getSource());
|
||||
dialog.setVisible(true);
|
||||
|
||||
if (dialog.getSelectedOption() == EpisodeBindingDialog.Option.APPROVE) {
|
||||
|
@ -2,6 +2,8 @@
|
||||
package net.sourceforge.filebot.ui.panel.rename;
|
||||
|
||||
|
||||
import static net.sourceforge.tuned.ui.TunedUtilities.*;
|
||||
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ActionEvent;
|
||||
@ -15,8 +17,6 @@ import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.SwingWorker;
|
||||
|
||||
import net.sourceforge.filebot.ResourceManager;
|
||||
@ -46,9 +46,8 @@ class MatchAction extends AbstractAction {
|
||||
if (model.names().isEmpty() || model.files().isEmpty())
|
||||
return;
|
||||
|
||||
JComponent eventSource = (JComponent) evt.getSource();
|
||||
|
||||
SwingUtilities.getRoot(eventSource).setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
Window window = getWindow(evt.getSource());
|
||||
window.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
|
||||
BackgroundMatcher backgroundMatcher = new BackgroundMatcher(model, MatchSimilarityMetric.defaultSequence());
|
||||
backgroundMatcher.execute();
|
||||
@ -58,15 +57,16 @@ class MatchAction extends AbstractAction {
|
||||
backgroundMatcher.get(2, TimeUnit.SECONDS);
|
||||
} catch (TimeoutException ex) {
|
||||
// matcher will probably take a while
|
||||
ProgressDialog progressDialog = createProgressDialog(SwingUtilities.getWindowAncestor(eventSource), backgroundMatcher);
|
||||
ProgressDialog dialog = createProgressDialog(window, backgroundMatcher);
|
||||
dialog.setLocation(getOffsetLocation(dialog.getOwner()));
|
||||
|
||||
// display progress dialog and stop blocking EDT
|
||||
progressDialog.setVisible(true);
|
||||
dialog.setVisible(true);
|
||||
} catch (Exception e) {
|
||||
Logger.getLogger(getClass().getName()).log(Level.SEVERE, e.toString(), e);
|
||||
}
|
||||
|
||||
SwingUtilities.getRoot(eventSource).setCursor(Cursor.getDefaultCursor());
|
||||
window.setCursor(Cursor.getDefaultCursor());
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,136 +0,0 @@
|
||||
|
||||
package net.sourceforge.filebot.ui.panel.rename;
|
||||
|
||||
|
||||
import static net.sourceforge.tuned.ui.TunedUtilities.*;
|
||||
|
||||
import java.awt.Window;
|
||||
import java.awt.Dialog.ModalityType;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
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;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import net.sourceforge.filebot.mediainfo.MediaInfo;
|
||||
import net.sourceforge.filebot.mediainfo.MediaInfo.StreamKind;
|
||||
|
||||
|
||||
class MediaInfoPane extends JTabbedPane {
|
||||
|
||||
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 addTableTab(String title, Map<String, String> data) {
|
||||
JTable table = new JTable(new ParameterTableModel(data));
|
||||
table.setFillsViewportHeight(true);
|
||||
|
||||
// allow sorting
|
||||
table.setAutoCreateRowSorter(true);
|
||||
|
||||
// sort by parameter name
|
||||
table.getRowSorter().toggleSortOrder(0);
|
||||
|
||||
addTab(title, new JScrollPane(table));
|
||||
}
|
||||
|
||||
|
||||
public static void showMessageDialog(Window parent, File file) {
|
||||
final JDialog dialog = new JDialog(parent, "MediaInfo", ModalityType.DOCUMENT_MODAL);
|
||||
|
||||
Action closeAction = new AbstractAction("OK") {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
dialog.setVisible(false);
|
||||
dialog.dispose();
|
||||
}
|
||||
};
|
||||
|
||||
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.setLocation(getPreferredLocation(dialog));
|
||||
dialog.pack();
|
||||
|
||||
dialog.setVisible(true);
|
||||
}
|
||||
|
||||
|
||||
private static class ParameterTableModel extends AbstractTableModel {
|
||||
|
||||
private final List<Entry<String, String>> data;
|
||||
|
||||
|
||||
public ParameterTableModel(Map<String, String> data) {
|
||||
this.data = new ArrayList<Entry<String, String>>(data.entrySet());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return data.size();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getColumnName(int column) {
|
||||
switch (column) {
|
||||
case 0:
|
||||
return "Parameter";
|
||||
case 1:
|
||||
return "Value";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int row, int column) {
|
||||
switch (column) {
|
||||
case 0:
|
||||
return data.get(row).getKey();
|
||||
case 1:
|
||||
return data.get(row).getValue();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -152,7 +152,7 @@ public class RenamePanel extends JComponent {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
EpisodeFormatDialog dialog = new EpisodeFormatDialog(SwingUtilities.getWindowAncestor(RenamePanel.this));
|
||||
|
||||
dialog.setLocation(getOffsetLocation(dialog.getOwner()));
|
||||
dialog.setVisible(true);
|
||||
|
||||
switch (dialog.getSelectedOption()) {
|
||||
@ -191,6 +191,7 @@ public class RenamePanel extends JComponent {
|
||||
History model = HistorySpooler.getInstance().getCompleteHistory();
|
||||
|
||||
HistoryDialog dialog = new HistoryDialog(getWindow(RenamePanel.this));
|
||||
dialog.setLocationRelativeTo(RenamePanel.this);
|
||||
dialog.setModel(model);
|
||||
|
||||
// show and block
|
||||
|
@ -48,9 +48,8 @@ public class SfvPanel extends JComponent {
|
||||
private final ChecksumTableTransferablePolicy transferablePolicy = new ChecksumTableTransferablePolicy(table.getModel(), computationService);
|
||||
private final ChecksumTableExportHandler exportHandler = new ChecksumTableExportHandler(table.getModel());
|
||||
|
||||
|
||||
|
||||
public SfvPanel() {
|
||||
|
||||
table.setTransferHandler(new DefaultTransferHandler(transferablePolicy, exportHandler));
|
||||
|
||||
JPanel contentPane = new JPanel(new MigLayout("insets 0, nogrid, fill", "", "[fill]10px[bottom, pref!]4px"));
|
||||
@ -128,6 +127,7 @@ public class SfvPanel extends JComponent {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final SaveAction saveAction = new ChecksumTableSaveAction();
|
||||
|
||||
private final LoadAction loadAction = new LoadAction(transferablePolicy);
|
||||
@ -176,7 +176,7 @@ public class SfvPanel extends JComponent {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
protected class ChangeHashTypeAction extends AbstractAction implements PropertyChangeListener {
|
||||
|
||||
private ChangeHashTypeAction(HashType hash) {
|
||||
@ -215,7 +215,7 @@ public class SfvPanel extends JComponent {
|
||||
|
||||
private File selectedColumn = null;
|
||||
|
||||
|
||||
|
||||
public ChecksumTableSaveAction() {
|
||||
super(exportHandler);
|
||||
}
|
||||
@ -282,6 +282,7 @@ public class SfvPanel extends JComponent {
|
||||
};
|
||||
|
||||
selectDialog.getHeaderLabel().setText("Select checksum column:");
|
||||
selectDialog.setLocationRelativeTo(SfvPanel.this);
|
||||
selectDialog.setVisible(true);
|
||||
|
||||
this.selectedColumn = selectDialog.getSelectedValue();
|
||||
|
@ -110,10 +110,8 @@ public abstract class AbstractFancyListCellRenderer extends JPanel implements Li
|
||||
|
||||
|
||||
@Override
|
||||
public final Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
|
||||
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
configureListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||
|
||||
validate();
|
||||
|
||||
return this;
|
||||
|
@ -25,7 +25,7 @@ public class ProgressDialog extends JDialog {
|
||||
|
||||
private final Cancellable cancellable;
|
||||
|
||||
|
||||
|
||||
public ProgressDialog(Window owner, Cancellable cancellable) {
|
||||
super(owner, ModalityType.DOCUMENT_MODAL);
|
||||
|
||||
@ -39,7 +39,6 @@ public class ProgressDialog extends JDialog {
|
||||
progressBar.setStringPainted(true);
|
||||
|
||||
JPanel c = (JPanel) getContentPane();
|
||||
|
||||
c.setLayout(new MigLayout("insets dialog, nogrid, fill"));
|
||||
|
||||
c.add(iconLabel, "h pref!, w pref!");
|
||||
@ -49,8 +48,6 @@ public class ProgressDialog extends JDialog {
|
||||
c.add(new JButton(cancelAction), "align center");
|
||||
|
||||
setSize(240, 155);
|
||||
|
||||
setLocation(TunedUtilities.getPreferredLocation(this));
|
||||
}
|
||||
|
||||
|
||||
@ -81,6 +78,7 @@ public class ProgressDialog extends JDialog {
|
||||
dispose();
|
||||
}
|
||||
|
||||
|
||||
protected final Action cancelAction = new AbstractAction("Cancel") {
|
||||
|
||||
@Override
|
||||
@ -89,7 +87,7 @@ public class ProgressDialog extends JDialog {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
public static interface Cancellable {
|
||||
|
||||
boolean isCancelled();
|
||||
|
@ -20,7 +20,6 @@ import javax.swing.Action;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.SwingUtilities;
|
||||
@ -100,9 +99,7 @@ public final class TunedUtilities {
|
||||
}
|
||||
|
||||
|
||||
public static Point getPreferredLocation(JDialog dialog) {
|
||||
Window owner = dialog.getOwner();
|
||||
|
||||
public static Point getOffsetLocation(Window owner) {
|
||||
if (owner == null) {
|
||||
Window[] toplevel = Window.getOwnerlessWindows();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user