/*
* Copyright 1998-2012 University Corporation for Atmospheric Research/Unidata
*
* Portions of this software were developed by the Unidata Program at the
* University Corporation for Atmospheric Research.
*
* Access and use of this software shall impose the following obligations
* and understandings on the user. The user is granted the right, without
* any fee or cost, to use, copy, modify, alter, enhance and distribute
* this software, and any derivative works thereof, and its supporting
* documentation for any purpose whatsoever, provided that this entire
* notice appears in all copies of the software, derivative works and
* supporting documentation. Further, UCAR requests that the user credit
* UCAR/Unidata in any publications that result from the use of this
* software or in any product that includes this software. The names UCAR
* and/or Unidata, however, may not be used in any advertising or publicity
* to endorse or promote any products or commercial entity unless specific
* written permission is obtained from UCAR/Unidata. The user also
* understands that UCAR/Unidata is not obligated to provide the user with
* any support, consulting, training or assistance of any kind with regard
* to the use, operation and performance of this software nor to provide
* the user with any updates, revisions, new versions or "bug fixes."
*
* THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package ucar.nc2.ui.geoloc;
import java.awt.Dimension;
import java.io.*;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import ucar.nc2.util.ListenerManager;
import ucar.unidata.geoloc.ProjectionImpl;
import ucar.unidata.geoloc.ProjectionRect;
import ucar.util.prefs.PreferencesExt;
/**
* Consider this a private inner class of ProjectionManager.
*
* @author John Caron
* @version revived /20/2012
*/
public class JTableProjection extends JTable {
private PreferencesExt store = null;
private ProjectionTableModel model = null;
private ArrayList list;
private boolean debug = false;
private int selectedRow = 0; // JTable doesnt handle selections correctly
private ListenerManager lm;
private static final String STORE_NAME = "ProjectionTableModel";
public JTableProjection( PreferencesExt pstore) {
this.store = pstore;
if (store == null)
model = new ProjectionTableModel();
else {
model = (ProjectionTableModel) store.getObject( STORE_NAME);
if (model == null)
model = new ProjectionTableModel();
}
list = model.getList();
setModel(model);
setAutoResizeMode( JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
setPreferredScrollableViewportSize( new Dimension(400, 200));
getTableHeader().setReorderingAllowed(true);
model.adjustColumns(getColumnModel());
// manage the selection
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
// have to manage selectedRow ourselves, due to bugs
getSelectionModel().addListSelectionListener( new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (debug) System.out.println(" ListSelectionListener= "+ e);
if (!e.getValueIsAdjusting()) {
selectedRow = getSelectedRow();
if (debug) System.out.println(" selectd= "+ selectedRow);
lm.sendEvent(new NewProjectionEvent(this, getSelected()));
}
}
});
// manage NewProjectionListener's
lm = new ListenerManager(
"ucar.nc2.ui.geoloc.NewProjectionListener",
"ucar.nc2.ui.geoloc.NewProjectionEvent",
"actionPerformed");
}
public void addProjection(ProjectionImpl proj) {
int rowno = model.addProjection(proj);
setRowSelectionInterval(rowno, rowno);
selectedRow = rowno;
}
public void replaceProjection(ProjectionImpl proj) {
int rowno = model.replaceProjection(proj);
setRowSelectionInterval(rowno, rowno);
selectedRow = rowno;
}
public boolean contains(ProjectionImpl proj) {
return (model.search(proj) >= 0);
}
public boolean contains(String id) {
return (model.search(id) >= 0);
}
public ProjectionImpl getSelected() {
int len = list.size();
if ((0 > selectedRow) || (len <= selectedRow))
return null;
else
return (ProjectionImpl) list.get(selectedRow);
}
public void deleteSelected() {
int len = list.size();
if ((0 > selectedRow) || (len <= selectedRow))
return;
model.deleteRow( selectedRow);
// bugs in list selection code
len = list.size();
if (len == 0) {
clearSelection();
selectedRow = -1;
} else {
if (selectedRow > len-1) selectedRow = len-1;
setRowSelectionInterval(selectedRow, selectedRow);
if (debug) System.out.println(" set selection to "+selectedRow);
}
if (debug) System.out.println(" selection now= "+getSelectedRow()+ " really= "+ selectedRow);
lm.sendEvent(new NewProjectionEvent(this, getSelected()));
repaint();
}
public boolean isEmpty() {
return (model.getRowCount() == 0);
}
public void storePersistentData() {
if (store != null)
store.putObject( STORE_NAME, model);
}
public void setMapArea( ProjectionRect bb) {
if (0 > selectedRow)
return;
model.setMapArea(selectedRow, bb);
if (debug) System.out.println(" PTsetMapArea = "+ bb+ " on "+ selectedRow);
}
// set current projection if found, else deselect
public void setCurrentProjection(ProjectionImpl proj) {
int row;
if (0 <= (row = model.search(proj))) {
if (debug) System.out.println(" PTsetCurrentProjection found = "+ row);
selectedRow = row;
setRowSelectionInterval(row, row);
} else {
if (debug) System.out.println(" PTsetCurrentProjection not found = "+ row);
selectedRow = -1;
clearSelection();
}
}
// event listener managagment
public void addNewProjectionListener( NewProjectionListener l) {
lm.addListener(l);
}
public void removeNewProjectionListener( NewProjectionListener l) {
lm.removeListener(l);
}
// inner class must be static because JTable not Serializable
private static class ProjectionTableModel extends AbstractTableModel implements java.io.Serializable {
private static String[] colName = {"Name", "Type", "Parameters", "Default Zoom"};
private ArrayList list = new ArrayList(20);
// AbstractTableModel methods
public int getRowCount() { return list.size(); }
public int getColumnCount() { return colName.length; }
public String getColumnName(int col) { return colName[col]; }
public Object getValueAt (int row, int col) {
ProjectionImpl proj = (ProjectionImpl) list.get( row);
switch (col) {
case 0: return proj.getName();
case 1: return proj.getClassName();
case 2: return proj.paramsToString();
case 3: return proj.getDefaultMapArea();
}
return "error";
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
return (columnIndex == 0);
}
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
ProjectionImpl proj = (ProjectionImpl) list.get( rowIndex);
proj.setName( new String((String) aValue));
}
// do our own listener management to get around serialization bug
// can delete this section when bug is fixed
ProjectionTableModel() { constructLM(); }
private transient ListenerManager lm;
private void constructLM() {
lm = new ListenerManager("javax.swing.event.TableModelListener",
"javax.swing.event.TableModelEvent", "tableChanged");
}
public void addTableModelListener(TableModelListener l) {
lm.addListener(l);
}
public void removeTableModelListener(TableModelListener l) {
lm.removeListener(l);
}
public void fireTableChanged(TableModelEvent e) {
lm.sendEvent(e);
}
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
s.defaultReadObject();
constructLM();
}
// added methods
int addProjection(ProjectionImpl proj) {
list.add(proj);
int count = list.size() - 1;
fireTableRowsInserted(count, count);
return count;
}
int replaceProjection(ProjectionImpl proj) {
int rowno = search( proj);
if (rowno < 0)
return -1;
list.set( rowno, proj);
return rowno;
}
void adjustColumns( TableColumnModel colModel) {
for (int i=0; i<colName.length; i++) {
colModel.getColumn(i).setMinWidth(50);
colModel.getColumn(i).setPreferredWidth(100);
}
}
ArrayList getList() { return list; }
void deleteRow(int row) {
int len = list.size();
if (row < len)
list.remove(row);
else return;
fireTableRowsDeleted(row, row);
}
int search( ProjectionImpl proj) {
for (int row=0; row<list.size(); row++) {
ProjectionImpl test = (ProjectionImpl) list.get( row);
if (proj.getName().equals(test.getName()))
return row;
}
return -1;
}
int search( String projName) {
for (int row=0; row<list.size(); row++) {
ProjectionImpl test = (ProjectionImpl) list.get( row);
if (projName.equals(test.getName()))
return row;
}
return -1;
}
void setMapArea( int row, ProjectionRect bb) {
int len = list.size();
if (row >= len)
return;
ProjectionImpl proj = (ProjectionImpl) list.get(row);
proj.getDefaultMapArea().setRect( bb);
fireTableRowsUpdated(row, row);
}
}
}