001 /* 002 003 Copyright (C) 2001 Renaud Pawlak, Laurent Martelli 004 005 This program is free software; you can redistribute it and/or modify 006 it under the terms of the GNU Lesser General Public License as 007 published by the Free Software Foundation; either version 2 of the 008 License, or (at your option) any later version. 009 010 This program is distributed in the hope that it will be useful, but 011 WITHOUT ANY WARRANTY; without even the implied warranty of 012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 Lesser General Public License for more details. 014 015 You should have received a copy of the GNU Lesser General Public 016 License along with this program; if not, write to the Free Software 017 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 018 USA */ 019 020 package org.objectweb.jac.aspects.gui; 021 022 import org.objectweb.jac.core.Display; 023 import org.objectweb.jac.core.rtti.AbstractMethodItem; 024 import org.objectweb.jac.core.rtti.ClassRepository; 025 import org.objectweb.jac.util.Stack; 026 027 /** 028 * This class allows a GUI programmer to create input sequences to ask 029 * the user to fill a set of parameters when invoking a method. 030 * 031 * <p>By default, when invoking a method through the GUI, an 032 * <code>InputWrapper</code> opens a dialog to fill the parameters 033 * values when needed. If an input sequence is attached to this method 034 * (see <code>GuiAC.setInputSequence</code>), then the input wrappers 035 * will ask for the parameters using several input dialogs, each one 036 * corresponding to a step of the input sequence. 037 * 038 * <p>Defining a new input sequence is done by concretizing this 039 * class. For instance, the following class defines a sequence with 040 * two steps that open input dialogs from some prototypes defined in 041 * the class. The first steps asks for a boolean value that will 042 * dinamically determines the second step input. 043 * 044 * <pre> 045 * public class MyInputSequence extends InputSequence { 046 * public MyInputSequence( Display display, 047 * AbstractMethodItem method, 048 * Object[] parameters ) { 049 * super(display,method,parameters); 050 * } 051 * public int getNbSteps() { 052 * return 2; 053 * } 054 * public void init() {} 055 * public void validate() { 056 * Object[] values = getStepValues(2); 057 * setParameterValue(0, values[0]); 058 * Boolean firstStepResult = getStepValues(1)[0]; 059 * if ( firstStepResult.booleanValue() ) { 060 * setParameterValue(1, values[1]); 061 * } else { 062 * setParameterValue(1, null); 063 * } 064 * } 065 * public AbstractMethodItem getStepMethod( int step ) { 066 * if( step == 1 ) { 067 * return getLocalInputMethod( "myPrototype1" ); 068 * } else if ( step == 2 ) { 069 * Object[] values = getStepValues(1); 070 * Boolean firstStepResult = values[0]; 071 * if ( firstStepResult.booleanValue() ) { 072 * return getLocalInputMethod( "myPrototype2" ); 073 * } else { 074 * return getLocalInputMethod( "myPrototype3" ); 075 * } else { 076 * return null; 077 * } 078 * } 079 * public void myPrototype1( boolean b ) {} 080 * public void myPrototype2( String s ) {} 081 * public void myPrototype3( String s1, String s2 ) {} 082 * } 083 * </pre> 084 * 085 * @see InputWrapper 086 * 087 * @author <a href="mailto:pawlak@cnam.fr">Renaud Pawlak</a> */ 088 089 public abstract class InputSequence { 090 091 AbstractMethodItem method; 092 Object[] parameters; 093 Display display; 094 095 Stack stepParameters = new Stack(); 096 int currentStep = 0; 097 098 /** 099 * Creates a user-defined input sequence. 100 * 101 * @param display the display to use to show the input boxes 102 * @param method the method that will be finally invoked at the end 103 * of the input sequence 104 * @param parameters the array that contains the parameters of the 105 * invoked method */ 106 107 public InputSequence( Display display, AbstractMethodItem method, 108 Object[] parameters ) { 109 this.display = display; 110 this.method = method; 111 this.parameters = parameters; 112 } 113 114 /** 115 * This method is called when a new invocation is performed on the 116 * method. 117 * 118 * <p>Define it if some objects must be dynamically constructed to 119 * handle the sequence. */ 120 121 public abstract void init(); 122 123 /** 124 * This method is called when the input sequence is finished and 125 * when the user validates the last step input. 126 * 127 * <p>Define this method to fill the method parameters from the 128 * values found in all the performed steps. 129 * 130 * @return true is the input is valid (false cancels the 131 * invocation) 132 * @see #getStepValues(int) 133 * @see #setParameterValue(int,Object) */ 134 135 public abstract boolean validate(); 136 137 /** 138 * Define this method to return the number of steps (can 139 * dynamically change regarding the inputted vaules of the steps). 140 * 141 * @return the number of steps of the input sequence */ 142 143 public abstract int getNbSteps(); 144 145 /** 146 * Returns the current step (indexed from 1). 147 * 148 * @return the current step */ 149 150 public final int getCurrentStep() { 151 return currentStep; 152 } 153 154 /** 155 * Tells if the sequence has a next step to perform after the 156 * current one. 157 * 158 * @return true if a next step to perform */ 159 160 public final boolean hasNextStep() { 161 return currentStep < getNbSteps(); 162 } 163 164 /** 165 * Returns the method that is used to define the input box for a 166 * given step. 167 * 168 * <p>This is the most important method since it defines the shape 169 * of an input box step. You should define a set of local method 170 * with the right prototype and get their correponding method item 171 * with the <code>getLocalInputMethod</code> method. 172 * 173 * <p>Note that the method is not actually called but is only used 174 * through the <code>Display.showIntput</code> method. 175 * 176 * @param step the step (indexed from 1) 177 * @return the method that is used to create the input 178 * @see org.objectweb.jac.core.Display#showInput(Object,AbstractMethodItem,Object[]) 179 * @see #getLocalInputMethod(String) */ 180 181 public abstract AbstractMethodItem getStepMethod( int step ); 182 183 /** 184 * Call this method on a new input sequence to process the inputs. 185 * 186 * @return false if some error happened or if an input step was 187 * cancelled by the user */ 188 189 public final boolean proceedInputs() { 190 init(); 191 while( hasNextStep() ) { 192 if ( ! nextStep() ) return false; 193 } 194 return validate(); 195 } 196 197 /** 198 * Process the next step. 199 * @return true if ok */ 200 201 public final boolean nextStep() { 202 currentStep++; 203 AbstractMethodItem stepMethod = getStepMethod( currentStep ); 204 Object[] params = null; 205 stepParameters.push( params = new Object[stepMethod.getParameterTypes().length] ); 206 return display.showInput( null, stepMethod, params ); 207 } 208 209 /** 210 * Process the previous step back. 211 * @return true if ok */ 212 213 public boolean previousStep() { 214 stepParameters.pop(); 215 currentStep--; 216 AbstractMethodItem stepMethod = getStepMethod( currentStep ); 217 return display.showInput( null, stepMethod, (Object[])stepParameters.peek() ); 218 } 219 220 /** 221 * Returns the method item that corresponds to a method defined in 222 * the user-defined input sequence. 223 * 224 * @param name the method name 225 * @return the corresponding method item */ 226 227 protected AbstractMethodItem getLocalInputMethod( String name ) { 228 return ClassRepository.get().getClass( this.getClass() ).getMethod( name ); 229 } 230 231 /** 232 * Returns the values that were entered by the user for a given 233 * step. 234 * 235 * @param step the step number (indexed from 1) 236 * @return the user-inputted values */ 237 238 protected Object[] getStepValues( int step ) { 239 if( currentStep < step ) { 240 throw new RuntimeException("Step "+step+" result is not available yet"); 241 } 242 return (Object[])stepParameters.get(step-1); 243 } 244 245 /** 246 * Sets the parameter value for the final call of the method that 247 * will be invoked at the end of the sequence. 248 * 249 * @param i the parameter index 250 * @param value the value */ 251 252 protected void setParameterValue( int i, Object value ) { 253 parameters[i] = value; 254 } 255 } 256 257