/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenFlexo 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.fib.view.widget.table; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Hashtable; import java.util.List; import java.util.Observable; import java.util.Observer; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.event.EventListenerList; import javax.swing.event.TableModelEvent; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableModel; import org.openflexo.fib.controller.FIBController; import org.openflexo.fib.model.FIBButtonColumn; import org.openflexo.fib.model.FIBCheckBoxColumn; import org.openflexo.fib.model.FIBCustomColumn; import org.openflexo.fib.model.FIBDropDownColumn; import org.openflexo.fib.model.FIBIconColumn; import org.openflexo.fib.model.FIBLabelColumn; import org.openflexo.fib.model.FIBNumberColumn; import org.openflexo.fib.model.FIBTable; import org.openflexo.fib.model.FIBTableColumn; import org.openflexo.fib.model.FIBTextFieldColumn; import org.openflexo.fib.view.widget.FIBTableWidget; import org.openflexo.toolbox.HasPropertyChangeSupport; /** * Please comment this class * * @author sguerin * */ public class FIBTableModel extends AbstractTableModel { private static final Logger logger = Logger.getLogger(FIBTableModel.class.getPackage().getName()); private List<Object> _values; private Vector<AbstractColumn> _columns; private FIBTable _fibTable; private FIBTableWidget _widget; private final Hashtable<Object, RowObjectModificationTracker> _rowObjectModificationTrackers; /** * Stores controls: key is the JButton and value the PropertyListActionListener */ // private Hashtable<JButton,PropertyListActionListener> _controls; public FIBTableModel(FIBTable fibTable, FIBTableWidget widget, FIBController controller) { super(); _fibTable = fibTable; _widget = widget; _values = null; _columns = new Vector<AbstractColumn>(); for (FIBTableColumn column : fibTable.getColumns()) { addToColumns(buildTableColumn(column, controller)); } _rowObjectModificationTrackers = new Hashtable<Object, RowObjectModificationTracker>(); } public FIBTable getTable() { return _fibTable; } public void delete() { if (_values != null) { for (Object o : _values) { // logger.info("REMOVE "+o); if (o instanceof HasPropertyChangeSupport) { PropertyChangeSupport pcSupport = ((HasPropertyChangeSupport) o).getPropertyChangeSupport(); // logger.info("Widget "+getWidget()+" remove property change listener: "+o); pcSupport.removePropertyChangeListener(getTracker(o)); deleteTracker(o); } else if (o instanceof Observable) { // logger.info("Widget "+getWidget()+" remove observable: "+o); ((Observable) o).deleteObserver(getTracker(o)); deleteTracker(o); } } } for (AbstractColumn c : _columns) { c.delete(); } _columns.clear(); if (_values != null) { _values.clear(); } _columns = null; _values = null; _widget = null; _fibTable = null; } public FIBTableWidget getWidget() { return _widget; } public List<Object> getValues() { return _values; } public void setValues(Collection<?> values) { // logger.info("setValues with "+values); if (logger.isLoggable(Level.FINE)) { logger.fine("setValues() with " + values); } Collection<?> newValues = values; if (values == null) { newValues = Collections.emptyList(); } List<Object> oldValues = _values; _values = new ArrayList<Object>(); List<Object> removedValues = new ArrayList<Object>(); List<Object> addedValues = new ArrayList<Object>(); if (oldValues != null) { removedValues.addAll(oldValues); } for (Object v : newValues) { if (oldValues != null && oldValues.contains(v)) { removedValues.remove(v); } else { addedValues.add(v); } _values.add(v); } for (Object o : addedValues) { logger.fine("ADD " + o); if (o instanceof HasPropertyChangeSupport) { PropertyChangeSupport pcSupport = ((HasPropertyChangeSupport) o).getPropertyChangeSupport(); logger.fine("Widget " + getWidget() + " remove property change listener: " + o); pcSupport.addPropertyChangeListener(getTracker(o)); } else if (o instanceof Observable) { logger.fine("Widget " + getWidget() + " remove observable: " + o); ((Observable) o).addObserver(getTracker(o)); } } for (Object o : removedValues) { logger.fine("REMOVE " + o); if (o instanceof HasPropertyChangeSupport) { PropertyChangeSupport pcSupport = ((HasPropertyChangeSupport) o).getPropertyChangeSupport(); logger.fine("Widget " + getWidget() + " remove property change listener: " + o); pcSupport.removePropertyChangeListener(getTracker(o)); deleteTracker(o); } else if (o instanceof Observable) { logger.fine("Widget " + getWidget() + " remove observable: " + o); ((Observable) o).deleteObserver(getTracker(o)); deleteTracker(o); } } fireModelObjectHasChanged(oldValues, _values); fireTableDataChanged(); } private void deleteTracker(Object o) { _rowObjectModificationTrackers.remove(o); } private RowObjectModificationTracker getTracker(Object o) { RowObjectModificationTracker returned = _rowObjectModificationTrackers.get(o); if (returned == null) { returned = new RowObjectModificationTracker(o); _rowObjectModificationTrackers.put(o, returned); } return returned; } protected class RowObjectModificationTracker implements Observer, PropertyChangeListener { private final Object rowObject; public RowObjectModificationTracker(Object rowObject) { this.rowObject = rowObject; } @Override public void propertyChange(PropertyChangeEvent evt) { // System.out.println("Row object "+evt.getSource()+" : propertyChange "+evt); if (logger.isLoggable(Level.FINE)) { logger.fine("table " + getTable().getName() + " propertyChange for " + rowObject + " source=" + evt.getSource() + " evt=" + evt); } updateRow(); } @Override public void update(Observable o, Object arg) { updateRow(); } private void updateRow() { fireTableRowsUpdated(indexOf(rowObject), indexOf(rowObject)); getTableWidget().notifyDynamicModelChanged(); } } /** * Notifies all listeners that represented model has changed * * @see TableModelEvent * @see EventListenerList * @see javax.swing.JTable#tableChanged(TableModelEvent) */ public void fireModelObjectHasChanged(List<Object> oldValues, List<Object> newValues) { // logger.info("fireModelObjectHasChanged in " + getTable().getName() + " from " + oldValues + " to " + newValues); fireTableChanged(new ModelObjectHasChanged(this, oldValues, newValues)); } public class ModelObjectHasChanged extends TableModelEvent { private final List<Object> _oldValues; private final List<Object> _newValues; public ModelObjectHasChanged(TableModel source, List<Object> oldValues, List<Object> newValues) { super(source); _oldValues = oldValues; _newValues = newValues; } public List<Object> getNewValues() { return _newValues; } public List<Object> getOldValues() { return _oldValues; } } @Override public int getRowCount() { if (getValues() != null) { return getValues().size(); } return 0; } public Object elementAt(int row) { if (getValues() != null && row >= 0 && row < getValues().size()) { return getValues().get(row); } return null; } public int indexOf(Object object) { for (int i = 0; i < getRowCount(); i++) { if (elementAt(i) == object) { return i; } } return -1; } public void addToColumns(AbstractColumn aColumn) { _columns.add(aColumn); aColumn.setTableModel(this); } public void removeFromColumns(AbstractColumn aColumn) { _columns.remove(aColumn); aColumn.setTableModel(null); } public AbstractColumn columnAt(int index) { AbstractColumn returned = _columns.elementAt(index); return returned; } @Override public int getColumnCount() { return _columns.size(); } @Override public String getColumnName(int col) { AbstractColumn column = columnAt(col); if (column != null) { return column.getLocalizedTitle(); } return "???"; } public int getDefaultColumnSize(int col) { AbstractColumn column = columnAt(col); if (column != null) { return column.getDefaultWidth(); } return 75; } public boolean getColumnResizable(int col) { AbstractColumn column = columnAt(col); if (column != null) { return column.getResizable(); } return true; } @Override public Class<?> getColumnClass(int col) { AbstractColumn column = columnAt(col); if (column != null) { return column.getValueClass(); } return null; } @Override public boolean isCellEditable(int row, int col) { AbstractColumn column = columnAt(col); if (column != null) { Object object = elementAt(row); return column.isCellEditableFor(object); } return false; } @Override public Object getValueAt(int row, int col) { AbstractColumn column = columnAt(col); if (column != null) { Object object = elementAt(row); return column.getValueFor(object); } return null; } @Override public void setValueAt(Object value, int row, int col) { AbstractColumn column = columnAt(col); if (column != null && column instanceof EditableColumn) { Object object = elementAt(row); ((EditableColumn) column).setValueFor(object, value); fireCellUpdated(object, row, col); } } public void fireCellUpdated(Object editedObject, int row, int column) { // fireTableChanged(new TableModelEvent(this, row, row, column)); int newRow = indexOf(editedObject); if (logger.isLoggable(Level.FINE)) { logger.fine("editedObject=" + editedObject); logger.fine("row was " + row); logger.fine("new row is " + newRow); } if (row != newRow) { if (logger.isLoggable(Level.FINE)) { logger.fine("row changed !"); } fireTableChanged(new RowMoveForObjectEvent(this, editedObject, newRow, column)); } } public class RowMoveForObjectEvent extends TableModelEvent { private final Object _editedObject; private final int _newRow; private final int _column; public RowMoveForObjectEvent(TableModel source, Object editedObject, int newRow, int column) { super(source); _editedObject = editedObject; _column = column; _newRow = newRow; } public Object getEditedObject() { return _editedObject; } @Override public int getColumn() { return _column; } public int getNewRow() { return _newRow; } } /* protected class PropertyListCellRenderer extends DefaultTableCellRenderer { public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component returned = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); AbstractColumn col = get if (returned instanceof JComponent) ((JComponent)returned).setToolTipText(getLocalizedTooltip(getModel().elementAt(row))); return returned; } } */ /* protected void addToActions(PropertyListAction plAction) { PropertyListActionListener plActionListener = new PropertyListActionListener(plAction, this); JButton newButton = new JButton(); newButton.setText(FlexoLocalization.localizedForKey(plAction.name, newButton)); if (plAction.help!=null) newButton.setToolTipText(FlexoLocalization.localizedForKey(plAction.help, newButton)); newButton.addActionListener(plActionListener); getControlPanel().add(newButton); _controls.put(newButton, plActionListener); updateControls(null); } public Enumeration<PropertyListActionListener> getActionListeners() { return _controls.elements(); }*/ /* if (controlPanel == null) { controlPanel = new JPanel() { @Override public void remove(int index) { super.remove(index); } }; controlPanel.setLayout(new FlowLayout()); controlPanel.setOpaque(false); } return controlPanel;*/ public FIBTableColumn getPropertyListColumnWithTitle(String title) { return _fibTable.getColumnWithTitle(title); } @Override public void fireTableRowsUpdated(int firstRow, int lastRow) { if (logger.isLoggable(Level.FINE)) { logger.fine("fireTableRowsUpdated firstRow=" + firstRow + " lastRow=" + lastRow); } if (firstRow > -1 && lastRow > -1) { super.fireTableRowsUpdated(firstRow, lastRow); } } /** * @return the table widget associated with this model. * @deprecated model should not have access to its view nor its controller */ @Deprecated protected FIBTableWidget getTableWidget() { return _widget; } private AbstractColumn buildTableColumn(FIBTableColumn column, FIBController controller) { if (column instanceof FIBLabelColumn) { return new LabelColumn((FIBLabelColumn) column, this, controller); } else if (column instanceof FIBTextFieldColumn) { return new TextFieldColumn((FIBTextFieldColumn) column, this, controller); } else if (column instanceof FIBCheckBoxColumn) { return new CheckBoxColumn((FIBCheckBoxColumn) column, this, controller); } else if (column instanceof FIBDropDownColumn) { return new DropDownColumn((FIBDropDownColumn) column, this, controller); } else if (column instanceof FIBIconColumn) { return new IconColumn((FIBIconColumn) column, this, controller); } else if (column instanceof FIBNumberColumn) { return new NumberColumn((FIBNumberColumn) column, this, controller); } else if (column instanceof FIBCustomColumn) { return new CustomColumn((FIBCustomColumn) column, this, controller); } else if (column instanceof FIBButtonColumn) { return new ButtonColumn((FIBButtonColumn) column, this, controller); } return null; } }