* intuitive access for all map bindings in episode expression format (e.g. video.width or video['width'])

* added AssociativeScriptObject
* enable table sorting in MediaInfoComponent
This commit is contained in:
Reinhard Pointner 2009-04-06 20:34:33 +00:00
parent 912bf0464f
commit e6b785df63
6 changed files with 220 additions and 41 deletions

View File

@ -0,0 +1,169 @@
package net.sourceforge.filebot.format;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
import sun.org.mozilla.javascript.internal.Scriptable;
class AssociativeScriptObject implements Scriptable {
/**
* Map allowing look-up of values by a fault-tolerant key as specified by the defining key.
*
* @see {@link #definingKey(String)}
*/
protected final TreeMap<String, Object> properties = new TreeMap<String, Object>(new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return definingKey(s1).compareTo(definingKey(s2));
}
});
/**
* The Java constructor
*/
public AssociativeScriptObject(Map<String, ?> properties) {
this.properties.putAll(properties);
}
protected String definingKey(String s) {
// letters and digits are defining, everything else will be ignored
return s.replaceAll("[^\\p{Alnum}]", "").toLowerCase();
}
/**
* Defines properties available by name.
*
* @param name the name of the property
* @param start the object where lookup began
*/
public boolean has(String name, Scriptable start) {
return properties.containsKey(name);
}
/**
* Get the property with the given name.
*
* @param name the property name
* @param start the object where the lookup began
*/
public Object get(String name, Scriptable start) {
Object value = properties.get(name);
if (value == null)
throw new BindingException(name, "undefined");
return value;
}
/**
* Defines properties available by index.
*
* @param index the index of the property
* @param start the object where lookup began
*/
public boolean has(int index, Scriptable start) {
// get property by index not supported
return false;
}
/**
* Get property by index.
*
* @param index the index of the property
* @param start the object where the lookup began
*/
public Object get(int index, Scriptable start) {
// get property by index not supported
throw new BindingException(String.valueOf(index), "undefined");
}
/**
* Get property names.
*/
public Object[] getIds() {
return properties.keySet().toArray();
}
/**
* Returns the name of this JavaScript class.
*/
public String getClassName() {
return getClass().getSimpleName();
}
/**
* Returns the string value of this object.
*/
@SuppressWarnings("unchecked")
@Override
public Object getDefaultValue(Class typeHint) {
return this.toString();
}
@Override
public String toString() {
return getClassName() + properties.entrySet().toString();
}
public void put(String name, Scriptable start, Object value) {
// ignore, object is immutable
}
public void put(int index, Scriptable start, Object value) {
// ignore, object is immutable
}
public void delete(String id) {
// ignore, object is immutable
}
public void delete(int index) {
// ignore, object is immutable
}
public Scriptable getPrototype() {
return null;
}
public void setPrototype(Scriptable prototype) {
// ignore, don't care about prototype
}
public Scriptable getParentScope() {
return null;
}
public void setParentScope(Scriptable parent) {
// ignore, don't care about scope
}
public boolean hasInstance(Scriptable value) {
return false;
}
}

View File

@ -9,6 +9,11 @@ public class BindingException extends RuntimeException {
}
public BindingException(String binding, String innerMessage) {
this(binding, innerMessage, null);
}
public BindingException(String binding, String innerMessage, Throwable cause) {
this(String.format("BindingError: \"%s\": %s", binding, innerMessage), cause);
}

View File

@ -8,7 +8,6 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.SortedMap;
import java.util.zip.CRC32;
import net.sf.ehcache.Cache;
@ -81,7 +80,7 @@ public class EpisodeFormatBindingBean {
@Define("hi")
public String getHeightAndInterlacement() {
String height = getMediaInfo(StreamKind.Video, 0, "Height");
String interlacement = getMediaInfo(StreamKind.Video, 0, "Interlacement/String");
String interlacement = getMediaInfo(StreamKind.Video, 0, "Interlacement");
if (height == null || interlacement == null)
return null;
@ -120,37 +119,37 @@ public class EpisodeFormatBindingBean {
return null;
}
@Define("general")
public SortedMap<String, String> getGeneralMediaInfo() {
return getMediaInfo().snapshot(StreamKind.General, 0);
public Object getGeneralMediaInfo() {
return new AssociativeScriptObject(getMediaInfo().snapshot(StreamKind.General, 0));
}
@Define("video")
public SortedMap<String, String> getVideoInfo() {
return getMediaInfo().snapshot(StreamKind.Video, 0);
public Object getVideoInfo() {
return new AssociativeScriptObject(getMediaInfo().snapshot(StreamKind.Video, 0));
}
@Define("audio")
public SortedMap<String, String> getAudioInfo() {
return getMediaInfo().snapshot(StreamKind.Audio, 0);
public Object getAudioInfo() {
return new AssociativeScriptObject(getMediaInfo().snapshot(StreamKind.Audio, 0));
}
@Define("text")
public SortedMap<String, String> getTextInfo() {
return getMediaInfo().snapshot(StreamKind.Text, 0);
}
@Define("image")
public SortedMap<String, String> getImageInfo() {
return getMediaInfo().snapshot(StreamKind.Image, 0);
}
@Define("text")
public Object getTextInfo() {
return new AssociativeScriptObject(getMediaInfo().snapshot(StreamKind.Text, 0));
}
@Define("image")
public Object getImageInfo() {
return new AssociativeScriptObject(getMediaInfo().snapshot(StreamKind.Image, 0));
}
public synchronized MediaInfo getMediaInfo() {
if (mediaFile == null) {

View File

@ -6,10 +6,9 @@ import java.io.Closeable;
import java.io.File;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import com.sun.jna.Pointer;
import com.sun.jna.WString;
@ -80,14 +79,14 @@ public class MediaInfo implements Closeable {
}
public Map<StreamKind, List<SortedMap<String, String>>> snapshot() {
Map<StreamKind, List<SortedMap<String, String>>> mediaInfo = new EnumMap<StreamKind, List<SortedMap<String, String>>>(StreamKind.class);
public Map<StreamKind, List<Map<String, String>>> snapshot() {
Map<StreamKind, List<Map<String, String>>> mediaInfo = new EnumMap<StreamKind, List<Map<String, String>>>(StreamKind.class);
for (StreamKind streamKind : StreamKind.values()) {
int streamCount = streamCount(streamKind);
if (streamCount > 0) {
List<SortedMap<String, String>> streamInfoList = new ArrayList<SortedMap<String, String>>(streamCount);
List<Map<String, String>> streamInfoList = new ArrayList<Map<String, String>>(streamCount);
for (int i = 0; i < streamCount; i++) {
streamInfoList.add(snapshot(streamKind, i));
@ -101,8 +100,8 @@ public class MediaInfo implements Closeable {
}
public SortedMap<String, String> snapshot(StreamKind streamKind, int streamNumber) {
TreeMap<String, String> streamInfo = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
public Map<String, String> snapshot(StreamKind streamKind, int streamNumber) {
Map<String, String> streamInfo = new LinkedHashMap<String, String>();
for (int i = 0, count = parameterCount(streamKind, streamNumber); i < count; i++) {
String value = get(streamKind, streamNumber, i, InfoKind.Text);

View File

@ -109,8 +109,8 @@ public class EpisodeFormatDialog extends JDialog {
header.add(progressIndicator, "pos 1al 0al, hidemode 3");
header.add(title, "wrap unrel:push");
header.add(preview, "gap indent, hidemode 3, wmax 90%");
header.add(errorMessage, "gap indent, hidemode 3, newline");
header.add(warningMessage, "gap indent, hidemode 3, newline");
header.add(errorMessage, "gap indent, hidemode 3, wmax 90%, newline");
header.add(warningMessage, "gap indent, hidemode 3, wmax 90%, newline");
JPanel content = new JPanel(new MigLayout("insets dialog, nogrid, fill"));
@ -208,7 +208,7 @@ public class EpisodeFormatDialog extends JDialog {
} catch (LinkageError e) {
// MediaInfo native library is missing -> notify user
Logger.getLogger("ui").log(Level.SEVERE, e.getMessage(), e);
// rethrow error
throw e;
}
@ -353,7 +353,7 @@ public class EpisodeFormatDialog extends JDialog {
error = e;
}
errorMessage.setText(error != null ? error.getCause().getMessage() : null);
errorMessage.setText(error != null ? ExceptionUtilities.getRootCauseMessage(error) : null);
errorMessage.setVisible(error != null);
warningMessage.setText(warning != null ? warning.getCause().getMessage() : null);

View File

@ -9,7 +9,6 @@ import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.Map.Entry;
import javax.swing.AbstractAction;
@ -29,16 +28,24 @@ import net.sourceforge.tuned.ui.TunedUtilities;
public class MediaInfoComponent extends JTabbedPane {
public MediaInfoComponent(Map<StreamKind, List<SortedMap<String, String>>> mediaInfo) {
public MediaInfoComponent(Map<StreamKind, List<Map<String, String>>> mediaInfo) {
insert(mediaInfo);
}
public void insert(Map<StreamKind, List<SortedMap<String, String>>> mediaInfo) {
public void insert(Map<StreamKind, List<Map<String, String>>> mediaInfo) {
// create tabs for all streams
for (Entry<StreamKind, List<SortedMap<String, String>>> entry : mediaInfo.entrySet()) {
for (SortedMap<String, String> parameters : entry.getValue()) {
addTab(entry.getKey().toString(), new JScrollPane(new JTable(new ParameterTableModel(parameters))));
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
table.setAutoCreateRowSorter(true);
// sort by parameter name
table.getRowSorter().toggleSortOrder(0);
addTab(entry.getKey().toString(), new JScrollPane(table));
}
}
}
@ -75,11 +82,11 @@ public class MediaInfoComponent extends JTabbedPane {
protected static class ParameterTableModel extends AbstractTableModel {
private final List<Entry<?, ?>> data;
private final List<Entry<String, String>> data;
public ParameterTableModel(Map<?, ?> data) {
this.data = new ArrayList<Entry<?, ?>>(data.entrySet());
public ParameterTableModel(Map<String, String> data) {
this.data = new ArrayList<Entry<String, String>>(data.entrySet());
}