package jadex.commons.gui;
import jadex.commons.SGUI;
import jadex.commons.SUtil;
import java.awt.Component;
import java.awt.Insets;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JTable;
import javax.swing.UIDefaults;
import javax.swing.event.TableModelEvent;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
/**
* A editable list with x / + symbols at each row.
*/
public class EditableList extends JTable
{
//-------- static part --------
/** The image icons. */
protected static UIDefaults icons = new UIDefaults(new Object[]
{
"add", SGUI.makeIcon(EditableList.class, "/jadex/tools/common/images/add_small.png"),
"delete", SGUI.makeIcon(EditableList.class, "/jadex/tools/common/images/delete_small.png"),
});
//-------- attributes --------
/** The editable flag. */
protected boolean editable;
/** The entries. */
protected java.util.List entries;
/** Allow duplicate entries. */
protected boolean allowduplicates;
/** The list title. */
protected String title;
/** Show the numbers of entries in title. */
protected boolean showcnt;
//-------- constructors --------
/**
* Create a new editable list.
*/
public EditableList(final String title)
{
this(title, false);
}
/**
* Create a new editable list.
*/
public EditableList(final String title, boolean showcnt)
{
this.title = title;
this.entries = new ArrayList();
this.editable = true;
this.allowduplicates = false;
this.showcnt = showcnt;
setModel(new AbstractTableModel()
{
public int getColumnCount()
{
return editable ? 2 : 1;
}
public String getColumnName(int column)
{
return editable && column==0 ? " " : getTitle();
}
public Class getColumnClass(int columnIndex)
{
return editable && columnIndex==0 ? JButton.class : String.class;
}
public int getRowCount()
{
return getEntries().length + (editable ? 1 : 0);
}
public Object getValueAt(int rowIndex, int columnIndex)
{
if((!editable || columnIndex!=0) && rowIndex<getEntries().length)
{
return getEntries()[rowIndex];
}
else
{
return "";
}
}
public boolean isCellEditable(int rowIndex, int columnIndex)
{
return editable && (columnIndex==0 || rowIndex!=getEntries().length);
}
public void setValueAt(Object newadr, int rowIndex, int columnIndex)
{
if(columnIndex==1)
{
while(rowIndex>=entries.size())
entries.add("");
entries.set(rowIndex, (String)newadr);
fireTableCellUpdated(rowIndex, columnIndex);
}
}
});
// Hack!!! Set header preferred size and afterwards set title text to "" (bug in JDK1.5).
getTableHeader().setPreferredSize(getTableHeader().getPreferredSize());
getColumnModel().getColumn(0).setHeaderValue("");
// Hack!!! Stupid JTable behaviour, see bug #4709394.
putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
setDefaultRenderer(JButton.class, new ButtonCellManager());
setDefaultEditor(JButton.class, new ButtonCellManager());
JButton but = new JButton(icons.getIcon("delete"));
but.setMargin(new Insets(0,0,0,0));
getColumnModel().getColumn(0).setMaxWidth(but.getPreferredSize().width);
//teststable.setPreferredScrollableViewportSize(new Dimension(tfname.getPreferredSize().width, tfname.getPreferredSize().height*3));
// Add resizable header.
/*ResizeableTableHeader header = new ResizeableTableHeader();
header.setColumnModel(getColumnModel());
header.setAutoResizingEnabled(true); //default
header.setIncludeHeaderWidth(false); //default
setTableHeader(header);
setAutoResizeMode(JTable.AUTO_RESIZE_OFF);*/
}
/**
* Test if duplicates are allowed.
* @return the allowduplicates.
*/
public boolean isAllowDuplicates()
{
return allowduplicates;
}
/**
* Set if duplicates are allowed.
* @param allowduplicates the allowduplicates to set.
*/
public void setAllowDuplicates(boolean allowduplicates)
{
this.allowduplicates = allowduplicates;
if(!allowduplicates)
removeDuplicates();
}
/**
* Remove all duplicates from the list.
*/
protected void removeDuplicates()
{
for(int i=0; i<entries.size(); i++)
{
Object tmp = entries.get(i);
int last = entries.lastIndexOf(tmp);
while(i<last)
{
entries.remove(last);
last = entries.lastIndexOf(tmp);
}
}
refresh();
}
/**
* Get the entries.
* @return The entries.
*/
public String[] getEntries()
{
return (String[])entries.toArray(new String[entries.size()]);
}
/**
* Get the size.
* @return The size.
*/
public int getEntryCount()
{
return entries.size();
}
/**
* Set the entries.
* @param entries The entries.
*/
public void setEntries(String[] entries)
{
this.entries = SUtil.arrayToList(entries);
if(!allowduplicates)
removeDuplicates();
refresh();
}
/**
* Add a new entry.
* @param entry The new entry.
*/
public void addEntry(String entry)
{
if(allowduplicates || !entries.contains(entry))
this.entries.add(entry);
refresh();
}
/**
* Add a new entry.
* @param entry The new entry.
*/
public void removeEntry(String entry)
{
this.entries.remove(entry);
refresh();
}
/**
* Remove all entries.
*/
public void removeEntries()
{
this.entries.clear();
refresh();
}
/**
* Test if an entry is contained.
* @param entry The entry.
* @return True, if contained.
*/
public boolean containsEntry(String entry)
{
return this.entries.contains(entry);
}
/**
* Table cell renderer / editor using add delete buttons.
*/
public class ButtonCellManager extends AbstractCellEditor implements TableCellRenderer, TableCellEditor
{
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int rowIndex, int column)
{
JButton ret;
if(rowIndex!=getEntries().length)
{
ret = new JButton(icons.getIcon("delete"));
ret.setToolTipText("Remove this entry.");
}
else
{
ret = new JButton(icons.getIcon("add"));
ret.setToolTipText("Add a new entry.");
}
return ret;
}
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, final int rowIndex, int column)
{
if(rowIndex!=getEntries().length)
{
JButton del = new JButton(icons.getIcon("delete"));
del.addActionListener(new ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent e)
{
// System.out.println("remove");
// ((AbstractTableModel)getModel()).fireTableRowsDeleted(rowIndex, rowIndex);
Object entry = entries.remove(rowIndex);
((AbstractTableModel)getModel()).fireTableChanged(new EditableListEvent(getModel(), rowIndex, rowIndex,
TableModelEvent.ALL_COLUMNS, TableModelEvent.DELETE, new Object[]{entry}));
fireEditingStopped();
refresh();
}
});
return del;
}
else
{
JButton add = new JButton(icons.getIcon("add"));
add.addActionListener(new ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent e)
{
// System.out.println("add");
entries.add("");
AbstractTableModel model = (AbstractTableModel)getModel();
model.fireTableRowsInserted(model.getRowCount(), model.getRowCount());
fireEditingStopped();
refresh();
}
});
return add;
}
}
public Object getCellEditorValue()
{
return "";
}
}
/**
* Update the ui, when the aid has changed.
*/
public void refresh()
{
// Force table repaint (hack???).
tableChanged(new TableModelEvent(getModel(), TableModelEvent.HEADER_ROW));
if(editable)
{
// Hack!!! Have to (re)set column width for buttons.
JButton but = new JButton(icons.getIcon("delete"));
but.setMargin(new Insets(0,0,0,0));
getColumnModel().getColumn(0).setMaxWidth(but.getPreferredSize().width);
}
// Hack!!! For the table to be relayouted, we have to revalidate the scroll pane.
this.invalidate();
this.validate();
this.repaint();
}
/**
* Set the list title.
* @param title The title.
*/
public void setTitle(String title)
{
this.title = title;
refresh();
}
/**
* Get the list title.
* @return The title.
*/
public String getTitle()
{
return showcnt? this.title+" ["+entries.size()+"]": this.title;
}
/**
* Test if number of entries is shown.
* @return The showcnt.
*/
public boolean isShowEntriesCount()
{
return showcnt;
}
/**
* Show the number of entries in title.
* @param showcnt True for showing the number.
*/
public void setShowEntriesCount(boolean showcnt)
{
this.showcnt = showcnt;
}
}