Package org.beryl.gui.widgets

Source Code of org.beryl.gui.widgets.Table$CustomCellEditor

/*
* Beryl - A web platform based on XML, XSLT and Java
* This file is part of the Beryl XML GUI
*
* Copyright (C) 2004 Wenzel Jakob <wazlaf@tigris.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.

* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-3107  USA
*/

package org.beryl.gui.widgets;

import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;

import javax.swing.AbstractCellEditor;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;

import org.beryl.gui.GUIEvent;
import org.beryl.gui.GUIEventListener;
import org.beryl.gui.GUIException;
import org.beryl.gui.Widget;
import org.beryl.gui.WidgetInfo;
import org.beryl.gui.model.MapChangeEvent;
import org.beryl.gui.model.MapDataModel;
import org.beryl.gui.model.ModelChangeEvent;
import org.beryl.gui.model.ModelChangeListener;
import org.beryl.gui.model.TableChangeEvent;
import org.beryl.gui.model.TableDataModel;
import org.beryl.gui.model.TableRow;
import org.beryl.gui.table.TableSorter;

public class Table extends Widget {
  protected static WidgetInfo tableInfo = null;
  private JTable table = null;
  private JScrollPane scrollPane = null;
  private TableSorter sorter = null;
  private TableModel messageModel = null;
  private TableDataModel tableDataModel = null;
  private boolean sendEvents = true;
  private boolean processEvents = true;
  private ArrayList columnKeys = null;
  private ArrayList columnLabels = null;
  private ArrayList columnSizes = null;
  private Class[] columnClasses = null;
  private String indexKey = null;
  private String valueKey = null;
  private String message = null;
  private JTableHeader tableHeader = null;

  static {
    tableInfo = new WidgetInfo(Table.class, widgetInfo);
    tableInfo.addProperty("indexkey", "string", "");
    tableInfo.addProperty("valuekey", "string", "");
    tableInfo.addProperty("verticalScrollBar", "bool", Boolean.FALSE);
    tableInfo.addProperty("horizontalScrollBar", "bool", Boolean.FALSE);
    tableInfo.addProperty("selectionMode", "enum", "multiple_interval");
    tableInfo.addEvent("rightclick");
    tableInfo.addEvent("doubleclick");
  };

  /**
   * Custom table model to display information messages
   */
  private class MessageModel extends AbstractTableModel {
    public int getColumnCount() {
      return 1;
    }

    public int getRowCount() {
      return 1;
    }

    public String getColumnName(int column) {
      return "";
    }

    public Object getValueAt(int rowIndex, int columnIndex) {
      return message;
    }
  };

  /**
   * The custom cell editor lets you add your own widgets as renderer
   * components of a <tt>Table</tt>.
   */

  private class CustomCellRenderer implements TableCellRenderer {
    private Widget widget = null;

    public CustomCellRenderer(Widget widget) {
      this.widget = widget;
    }

    public Component getTableCellRendererComponent(
      JTable table,
      Object value,
      boolean isSelected,
      boolean hasFocus,
      int row,
      int column) {
      try {
        if (table.isRowSelected(row))
          widget.setProperty("background", table.getSelectionBackground());
        else
          widget.setProperty("background", table.getBackground());
      } catch (GUIException e) {
        throw new RuntimeException(e);
      }
      return widget.getRealWidget();
    }
  }

  /**
   * The custom cell editor lets you add your own widgets as editor
   * components of a <tt>Table</tt>.
   * The Table's data model must contain a key called "value" from which
   * the edited value will be extracted
   */

  private class CustomCellEditor extends AbstractCellEditor implements TableCellEditor {
    private Widget widget = null;

    private CustomCellEditor(Widget widget) {
      this.widget = widget;
    }

    public Component getTableCellEditorComponent(
      JTable table,
      Object value,
      boolean isSelected,
      int row,
      int column) {
      try {
        widget.setProperty("background", table.getSelectionBackground());
      } catch (GUIException e) {
        throw new RuntimeException(e);
      }
      return widget.getRealWidget();
    }

    public Object getCellEditorValue() {
      return widget.getDataModel().getValue("value");
    }
  };

  private class TableDataModelAdapter implements TableModel, ModelChangeListener {
    private TableDataModel model = null;
    private ArrayList listeners = null;

    public TableDataModelAdapter(TableDataModel model) {
      this.model = model;
      model.addModelChangeListener(this);
      listeners = new ArrayList();
    }

    public int getColumnCount() {
      return columnKeys.size();
    }

    public int getRowCount() {
      return model.getRowCount();
    }

    public Object getValueAt(int row, int column) {
      return model.getValue(row, (String) columnKeys.get(column));
    }

    public void setValueAt(Object value, int row, int column) {
      try {
        model.setValue(row, (String) columnKeys.get(column), value);
      } catch (GUIException e) {
        throw new RuntimeException(e);
      }
    }

    public boolean isCellEditable(int row, int column) {
      return model.isEditable(row, (String) columnKeys.get(column));
    }

    public Class getColumnClass(int column) {
      if (columnClasses != null)
        return columnClasses[column];
      return Object.class;
    }

    public String getColumnName(int column) {
      return (String) columnLabels.get(column);
    }

    public void addTableModelListener(TableModelListener listener) {
      listeners.add(listener);
    }

    public void removeTableModelListener(TableModelListener listener) {
      listeners.remove(listener);
    }

    public void modelChanged(ModelChangeEvent e) {
      if (message == null) {
        TableChangeEvent tce = (TableChangeEvent) e;

        TableModelEvent event =
          new TableModelEvent(
            this,
            tce.getFirstIndex(),
            tce.getLastIndex(),
            columnKeys.indexOf(tce.getKey()),
            tce.getType());

        try {
          sendEvents = false;
          processEvents = false;

          for (int i = 0; i < listeners.size(); i++) {
            ((TableModelListener) listeners.get(i)).tableChanged(event);
          }
          synchronizeDataModel();
        } catch (GUIException ex) {
          throw new RuntimeException(ex);
        } finally {
          sendEvents = true;
          processEvents = true;
        }

        table.repaint();
      }
    }
  }

  public Table(Widget parent, String name) throws GUIException {
    super(parent, name);

    table = new JTable() {
      /**
       * Swing bugfix: Allow different renderers/editor for each column,
       * removes the limitation of 1 renderer/editor per column
       */
      public TableCellRenderer getCellRenderer(int row, int column) {
        if (message == null) {
          int sortedRow = sorter.getSortedRowForRow(row);
          try {
            TableRow tableRow = tableDataModel.getTableRow(sortedRow);
            String key = (String) columnKeys.get(column);
            if (tableRow.hasCustomRenderer(key)) {
              Widget renderer =
                tableRow.getRenderer(
                  Table.this,
                  getValueAt(row, column),
                  isCellSelected(row, column),
                  hasFocus(),
                  tableRow,
                  key);

              if (renderer != null) {
                return new CustomCellRenderer(renderer);
              }
            }
          } catch (GUIException e) {
            /* There should be no exception here */
            throw new RuntimeException(e);
          }

          if (tableDataModel != null) {
            Object object = tableDataModel.getValue(sortedRow, (String) columnKeys.get(column));
            if (object != null) {
              return getDefaultRenderer(object.getClass());
            }
          }
        }

        /* Fall back to the JTable internal processing */
        return super.getCellRenderer(row, column);
      }

      public TableCellEditor getCellEditor(int row, int column) {
        if (message == null) {
          int sortedRow = sorter.getSortedRowForRow(row);

          try {
            TableRow tableRow = tableDataModel.getTableRow(sortedRow);
            String key = (String) columnKeys.get(column);

            Widget editor =
              tableRow.getEditor(
                Table.this,
                getValueAt(row, column),
                tableDataModel.getTableRow(sortedRow),
                key);

            if (editor != null) {
              return new CustomCellEditor(editor);
            }
          } catch (GUIException e) {
            /* There should be no exception here */
            throw new RuntimeException(e);
          }

          if (tableDataModel != null) {
            Object object = tableDataModel.getValue(sortedRow, (String) columnKeys.get(column));
            if (object != null) {
              return getDefaultEditor(object.getClass());
            }
          }
        }
        /* Fall back to the JTable internal processing */
        return super.getCellEditor(row, column);
      }
    };

    tableHeader = table.getTableHeader();
    sorter = new TableSorter();
    sorter.addMouseListenerToHeaderInTable(table);
    messageModel = new MessageModel();
    scrollPane = new JScrollPane(table);
    columnKeys = new ArrayList();
    columnLabels = new ArrayList();
    columnSizes = new ArrayList();

    table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
      public void valueChanged(ListSelectionEvent e) {
        try {
          if (sendEvents && !e.getValueIsAdjusting()) {
            synchronizeDataModel();
          }
        } catch (GUIException ex) {
          throw new RuntimeException(ex);
        }
      }
    });
    table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    table.setRowSelectionAllowed(true);
    table.setColumnSelectionAllowed(false);
  }

  /**
   * This lets you hide the current table and display a message instead.
   * A call with a null message makes the table visible again. Use this
   * method to indicate for example that there were "No Results" for
   * a database query
   */

  public void setMessage(String message) {
    this.message = message;

    if (message == null) {
      table.setTableHeader(tableHeader);
      table.setModel(sorter);
    } else if (message != null) {
      table.setTableHeader(null);
      table.setModel(messageModel);
    }
  }

  public void setColumnClasses(Class columnClasses[]) {
    this.columnClasses = columnClasses;
  }

  private void synchronizeDataModel() throws GUIException {
    MapDataModel model = getDataModel();
    if (model == null)
      return;

    if (indexKey != null) {
      int indices[] = table.getSelectedRows();
      for (int i = 0; i < indices.length; i++) {
        indices[i] = sorter.getRowForSortedRow(indices[i]);
      }
      model.setValue(Table.this, indexKey, indices);
    }

    if (valueKey != null) {
      int indices[] = table.getSelectedRows();
      TableRow rows[] = new TableRow[indices.length];
      for (int i = 0; i < indices.length; i++) {
        rows[i] = tableDataModel.getTableRow(sorter.getRowForSortedRow(indices[i]));
      }
      model.setValue(Table.this, valueKey, rows);
    }
  }

  public void setTableDataModel(TableDataModel tableDataModel) throws GUIException {
    ModelChangeEvent event = new ModelChangeEvent(this, tableDataModel);
    this.tableDataModel = tableDataModel;
    try {
      sendEvents = false;
      table.editingStopped(null); /* This is necessary to ensure the changes won't be discarded */
      TableDataModelAdapter adapter = new TableDataModelAdapter(tableDataModel);
      sorter.setModel(adapter);
      table.setModel(sorter);
    } finally {
      sendEvents = true;
    }
    /* Reload data model information */
    modelChanged(event);

    for (int i = 0; i < columnSizes.size(); i++) {
      Integer size = (Integer) columnSizes.get(i);
      if (size != null) {
        table.getColumnModel().getColumn(i).setPreferredWidth(size.intValue());
      }
    }
  }

  public TableDataModel getTableDataModel() {
    return this.tableDataModel;
  }

  public void setProperty(String name, Object value) throws GUIException {
    if (name.startsWith("column.")) {
      String key = name.substring(7, name.length());
      if (columnKeys.contains(key)) {
        columnLabels.set(columnKeys.indexOf(key), (String) value);
      } else {
        columnKeys.add(key);
        columnLabels.add((String) value);
        columnSizes.add(null);
      }
    } else if (name.startsWith("columnsize.")) {
      int column = columnKeys.indexOf(name.substring(11, name.length()));
      if (column != -1) {
        columnSizes.set(column, value);
      } else {
        throw new GUIException("Invalid column name while trying to set column size");
      }
    } else if ("verticalScrollBar".equals(name)) {
      scrollPane.setVerticalScrollBarPolicy(
        ((Boolean) value).booleanValue()
          ? JScrollPane.VERTICAL_SCROLLBAR_ALWAYS
          : JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
    } else if ("horizontalScrollBar".equals(name)) {
      scrollPane.setHorizontalScrollBarPolicy(
        ((Boolean) value).booleanValue()
          ? JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS
          : JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    } else if ("indexkey".equals(name)) {
      indexKey = (String) value;
    } else if ("valuekey".equals(name)) {
      valueKey = (String) value;
    } else {
      super.setProperty(name, value);
    }
  }

  private void setSelectionValues(TableRow[] values) {
    ListSelectionModel model = table.getSelectionModel();
    if (values == null) {
      table.clearSelection();
    } else {
      table.clearSelection();
      for (int i = 0; i < values.length; i++) {
        int index = sorter.getSortedRowForRow(tableDataModel.indexOf(values[i]));
        table.addRowSelectionInterval(index, index);
      }
    }
  }

  private void setSelectionIndices(int[] indices) {
    ListSelectionModel model = table.getSelectionModel();
    if (indices == null) {
      table.clearSelection();
    } else {
      table.clearSelection();
      for (int i = 0; i < indices.length; i++) {
        int index = sorter.getSortedRowForRow(indices[i]);
        table.addRowSelectionInterval(index, index);
      }
    }
  }

  public void reload() throws GUIException {
    MapDataModel model = getDataModel();
    if (model != null) {
      try {
        processEvents = false;

        int[] indices = indexKey == null ? null : (int[]) model.getValue(indexKey);
        TableRow values[] = valueKey == null ? null : (TableRow[]) model.getValue(valueKey);

        if (indices != null) {
          setSelectionIndices(indices);
        } else if (values != null) {
          setSelectionValues(values);
        }

        if (((values != null && indices == null) || (values == null && indices == null)) && indexKey != null) {
          int indices2[] = table.getSelectedRows();
          for (int i = 0; i < indices2.length; i++) {
            indices2[i] = sorter.getRowForSortedRow(indices[i]);
          }
          model.setValue(Table.this, indexKey, indices);
        }

        if (((indices != null && values == null) || (values == null && indices == null)) && valueKey != null) {
          int indices2[] = table.getSelectedRows();
          TableRow rows[] = new TableRow[indices2.length];
          for (int i = 0; i < indices2.length; i++)
            rows[i] = tableDataModel.getTableRow(sorter.getRowForSortedRow(indices2[i]));
          model.setValue(Table.this, valueKey, rows);
        }
      } finally {
        processEvents = true;
      }
    }
  }

  public void modelChanged(ModelChangeEvent e) throws GUIException {
    if (processEvents) {
      try {
        sendEvents = false;
        if (e.getSource() == this) {
          try {
            reload();
          } catch (IllegalArgumentException ex) {
            /* Ignore, table data model is not yet set */
          } catch (ArrayIndexOutOfBoundsException ex) {
            /* Ignore, table data model is not yet set */
          }
        } else if (e instanceof MapChangeEvent) {
          MapChangeEvent event = (MapChangeEvent) e;
          if (event.getKey() == null) {
            reload();
          } else if (event.getKey().equals(indexKey)) {
            setSelectionIndices((int[]) ((MapChangeEvent) e).getNewValue());
            try {
              processEvents = false;
              if (valueKey != null) {
                int indices[] = table.getSelectedRows();
                TableRow rows[] = new TableRow[indices.length];
                for (int i = 0; i < indices.length; i++)
                  rows[i] = tableDataModel.getTableRow(sorter.getRowForSortedRow(indices[i]));
                ((MapDataModel) event.getModel()).setValue(Table.this, valueKey, rows);
              }
            } finally {
              processEvents = true;
            }
          } else if (event.getKey().equals(valueKey)) {
            setSelectionValues((TableRow[]) ((MapChangeEvent) e).getNewValue());
            try {
              processEvents = false;
              if (indexKey != null) {
                int indices[] = table.getSelectedRows();
                for (int i = 0; i < indices.length; i++) {
                  indices[i] = sorter.getRowForSortedRow(indices[i]);
                }
                ((MapDataModel) event.getModel()).setValue(Table.this, indexKey, indices);
              }
            } finally {
              processEvents = true;
            }
          }
        }
      } finally {
        sendEvents = true;
      }
    }
  }

  public void addListener(String event, final String name, final GUIEventListener listener) throws GUIException {
    if ("rightclick".equals(event)) {
      table.addMouseListener(new MouseAdapter() {
        public void mousePressed(MouseEvent me) {
          if (me.isPopupTrigger() && message == null) {
            listener.eventOccured(new GUIEvent(Table.this, name, me));
          }
        }

        public void mouseReleased(MouseEvent me) {
          mousePressed(me);
        }
      });
    } else if (event.equals("doubleclick")) {
      table.addMouseListener(new MouseAdapter() {
        public void mousePressed(MouseEvent me) {
          if (me.getClickCount() == 2 && message == null) {
            listener.eventOccured(new GUIEvent(Table.this, name, me));
          }
        }
      });
    } else {
      super.addListener(event, name, listener);
    }
  }

  public Component getWidget() {
    return scrollPane;
  }

  public Component getRealWidget() {
    return table;
  }

  public WidgetInfo getWidgetInfo() {
    return tableInfo;
  }
}
TOP

Related Classes of org.beryl.gui.widgets.Table$CustomCellEditor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.