r1269 - in jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing: . wizard
Author: tchemit Date: 2009-03-18 08:45:58 +0000 (Wed, 18 Mar 2009) New Revision: 1269 Added: jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/CardLayout2Ext.java Modified: jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardModel.java jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationAction.java jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationActionThread.java jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationModel.java jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardUILancher.java Log: introduce CardLayout2Ext + improve wizard framework Added: jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/CardLayout2Ext.java =================================================================== --- jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/CardLayout2Ext.java (rev 0) +++ jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/CardLayout2Ext.java 2009-03-18 08:45:58 UTC (rev 1269) @@ -0,0 +1,99 @@ +package jaxx.runtime.swing; + +import java.awt.Container; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import jaxx.runtime.JAXXObject; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Une extension de {@link CardLayout2} pour pouvoir automatiquement afficher un + * contenu à partir de la propriété {@link #selected}. + * + * Ainsi, en changeant cette propriété via la méthode {@link #setSelected(String)}, + * le contenu sera changé automatiquement, ce qui permet une utilisation direct + * dans jaxx sans à avoir à écrire d'écouteur. + * + * @author tony + * @since 1.3 + * @see CardLayout2 + */ +public class CardLayout2Ext extends CardLayout2 { + + /** log */ + static private Log log = LogFactory.getLog(CardLayout2.class); + private static final long serialVersionUID = 1L; + public static final String SELECTED_PROPERTY_NAME = "selected"; + /** + * pour propager les changements dans le modèle vers l'ui + */ + protected PropertyChangeSupport pcs; + /** + * le contenu sélectionné + */ + protected String selected; + private String containerName; + private JAXXObject ui; + private Container container; + + public CardLayout2Ext(JAXXObject ui, String containerName) { + pcs = new PropertyChangeSupport(this); + this.ui = ui; + this.containerName = containerName; + } + + public String getSelected() { + return selected; + } + + public String getPreviousSelected() { + int index = contexts.indexOf(selected); + if (index < 1) { + return null; + } + return contexts.get(index - 1) + ""; + } + + public String getNextSelected() { + int index = contexts.indexOf(selected); + if (index >= contexts.size()) { + return null; + } + return contexts.get(index + 1) + ""; + } + + public void setSelected(String selected) { + this.selected = selected; + show(getContainer(), selected); + } + + public Container getContainer() { + if (container == null) { + container = (Container) ui.getObjectById(containerName); + } + return container; + } + + public void addPropertyChangeListener(PropertyChangeListener listener) { + pcs.addPropertyChangeListener(listener); + } + + public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + pcs.removePropertyChangeListener(listener); + } + + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + pcs.removePropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListeners() { + for (PropertyChangeListener l : pcs.getPropertyChangeListeners()) { + pcs.removePropertyChangeListener(l); + } + } +} Modified: jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardModel.java =================================================================== --- jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardModel.java 2009-03-16 18:44:15 UTC (rev 1268) +++ jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardModel.java 2009-03-18 08:45:58 UTC (rev 1269) @@ -195,6 +195,17 @@ } } + public void validate() { + if (step == null) { + // pas de validation quand aucune etape n'est sélectionnée + return; + } + boolean validate = validate(step); + this.validStep = validate; + // toujours forcer la propagation + firePropertyChange(VALID_STEP_PROPERTY_NAME, null, validStep); + } + protected Class<E> getStepClass() { return stepClass; } @@ -210,17 +221,6 @@ validate(); } - protected void validate() { - if (step == null) { - // pas de validation quand aucune etape n'est sélectionnée - return; - } - boolean validate = validate(step); - this.validStep = validate; - // toujours forcer la propagation - firePropertyChange(VALID_STEP_PROPERTY_NAME, null, validStep); - } - protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { pcs.firePropertyChange(propertyName, oldValue, newValue); } Modified: jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationAction.java =================================================================== --- jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationAction.java 2009-03-16 18:44:15 UTC (rev 1268) +++ jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationAction.java 2009-03-18 08:45:58 UTC (rev 1269) @@ -34,6 +34,18 @@ return operation; } + public Exception getError() { + return error; + } + + public void setError(Exception e) { + error = e; + } + + public void sendMessage(String msg) { + firePropertyChange("message", null, msg); + } + public abstract void start(JAXXContext context); public abstract void beforeAction(JAXXContext context, M model) throws Exception; @@ -44,8 +56,6 @@ public abstract WizardOperationState onCancel(M model, Exception e); - public abstract void afterAction(M model, WizardOperationState result, Exception error); - protected abstract M getModel(); public WizardOperationState getOperationState() { Modified: jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationActionThread.java =================================================================== --- jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationActionThread.java 2009-03-16 18:44:15 UTC (rev 1268) +++ jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationActionThread.java 2009-03-18 08:45:58 UTC (rev 1269) @@ -49,44 +49,42 @@ } public void cancel() { - if (currentAction != null) { - log.debug("cancel action " + currentAction); - // on a une action en cours, on l'annule - currentAction.cancel(true); - } - // on annule aussi le modele + log.info("cancel " + this); + this.canceled = true; + + // on annule le modele getModel().cancel(); - this.canceled = true; + // on rend la main au thread setWaiting(false); } @SuppressWarnings("unchecked") - public void launchOperation(E operation) { + public A launchOperation(E operation) { - if (currentAction != null) { + if (currentAction != null && (!currentAction.isDone() || currentAction.operationState == WizardOperationState.RUNNING)) { // on ne peut traiter qu'une seule opération à la fois throw new IllegalStateException("can not add a operation when thread is busy, or has another operation to be done"); } - try { - currentAction = (A) operation.getActionClass().newInstance(); - } catch (Exception ex) { - throw new RuntimeException(ex); - } + currentAction = (A) getModel().getOperationAction(operation); + // on libere le thread pour qu'il execute l'opération setWaiting(false); + + return currentAction; } + public A getCurrentAction() { + return currentAction; + } + @Override public void propertyChange(PropertyChangeEvent evt) { log.trace(evt.getPropertyName() + " <" + evt.getOldValue() + " - " + evt.getNewValue() + ">"); if ("state".equals(evt.getPropertyName())) { - //@SuppressWarnings("unchecked") - //A action = (A) evt.getSource(); StateValue state = (StateValue) evt.getNewValue(); if (state == StateValue.DONE) { // on rend la main au thread pour qu'il attende une prochaine operation - //getModel().setOperationState(action.getOperation(), action.getOperationState()); setWaiting(false); } } @@ -137,13 +135,17 @@ // est terminée ou a été annulée, on passera alors // dans la méthode onPropertyChanged - getModel().setOperationState(currentAction.getOperationState()); + if (canceled) { + getModel().setOperationState(WizardOperationState.CANCELED); + } else { + getModel().setOperationState(currentAction.getOperationState()); + } // le thread n'écoute plus l'action car elle est terminée // ou annulée currentAction.removePropertyChangeListener(this); // suppression de l'action - currentAction = null; + //currentAction = null; } } Modified: jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationModel.java =================================================================== --- jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationModel.java 2009-03-16 18:44:15 UTC (rev 1268) +++ jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardOperationModel.java 2009-03-18 08:45:58 UTC (rev 1269) @@ -1,9 +1,12 @@ package jaxx.runtime.swing.wizard; +import java.util.Arrays; import java.util.EnumMap; import java.util.EnumSet; +import java.util.List; import java.util.Map; import java.util.Set; +import javax.swing.SwingWorker.StateValue; /** * Un modèle de wizard avec des opérations. @@ -18,11 +21,8 @@ public static final String OPERATION_STATE_PROPERTY_NAME = "operationState"; public static final String MODEL_STATE_PROPERTY_NAME = "modelState"; public static final String WAS_STARTED_PROPERTY_NAME = "wasStarted"; + /** - * le type d'une opération - */ -// protected Class<O> operationClass; - /** * La liste des opérations à effectuer */ protected Set<E> operations; @@ -30,6 +30,7 @@ * Pour conserver les états des opérations */ protected Map<E, WizardOperationState> operationStates; + protected Map<E, WizardOperationAction> operationActions; /** * L'état générale du modèle */ @@ -45,6 +46,7 @@ Class<T> k = (Class) stepClass; this.operationStates = (Map) new EnumMap(k); this.operations = (Set<E>) EnumSet.noneOf(k); + this.operationActions = (Map) new EnumMap(k); } public Set<E> getOperations() { @@ -73,6 +75,19 @@ return operationStates.get(operation); } + public WizardOperationAction getOperationAction(E operation) { + WizardOperationAction action = operationActions.get(operation); + if (action == null) { + try { + action = operation.getActionClass().newInstance(); + operationActions.put(operation, action); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + return action; + } + public void setOperationState(WizardOperationState operationState) { E operation = getOperation(); setOperationState(operation, operationState); @@ -90,7 +105,7 @@ boolean[] result = new boolean[getSteps().size()]; int index = getSteps().indexOf(getStep()); if (index != -1) { - + for (int i = 0, j = steps.size(); i < j; i++) { if (i <= index) { // tous les onglets inferieur ou egal au courant sont accessibles @@ -106,7 +121,7 @@ (!previousStep.isOperation() || getOperationState(previousStep) == WizardOperationState.SUCCESSED)); } } - System.out.println("accessibles steps -------- " + java.util.Arrays.toString(result)); + //System.out.println("accessibles steps -------- " + java.util.Arrays.toString(result)); return result; } @@ -121,12 +136,24 @@ } public void cancel() { + for (E op : operations) { if (getOperationState(op) == WizardOperationState.PENDING) { // on annule l'opération à venir setOperationState(op, WizardOperationState.CANCELED); } } + setModelState(WizardOperationState.CANCELED); + if (getStep() != null && getStep().isOperation()) { + WizardOperationAction action = getOperationAction(getStep()); + if (action != null) { + if (!action.isCancelled() && !action.isDone() && action.getState() == StateValue.STARTED) { + System.out.println("cancel action " + action); + // on annule l'action + action.cancel(true); + } + } + } } public WizardOperationModel<E> addOperation(E operation) { @@ -152,6 +179,10 @@ super.setSteps(steps); // on force la propagation de la nouvelle liste firePropertyChange(OPERATIONS_PROPERTY_NAME, null, operations); + updateOperationStates(Arrays.asList(steps)); + } + + public void updateOperationStates(List<E> steps) { int index = 0; for (E e : steps) { fireIndexedPropertyChange(OPERATION_STATE_PROPERTY_NAME, index++, null, getOperationState(e)); @@ -185,7 +216,7 @@ case CANCELED: //le modele devient annulé setModelState(WizardOperationState.CANCELED); - break; + return; case PENDING: //le modele est en attente setModelState(WizardOperationState.PENDING); @@ -210,6 +241,7 @@ } break; } + updateOperationStates(steps); } @Override Modified: jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardUILancher.java =================================================================== --- jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardUILancher.java 2009-03-16 18:44:15 UTC (rev 1268) +++ jaxx/trunk/jaxx-runtime-swing/src/main/java/jaxx/runtime/swing/wizard/WizardUILancher.java 2009-03-18 08:45:58 UTC (rev 1269) @@ -1,6 +1,7 @@ package jaxx.runtime.swing.wizard; -import javax.swing.JFrame; +import java.awt.Window; +import javax.swing.ImageIcon; import jaxx.runtime.JAXXContext; import jaxx.runtime.JAXXInitialContext; import jaxx.runtime.JAXXObject; @@ -20,85 +21,37 @@ protected UI ui; - @SuppressWarnings("unchecked") - public WizardUILancher(JAXXContext context, JFrame mainUI, Class<UI> uiClass, M model) { - super(); + public WizardUILancher(JAXXContext context, Class<UI> uiClass, Class<M> modelClass, String title, String tip, ImageIcon icon) { + this(context, uiClass, modelClass, null, title, tip, icon); + } + + public WizardUILancher(JAXXContext context, Class<UI> uiClass, Class<M> modelClass, M model, String title, String tip, ImageIcon icon) { try { - // instanciate ui parent context - JAXXInitialContext uiContext = new JAXXInitialContext(); - uiContext.add(mainUI == null ? context : mainUI); - // parent context model - uiContext.add(model); - // apply action - uiContext.add("apply", new Runnable() { - - @Override - public void run() { - doAction(ui); - } - }); - // cancel action - uiContext.add("cancel", new Runnable() { - - @Override - public void run() { - doCancel(ui); - } - }); - - // instanciate ui - ui = (UI) ConstructorUtils.invokeConstructor(uiClass, new Object[]{mainUI, uiContext}, new Class[]{JFrame.class, JAXXContext.class}); - + ui = createUI(context, uiClass, modelClass, model, title, tip, icon); } catch (Exception ex) { throw new RuntimeException("could not instanciate launcher for reason " + ex.getMessage(), ex); } } - @SuppressWarnings("unchecked") - public WizardUILancher(JAXXContext context, JFrame mainUI, Class<UI> uiClass, Class<M> modelClass) { - super(); + public WizardUILancher(JAXXContext context, Window mainUI, Class<UI> uiClass, Class<M> modelClass, M model) { try { - // instanciate ui parent context - JAXXInitialContext uiContext = new JAXXInitialContext(); - uiContext.add(mainUI == null ? context : mainUI); - // parent context model - uiContext.add(modelClass.newInstance()); - // apply action - uiContext.add("apply", new Runnable() { - - @Override - public void run() { - doAction(ui); - } - }); - // cancel action - uiContext.add("cancel", new Runnable() { - - @Override - public void run() { - doCancel(ui); - } - }); - - // instanciate ui - ui = (UI) ConstructorUtils.invokeConstructor(uiClass, new Object[]{mainUI, uiContext}, new Class[]{JFrame.class, JAXXContext.class}); - + ui = createUI(context, mainUI, uiClass, modelClass, model); } catch (Exception ex) { throw new RuntimeException("could not instanciate launcher for reason " + ex.getMessage(), ex); } } + public WizardUILancher(JAXXContext context, Window mainUI, Class<UI> uiClass, Class<M> modelClass) { + this(context, mainUI, uiClass, modelClass, null); + } + public void start() { - try { - init(ui); - ui.start(); - } finally { - dispose(); - } + init(ui); + start(ui); } - public void dispose() { - // par defaut, on ne fait rien + protected void start(UI ui) { + ui.start(); } public <T> T getContextValue(Class<T> clazz, String name) { @@ -124,4 +77,86 @@ protected void doCancel(UI ui) { } + + protected void doClose(UI ui, boolean wasCanceld) { + } + + @SuppressWarnings("unchecked") + protected UI createUI(JAXXContext context, Window mainUI, Class<UI> uiClass, Class<M> modelClass, M model) throws Exception { + JAXXInitialContext uiContext = new JAXXInitialContext(); + uiContext.add(mainUI == null ? context : mainUI); + // parent context model + uiContext.add(modelClass.newInstance()); + if (model != null) { + uiContext.add("incoming", model); + } + // apply action + uiContext.add("apply", new Runnable() { + + @Override + public void run() { + try { + doAction(ui); + } finally { + doClose(ui,false); + } + } + }); + // cancel action + uiContext.add("cancel", new Runnable() { + + @Override + public void run() { + try { + doCancel(ui); + } finally { + doClose(ui,true); + } + } + }); + + // instanciate ui + + UI newUI = (UI) ConstructorUtils.invokeConstructor(uiClass, new Object[]{mainUI, uiContext}, new Class[]{Window.class, JAXXContext.class}); + return newUI; + } + + @SuppressWarnings("unchecked") + protected UI createUI(JAXXContext context, Class<UI> uiClass, Class<M> modelClass, M model, String title, String tip, ImageIcon icon) throws Exception { + JAXXInitialContext uiContext = new JAXXInitialContext(); + uiContext.add(context); + // parent context model + uiContext.add(modelClass.newInstance()); + if (model != null) { + uiContext.add("incoming", model); + } + // apply action + uiContext.add("apply", new Runnable() { + + @Override + public void run() { + try { + doAction(ui); + } finally { + doClose(ui,false); + } + } + }); + // cancel action + uiContext.add("cancel", new Runnable() { + + @Override + public void run() { + try { + doCancel(ui); + } finally { + doClose(ui,true); + } + } + }); + + // instanciate ui + UI newUI = (UI) ConstructorUtils.invokeConstructor(uiClass, new Object[]{uiContext, title, tip, icon}, new Class[]{JAXXContext.class, String.class, String.class, ImageIcon.class}); + return newUI; + } }
participants (1)
-
tchemit@users.labs.libre-entreprise.org