package com.gmail.dpierron.calibre.gui.table;
import com.gmail.dpierron.calibre.configuration.CustomCatalogEntry;
import com.gmail.dpierron.calibre.opds.Constants;
import com.gmail.dpierron.tools.i18n.Localization;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
import java.util.List;
import java.util.Vector;
/**
* The table model for the custom catalogs options table
* The <code>TableModel</code> interface specifies the methods the
* <code>JTable</code> will use to interrogate a tabular data model. <p>
*
* The <code>JTable</code> can be set up to display any data
* model which implements the
* <code>TableModel</code> interface with a couple of lines of code: <p>
* <pre>
* TableModel myData = new MyTableModel();
* JTable table = new JTable(myData);
* </pre><p>
*
* For further documentation, see <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/table.html#data">Creating a Table Model</a>
* in <em>The Java Tutorial</em>.
* <p>
* @author Philip Milne
* @see javax.swing.JTable
*/
public class CustomCatalogTableModel implements TableModel {
private static List<CustomCatalogEntry> customCatalogs;
private static List<TableModelListener> listeners;
public CustomCatalogTableModel() {
if (customCatalogs == null) {
customCatalogs = new Vector<CustomCatalogEntry>();
listeners = new Vector<TableModelListener>();
}
}
/**
* Get the Custom catalogs String representation
* (used to load the GUI control values)
* TODO: Look at whether a XML format could be used for the string (c2o-90)
* @return
*/
public List<CustomCatalogEntry> getCustomCatalogs() {
return customCatalogs;
}
/**
* Set the Custom Catalog values from their string representation
* (used to store the GUI control values)
* TODO: Look at whether a XML format could be used for the string (c2o-90)
* @param customCatalogs
*/
public void setCustomCatalogs(List<CustomCatalogEntry> customCatalogs) {
this.customCatalogs = customCatalogs;
fireTableChangedEvent(new TableModelEvent(this));
}
/**
* Add a new line to the Custom catalog table
*/
public void addCustomCatalog() {
customCatalogs.add(new CustomCatalogEntry(Constants.CUSTOMCATALOG_DEFAULT_TITLE, Constants.CUSTOMCATALOG_DEFAULT_SEARCH, false)); // add a new line
fireTableChangedEvent(new TableModelEvent(this));
}
private void fireTableChangedEvent(TableModelEvent event) {
assert listeners != null && listeners.size() > 0;
for (TableModelListener listener : listeners) {
listener.tableChanged(event);
}
}
/**
* Remove a line from the Custom catalog table
* @param index
*/
public void deleteCustomCatalog(int index) {
if (index < customCatalogs.size()) {
customCatalogs.remove(index);
fireTableChangedEvent(new TableModelEvent(this));
}
}
/**
* Returns the number of rows in the model. A
* <code>JTable</code> uses this method to determine how many rows it
* should display. This method should be quick, as it
* is called frequently during rendering.
*
* @return the number of rows in the model
* @see #getColumnCount
*/
public int getRowCount() {
return getCustomCatalogs().size();
}
/**
* Returns the number of columns in the model. A
* <code>JTable</code> uses this method to determine how many columns it
* should create and display by default.
*
* @return the number of columns in the model
* @see #getRowCount
*/
public int getColumnCount() {
return 4;
}
/**
* Returns the name of the column at <code>columnIndex</code>. This is used
* to initialize the table's column header name. Note: this name does
* not need to be unique; two columns in a table can have the same name.
*
* @param columnIndex the index of the column
* @return the name of the column
*/
public String getColumnName(int columnIndex) {
switch (columnIndex) {
case 0:
return Localization.Main.getText("config.CustomCatalogTitle.label");
case 1:
return Localization.Main.getText("config.CustomCatalogSavedSearchName.label");
case 2:
return Localization.Main.getText("config.CustomCatalogSavedSearchTop.label");
case 3:
// Delete button column
return "";
default:
assert false : "unexpected value of columnIndex=" + columnIndex;;
return "";
}
}
/**
* Returns the most specific superclass for all the cell values
* in the column. This is used by the <code>JTable</code> to set up a
* default renderer and editor for the column.
*
* @param columnIndex the index of the column
* @return the common ancestor class of the object values in the model.
*/
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0: // Title
case 1: // Value
return String.class;
case 2: // Display at top toggle
return Boolean.class;
case 3: // Delete buttong
// TODO ITIMPI: Not sure what we should return for this column - does it even matter?
return String.class;
default:
assert false : "unexpected value of columnIndex=" + columnIndex;
return Boolean.class;
}
}
/**
* Returns true if the cell at <code>rowIndex</code> and
* <code>columnIndex</code>
* is editable. Otherwise, <code>setValueAt</code> on the cell will not
* change the value of that cell.
*
* @param rowIndex the row whose value to be queried
* @param columnIndex the column whose value to be queried
* @return true if the cell is editable
* @see #setValueAt
*/
public boolean isCellEditable(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0: // Label
case 1: // Value
case 2: // At top checkbox
case 3: // Delete button column
return true;
default:
assert false : "unexpected value of columnIndex=" + columnIndex;
return false;
}
}
/**
* Returns the value for the cell at <code>columnIndex</code> and
* <code>rowIndex</code>.
*
* @param rowIndex the row whose value is to be queried
* @param columnIndex the column whose value is to be queried
* @return the value Object at the specified cell
*/
public Object getValueAt(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0: // Label
return getCustomCatalogs().get(rowIndex).getLabel();
case 1: // Value
return getCustomCatalogs().get(rowIndex).getValue();
case 2: // At Top checkbox
return getCustomCatalogs().get(rowIndex).getAtTop();
case 3: // Delete button
return Localization.Main.getText("config.CustomCatalogSavedSearchDelete.label");
default:
assert false : "unexpected value of columnIndex=" + columnIndex;
return "";
}
}
/**
* Sets the value in the cell at <code>columnIndex</code> and
* <code>rowIndex</code> to <code>aValue</code>.
*
* @param aValue the new value
* @param rowIndex the row whose value is to be changed
* @param columnIndex the column whose value is to be changed
* @see #getValueAt
* @see #isCellEditable
*/
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
CustomCatalogEntry val = getCustomCatalogs().get(rowIndex);
switch (columnIndex) {
case 0:
val.setLabel("" + aValue);
break;
case 1:
val.setValue("" + aValue);
break;
case 2:
val.setAtTop((Boolean)aValue);
break;
case 3:
// Do nothing - this is the Delete button column
break;
default:
assert false : "Unexpected balue of columnIndex=" + columnIndex;
break;
}
}
/**
* Adds a listener to the list that is notified each time a change
* to the data model occurs.
*
* @param l the TableModelListener
*/
public void addTableModelListener(TableModelListener l) {
if (!listeners.contains(l))
listeners.add(l);
}
/**
* Removes a listener from the list that is notified each time a
* change to the data model occurs.
*
* @param l the TableModelListener
*/
public void removeTableModelListener(TableModelListener l) {
listeners.remove(l);
}
}