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 java.util.Vector;
026: import edu.hws.jcm.data.Value;
027:
028: /**
029: * A Tie associates several Tieable objects. When the check() mehtod of the
030: * Tie is called, it determines which of the Tieables has the largest serial number.
031: * It then tells each Tieable to synchronize with that object. Ordinarily, the
032: * Tie is added to a Controller, which is responsible for calling the Tie's
033: * check() method.
034: *
035: * <p>This is meant to be used, for example, to Tie together two InputObjects to synchronize
036: * the values that they represent. For example, you might want a VariableSlider
037: * and a VariableInput to be alternative ways of inputting the same value. If so,
038: * you can put them in a Tie and add that Tie to any Controller that is set to
039: * respond to changes in the VariableSlider or VariableInput.
040: * The x- and y- variables of a MouseTracker are also Tieable objects, so you
041: * can synchronize the values of two MouseTrackers (in different CoordinateRects,
042: * presumably) and you can synchronize the value of a MouseTracker variable with
043: * a VariableInput or VariableSlider.
044: *
045: * <p>CoordinateRects and LimitControlPanels are also Tieable (to each other -- not
046: * to Value objects). This is used to allow the LimitControlPanel to synchronize
047: * with the Limits on the CoordinateRects that it controls. It could also
048: * synchronize the Limits on two CoordinateRects, even in the absense of a
049: * LimitControlPanel.
050: *
051: * @author David Eck
052: */
053: public class Tie {
054:
055: /**
056: * The Tieables in this Tie.
057: */
058: protected Vector items = new Vector(2);
059:
060: /**
061: * Create a Tie, initially containing no objects.
062: */
063: public Tie() {
064: }
065:
066: /**
067: * Create a Tie initally containing only the object item.
068: * item should be non-null.
069: *
070: * @param item the only initial item in this tieable.
071: */
072: public Tie(Tieable item) {
073: add(item);
074: }
075:
076: /**
077: * Create a Tie initially containing item1 and item2.
078: * The items should be non-null. The items will be
079: * synced with each other at the time the Tie is created.
080: */
081: public Tie(Tieable item1, Tieable item2) {
082: add(item1);
083: add(item2);
084: }
085:
086: /**
087: * Add item to the tie, and sync it with the items that are
088: * already in the Tie. It should be non-null. Note that synchronization
089: * of the objects is forced even if they all have the same serial number,
090: * since the values might not be the same when they are first added to
091: * the Tie.
092: */
093: public void add(Tieable item) {
094: if (item != null) {
095: items.addElement(item);
096: forcecheck();
097: }
098: }
099:
100: /**
101: * If this Tie contains more than one item, find the newest
102: * one and sync all the items with that item. If the serial
103: * numbers of all the items are already the same, nothing is
104: * done.
105: */
106: public void check() {
107: int top = items.size();
108: if (top < 2)
109: return;
110: long maxSerialNumber = ((Tieable) items.elementAt(0))
111: .getSerialNumber();
112: int indexOfMax = 0;
113: boolean outOfSync = false;
114: for (int i = 1; i < top; i++) {
115: long sn = ((Tieable) items.elementAt(i)).getSerialNumber();
116: if (sn != maxSerialNumber)
117: outOfSync = true;
118: if (sn > maxSerialNumber) {
119: maxSerialNumber = sn;
120: indexOfMax = i;
121: }
122: }
123: if (!outOfSync) // if serialnumbers are the same, no sync is necessary.
124: return;
125: Tieable newest = (Tieable) items.elementAt(indexOfMax);
126: for (int i = 0; i < top; i++)
127: ((Tieable) items.elementAt(i)).sync(this , newest);
128: }
129:
130: private void forcecheck() { // Synchronize the items in this Tie, even if serial numbers are the same.
131: int top = items.size();
132: if (top < 2)
133: return;
134: long maxSerialNumber = ((Tieable) items.elementAt(0))
135: .getSerialNumber();
136: int indexOfMax = 0;
137: boolean outOfSync = false;
138: for (int i = 1; i < top; i++) {
139: long sn = ((Tieable) items.elementAt(i)).getSerialNumber();
140: if (sn != maxSerialNumber)
141: outOfSync = true;
142: if (sn > maxSerialNumber) {
143: maxSerialNumber = sn;
144: indexOfMax = i;
145: }
146: }
147: Tieable newest = (Tieable) items.elementAt(indexOfMax);
148: for (int i = 0; i < top; i++)
149: ((Tieable) items.elementAt(i)).sync(this , newest);
150: }
151:
152: } // end class Tie
|