/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.autoplot.dom; import java.beans.BeanInfo; import java.beans.IndexedPropertyDescriptor; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import java.util.logging.Level; import java.util.logging.Logger; /** * represent and implement array actions like insert, delete and move node. * @author jbf */ public class ArrayNodeDiff implements Diff { private static final Logger logger= org.das2.util.LoggerManager.getLogger( "autoplot.dom"); String propertyName; Object node; int index; int toIndex; public enum Action { Insert, Delete, Move } Action action; protected ArrayNodeDiff( String propertyName, Action action, Object node, int index ) { this.propertyName= propertyName; this.action= action; this.node= node; this.index= index; } protected ArrayNodeDiff( String propertyName, Action action, Object node, int index, int toIndex ) { this.propertyName= propertyName; this.action= action; this.node= node; this.index= index; this.toIndex= toIndex; } /** * encapsulate the ugly introspection stuff. Creates a new array with * the element deleted. * @param o an array of some type. * @param index * @return */ static Object deleteElement( Object o, int index ) { Class c= o.getClass(); if ( !c.isArray() ) throw new IllegalArgumentException("expected an array: "+o ); final int length = Array.getLength(o); Object result= Array.newInstance( c.getComponentType(),length-1); for ( int i=0; i<index; i++ ) { Array.set( result, i, Array.get(o, i) ); } for ( int i=index; i<length-1; i++ ) { Array.set( result, i, Array.get(o, i+1) ); } return result; } /** * encapsulate the ugly introspection stuff. Creates a new array with * the element added. * @param o an array of some type. * @param element * @param index * @return */ static Object insertElement( Object o, Object element, int index ) { Class c= o.getClass(); if ( !c.isArray() ) throw new IllegalArgumentException("expected an array: "+o ); final int length = Array.getLength(o); Object result= Array.newInstance(c.getComponentType(),length+1); for ( int i=0; i<index; i++ ) { Array.set( result, i, Array.get(o, i) ); } Array.set( result, index, element ); for ( int i=index+1; i<length+1; i++ ) { Array.set( result, i, Array.get(o, i-1) ); } return result; } private static void doAction( DomNode node, String propertyName, Object element, Action action, int arg0, int arg1 ) { try { BeanInfo info = Introspector.getBeanInfo(node.getClass()); PropertyDescriptor pd=null; for (PropertyDescriptor pd1 : info.getPropertyDescriptors()) { if (pd1.getName().equals(propertyName)) { pd= pd1; break; } } if ( pd==null ) throw new IllegalArgumentException("failed to find property "+propertyName + " in "+node); if ( !( pd instanceof IndexedPropertyDescriptor ) ) throw new IllegalArgumentException("expected indexed property"); IndexedPropertyDescriptor ipd= (IndexedPropertyDescriptor)pd; Object array= ipd.getReadMethod().invoke(node); Object newArray; if ( action==Action.Delete ) { newArray= deleteElement( array, arg0 ); } else if ( action==Action.Insert ) { newArray= insertElement( array, element, arg0 ); } else if ( action==Action.Move ) { newArray= deleteElement( array, arg0 ); if ( arg1>arg0 ) arg1--; newArray= insertElement( array, element, arg1 ); } else { throw new IllegalArgumentException("unimplemented action: "+action); } ipd.getWriteMethod().invoke(node, newArray); } catch (IllegalAccessException ex) { logger.log(Level.SEVERE, ex.getMessage(), ex); } catch (IllegalArgumentException ex) { logger.log(Level.SEVERE, ex.getMessage(), ex); } catch (InvocationTargetException ex) { logger.log(Level.SEVERE, ex.getMessage(), ex); } catch (IntrospectionException ex) { logger.log(Level.SEVERE, ex.getMessage(), ex); } } public void doDiff( DomNode node ) { doAction( node, this.propertyName, this.node, this.action, this.index, this.toIndex ); } public void undoDiff(DomNode node) { if ( action==Action.Delete ) { doAction( node, this.propertyName, this.node, Action.Insert, this.index, this.toIndex ); } else if ( action==Action.Insert ) { doAction( node, this.propertyName, this.node, Action.Delete, this.index, this.toIndex ); } else if ( action==Action.Move ) { doAction( node, this.propertyName, this.node, Action.Move, this.toIndex, this.index ); } } public String propertyName() { return propertyName; } public Action getAction() { return action; } public Object getNode() { return node; } public String toString() { if ( action==Action.Delete ) { return "delete "+node + " from "+propertyName+" @ " +index; } else if ( action==Action.Insert ) { return "insert "+node + " into "+propertyName+" @ " +index; } else if ( action==Action.Move ) { return "move "+node + "."+ propertyName + " from " +index +" to "+ toIndex; } else { return super.toString(); } } public String getLabel() { return toString(); } public String getDescription() { return toString(); } }