Added #1901 Editor mode and autosave feature for header, raw editor, transform

This commit is contained in:
Jindra Petřík
2022-12-23 17:02:50 +01:00
parent 380d7b9078
commit c2ceec8628
18 changed files with 362 additions and 778 deletions
@@ -67,7 +67,7 @@ import layout.TableLayout;
*
* @author JPEXS
*/
public class FontPanel extends JPanel {
public class FontPanel extends JPanel implements TagEditorPanel {
private final MainPanel mainPanel;
@@ -110,6 +110,7 @@ public class FontPanel extends JPanel {
return new DefaultComboBoxModel<>(new Vector<>(faceSet));
}
@Override
public boolean isEditing() {
return saveButton.isVisible();
}
@@ -861,4 +862,13 @@ public class FontPanel extends JPanel {
private JPanel contentPanel;
private JScrollPane contentScrollPane;
@Override
public boolean tryAutoSave() {
if (Configuration.autoSaveTagModifications.get()) {
saveButtonActionPerformed(null);
return !(saveButton.isVisible() && saveButton.isEnabled());
}
return false;
}
}
@@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.gui;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.amf.amf3.Amf3Value;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.gui.generictageditors.Amf3ValueEditor;
import com.jpexs.decompiler.flash.gui.generictageditors.BinaryDataEditor;
import com.jpexs.decompiler.flash.gui.generictageditors.BooleanEditor;
@@ -71,550 +72,25 @@ import javax.swing.SpringLayout;
*
* @author JPEXS
*/
public class GenericTagPanel extends JPanel implements ChangeListener {
private static final Logger logger = Logger.getLogger(GenericTagPanel.class.getName());
public abstract class GenericTagPanel extends JPanel {
protected final MainPanel mainPanel;
private final JEditorPane genericTagPropertiesEditorPane;
private final JPanel genericTagPropertiesEditPanel;
private final JScrollPane genericTagPropertiesEditorPaneScrollPanel;
private final JScrollPane genericTagPropertiesEditPanelScrollPanel;
private Tag tag;
private Tag editedTag;
private List<String> keys = new ArrayList<>();
private Map<String, GenericTagEditor> editors = new HashMap<>();
private Map<String, Component> labels = new HashMap<>();
private Map<String, Component> types = new HashMap<>();
private Map<String, List<Field>> fieldPaths = new HashMap<>();
private Map<String, List<Integer>> fieldIndices = new HashMap<>();
private HeaderLabel hdr;
private Set<String> addKeys = new HashSet<>();
private Map<String, Component> addButtons = new HashMap<>();
private Map<String, Component> removeButtons = new HashMap<>();
public GenericTagPanel(MainPanel mainPanel) {
super(new BorderLayout());
this.mainPanel = mainPanel;
hdr = new HeaderLabel("");
add(hdr, BorderLayout.NORTH);
genericTagPropertiesEditorPane = new JEditorPane() {
@Override
public boolean getScrollableTracksViewportWidth() {
return true;
}
};
genericTagPropertiesEditorPane.setEditable(false);
genericTagPropertiesEditorPaneScrollPanel = new FasterScrollPane(genericTagPropertiesEditorPane);
add(genericTagPropertiesEditorPaneScrollPanel, BorderLayout.CENTER);
genericTagPropertiesEditPanel = new JPanel();
genericTagPropertiesEditPanel.setLayout(new SpringLayout());
JPanel edPanel = new JPanel(new BorderLayout());
edPanel.add(genericTagPropertiesEditPanel, BorderLayout.NORTH);
genericTagPropertiesEditPanelScrollPanel = new FasterScrollPane(edPanel);
}
public void clear() {
editors.clear();
fieldPaths.clear();
fieldIndices.clear();
labels.clear();
types.clear();
keys.clear();
addKeys.clear();
addButtons.clear();
removeButtons.clear();
genericTagPropertiesEditPanel.removeAll();
genericTagPropertiesEditPanel.setSize(0, 0);
tag = null;
editedTag = null;
}
public abstract void clear();
public void setEditMode(boolean edit, Tag tag) {
if (tag == null) {
tag = this.tag;
}
public abstract void setEditMode(boolean edit, Tag tag);
public abstract boolean tryAutoSave();
public abstract boolean save();
this.tag = tag;
this.editedTag = Helper.deepCopy(tag);
generateEditControls(editedTag, !edit);
public abstract Tag getTag();
if (edit) {
remove(genericTagPropertiesEditorPaneScrollPanel);
add(genericTagPropertiesEditPanelScrollPanel, BorderLayout.CENTER);
} else {
genericTagPropertiesEditPanel.removeAll();
genericTagPropertiesEditPanel.setSize(0, 0);
remove(genericTagPropertiesEditPanelScrollPanel);
add(genericTagPropertiesEditorPaneScrollPanel, BorderLayout.CENTER);
setTagText(this.tag);
}
revalidate();
repaint();
}
private void setTagText(Tag tag) {
clear();
generateEditControls(tag, true);
StringBuilder val = new StringBuilder();
for (String key : keys) {
GenericTagEditor ed = editors.get(key);
if (((Component) ed).isVisible()) {
val.append(key).append(" : ").append(ed.getReadOnlyValue()).append("<br>");
}
}
//HTML for colors:
val.insert(0, "<html>").append("</html>");
genericTagPropertiesEditorPane.setContentType("text/html");
genericTagPropertiesEditorPane.setText(val.toString());
genericTagPropertiesEditorPane.setCaretPosition(0);
hdr.setText(tag.toString());
}
private void generateEditControls(Tag tag, boolean readonly) {
clear();
generateEditControlsRecursive(tag, "", new ArrayList<>(), new ArrayList<>(), readonly);
change(null);
}
private void relayout(int propCount) {
//Lay out the panel.
SpringUtilities.makeCompactGrid(genericTagPropertiesEditPanel,
propCount, 3, //rows, cols
6, 6, //initX, initY
6, 6); //xPad, yPad
revalidate();
repaint();
}
private int generateEditControlsRecursive(final Object obj, String parent, List<Field> parentFields, List<Integer> parentIndices, boolean readonly) {
if (obj == null) {
return 0;
}
Field[] fields = obj.getClass().getDeclaredFields();
int propCount = 0;
for (final Field field : fields) {
try {
if (Modifier.isStatic(field.getModifiers())) {
continue;
}
field.setAccessible(true);
String name = parent + field.getName();
final Object value = field.get(obj);
if (List.class.isAssignableFrom(field.getType())) {
if (value != null) {
int i = 0;
for (Object obj1 : (Iterable) value) {
final String subname = name + "[" + i + "]";
propCount += addEditor(subname, obj, field, i, obj1.getClass(), obj1, parentFields, parentIndices, readonly);
final int fi = i;
i++;
JButton removeButton = new JButton(View.getIcon("close16"));
removeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
removeItem(obj, field, fi);
}
});
removeButtons.put(subname, removeButton);
}
}
} else if (field.getType().isArray()) {
if (value != null) {
for (int i = 0; i < Array.getLength(value); i++) {
Object item = Array.get(value, i);
String subname = name + "[" + i + "]";
propCount += addEditor(subname, obj, field, i, item.getClass(), item, parentFields, parentIndices, readonly);
final int fi = i;
JButton removeButton = new JButton(View.getIcon("close16"));
removeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
removeItem(obj, field, fi);
}
});
removeButtons.put(subname, removeButton);
}
}
} else {
propCount += addEditor(name, obj, field, 0, field.getType(), value, parentFields, parentIndices, readonly);
}
if (ReflectionTools.needsIndex(field) && !readonly && !field.getName().equals("clipActionRecords")) { //No clip actions, sorry
JButton addButton = new JButton(View.getIcon("add16"));
addButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
addItem(obj, field);
}
});
name += "[]";
List<Field> parList = new ArrayList<>(parentFields);
parList.add(field);
fieldPaths.put(name, parList);
List<Integer> parIndices = new ArrayList<>(parentIndices);
parIndices.add(0);
fieldIndices.put(name, parIndices);
addRow(name, addButton, field);
addKeys.add(name);
addButtons.put(name, addButton);
}
} catch (IllegalArgumentException | IllegalAccessException ex) {
logger.log(Level.SEVERE, null, ex);
}
}
return propCount;
}
private void removeItem(Object obj, Field field, int index) {
final JScrollBar sb = genericTagPropertiesEditPanelScrollPanel.getVerticalScrollBar();
final int val = sb.getValue(); //save scroll top
SWFType swfType = field.getAnnotation(SWFType.class);
if (swfType != null && !swfType.countField().isEmpty()) { //Fields with same countField must be removed from too
Field[] fields = obj.getClass().getDeclaredFields();
for (int f = 0; f < fields.length; f++) {
SWFType fieldSwfType = fields[f].getAnnotation(SWFType.class);
if (fieldSwfType != null && fieldSwfType.countField().equals(swfType.countField())) {
ReflectionTools.removeFromField(obj, fields[f], index);
}
}
try {
//If countField exists, decrement, otherwise do nothing
Field countField = obj.getClass().getDeclaredField(swfType.countField());
int cnt = countField.getInt(obj);
cnt--;
countField.setInt(obj, cnt);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) {
//ignored
}
} else {
ReflectionTools.removeFromField(obj, field, index);
}
generateEditControls(editedTag, false);
//Restore scroll top after some time. TODO: Handle this better. I don't know how :-(.
new Thread() {
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
logger.log(Level.SEVERE, null, ex);
}
View.execInEventDispatch(() -> {
genericTagPropertiesEditPanelScrollPanel.getVerticalScrollBar().setValue(val);
});
}
}.start();
revalidate();
repaint();
}
private void addItem(Object obj, Field field) {
final JScrollBar sb = genericTagPropertiesEditPanelScrollPanel.getVerticalScrollBar();
final int val = sb.getValue(); //save scroll top
SWFType swfType = field.getAnnotation(SWFType.class);
if (swfType != null && !swfType.countField().isEmpty()) { //Fields with same countField must be enlarged too
Field[] fields = obj.getClass().getDeclaredFields();
for (int f = 0; f < fields.length; f++) {
SWFType fieldSwfType = fields[f].getAnnotation(SWFType.class);
if (fieldSwfType != null && fieldSwfType.countField().equals(swfType.countField())) {
ReflectionTools.addToField(obj, fields[f], ReflectionTools.getFieldSubSize(obj, fields[f]), true, null);
}
}
try {
//If countField exists, increment, otherwise do nothing
Field countField = obj.getClass().getDeclaredField(swfType.countField());
int cnt = countField.getInt(obj);
cnt++;
countField.setInt(obj, cnt);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) {
//ignored
}
} else {
ReflectionTools.addToField(obj, field, ReflectionTools.getFieldSubSize(obj, field), true, null);
}
generateEditControls(editedTag, false);
//Restore scroll top after some time. TODO: Handle this better. I don't know how :-(.
new Thread() {
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
logger.log(Level.SEVERE, null, ex);
}
View.execInEventDispatch(() -> {
genericTagPropertiesEditPanelScrollPanel.getVerticalScrollBar().setValue(val);
});
}
}.start();
revalidate();
repaint();
}
private int addEditor(String name, Object obj, Field field, int index, Class<?> type, Object value, List<Field> parentList, List<Integer> parentIndices, boolean readonly) throws IllegalArgumentException, IllegalAccessException {
Calculated calculated = field.getAnnotation(Calculated.class);
if (calculated != null) {
return 0;
}
List<Field> parList = new ArrayList<>(parentList);
parList.add(field);
List<Integer> parIndices = new ArrayList<>(parentIndices);
parIndices.add(index);
Internal inter = field.getAnnotation(Internal.class);
if (inter != null) {
return 0;
}
SWFType swfType = field.getAnnotation(SWFType.class);
Multiline multiline = field.getAnnotation(Multiline.class);
Component editor;
if (type.equals(int.class) || type.equals(Integer.class)
|| type.equals(short.class) || type.equals(Short.class)
|| type.equals(long.class) || type.equals(Long.class)
|| type.equals(double.class) || type.equals(Double.class)
|| type.equals(float.class) || type.equals(Float.class)) {
editor = new NumberEditor(name, obj, field, index, type, swfType);
} else if (type.equals(boolean.class) || type.equals(Boolean.class)) {
editor = new BooleanEditor(name, obj, field, index, type);
} else if (type.equals(String.class)) {
editor = new StringEditor(name, obj, field, index, type, multiline != null);
} else if (type.equals(RGB.class) || type.equals(RGBA.class) || type.equals(ARGB.class)) {
editor = new ColorEditor(name, obj, field, index, type);
} else if (type.equals(ByteArrayRange.class)) {
editor = new BinaryDataEditor(mainPanel, name, obj, field, index, type);
} else if (type.equals(Amf3Value.class)) {
editor = new Amf3ValueEditor(name, obj, field, index, type);
} else {
if (value == null) {
if (readonly) {
return 0;
}
Optional opt = field.getAnnotation(Optional.class);
if (opt == null) {
try {
value = ReflectionTools.newInstanceOf(field.getType());
field.set(obj, value);
} catch (InstantiationException | IllegalAccessException ex) {
logger.log(Level.SEVERE, null, ex);
return 0;
}
} else {
return 0;
}
}
return generateEditControlsRecursive(value, name + ".", parList, parIndices, readonly);
}
if (editor instanceof GenericTagEditor) {
GenericTagEditor ce = (GenericTagEditor) editor;
ce.addChangeListener(this);
editors.put(name, ce);
fieldPaths.put(name, parList);
fieldIndices.put(name, parIndices);
addRow(name, editor, field);
ce.added();
}
return 1;
}
private void addRow(String name, Component editor, Field field) {
JLabel label = new JLabel(name + ":", JLabel.TRAILING);
label.setVerticalAlignment(JLabel.TOP);
genericTagPropertiesEditPanel.add(label);
label.setLabelFor(editor);
labels.put(name, label);
genericTagPropertiesEditPanel.add(editor);
JLabel typeLabel = new JLabel(swfTypeToString(field.getAnnotation(SWFType.class)), JLabel.TRAILING);
typeLabel.setVerticalAlignment(JLabel.TOP);
genericTagPropertiesEditPanel.add(typeLabel);
types.put(name, typeLabel);
keys.add(name);
}
public String swfTypeToString(SWFType swfType) {
if (swfType == null) {
return null;
}
String result = swfType.value().toString();
if (swfType.count() > 0) {
result += "[" + swfType.count();
if (swfType.countAdd() > 0) {
result += " + " + swfType.countAdd();
}
result += "]";
} else if (!swfType.countField().isEmpty()) {
result += "[" + swfType.countField();
if (swfType.countAdd() > 0) {
result += " + " + swfType.countAdd();
}
result += "]";
}
return result;
}
private void assignTag(Tag t, Tag assigned) {
if (t.getClass() != assigned.getClass()) {
return;
}
for (Field f : t.getClass().getDeclaredFields()) {
if ((f.getModifiers() & Modifier.FINAL) == Modifier.FINAL) {
continue;
}
if ((f.getModifiers() & Modifier.STATIC) == Modifier.STATIC) {
continue;
}
try {
f.set(t, f.get(assigned));
} catch (IllegalArgumentException | IllegalAccessException ex) {
logger.log(Level.SEVERE, null, ex);
}
}
}
public boolean save() {
for (Object component : genericTagPropertiesEditPanel.getComponents()) {
if (component instanceof GenericTagEditor) {
try {
((GenericTagEditor) component).validateValue();
((GenericTagEditor) component).save();
} catch (IllegalArgumentException iex) {
return false;
}
}
}
SWF swf = tag.getSwf();
Timelined tim = tag.getTimelined();
assignTag(tag, editedTag);
tag.setModified(true);
tag.setSwf(swf);
tag.setTimelined(tim);
setTagText(tag);
return true;
}
public Tag getTag() {
return tag;
}
@Override
public void change(GenericTagEditor ed) {
for (String key : editors.keySet()) {
GenericTagEditor dependentEditor = editors.get(key);
Component dependentLabel = labels.get(key);
Component dependentTypeLabel = types.get(key);
List<Field> path = fieldPaths.get(key);
List<Integer> indices = fieldIndices.get(key);
String p = "";
boolean conditionMet = true;
for (int i = 0; i < path.size(); i++) {
Field f = path.get(i);
int index = indices.get(i);
String par = p;
if (!p.isEmpty()) {
p += ".";
}
p += f.getName();
if (ReflectionTools.needsIndex(f)) {
p += "[" + index + "]";
}
Conditional cond = f.getAnnotation(Conditional.class);
if (cond != null) {
ConditionEvaluator ev = new ConditionEvaluator(cond);
try {
Set<String> fieldNames = ev.getFields();
Map<String, Boolean> fields = new HashMap<>();
for (String fld : fieldNames) {
String ckey = "";
if (!par.isEmpty()) {
ckey = par + ".";
}
ckey += fld;
if (editors.containsKey(ckey)) {
GenericTagEditor editor = editors.get(ckey);
Object val = editor.getChangedValue();
fields.put(fld, true);
if (val instanceof Boolean) {
fields.put(fld, (Boolean) val);
}
}
}
boolean ok = ev.eval(fields, tag.getId());
if (conditionMet) {
conditionMet = ok;
}
((Component) dependentEditor).setVisible(conditionMet);
dependentLabel.setVisible(conditionMet);
dependentTypeLabel.setVisible(conditionMet);
} catch (AnnotationParseException ex) {
logger.log(Level.SEVERE, "Invalid condition", ex);
}
}
if (!conditionMet) {
break;
}
}
}
genericTagPropertiesEditPanel.removeAll();
genericTagPropertiesEditPanel.setSize(0, 0);
int propCount = 0;
for (String key : keys) {
Component dependentEditor;
if (addKeys.contains(key)) {
dependentEditor = addButtons.get(key);
} else if (removeButtons.containsKey(key)) { //It's array/list, add remove button
JPanel editRemPanel = new JPanel(new BorderLayout());
editRemPanel.add((Component) editors.get(key), BorderLayout.CENTER);
editRemPanel.add(removeButtons.get(key), BorderLayout.EAST);
dependentEditor = editRemPanel;
} else {
dependentEditor = (Component) editors.get(key);
}
Component dependentLabel = labels.get(key);
Component dependentTypeLabel = types.get(key);
if (dependentEditor.isVisible()) {
genericTagPropertiesEditPanel.add(dependentLabel);
genericTagPropertiesEditPanel.add(((Component) dependentEditor));
genericTagPropertiesEditPanel.add(dependentTypeLabel);
propCount++;
}
}
/*genericTagPropertiesEditPanel.add(new JPanel());
genericTagPropertiesEditPanel.add(new JPanel());
genericTagPropertiesEditPanel.add(new JPanel());*/
relayout(propCount /*+ 1*/);
}
//@Override
//public abstract void change(GenericTagEditor ed);
}
@@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.gui;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.amf.amf3.Amf3Value;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.gui.generictageditors.Amf3ValueEditor;
import com.jpexs.decompiler.flash.gui.generictageditors.BinaryDataEditor;
import com.jpexs.decompiler.flash.gui.generictageditors.BooleanEditor;
@@ -119,16 +120,20 @@ public class GenericTagTreePanel extends GenericTagPanel {
private static final int FIELD_INDEX = 0;
private List<TreeModelListener> listeners = new ArrayList<>();
public void addTreeModelListener(TreeModelListener listener) {
((MyTreeModel)tree.getModel()).addTreeModelListener(listener);
listeners.add(listener);
((DefaultTreeModel) tree.getModel()).addTreeModelListener(listener);
}
public void removeTreeModelListener(TreeModelListener listener) {
((MyTreeModel)tree.getModel()).removeTreeModelListener(listener);
listeners.remove(listener);
((DefaultTreeModel) tree.getModel()).removeTreeModelListener(listener);
}
private class MyTree extends JTree {
public MyTree() {
if (View.isOceanic()) {
setBackground(Color.white);
@@ -146,7 +151,7 @@ public class GenericTagTreePanel extends GenericTagPanel {
}
}
private static SWFType evalSwfType(MyTreeModel mod, String parentPath, SWFType swfType) {
if (swfType == null) {
return null;
@@ -157,7 +162,7 @@ public class GenericTagTreePanel extends GenericTagPanel {
Conditional cond = new Conditional() {
@Override
public String[] value() {
return new String[] {swfType.alternateCondition()};
return new String[]{swfType.alternateCondition()};
}
@Override
@@ -189,7 +194,7 @@ public class GenericTagTreePanel extends GenericTagPanel {
public Class<? extends Annotation> annotationType() {
return Conditional.class;
}
};
};
ConditionEvaluator ev = new ConditionEvaluator(cond);
try {
Map<String, Boolean> fieldMap = new HashMap<>();
@@ -219,41 +224,41 @@ public class GenericTagTreePanel extends GenericTagPanel {
return swfType;
}
return new SWFType() {
@Override
public BasicType value() {
return swfType.alternateValue();
}
@Override
public BasicType value() {
return swfType.alternateValue();
}
@Override
public BasicType alternateValue() {
return BasicType.NONE;
}
@Override
public BasicType alternateValue() {
return BasicType.NONE;
}
@Override
public String alternateCondition() {
return "";
}
@Override
public String alternateCondition() {
return "";
}
@Override
public int count() {
return swfType.count();
}
@Override
public int count() {
return swfType.count();
}
@Override
public String countField() {
return swfType.countField();
}
@Override
public String countField() {
return swfType.countField();
}
@Override
public int countAdd() {
return swfType.countAdd();
}
@Override
public int countAdd() {
return swfType.countAdd();
}
@Override
public Class<? extends Annotation> annotationType() {
return SWFType.class;
}
};
@Override
public Class<? extends Annotation> annotationType() {
return SWFType.class;
}
};
} catch (AnnotationParseException | IllegalArgumentException | IllegalAccessException ex) {
logger.log(Level.SEVERE, null, ex);
return swfType;
@@ -270,7 +275,7 @@ public class GenericTagTreePanel extends GenericTagPanel {
public MyTreeCellEditor(JTree tree) {
this.tree = tree;
}
}
@Override
public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) {
@@ -298,8 +303,8 @@ public class GenericTagTreePanel extends GenericTagPanel {
}
GenericTagEditor editor = null;
SWFType swfType = field.getAnnotation(SWFType.class);
MyTreeModel model = (MyTreeModel)tree.getModel();
MyTreeModel model = (MyTreeModel) tree.getModel();
SWFArray swfArray = field.getAnnotation(SWFArray.class);
boolean isArray = ReflectionTools.needsIndex(field) || swfArray != null;
boolean isArrayParent = isArray && index == -1;
@@ -309,11 +314,11 @@ public class GenericTagTreePanel extends GenericTagPanel {
if (isArray && !isArrayParent) {
parentPath = parentPath.substring(0, parentPath.lastIndexOf("."));
}
swfType = evalSwfType(model, parentPath, swfType);
UUID uuid = field.getAnnotation(UUID.class);
Multiline multiline = field.getAnnotation(Multiline.class);
EnumValues enumValues = field.getAnnotation(EnumValues.class);
if (uuid != null) {
@@ -415,10 +420,10 @@ public class GenericTagTreePanel extends GenericTagPanel {
return false;
}
Object obj = path.getLastPathComponent();
FieldNode fnode = (FieldNode) obj;
Field field = fnode.fieldSet.get(FIELD_INDEX);
boolean ret = super.isCellEditable(e)
&& tree.getModel().isLeaf(obj) && hasEditor(fnode.obj, field, fnode.index);
return ret;
@@ -426,11 +431,14 @@ public class GenericTagTreePanel extends GenericTagPanel {
@Override
public boolean stopCellEditing() {
boolean modified = false;
if (editors != null) {
for (GenericTagEditor editor : editors) {
try {
editor.validateValue();
editor.save();
if (editor.save()) {
modified = true;
}
} catch (IllegalArgumentException iex) {
return false;
}
@@ -440,15 +448,29 @@ public class GenericTagTreePanel extends GenericTagPanel {
editors = null;
TreePath sp = tree.getSelectionPath();
if (sp != null) {
((MyTreeModel) tree.getModel()).vchanged(sp);
if (modified) {
TreePath sp = tree.getSelectionPath();
if (sp != null) {
((MyTreeModel) tree.getModel()).vchanged(sp);
}
refreshTree();
}
refreshTree();
return true;
}
}
@Override
public boolean tryAutoSave() {
if (Configuration.autoSaveTagModifications.get()) {
if (tag == null) {
return true;
}
return save();
}
return true;
}
public GenericTagTreePanel(MainPanel mainPanel) {
super(mainPanel);
setLayout(new BorderLayout());
@@ -659,20 +681,19 @@ public class GenericTagTreePanel extends GenericTagPanel {
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
Component component = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
if (component instanceof JLabel) {
JLabel lab = (JLabel) component;
if (value == tree.getModel().getRoot()) {
//It still does not matter since root is hidden
if (editedTag != null) {
lab.setIcon(AbstractTagTree.getIconForType(AbstractTagTree.getTreeNodeType(editedTag)));
}
}
}
return component;
Component component = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
if (component instanceof JLabel) {
JLabel lab = (JLabel) component;
if (value == tree.getModel().getRoot()) {
//It still does not matter since root is hidden
if (editedTag != null) {
lab.setIcon(AbstractTagTree.getIconForType(AbstractTagTree.getTreeNodeType(editedTag)));
}
}
}
return component;
}
}
@Override
@@ -702,7 +723,7 @@ public class GenericTagTreePanel extends GenericTagPanel {
private FieldSet fieldSet;
private int index;
private MyTreeModel model;
public FieldNode(MyTreeModel model, Tag tag, Object obj, FieldSet fieldSet, int index) {
@@ -746,7 +767,7 @@ public class GenericTagTreePanel extends GenericTagPanel {
}
return ret.toString();
}
if (fieldSet.size() == 1) {
ret.append(toString(0));
} else {
@@ -766,11 +787,11 @@ public class GenericTagTreePanel extends GenericTagPanel {
public String toString(int fieldIndex) {
String valStr = "";
Field field = fieldSet.get(fieldIndex);
if (field.getAnnotation(UUID.class) != null) {
StringBuilder sb = new StringBuilder();
byte[] val = (byte[]) getValue(fieldIndex);
for(int i = 0; i < val.length; i++) {
for (int i = 0; i < val.length; i++) {
String h = Integer.toHexString(val[i] & 0xff);
if (h.length() == 1) {
h = "0" + h;
@@ -829,15 +850,14 @@ public class GenericTagTreePanel extends GenericTagPanel {
Class<?> declaredType = fieldSet.get(fieldIndex).getType();
boolean isArray = ReflectionTools.needsIndex(fieldSet.get(fieldIndex)) || swfArray != null;
boolean isArrayParent = isArray && index == -1;
SWFType swfType = fieldSet.get(fieldIndex).getAnnotation(SWFType.class);
SWFType swfType = fieldSet.get(fieldIndex).getAnnotation(SWFType.class);
String thisPath = model.getNodePathName(this);
String parentPath = thisPath.substring(0, thisPath.lastIndexOf("."));
if (isArray && !isArrayParent) {
parentPath = parentPath.substring(0, parentPath.lastIndexOf("."));
}
swfType = evalSwfType(model, parentPath, swfType);
Class<?> declaredSubType = isArray ? ReflectionTools.getFieldSubType(obj, fieldSet.get(fieldIndex)) : null;
@@ -1016,7 +1036,7 @@ public class GenericTagTreePanel extends GenericTagPanel {
}
public String getNodePathName(Object find) {
if (nodeCacheReverse.containsKey(find)) {
return nodeCacheReverse.get(find);
}
@@ -1112,19 +1132,17 @@ public class GenericTagTreePanel extends GenericTagPanel {
if (parent == mtroot) {
return filterFields(this, mtroot.getClass().getSimpleName(), mtroot.getClass(), limited, mtroot.getId()).size();
}
FieldNode fnode = (FieldNode) parent;
Field field = fnode.fieldSet.get(FIELD_INDEX);
boolean isByteArray = field.getType().equals(byte[].class);
if (hasEditor(fnode.obj, field, fnode.index) || isByteArray) {
return 0;
}
}
if (ReflectionTools.needsIndex(field) && (fnode.index == -1)) { //Arrays or Lists
try {
if (field.get(fnode.obj) == null) {
@@ -1137,8 +1155,8 @@ public class GenericTagTreePanel extends GenericTagPanel {
return ReflectionTools.getFieldSubSize(fnode.obj, field);
}
parent = fnode.getValue(FIELD_INDEX);
parent = fnode.getValue(FIELD_INDEX);
return filterFields(this, getNodePathName(fnode), parent.getClass(), limited, mtroot.getId()).size();
}
@@ -1184,7 +1202,7 @@ public class GenericTagTreePanel extends GenericTagPanel {
}
if (!edit && tree.isEditing()) {
tree.stopEditing();
}
}
tree.setEditable(edit);
refreshTree();
}
@@ -1200,13 +1218,13 @@ public class GenericTagTreePanel extends GenericTagPanel {
tag.setModified(true);
tag.setSwf(swf);
if (tag instanceof Timelined) {
((Timelined)tag).resetTimeline();
((Timelined) tag).resetTimeline();
}
//For example DefineButton and its DefineButtonCxForm
if ((tag instanceof CharacterIdTag) && (!(tag instanceof CharacterTag))) {
CharacterTag parentCharacter = swf.getCharacter(((CharacterIdTag)tag).getCharacterId());
CharacterTag parentCharacter = swf.getCharacter(((CharacterIdTag) tag).getCharacterId());
if (parentCharacter instanceof Timelined) {
((Timelined)parentCharacter).resetTimeline();
((Timelined) parentCharacter).resetTimeline();
}
}
swf.computeDependentCharacters();
@@ -1249,9 +1267,9 @@ public class GenericTagTreePanel extends GenericTagPanel {
type = val.getClass();
} catch (IllegalArgumentException | IllegalAccessException ex) {
return false;
}
}
UUID uuid = field.getAnnotation(UUID.class);
if (uuid != null) {
return true;
} else if (type.equals(int.class) || type.equals(Integer.class)
@@ -1475,7 +1493,7 @@ public class GenericTagTreePanel extends GenericTagPanel {
if ((obj instanceof CLIPACTIONS) && (v instanceof CLIPACTIONRECORD)) {
((CLIPACTIONRECORD) v).setParentClipActions((CLIPACTIONS) obj);
}
if (obj instanceof HasSwfAndTag) {
((HasSwfAndTag) obj).setSourceTag(editedTag);
}
@@ -1484,11 +1502,15 @@ public class GenericTagTreePanel extends GenericTagPanel {
//ignore
}
}
((MyTreeModel) tree.getModel()).vchanged(new TreePath(tree.getModel().getRoot()));
refreshTree();
}
public void refreshTree() {
View.refreshTree(tree, getModel());
for (TreeModelListener listener:listeners) {
((DefaultTreeModel) tree.getModel()).addTreeModelListener(listener);
}
revalidate();
repaint();
}
@@ -18,12 +18,15 @@ package com.jpexs.decompiler.flash.gui;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFCompression;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.gui.helpers.TableLayoutHelper;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
@@ -34,6 +37,7 @@ import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.border.BevelBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import layout.TableLayout;
/**
@@ -190,14 +194,24 @@ public class HeaderInfoPanel extends JPanel implements TagEditorPanel {
add(propertiesPanel, BorderLayout.CENTER);
editButton.setVisible(false);
editButton.addActionListener(this::editButtonActionPerformed);
saveButton.setVisible(false);
saveButton.addActionListener(this::saveButtonActionPerformed);
cancelButton.setVisible(false);
cancelButton.addActionListener(this::cancelButtonActionPerformed);
if (Configuration.editorMode.get()) {
editButton.setVisible(false);
saveButton.setVisible(false);
saveButton.setEnabled(false);
cancelButton.setVisible(false);
cancelButton.setEnabled(false);
} else {
editButton.setVisible(false);
saveButton.setVisible(false);
cancelButton.setVisible(false);
}
buttonsPanel.setLayout(new FlowLayout());
buttonsPanel.setBorder(new BevelBorder(BevelBorder.RAISED));
@@ -294,7 +308,27 @@ public class HeaderInfoPanel extends JPanel implements TagEditorPanel {
yMinEditor.setModel(new SpinnerNumberModel(swf.displayRect.Ymin, -0x80000000, 0x7fffffff, 1));
yMaxEditor.setModel(new SpinnerNumberModel(swf.displayRect.Ymax, -0x80000000, 0x7fffffff, 1));
setEditMode(false);
compressionComboBox.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
setModified();
}
});
versionEditor.addChangeListener((ChangeEvent e) -> {setModified();});
gfxCheckBox.addChangeListener((ChangeEvent e) -> {setModified();});
frameRateEditor.addChangeListener((ChangeEvent e) -> {setModified();});
xMinEditor.addChangeListener((ChangeEvent e) -> {setModified();});
xMaxEditor.addChangeListener((ChangeEvent e) -> {setModified();});
yMinEditor.addChangeListener((ChangeEvent e) -> {setModified();});
yMaxEditor.addChangeListener((ChangeEvent e) -> {setModified();});
setEditMode(Configuration.editorMode.get());
}
private void setModified() {
saveButton.setEnabled(true);
cancelButton.setEnabled(true);
mainPanel.setEditingStatus();
}
public void clear() {
@@ -311,6 +345,10 @@ public class HeaderInfoPanel extends JPanel implements TagEditorPanel {
}
private void setEditMode(boolean edit) {
if (Configuration.editorMode.get()) {
edit = true;
}
compressionLabel.setVisible(!edit);
compressionEditorPanel.setVisible(edit);
versionLabel.setVisible(!edit);
@@ -326,9 +364,17 @@ public class HeaderInfoPanel extends JPanel implements TagEditorPanel {
warningPanel.setVisible(false);
editButton.setVisible(!edit);
saveButton.setVisible(edit);
cancelButton.setVisible(edit);
if (Configuration.editorMode.get()) {
editButton.setVisible(false);
saveButton.setVisible(true);
saveButton.setEnabled(false);
cancelButton.setVisible(true);
cancelButton.setEnabled(false);
} else {
editButton.setVisible(!edit);
saveButton.setVisible(edit);
cancelButton.setVisible(edit);
}
}
private boolean validateHeader() {
@@ -362,13 +408,15 @@ public class HeaderInfoPanel extends JPanel implements TagEditorPanel {
@Override
public boolean tryAutoSave() {
// todo: implement
return false;
if (saveButton.isVisible() && saveButton.isEnabled()) {
saveButtonActionPerformed(null);
}
return !(saveButton.isVisible() && saveButton.isEnabled());
}
@Override
public boolean isEditing() {
return saveButton.isVisible();
return saveButton.isVisible() && saveButton.isEnabled();
}
public void startEdit() {
@@ -846,7 +846,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
}
public void setEditingStatus() {
statusPanel.setStatus(translate("status.editing"));
statusPanel.setStatus(translate(Configuration.autoSaveTagModifications.get() ? "status.editing.autosave" : "status.editing"));
}
public void clearEditingStatus() {
@@ -63,6 +63,8 @@ import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
@@ -422,7 +424,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
genericSaveButton.setVisible(true);
genericSaveButton.setEnabled(false);
genericCancelButton.setVisible(true);
genericSaveButton.setEnabled(false);
genericCancelButton.setEnabled(false);
} else {
genericEditButton.setVisible(true);
genericSaveButton.setVisible(false);
@@ -524,7 +526,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
mainPanel.setTagTreeSelectedNode(mainPanel.getCurrentTree(), placeObject);
}
}
});
});
imagePanel.setLoop(Configuration.loopMedia.get());
@@ -687,6 +689,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
genericTagPanel = new GenericTagTreePanel(mainPanel);
genericTagCard.add(genericTagPanel, BorderLayout.CENTER);
genericTagCard.add(createGenericTagButtonsPanel(), BorderLayout.SOUTH);
addGenericListener();
return genericTagCard;
}
@@ -708,6 +711,16 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
}
});
if (Configuration.editorMode.get()) {
placeImagePanel.addBoundsChangeListener(new BoundsChangeListener() {
@Override
public void boundsChanged(Rectangle2D newBounds, Point2D registrationPoint, RegistrationPointPosition registrationPointPosition) {
if (placeSaveButton.isVisible()) {
placeSaveButton.setEnabled(true);
}
}
});
}
placeTransformPanel = new TransformPanel(placeImagePanel);
//imagePanel.setLoop(Configuration.loopMedia.get());
previewCnt.add(placeTransformSplitPane = new JPersistentSplitPane(
@@ -727,6 +740,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
previewPanel.add(prevIntLabel, BorderLayout.NORTH);
placeGenericPanel = new GenericTagTreePanel(mainPanel);
addPlaceGenericListener();
placeSplitPane = new JPersistentSplitPane(JSplitPane.HORIZONTAL_SPLIT, previewPanel, placeGenericPanel, Configuration.guiSplitPanePlaceDividerLocationPercent);
placeTagCard.add(placeSplitPane, BorderLayout.CENTER);
@@ -1058,7 +1072,6 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
genericEditButton.setEnabled(true);
if (Configuration.editorMode.get()) {
genericTagPanel.setEditMode(!tag.isReadOnly(), tag);
addGenericListener();
genericSaveButton.setVisible(!tag.isReadOnly());
genericCancelButton.setVisible(!tag.isReadOnly());
} else {
@@ -1079,7 +1092,6 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
if (Configuration.editorMode.get()) {
placeGenericPanel.setEditMode(!tag.isReadOnly(), tag);
addPlaceGenericListener();
placeEditButton.setVisible(false);
placeSaveButton.setVisible(!tag.isReadOnly());
placeCancelButton.setVisible(!tag.isReadOnly());
@@ -1292,7 +1304,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
}
}
private void saveGenericTagButtonActionPerformed(ActionEvent evt) {
private void saveGenericTag(boolean refreshTree) {
if (genericTagPanel.save()) {
Tag tag = genericTagPanel.getTag();
SWF swf = tag.getSwf();
@@ -1302,7 +1314,9 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
tag.getTimelined().resetTimeline();
swf.assignClassesToSymbols();
swf.assignExportNamesToSymbols();
mainPanel.refreshTree(swf);
if (refreshTree) {
mainPanel.refreshTree(swf);
}
if (Configuration.editorMode.get()) {
genericEditButton.setVisible(false);
genericSaveButton.setVisible(true);
@@ -1319,26 +1333,29 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
mainPanel.clearEditingStatus();
}
}
private void saveGenericTagButtonActionPerformed(ActionEvent evt) {
saveGenericTag(true);
}
private void cancelGenericTagButtonActionPerformed(ActionEvent evt) {
if (Configuration.editorMode.get()) {
genericTagPanel.setEditMode(true, null);
genericEditButton.setVisible(false);
genericSaveButton.setVisible(true);
genericSaveButton.setEnabled(false);
genericCancelButton.setVisible(true);
genericCancelButton.setEnabled(false);
genericTagPanel.setEditMode(true, null);
addGenericListener();
genericCancelButton.setEnabled(false);
} else {
genericTagPanel.setEditMode(false, null);
genericEditButton.setVisible(true);
genericSaveButton.setVisible(false);
genericCancelButton.setVisible(false);
genericTagPanel.setEditMode(false, null);
genericCancelButton.setVisible(false);
}
mainPanel.clearEditingStatus();
}
private void savePlaceTagButtonActionPerformed(ActionEvent evt) {
private void savePlaceTag(boolean refreshTree) {
if (placeEditMode == PLACE_EDIT_TRANSFORM) {
Matrix matrix = placeImagePanel.getNewMatrix();
placeTag.setPlaceFlagHasMatrix(true);
@@ -1348,7 +1365,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
placeImagePanel.freeTransformDepth(-1);
placeTag.getTimelined().resetTimeline();
placeTransformScrollPane.setVisible(false);
placeGenericPanel.setVisible(true);
placeGenericPanel.setVisible(true);
}
Tag hilightTag = null;
if (placeEditMode == PLACE_EDIT_RAW) {
@@ -1356,7 +1373,9 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
Tag tag = placeGenericPanel.getTag();
SWF swf = tag.getSwf();
tag.getTimelined().resetTimeline();
mainPanel.refreshTree(swf);
if (refreshTree) {
mainPanel.refreshTree(swf);
}
hilightTag = tag;
}
placeGenericPanel.setEditMode(false, null);
@@ -1385,6 +1404,10 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
}
}
private void savePlaceTagButtonActionPerformed(ActionEvent evt) {
savePlaceTag(true);
}
private void editPlaceTagButtonActionPerformed(ActionEvent evt) {
placeEditMode = PLACE_EDIT_RAW;
placeGenericPanel.setEditMode(true, placeTag);
@@ -1410,7 +1433,12 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
placeTransformButton.setVisible(false);
placeSaveButton.setVisible(true);
placeCancelButton.setVisible(true);
placeSaveButton.setEnabled(true);
if (Configuration.editorMode.get()) {
placeSaveButton.setEnabled(false);
} else {
placeSaveButton.setEnabled(true);
}
placeCancelButton.setEnabled(true);
mainPanel.setEditingStatus();
@@ -1430,7 +1458,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
}, 40); //add some delay before controls are hidden
}
private void saveImageTransformButtonActionPerformed(ActionEvent evt) {
private void saveImageTransform(boolean refreshTree) {
Matrix matrix = imagePanel.getNewMatrix();
imageTransformScrollPane.setVisible(false);
@@ -1470,7 +1498,13 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
}
mainPanel.clearEditingStatus();
mainPanel.reload(true);
if (refreshTree) {
mainPanel.reload(true);
}
}
private void saveImageTransformButtonActionPerformed(ActionEvent evt) {
saveImageTransform(true);
}
private void cancelImageTransformButtonActionPerformed(ActionEvent evt) {
@@ -1615,8 +1649,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
if (Configuration.editorMode.get()) {
if (placeEditMode == PLACE_EDIT_RAW) {
placeGenericPanel.setEditMode(true, null);
addPlaceGenericListener();
placeGenericPanel.setEditMode(true, null);
}
placeEditButton.setVisible(false);
placeSaveButton.setVisible(true);
@@ -1634,7 +1667,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
mainPanel.clearEditingStatus();
placeTransformButton.setVisible(true);
if (placeEditMode == PLACE_EDIT_TRANSFORM) {
placeEditMode = PLACE_EDIT_RAW;
}
@@ -1660,8 +1693,31 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel
@Override
public boolean tryAutoSave() {
// todo: implement
return textPanel.tryAutoSave() && false;
boolean ok = true;
if (imageTransformSaveButton.isVisible() && imageTransformSaveButton.isEnabled() && Configuration.autoSaveTagModifications.get()) {
saveImageTransform(false);
ok = ok && !(imageTransformSaveButton.isVisible() && imageTransformSaveButton.isEnabled());
}
if (placeSaveButton.isVisible() && placeSaveButton.isEnabled() && Configuration.autoSaveTagModifications.get()) {
savePlaceTag(false);
ok = ok && !(placeSaveButton.isVisible() && placeSaveButton.isEnabled());
}
if (genericSaveButton.isVisible() && genericSaveButton.isEnabled()) {
saveGenericTag(false);
ok = ok && !(genericSaveButton.isVisible() && genericSaveButton.isEnabled());
}
if (metadataSaveButton.isVisible() && metadataSaveButton.isEnabled() && Configuration.autoSaveTagModifications.get()) {
saveMetadataButtonActionPerformed(null);
ok = ok && !(metadataSaveButton.isVisible() && metadataSaveButton.isEnabled());
}
if (fontPanel.isEditing() && Configuration.autoSaveTagModifications.get()) {
ok = ok && fontPanel.tryAutoSave();
}
ok = ok && textPanel.tryAutoSave();
return ok;
}
@Override
@@ -38,6 +38,7 @@ import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Objects;
import java.util.Timer;
import javax.swing.JButton;
import javax.swing.JLabel;
@@ -175,14 +176,19 @@ public class Amf3ValueEditor extends JPanel implements GenericTagEditor, FullSiz
}
@Override
public void save() {
public boolean save() {
try {
Object val = getChangedValue();
ReflectionTools.setValue(obj, field, index, val);
value = (Amf3Value) val;
Object oldValue = (Amf3Value) ReflectionTools.getValue(obj, field, index);
Object newValue = getChangedValue();
if (Objects.equals(oldValue, newValue)) {
return false;
}
ReflectionTools.setValue(obj, field, index, newValue);
value = (Amf3Value) newValue;
} catch (IllegalAccessException ex) {
//ignore
}
return true;
}
@Override
@@ -26,6 +26,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.lang.reflect.Field;
import java.util.Objects;
import javax.swing.JButton;
/**
@@ -99,12 +100,18 @@ public class BinaryDataEditor extends JButton implements GenericTagEditor {
}
@Override
public void save() {
public boolean save() {
try {
ReflectionTools.setValue(obj, field, index, value);
Object oldValue = ReflectionTools.getValue(obj, field, index);
Object newValue = value;
if (Objects.equals(oldValue, newValue)) {
return false;
}
ReflectionTools.setValue(obj, field, index, newValue);
} catch (IllegalArgumentException | IllegalAccessException ex) {
// ignore
}
return true;
}
@Override
@@ -67,12 +67,20 @@ public class BooleanEditor extends JCheckBox implements GenericTagEditor {
}
@Override
public void save() {
public boolean save() {
try {
boolean oldValue = (boolean) ReflectionTools.getValue(obj, field, index);
boolean newValue = isSelected();
if (oldValue == newValue) {
return false;
}
ReflectionTools.setValue(obj, field, index, isSelected());
} catch (IllegalArgumentException | IllegalAccessException ex) {
// ignore
}
return true;
}
@Override
@@ -35,6 +35,7 @@ import java.awt.event.FocusEvent;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Objects;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JColorChooser;
@@ -145,13 +146,19 @@ public class ColorEditor extends JPanel implements GenericTagEditor, ActionListe
}
@Override
public void save() {
Object val = getChangedValue();
public boolean save() {
try {
ReflectionTools.setValue(obj, field, index, val);
} catch (IllegalAccessException ex) {
Object oldValue = ReflectionTools.getValue(obj, field, index);
Object newValue = getChangedValue();
if (Objects.equals(oldValue, newValue)) {
return false;
}
ReflectionTools.setValue(obj, field, index, newValue);
} catch (IllegalArgumentException | IllegalAccessException ex) {
// ignore
}
return true;
}
@Override
@@ -26,6 +26,7 @@ import java.awt.event.FocusEvent;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import javax.swing.JComboBox;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
@@ -103,104 +104,22 @@ public class EnumEditor extends JComboBox<ComboBoxItem<Integer>> implements Gene
}
@Override
public void save() {
public boolean save() {
try {
Object value = getChangedValue();
if (value != null) {
ReflectionTools.setValue(obj, field, index, value);
Integer oldValue = (Integer) ReflectionTools.getValue(obj, field, index);
Integer newValue = (Integer)getChangedValue();
if (newValue == null) {
return false;
}
if (Objects.equals(oldValue, newValue)) {
return false;
}
ReflectionTools.setValue(obj, field, index, newValue);
} catch (IllegalArgumentException | IllegalAccessException ex) {
// ignore
}
}
private SpinnerModel getModel(SWFType swfType, Object value) {
SpinnerNumberModel m = null;
BasicType basicType = swfType == null ? BasicType.NONE : swfType.value();
switch (basicType) {
case UI8:
m = new SpinnerNumberModel(toInt(value), 0, 0xff, 1);
break;
case UI16:
m = new SpinnerNumberModel(toInt(value), 0, 0xffff, 1);
break;
case UB: {
long max = 1;
if (swfType.count() > 0) {
max <<= swfType.count();
} else {
max <<= 31;
}
m = new SpinnerNumberModel((Number) toLong(value), 0L, (long) max - 1, 1L);
}
break;
case UI32:
case EncodedU32:
case NONE:
m = new SpinnerNumberModel((Number) toLong(value), 0L, 0xffffffffL, 1L);
break;
case SI8:
m = new SpinnerNumberModel(toInt(value), -0x80, 0x7f, 1);
break;
case SI16:
case FLOAT16:
m = new SpinnerNumberModel(toInt(value), -0x8000, 0x7fff, 1);
break;
case FB:
case SB: {
long max = 1;
if (swfType.count() > 0) {
max <<= (swfType.count() - 1);
} else {
max <<= 30;
}
m = new SpinnerNumberModel((Number) toLong(value), (long) (-max), (long) max - 1, 1L);
}
break;
case SI32:
m = new SpinnerNumberModel(toDouble(value), -0x80000000, 0x7fffffff, 1);
break;
case FLOAT:
case FIXED:
case FIXED8:
m = new SpinnerNumberModel(toDouble(value), -0x80000000, 0x7fffffff, 0.01);
break;
}
return m;
}
private double toDouble(Object value) {
if (value instanceof Float) {
return (double) (Float) value;
}
if (value instanceof Double) {
return (double) (Double) value;
}
return 0;
}
private int toInt(Object value) {
if (value instanceof Short) {
return (int) (Short) value;
}
if (value instanceof Integer) {
return (int) (Integer) value;
}
return 0;
}
private long toLong(Object value) {
if (value instanceof Short) {
return (long) (Short) value;
}
if (value instanceof Integer) {
return (long) (Integer) value;
}
if (value instanceof Long) {
return (long) (Long) value;
}
return 0;
}
return true;
}
@Override
public void addChangeListener(final ChangeListener l) {
@@ -28,7 +28,7 @@ public interface GenericTagEditor {
public void reset();
public void save();
public boolean save();
public void addChangeListener(ChangeListener l);
@@ -23,6 +23,7 @@ import java.awt.Component;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.lang.reflect.Field;
import java.util.Objects;
import javax.swing.JFormattedTextField;
import javax.swing.JSpinner;
import javax.swing.SpinnerModel;
@@ -91,15 +92,21 @@ public class NumberEditor extends JSpinner implements GenericTagEditor {
}
@Override
public void save() {
public boolean save() {
try {
Object value = getChangedValue();
if (value != null) {
ReflectionTools.setValue(obj, field, index, value);
Object oldValue = ReflectionTools.getValue(obj, field, index);
Object newValue = getChangedValue();
if (newValue == null) {
return false;
}
if (Objects.equals(oldValue, newValue)) {
return false;
}
ReflectionTools.setValue(obj, field, index, newValue);
} catch (IllegalArgumentException | IllegalAccessException ex) {
// ignore
}
return true;
}
private SpinnerModel getModel(SWFType swfType, Object value) {
@@ -23,6 +23,7 @@ import java.awt.Dimension;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.lang.reflect.Field;
import java.util.Objects;
import javax.swing.JTextArea;
/**
@@ -91,12 +92,18 @@ public class StringEditor extends JTextArea implements GenericTagEditor {
}
@Override
public void save() {
public boolean save() {
try {
String oldValue = (String) ReflectionTools.getValue(obj, field, index);
String newValue = getText();
if (Objects.equals(oldValue, newValue)) {
return false;
}
ReflectionTools.setValue(obj, field, index, getText());
} catch (IllegalAccessException ex) {
} catch (IllegalArgumentException | IllegalAccessException ex) {
// ignore
}
return true;
}
@Override
@@ -23,6 +23,7 @@ import java.awt.Dimension;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.lang.reflect.Field;
import java.util.Objects;
import javax.swing.JTextArea;
import javax.swing.JTextField;
@@ -65,7 +66,7 @@ public class UUIDEditor extends JTextField implements GenericTagEditor {
}
public UUIDEditor(String fieldName, Object obj, Field field, int index, Class<?> type) {
super(32+4);
super(32 + 4);
this.obj = obj;
this.field = field;
this.index = index;
@@ -79,7 +80,7 @@ public class UUIDEditor extends JTextField implements GenericTagEditor {
try {
byte[] val = (byte[]) ReflectionTools.getValue(obj, field, index);
StringBuilder sb = new StringBuilder();
for(int i = 0; i < val.length; i++) {
for (int i = 0; i < val.length; i++) {
String h = Integer.toHexString(val[i] & 0xff);
if (h.length() == 1) {
h = "0" + h;
@@ -96,22 +97,28 @@ public class UUIDEditor extends JTextField implements GenericTagEditor {
}
@Override
public void save() {
public boolean save() {
try {
byte[] oldValue = (byte[]) ReflectionTools.getValue(obj, field, index);
String text = getText();
text = text.replace("-", "").trim();
if (!text.matches("[a-fA-F0-9]{32}")) {
return;
return false;
}
byte[] val = new byte[16];
byte[] newValue = new byte[16];
for (int i = 0; i < 16; i++) {
String ch = text.substring(i * 2, i * 2 + 2);
val[i] = (byte) Integer.parseInt(ch, 16);
newValue[i] = (byte) Integer.parseInt(ch, 16);
}
ReflectionTools.setValue(obj, field, index, val);
} catch (IllegalAccessException ex) {
if (Objects.equals(oldValue, newValue)) {
return false;
}
ReflectionTools.setValue(obj, field, index, newValue);
} catch (IllegalArgumentException | IllegalAccessException ex) {
// ignore
}
return true;
}
@Override
@@ -1080,4 +1080,6 @@ message.info.importImages2 = During importing images, you need to select a FOLDE
transform.clipboard = Clipboard
transform.clipboard.copy = Copy matrix to clipboard
transform.clipboard.paste = Paste matrix from clipboard
transform.clipboard.paste = Paste matrix from clipboard
status.editing.autosave = You are in the EDIT mode. Make changes, then press Save button. Or discard changes with Cancel button. If you switch to other tag, current editation will be automatically saved.
@@ -1065,4 +1065,6 @@ message.info.importImages2 = B\u011bhem importu text\u016f mus\u00edte vybrat SL
transform.clipboard = Schr\u00e1nka
transform.clipboard.copy = Kop\u00edrovat matici do schr\u00e1nky
transform.clipboard.paste = Vlo\u017eit matici ze schr\u00e1nky
transform.clipboard.paste = Vlo\u017eit matici ze schr\u00e1nky
status.editing.autosave = Jste v EDITA\u010cN\u00cdM re\u017eimu. Prove\u010fte zm\u011bny a stiskn\u011bte tla\u010d\u00edtko Ulo\u017eit. Nebo zru\u0161te zm\u011bny tla\u010d\u00edtkem Storno. Pokud p\u0159epnete na jin\u00fd tag, aktu\u00e1ln\u00ed editace bude automaticky ulo\u017eena.