create a tableview for entities

list view

Strictly speaking, the list view is not just a view, but a view controller, but we don't want to be ultramontane - after all, the "big" user actions stay in the controller (our application class). Our list view will be derived from AbstractTableView:

public class AddressTableView extends AbstractTableView<Addresses> {
    protected static final String    PREFIX = AddressesTableView.class.getSimpleName();
    protected static RendererFactory rf;

    public AddressTableView(List<Addresses> list,
                            int selectionMode,
                            List<Addresses> initialSelection) {
        super(list, selectionMode, initialSelection);
        setTableFormat(new AddressTableFormat());
        setSelectionMode(selectionMode);
    }
    
    @Override
    protected JComponent buildPanel() {
        return createTable();
    }
} 

Simple list views might return createTable from buildPanel.

If you're looking for higher sofisticated samples, take a look at the project VdrAssistant - the mother of SRJRCFrames. There you'll find more list views and complex filtered lists (i.e. EpgManager).

Format

As indicated by the constructor above, even a simple list view needs a TableFormat. That class is used to customize the columns of the table, that displays the list data. Extended list views might use filters and much more. We come back to this point later. Such a format class could look like:

protected class AddressTableFormat extends AbstractTableFormat {
     private final String[] columnNames  = { "type", "city", "street",
                                             "zip", "state", "country" };
     private final int[]    width        = { 20, 200, 200, 90, 150, 150 };

     public AddressTableFormat() {
         super(PREFIX);
     }

     @Override
     protected String[] getColumnNames() {
         return columnNames;
     }

     @Override
     protected int getColumnWidth(int idx) {
         if (idx < width.length) return width[idx];
         return 0;
     }

     @Override
     protected int getMaxColWidth(int idx) {
         if (idx < width.length) return width[idx];
         return 0;
     }

     @Override
     protected void setColumnRenderer(TableColumn tc, int colIndex) {
        if (colIndex == 0)
           tc.setCellRenderer(rf.getEnumRenderer(JLabel.RIGHT));
     }

     @Override
     protected void setTypeRenderers(JTable table) {
         // ask for factory service here
         rf = (RendererFactory) 
              ApplicationServiceProvider.getService(RendererFactory.class);
     }

     @Override
     public Object getColumnValue(Addresses instance, int idx) {
        switch (idx) {
        case 0: return instance.getType();
        case 1: return instance.getCity();
        case 2: return instance.getStreet();
        case 3: return instance.getZip();
        case 4: return instance.getState();
        case 5: return instance.getCountry();        
        }
        return null;
     }
} 
Constructor
the constructor needs to establish a name, which will be used i.e. to localize column headers.
getColumnNames
returns all column headings. These values, together with the name from the constructor, form the key for the localized messages.
getColumnWidth
returns the width for certain column. The with is the preferred width, which need not match and which can be changed at runtime.
getMaxColWidth
returns the maximum width for certain column. The value may be the same, as above, but sometimes you'll might need a different one
getMinColWidth (optional)
returns the minimum widht for certain column (default is 0)
setColumnRenderer
use this call to establish your own renderer, if you don't like the way, the default renderer displays the data. SRJRCFrames provides a factory with several renderers.
setTypeRenderers
will be called before the table is created, so it can be used for other initializations too.

Filter

Filters are used to reduce the number of displayed list entries, without database access. Glazedlists provides this functionality out of the box so the effort of high sofisticated list views is negligible.

A filter consists of an form component, where the user may change the filtercriteria (of cause, we will use JGoodies for that). Then you'll need a class, that performs the list filtering and last not least, your filter needs to get registered.

Let's start with the form component:

public class AddressesFilter implements ListFilterComponent<Addresses> {
   private JTextField                            filter;
   private TextComponentMatcherEditor<Addresses> me;


   public RecordingFilter() {
      filter = new JTextField(20);
      me     = new TextComponentMatcherEditor<Addresses>(
                              filter, new AddressesFilterator());
   }


   public JComponent getFilterPane() {
      FormLayout layout = new FormLayout("right:max(25dlu;pref), 3dlu, default:grow");
      DefaultFormBuilder builder = new DefaultFormBuilder(layout);
      MessageSource msgSource = (MessageSource) 
                                ApplicationServiceProvider.getService(MessageSource.class);

      builder.setDefaultDialogBorder();
      builder.append(msgSource.getMessage(PREFIX + "filter", 
                                          null, 
                                          PREFIX + "filter", 
                                          null),
                     filter,
                     true);

      return builder.getPanel();
   }


   public MatcherEditor<Addresses> getMatcherEditor() {
      return me;
   }
} 

Next we'll add a class, that does the list filtering. Using the Superclass TextFilterator you'll only have to add the properties, that should get evaluated:

protected class AddressesFilterator implements TextFilterator<Addresses> {
   public void getFilterStrings(List baseList, Addresses instance) {
      baseList.add(item.getCity());
      baseList.add(item.getStreet());
      baseList.add(item.getState());
      baseList.add(item.getCountry());
   }
} 

Finally we have to register our filter at the views constructor and extend the pane, that shows up the list:

public class AddressTableView extends AbstractTableView<Addresses> {
    protected static final String    PREFIX = AddressesTableView.class.getSimpleName();
    protected static RendererFactory rf;
    private AddressesFilter          filter;

    public AddressTableView(List list,
                            int selectionMode,
                            List initialSelection) {
        super(list, selectionMode, initialSelection);
        setTableFormat(new AddressTableFormat());
        setSelectionMode(selectionMode);
        filter = new AddressesFilter();
        addFilter(filter);
    }
    
    @Override
    protected JComponent buildPanel() {
       JPanel rv = new JPanel();

       rv.setLayout(new BorderLayout());
       rv.add(filter.getFilterPane(), BorderLayout.NORTH);
       rv.add(createTable(), BorderLayout.CENTER);

       return rv;
    }
} 

Summary

Once again the complete list view class:

public class AddressTableView extends AbstractTableView<Addresses> {
   public class AddressesFilter implements ListFilterComponent<Addresses> {
      private JTextField                            filter;
      private TextComponentMatcherEditor<Addresses> me;


      public RecordingFilter() {
         filter = new JTextField(20);
         me     = new TextComponentMatcherEditor<Addresses>(
                                 filter, new AddressesFilterator());
      }


      public JComponent getFilterPane() {
         FormLayout layout = new FormLayout("right:max(25dlu;pref), 3dlu, default:grow");
         DefaultFormBuilder builder = new DefaultFormBuilder(layout);
         MessageSource msgSource = (MessageSource) 
                                   ApplicationServiceProvider.getService(MessageSource.class);

         builder.setDefaultDialogBorder();
         builder.append(msgSource.getMessage(PREFIX + "filter", 
                                             null, 
                                             PREFIX + "filter", 
                                             null),
                        filter,
                        true);

         return builder.getPanel();
      }


      public MatcherEditor<Addresses> getMatcherEditor() {
         return me;
      }
   }
   protected class AddressesFilterator implements TextFilterator<Addresses> {
      public void getFilterStrings(List baseList, Addresses instance) {
         baseList.add(item.getCity());
         baseList.add(item.getStreet());
         baseList.add(item.getState());
         baseList.add(item.getCountry());
      }
   }
   protected class AddressTableFormat extends AbstractTableFormat {
       private final String[] columnNames  = { "type", "city", "street",
                                               "zip", "state", "country" };
       private final int[]    width        = { 20, 200, 200, 90, 150, 150 };

       public AddressTableFormat() {
           super(PREFIX);
       }

       @Override
       protected String[] getColumnNames() {
           return columnNames;
       }

       @Override
       protected int getColumnWidth(int idx) {
           if (idx < width.length) return width[idx];
           return 0;
       }

       @Override
       protected int getMaxColWidth(int idx) {
           if (idx < width.length) return width[idx];
           return 0;
       }

       @Override
       protected void setColumnRenderer(TableColumn tc, int colIndex) {
          if (colIndex == 0)
             tc.setCellRenderer(rf.getEnumRenderer(JLabel.RIGHT));
       }

       @Override
       protected void setTypeRenderers(JTable table) {
           // ask for factory service here
           rf = (RendererFactory) 
                ApplicationServiceProvider.getService(RendererFactory.class);
       }

       @Override
       public Object getColumnValue(Addresses instance, int idx) {
          switch (idx) {
          case 0: return instance.getType();
          case 1: return instance.getCity();
          case 2: return instance.getStreet();
          case 3: return instance.getZip();
          case 4: return instance.getState();
          case 5: return instance.getCountry();        
          }
          return null;
       }
   }
   protected static final String    PREFIX = AddressesTableView.class.getSimpleName();
   protected static RendererFactory rf;
   private AddressesFilter          filter;

   public AddressTableView(List<Addresses> list,
                           int selectionMode,
                           List<Addresses> initialSelection) {
      super(list, selectionMode, initialSelection);
      setTableFormat(new AddressTableFormat());
      setSelectionMode(selectionMode);
      filter = new AddressesFilter();
      addFilter(filter);
   }
    
   @Override
   protected JComponent buildPanel() {
      JPanel rv = new JPanel();

      rv.setLayout(new BorderLayout());
      rv.add(filter.getFilterPane(), BorderLayout.NORTH);
      rv.add(createTable(), BorderLayout.CENTER);

      return rv;
   }
}