/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package photoSpreadObjects.photoSpreadComponents; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.rmi.AlreadyBoundException; import java.rmi.NotBoundException; import java.text.Collator; import java.util.ArrayList; import java.util.Comparator; import java.util.TreeMap; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.event.ChangeEvent; import javax.swing.event.MouseInputAdapter; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableRowSorter; import photoSpread.PhotoSpread; import photoSpread.PhotoSpreadException.CannotLoadImage; import photoSpreadObjects.PhotoSpreadFileObject; import photoSpreadObjects.PhotoSpreadObject; import photoSpreadUtilities.ChangeManager; import photoSpreadUtilities.ComputableDimension; import photoSpreadUtilities.Const; import photoSpreadUtilities.Misc; import photoSpreadUtilities.PhotoSpreadContextMenu; import photoSpreadUtilities.Misc.ShowHelpAction; import photoSpreadUtilities.Misc.WindowCloseAction; /** * * @author skandel */ public class MetadataEditor extends JFrame { private static final long serialVersionUID = 1L; // The following instance var is required to // make the context menu work, even though it's // never accessed: JPopupMenu _popup; private static final int NUM_OF_TABLE_COLS = 2; private static final int NUM_OF_TABLE_ROWS = 25; // Vertical space between the save/save-and-exit/cancel buttons; private static final int _EDITED_ITEM_TO_ACTION_BUTTONS_HGAP = 5; private static final int ACTION_BUTTONS_VGAP = 3; PhotoSpreadObject _editedObject; ChangeManager _changeManager; // Name of this metadata editor instance. // Invented and used for the ChangeManager // interaction. String _editorName; JPanel _panel; JTable _table; DataTableModel _tableModel; TableRowSorter<DataTableModel> _metadataSorter = null; Comparator<Object> _metadataComparator = new MetadataComparator(); PhotoSpreadContextMenu _contextMenu; JScrollPane _scrollPane; Dimension _workspacePanelSize; /**************************************************** * Constructor(s) *****************************************************/ public MetadataEditor() { this.addWindowListener(new MetadataEditorWindowListener()); this.setTitle("PhotoSpread Metadata Editor"); _panel = new JPanel(); _panel.setBackground(Color.DARK_GRAY); // _panel.setSize(PhotoSpread.photoSpreadPrefs.getDimension(PhotoSpread.editorSizeKey)); // Safety: catch the 'close window operation' in // an event handler to warn about uncommitted changes. this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); _scrollPane = new JScrollPane(_panel); _scrollPane .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); _scrollPane .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); this.add(_scrollPane); WindowCloseAction winCloseAction = new Misc().new WindowCloseAction(this); Misc.bindKey(this, "control W", winCloseAction); Misc.bindKey(this, "F1", new ShowHelpAction( "To do in Metadata Editor Window", "HelpFiles/metadataEditorHelp.html", this)); // For cnt-a (select all), etc.: this.addKeyListener(new KeyBindEditorKeyListener()); } public MetadataEditor(PhotoSpreadObject editableObject) throws NumberFormatException, NotBoundException { this(); setEditedObject(editableObject); // Put selection on first cell: _table.setRowSelectionInterval(0,0); _table.setColumnSelectionInterval(0,0); pack(); } /**************************************************** * Private (Inner) Classes *****************************************************/ class MetadataEditorWindowListener extends WindowAdapter { public void windowClosing(WindowEvent e) { if (JOptionPane.showConfirmDialog( _scrollPane, // Show dialog within the metadata editor window "Discard changes (if any)?", "Confirm", // Title JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { // Unregister from the ChangeManager: _tableModel.dispose(); dispose(); } } public void windowDeiconified(WindowEvent e) { } } /**************************************************** * Inner Classes: Listeners *****************************************************/ class KeyBindEditorKeyListener extends KeyAdapter { public void keyPressed(KeyEvent e) { if (e.getID() == KeyEvent.KEY_PRESSED) { // Get indices of first and last currently selected rows: int firstSelectedRow = _table.getSelectionModel() .getAnchorSelectionIndex(); int lastSelectedRow = _table.getSelectionModel() .getLeadSelectionIndex(); int currRow = getRow(); char typedChar = e.getKeyChar(); switch (typedChar) { case KeyEvent.VK_DELETE: // Main or Numpad delete key // NumPad Delete key? if (e.getKeyLocation() == KeyEvent.KEY_LOCATION_NUMPAD) _tableModel.removeRow(firstSelectedRow, lastSelectedRow); else { // Main keyboard Delete key: // Clear current row (i.e. make it empty; leave row in // place): _tableModel.clearRow(firstSelectedRow, lastSelectedRow); // Put edit focus to first of the cleared rows: int selectionUpMove = lastSelectedRow - firstSelectedRow; for (; selectionUpMove > 0; selectionUpMove--) _table.transferFocusBackward(); } // NOTE1: This next statement ensures that // repainting of the table is completed // correctly. Without it, the cell with // focus will retain its old value (Swing // bug as far as I'm concerned!): _table.editingStopped(new ChangeEvent(this)); break; case KeyEvent.VK_ENTER: // If we don't consume this key event, the default // JTable behavior interferes: e.consume(); // _table.getSelectionModel().clearSelection(); if (currRow >= _tableModel.getRowCount() - 1) { _tableModel.appendRow(); _table.editingStopped(new ChangeEvent(this)); } int selectedRowNum = _table.getSelectedRow(); int selectedColNum = _table.getSelectedColumn(); if (selectedColNum >= _table.getColumnCount() - 1) _table.changeSelection( selectedRowNum + 1, // Select next row, ... 0, // ... column 0 Const.DONT_TOGGLE_SELECTION, // Set selection there, don't toggle it Const.DONT_EXTEND_SELECTION); // Clear the previous selection else _table.changeSelection( currRow, // Select same row, ... selectedColNum + 1, // ... next column Const.DONT_TOGGLE_SELECTION, // Set selection there, don't toggle it Const.DONT_EXTEND_SELECTION); // Clear the previous selection _table.editCellAt(_table.getSelectedRow(), _table.getSelectedColumn()); break; case KeyEvent.VK_INSERT: _tableModel.addRowBefore(currRow); // see NOTE1 above on need for following statement: _table.editingStopped(new ChangeEvent(this)); default: break; } } } public void keyTyped(KeyEvent e) { if (e.getID() == KeyEvent.KEY_TYPED) { char typedChar = e.getKeyChar(); switch (typedChar) { // This branch, intended for cnt-s, unfortunately never // gets control: case KeyEvent.VK_S: if (e.getModifiersEx() == KeyEvent.VK_CONTROL) return; break; default: break; } } } /** * @return */ private int getRow() { // Which row is in focus? int currRow = _table.getEditingRow(); if (currRow == -1) currRow = _table.getSelectedRow(); if (currRow == -1) currRow = 0; return currRow; } /** * */ @SuppressWarnings("unused") private int getColumn() { // Which column is in focus? int currCol = _table.getEditingColumn(); if (currCol == -1) currCol = _table.getSelectedColumn(); if (currCol == -1) currCol = 0; return currCol; } } // end class ObjectPanelKeyListener class SaveButtonListener implements ActionListener { public SaveButtonListener() { } public void actionPerformed(ActionEvent e) { submitChanges(); } } class SaveAndExitButtonListener implements ActionListener { public SaveAndExitButtonListener() { } public void actionPerformed(ActionEvent e) { submitChanges(); ChangeManager.unregisterClient(_editorName); dispose(); } } class CancelButtonListener implements ActionListener { public CancelButtonListener() { } public void actionPerformed(ActionEvent e) { // Just close the editor window: ChangeManager.unregisterClient(_editorName); dispose(); } } /** * @author paepcke * * We display the PhotoSpread objects whose metadata is being edited * in the metadata editor. But we don't want them selectable or * draggable there, because the respective handlers (on * DraggableLabel, for instance), assume that they live in the * context of an ObjetcsPanel. This assumption leads to a ... JPanel * cannot be cast to ...ObjectsPanel. We therefore swallow any mouse * events that occur on top of the edited object's representation. * */ class MetadataEditorOverrideStandardMotionListener extends MouseInputAdapter { public void mouseReleased(MouseEvent e) { if (e.getSource() == _editedObject) { e.consume(); } } public void mouseEntered(MouseEvent e) { if (e.getSource() == _editedObject) { e.consume(); } } public void mouseExited(MouseEvent e) { if (e.getSource() == _editedObject) { e.consume(); } } public void mouseDragged(MouseEvent e) { if (e.getSource() == _editedObject) { e.consume(); } } } /**************************************************** * Methods *****************************************************/ public void setEditedObject(PhotoSpreadObject value) throws NumberFormatException, NotBoundException { this._editedObject = value; this._editorName = value.getObjectID().toString(); //******** /* value.setMetaData( "@HomeCell", value.getCell().getCellAddress()); */ //******** try { // Use ChangeManager to show visually whether user // has changed anything since last saving: ChangeManager.registerClient(_editorName, this); } catch (AlreadyBoundException e) { ChangeManager.unregisterClient(_editorName); try { ChangeManager.registerClient(_editorName, this); } catch (AlreadyBoundException e1) { e1.printStackTrace(); } } loadEditor(); } /** * */ public void selectAll() { if (_table != null) _table.selectAll(); } private void loadEditor() { BoxLayout topWindowLayout = new BoxLayout(_panel, BoxLayout.PAGE_AXIS); _panel.setLayout(topWindowLayout); JButton saveChangesButton = new JButton("Save Changes"); saveChangesButton.setAlignmentX(Component.CENTER_ALIGNMENT); JButton cancelButton = new JButton("Cancel"); cancelButton.setAlignmentX(Component.CENTER_ALIGNMENT); JButton saveAndExitButton = new JButton("Save & Stop Edit"); saveAndExitButton.setAlignmentX(CENTER_ALIGNMENT); saveChangesButton.addActionListener(new SaveButtonListener()); cancelButton.addActionListener(new CancelButtonListener()); saveAndExitButton.addActionListener(new SaveAndExitButtonListener()); // Panel for the submit/cancel buttons: JPanel buttonsPanel = new JPanel(); // Put each button into its own horizontal box // with horizontal glue on each of its sides. // This will make the buttons expand to the // same size: JPanel saveChangesButtonPanel = new JPanel(); BoxLayout saveChangesButtonLayout = new BoxLayout(saveChangesButtonPanel, BoxLayout.LINE_AXIS); saveChangesButtonPanel.setLayout(saveChangesButtonLayout); saveChangesButtonPanel.add(Box.createHorizontalGlue()); saveChangesButtonPanel.add(saveChangesButton); saveChangesButtonPanel.add(Box.createHorizontalGlue()); JPanel saveAndExitButtonPanel = new JPanel(); BoxLayout saveAndExitButtonLayout = new BoxLayout(saveAndExitButtonPanel, BoxLayout.LINE_AXIS); saveAndExitButtonPanel.setLayout(saveAndExitButtonLayout); saveAndExitButtonPanel.add(Box.createHorizontalGlue()); saveAndExitButtonPanel.add(saveAndExitButton); saveAndExitButtonPanel.add(Box.createHorizontalGlue()); JPanel cancelButtonPanel = new JPanel(); BoxLayout cancelButtonLayout = new BoxLayout(cancelButtonPanel, BoxLayout.LINE_AXIS); cancelButtonPanel.setLayout(cancelButtonLayout); cancelButtonPanel.add(Box.createHorizontalGlue()); cancelButtonPanel.add(cancelButton); cancelButtonPanel.add(Box.createHorizontalGlue()); // Make all buttons as wide and high as the widest/highest among them: Dimension preferredDims[] = { saveChangesButton.getPreferredSize(), saveAndExitButton.getPreferredSize(), cancelButton.getPreferredSize() }; Dimension maxPreferredDim = ComputableDimension.maxWidthHeight(preferredDims); saveChangesButton.setPreferredSize(maxPreferredDim); saveAndExitButton.setPreferredSize(maxPreferredDim); cancelButton.setPreferredSize(maxPreferredDim); BoxLayout buttonLayout = new BoxLayout(buttonsPanel, BoxLayout.Y_AXIS); buttonsPanel.setLayout(buttonLayout); buttonsPanel.setAlignmentX(CENTER_ALIGNMENT); buttonsPanel.setBorder(BorderFactory.createLoweredBevelBorder()); buttonsPanel.setBackground(Color.LIGHT_GRAY); buttonsPanel.add(saveChangesButtonPanel); buttonsPanel.add(Box.createRigidArea(new Dimension(0, ACTION_BUTTONS_VGAP))); buttonsPanel.add(saveAndExitButtonPanel); buttonsPanel.add(Box.createRigidArea(new Dimension(0, ACTION_BUTTONS_VGAP))); buttonsPanel.add(cancelButtonPanel); // Make a panel containing a visual representation // of the edited item and the Submit/cancel button panel: JPanel editeeAndButtons = new JPanel(); BoxLayout editeeAndButtonsLayout = new BoxLayout(editeeAndButtons, BoxLayout.LINE_AXIS); editeeAndButtons.setLayout(editeeAndButtonsLayout); editeeAndButtons.setBorder(BorderFactory.createLoweredBevelBorder()); editeeAndButtons.setBackground(Color.gray); editeeAndButtons.add(Box.createRigidArea(new Dimension( _EDITED_ITEM_TO_ACTION_BUTTONS_HGAP, 0))); try { int editeeScaledWidth = PhotoSpread.photoSpreadPrefs.getInt(PhotoSpread.workspaceMaxObjWidthKey); int editeeScaledHeight= PhotoSpread.photoSpreadPrefs.getInt(PhotoSpread.workspaceMaxObjHeightKey); DraggableLabel editeeVisualRep = (DraggableLabel) _editedObject.getWorkspaceComponent(editeeScaledWidth, editeeScaledHeight); editeeVisualRep.setPreferredSize(new Dimension(editeeScaledWidth, editeeScaledHeight)); editeeAndButtons.add(editeeVisualRep); } catch (CannotLoadImage e) { // We are not loading an image here, so this error // doesn't come up. } editeeAndButtons.add(Box.createRigidArea(new Dimension( _EDITED_ITEM_TO_ACTION_BUTTONS_HGAP, 0))); editeeAndButtons.add(buttonsPanel); editeeAndButtons.add(Box.createRigidArea(new Dimension( _EDITED_ITEM_TO_ACTION_BUTTONS_HGAP, 0))); editeeAndButtons.setAlignmentX(CENTER_ALIGNMENT); // Top: edited object plus submit/cancel: _panel.add(editeeAndButtons); /* Create TablePanel for Table and Column Header */ JPanel tablePanel = new JPanel(); BoxLayout tableAndHeaderLayout = new BoxLayout(tablePanel, BoxLayout.PAGE_AXIS); tablePanel.setLayout(tableAndHeaderLayout); // The table of metadata attributes and values: _tableModel = new DataTableModel(_editedObject); _table = new JTable(_tableModel); _metadataSorter = new TableRowSorter<DataTableModel>(_tableModel); for (int col=0; col<NUM_OF_TABLE_COLS; col++) _metadataSorter.setComparator(col, _metadataComparator); _table.setRowSorter(_metadataSorter); addContextMenu(); // Give the table sort capabilities // in both of the columns: _table.setAutoCreateRowSorter(true); _table.setBackground(Const.metaDataEditorBackGroundColor); _table.setForeground(Const.metaDataEditorForeGroundColor); _table.setSelectionForeground(Color.gray); _table.setFont(Const.TABLE_FONT); _table.addKeyListener(new KeyBindEditorKeyListener()); _table.setVisible(true); // ****_table.setMinimumSize(new Dimension(100, 100)); tablePanel.add(_table.getTableHeader()); tablePanel.add(_table); this.setBackground(Color.darkGray); // Attr/value table header and body: _panel.add(tablePanel); _panel.validate(); } private void submitChanges() { _editedObject.setMetaData(((DataTableModel) this._table.getModel()) .getData()); try { _editedObject.getCell().evaluate(Const.DO_REDRAW); } catch (Exception e) { Misc.showErrorMsgAndStackTrace(e, ""); //e.printStackTrace(); } ChangeManager.markClean(_editorName); } /**************************************************** * Context Menu Actions *****************************************************/ private void addContextMenu(){ _contextMenu = new PhotoSpreadContextMenu(); _contextMenu.addMenuItem("Add row above", new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { _tableModel.addRowBefore(); // see NOTE1 above on need for following statement: _table.editingStopped(new ChangeEvent(this)); } } ); _contextMenu.addMenuItem("Add row below", new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { _tableModel.addRowAfter(); // see NOTE1 above on need for following statement: _table.editingStopped(new ChangeEvent(this)); } } ); _contextMenu.addMenuItem("Clear row", new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { _tableModel.clearRow(); // see NOTE1 above on need for following statement: _table.editingStopped(new ChangeEvent(this)); } } ); _contextMenu.addMenuItem("Delete row", new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { _tableModel.removeRow(); // see NOTE1 above on need for following statement: _table.editingStopped(new ChangeEvent(this)); } } ); _contextMenu.addMenuItem("Re-alphabetize",new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { _tableModel.reAlphabetize(); // see NOTE1 above on need for following statement: _table.editingStopped(new ChangeEvent(this)); } } ); _contextMenu.addMenuItem("Select All",new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { selectAll(); } } ); /* _contextMenu.addMenuItem("Clear cell",new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { clearCell(); } } ); _contextMenu.addMenuItem("Insert Table",new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { loadTable(); } } ); _contextMenu.addMenuItem("Copy",new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { copy(); } } ); _contextMenu.addMenuItem("Paste",new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { paste(); } } ); */ _table.addMouseListener(_contextMenu.getPopupListener()); } /**************************************************** * DataTableModel *****************************************************/ class DataTableModel extends AbstractTableModel { public static final int ATTR_NAME_COL = 0; public static final int VALUE_COL = 1; public static final int NONE_FILE_EMPTY_ROWS = 1; public static final int FILE_OBJECTS_EMPTY_ROWS = 2; private static final long serialVersionUID = 1L; private String[] columnNames = { "<HTML><H3>Attribute</H3></HTML>", "<HTML><H3>Value</H3></HTML>" }; private ArrayList<ArrayList<String>> data; // How many initial rows in the metadata editor // should be read-only: private int numOfReadOnlyRows = -1; public DataTableModel(PhotoSpreadObject _editedObject) { data = _editedObject.getMetaDataSet(); // Add some empty rows: for (int i = 0; i < NUM_OF_TABLE_ROWS; i++) { data.add(makeEmptyRow()); } // File objects have the file name and the obj id // as read-only entries in the metadata editor. // Instances of other types only have the ID: if (_editedObject instanceof PhotoSpreadFileObject) numOfReadOnlyRows = FILE_OBJECTS_EMPTY_ROWS; else numOfReadOnlyRows = NONE_FILE_EMPTY_ROWS; } public void dispose() { } public Class<String> getColumnClass(int columnIndex) { return String.class; } public Comparator<?> getComparator (int col) { return _metadataComparator; } private ArrayList<String> makeEmptyRow() { ArrayList<String> newRow = new ArrayList<String>(); newRow.add(""); newRow.add(""); return newRow; } public void addRowBefore() { // Get indices of first and last currently selected rows: int firstSelectedRow = _table.getSelectionModel() .getAnchorSelectionIndex(); addRowBefore(firstSelectedRow); } public void addRowBefore(int rowNum) { int[] rowSpecs = {rowNum}; if (!areTableCoordsLegal(rowSpecs)) return; data.add(rowNum, makeEmptyRow()); ChangeManager.markDirty(_editorName); fireTableRowsInserted(rowNum, rowNum); } public void addRowAfter () { int firstSelectedRow = _table.getSelectionModel() .getAnchorSelectionIndex(); if (firstSelectedRow == getRowCount() - 1) appendRow(); else addRowBefore(firstSelectedRow + 1); } public void appendRow() { int newRowIndex = getRowCount(); data.add(makeEmptyRow()); ChangeManager.markDirty(_editorName); fireTableRowsInserted(newRowIndex, newRowIndex); } public void removeRow() { // Get indices of first and last currently selected rows: int firstSelectedRow = _table.getSelectionModel() .getAnchorSelectionIndex(); removeRow(firstSelectedRow); } public void removeRow(int rowNum) { removeRow(rowNum, rowNum); } public void removeRow(int firstRowNum, int lastRowNum) { int[] rowSpecs = { firstRowNum, lastRowNum }; if (!areTableCoordsLegal(rowSpecs)) return; for (int rowNum = firstRowNum; rowNum <= lastRowNum; rowNum++) data.remove(rowNum); ChangeManager.markDirty(_editorName); fireTableRowsDeleted(firstRowNum, lastRowNum); } public void clearRow() { // Get indices of first and last currently selected rows: int firstSelectedRow = _table.getSelectionModel() .getAnchorSelectionIndex(); clearRow(firstSelectedRow); } public void clearRow(int rowNum) { clearRow(rowNum, rowNum); } public void clearRow(int firstRowNum, int lastRowNum) { int[] rowSpecs = { firstRowNum, lastRowNum }; if (!areTableCoordsLegal(rowSpecs)) return; ArrayList<String> rowToClear; for (int rowNum = firstRowNum; rowNum <= lastRowNum; rowNum++) { rowToClear = data.get(rowNum); rowToClear.set(ATTR_NAME_COL, ""); rowToClear.set(VALUE_COL, ""); } ChangeManager.markDirty(_editorName); fireTableRowsUpdated(firstRowNum, lastRowNum); } public void clearCell(int rowNum, int colNum) { int[] rowSpecs = { rowNum }; int[] colSpecs = { colNum }; if (!areTableCoordsLegal(rowSpecs, colSpecs)) return; // setValueAt() will fire the update event: setValueAt("", rowNum, colNum); } @Override public boolean isCellEditable(int row, int col) { if (row > numOfReadOnlyRows - 1) return true; else return false; } @Override public String getColumnName(int col) { return columnNames[col]; } public int getColumnCount() { return columnNames.length; } public int getRowCount() { return data.size(); } public Object getValueAt(int row, int col) { return data.get(row).get(col); } public void setValueAt(Object value, int rowNum, int colNum) { if ((rowNum >= getRowCount()) || (rowNum < 0)) return; if ((colNum >= getColumnCount()) || (colNum < 0)) return; data.get(rowNum).set(colNum, (String) value); ChangeManager.markDirty(_editorName); fireTableCellUpdated(rowNum, colNum); } public void reAlphabetize () { TreeMap<String, String> sorter = new TreeMap<String, String>(); for (ArrayList<String> attrValPair : data) sorter.put(attrValPair.get(ATTR_NAME_COL), attrValPair.get(VALUE_COL)); data.clear(); for (String attr : sorter.keySet()) { ArrayList<String> row = new ArrayList<String>(); row.add(attr); row.add(sorter.get(attr)); data.add(row); } fireTableDataChanged(); } public ArrayList<ArrayList<String>> getData() { return data; } private boolean areTableCoordsLegal(int[] rows) { for (int rowNum : rows) { if ((rowNum >= getRowCount()) || (rowNum < 0)) return false; } return true; } private boolean areTableCoordsLegal(int[] rows, int[] cols) { for (int rowNum : rows) { if ((rowNum >= getRowCount()) || (rowNum < 0)) return false; } for (int colNum : rows) { if ((colNum >= columnNames.length) || (colNum < 0)) return false; } return true; } } /**************************************************** * Class Metadata *****************************************************/ /* private class MetadataComparator implements Comparator<String> { Collator _defaultComparator = Collator.getInstance(); public int compare(String metadata1, String metadata2) { if (metadata1.isEmpty()) return Const.BIGGER; return _defaultComparator.compare(metadata1, metadata2); } } */ private class MetadataComparator implements Comparator<Object> { Collator _defaultComparator = Collator.getInstance(); public int compare(Object metadata1, Object metadata2) { if (((String) metadata1).isEmpty()) return Const.BIGGER; return _defaultComparator.compare(metadata1, metadata2); } } }