generic tag editor: disable instantiation of abstract classes, make Action list related types not editable (it does not work yet)

This commit is contained in:
Jindra Pet��k
2014-03-02 17:34:45 +01:00
parent 6e8f8931b3
commit 55f54de9cb
6 changed files with 106 additions and 8 deletions
@@ -61,6 +61,7 @@ import javax.swing.AbstractCellEditor;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
@@ -242,6 +243,11 @@ public class GenericTagTreePanel extends GenericTagPanel {
itemStr = AppStrings.translate("generictag.array.item");
}
if (ReflectionTools.needsIndex(fnode.field)) {
boolean canAdd = true;
if (!ReflectionTools.canAddToField(fnode.obj, fnode.field)) {
canAdd = false;
}
JPopupMenu p = new JPopupMenu();
JMenuItem mi;
mi = new JMenuItem(AppStrings.translate("generictag.array.insertbeginning").replace("%item%", itemStr));
@@ -252,6 +258,9 @@ public class GenericTagTreePanel extends GenericTagPanel {
addItem(fnode.obj, fnode.field, 0);
}
});
if (!canAdd) {
mi.setEnabled(false);
}
p.add(mi);
if (fnode.index > -1) {
@@ -263,6 +272,9 @@ public class GenericTagTreePanel extends GenericTagPanel {
addItem(fnode.obj, fnode.field, fnode.index);
}
});
if (!canAdd) {
mi.setEnabled(false);
}
p.add(mi);
mi = new JMenuItem(AppStrings.translate("generictag.array.remove").replace("%item%", itemStr));
@@ -283,6 +295,9 @@ public class GenericTagTreePanel extends GenericTagPanel {
addItem(fnode.obj, fnode.field, fnode.index + 1);
}
});
if (!canAdd) {
mi.setEnabled(false);
}
p.add(mi);
}
@@ -294,6 +309,9 @@ public class GenericTagTreePanel extends GenericTagPanel {
addItem(fnode.obj, fnode.field, ReflectionTools.getFieldSubSize(fnode.obj, fnode.field));
}
});
if (!canAdd) {
mi.setEnabled(false);
}
p.add(mi);
//}
p.show(tree, e.getX(), e.getY());
@@ -789,12 +807,21 @@ public class GenericTagTreePanel extends GenericTagPanel {
SWFArray swfArray = field.getAnnotation(SWFArray.class);
if (swfArray != null && !swfArray.countField().equals("")) { //Fields with same countField must be enlarged too
Field fields[] = obj.getClass().getDeclaredFields();
List<Integer> sameFlds = new ArrayList<>();
for (int f = 0; f < fields.length; f++) {
SWFArray fieldSwfArray = fields[f].getAnnotation(SWFArray.class);
if (fieldSwfArray != null && fieldSwfArray.countField().equals(swfArray.countField())) {
ReflectionTools.addToField(obj, fields[f], index, true);
sameFlds.add(f);
if (!ReflectionTools.canAddToField(obj, fields[f])) {
JOptionPane.showMessageDialog(this, "This field is abstract, cannot be instantiated, sorry."); //TODO!!!
return;
}
}
}
for (int f : sameFlds) {
ReflectionTools.addToField(obj, fields[f], index, true);
}
try {
//If countField exists, increment, otherwise do nothing
Field countField = obj.getClass().getDeclaredField(swfArray.countField());
@@ -807,6 +834,10 @@ public class GenericTagTreePanel extends GenericTagPanel {
//ignored
}
} else {
if (!ReflectionTools.canAddToField(obj, field)) {
JOptionPane.showMessageDialog(this, "This field is abstract, cannot be instantiated, sorry."); //TODO!!!
return;
}
ReflectionTools.addToField(obj, field, index, true);
}
refreshTree();
@@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.gui.generictageditors;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.logging.Level;
@@ -85,6 +86,42 @@ public class ReflectionTools {
}
}
public static boolean canInstantiate(Class cls) {
if (cls.isInterface()) {
return false;
}
if (Modifier.isAbstract(cls.getModifiers())) {
return false;
}
return true;
}
public static boolean canAddToField(Object object, Field field) {
if (List.class.isAssignableFrom(field.getType())) {
ParameterizedType listType = (ParameterizedType) field.getGenericType();
Class<?> parameterClass = (Class<?>) listType.getActualTypeArguments()[0];
return canInstantiate(parameterClass);
}
if (field.getType().isArray()) {
Object arrValue;
try {
arrValue = field.get(object);
} catch (IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
Class componentClass = arrValue.getClass().getComponentType();
if (componentClass.isPrimitive()) {
return true;
}
return canInstantiate(componentClass);
}
return false;
}
public static Object newInstanceOf(Class cls) throws InstantiationException, IllegalAccessException {
if (cls == Integer.class || cls == int.class) {
return new Integer(0);
@@ -95,6 +132,12 @@ public class ReflectionTools {
} else if (cls == Long.class || cls == long.class) {
return new Long(0L);
}
if (cls.isInterface()) {
return null;
}
if (Modifier.isAbstract(cls.getModifiers())) {
return null;
}
return cls.newInstance();
}
@@ -114,6 +157,9 @@ public class ReflectionTools {
Class<?> parameterClass = (Class<?>) listType.getActualTypeArguments()[0];
try {
Object val = newInstanceOf(parameterClass);
if (val == null) {
return false;
}
list.add(index, val);
} catch (InstantiationException | IllegalAccessException ex) {
Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex);
@@ -151,19 +197,28 @@ public class ReflectionTools {
return false;
}
Class componentClass = arrValue.getClass().getComponentType();
int originalSize = Array.getLength(arrValue);
Object copy = Array.newInstance(componentClass, originalSize + 1);
//Copy items before
for (int i = 0; i < index; i++) {
Array.set(copy, i, Array.get(arrValue, i));
}
Object val = null;
if (!componentClass.isPrimitive()) {
try {
Array.set(copy, index, componentClass.newInstance());
val = newInstanceOf(componentClass);
} catch (InstantiationException | IllegalAccessException ex) {
Logger.getLogger(ReflectionTools.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
if (val == null) {
return false;
}
}
int originalSize = Array.getLength(arrValue);
Object copy = Array.newInstance(componentClass, originalSize + 1);
//Copy items before
for (int i = 0; i < index; i++) {
Array.set(copy, i, Array.get(arrValue, i));
}
if (val != null) {
Array.set(copy, index, val);
}
//Copy items after
for (int i = index; i < originalSize; i++) {
@@ -32,6 +32,7 @@ import com.jpexs.decompiler.flash.types.ColorTransform;
import com.jpexs.decompiler.flash.types.MATRIX;
import com.jpexs.decompiler.flash.types.RGBA;
import com.jpexs.decompiler.flash.types.annotations.Conditional;
import com.jpexs.decompiler.flash.types.annotations.Internal;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.filters.FILTER;
import java.io.ByteArrayInputStream;
@@ -123,6 +124,7 @@ public class PlaceObject2Tag extends CharacterIdTag implements Container, PlaceO
* @since SWF 5 If PlaceFlagHasClipActions, Clip Actions Data
*/
@Conditional("placeFlagHasClipActions")
@Internal //TODO: make editable
public CLIPACTIONS clipActions;
public static final int ID = 26;
@@ -181,6 +181,7 @@ public class PlaceObject3Tag extends CharacterIdTag implements Container, PlaceO
* @since SWF 5 If PlaceFlagHasClipActions, Clip Actions Data
*/
@Conditional(value = "placeFlagHasClipActions", minSwfVersion = 5)
@Internal //TODO: make editable
public CLIPACTIONS clipActions;
/**
* If PlaceFlagHasVisible, 0 = Place invisible, 1 = Place visible
@@ -181,6 +181,7 @@ public class PlaceObject4Tag extends CharacterIdTag implements Container, PlaceO
* @since SWF 5 If PlaceFlagHasClipActions, Clip Actions Data
*/
@Conditional(value = "placeFlagHasClipActions", minSwfVersion = 5)
@Internal //TODO: make editable
public CLIPACTIONS clipActions;
/**
* If PlaceFlagHasVisible, 0 = Place invisible, 1 = Place visible
@@ -95,6 +95,14 @@ public class CLIPACTIONRECORD implements ASMSource, Exportable, ContainerItem, S
@Internal
private long hdrPos;
//Constructor for Generic tag editor. TODO:Handle this somehow better
public CLIPACTIONRECORD(){
swf = null;
eventFlags = new CLIPEVENTFLAGS();
actionBytes = new byte[0];
hdrPos = 0;
}
public CLIPACTIONRECORD(SWF swf, InputStream is, int version, long pos) throws IOException {
this.swf = swf;
SWFInputStream sis = new SWFInputStream(is, version);