001: package org.cougaar.core.qos.frame.visualizer;
002:
003: import java.awt.Component;
004: import java.awt.Dimension;
005: import java.awt.Graphics2D;
006: import java.net.URL;
007: import java.util.ArrayList;
008: import java.util.Collection;
009: import java.util.HashMap;
010: import java.util.Iterator;
011:
012: import javax.swing.Box;
013: import javax.swing.BoxLayout;
014: import javax.swing.JCheckBox;
015: import javax.swing.JLabel;
016: import javax.swing.JSlider;
017: import javax.swing.SwingUtilities;
018: import javax.swing.event.ChangeEvent;
019: import javax.swing.event.ChangeListener;
020:
021: import org.cougaar.core.qos.frame.RelationFrame;
022: import org.cougaar.core.qos.frame.visualizer.event.AddedFramesEvent;
023: import org.cougaar.core.qos.frame.visualizer.event.ChangedFramesEvent;
024: import org.cougaar.core.qos.frame.visualizer.event.RemovedFramesEvent;
025: import org.cougaar.core.qos.frame.visualizer.event.TickEvent;
026: import org.cougaar.core.qos.frame.visualizer.util.SlotChangeListeners;
027: import org.cougaar.core.qos.frame.visualizer.util.ViewConfigParser;
028: import org.cougaar.core.service.ThreadService;
029: import org.cougaar.util.log.Logger;
030: import org.cougaar.util.log.Logging;
031:
032: /**
033: * Created by IntelliJ IDEA.
034: * User: mwalczak
035: * Date: Apr 8, 2005
036: * Time: 9:31:15 AM
037: * To change this template use File | Settings | File Templates.
038: */
039: public class Display extends AnimatedCanvas implements ChangeListener {
040: public static boolean ENABLE_ANIMATION = false;//true;
041: static String TICK_EVENT_LABEL = "TICK";
042: protected int tickNumber;
043: Shapes shapes;
044: LabelRenderers labelRenderers;
045: ShapeRenderers shapeRenderers;
046: SlotChangeListeners slotListeners;
047:
048: ShapeContainer root;
049: boolean initialized, processingTickEvent;
050: ArrayList transitions, tickEventQueue;
051:
052: // debug
053: Collection frames;
054: HashMap frameContainerMap, prototypeMap;
055: FrameModel frameModel;
056: private transient Logger log = Logging.getLogger(getClass()
057: .getName());
058:
059: ViewConfigParser.WindowSpec wSpec;
060: ControlPanel cPanel;
061:
062: // changes
063: org.cougaar.core.qos.frame.visualizer.event.ChangeModel tickStatusListeners;
064: ChangeEvent tickCompleted;
065:
066: //Object lock;
067:
068: public Display(FrameModel frameModel, URL xmlFile,
069: ThreadService tsvc) {
070: //lock = new Object();
071: this .frameModel = frameModel;
072: tickNumber = 0;
073: //graphics = new HashMap();
074: transitions = new ArrayList();
075: tickEventQueue = new ArrayList();
076: frameContainerMap = new HashMap();
077: prototypeMap = new HashMap();
078: processingTickEvent = initialized = false;
079: tickStatusListeners = new org.cougaar.core.qos.frame.visualizer.event.ChangeModel();
080: tickCompleted = new ChangeEvent(this );
081: ViewConfigParser parser = new ViewConfigParser();
082: parser.parse(xmlFile);
083: wSpec = parser.windowSpec;
084: shapes = parser.getShapes();
085: labelRenderers = parser.getLabelRenderers();
086: shapeRenderers = parser.getShapeRenderers();
087: slotListeners = parser.getSlotListeners();
088:
089: root = parser.root;
090: initialized = (root != null);
091: if (initialized) {
092: if (animating != null)
093: animating.start(tsvc);
094: }
095: frameModel.addAddedFramesListener(this );
096: frameModel.addChangedFramesListener(this );
097: frameModel.addRemovedFramesListener(this );
098: //frameModel.addTransitionListener(this);
099: }
100:
101: public Shapes getShapes() {
102: return shapes;
103: }
104:
105: public LabelRenderers getLabelRenderers() {
106: return labelRenderers;
107: }
108:
109: public ShapeRenderers getShapeRenderers() {
110: return shapeRenderers;
111: }
112:
113: public SlotChangeListeners getSlotListeners() {
114: return slotListeners;
115: }
116:
117: public void stateChanged(ChangeEvent e) {
118: ProcessEventHelper helper = new ProcessEventHelper(e);
119: if (SwingUtilities.isEventDispatchThread())
120: helper.run();
121: else
122: SwingUtilities.invokeLater(helper);
123: }
124:
125: class ProcessEventHelper implements Runnable {
126: ChangeEvent e;
127:
128: public ProcessEventHelper(ChangeEvent che) {
129: e = che;
130: }
131:
132: public void run() {
133: if (e instanceof AddedFramesEvent) {
134: // process added frames
135: AddedFramesEvent ee = (AddedFramesEvent) e;
136: root.update(frameModel, ee.getAddedDataFrames(), null,
137: ee.getAddedRelationFrames());
138:
139: } else if (e instanceof ChangedFramesEvent) {
140: // process slot changes of data frames
141: ChangedFramesEvent ee = (ChangedFramesEvent) e;
142: HashMap changeMap = ee.getChangedDataFrames();
143: if (changeMap != null) {
144: org.cougaar.core.qos.frame.Frame frame;
145: ShapeGraphic sh;
146: for (Iterator ii = changeMap.keySet().iterator(); ii
147: .hasNext();) {
148: frame = (org.cougaar.core.qos.frame.Frame) ii
149: .next();
150: sh = frameModel.getGraphic(frame);
151: if (sh != null) {
152: for (Iterator jj = ((Collection) changeMap
153: .get(frame)).iterator(); jj
154: .hasNext();)
155: sh
156: .processFrameChange(
157: frame,
158: (org.cougaar.core.qos.frame.Frame.Change) jj
159: .next());
160: }
161: }
162: }
163: // process relationship changes
164: HashMap relationChangesMap = ee
165: .getChangedRelationFrames();
166: if (relationChangesMap != null) {
167: RelationFrame rf;
168: Collection changeReports;
169: ArrayList transitionList = new ArrayList();
170:
171: for (Iterator ii = relationChangesMap.keySet()
172: .iterator(); ii.hasNext();) {
173: rf = (RelationFrame) ii.next();
174: changeReports = (Collection) relationChangesMap
175: .get(rf);
176: Collection trans = processRelationshipChanges(
177: rf, changeReports);
178: if (trans != null)
179: transitionList.addAll(trans);
180: }
181: if (transitionList.size() > 0) {
182: if (log.isDebugEnabled())
183: log
184: .debug("ProcessEventHelper: creating a tick event #"
185: + (tickNumber + 1)
186: + " with "
187: + transitionList.size()
188: + " transitions");
189: tickEventOccured(new TickEvent(this ,
190: tickNumber++, TICK_EVENT_LABEL,
191: transitionList));
192: }
193: }
194:
195: } else if (e instanceof RemovedFramesEvent) {
196: ;// nothing yet
197: }// else if (e instanceof TickEvent) {
198: // process new transitions (add to a transition queue to be picked up by the
199: // animation thread)
200: // tickEventOccured((TickEvent)e);
201: //}
202: }
203: }
204:
205: protected Transition processRelationshipFrame(RelationFrame rframe) {
206: ShapeGraphic child, parent;
207: org.cougaar.core.qos.frame.Frame fchild, fparent;
208:
209: fparent = rframe.relationshipParent();
210: fchild = rframe.relationshipChild();
211: if (fparent == null || fchild == null) {
212: if (log.isDebugEnabled())
213: log
214: .debug("processRelationshipChange: invalid Relation '"
215: + rframe.getKind()
216: + "' parent="
217: + FrameModel.getName(fparent)
218: + " child="
219: + FrameModel.getName(fchild));
220: }
221:
222: parent = frameModel.getGraphic(fparent);
223: child = frameModel.getGraphic(fchild);
224: if (parent == null || child == null) {
225: if (log.isDebugEnabled())
226: log.debug("--error: did not find shapes: Relation '"
227: + rframe.getKind()
228: + "' changed parent="
229: + (fparent == null ? "+NULL+" : rframe
230: .getParentValue())
231: + " child="
232: + (fchild == null ? "+NULL+" : rframe
233: .getChildValue()) + " parentFrame="
234: + fparent + " childFrame=" + fchild);
235: return null;
236: }
237: if (child.getParent() != null
238: && child.getParent().getId().equals(parent.getId())) {
239: if (log.isDebugEnabled())
240: log.debug("--warning: old parent = "
241: + child.getParent() + " new parent=" + parent
242: + ", ignoring...");
243: return null;
244: }
245: if (log.isDebugEnabled())
246: log.debug("Relation '"
247: + rframe.getKind()
248: + "' changed parent="
249: + (fparent == null ? "+NULL+" : rframe
250: .getParentValue())
251: + " child="
252: + (fchild == null ? "+NULL+" : rframe
253: .getChildValue()));//+" parentFrame="+fparent+" childFrame="+fchild);
254:
255: return new Transition(child, child.getParent(),
256: (ShapeContainer) parent);
257: }
258:
259: protected Collection processRelationshipChanges(
260: RelationFrame rframe, Collection changeReports) {
261: ArrayList transitions = null; //new ArrayList();
262:
263: if (log.isDebugEnabled())
264: log.debug("processRelationshipChanges: frame="
265: + rframe.getKind() + " changeReports.size="
266: + changeReports.size());
267:
268: Transition t;
269: for (Iterator ii = changeReports.iterator(); ii.hasNext();) {
270: // org.cougaar.core.qos.frame.Frame.Change change = (org.cougaar.core.qos.frame.Frame.Change) ii.next();
271: // Handle change to existing frame
272: //slotName = change.getSlotName();
273: //value = change.getValue();
274: ii.next();
275: t = processRelationshipFrame(rframe);
276: if (t != null) {
277: if (transitions == null)
278: transitions = new ArrayList();
279: transitions.add(t);
280: }
281: }
282: return transitions;
283: }
284:
285: public void addTickStatusListener(ChangeListener l) {
286: tickStatusListeners.addListener(l);
287: }
288:
289: public void removeTickStatusListener(ChangeListener l) {
290: tickStatusListeners.removeListener(l);
291: }
292:
293: public Component getControlPanel() {
294: if (cPanel == null)
295: cPanel = new ControlPanel();
296: return cPanel;
297: }
298:
299: public ViewConfigParser.WindowSpec getWindowSpec() {
300: return wSpec;
301: }
302:
303: public void reset() {
304: Dimension d = getSize();
305: reset(d.width, d.height);
306: }
307:
308: public void reset(int w, int h) {
309: super .reset(w, h);
310: if (!initialized)
311: return;
312:
313: root.reshape(0d, 0d, w, h);
314: }
315:
316: public void step(int w, int h) {
317: if (!initialized)
318: return;
319: //if (log.isDebugEnabled())
320: // log.debug("**step: w="+w+" h="+h);
321: if (!processingTickEvent)
322: processNextTickEvent();
323: //synchronized (lock) {
324: ArrayList remove = new ArrayList();
325: Transition t;
326: boolean finished;
327: for (Iterator ii = transitions.iterator(); ii.hasNext();) {
328: t = (Transition) ii.next();
329: finished = t.step();
330: if (log.isDebugEnabled())
331: log.debug("\n******* transition step: " + t);
332: if (finished)
333: remove.add(t);
334: }
335: int temp = transitions.size();
336: for (Iterator rr = remove.iterator(); rr.hasNext();)
337: transitions.remove(rr.next());
338: if (temp > 0 && transitions.size() == 0) {
339: processingTickEvent = false;
340: tickStatusListeners.notifyListeners(tickCompleted);
341: //processNextTickEvent();
342: }
343: //}
344: }
345:
346: public void render(int w, int h, Graphics2D g2) {
347: //System.out.println("render");
348: if (!initialized)
349: return;
350: //synchronized (lock) {
351: super .render(w, h, g2);
352: root.draw(g2);
353: root.drawLabel(g2);
354:
355: Transition t;
356: for (Iterator ii = transitions.iterator(); ii.hasNext();) {
357: t = (Transition) ii.next();
358: t.draw(g2);
359: }
360:
361: //if (!processingTickEvent)
362: // processNextTickEvent();
363: //}
364: }
365:
366: public ShapeContainer getRootContainer() {
367: return root;
368: }
369:
370: public ShapeGraphic findShape(double x, double y) {
371: return root.find(x, y);
372: }
373:
374: public void tickEventOccured(
375: org.cougaar.core.qos.frame.visualizer.event.TickEvent tick) {
376: //synchronized (lock) {
377: tickEventQueue.add(tick);
378: //}
379: }
380:
381: public void processNextTickEvent() {
382: org.cougaar.core.qos.frame.visualizer.event.TickEvent tickEvent = null;
383: //synchronized (lock) {
384: if (tickEventQueue.size() > 0) {
385: tickEvent = (TickEvent) tickEventQueue.get(0);
386: tickEventQueue.remove(0);
387: }
388: //}
389: if (tickEvent == null)
390: return;
391: processingTickEvent = true;
392: if (log.isDebugEnabled())
393: log.debug("\nprocessing " + tickEvent);
394:
395: transitions.addAll(tickEvent.getTransitions());
396: }
397:
398: /*
399: public void setFrameHelper(FrameModel h) {
400: synchronized (lock) {
401: //this.graphics = new HashMap();
402: this.frameModel = h;
403: root.setFrameHelper(frameModel);
404: }
405: }*/
406:
407: /*
408: public void addFrames(Collection newFrames) {
409: synchronized (lock) {
410: //root.addedFrames(newFrames, this);
411: }
412: }
413:
414: public void removeFrames(Collection removedFrames) {
415: synchronized (lock) {
416: //root.removedFrames(removedFrames, this);
417: }
418: }*/
419:
420: class ControlPanel extends Box implements ChangeListener {
421: JSlider animationDelaySlider;
422: JCheckBox animationOn;
423:
424: public ControlPanel() {
425: super (BoxLayout.X_AXIS);
426: animationDelaySlider = new JSlider(0, 100,
427: (int) sleepAmount);
428: animationDelaySlider.addChangeListener(this );
429: //animationDelaySlider.setPaintLabels(true);
430: animationOn = new JCheckBox("Animation On");
431: animationOn.setSelected(Display.ENABLE_ANIMATION);
432: animationOn.addChangeListener(this );
433: add(new JLabel("Animation delay:"));
434: add(animationDelaySlider);
435: add(Box.createHorizontalStrut(20));
436: add(animationOn);
437: }
438:
439: public void stateChanged(ChangeEvent e) {
440: Object source = e.getSource();
441: if (source == animationDelaySlider) {
442: sleepAmount = animationDelaySlider.getValue();
443: } else if (source == animationOn) {
444: Display.ENABLE_ANIMATION = animationOn.isSelected();
445: }
446: }
447: }
448:
449: /*
450: public void p(String msg) {
451: System.out.println(msg);
452: }
453:
454: public void mousePressed(MouseEvent evt) {
455: //super.mousePressed(evt);
456: p("Display.mousePressed count="+count);
457: if(mouseMoveFlag==false) {
458: mousePoint=evt.getPoint();
459: count = (++count)%2;
460: if (count == 0) {
461: lastPoint = mousePoint;
462: } else if (count == 1 && lastPoint != null) {
463: p("creating a transition from "+lastPoint.x+","+lastPoint.y+" to "+mousePoint.x+", "+mousePoint.y);
464: transitions.add(new TestTransition(new Point2D.Double((double)lastPoint.x, (double)lastPoint.y),
465: new Point2D.Double((double)mousePoint.x, (double)mousePoint.y)));
466: lastPoint = null;
467: }
468:
469: }
470: super.mousePressed(evt);
471: }
472: */
473: }
|