001    package com.sptci.echo2demo;
002    
003    import java.beans.PropertyDescriptor;
004    import java.lang.reflect.Field;
005    import java.util.HashMap;
006    import java.util.Map;
007    
008    import nextapp.echo2.app.Alignment;
009    import nextapp.echo2.app.Button;
010    import nextapp.echo2.app.CheckBox;
011    import nextapp.echo2.app.Column;
012    import nextapp.echo2.app.Component;
013    import nextapp.echo2.app.ContentPane;
014    import nextapp.echo2.app.Extent;
015    import nextapp.echo2.app.Grid;
016    import nextapp.echo2.app.Insets;
017    import nextapp.echo2.app.Label;
018    import nextapp.echo2.app.ListBox;
019    import nextapp.echo2.app.Row;
020    import nextapp.echo2.app.SelectField;
021    import nextapp.echo2.app.TextArea;
022    import nextapp.echo2.app.TextField;
023    import nextapp.echo2.app.layout.GridLayoutData;
024    import nextapp.echo2.app.list.DefaultListModel;
025    import nextapp.echo2.app.text.TextComponent;
026    
027    import nextapp.echo2.app.event.ActionEvent;
028    import nextapp.echo2.app.event.ActionListener;
029    
030    import org.rakeshv.utils.StringUtilities;
031    import com.sptci.echo2.JDOModelUpdater;
032    import com.sptci.echo2.JDOModelPropertyChangeListener;
033    import com.sptci.echo2.ListItem;
034    import com.sptci.echo2.ViewPropertyChangeListener;
035    import com.sptci.echo2.ViewUpdater;
036    
037    /**
038     * A <code>ContentPane</code> that builds the form used to input
039     * user and job information.
040     *
041     * <p>Copyright 2006 Sans Pareil Technologies, Inc.</p>
042     * @author Rakesh Vidyadharan 2006-01-21
043     * @version $Id: InputForm.java,v 1.10 2006/02/15 16:14:57 rakesh Exp $
044     */
045    public class InputForm extends ContentPane implements ActionListener
046    {
047      /**
048       * The java bean used to store the values of the data for the
049       * UI components.
050       */
051      private InputFormModel model;
052    
053      /**
054       * The property change listener used to synchronise modifications
055       * applied to UI components to the {@link #model} java bean.
056       */
057      private JDOModelPropertyChangeListener jdoChangeListener;
058    
059      /**
060       * The property change listener used to synchronise modifications
061       * applied to the {@link #model} java bean to the UI components.
062       */
063      private ViewPropertyChangeListener uiChangeListener;
064    
065      private TextField textField;
066      private TextArea textArea;
067      private HashMap<String, CheckBox> checkBoxes;
068      private ListBox listBox;
069      private SelectField selectField;
070    
071      private Button first;
072      private Button previous;
073      private Button last;
074      private Button next;
075      private Button save;
076      private Button delete;
077      private Label index;
078    
079      /**
080       * Create a new instance of the form.
081       *
082       * @see #initForm
083       */
084      public InputForm()
085      {
086        this( new InputFormModel() );
087      }
088    
089      /**
090       * Create a new instance of the form using the specified java bean.
091       *
092       * @see #initForm
093       * @param model The java bean to use to store the values of the
094       *   UI components.
095       */
096      public InputForm( InputFormModel model )
097      {
098        this.model = model;
099        /*
100        try
101        {
102          jdoChangeListener = new JDOModelPropertyChangeListener( model );
103        }
104        catch ( java.beans.IntrospectionException iex )
105        {
106          throw new RuntimeException( iex.getMessage(), iex );
107        }
108        */
109    
110        initForm();
111    
112        //uiChangeListener = new ViewPropertyChangeListener( this );
113        //this.model.addPropertyChangeListener( uiChangeListener );
114      }
115    
116      /**
117       * Initialise the UI components for the form.
118       *
119       * @see #createTextField
120       * @see #createTextArea
121       * @see #createCheckBoxes
122       * @see #createSelectField
123       * @see #createListBox
124       * @see #createButton
125       */
126      private void initForm()
127      {
128        setStyleName( "InputForm.ContentPane" );
129        Grid grid = new Grid( 3 );
130        grid.setInsets( new Insets( 2, 2 ) );
131    
132        grid.add( createTextField( "textField" ) );
133        grid.add( createTextArea( "textArea" ) );
134    
135        grid.add( createCheckBoxes() );
136        grid.add( createSelectField() );
137        grid.add( createListBox() );
138    
139        Row row1 = new Row();
140        row1.add( createButton( "first" ) );
141        row1.add( createButton( "previous" ) );
142    
143        Row row3 = new Row();
144        row3.add( createButton( "next" ) );
145        row3.add( createButton( "last" ) );
146    
147        Row row2 = new Row();
148        row2.add( createButton( "save" ) );
149        index = new Label();
150        index.setToolTipText( "Record number" );
151        row2.add( index );
152        row2.add( createButton( "delete" ) );
153        setIndexValue( InputFormModelFactory.getInstance().lastIndex() + 1 );
154    
155        grid.add( row1 );
156        grid.add( row2 );
157        grid.add( row3 );
158    
159        add( grid );
160      }
161    
162      /**
163       * Create the label and text field necessary to display the UI
164       * components.
165       *
166       * @see #createLabel
167       * @see #setText
168       * @param name The name used to identify the text field to create.
169       *   The name must match the name of the appropriate field
170       *   without the Field suffix (eg. userName, salary, ...).  The
171       *   same name must be configured in the configuration file for
172       *   the properties and resources.
173       * @return Component The new component that contains the newly
174       *   created UI components.
175       */
176      private Component createTextField( String name )
177      {
178        Column column = new Column();
179        column.setStyleName( "InputForm.LabelFieldColumn" );
180    
181        createLabel( name, column );
182    
183        TextField textField = new TextField();
184        textField.setActionCommand( name );
185        textField.setWidth( new Extent(
186            Configuration.getInt( "InputForm." + name + ".width" ) ) );
187        textField.setToolTipText( 
188            Configuration.getString( "InputForm." + name + ".tooltip" ) );
189        textField.setStyleName( "InputForm.TextComponent" );
190        //textField.addPropertyChangeListener( jdoChangeListener );
191        //setText( textField );
192    
193        try
194        {
195          Field field = getClass().getDeclaredField( name );
196          field.set( this, textField );
197        }
198        catch ( Throwable t )
199        {
200          throw new RuntimeException( t.getMessage(), t );
201        }
202    
203        column.add( textField );
204        return column;
205      }
206    
207      /**
208       * Create a label using the specified name property and add it to the 
209       * specified component.
210       *
211       * @param name The name used to identify the label to create.  The
212       *   same name must be configured in the configuration file for
213       *   the properties and resources.
214       */
215      private Label createLabel( String name, Component component )
216      {
217        Label label = new Label( 
218            Configuration.getString( "InputForm." + name + ".label" ) );
219        label.setToolTipText( 
220            Configuration.getString( "InputForm." + name + ".tooltip" ) );
221        label.setStyleName( "InputForm.Label" );
222        component.add( label );
223    
224        return label;
225      }
226    
227      /**
228       * Set the text for the specified <code>TextComponent</code> from
229       * the value in the {@link #model} data bean through {@link
230       * #jdoChangeListener}.
231       *
232       * <p><b>Note:</b> It is mandatory that the <code>ActionCommand</code>
233       * for the <code>TextComponent</code> be set prior to invoking this
234       * method.</p>
235       *
236       * @param text The text component whose text is to be set.
237       */
238      private void setText( TextComponent text )
239      {
240        PropertyDescriptor descriptor = 
241          jdoChangeListener.getProperties().get( text.getActionCommand() );
242        if ( descriptor != null )
243        {
244          try
245          {
246            Object object = descriptor.getReadMethod().invoke( model );
247            if ( object != null )
248            {
249              text.setText( object.toString() );
250            }
251          }
252          catch ( Throwable t )
253          {
254            throw new RuntimeException( t.getMessage(), t );
255          }
256        }
257      }
258    
259      /**
260       * Create the label and text area necessary to display the UI
261       * components.
262       *
263       * @see #createLabel
264       * @see #setText
265       * @param name The name used to identify the text area to create.
266       *   The name must match the name of the appropriate area
267       *   without the Area suffix (eg. userName, salary, ...).  The
268       *   same name must be configured in the configuration file for
269       *   the properties and resources.
270       * @return Component The new component that contains the newly
271       *   created UI components.
272       */
273      private Component createTextArea( String name )
274      {
275        Column column = new Column();
276        GridLayoutData layout = new GridLayoutData();
277        layout.setColumnSpan( 2 );
278        column.setLayoutData( layout );
279        createLabel( name, column );
280    
281        TextArea textArea = new TextArea();
282        textArea.setActionCommand( name );
283        textArea.setHeight( new Extent( Configuration.getInt( 
284                "InputForm." + name + ".height" ), Extent.EM ) );
285        textArea.setWidth( new Extent(
286            Configuration.getInt( "InputForm." + name + ".width" ) ) );
287        textArea.setToolTipText( 
288            Configuration.getString( "InputForm." + name + ".tooltip" ) );
289        textArea.setStyleName( "InputForm.TextComponent" );
290        //textArea.addPropertyChangeListener( jdoChangeListener );
291        //setText( textArea );
292    
293        try
294        {
295          Field field = getClass().getDeclaredField( name );
296          field.set( this, textArea );
297        }
298        catch ( Throwable t )
299        {
300          throw new RuntimeException( t.getMessage(), t );
301        }
302    
303        column.add( textArea );
304        return column;
305      }
306    
307      /**
308       * Create the column necessary to display the check boxes and also
309       * create the required check boxes.
310       */
311      private Component createCheckBoxes()
312      {
313        checkBoxes = new HashMap<String, CheckBox>();
314        Column column = new Column();
315    
316        for ( Map.Entry<String, Boolean> entry : model.getCheckBoxes().entrySet() )
317        {
318          CheckBox checkBox = new CheckBox( entry.getKey() );
319          checkBox.setActionCommand( "checkBoxes>" + entry.getKey() );
320          checkBox.setStyleName( "InputForm.TextComponent" );
321          checkBox.setSelected( entry.getValue() );
322          //checkBox.addPropertyChangeListener( jdoChangeListener );
323          column.add( checkBox );
324    
325          checkBoxes.put( checkBox.getActionCommand(), checkBox );
326        }
327    
328        return column;
329      }
330    
331      /**
332       * Create the select field component.
333       */
334      private Component createSelectField()
335      {
336        selectField = new SelectField();
337    
338        DefaultListModel listModel = new DefaultListModel();
339        int count = 0;
340        for ( ListItem item : model.getSelectField() )
341        {
342          listModel.add( count++, item.getValue() );
343          if ( item.isSelected() )
344          {
345            selectField.setSelectedIndex( count );
346          }
347        }
348        selectField.setModel( listModel );
349        selectField.setSelectedIndex( 0 );
350    
351        selectField.setActionCommand( "selectField" );
352        //selectField.addPropertyChangeListener( jdoChangeListener );
353        return selectField;
354      }
355    
356      /**
357       * Create the list box component.
358       */
359      private Component createListBox()
360      {
361        listBox = new ListBox();
362    
363        DefaultListModel listModel = new DefaultListModel();
364        int count = 0;
365        for ( ListItem item : model.getListBox() )
366        {
367          listModel.add( count++, item.getValue() );
368        }
369        listBox.setModel( listModel );
370    
371        listBox.setActionCommand( "listBox" );
372        //listBox.addPropertyChangeListener( jdoChangeListener );
373        return listBox;
374      }
375    
376      /**
377       * Create the button identified by the specified name.
378       * 
379       * @param name The name used to identify the button to create.
380       *   The name must match the name of the appropriate button.  The
381       *   same name must be configured in the configuration file for
382       *   the properties and resources.
383       * @return Component The new component that contains the newly
384       *   created UI components.
385       */
386      private Button createButton( String name )
387      {
388        Button button = new Button( Configuration.getString( 
389              "InputForm." + name + ".text" ) );
390        button.setStyleName( "InputForm.Button" );
391        button.setToolTipText( Configuration.getString( 
392              "InputForm." + name + ".tooltip" ) );
393        button.setActionCommand( name );
394        button.addActionListener( this );
395    
396        try
397        {
398          Field field = getClass().getDeclaredField( name );
399          field.set( this, button );
400        }
401        catch ( Throwable t )
402        {
403          throw new RuntimeException( t.getMessage(), t );
404        }
405    
406        return button;
407      }
408    
409      /**
410       * Set the text of the {@link #index} label.  Enable or disable
411       * the navigation buttons depending upon the values.
412       *
413       * @param index The index value to set.
414       */
415      private void setIndexValue( int index )
416      {
417        first.setEnabled( true );
418        previous.setEnabled( true );
419        next.setEnabled( true );
420        last.setEnabled( true );
421        delete.setEnabled( true );
422    
423        if ( index == 0 )
424        {
425          first.setEnabled( false );
426          previous.setEnabled( false );
427        }
428        if ( index >= InputFormModelFactory.getInstance().lastIndex() )
429        {
430          last.setEnabled( false );
431        }
432        if ( index > InputFormModelFactory.getInstance().lastIndex() )
433        {
434          next.setEnabled( false );
435          delete.setEnabled( false );
436        }
437    
438        this.index.setText( String.valueOf( index ) );
439      }
440      
441      /**
442       * Returns {@link #model}.
443       *
444       * @return InputFormModel The value/reference of/to model.
445       */
446      public final InputFormModel getFormData()
447      {
448        return model;
449      }
450      
451      /**
452       * Set {@link #model}.
453       *
454       * @param model The value to set.
455       */
456      final void setModel( InputFormModel model )
457      {
458        //this.model.removePropertyChangeListener( uiChangeListener );
459        this.model = model;
460        //this.model.addPropertyChangeListener( uiChangeListener );
461        /*
462        try
463        {
464          jdoChangeListener.setBean( model );
465        }
466        catch ( Throwable t )
467        {
468          throw new RuntimeException( t.getMessage(), t );
469        }
470        */
471    
472        ( new ViewUpdater( this, model ) ).update();
473      }
474      
475      /**
476       * Returns {@link #jdoChangeListener}.
477       *
478       * @return JDOModelPropertyChangeListener The value/reference of/to 
479       *   jdoChangeListener.
480       */
481      public final JDOModelPropertyChangeListener getDataChangeListener()
482      {
483        return jdoChangeListener;
484      }
485    
486      /**
487       * ActionListener implementation.  Actions are triggered when a
488       * button is pressed.
489       *
490       * @param event The event that contains the information
491       *   pertaining to the action.
492       */
493      public void actionPerformed( ActionEvent event )
494      {
495        if ( event.getActionCommand().equals( "save" ) )
496        {
497          doSave();
498        }
499        else if ( event.getActionCommand().equals( "delete" ) )
500        {
501          doDelete();
502        }
503        else if ( event.getActionCommand().equals( "first" ) )
504        {
505          doNavigate( 0 );
506        }
507        else if ( event.getActionCommand().equals( "previous" ) )
508        {
509          doNavigate( Integer.parseInt( index.getText() ) - 1 );
510        }
511        else if ( event.getActionCommand().equals( "next" ) )
512        {
513          doNavigate( Integer.parseInt( index.getText() ) + 1 );
514        }
515        else if ( event.getActionCommand().equals( "last" ) )
516        {
517          doNavigate( InputFormModelFactory.getInstance().lastIndex() );
518        }
519      }
520    
521      /**
522       * The action for the {@link #save} button.
523       */
524      private void doSave()
525      {
526        save.setEnabled( false );
527        save.setText( Configuration.getString( "InputForm.save.working" ) );
528        InputFormModelFactory factory =
529          InputFormModelFactory.getInstance();
530    
531        try
532        {
533          ( new JDOModelUpdater( this, model ) ).update();
534          factory.save( model );
535          setModel( new InputFormModel() );
536          setIndexValue( factory.lastIndex() + 1 );
537        }
538        catch ( Throwable t )
539        {
540          ErrorPane pane = new ErrorPane( 
541              t.getMessage(), StringUtilities.stackTrace( t ) );
542          add( pane );
543        }
544    
545        save.setEnabled( true );
546        save.setText( Configuration.getString( "InputForm.save.text" ) );
547      }
548    
549      /**
550       * The action for the {@link #delete} button.
551       */
552      private void doDelete()
553      {
554        delete.setEnabled( false );
555        delete.setText( Configuration.getString( "InputForm.delete.working" ) );
556        InputFormModelFactory factory =
557          InputFormModelFactory.getInstance();
558    
559        try
560        {
561          factory.delete( model );
562          setModel( new InputFormModel() );
563          setIndexValue( factory.lastIndex() + 1 );
564        }
565        catch ( Throwable t )
566        {
567          ErrorPane pane = new ErrorPane( 
568              t.getMessage(), StringUtilities.stackTrace( t ) );
569          add( pane );
570        }
571    
572        delete.setEnabled( true );
573        delete.setText( Configuration.getString( "InputForm.delete.text" ) );
574      }
575    
576      /**
577       * The action for the navigation buttons.
578       *
579       * @param index The index in a List of {@link InputFormModel} objects at
580       *   which the object is to be retrieved.
581       */
582      private void doNavigate( int index )
583      {
584        InputFormModel data = 
585          InputFormModelFactory.getInstance().fetchByIndex( index );
586        if ( data == null )
587        {
588          data = new InputFormModel();
589        }
590    
591        setModel( data );
592        setIndexValue( index );
593      }
594    }