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

This commit is contained in:
Jindra Petřík
2022-12-22 18:15:29 +01:00
parent 380d7b9078
commit c2ceec8628
18 changed files with 362 additions and 778 deletions

View File

@@ -12,7 +12,7 @@ All notable changes to this project will be documented in this file.
("PNG/GIF/JPEG+alpha" option in GUI, "-format image:png_gif_jpeg_alpha" for commandline)
- [#1910] Copy/paste transform matrix to/from the clipboard
- [#1912] Persist selected item in the tree upon quick search (Ctrl+F)
- [#1901] Editor mode for raw edit
- [#1901] Editor mode and autosave feature for header, raw editor, transform
### Fixed
- [#1904] NullPointerException when renaming invalid identifiers in AS1/2 files caused by missing charset

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -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() {

View File

@@ -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() {

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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) {

View File

@@ -28,7 +28,7 @@ public interface GenericTagEditor {
public void reset();
public void save();
public boolean save();
public void addChangeListener(ChangeListener l);

View File

@@ -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) {

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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.