You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
SIPRP/trunk/SIPRPSoft/src/leaf/LeafWindow.java

859 lines
21 KiB

package leaf;
import static leaf.LeafLogic.ACTION_CANCEL;
import static leaf.LeafLogic.ACTION_STARTUP;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import javax.swing.DefaultListSelectionModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.table.TableModel;
import leaf.LeafLogic.Action;
import leaf.LeafLogic.LeafLogicActionBinding;
import leaf.LeafLogic.LeafUIActionBinding;
import com.evolute.utils.tables.BaseTable;
import com.evolute.utils.tables.ColumnizedMappable;
import com.evolute.utils.tables.VectorTableModel;
import com.evolute.utils.tracker.TrackableWindow;
public class LeafWindow extends JFrame implements TrackableWindow, ListSelectionListener, TreeSelectionListener, ActionListener, PropertyChangeListener
{
private static final long serialVersionUID = 1L;
/**
* Registers DataComponent in a list of actions
*
* @author tsimao
*
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface ActionActivation
{
/**
* Array of actions to execute when a select is listened in this
* JComponent
*
* @return
*/
String[] onSelect();
/**
* Array of actions to execute when a change is listened in this
* JComponent
*
* @return
*/
String[] onChange();
}
/**
* Binds an Object to actions
*
* @author tsimao
*
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface LeafObject
{
/**
* Actions that use this field
*/
String[] useWith();
}
/**
* Declares a JPanel as a leaf
*
* @author tsimao
*
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface LeafPanel
{
}
/**
* This window's logic controller
*/
private final LeafLogic logicController;
private List<JPanel> subPanels = new ArrayList<JPanel>();
/**
* Actions
*/
private Map<String, Action> mapActionByName = new HashMap<String, Action>();
/**
* Fields
*/
private Map<String, List<Object>> mapWindowOnSelectFieldByActionName = new HashMap<String, List<Object>>();
private Map<String, List<Object>> mapWindowOnChangeFieldByActionName = new HashMap<String, List<Object>>();
private Map<String, Field> mapLeafObjectByActionName = new HashMap<String, Field>();
private Map<Field, Object> mapInstanceByField = new HashMap<Field, Object>();
/**
* Methods
*/
private Map<String, List<Method>> mapWindowMethodsByActionName = new HashMap<String, List<Method>>();
private Map<String, Method> mapLogicMethodByActionName = new HashMap<String, Method>();
private Map<Method, Object> mapInstanceByMethod = new HashMap<Method, Object>();
/**
* Meta-info
*/
private Map<Object, Annotation> mapAnnotationByObject = new HashMap<Object, Annotation>();
/**
* Run later actions
*/
private Queue<String> listRunLater = new LinkedList<String>();
/**
* Creates a new LeafWindow binded with given 'logicController'
*
* @param logicController
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
public LeafWindow(LeafLogic logicController) throws IllegalArgumentException, IllegalAccessException
{
super();
this.logicController = logicController;
if( logicController != null )
{
logicController.addWindow( this );
}
}
@Override
public void open()
{
setVisible( true );
}
public void close()
{
SwingUtilities.invokeLater( new Runnable()
{
public void run()
{
setVisible( false );
dispose();
}
} );
}
@Override
public boolean closeIfPossible()
{
close();
return true;
}
@Override
public void refresh()
{
}
/**
* Aborts current action. Aborts pending actions as well if 'all' is true
*
* @param all
*/
public void abortAction( boolean all )
{
runGivenAction( ACTION_CANCEL, null );
throw new LeafRuntimeException( all );
}
protected boolean runAction( String actionName )
{
return runAction( actionName, null );
}
/**
* Returns false if an error occurred
*
* @param actionName
* @param argument
* @return
*/
protected boolean runAction( String actionName, Object argument )
{
boolean ok = true;
if( argument == null )
{
Field field = mapLeafObjectByActionName.get( actionName );
if(field != null)
{
Object instance = mapInstanceByField.get( field );
if( instance != null)
{
try
{
argument = field.get( instance );
} catch( IllegalArgumentException e )
{
e.printStackTrace(System.out);
} catch( IllegalAccessException e )
{
e.printStackTrace( System.out);
}
}
}
}
try
{
runGivenAction( actionName, argument );
} catch( LeafRuntimeException leafRuntimeException )
{
ok = !leafRuntimeException.isAbort();
}
if( ok )
{
runPendingActions();
}
else
{
listRunLater.clear();
}
return ok;
}
public void runActionLater( String action )
{
if( action != null && mapActionByName.containsKey( action ) )
{
listRunLater.add( action );
}
}
public void completeSetup()
{
try
{
loadLeafs();
loadActions();
loadFields();
loadMethods();
runAction( ACTION_STARTUP, null );
} catch( Exception e )
{
e.printStackTrace( System.out );
}
}
private void loadLeafs() throws IllegalArgumentException, IllegalAccessException
{
Field fields[] = this.getClass().getDeclaredFields();
if( fields != null )
{
for( Field field : fields )
{
if( field.getAnnotation( LeafPanel.class ) != null && field.get( this ) != null )
{
subPanels.add( (JPanel) field.get( this ) );
}
}
}
}
private void loadActions() throws IllegalArgumentException, IllegalAccessException
{
Field[] allLogicFields = this.logicController.getClass().getFields();
for( Field field : allLogicFields )
{
Action action = field.getAnnotation( Action.class );
if( action != null )
{
String value = (String) field.get( this );
if( value != null )
{
mapActionByName.put( value, action );
mapWindowMethodsByActionName.put( value, new ArrayList<Method>() );
mapWindowOnSelectFieldByActionName.put( value, new ArrayList<Object>() );
mapWindowOnChangeFieldByActionName.put( value, new ArrayList<Object>() );
}
}
}
}
private void loadFields( Field[] fields, Object instance )
{
try
{
for( Field field : fields )
{
ActionActivation componentBehaviour = field.getAnnotation( ActionActivation.class );
if( componentBehaviour != null )
{
String[] allChanges = componentBehaviour.onChange();
if( allChanges != null )
{
for( String onChange : allChanges )
{
if( mapActionByName.containsKey( onChange ) )
{
// valid action
mapAnnotationByObject.put( field.get( instance ), componentBehaviour );
mapWindowOnChangeFieldByActionName.get( onChange ).add( field.get( instance ) );
if( !mapInstanceByField.containsKey( field ) )
{
addListenerForField( componentBehaviour, field, instance );
mapInstanceByField.put( field, instance );
}
}
}
}
String[] allSelect = componentBehaviour.onSelect();
if( allSelect != null )
{
for( String onSelect : allSelect )
{
if( mapActionByName.containsKey( onSelect ) )
{
// valid action
mapAnnotationByObject.put( field.get( instance ), componentBehaviour );
mapWindowOnSelectFieldByActionName.get( onSelect ).add( field.get( instance ) );
if( !mapInstanceByField.containsKey( field ) )
{
addListenerForField( componentBehaviour, field, instance );
mapInstanceByField.put( field, instance );
}
}
}
}
}
LeafObject leafObject = field.getAnnotation( LeafObject.class );
if( leafObject != null )
{
String[] useWith = leafObject.useWith();
if( useWith != null )
{
for( String current : useWith )
{
if( mapActionByName.containsKey( current ) )
{
// valid action
mapLeafObjectByActionName.put( current, field );
mapInstanceByField.put( field, instance );
}
}
}
}
}
} catch( IllegalAccessException exception )
{
exception.printStackTrace( System.out );
}
}
private void loadFields()
{
Field[] allFields = this.getClass().getDeclaredFields();
if( allFields != null )
{
loadFields( allFields, this );
}
allFields = logicController.getClass().getDeclaredFields();
if( allFields != null )
{
loadFields( allFields, logicController );
}
for( JPanel panel : subPanels )
{
allFields = panel.getClass().getDeclaredFields();
if( allFields != null )
{
loadFields( allFields, panel );
}
}
}
private void loadWindowMethods( Method[] windowMethods, Object instance )
{
for( Method method : windowMethods )
{
LeafUIActionBinding actionBinding = method.getAnnotation( LeafUIActionBinding.class );
if( actionBinding != null )
{
String[] actions = actionBinding.action();
for( String actionName : actions )
{
if( mapActionByName.containsKey( actionName ) )
{
// valid action
mapWindowMethodsByActionName.get( actionName ).add( method );
mapAnnotationByObject.put( method, actionBinding );
mapInstanceByMethod.put( method, instance );
}
}
}
}
}
private void loadLogicMethods()
{
Method[] allLogicMethods = this.logicController.getClass().getDeclaredMethods();
if( allLogicMethods != null )
{
for( Method method : allLogicMethods )
{
LeafLogicActionBinding actionBinding = method.getAnnotation( LeafLogicActionBinding.class );
if( actionBinding != null )
{
String[] actions = actionBinding.actions();
if( actions != null )
{
for( String actionName : actions )
{
if( mapActionByName.containsKey( actionName ) )
{
// valid action
mapAnnotationByObject.put( method, actionBinding );
mapLogicMethodByActionName.put( actionName, method );
mapInstanceByMethod.put( method, logicController );
}
}
}
}
}
}
}
private void loadMethods()
{
loadLogicMethods();
Method[] allWindowMethods = this.getClass().getDeclaredMethods();
if( allWindowMethods != null )
{
loadWindowMethods( allWindowMethods, this );
}
for( JPanel panel : subPanels )
{
allWindowMethods = panel.getClass().getDeclaredMethods();
if( allWindowMethods != null )
{
loadWindowMethods( allWindowMethods, panel );
}
}
}
private Object getObjectForAction( String actionName )
{
Object result = null;
Field field = mapLeafObjectByActionName.get( actionName );
if( field != null )
{
Object instance = mapInstanceByField.get( field );
if( instance != null )
{
try
{
result = field.get( instance );
} catch( IllegalArgumentException e )
{
e.printStackTrace();
} catch( IllegalAccessException e )
{
e.printStackTrace();
}
}
}
return result;
}
private void runPendingActions()
{
while( listRunLater.size() > 0 )
{
runAction( listRunLater.poll() );
}
}
/**
* Executes given action
*/
private void runGivenAction( String actionName, Object argument )
{
System.out.println( "Running: " + actionName );
try
{
this.setCursor( Cursor.getPredefinedCursor( Cursor.WAIT_CURSOR ) );
if( actionName != null && mapActionByName.containsKey( actionName ) )
{
Action action = mapActionByName.get( actionName );
if( action.isSave() )
{
Object windowArgument = getObjectForAction( actionName );
Object logicArgument = windowArgument;
for( Method currentWindowMethod : mapWindowMethodsByActionName.get( actionName ) )
{
Object currentLogicArgument = runWindowMethod( currentWindowMethod, windowArgument != null ? windowArgument : argument );
logicArgument = logicArgument == null ? currentLogicArgument : logicArgument;
}
runLogicMethod( mapLogicMethodByActionName.get( actionName ), logicArgument );
}
else
{
Object windowArgument = runLogicMethod( mapLogicMethodByActionName.get( actionName ), argument );
for( Method currentWindowMethod : mapWindowMethodsByActionName.get( actionName ) )
{
runWindowMethod( currentWindowMethod, windowArgument != null ? windowArgument : argument );
}
}
}
} finally
{
this.setCursor( Cursor.getDefaultCursor() );
}
}
private Object runLogicMethod( Method logicMethod, Object argument ) throws LeafRuntimeException
{
Object result = null;
try
{
if( logicMethod != null )
{
if( logicMethod.getParameterTypes().length > 0 )
{
result = logicMethod.invoke( logicController, argument );
}
else
{
result = logicMethod.invoke( logicController );
}
}
} catch( IllegalArgumentException e )
{
System.out.println("Error in: " + logicMethod.getName() );
System.out.println("Got: " + argument + " expected: " + (logicMethod.getParameterTypes().length > 0 ? logicMethod.getParameterTypes()[0].getCanonicalName() : "(nothing)"));
e.printStackTrace( System.out );
} catch( IllegalAccessException e )
{
e.printStackTrace( System.out );
} catch( InvocationTargetException e )
{
if( e.getCause() instanceof LeafRuntimeException )
{
throw (LeafRuntimeException) e.getCause();
}
else
{
e.printStackTrace( System.out );
}
}
return result;
}
private Object runWindowMethod( Method windowMethod, Object argument ) throws LeafRuntimeException
{
Object result = null;
try
{
if( windowMethod != null )
{
if( windowMethod.getParameterTypes().length > 0 )
{
result = windowMethod.invoke( mapInstanceByMethod.get( windowMethod ), argument );
}
else
{
result = windowMethod.invoke( mapInstanceByMethod.get( windowMethod ) );
}
}
} catch( IllegalArgumentException e )
{
System.out.println("Error in: " + windowMethod.getName() );
System.out.println("Got: " + argument + " expected: " + (windowMethod.getParameterTypes().length > 0 ? windowMethod.getParameterTypes()[0].getCanonicalName() : "(nothing)"));
e.printStackTrace( System.out );
} catch( IllegalAccessException e )
{
e.printStackTrace( System.out );
} catch( InvocationTargetException e )
{
if( e.getCause() instanceof LeafRuntimeException )
{
throw (LeafRuntimeException) e.getCause();
}
else
{
e.printStackTrace( System.out );
}
}
return result;
}
private void addListenerForField( ActionActivation annotation, Field field, Object instance )
{
if( instance instanceof JFrame || instance instanceof JPanel )
{
try
{
Object value = field.get( instance );
if( value instanceof BaseTable )
{
((BaseTable) value).getSelectionModel().addListSelectionListener( this );
}
else if( value instanceof JTree )
{
((JTree) value).addTreeSelectionListener( this );
}
else if( value instanceof JButton )
{
((JButton) value).addActionListener( this );
}
else if( value instanceof LeafInputField )
{
((LeafInputField) value).addPropertyChangeListener( this );
}
} catch( IllegalAccessException e )
{
e.printStackTrace( System.out );
} catch( NullPointerException e )
{
e.printStackTrace( System.out );
}
}
}
private Object getArgumentListSelectionEvent( String actionName, ListSelectionEvent event )
{
Object source = event.getSource();
List<Object> allComponents = mapWindowOnSelectFieldByActionName.get( actionName );
for( Object component : allComponents )
{
if( component instanceof BaseTable && ((BaseTable) component).getSelectionModel().equals( source ) )
{
int index = ((BaseTable) component).getSelectedRow();
if( index > -1 )
{
TableModel model = ((BaseTable) component).getModel();
if( model instanceof VectorTableModel )
{
return ((ColumnizedMappable) ((VectorTableModel) model).getRowAt( index )).getID();
}
else if( model instanceof LeafTableModel )
{
return ((LeafTableModel) model).getKey( index );
}
}
}
}
return null;
}
private List<String> getActionListSelectionEvent( ListSelectionEvent event )
{
List<String> result = new ArrayList<String>();
if( event.getSource() instanceof DefaultListSelectionModel )
{
DefaultListSelectionModel model = (DefaultListSelectionModel) event.getSource();
BaseTable table = null;
for( List<Object> allComponents : mapWindowOnSelectFieldByActionName.values() )
{
// for each registered table
for( Object component : allComponents )
{
if( component instanceof BaseTable && ((BaseTable) component).getSelectionModel().equals( model ) )
{
table = (BaseTable) component;
}
if( table != null )
{
break;
}
}
if( table != null )
{
break;
}
}
Annotation an = mapAnnotationByObject.get( table );
if( an != null && an instanceof ActionActivation )
{
String[] actions = ((ActionActivation) an).onSelect();
for( String actionName : actions )
{
result.add( actionName );
}
}
}
return result;
}
// returns selected node
private Object getArgumentTreeSelectionEvent( String actionName, TreeSelectionEvent event )
{
List<Object> components = mapWindowOnSelectFieldByActionName.get( actionName );
for( Object component : components )
{
if( component instanceof JTree && event.getPath() != null )
{
Object[] nodes = event.getPath().getPath();
if( nodes != null && nodes.length > 0 )
{
return nodes[nodes.length - 1];
}
}
}
return null;
}
private List<String> getActionTreeSelectionEvent( TreeSelectionEvent event )
{
List<String> result = new ArrayList<String>();
Annotation an = mapAnnotationByObject.get( event.getSource() );
if( an != null && an instanceof ActionActivation )
{
String[] actions = ((ActionActivation) an).onSelect();
for( String actionName : actions )
{
result.add( actionName );
}
}
return result;
}
private List<String> getActionActionEvent( ActionEvent event )
{
List<String> result = new ArrayList<String>();
Annotation an = mapAnnotationByObject.get( event.getSource() );
if( an != null && an instanceof ActionActivation )
{
String[] actions = ((ActionActivation) an).onSelect();
for( String actionName : actions )
{
result.add( actionName );
}
}
return result;
}
private List<String> getActionsForPropertyChangeEvent( PropertyChangeEvent evt )
{
List<String> result = new ArrayList<String>();
Annotation an = mapAnnotationByObject.get( evt.getSource() );
if( an != null )
{
if( an instanceof ActionActivation )
{
if( evt.getSource() instanceof LeafInputField )
{
if( LeafInputField.PROPERTY_CHANGED_CONSTANT.equals( evt.getPropertyName() ) )
{
String[] actions = ((ActionActivation) an).onChange();
for( String actionName : actions )
{
result.add( actionName );
}
}
}
}
}
return result;
}
@Override
public void valueChanged( TreeSelectionEvent event )
{
List<String> actions = getActionTreeSelectionEvent( event );
for( String action : actions )
{
Object argument = getArgumentTreeSelectionEvent( action, event );
if( !runAction( action, argument ) )
{
break;
}
}
}
/**
* Listens to ListSelectionEvents
*/
@Override
public void valueChanged( ListSelectionEvent event )
{
if( !event.getValueIsAdjusting() )
{
List<String> actionNames = getActionListSelectionEvent( event );
for( String action : actionNames )
{
Object argument = getArgumentListSelectionEvent( action, event );
if( !runAction( action, argument ) )
{
break;
}
}
}
}
@Override
public void actionPerformed( ActionEvent event )
{
List<String> actionNames = getActionActionEvent( event );
if( actionNames.size() > 0 )
{
for( int i = 1; i < actionNames.size(); ++i )
{
runActionLater( actionNames.get( i ) );
}
runAction( actionNames.get( 0 ) );
}
}
@Override
public void propertyChange( PropertyChangeEvent evt )
{
List<String> actionNames = getActionsForPropertyChangeEvent( evt );
if( actionNames.size() > 0 )
{
for( int i = 1; i < actionNames.size(); ++i )
{
runActionLater( actionNames.get( i ) );
}
runAction( actionNames.get( 0 ) );
}
}
}