001    package com.sptci.echo2;
002    
003    import java.io.Serializable;
004    
005    import java.lang.reflect.InvocationTargetException;
006    import java.lang.reflect.Method;
007    
008    import java.util.ArrayList;
009    import java.util.List;
010    import java.util.Map;
011    import java.util.logging.Logger;
012    
013    import nextapp.echo2.app.ListBox;
014    import nextapp.echo2.app.SelectField;
015    import nextapp.echo2.app.button.ToggleButton;
016    import nextapp.echo2.app.list.DefaultListModel;
017    
018    import com.sptci.ReflectionUtility;
019    
020    /**
021     * An <code>updater</code> used to update UI containers with data from
022     * JavaBean objects.
023     *
024     * <p>Copyright 2006 Sans Pareil Technologies, Inc.</p>
025     * @author Rakesh Vidyadharan 2006-02-07
026     * @version $Id: ViewUpdater.java,v 1.3 2006/02/15 00:48:26 rakesh Exp $
027     */
028    public class ViewUpdater extends Updater implements Serializable
029    {
030      /**
031       * The logger used to log errors/warnings to.
032       */
033      private static transient final Logger logger =
034        Logger.getLogger( "com.sptci.echo2.ViewUpdater" );
035    
036      /**
037       * Create a new instance with the specified UI container and java 
038       * bean.
039       *
040       * @param uiContainer The {@link #uiContainer} to use.
041       * @param bean The {@link #bean} to use.
042       */
043      public ViewUpdater( Object uiContainer, Object bean )
044      {
045        super( uiContainer, bean );
046      }
047    
048      /**
049       * Update the fields of the {@link #uiContainer} with the data in
050       * similarly named fields in {@link #bean}.
051       *
052       * @see ReflectionUtility#fetchField
053       * @see #updateComponent
054       * @throws BindingException If errors are encountered while
055       *   accessing or setting the fields.
056       */
057      public void update()
058      {
059        try
060        {
061          for ( Map.Entry<String, Object> entry : beanValues().entrySet() )
062          {
063            Object object = 
064              ReflectionUtility.fetchObject( entry.getKey(), uiContainer );
065            updateComponent( object, entry.getValue() );
066          }
067        }
068        catch ( Throwable t )
069        {
070          throw new BindingException( t );
071        }
072      }
073    
074      /**
075       * Update the value of the specified code using the specified
076       * value.
077       *
078       * @see #processMap
079       * @see #updateSelectField
080       * @param object The UI component that is to be updated.
081       * @param value The value with which to update the object.
082       * @throws IllegalAccessException If a custom security policy
083       *   restricts access to the bean fields.
084       * @throws InvocationTargetException If the accessor method for
085       *   the field could not be invoked successfully.
086       */
087      protected void updateComponent( Object object, Object value )
088        throws IllegalAccessException, InvocationTargetException
089      {
090        if ( object instanceof  nextapp.echo2.app.text.TextComponent )
091        {
092          Method method = ReflectionUtility.fetchMethod( object, 
093              "setText", new Class[] { java.lang.String.class } );
094          method.invoke( object, value );
095        }
096        else if ( object instanceof  java.util.Map )
097        {
098          processMap( (Map<String, ToggleButton>) object, 
099              (Map<String, Boolean>) value );
100        }
101        else if ( object instanceof nextapp.echo2.app.SelectField )
102        {
103          updateSelectField( (SelectField) object, (List<ListItem>) value );
104        }
105        else if ( object instanceof nextapp.echo2.app.ListBox )
106        {
107          updateListBox( (ListBox) object, (List<ListItem>) value );
108        }
109      }
110    
111      /**
112       * Update <code>ToggleButton</code> UI components.
113       *
114       * @param ui The map that contains the name and selected state
115       *   of the toggle button.
116       * @param value The new mappings to apply to the UI component.
117       */
118      protected void processMap( Map<String, ToggleButton> ui, 
119          Map<String, Boolean> value )
120      {
121        for ( Map.Entry<String, ToggleButton> entry : ui.entrySet() )
122        {
123          String key = entry.getKey();
124    
125          if ( key != null && key.indexOf( ">" ) != -1 )
126          {
127            key = key.substring( key.indexOf( ">" ) + 1 );
128          }
129          
130          if ( value.containsKey( key ) )
131          {
132            entry.getValue().setSelected( 
133                ( (Boolean) value.get( key ) ).booleanValue() );
134          }
135          else 
136          { 
137            logger.info( "No key " + key + " found in map" );
138          }
139        }
140      }
141    
142      /**
143       * Update a <code>SelectField</code> UI component.
144       *
145       * @param selectField The UI component that is to be updated.
146       * @param list The updated list data to apply to the UI component.
147       */
148      protected void updateSelectField( SelectField selectField,
149          List<ListItem> list )
150      {
151        DefaultListModel model = new DefaultListModel();
152        selectField.setSelectedIndex( 0 );
153        int count = 0;
154        for ( ListItem item : list )
155        {
156          model.add( count, item.getValue() );
157          if ( item.isSelected() )
158          {
159            selectField.setSelectedIndex( count );
160          }
161    
162          ++count;
163        }
164    
165        selectField.setModel( model );
166      }
167    
168      /**
169       * Update a <code>ListBox</code> UI component.
170       *
171       * @param listBox The ListBox UI component that is to be updated.
172       * @param list The updated list data to apply to the UI component.
173       */
174      protected void updateListBox( ListBox listBox, 
175          List<ListItem> list )
176      {
177        DefaultListModel model = new DefaultListModel();
178        int count = 0;
179        ArrayList<Integer> indices = new ArrayList<Integer>();
180    
181        for ( ListItem item : list )
182        {
183          model.add( count, item.getValue() );
184          if ( item.isSelected() )
185          {
186            indices.add( count );
187          }
188          ++count;
189        }
190    
191        listBox.setModel( model );
192    
193        int[] selectedIndices = new int[ indices.size() ];
194        count = 0;
195        for ( int i : indices )
196        {
197          selectedIndices[ count++ ] = i;
198        }
199    
200        listBox.setSelectedIndices( selectedIndices );
201      }
202    }