1
2 package hep.wired.plot;
3
4 import java.awt.*;
5 import java.awt.event.*;
6 import java.awt.geom.*;
7 import java.io.*;
8 import java.lang.reflect.*;
9 import java.util.*;
10 import java.util.logging.*;
11 import javax.swing.*;
12 import javax.swing.event.*;
13 import javax.swing.undo.*;
14
15 import org.jdom.Element;
16
17 import org.freehep.application.Application;
18 import org.freehep.application.studio.Studio;
19 import org.freehep.graphics2d.VectorGraphics;
20 import org.freehep.swing.Headless;
21 import org.freehep.swing.layout.StackedLayout;
22 import org.freehep.swing.popup.HasPopupItems;
23 import org.freehep.swing.undo.AnimatedEditSupport;
24 import org.freehep.swing.undo.DoableEdit;
25 import org.freehep.swing.undo.UndoableEditProcessor;
26 import org.freehep.xml.io.XMLIO;
27 import org.freehep.xml.io.XMLIOManager;
28 import org.freehep.util.Value;
29
30 import hep.wired.edit.WiredEdit;
31 import hep.wired.edit.WiredCompoundEdit;
32 import hep.wired.edit.NoOperation;
33 import hep.wired.edit.GraphicsPanelEdit;
34 import hep.wired.edit.Reset;
35 import hep.wired.services.GraphicsPanel;
36 import hep.wired.services.InteractionHandler;
37 import hep.wired.services.RecordPlot;
38 import hep.wired.services.ViewPort;
39 import hep.wired.util.NullEvent;
40 import hep.wired.util.SwingEventMulticaster;
41
42 /***
43 * Defines a single event display plot.
44 *
45 * @author Mark Donszelmann
46 * @version $Id: WiredPlot.java 2091 2005-07-22 19:05:06Z duns $
47 */
48 public class WiredPlot extends JPanel
49 implements RecordPlot, HasPopupItems, XMLIO {
50
51 private static Logger logger = Logger.getLogger(WiredPlot.class.getPackage().getName());
52 private long t0;
53
54 private String name;
55 private GraphicsPanel graphicsPanel;
56 private UndoableEditSupport undoSupport;
57
58 private transient boolean selected;
59 private transient boolean needsReset;
60 private transient ChangeListener changeListenerList;
61
62
63 private WiredPlot() {
64 this(null, null, false, null);
65 }
66
67 /***
68 * Creates a plot without a record.
69 */
70 public WiredPlot(GraphicsPanel graphicsPanel) {
71 this("Plot", graphicsPanel);
72 }
73
74 /***
75 * Creates a plot with default GraphicsMode.
76 */
77 public WiredPlot(String name, GraphicsPanel graphicsPanel) {
78 this(name, graphicsPanel, true);
79 }
80
81 /***
82 * Creates a plot with given parameters.
83 */
84 public WiredPlot(String name, GraphicsPanel graphicsPanel, boolean supportUndo) {
85 this(name, graphicsPanel, supportUndo, null);
86
87 }
88
89
90
91 private WiredPlot(String name, GraphicsPanel graphicsPanel, boolean supportUndo, InteractionHandler interactionHandler) {
92 super(false);
93 this.name = name;
94 this.selected = false;
95 this.needsReset = true;
96
97
98 setLayout(new BorderLayout());
99 setOpaque(false);
100
101
102 if (graphicsPanel != null) setGraphicsPanel(graphicsPanel);
103
104
105 if (supportUndo) addUndoSupport();
106
107
108 if (interactionHandler != null) setInteractionHandler(interactionHandler);
109 }
110
111 /***
112 * Returns a copy of this plot, attached to the given objects, from the given parameters.
113 */
114 public RecordPlot copy(String name, Object record, boolean supportUndo) {
115 WiredPlot copy = new WiredPlot(name, graphicsPanel.copy(), supportUndo, null);
116
117 copy.setInteractionHandler(getInteractionHandler());
118 copy.setRecord(record);
119
120 copy.color = color;
121 copy.lineWidth = lineWidth;
122 copy.frameColor = frameColor;
123 copy.frameWidth = frameWidth;
124 copy.shape = shape;
125
126 return copy;
127 }
128
129 public void addChangeListener(ChangeListener listener) {
130 changeListenerList = SwingEventMulticaster.add(changeListenerList, listener);
131 }
132
133 public void removeChangeListener(ChangeListener listener) {
134 changeListenerList = SwingEventMulticaster.remove(changeListenerList, listener);
135 }
136
137 private void setGraphicsPanel(GraphicsPanel newPanel) {
138 if (graphicsPanel != null) remove((Component)graphicsPanel);
139
140 graphicsPanel = newPanel;
141 add((Component)graphicsPanel, BorderLayout.CENTER);
142 }
143
144 private void addUndoSupport() {
145 undoSupport = new AnimatedEditSupport(this);
146 }
147
148 /***
149 * Returns the undo support object, or null if undo was not switched on.
150 */
151 public UndoableEditSupport getUndoableEditSupport() {
152 return undoSupport;
153 }
154
155 /***
156 * Returns the name of the plot.
157 */
158 public String getName() {
159 return name;
160 }
161
162 public boolean requestFocusInWindow() {
163 return ((Component)graphicsPanel).requestFocusInWindow();
164 }
165
166 /***
167 * Returns the associated Graphics Panel.
168 */
169 public GraphicsPanel getGraphicsPanel() {
170 return graphicsPanel;
171 }
172
173 public void setSelected(boolean selected) {
174 this.selected = selected;
175 graphicsPanel.setSelected(this, selected);
176 if (handler != null) handler.setSelected(this, selected);
177 }
178
179 public void repaint() {
180 super.repaint();
181 if (graphicsPanel != null) ((Component)graphicsPanel).repaint();
182 }
183
184
185
186 public void setBounds(int x, int y, int width, int height) {
187 ((Component)graphicsPanel).setBounds(x, y, width, height);
188 if (handler != null) handler.setSize(this, width, height);
189 super.setBounds(x, y, width, height);
190 }
191
192 public String toString() {
193 return (getName() == null) ? "WiredPlot@"+hashCode() : "WiredPlot: "+getName();
194 }
195
196
197
198
199 /***
200 * Returns true if given edit is supported, which may depend on the current graphics panel.
201 */
202 public boolean supports(UndoableEdit edit) {
203 if (edit instanceof NoOperation) return true;
204
205 if (edit instanceof GraphicsPanelEdit) {
206 GraphicsPanelEdit graphicsPanelEdit = (GraphicsPanelEdit)edit;
207 return graphicsPanelEdit.isSupportedBy(getGraphicsPanel());
208 }
209
210 return false;
211 }
212
213 /***
214 * Handles an undoable edit, please use postEdit(WiredEdit).
215 */
216 public void postEdit(UndoableEdit edit) {
217 if (edit instanceof DoableEdit) {
218 postEdit((DoableEdit)edit);
219 return;
220 }
221 logger.warning("Edit ignored: "+edit);
222 }
223
224 /***
225 * Handles an doable edit, please use postEdit(WiredEdit).
226 */
227 public void postEdit(DoableEdit edit) {
228 if (edit instanceof WiredEdit) {
229 postEdit((WiredEdit) edit);
230 return;
231 }
232 if (edit instanceof WiredCompoundEdit) {
233 postEdit((WiredCompoundEdit) edit);
234 return;
235 }
236 logger.warning("Edit should be Wired(Compound)Edit...: "+edit);
237 edit.redo();
238 if (edit.isSignificant()) {
239 if (undoSupport != null) undoSupport.postEdit(edit);
240 }
241 }
242
243 /***
244 * Handles a Wired Edit. You may post the same edit to different plots, since edits are copied and
245 * afterwards attached to the plot. Any edits posted can be undone, if undoable support was switched
246 * on at creation time of the plot. Each plot has its own undo support.
247 */
248 public void postEdit(WiredEdit edit) {
249 WiredEdit wiredEdit = edit.copy(this);
250
251
252 wiredEdit.redo();
253 if (wiredEdit.isSignificant()) {
254 if (undoSupport != null) undoSupport.postEdit(wiredEdit);
255 }
256 }
257
258 /***
259 * Handles a Wired Compound Edit. You may post the same edit to different plots, since edits are copied
260 * (recursively) and
261 * afterwards attached to the plot. Any edits posted can be undone, if undoable support was switched
262 * on at creation time of the plot. Each plot has its own undo support.
263 */
264 public void postEdit(WiredCompoundEdit edit) {
265 WiredCompoundEdit wiredEdit = edit.copy(this);
266
267
268 wiredEdit.redo();
269 if (wiredEdit.isSignificant()) {
270 if (undoSupport != null) undoSupport.postEdit(wiredEdit);
271 }
272 }
273
274 /***
275 * If multiple edits need to count as one major update, call this method to start a compound edit.
276 */
277 public void beginUpdate() {
278 if (undoSupport != null) undoSupport.beginUpdate();
279 }
280
281 /***
282 * If multiple edits need to count as one major update, call this method to end a compound edit.
283 */
284 public void endUpdate() {
285 if (undoSupport != null) undoSupport.endUpdate();
286 }
287
288 /***
289 * Returns true if this plot (and its projection) supports the given interactionHandler.
290 */
291 public boolean supports(InteractionHandler interactionHandler) {
292 return interactionHandler != null ? interactionHandler.isSupportedBy(getGraphicsPanel()) : true;
293 }
294
295
296 private InteractionHandler handler;
297 private transient boolean pressed, dragged, clicked;
298 private transient MouseEvent pressEvent;
299
300 private transient MouseListener mouseListener;
301 private transient MouseMotionListener mouseMotionListener;
302 private transient MouseWheelListener mouseWheelListener;
303 private transient KeyListener keyListener;
304
305
306 private Color color = Color.white;
307 private double lineWidth = 1.0;
308 private Color frameColor = Color.black;
309 private double frameWidth = 3.0;
310 private Shape shape;
311
312 public void setInteractionHandler(InteractionHandler interactionHandler) {
313
314 if (selected) {
315 if (handler != null) handler.setSelected(this, false);
316 if (interactionHandler != null) interactionHandler.setSelected(this, true);
317 }
318
319 Component panel = (Component)graphicsPanel;
320
321 if (mouseListener != null) panel.removeMouseListener(mouseListener);
322 if (mouseMotionListener != null) panel.removeMouseMotionListener(mouseMotionListener);
323 if (mouseWheelListener != null) panel.removeMouseWheelListener(mouseWheelListener);
324 if (keyListener != null) panel.removeKeyListener(keyListener);
325
326 handler = interactionHandler;
327
328 drawShape(null);
329 repaint();
330
331 if (handler == null) {
332 setCursor(null);
333 } else {
334 handler.setSize(this, getWidth(), getHeight());
335 handler.reset(this, new NullEvent(this));
336 handler.changeCursor(this, new NullEvent(this));
337
338 mouseListener = new MouseListener() {
339
340 public void mousePressed(MouseEvent event) {
341 changeListenerList.stateChanged(new ChangeEvent(this));
342
343 if (SwingUtilities.isLeftMouseButton(event)) {
344
345
346 event.getComponent().requestFocusInWindow();
347
348 pressed = true;
349 pressEvent = event;
350 clicked = true;
351 dragged = false;
352 handler.mouseButton1Pressed(WiredPlot.this, event);
353 }
354 }
355
356 public void mouseReleased(MouseEvent event) {
357 if (SwingUtilities.isLeftMouseButton(event)) {
358
359
360 if (dragged) {
361 handler.mouseButton1DragEnded(WiredPlot.this, event);
362 dragged = false;
363 }
364 handler.mouseButton1Released(WiredPlot.this, event);
365 pressed = false;
366 pressEvent = null;
367 }
368 }
369
370 public void mouseClicked(MouseEvent event) {
371 if (SwingUtilities.isLeftMouseButton(event)) {
372 if (clicked) {
373
374
375 handler.mouseButton1Clicked(WiredPlot.this, event);
376 clicked = false;
377 }
378 pressed = false;
379 pressEvent = null;
380 dragged = false;
381 }
382 }
383
384 public void mouseEntered(MouseEvent event) {
385
386
387 event.getComponent().requestFocusInWindow();
388 handler.mouseEntered(WiredPlot.this, event);
389 }
390
391 public void mouseExited(MouseEvent event) {
392
393
394 handler.mouseExited(WiredPlot.this, event);
395 }
396 };
397 panel.addMouseListener(mouseListener);
398
399 mouseMotionListener = new MouseMotionListener() {
400 public void mouseDragged(MouseEvent event) {
401
402
403 if (SwingUtilities.isLeftMouseButton(event)) {
404 if (pressed) {
405 if (pressEvent != null) {
406 dragged = true;
407 clicked = false;
408 handler.mouseButton1DragStarted(WiredPlot.this, pressEvent);
409 pressEvent = null;
410 }
411 handler.mouseButton1Dragged(WiredPlot.this, event);
412 }
413 }
414 }
415 public void mouseMoved(MouseEvent event) {
416
417
418 handler.mouseMoved(WiredPlot.this, event);
419 }
420 };
421 panel.addMouseMotionListener(mouseMotionListener);
422
423 mouseWheelListener = new MouseWheelListener() {
424 public void mouseWheelMoved(MouseWheelEvent event) {
425
426
427 handler.mouseWheelMoved(WiredPlot.this, event);
428 }
429 };
430 panel.addMouseWheelListener(mouseWheelListener);
431
432 keyListener = new KeyListener() {
433 private boolean altKeyDown, ctrlKeyDown, shiftKeyDown, escKeyDown;
434
435 public void keyPressed(KeyEvent event) {
436 boolean consume = false;
437 switch(event.getKeyCode()) {
438 case KeyEvent.VK_ALT:
439 if (!altKeyDown) {
440 altKeyDown = true;
441 consume = handler.altKeyPressed(WiredPlot.this, event);
442 }
443 break;
444 case KeyEvent.VK_CONTROL:
445 if (!ctrlKeyDown) {
446 ctrlKeyDown = true;
447 consume = handler.ctrlKeyPressed(WiredPlot.this, event);
448 }
449 break;
450 case KeyEvent.VK_SHIFT:
451 if (!shiftKeyDown) {
452 shiftKeyDown = true;
453 consume = handler.shiftKeyPressed(WiredPlot.this, event);
454 }
455 break;
456 case KeyEvent.VK_ESCAPE:
457 if (!escKeyDown) {
458 escKeyDown = true;
459 pressed = false;
460 dragged = false;
461 handler.reset(WiredPlot.this, event);
462 consume = handler.escKeyPressed(WiredPlot.this, event);
463 }
464 break;
465 default:
466 consume = handler.otherKeyPressed(WiredPlot.this, event);
467 break;
468 }
469 if (consume) event.consume();
470 }
471
472 public void keyReleased(KeyEvent event) {
473 boolean consume = false;
474 switch(event.getKeyCode()) {
475 case KeyEvent.VK_ALT:
476 if (altKeyDown) {
477 altKeyDown = false;
478 consume = handler.altKeyReleased(WiredPlot.this, event);
479 }
480 break;
481 case KeyEvent.VK_CONTROL:
482 if (ctrlKeyDown) {
483 ctrlKeyDown = false;
484 consume = handler.ctrlKeyReleased(WiredPlot.this, event);
485 }
486 break;
487 case KeyEvent.VK_SHIFT:
488 if (shiftKeyDown) {
489 shiftKeyDown = false;
490 consume = handler.shiftKeyReleased(WiredPlot.this, event);
491 }
492 break;
493 case KeyEvent.VK_ESCAPE:
494 if (escKeyDown) {
495 escKeyDown = false;
496 consume = handler.escKeyReleased(WiredPlot.this, event);
497 }
498 break;
499 default:
500 consume = handler.otherKeyReleased(WiredPlot.this, event);
501 break;
502 }
503 if (consume) event.consume();
504 }
505
506 public void keyTyped(KeyEvent event) {
507 boolean consume = handler.keyTyped(WiredPlot.this, event);
508 if (consume) event.consume();
509 }
510 };
511 panel.addKeyListener(keyListener);
512 }
513 panel.requestFocusInWindow();
514 }
515
516 public void drawShape(Shape shape) {
517 this.shape = shape;
518
519 super.repaint();
520 }
521
522 public void paint(Graphics g) {
523 super.paint(g);
524
525
526
527
528 if (shape != null) {
529 VectorGraphics graphics = VectorGraphics.create(g);
530
531 BasicStroke cs = (BasicStroke)graphics.getStroke();
532 graphics.setStroke(new BasicStroke(cs.getLineWidth(),
533 cs.getEndCap(),
534 cs.getLineJoin(),
535 1.0f,
536 cs.getDashArray(),
537 cs.getDashPhase()));
538
539 graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
540 RenderingHints.VALUE_ANTIALIAS_ON);
541
542 graphics.setColor(frameColor);
543 graphics.setLineWidth(frameWidth);
544 graphics.draw(shape);
545 graphics.setLineWidth(lineWidth);
546 graphics.setColor(color);
547 graphics.draw(shape);
548 }
549 }
550
551 /***
552 * Return the current interaction handler.
553 */
554 public InteractionHandler getInteractionHandler() {
555 return handler;
556 }
557
558 /***
559 * Sets the plot to use this Object.
560 */
561 public void setRecord(Object record) {
562 graphicsPanel.setRecord(record);
563 if (handler != null) handler.setRecord(this, record);
564
565 if (needsReset && (record != null)) {
566 postEdit(new Reset());
567 needsReset = false;
568 }
569
570 repaint();
571 }
572
573 /***
574 * Returns the current Object.
575 */
576 public Object getRecord() {
577 return graphicsPanel.getRecord();
578 }
579
580
581
582
583 public JPopupMenu modifyPopupMenu(JPopupMenu menu, Component source, Point p) {
584 Application.getApplication().getXMLMenuBuilder().mergePopupMenu("wiredBasePopupMenu", menu);
585 menu = graphicsPanel.modifyPopupMenu(menu, this);
586 return menu;
587 }
588
589
590
591
592 public void save(XMLIOManager xmlioManager,
593 org.jdom.Element nodeEl) {
594 if (name != null) nodeEl.setAttribute("name", name);
595 nodeEl.addContent(xmlioManager.save(graphicsPanel));
596 if (handler != null) nodeEl.addContent(xmlioManager.save(handler));
597 nodeEl.setAttribute("undo", undoSupport != null ? "true" : "false");
598 }
599
600 public void restore(XMLIOManager xmlioManager,
601 org.jdom.Element nodeEl) {
602 name = nodeEl.getAttributeValue("name");
603 Iterator i = nodeEl.getChildren().iterator();
604 setGraphicsPanel((GraphicsPanel)xmlioManager.restore((Element)i.next()));
605 if (i.hasNext()) {
606 setInteractionHandler((InteractionHandler)xmlioManager.restore((Element)i.next()));
607 }
608 if (nodeEl.getAttributeValue("undo","").equals("true")) addUndoSupport();
609 }
610 }