From 40a9d99496e098562f090fb7ffce9e749011b131 Mon Sep 17 00:00:00 2001 From: Benjamin Culkin Date: Mon, 20 May 2024 17:58:16 -0400 Subject: Formatting pass --- .../net/wotonomy/ui/swing/TableAssociation.java | 1370 +++++++++----------- 1 file changed, 610 insertions(+), 760 deletions(-) (limited to 'projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TableAssociation.java') diff --git a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TableAssociation.java b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TableAssociation.java index bc02f7d..edba674 100644 --- a/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TableAssociation.java +++ b/projects/net.wotonomy.ui.swing/src/main/java/net/wotonomy/ui/swing/TableAssociation.java @@ -52,754 +52,619 @@ import net.wotonomy.ui.EOAssociation; import net.wotonomy.ui.EODisplayGroup; /** -* TableAssociation binds one or more TableColumnAssociations -* to a display group. You should not instantiate this class -* directly; use TableColumnAssociation.setTable() instead. -* Note that TableAssociation inserts itself as the controlled -* JTable's TableModel. -* -* Bindings are: -* -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 904 $ -*/ -public class TableAssociation extends EOAssociation - implements ActionListener, ListSelectionListener, FocusListener -{ - static final NSArray aspects = - new NSArray( new Object[] { - SourceAspect, EnabledAspect - } ); - static final NSArray aspectSignatures = - new NSArray( new Object[] { - AttributeToOneAspectSignature - } ); - static final NSArray objectKeysTaken = - new NSArray( new Object[] { - "tableModel", "tableHeader" - } ); - - // key command to copy contents to clipboard - static public final String COPY = "COPY"; + * TableAssociation binds one or more TableColumnAssociations to a display + * group. You should not instantiate this class directly; use + * TableColumnAssociation.setTable() instead. Note that TableAssociation inserts + * itself as the controlled JTable's TableModel. + * + * Bindings are: + * + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 904 $ + */ +public class TableAssociation extends EOAssociation implements ActionListener, ListSelectionListener, FocusListener { + static final NSArray aspects = new NSArray(new Object[] { SourceAspect, EnabledAspect }); + static final NSArray aspectSignatures = new NSArray(new Object[] { AttributeToOneAspectSignature }); + static final NSArray objectKeysTaken = new NSArray(new Object[] { "tableModel", "tableHeader" }); + + // key command to copy contents to clipboard + static public final String COPY = "COPY"; EODisplayGroup source; - EODisplayGroup sortTarget; // used by TreeColumnAssociation + EODisplayGroup sortTarget; // used by TreeColumnAssociation NSMutableArray columns; - JTableHeader tableHeader; - - boolean pleaseIgnore; - boolean selectionPaintedImmediately; - boolean selectionTracking; - - /** - * Constructor specifying the object to be controlled by this - * association. Throws an exception if the object is not - * a TableColumn. setTable() must be called before - * establishing the connection. - */ - public TableAssociation ( Object anObject ) - { - super( anObject ); + JTableHeader tableHeader; + + boolean pleaseIgnore; + boolean selectionPaintedImmediately; + boolean selectionTracking; + + /** + * Constructor specifying the object to be controlled by this association. + * Throws an exception if the object is not a TableColumn. setTable() must be + * called before establishing the connection. + */ + public TableAssociation(Object anObject) { + super(anObject); source = null; columns = new NSMutableArray(); - JTable aTable = ((JTable)anObject); - aTable.addFocusListener( this ); - aTable.setModel( - new TableAssociationModel( this ) ); - // set up keyboard events for cut-copy: Ctrl-C, Ctrl-X - - // why did sun make this harder to use? - //aTable.getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ).put( - // KeyStroke.getKeyStroke( KeyEvent.VK_C, java.awt.Event.CTRL_MASK ), COPY); - //aTable.getActionMap().put(COPY, this); - - aTable.registerKeyboardAction( this, COPY, - KeyStroke.getKeyStroke( KeyEvent.VK_C, - Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() ), - JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ); - aTable.registerKeyboardAction( this, COPY, - KeyStroke.getKeyStroke( KeyEvent.VK_X, - Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() ), - JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ); - tableHeader = new SortedTableHeader(); - tableHeader.setColumnModel( aTable.getColumnModel() ); - aTable.setTableHeader( tableHeader ); - tableHeader.addMouseListener( new TableHeaderListener() ); - pleaseIgnore = false; - selectionPaintedImmediately = false; - selectionTracking = false; - } - - /** - * Returns a List of aspect signatures whose contents - * correspond with the aspects list. Each element is - * a string whose characters represent a capability of - * the corresponding aspect. - * An empty signature "" means that the aspect can - * bind without needing a key. - * This implementation returns "A1M" for each - * element in the aspects array. - */ - public static NSArray aspectSignatures () - { - return aspectSignatures; - } - - /** - * Returns a List that describes the aspects supported - * by this class. Each element in the list is the string - * name of the aspect. This implementation returns an - * empty list. - */ - public static NSArray aspects () - { - return aspects; - } - - /** - * Returns a List of EOAssociation subclasses that, - * for the objects that are usable for this association, - * are less suitable than this association. - */ - public static NSArray associationClassesSuperseded () - { - return new NSArray(); - } - - /** - * Returns whether this class can control the specified - * object. - */ - public static boolean isUsableWithObject ( Object anObject ) - { - return ( anObject instanceof JTable ); - } - - /** - * Returns a List of properties of the controlled object - * that are controlled by this class. For example, - * "stringValue", or "selected". - */ - public static NSArray objectKeysTaken () - { - return objectKeysTaken; - } - - /** - * Returns the aspect that is considered primary - * or default. This is typically "value" or somesuch. - */ - public static String primaryAspect () - { - return ValueAspect; - } - - /** - * Returns whether this association can bind to the - * specified display group on the specified key for - * the specified aspect. - */ - public boolean canBindAspect ( - String anAspect, EODisplayGroup aDisplayGroup, String aKey) - { - return ( aspects.containsObject( anAspect ) ); - } - - /** - * Binds the specified aspect of this association to the - * specified key on the specified display group. - */ - public void bindAspect ( - String anAspect, EODisplayGroup aDisplayGroup, String aKey ) - { - if ( SourceAspect.equals( anAspect ) ) - { + JTable aTable = ((JTable) anObject); + aTable.addFocusListener(this); + aTable.setModel(new TableAssociationModel(this)); + // set up keyboard events for cut-copy: Ctrl-C, Ctrl-X + + // why did sun make this harder to use? + // aTable.getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ).put( + // KeyStroke.getKeyStroke( KeyEvent.VK_C, java.awt.Event.CTRL_MASK ), COPY); + // aTable.getActionMap().put(COPY, this); + + aTable.registerKeyboardAction(this, COPY, + KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), + JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + aTable.registerKeyboardAction(this, COPY, + KeyStroke.getKeyStroke(KeyEvent.VK_X, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), + JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + tableHeader = new SortedTableHeader(); + tableHeader.setColumnModel(aTable.getColumnModel()); + aTable.setTableHeader(tableHeader); + tableHeader.addMouseListener(new TableHeaderListener()); + pleaseIgnore = false; + selectionPaintedImmediately = false; + selectionTracking = false; + } + + /** + * Returns a List of aspect signatures whose contents correspond with the + * aspects list. Each element is a string whose characters represent a + * capability of the corresponding aspect. + * + * An empty signature "" means that the aspect can bind without needing a key. + * This implementation returns "A1M" for each element in the aspects array. + */ + public static NSArray aspectSignatures() { + return aspectSignatures; + } + + /** + * Returns a List that describes the aspects supported by this class. Each + * element in the list is the string name of the aspect. This implementation + * returns an empty list. + */ + public static NSArray aspects() { + return aspects; + } + + /** + * Returns a List of EOAssociation subclasses that, for the objects that are + * usable for this association, are less suitable than this association. + */ + public static NSArray associationClassesSuperseded() { + return new NSArray(); + } + + /** + * Returns whether this class can control the specified object. + */ + public static boolean isUsableWithObject(Object anObject) { + return (anObject instanceof JTable); + } + + /** + * Returns a List of properties of the controlled object that are controlled by + * this class. For example, "stringValue", or "selected". + */ + public static NSArray objectKeysTaken() { + return objectKeysTaken; + } + + /** + * Returns the aspect that is considered primary or default. This is typically + * "value" or somesuch. + */ + public static String primaryAspect() { + return ValueAspect; + } + + /** + * Returns whether this association can bind to the specified display group on + * the specified key for the specified aspect. + */ + public boolean canBindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) { + return (aspects.containsObject(anAspect)); + } + + /** + * Binds the specified aspect of this association to the specified key on the + * specified display group. + */ + public void bindAspect(String anAspect, EODisplayGroup aDisplayGroup, String aKey) { + if (SourceAspect.equals(anAspect)) { source = aDisplayGroup; } - super.bindAspect( anAspect, aDisplayGroup, aKey ); + super.bindAspect(anAspect, aDisplayGroup, aKey); } - /** - * Establishes a connection between this association - * and the controlled object. Subclasses should begin - * listening for events from their controlled object here. - */ - public void establishConnection () - { - if ( source == null ) - { - throw new WotonomyException( "No display group: " + - "please ensure that the TableColumnAssociation " + - "has a display group bound to the ValueAspect" ); - } - super.establishConnection(); - selectFromDisplayGroup(); - addAsListener(); - } - - /** - * Breaks the connection between this association and - * its object. Override to stop listening for events - * from the object. - */ - public void breakConnection () - { - removeAsListener(); - super.breakConnection(); - } - - protected void addAsListener() - { - component().getSelectionModel() - .addListSelectionListener( this ); - } - - protected void removeAsListener() - { - component().getSelectionModel() - .removeListSelectionListener( this ); - } - - /** - * Forces this association to cause the object to - * stop editing and validate the user's input. - * @return false if there were problems validating, - * or true to continue. - */ - public boolean endEditing () - { - // stop any cell editing - CellEditor editor = component().getCellEditor(); - if ( editor != null ) - { - return editor.stopCellEditing(); - } - return true; - } - - /** - * Called when either the selection or the contents - * of an associated display group have changed. - */ - public void subjectChanged () - { - if ( source != null ) - { - if ( source.contentsChanged() ) - { - removeAsListener(); - ((TableAssociationModel)component().getModel()). - fireTableDataChanged(); + /** + * Establishes a connection between this association and the controlled object. + * Subclasses should begin listening for events from their controlled object + * here. + */ + public void establishConnection() { + if (source == null) { + throw new WotonomyException("No display group: " + "please ensure that the TableColumnAssociation " + + "has a display group bound to the ValueAspect"); + } + super.establishConnection(); + selectFromDisplayGroup(); + addAsListener(); + } + + /** + * Breaks the connection between this association and its object. Override to + * stop listening for events from the object. + */ + public void breakConnection() { + removeAsListener(); + super.breakConnection(); + } + + protected void addAsListener() { + component().getSelectionModel().addListSelectionListener(this); + } + + protected void removeAsListener() { + component().getSelectionModel().removeListSelectionListener(this); + } + + /** + * Forces this association to cause the object to stop editing and validate the + * user's input. + * + * @return false if there were problems validating, or true to continue. + */ + public boolean endEditing() { + // stop any cell editing + CellEditor editor = component().getCellEditor(); + if (editor != null) { + return editor.stopCellEditing(); + } + return true; + } + + /** + * Called when either the selection or the contents of an associated display + * group have changed. + */ + public void subjectChanged() { + if (source != null) { + if (source.contentsChanged()) { + removeAsListener(); + ((TableAssociationModel) component().getModel()).fireTableDataChanged(); selectFromDisplayGroup(); - addAsListener(); - - // if we caused this change, do nothing - if ( pleaseIgnore ) - { - pleaseIgnore = false; - } - else // otherwise, update the sort indicator - { - tableHeader.repaint(); - - // cancel any cell editing - CellEditor editor = component().getCellEditor(); - if ( editor != null ) - { - editor.cancelCellEditing(); - } - } - } - else - if ( source.selectionChanged() ) - { - removeAsListener(); + addAsListener(); + + // if we caused this change, do nothing + if (pleaseIgnore) { + pleaseIgnore = false; + } else // otherwise, update the sort indicator + { + tableHeader.repaint(); + + // cancel any cell editing + CellEditor editor = component().getCellEditor(); + if (editor != null) { + editor.cancelCellEditing(); + } + } + } else if (source.selectionChanged()) { + removeAsListener(); selectFromDisplayGroup(); - addAsListener(); + addAsListener(); } } - } + } - private void selectFromDisplayGroup() - { + private void selectFromDisplayGroup() { JTable component = component(); int index; component.getSelectionModel().clearSelection(); - Enumeration e = - source.selectionIndexes().objectEnumerator(); - - while ( e.hasMoreElements() ) - { // add selections one-by-one to support non-contiguous - index = ((Number)e.nextElement()).intValue(); - component.getSelectionModel().addSelectionInterval( - index, index ); // adds one row + Enumeration e = source.selectionIndexes().objectEnumerator(); + + while (e.hasMoreElements()) { // add selections one-by-one to support non-contiguous + index = ((Number) e.nextElement()).intValue(); + component.getSelectionModel().addSelectionInterval(index, index); // adds one row } } // interface ListSelectionListener - public void valueChanged(ListSelectionEvent e) - { - if ( source != null ) - { - if ( selectionTracking || !e.getValueIsAdjusting() ) - { - int[] selectedIndices = component().getSelectedRows(); - final NSMutableArray indexList = new NSMutableArray(); - for ( int i = 0; i < selectedIndices.length; i++ ) - { - indexList.addObject( new Integer( selectedIndices[i] ) ); - } - - // invoke later so the component is repainted before - // any potentially lengthy second-order effects happen: - // this improves user-perceived responsiveness of big apps - Runnable select = new Runnable() - { - public void run() - { - pleaseIgnore = true; - source.setSelectionIndexes( indexList ); - } - }; - if ( selectionPaintedImmediately ) - { - EventQueue.invokeLater( select ); - } - else - { - select.run(); - } - } - } - } - - /** - * Determines whether the selection should be painted - * immediately after the user clicks and therefore - * before the children display group is updated. - * When the children group is bound to many associations - * or is bound to a master-detail association, updating - * the display group can take a perceptibly long time. - * This property defaults to false. - * @see #setSelectionPaintedImmediately - */ - public boolean isSelectionPaintedImmediately() - { - return selectionPaintedImmediately; - } - - /** - * Sets whether the selection should be painted immediately. - * Setting this property to true will let the table paint - * first before the display group is updated. - */ - public void setSelectionPaintedImmediately( boolean isImmediate ) - { - selectionPaintedImmediately = isImmediate; - } - - /** - * Determines whether the selection is actively tracking - * the selection as the user moves the mouse. - * If true, selection will not be updated while the - * list selection event returns true for isValueAdjusting(). - * This property defaults to false. - * @see #setSelectionTracking - */ - public boolean isSelectionTracking() - { - return selectionTracking; - } - - /** - * Sets whether the selection is actively tracking - * the selection as the user moves the mouse. - * Setting this property to true will update the display - * group with each change to the selection. - * This means that any tree selection listers will - * also be notified before the display group is updated - * and will have to invokeLater if they want to see the - * updated display group. - */ - public void setSelectionTracking( boolean isTracking ) - { - selectionTracking = isTracking; - } - - // convenience - private JTable component() - { - return (JTable) object(); - } + public void valueChanged(ListSelectionEvent e) { + if (source != null) { + if (selectionTracking || !e.getValueIsAdjusting()) { + int[] selectedIndices = component().getSelectedRows(); + final NSMutableArray indexList = new NSMutableArray(); + for (int i = 0; i < selectedIndices.length; i++) { + indexList.addObject(new Integer(selectedIndices[i])); + } + + // invoke later so the component is repainted before + // any potentially lengthy second-order effects happen: + // this improves user-perceived responsiveness of big apps + Runnable select = new Runnable() { + public void run() { + pleaseIgnore = true; + source.setSelectionIndexes(indexList); + } + }; + if (selectionPaintedImmediately) { + EventQueue.invokeLater(select); + } else { + select.run(); + } + } + } + } /** - * Copies the contents of the table to the clipboard as a tab-delimited string. - */ - public void copyToClipboard() - { - Toolkit toolkit = Toolkit.getDefaultToolkit(); - Clipboard clipboard = toolkit.getSystemClipboard(); - StringSelection selection = - new StringSelection( getTabDelimitedString() ); - clipboard.setContents( selection, selection ); - } + * Determines whether the selection should be painted immediately after the user + * clicks and therefore before the children display group is updated. When the + * children group is bound to many associations or is bound to a master-detail + * association, updating the display group can take a perceptibly long time. + * This property defaults to false. + * + * @see #setSelectionPaintedImmediately + */ + public boolean isSelectionPaintedImmediately() { + return selectionPaintedImmediately; + } /** - * Converts the contents of the table to a tab-delimited string. - * @return A String containing the text contents of the table. - */ - public String getTabDelimitedString() - { - StringBuffer result = new StringBuffer(64); - - TableModel model = component().getModel(); - int cols = model.getColumnCount(); - int rows = model.getRowCount(); - - Object o = null; - for ( int y = 0; y < rows; y++ ) - { - for ( int x = 0; x < cols; x++ ) - { - o = model.getValueAt( y, x ); - if ( o == null ) o = ""; - result.append( o ); - result.append( '\t' ); - } - result.append( '\n' ); - } - - return result.toString(); - } - - // interface ActionEventListener - - public void actionPerformed(ActionEvent evt) - { - String cmd = evt.getActionCommand(); - - if ( COPY.equals( cmd ) ) - { - copyToClipboard(); - return; - } - } - - /** - * Used to render the little triangle over the sorted column(s). - */ - class SortedTableHeader extends JTableHeader - { - public void paint(Graphics g) - { - super.paint( g ); - Rectangle r; - TableColumnAssociation association; - int size = columns.size(); - NSArray orderings; - if ( sortTarget != null ) - { - orderings = sortTarget.sortOrderings(); - } - else - { - orderings = source.sortOrderings(); - } - for ( int i = 0; i < size; i++ ) - { - r = getHeaderRect( component().convertColumnIndexToView( i ) ); - association = (TableColumnAssociation) columns.objectAtIndex( i ); - association.drawSortIndicator( r, g, orderings ); - } - } - } - - /** - * Used to listen for clicks on the table header. - */ - class TableHeaderListener extends MouseAdapter - { - public void mouseClicked( MouseEvent evt ) - { - EODisplayGroup displayGroup = sortTarget; - if ( displayGroup == null ) displayGroup = source; - - if ( evt.getClickCount() > 0 ) - { - int columnClicked = tableHeader.columnAtPoint( evt.getPoint() ); - if ( columnClicked != -1 ) - { - columnClicked = component().convertColumnIndexToModel( columnClicked ); - TableColumnAssociation association = (TableColumnAssociation) - columns.objectAtIndex( columnClicked ); - if ( association.isSortable() ) - { - NSMutableArray newOrder = - new NSMutableArray( displayGroup.sortOrderings() ); - - // click once = asc, twice = desc, thrice = clear - EOSortOrdering sortOrdering; - int index = association.getIndexOfMatchingOrdering( newOrder ); - if ( index == -1 ) sortOrdering = null; - else if ( index == 1 ) sortOrdering = association.getSortOrdering( false ); - else sortOrdering = association.getSortOrdering( true ); - - pleaseIgnore = true; - tableHeader.repaint(); - - // stop any cell editing - CellEditor editor = component().getCellEditor(); - if ( editor != null ) - { - editor.stopCellEditing(); - } - - // remove existing key - if ( index != 0 ) - { - newOrder.removeObjectAtIndex( Math.abs( index ) - 1 ); - } - - // put new key at front of list - if ( sortOrdering != null ) - { - newOrder.insertObjectAtIndex( sortOrdering, 0 ); - } - - displayGroup.setSortOrderings( newOrder ); - displayGroup.updateDisplayedObjects(); - } - } - } - } - } + * Sets whether the selection should be painted immediately. Setting this + * property to true will let the table paint first before the display group is + * updated. + */ + public void setSelectionPaintedImmediately(boolean isImmediate) { + selectionPaintedImmediately = isImmediate; + } /** - * Notifies of beginning of edit. - */ - public void focusGained(FocusEvent evt) - { + * Determines whether the selection is actively tracking the selection as the + * user moves the mouse. If true, selection will not be updated while the list + * selection event returns true for isValueAdjusting(). This property defaults + * to false. + * + * @see #setSelectionTracking + */ + public boolean isSelectionTracking() { + return selectionTracking; + } + + /** + * Sets whether the selection is actively tracking the selection as the user + * moves the mouse. Setting this property to true will update the display group + * with each change to the selection. This means that any tree selection listers + * will also be notified before the display group is updated and will have to + * invokeLater if they want to see the updated display group. + */ + public void setSelectionTracking(boolean isTracking) { + selectionTracking = isTracking; + } + + // convenience + private JTable component() { + return (JTable) object(); + } + + /** + * Copies the contents of the table to the clipboard as a tab-delimited string. + */ + public void copyToClipboard() { + Toolkit toolkit = Toolkit.getDefaultToolkit(); + Clipboard clipboard = toolkit.getSystemClipboard(); + StringSelection selection = new StringSelection(getTabDelimitedString()); + clipboard.setContents(selection, selection); + } + + /** + * Converts the contents of the table to a tab-delimited string. + * + * @return A String containing the text contents of the table. + */ + public String getTabDelimitedString() { + StringBuffer result = new StringBuffer(64); + + TableModel model = component().getModel(); + int cols = model.getColumnCount(); + int rows = model.getRowCount(); + + Object o = null; + for (int y = 0; y < rows; y++) { + for (int x = 0; x < cols; x++) { + o = model.getValueAt(y, x); + if (o == null) + o = ""; + result.append(o); + result.append('\t'); + } + result.append('\n'); + } + + return result.toString(); + } + + // interface ActionEventListener + + public void actionPerformed(ActionEvent evt) { + String cmd = evt.getActionCommand(); + + if (COPY.equals(cmd)) { + copyToClipboard(); + return; + } + } + + /** + * Used to render the little triangle over the sorted column(s). + */ + class SortedTableHeader extends JTableHeader { + public void paint(Graphics g) { + super.paint(g); + Rectangle r; + TableColumnAssociation association; + int size = columns.size(); + NSArray orderings; + if (sortTarget != null) { + orderings = sortTarget.sortOrderings(); + } else { + orderings = source.sortOrderings(); + } + for (int i = 0; i < size; i++) { + r = getHeaderRect(component().convertColumnIndexToView(i)); + association = (TableColumnAssociation) columns.objectAtIndex(i); + association.drawSortIndicator(r, g, orderings); + } + } + } + + /** + * Used to listen for clicks on the table header. + */ + class TableHeaderListener extends MouseAdapter { + public void mouseClicked(MouseEvent evt) { + EODisplayGroup displayGroup = sortTarget; + if (displayGroup == null) + displayGroup = source; + + if (evt.getClickCount() > 0) { + int columnClicked = tableHeader.columnAtPoint(evt.getPoint()); + if (columnClicked != -1) { + columnClicked = component().convertColumnIndexToModel(columnClicked); + TableColumnAssociation association = (TableColumnAssociation) columns.objectAtIndex(columnClicked); + if (association.isSortable()) { + NSMutableArray newOrder = new NSMutableArray(displayGroup.sortOrderings()); + + // click once = asc, twice = desc, thrice = clear + EOSortOrdering sortOrdering; + int index = association.getIndexOfMatchingOrdering(newOrder); + if (index == -1) + sortOrdering = null; + else if (index == 1) + sortOrdering = association.getSortOrdering(false); + else + sortOrdering = association.getSortOrdering(true); + + pleaseIgnore = true; + tableHeader.repaint(); + + // stop any cell editing + CellEditor editor = component().getCellEditor(); + if (editor != null) { + editor.stopCellEditing(); + } + + // remove existing key + if (index != 0) { + newOrder.removeObjectAtIndex(Math.abs(index) - 1); + } + + // put new key at front of list + if (sortOrdering != null) { + newOrder.insertObjectAtIndex(sortOrdering, 0); + } + + displayGroup.setSortOrderings(newOrder); + displayGroup.updateDisplayedObjects(); + } + } + } + } + } + + /** + * Notifies of beginning of edit. + */ + public void focusGained(FocusEvent evt) { Object o; EODisplayGroup displayGroup; - Enumeration e = aspects().objectEnumerator(); - while ( e.hasMoreElements() ) - { - displayGroup = - displayGroupForAspect( e.nextElement().toString() ); - if ( displayGroup != null ) - { - displayGroup.associationDidBeginEditing( this ); + Enumeration e = aspects().objectEnumerator(); + while (e.hasMoreElements()) { + displayGroup = displayGroupForAspect(e.nextElement().toString()); + if (displayGroup != null) { + displayGroup.associationDidBeginEditing(this); } } - } + } /** - * Updates object on focus lost and notifies of end of edit. - */ - public void focusLost(FocusEvent evt) - { - if ( ! component().isEditing() ) - { - Object o; - EODisplayGroup displayGroup; - Enumeration e = aspects().objectEnumerator(); - while ( e.hasMoreElements() ) - { - displayGroup = - displayGroupForAspect( e.nextElement().toString() ); - if ( displayGroup != null ) - { - displayGroup.associationDidEndEditing( this ); - } - } - } - } + * Updates object on focus lost and notifies of end of edit. + */ + public void focusLost(FocusEvent evt) { + if (!component().isEditing()) { + Object o; + EODisplayGroup displayGroup; + Enumeration e = aspects().objectEnumerator(); + while (e.hasMoreElements()) { + displayGroup = displayGroupForAspect(e.nextElement().toString()); + if (displayGroup != null) { + displayGroup.associationDidEndEditing(this); + } + } + } + } /** - * Used as the model for the controlled table. - * Package access so TableColumnAssociation can recognize - * it and use the addColumnAssociation() method. - * Extends AbstractTableModel just so we get event - * broadcasting for free. - */ - static class TableAssociationModel extends AbstractTableModel - { + * Used as the model for the controlled table. Package access so + * TableColumnAssociation can recognize it and use the addColumnAssociation() + * method. Extends AbstractTableModel just so we get event broadcasting for + * free. + */ + static class TableAssociationModel extends AbstractTableModel { private TableAssociation parent; - private TableAssociationModel( TableAssociation aParent ) - { + private TableAssociationModel(TableAssociation aParent) { parent = aParent; } - - public TableAssociation getAssociation() - { - return parent; - } + + public TableAssociation getAssociation() { + return parent; + } /** - * Adds the column to the list of ColumnAssociations, - * and adds the corresponding column to the table - * at the next available index, setting the value of - * the column's model index accordingly. - * Establishes connection if no columns are currently - * associated. - */ - public void addColumnAssociation( - TableColumnAssociation aColumnAssociation ) - { - // establish connection if necessary - if ( parent.columns.size() == 0 ) - { - parent.establishConnection(); - } - + * Adds the column to the list of ColumnAssociations, and adds the corresponding + * column to the table at the next available index, setting the value of the + * column's model index accordingly. Establishes connection if no columns are + * currently associated. + */ + public void addColumnAssociation(TableColumnAssociation aColumnAssociation) { + // establish connection if necessary + if (parent.columns.size() == 0) { + parent.establishConnection(); + } + int newIndex = parent.columns.count(); - parent.columns.add( aColumnAssociation ); + parent.columns.add(aColumnAssociation); // add column to table TableColumn column = (TableColumn) aColumnAssociation.object(); - column.setModelIndex( newIndex ); - parent.component().addColumn( column ); - + column.setModelIndex(newIndex); + parent.component().addColumn(column); + } /** - * Removes the column from the list of ColumnAssociations, - * and removes the corresponding column from the table. - * Breaks connection if no more columns are associated. - */ - public void removeColumnAssociation( - TableColumnAssociation aColumnAssociation ) - { - int index = parent.columns.indexOfIdenticalObject( aColumnAssociation ); - if ( index == NSArray.NotFound ) return; - - parent.columns.removeObjectAtIndex( index ); + * Removes the column from the list of ColumnAssociations, and removes the + * corresponding column from the table. Breaks connection if no more columns are + * associated. + */ + public void removeColumnAssociation(TableColumnAssociation aColumnAssociation) { + int index = parent.columns.indexOfIdenticalObject(aColumnAssociation); + if (index == NSArray.NotFound) + return; + + parent.columns.removeObjectAtIndex(index); // remove column from table TableColumn column = (TableColumn) aColumnAssociation.object(); - parent.component().removeColumn( column ); - - // break connection if necessary - if ( parent.columns.size() == 0 ) - { - parent.breakConnection(); - } + parent.component().removeColumn(column); + + // break connection if necessary + if (parent.columns.size() == 0) { + parent.breakConnection(); + } } - public int getRowCount() - { - if ( parent.source == null ) return 0; + public int getRowCount() { + if (parent.source == null) + return 0; return parent.source.displayedObjects().count(); } - public int getColumnCount() - { + public int getColumnCount() { return parent.columns.count(); } /** - * Attempts to retrieve the header value from the specified column, - * or returns " " if the value is null. - */ - public String getColumnName(int columnIndex) - { - TableColumnAssociation association = (TableColumnAssociation) - parent.columns.objectAtIndex( columnIndex ); - Object value = ((TableColumn)association.object()).getHeaderValue(); - if ( value != null ) return value.toString(); - return " "; + * Attempts to retrieve the header value from the specified column, or returns " + * " if the value is null. + */ + public String getColumnName(int columnIndex) { + TableColumnAssociation association = (TableColumnAssociation) parent.columns.objectAtIndex(columnIndex); + Object value = ((TableColumn) association.object()).getHeaderValue(); + if (value != null) + return value.toString(); + return " "; } /** - * Returns the class of the first item in the - * display group bound to the column. - */ - public Class getColumnClass(int columnIndex) - { - Object value; - int count = getRowCount(); - for( int i = 0; i < count; i++ ) - { //First row in column is null find one that is not. - value = ((TableColumnAssociation)parent.columns. - objectAtIndex( columnIndex ) ).valueAtIndex( i ); - if ( value != null ) return value.getClass(); - } - return Object.class; + * Returns the class of the first item in the display group bound to the column. + */ + public Class getColumnClass(int columnIndex) { + Object value; + int count = getRowCount(); + for (int i = 0; i < count; i++) { // First row in column is null find one that is not. + value = ((TableColumnAssociation) parent.columns.objectAtIndex(columnIndex)).valueAtIndex(i); + if (value != null) + return value.getClass(); + } + return Object.class; } - /** - * Calls the column association's isEditableAtRow method. - */ - public boolean isCellEditable(int rowIndex, - int columnIndex) - { - return - ((TableColumnAssociation)parent.columns.objectAtIndex( - columnIndex ) ).isEditableAtRow( rowIndex ); + /** + * Calls the column association's isEditableAtRow method. + */ + public boolean isCellEditable(int rowIndex, int columnIndex) { + return ((TableColumnAssociation) parent.columns.objectAtIndex(columnIndex)).isEditableAtRow(rowIndex); } - /** - * Calls the column association's valueAtIndex method. - */ - public Object getValueAt(int rowIndex, - int columnIndex) - { - return - ((TableColumnAssociation)parent.columns.objectAtIndex( - columnIndex ) ).valueAtIndex( rowIndex ); + /** + * Calls the column association's valueAtIndex method. + */ + public Object getValueAt(int rowIndex, int columnIndex) { + return ((TableColumnAssociation) parent.columns.objectAtIndex(columnIndex)).valueAtIndex(rowIndex); } - /** - * Calls the column association's setValueAtIndex method. - */ - public void setValueAt(Object aValue, - int rowIndex, - int columnIndex) - { - Object existingValue = getValueAt( rowIndex, columnIndex ); - - // don't update display group if value is the same as before - if ( aValue == existingValue ) return; // handles null case - if ( existingValue != null ) // both are not null - { - Object newValue = aValue; - - // if different types - if ( newValue.getClass() != existingValue.getClass() ) - { - // convert to string since most editors do anyway - newValue = newValue.toString(); - existingValue = existingValue.toString(); - } - if ( newValue.equals( existingValue ) ) - { - // same value - do nothing - return; - } - } - - ((TableColumnAssociation)parent.columns.objectAtIndex( - columnIndex ) ).setValueAtIndex( aValue, rowIndex ); + /** + * Calls the column association's setValueAtIndex method. + */ + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + Object existingValue = getValueAt(rowIndex, columnIndex); + + // don't update display group if value is the same as before + if (aValue == existingValue) + return; // handles null case + if (existingValue != null) // both are not null + { + Object newValue = aValue; + + // if different types + if (newValue.getClass() != existingValue.getClass()) { + // convert to string since most editors do anyway + newValue = newValue.toString(); + existingValue = existingValue.toString(); + } + if (newValue.equals(existingValue)) { + // same value - do nothing + return; + } + } + + ((TableColumnAssociation) parent.columns.objectAtIndex(columnIndex)).setValueAtIndex(aValue, rowIndex); } } @@ -807,121 +672,106 @@ public class TableAssociation extends EOAssociation } /* - * $Log$ - * Revision 1.2 2006/02/18 23:19:05 cgruber - * Update imports and maven dependencies. + * $Log$ Revision 1.2 2006/02/18 23:19:05 cgruber Update imports and maven + * dependencies. * - * Revision 1.1 2006/02/16 13:22:22 cgruber - * Check in all sources in eclipse-friendly maven-enabled packages. + * Revision 1.1 2006/02/16 13:22:22 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.31 2003/08/06 23:07:52 chochos - * general code cleanup (mostly, removing unused imports) + * Revision 1.31 2003/08/06 23:07:52 chochos general code cleanup (mostly, + * removing unused imports) * - * Revision 1.30 2002/11/16 16:33:31 mpowers - * Now using platform-specific accelerator key for shortcuts. + * Revision 1.30 2002/11/16 16:33:31 mpowers Now using platform-specific + * accelerator key for shortcuts. * - * Revision 1.29 2002/05/24 14:41:29 mpowers - * Throwing an exception for clarity. + * Revision 1.29 2002/05/24 14:41:29 mpowers Throwing an exception for clarity. * - * Revision 1.28 2002/04/10 21:20:04 mpowers - * Better handling for tree nodes when working with editing contexts. - * Better handling for invalidation. No longer broadcasting events - * when nodes have not been "registered" in the tree. + * Revision 1.28 2002/04/10 21:20:04 mpowers Better handling for tree nodes when + * working with editing contexts. Better handling for invalidation. No longer + * broadcasting events when nodes have not been "registered" in the tree. * - * Revision 1.27 2002/03/05 23:18:28 mpowers - * Added documentation. - * Added isSelectionPaintedImmediate and isSelectionTracking attributes - * to TableAssociation. - * Added getTableAssociation to TableColumnAssociation. + * Revision 1.27 2002/03/05 23:18:28 mpowers Added documentation. Added + * isSelectionPaintedImmediate and isSelectionTracking attributes to + * TableAssociation. Added getTableAssociation to TableColumnAssociation. * - * Revision 1.25 2002/03/04 22:49:53 mpowers - * Now working with TreeColumnAssociation to delegate sorting behavior. + * Revision 1.25 2002/03/04 22:49:53 mpowers Now working with + * TreeColumnAssociation to delegate sorting behavior. * - * Revision 1.23 2002/03/04 03:58:17 mpowers - * Refined table header click behavior. + * Revision 1.23 2002/03/04 03:58:17 mpowers Refined table header click + * behavior. * - * Revision 1.22 2002/03/01 23:41:39 mpowers - * Added facility to get table association from model. + * Revision 1.22 2002/03/01 23:41:39 mpowers Added facility to get table + * association from model. * - * Revision 1.21 2002/03/01 20:41:22 mpowers - * Cleaned up unused code. + * Revision 1.21 2002/03/01 20:41:22 mpowers Cleaned up unused code. * - * Revision 1.20 2002/03/01 15:42:00 mpowers - * Table column headers now always show their sort indicator. - * A third table-column click clears the sort for that column. + * Revision 1.20 2002/03/01 15:42:00 mpowers Table column headers now always + * show their sort indicator. A third table-column click clears the sort for + * that column. * - * Revision 1.19 2002/02/28 23:01:39 mpowers - * TableColumnAssociations add and remove themselves from the TableAssociation - * when their connection is established and broken respectively. - * TableAssociations now break connection if they have no column associations. + * Revision 1.19 2002/02/28 23:01:39 mpowers TableColumnAssociations add and + * remove themselves from the TableAssociation when their connection is + * established and broken respectively. TableAssociations now break connection + * if they have no column associations. * - * Revision 1.18 2002/02/28 22:45:27 mpowers - * Now registers as editing association when table gets focus, so that - * endEditing can appropriate commit any table cell editors. + * Revision 1.18 2002/02/28 22:45:27 mpowers Now registers as editing + * association when table gets focus, so that endEditing can appropriate commit + * any table cell editors. * - * Revision 1.17 2001/10/26 20:01:50 mpowers - * We're again cancelling instead of stopping editing on subjectChanged. - * I believe that the introduction of NSRunLoop has allowed us to return - * to the correct behavior. + * Revision 1.17 2001/10/26 20:01:50 mpowers We're again cancelling instead of + * stopping editing on subjectChanged. I believe that the introduction of + * NSRunLoop has allowed us to return to the correct behavior. * - * Revision 1.16 2001/09/14 13:40:26 mpowers - * User-initiated selection changes are now handled on the next event loop - * so that the component repaints the new selection before any potentially - * lengthy logic is triggered by the selection change. + * Revision 1.16 2001/09/14 13:40:26 mpowers User-initiated selection changes + * are now handled on the next event loop so that the component repaints the new + * selection before any potentially lengthy logic is triggered by the selection + * change. * - * Revision 1.15 2001/07/25 15:03:01 mpowers - * getColumnName now checks for a column header value before defaulting " ". + * Revision 1.15 2001/07/25 15:03:01 mpowers getColumnName now checks for a + * column header value before defaulting " ". * - * Revision 1.14 2001/06/05 19:09:25 mpowers - * Fixed broken build. + * Revision 1.14 2001/06/05 19:09:25 mpowers Fixed broken build. * - * Revision 1.13 2001/06/05 19:08:12 mpowers - * Better determination of column class. Previously, if the first object - * was null, Object.class was used. Now we get the first non-null object. + * Revision 1.13 2001/06/05 19:08:12 mpowers Better determination of column + * class. Previously, if the first object was null, Object.class was used. Now + * we get the first non-null object. * - * Revision 1.12 2001/05/02 17:39:01 mpowers - * Now selects from display group after initial population. + * Revision 1.12 2001/05/02 17:39:01 mpowers Now selects from display group + * after initial population. * - * Revision 1.11 2001/03/29 23:05:22 mpowers - * Fixes for editing table cells. + * Revision 1.11 2001/03/29 23:05:22 mpowers Fixes for editing table cells. * - * Revision 1.10 2001/03/09 22:09:22 mpowers - * Now better handling jdk1.1 for rendering the column header. + * Revision 1.10 2001/03/09 22:09:22 mpowers Now better handling jdk1.1 for + * rendering the column header. * - * Revision 1.9 2001/02/27 02:10:38 mpowers - * No longer updating values to the display group if the value - * has not changed. + * Revision 1.9 2001/02/27 02:10:38 mpowers No longer updating values to the + * display group if the value has not changed. * - * Revision 1.8 2001/02/17 16:52:05 mpowers - * Changes in imports to support building with jdk1.1 collections. + * Revision 1.8 2001/02/17 16:52:05 mpowers Changes in imports to support + * building with jdk1.1 collections. * - * Revision 1.7 2001/02/16 17:47:17 mpowers - * Now cancelling any cell editing on subjectChanged(). + * Revision 1.7 2001/02/16 17:47:17 mpowers Now cancelling any cell editing on + * subjectChanged(). * - * Revision 1.6 2001/01/12 19:11:56 mpowers - * Fixed table column click sorting. + * Revision 1.6 2001/01/12 19:11:56 mpowers Fixed table column click sorting. * - * Revision 1.5 2001/01/12 17:20:30 mpowers - * Moved EOSortOrdering creation to ColumnAssociation. + * Revision 1.5 2001/01/12 17:20:30 mpowers Moved EOSortOrdering creation to + * ColumnAssociation. * - * Revision 1.4 2001/01/11 21:55:57 mpowers - * Implemented sort indicator for table column headers. + * Revision 1.4 2001/01/11 21:55:57 mpowers Implemented sort indicator for table + * column headers. * - * Revision 1.3 2001/01/11 20:34:26 mpowers - * Implemented EOSortOrdering and added support in framework. - * Added header-click to sort table columns. + * Revision 1.3 2001/01/11 20:34:26 mpowers Implemented EOSortOrdering and added + * support in framework. Added header-click to sort table columns. * - * Revision 1.2 2001/01/08 20:40:51 mpowers - * JTables in 1.3 clear their selection when the data model changes, - * which sends a list selection event. We now reset the selection again - * after the data changes so we're compatible across 1.2 and 1.3. + * Revision 1.2 2001/01/08 20:40:51 mpowers JTables in 1.3 clear their selection + * when the data model changes, which sends a list selection event. We now reset + * the selection again after the data changes so we're compatible across 1.2 and + * 1.3. * - * Revision 1.1.1.1 2000/12/21 15:49:00 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:49:00 mpowers Contributing wotonomy. * - * Revision 1.7 2000/12/20 16:25:41 michael - * Added log to all files. + * Revision 1.7 2000/12/20 16:25:41 michael Added log to all files. * * */ - -- cgit v1.2.3