/* Wotonomy: OpenStep design patterns for pure Java applications. Copyright (C) 2000 Intersect Software Corporation This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see http://www.gnu.org */ package net.wotonomy.ui.swing; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import net.wotonomy.foundation.NSArray; import net.wotonomy.foundation.internal.ValueConverter; import net.wotonomy.ui.EOAssociation; import net.wotonomy.ui.EODisplayGroup; import net.wotonomy.ui.swing.components.RadioButtonPanel; /** * RadioPanelAssociation binds RadioButtonPanels to display groups. It works * exactly like a ComboBoxAssociation. Bindings are: * * * @author michael@mpowers.net * @author $Author: cgruber $ * @version $Revision: 904 $ */ public class RadioPanelAssociation extends EOAssociation implements ActionListener { static final NSArray aspects = new NSArray( new Object[] { TitlesAspect, ValueAspect, ObjectsAspect, EnabledAspect }); static final NSArray aspectSignatures = new NSArray(new Object[] { AttributeToOneAspectSignature, AttributeToOneAspectSignature, AttributeToOneAspectSignature, AttributeToOneAspectSignature }); static final NSArray objectKeysTaken = new NSArray(new Object[] { "text" }); /** * Constructor specifying the object to be controlled by this association. Does * not establish connection. */ public RadioPanelAssociation(Object anObject) { super(anObject); } /** * 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 RadioButtonPanel); } /** * 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)); } /** * Establishes a connection between this association and the controlled object. * Subclasses should begin listening for events from their controlled object * here. */ public void establishConnection() { super.establishConnection(); // prepopulate titles EODisplayGroup displayGroup = displayGroupForAspect(TitlesAspect); if (displayGroup != null) { String key = displayGroupKeyForAspect(TitlesAspect); populateTitles(displayGroup, key); } populateValue(); addAsListener(); } protected void addAsListener() { component().addActionListener(this); } /** * 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 removeAsListener() { component().removeActionListener(this); } /** * Called when either the selection or the contents of an associated display * group have changed. */ public void subjectChanged() { removeAsListener(); RadioButtonPanel component = component(); EODisplayGroup displayGroup; String key; // titles aspect displayGroup = displayGroupForAspect(TitlesAspect); if (displayGroup != null) { // if backing group has changed if (displayGroup.contentsChanged()) { key = displayGroupKeyForAspect(TitlesAspect); populateTitles(displayGroup, key); } } // value aspect populateValue(); // enabled aspect displayGroup = displayGroupForAspect(EnabledAspect); if (displayGroup != null) { key = displayGroupKeyForAspect(EnabledAspect); Object value = displayGroup.selectedObjectValueForKey(key); Boolean converted = null; if (value != null) { converted = (Boolean) ValueConverter.convertObjectToClass(value, Boolean.class); } if (converted == null) converted = Boolean.FALSE; if (converted.booleanValue() != component.isEnabled()) { component.setEnabled(converted.booleanValue()); } } addAsListener(); } /** * Called to repopulate the title list from the specified display group. */ protected void populateTitles(EODisplayGroup displayGroup, String key) { Object value; int count = displayGroup.displayedObjects().count(); String[] titles = new String[count]; for (int i = 0; i < count; i++) { value = displayGroup.valueForObjectAtIndex(i, key); if (value != null) { titles[i] = value.toString(); } else { titles[i] = ""; } } component().setLabels(titles); } /** * Called to populate the value from the display group. */ protected void populateValue() { RadioButtonPanel component = component(); EODisplayGroup displayGroup; String key; // value aspect displayGroup = displayGroupForAspect(ValueAspect); if (displayGroup != null) { key = displayGroupKeyForAspect(ValueAspect); component.setEnabled(displayGroup.enabledToSetSelectedObjectValueForKey(key)); Object value = displayGroup.selectedObjectValueForKey(key); // objects aspect EODisplayGroup objectsDisplayGroup = displayGroupForAspect(ObjectsAspect); if ((objectsDisplayGroup != null) && (value != null)) { String objectKey = displayGroupKeyForAspect(ObjectsAspect); Object match; int index = NSArray.NotFound; int count = objectsDisplayGroup.displayedObjects().count(); for (int i = 0; i < count; i++) { match = objectsDisplayGroup.valueForObjectAtIndex(i, objectKey); if (value.equals(match)) { index = i; } } if (index == NSArray.NotFound) { if (component.getValue() != null) { component.setValue(null); } } else { String[] titles = component().getLabels(); component.setValue(titles[index]); } } else { if (value != null) value = value.toString(); component.setValue((String) value); } } } /** * 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() { return writeValueToDisplayGroup(); } /** * Writes the value currently in the component to the selected object in the * display group bound to the value aspect. * * @return false if there were problems validating, or true to continue. */ protected boolean writeValueToDisplayGroup() { RadioButtonPanel component = component(); EODisplayGroup displayGroup; String key; // selected title aspect displayGroup = displayGroupForAspect(ValueAspect); if (displayGroup != null) { key = displayGroupKeyForAspect(ValueAspect); Object value = null; // selected object aspect, if any EODisplayGroup objectsGroup = displayGroupForAspect(ObjectsAspect); if (objectsGroup != null) { String objectKey = displayGroupKeyForAspect(ObjectsAspect); String selectedValue = component.getValue(); if (selectedValue != null) { String[] titles = component.getLabels(); int index = -1; for (int i = 0; i < titles.length; i++) { if (selectedValue.equals(titles[i])) { index = i; } } if (index != -1) { value = objectsGroup.valueForObjectAtIndex(index, objectKey); } } } else // just use the selected item { value = component.getValue(); } return displayGroup.setSelectedObjectValue(value, key); } return false; } // interface ActionListener /** * Updates object on action performed. */ public void actionPerformed(ActionEvent evt) { writeValueToDisplayGroup(); } // convenience private RadioButtonPanel component() { return (RadioButtonPanel) object(); } } /* * $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.4 2004/01/28 18:34:57 mpowers Better handling for enabling. Now * respecting enabledToSetSelectedObjectValueForKey from display group. * * Revision 1.3 2003/08/06 23:07:52 chochos general code cleanup (mostly, * removing unused imports) * * Revision 1.2 2001/02/16 17:48:07 mpowers Populating titles or data not longer * marks target object as changed. * * Revision 1.1.1.1 2000/12/21 15:48:52 mpowers Contributing wotonomy. * * Revision 1.3 2000/12/20 16:25:41 michael Added log to all files. * * */