001: /*************************************************************************
002: * *
003: * 1) This source code file, in unmodified form, and compiled classes *
004: * derived from it can be used and distributed without restriction, *
005: * including for commercial use. (Attribution is not required *
006: * but is appreciated.) *
007: * *
008: * 2) Modified versions of this file can be made and distributed *
009: * provided: the modified versions are put into a Java package *
010: * different from the original package, edu.hws; modified *
011: * versions are distributed under the same terms as the original; *
012: * and the modifications are documented in comments. (Modification *
013: * here does not include simply making subclasses that belong to *
014: * a package other than edu.hws, which can be done without any *
015: * restriction.) *
016: * *
017: * David J. Eck *
018: * Department of Mathematics and Computer Science *
019: * Hobart and William Smith Colleges *
020: * Geneva, New York 14456, USA *
021: * Email: eck@hws.edu WWW: http://math.hws.edu/eck/ *
022: * *
023: *************************************************************************/package edu.hws.jcm.awt;
024:
025: import edu.hws.jcm.data.*;
026: import java.awt.*;
027: import java.awt.event.*;
028:
029: /**
030: * A JCMPanel is a Panel with an associated Controller. When an InputObject or
031: * Computable is added to the JCMPanel, it is automatically added to the controller.
032: * When a sub-JCMPanel is added, the Controller of the sub-panel is "attatched" to
033: * the controller of the main panel so that objects in the sub-panel will also
034: * be controlled by the Controller of the main panel. So, if you build an
035: * interface entirely from JCMPanels, a lot of the control setup is done
036: * automatically. Note that to make this work, you will need
037: * a "mainPanel" that fills the entire window or applet (or at least the part that
038: * holds JCM components). You should also call the gatherInputs() method of
039: * the main JCMPanel after it is completely set up, so that changes in input objects
040: * will cause the panel's controller to be notified, or, alternatively, you
041: * can register the Controller by hand with InputObjects so that the
042: * Controller will be notified when they change.
043: *
044: * <p>The disadvantage of this is that all the data used in the interface is recomputed,
045: * even if the input objects that they depend on have not changed. For example.
046: * if the user changes the value in a VarialbleInput, all the points on a graph
047: * will be recomputed even if the function has not changed. The alternative is
048: * to use regular Panels for all or part of the interface and configure some
049: * Controllers by hand.
050: *
051: */
052: public class JCMPanel extends Panel {
053:
054: private int insetGap; // Size of gap, in pixels, around the edges of the
055: // Panel, where the background color shows through.
056:
057: private Controller controller; // The controller associated with this panel.
058:
059: /**
060: * Create a JCMPanel that uses a given layout manager.
061: *
062: * @param layout layout manager to use. (This could be null.)
063: */
064: public JCMPanel(LayoutManager layout) {
065: enableEvents(ContainerEvent.CONTAINER_EVENT_MASK);
066: setLayout(layout);
067: }
068:
069: /**
070: * Create a JCMPanel that uses a BorderLayout with horizontal and veritcal
071: * gaps of 3 pixels.
072: */
073: public JCMPanel() {
074: this (3);
075: }
076:
077: /**
078: * Create a JCMPanel that uses a BorderLayout with horizontal and vertical
079: * gaps of "gap" pixels.
080: *
081: * @param gap inset gap to use.
082: */
083: public JCMPanel(int gap) {
084: this (new BorderLayout(gap, gap));
085: }
086:
087: /**
088: * Create a JCMPanel that uses a GridLayout with the specified number of rows
089: * and columns and with horizontal and veritcal gaps of 3 pixels between components.
090: *
091: * @param rows number of rows in the GridLayout.
092: * @param columns number of columns in the GridLayout.
093: */
094: public JCMPanel(int rows, int columns) {
095: this (rows, columns, 3);
096: }
097:
098: /**
099: * Create a JCMPanel that uses a GridLayout with the specified number of rows
100: * and columns and with horizontal and vertical gaps of "gap" pixels.
101: *
102: * @param rows number of rows in the GridLayout.
103: * @param columns number of columns in the GridLayout.
104: * @param gap number of pixels between rows and columns
105: */
106: public JCMPanel(int rows, int columns, int gap) {
107: this (new GridLayout(rows, columns, gap, gap));
108: }
109:
110: /**
111: * Set the size of the "Insets" for this JCMPanel. This is the gap, in pixels, around the edges of the
112: * Panel, where the background color shows through.
113: *
114: * @param x inset gap to use.
115: */
116: public void setInsetGap(int x) {
117: insetGap = x;
118: }
119:
120: /**
121: * Called by the system to determine how much of a gap to leave
122: * on each edge of the panel. Not meant to be called directly
123: */
124: public Insets getInsets() {
125: return new Insets(insetGap, insetGap, insetGap, insetGap);
126: }
127:
128: /**
129: * Return the controller associated with this JCMPanel.
130: */
131: public Controller getController() {
132: if (controller == null)
133: controller = new Controller();
134: return controller;
135: }
136:
137: /**
138: * This method will set all the input objects in this JCMPanel
139: * and in sub-JCMPanels, as well as any other input objects that have been
140: * added to the panels' Controllers, to notify the Controller of this JCMPanel
141: * when they change. It does this by calling setOnUserAction(c) -- or
142: * a corresponding method -- for each input object c. This is meant to
143: * be used, ordinarily, at the end of an applet's init() method, as
144: * an alternative to adding each of the input objects to the controller
145: * by hand.
146: */
147: public void gatherInputs() {
148: Controller c = getController();
149: c.notifyControllerOnChange(c);
150: }
151:
152: /**
153: * Called by the system when a component is added to or removed from
154: * this panel. This takes care of automatically adding and removing
155: * things from this Panel's Controller. This is not meant to be called directly
156: */
157: public void processContainerEvent(ContainerEvent evt) {
158: Component child = evt.getChild();
159: if (child instanceof JCMPanel) {
160: if (evt.getID() == ContainerEvent.COMPONENT_ADDED)
161: getController().add(((JCMPanel) child).getController());
162: else if (evt.getID() == ContainerEvent.COMPONENT_REMOVED)
163: getController().remove(
164: ((JCMPanel) child).getController());
165: } else if (child instanceof Computable
166: || child instanceof InputObject) {
167: if (evt.getID() == ContainerEvent.COMPONENT_ADDED)
168: getController().add(child);
169: else if (evt.getID() == ContainerEvent.COMPONENT_REMOVED)
170: getController().remove(child);
171: }
172: }
173: } // end class JCMPanel
|