1 package org.convey;
2 
3 import java.util.*;
4 import java.awt.*;
5 import java.awt.event.*;
6 import java.awt.geom.*;
7 import javax.swing.event.*;
8 import javax.swing.*;
9 import javax.swing.border.*;
10 import org.jdom.output.*;
11 import org.jdom.*;
12 
13 /**
14  * GraphicPanel is a JPanel implementation that manages the Graphic objects.
15  * This class provides the link between the Graphic objects and Java Swing's
16  * painting and input mechanisms.
17  * <p>
18  * The GraphicPanel has a state field indicating which mode of interaction the
19  * GraphicPanel is in. For example, if the state is SELECT, the user may select
20  * existing graphic objects in the panel. One or more graphic objects may be
21  * selected simultaneously by clicking them directly or dragging a rectangular
22  * selection box.
23  * <p>
24  * Additionally, in the SELECT state, the user may move the set of selected
25  * graphics.
26  * <p>
27  * In the RECTANGLE state, the user may create rectangles with the mouse by
28  * dragging a rectangular regon in the graphic panel. This is known as a
29  * graphic creation state.
30  * <p>
31  * All states except SELECT and VERTEX are considered graphic creation states
32  * because these states allow the user to create new graphic objects. When the
33  * graphic panel is in a creation state and the user is creating a new graphic,
34  * the newGraphic field stores a reference to the new graphic. When the user has
35  * completed the graphic creation, the new graphic is added to the Vector of
36  * graphic objects and newGraphic is set to null.
37  * <p>
38  * There are four Vectors of graphic objects: graphics, selectedGraphics, and
39  * clipboardGraphics.
40  * <p>
41  * The graphics Vector consists of all graphic objects that have NOT been sent
42  * across the Jabber network. These graphic objects are painted in the graphic
43  * panel without a selection border nor selection handles.
44  * <p>
45  * The selectedGraphic Vector consists of all graphic objects in the SELECTED
46  * state and have NOT been sent across the Jabber network. These graphic objects
47  * are painted in the graphic panel with a selection border or selection
48  * handles. Graphic objects in this Vector are also stored in the graphics
49  * Vector.
50  * <p>
51  * The clipboardGraphics Vector consists of org.jdom.Element references that
52  * describe the set of graphic objects that have been cut or copied into the
53  * clipboard. This Vector does not actually store Graphic references.
54  * <p>
55  *
56  * @author Andy Ames, Ed Braunhut
57  */
58 public class GraphicPanel extends JPanel
59 		implements MouseInputListener, KeyListener {
60 
61 	public static final int SELECT = 0;
62 	public static final int SCALE = 1;
63 	public static final int TEXT = 2;
64 	public static final int RECTANGLE = 3;
65 	public static final int ELLIPSE = 4;
66 	public static final int POLYLINE = 5;
67 	public static final int POLYGON = 6;
68 	public static final int QUADCURVE = 7;
69 	public static final int CUBICCURVE = 8;
70 	public static final int FITTEDCURVE = 9;
71 	public static final int FREEHANDCURVE = 10;
72 
73 	private static final int MAX_STATE = 10;
74 
75 	private transient boolean incoming;
76 
77 	private transient boolean hasPen;
78 
79 	protected transient CanvasPanel canvasPanel = null;
80 
81 	protected transient Graphic newGraphic = null;
82 
83 	protected Hashtable nameGraphicTable = new Hashtable();
84 
85 	/**
86 	 * Vector of all Graphic objects contained in the GraphicPanel. The Graphic
87 	 * objects are ordered from back to front.
88 	 */
89 	protected Vector graphics = new Vector();
90 
91 	protected transient Vector selectedGraphics = new Vector();
92 
93 	protected Vector graphicEvents = new Vector();
94 
95 	protected int lastGraphicEventIndex = -1;
96 
97 	protected Vector graphicEventStack = new Vector();
98 
99 	/**
100 	 * Stores GraphicEvents when auto send is off. They are then sent when auto
101 	 * send is turned back on, or when the pen is yielded.
102 	 */
103 	protected Vector graphicEventQueue = new Vector();
104 
105 	/**
106 	 * State of the graphic panel. One of SELECT, VERTEX, TEXT, RECTANGLE, ELLIPSE,
107 	 * POLYLINE, POLYGON, QUADCURVE, CUBICCURVE, and FITTEDCURVE.
108 	 */
109 	protected transient int state;
110 
111 	/**
112 	 * Flag indicating if the user is in the process of dragging a rectangular
113 	 * selection box. This flag is always false when the graphic panel is not in
114 	 * the SELECT nor the VERTEX state.
115 	 *
116 	 * @todo Get rid of this flag. Its redundant.
117 	 */
118 	protected transient boolean rectSelecting = false;
119 
120 	/**
121 	 * Current rectangular selection area. This Rectangle is null when
122 	 * rectSelecting is false.
123 	 */
124 	protected transient Rectangle selectRect = null;
125 
126 	/**
127 	 * Point indicating the last point captured from a mouseDragged event.
128 	 */
129 	protected transient Point lastDragPoint;
130 
131 	/**
132 	 * Point indicating the last point captured from a mousePressed event.
133 	 */
134 	protected transient Point pressPoint;
135 
136 	protected transient Graphic vertexSelected = null;
137 
138 	protected boolean autoSend;
139 
140 	/**
141 	 * Set white for the background color. Set up mouse and key listeners.
142 	 */
GraphicPanel(CanvasPanel canvasPanel)143 	public GraphicPanel(CanvasPanel canvasPanel) {
144 		super.setBorder(new SoftBevelBorder(SoftBevelBorder.LOWERED));
145 		this.incoming = false;
146 
147 		super.setBackground(Color.white);
148 
149 		this.canvasPanel = canvasPanel;
150 
151 		super.addMouseListener(this);
152 		super.addMouseMotionListener(this);
153 		super.addKeyListener(this);
154 
155 		this.hasPen = true;
156 	}
157 
setHasPen(boolean value)158 	public void setHasPen(boolean value) {
159 		CanvasPanel canvasPanel = this.getCanvasPanel();
160 		if(canvasPanel instanceof JabberCanvasPanel) {
161 			JabberCanvasPanel jabberCanvasPanel = (JabberCanvasPanel)canvasPanel;
162 			jabberCanvasPanel.getConveyFrame().changePenIcon(jabberCanvasPanel, value);
163 		}
164 		this.hasPen = value;
165 	}
166 
hasPen()167 	public boolean hasPen() {
168 		return this.hasPen;
169 	}
170 
isIncoming()171 	public boolean isIncoming() {
172 		return this.incoming;
173 	}
174 
setIncoming(boolean incoming)175 	public void setIncoming(boolean incoming) {
176 		this.incoming = incoming;
177 	}
178 
179 	/**
180 	 * Paints the GraphicPanel component by painting all Graphic objects.
181 	 * <p>
182 	 * First, the lockedGraphics Vector graphic objects are painted. Second, the
183 	 * graphics Vector graphic objects are painted.
184 	 * <p>
185 	 * Third, if newGraphic is valid, it is painted. Otherwise, the
186 	 * selectedGraphics Vector graphic objects have their selection painted.
187 	 * <p>
188 	 * Finally, if rectSelecting is true, the selectRect rectangle is painted.
189 	 */
paintComponent(Graphics g)190 	public void paintComponent(Graphics g) {
191 		super.paintComponent(g);
192 
193 		Graphics2D g2d = (Graphics2D)g;
194 
195 		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
196 
197 		Iterator iter = this.graphics.iterator();
198 		while (iter.hasNext()) {
199 			Graphic graphic = (Graphic) iter.next();
200 			graphic.paint(g2d);
201 			if (graphic.getState() == Graphic.SELECTED)
202 				graphic.paintSelection(g2d);
203 		}
204 
205 		if(this.newGraphic != null) {
206 			this.newGraphic.paint(g2d);
207 			if(this.newGraphic instanceof TextGraphic)
208 				this.newGraphic.paintSelection(g2d);
209 		}
210 
211 		if(rectSelecting) {
212 			g2d.setStroke(new BasicStroke(1));
213 			g2d.setColor(Color.gray);
214 			g2d.draw(selectRect);
215 		}
216 
217 		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
218 	}
219 
graphicIterator()220 	public Iterator graphicIterator() {
221 		return this.graphics.iterator();
222 	}
223 
224 	/**
225 	 * Sets the state of the graphicPanel. Possible states are SELECT, VERTEX,
226 	 * TEXT, RECTANGLE, ELLIPSE, POLYLINE, POLYGON, QUADCURVE, CUBICCURVE,
227 	 * FITTEDCURVE and FREEHANDCURVE.
228 	 * <p>
229 	 * Currently, we are repainting the entire graphic panel when this happens.
230 	 *
231 	 * @todo Identify what needs to be repainted when. Only repaint in those
232 	 *       cases.
233 	 */
setState(int state)234 	void setState(int state) {
235 		if(state <= MAX_STATE && state >= 0 && state != this.state) {
236 			this.state = state;
237 			super.repaint();
238 		}
239 	}
240 
241 	/**
242 	 * Gets the state of the graphicPanel. Possible states are SELECT, VERTEX,
243 	 * TEXT, RECTANGLE, ELLIPSE, POLYLINE, POLYGON, QUADCURVE, CUBICCURVE,
244 	 * FITTEDCURVE and FREEHANDCURVE.
245 	 */
getState()246 	int getState() {
247 		return this.state;
248 	}
249 
deselectAll()250 	public void deselectAll() {
251 		Vector oldSelectedGraphics = this.selectedGraphics;
252 		this.selectedGraphics = new Vector();
253 
254 		Iterator iter = oldSelectedGraphics.iterator();
255 		while(iter.hasNext()) {
256 			Graphic graphic = (Graphic)iter.next();
257 			graphic.setState(Graphic.DORMANT);
258 		}
259 
260 		this.canvasPanel.getConveyFrame().updateButtons();
261 	}
262 
263 	/**
264 	 * Invoked when a mouse button has been pressed on the graphic panel.
265 	 * <p>
266 	 * Depending on the state of the graphic panel, this event may or may not
267 	 * be forwarded to one or more graphic objects.
268 	 * <p>
269 	 * For example, if the state is a graphic creation state and the newGraphic
270 	 * field is non-null, then the newGraphic receives this event.
271 	 * <p>
272 	 * If the newGraphic field is null, some graphic creation states will have
273 	 * a new graphic created in response to this method. Other graphic creation
274 	 * states have a new graphic created in response to mouseClicked.
275 	 * <p>
276 	 * Currently, the following graphic creation states require a mousePressed to
277 	 * begin the creation process: RECTANGLE, ELLIPSE, FITTEDCURVE and FREEHANDCURVE.
278 	 */
mousePressed(MouseEvent e)279 	public void mousePressed(MouseEvent e) {
280 		Iterator iter;
281 
282 		super.requestFocus();
283 
284 		if(this.hasPen && this.newGraphic != null && this.newGraphic instanceof TextGraphic) {
285 			if(!this.newGraphic.hitPath(e.getPoint())) {
286 				((TextGraphic)this.newGraphic).setCursor(-1);
287 				this.newGraphic.setState(Graphic.DORMANT);
288 				this.addGraphic(this.newGraphic);
289 				this.addGraphicEvent(new NewGraphicEvent(this.newGraphic));
290 				this.newGraphic = null;
291 			}
292 		}
293 
294 		if(this.hasPen && this.newGraphic != null) {
295 			this.newGraphic.mousePressed(e);
296 
297 			if(newGraphic.getState() != Graphic.CREATING) {
298 
299 				// if newGraphic is no longer in CREATING state after processing event,
300 				// add the newGraphic to the graphics Vector
301 				this.addGraphic(this.newGraphic);
302 				this.newGraphic.setState(Graphic.SELECTED);
303 				this.addGraphicEvent(new NewGraphicEvent(this.newGraphic));
304 				this.newGraphic = null;
305 			}
306 		} else {
307 
308 			Point p = e.getPoint();
309 
310 			// if newGraphic is null...
311 
312 			if(this.hasPen && this.state != SELECT && this.state != SCALE) {
313 
314 				// Check if we hit a vertex of a selected graphic. If so, pop ourselves
315 				// into SELECT state and carry on.
316 
317 				Graphic graphic = this.hitGraphic(p);
318 				if(graphic != null && graphic.getState() == Graphic.SELECTED && graphic.hitVertex(p)) {
319 					this.vertexSelected = graphic;
320 					graphic.setOrig();
321 					graphic.mousePressed(e);
322 					return;
323 				}
324 
325 				// If we're not in SELECT or VERTEX states (we are in a graphic creation
326 				// state) we're about to create a new Graphic, deselect everyone.
327 				deselectAll();
328 			}
329 
330 			switch(this.state) {
331 				case SELECT:
332 					Graphic selected = null;
333 					this.vertexSelected = null;
334 
335 					if(!e.isControlDown() && !e.isAltDown() &&
336 						 !e.isShiftDown() && !e.isMetaDown()) {
337 
338 						// If we are single-selecting...
339 
340 						// What graphic got hit?
341 						selected = hitGraphic(p);
342 
343 						if(selected != null) {
344 							// if a graphic was hit...
345 
346 							if(selected.getState() == Graphic.DORMANT) {
347 
348 								// If the hit graphic was previously DORMANT, deselect all
349 								deselectAll();
350 
351 								// select hit graphic
352 								selected.setState(Graphic.SELECTED);
353 							} else if(selected.hitVertex(p))
354 								this.vertexSelected = selected;
355 						} else {
356 
357 							// If a graphic was not hit, deselect all
358 							deselectAll();
359 
360 							// Enter rectangular select mode
361 							rectSelecting = true;
362 							selectRect = new Rectangle(p);
363 							lastDragPoint = pressPoint = p;
364 						}
365 					} else {
366 
367 						// If we are multi-selecting...
368 
369 						// What graphic got hit?
370 						selected = hitGraphic(p);
371 
372 						if(selected != null) {
373 
374 							// If a graphic got hit...
375 
376 							if(selected.getState() == Graphic.DORMANT) {
377 
378 								// If the hit graphic was previously DORMANT, add it to the
379 								// selectedGraphics Vector.
380 								selected.setState(Graphic.SELECTED);
381 							} else {
382 
383 								// If the hit graphic was previously SELECTED, remove it from
384 								// the selectedGraphics Vector.
385 								selected.setState(Graphic.DORMANT);
386 							}
387 						} else {
388 
389 							// If a graphic was NOT hit, enter rectangular select mode
390 							rectSelecting = true;
391 							selectRect = new Rectangle(p);
392 							lastDragPoint = pressPoint = p;
393 						}
394 					}
395 
396 					// Finally, we give all selected Graphic objects the mousePressed
397 					// event only if vertexOnly is false...
398 					if(this.hasPen && this.vertexSelected == null) {
399 						iter = this.selectedGraphics.iterator();
400 						while(iter.hasNext()) {
401 							Graphic graphic = (Graphic)iter.next();
402 							graphic.setOrig();
403 							graphic.mousePressed(e);
404 						}
405 					} else if(this.hasPen) {
406 						vertexSelected.setOrig();
407 						vertexSelected.mousePressed(e);
408 					}
409 
410 					break;
411 				case SCALE:
412 					selected = hitGraphic(p);
413 
414 					deselectAll();
415 
416 					if(selected != null) {
417 						selected.setState(Graphic.SELECTED);
418 						if(this.hasPen) {
419 							selected.setOrig();
420 							selected.mousePressed(e);
421 						}
422 					}
423 					break;
424 				case RECTANGLE:
425 					if(this.hasPen) {
426 						QuadGraphic quadGraphic = new QuadGraphic(this, e.getPoint());
427 						this.newGraphic = quadGraphic;
428 					}
429 					break;
430 				case ELLIPSE:
431 					if(this.hasPen) {
432 						EllipseGraphic ellipseGraphic = new EllipseGraphic(this, e.getPoint());
433 						this.newGraphic = ellipseGraphic;
434 					}
435 					break;
436 				case FITTEDCURVE:
437 					if(this.hasPen) {
438 						FittedCurveGraphic curveGraphic = new FittedCurveGraphic(this, e.getPoint());
439 						this.newGraphic = curveGraphic;
440 					}
441 					break;
442 				case FREEHANDCURVE:
443 					if(this.hasPen) {
444 						FreehandGraphic freeGraphic = new FreehandGraphic(this, e.getPoint());
445 						this.newGraphic = freeGraphic;
446 					}
447 					break;
448 			}
449 		}
450 
451 		this.canvasPanel.getConveyFrame().updateButtons();
452 	}
453 
454 	/**
455 	 * Invoked when a mouse button has been released.
456 	 */
mouseReleased(MouseEvent e)457 	public void mouseReleased(MouseEvent e) {
458 		if(rectSelecting) {
459 
460 			// If we were selecting a rectangular region...
461 
462 			Iterator iter = graphics.iterator();
463 			while(iter.hasNext()) {
464 				Graphic graphic = (Graphic) iter.next();
465 				if(graphic.hitPath(selectRect) && graphic.getState() != Graphic.SELECTED)
466 					graphic.setState(Graphic.SELECTED);
467 			}
468 			rectSelecting = false;
469 			selectRect.grow(5, 5);
470 			super.repaint(selectRect);
471 		} else if(this.hasPen && newGraphic != null) {
472 			newGraphic.mouseReleased(e);
473 			if(newGraphic.getState() == Graphic.DELETE) {
474 				Graphic graphic = this.newGraphic;
475 				this.newGraphic = null;
476 				graphic.forceRepaint();
477 			} else if(newGraphic.getState() != Graphic.CREATING) {
478 				this.addGraphic(this.newGraphic);
479 				this.newGraphic.setState(Graphic.SELECTED);
480 				this.addGraphicEvent(new NewGraphicEvent(this.newGraphic));
481 				this.newGraphic = null;
482 			}
483 		} else if(this.hasPen && this.vertexSelected == null) {
484 			Iterator iter = this.selectedGraphics.iterator();
485 			while(iter.hasNext()) {
486 				Graphic graphic = (Graphic)iter.next();
487 				graphic.mouseReleased(e);
488 			}
489 		} else if(this.hasPen) {
490 			this.vertexSelected.mouseReleased(e);
491 			this.vertexSelected = null;
492 		}
493 
494 		GraphicEvent event = this.popAllGraphicEvents();
495 		if(event != null)
496 			this.addGraphicEvent(event);
497 
498 		this.canvasPanel.getConveyFrame().updateButtons();
499 	}
500 
501 	/**
502 	 * Invoked when the mouse has been clicked on a component.
503 	 */
mouseClicked(MouseEvent e)504 	public void mouseClicked(MouseEvent e) {
505 		if(!this.hasPen && !this.isIncoming())
506 			return;
507 
508 		if(newGraphic != null) {
509 			newGraphic.mouseClicked(e);
510 			if(newGraphic.getState() != Graphic.CREATING) {
511 				this.addGraphic(this.newGraphic);
512 				this.newGraphic.setState(Graphic.SELECTED);
513 				this.addGraphicEvent(new NewGraphicEvent(this.newGraphic));
514 				this.newGraphic = null;
515 			}
516 		} else {
517 			switch(this.state) {
518 				case SELECT:
519 				case SCALE:
520 					Iterator iter = this.selectedGraphics.iterator();
521 					while(iter.hasNext()) {
522 						Graphic graphic = (Graphic)iter.next();
523 						graphic.mouseClicked(e);
524 					}
525 					if(e.getClickCount() == 2) {
526 						Graphic hitGraphic = this.hitGraphic(e.getPoint());
527 						if(hitGraphic instanceof TextGraphic) {
528 							TextGraphic textGraphic = (TextGraphic)hitGraphic;
529 
530 							this.deselectAll();
531 
532 							this.addSelectedGraphic(textGraphic);
533 
534 							textGraphic.edit(e.getPoint());
535 						}
536 					}
537 					break;
538 				case TEXT:
539 					TextGraphic textGraphic = new TextGraphic(this, new Point(e.getX(), e.getY()));
540 					this.newGraphic = textGraphic;
541 					break;
542 				case POLYGON:
543 					PolygonGraphic polygonGraphic = new PolygonGraphic(this, e.getPoint());
544 					this.newGraphic = polygonGraphic;
545 					break;
546 				case POLYLINE:
547 					PolylineGraphic polylineGraphic = new PolylineGraphic(this, e.getPoint());
548 					this.newGraphic = polylineGraphic;
549 					break;
550 				case QUADCURVE:
551 					QuadCurveGraphic quadCurveGraphic = new QuadCurveGraphic(this, e.getPoint());
552 					this.newGraphic = quadCurveGraphic;
553 					break;
554 				case CUBICCURVE:
555 					CubicCurveGraphic cubicCurveGraphic = new CubicCurveGraphic(this, e.getPoint());
556 					this.newGraphic = cubicCurveGraphic;
557 					break;
558 			}
559 		}
560 
561 		this.canvasPanel.getConveyFrame().updateButtons();
562 	}
563 
564 	/**
565 	* Invoked when a mouse button is pressed on a component and then
566 	* dragged.  Mouse drag events will continue to be delivered to
567 	* the component where the first originated until the mouse button is
568 	* released (regardless of whether the mouse position is within the
569 	* bounds of the component).
570 	*/
mouseDragged(MouseEvent e)571 	public void mouseDragged(MouseEvent e) {
572 		if(rectSelecting) {
573 			Point p = e.getPoint();
574 			Rectangle newRectangle = new Rectangle(Math.min(pressPoint.x, p.x),
575 													 Math.min(pressPoint.y, p.y),
576 													 Math.abs(pressPoint.x - p.x),
577 													 Math.abs(pressPoint.y - p.y));
578 			Rectangle dirty = newRectangle.union(selectRect);
579 			selectRect = newRectangle;
580 			dirty.grow(5, 5);
581 			super.repaint(dirty);
582 		} else if(this.hasPen) {
583 			if(newGraphic != null) {
584 				newGraphic.mouseDragged(e);
585 				if(newGraphic.getState() != Graphic.CREATING) {
586 					this.addGraphic(this.newGraphic);
587 					this.newGraphic.setState(Graphic.SELECTED);
588 					this.addGraphicEvent(new NewGraphicEvent(this.newGraphic));
589 					this.newGraphic = null;
590 				}
591 			} else if(this.vertexSelected == null) {
592 				Iterator iter = this.selectedGraphics.iterator();
593 				while(iter.hasNext()) {
594 					Graphic graphic = (Graphic) iter.next();
595 					graphic.mouseDragged(e);
596 				}
597 			} else
598 				this.vertexSelected.mouseDragged(e);
599 		}
600 	}
601 
602 	/**
603 	 * Invoked when the mouse button has been moved on a component
604 	 * (with no buttons or mouse buttons pressed)
605 	 */
mouseMoved(MouseEvent e)606 	public void mouseMoved(MouseEvent e) {
607 		if(!this.hasPen && !this.isIncoming())
608 			return;
609 
610 		if(newGraphic != null) {
611 			newGraphic.mouseMoved(e);
612 			int state = this.newGraphic.getState();
613 			if(state != Graphic.CREATING) {
614 				this.addGraphic(this.newGraphic);
615 				this.newGraphic.setState(Graphic.SELECTED);
616 				this.addGraphicEvent(new NewGraphicEvent(this.newGraphic));
617 				this.newGraphic = null;
618 			}
619 		} else {
620 			Iterator iter = this.selectedGraphics.iterator();
621 			while(iter.hasNext()) {
622 				Graphic graphic = (Graphic)iter.next();
623 				graphic.mouseMoved(e);
624 			}
625 		}
626 	}
627 
628 		/**
629 	 * Invoked when the mouse exits a component.
630 	 */
mouseExited(MouseEvent e)631 	public void mouseExited(MouseEvent e) {}
632 
633 		/**
634 		 * Invoked when the mouse enters a component.
635 	 */
mouseEntered(MouseEvent e)636 	public void mouseEntered(MouseEvent e) {}
637 
638 	/**
639 	 * Invoked when a key has been typed. This event occurs when a key press is
640 	 * followed by a key release.
641 	 */
keyTyped(KeyEvent e)642 	public void keyTyped(KeyEvent e) {
643 		if(!this.hasPen && !this.isIncoming())
644 			return;
645 
646 		if(this.newGraphic != null && this.newGraphic instanceof TextGraphic) {
647 			TextGraphic textGraphic = (TextGraphic)this.newGraphic;
648 			textGraphic.keyTyped(e);
649 			if(textGraphic.getState() != Graphic.CREATING) {
650 				this.addGraphic(this.newGraphic);
651 				this.addGraphicEvent(new NewGraphicEvent(this.newGraphic));
652 				this.newGraphic.setState(Graphic.SELECTED);
653 				this.newGraphic = null;
654 			}
655 		} else {
656 			if(this.selectedGraphics.size() == 1 && this.selectedGraphics.elementAt(0) instanceof TextGraphic) {
657 				TextGraphic textGraphic = (TextGraphic)this.selectedGraphics.elementAt(0);
658 				textGraphic.keyTyped(e);
659 			}
660 		}
661 	}
662 
663 	/**
664 	 * Invoked when a key has been pressed.
665 	 */
keyPressed(KeyEvent e)666 	public void keyPressed(KeyEvent e) {
667 		if(!this.hasPen && !this.isIncoming())
668 			return;
669 
670 		if(this.newGraphic != null && this.newGraphic instanceof TextGraphic) {
671 			TextGraphic textGraphic = (TextGraphic)this.newGraphic;
672 			textGraphic.keyPressed(e);
673 			if(textGraphic.getState() != Graphic.CREATING) {
674 				this.addGraphic(this.newGraphic);
675 				this.addGraphicEvent(new NewGraphicEvent(this.newGraphic));
676 				this.newGraphic.setState(Graphic.SELECTED);
677 				this.newGraphic = null;
678 			}
679 		} else if(this.selectedGraphics.size() == 1 && this.selectedGraphics.elementAt(0) instanceof TextGraphic) {
680 			TextGraphic textGraphic = (TextGraphic)this.selectedGraphics.elementAt(0);
681 			textGraphic.keyPressed(e);
682 		}
683 	}
684 
685 	/**
686 	 * Invoked when a key has been released.
687 	 */
keyReleased(KeyEvent e)688 	public void keyReleased(KeyEvent e) {
689 		if(!this.hasPen && !this.isIncoming())
690 			return;
691 	}
692 
693 	/**
694 	 * Method iterates through the vector of all graphics in the graphicPanel
695 	 * and creates a new vectosr of the selected ones, which replaces the selected
696 	 * graphics as a single component of the vector of all graphics.
697 	 */
editGroup()698 	public void editGroup() {
699 		if(!this.hasPen && !this.isIncoming())
700 			return;
701 
702 		GroupGraphic group = new GroupGraphic(this);
703 
704 			Vector oldSelectedGraphics = this.selectedGraphics;
705 			this.selectedGraphics = new Vector();
706 
707 		Iterator iter = oldSelectedGraphics.iterator();
708 		while (iter.hasNext()) {
709 			Graphic graphic = (Graphic) iter.next();
710 
711 			graphic.setState(Graphic.DORMANT);
712 			this.graphics.remove(graphic);
713 
714 			group.addGraphic(graphic);
715 		}
716 
717 		this.addGraphic(group);
718 		group.setState(Graphic.SELECTED);
719 
720 		group.updateCache();
721 
722 		if(!this.isIncoming())
723 			this.addGraphicEvent(new GroupGraphicEvent(group, GroupGraphicEvent.TYPE_GROUP));
724 
725 		this.canvasPanel.getConveyFrame().updateButtons();
726 	}
727 
editUngroup()728 	public void editUngroup() {
729 		if(!this.hasPen && !this.isIncoming())
730 			return;
731 
732 		GroupGraphic group = (GroupGraphic)this.selectedGraphics.elementAt(0);
733 
734 		if(this.state == SCALE)
735 			this.setState(SELECT);
736 
737 		// Do the following three in this order so the GroupGraphic gets repainted
738 		this.selectedGraphics.clear();
739 		this.removeGraphic(group);
740 
741 		Iterator iter = group.iterator();
742 
743 		while(iter.hasNext()) {
744 			Graphic graphic = (Graphic)iter.next();
745 
746 			graphic.setState(Graphic.SELECTED);
747 
748 			this.graphics.add(graphic);
749 		}
750 
751 		this.canvasPanel.getConveyFrame().updateButtons();
752 
753 		if(!this.isIncoming())
754 			this.addGraphicEvent(new GroupGraphicEvent(group, GroupGraphicEvent.TYPE_UNGROUP));
755 	}
756 
editCut()757 	public void editCut() {
758 		if(!this.hasPen && !this.isIncoming())
759 			return;
760 
761 		this.canvasPanel.getConveyFrame().getClipboardGraphics().removeAllElements();
762 
763 		Vector oldSelectedGraphics = this.selectedGraphics;
764 		this.selectedGraphics = new Vector();
765 
766 		Vector graphicEvents = new Vector();
767 
768 		Iterator iter = oldSelectedGraphics.iterator();
769 		while(iter.hasNext()) {
770 			Graphic graphic = (Graphic)iter.next();
771 
772 			// Do the following two in this order so the Graphic gets erased
773 			this.removeGraphic(graphic);
774 
775 			this.canvasPanel.getConveyFrame().getClipboardGraphics().add(graphic.toElement());
776 
777 			graphicEvents.add(new DeleteGraphicEvent(graphic));
778 		}
779 
780 		if(graphicEvents.size() > 1)
781 			this.addGraphicEvent(new CompositeGraphicEvent(graphicEvents));
782 		else if(graphicEvents.size() == 1)
783 			this.addGraphicEvent((GraphicEvent)graphicEvents.elementAt(0));
784 
785 		this.canvasPanel.getConveyFrame().updateButtons();
786 	}
787 
editCopy()788 	public void editCopy() {
789 		Graphic graphic;
790 		this.canvasPanel.getConveyFrame().getClipboardGraphics().removeAllElements();
791 		Iterator iter = this.selectedGraphics.iterator();
792 		while (iter.hasNext()) {
793 			graphic = (Graphic)iter.next();
794 			this.canvasPanel.getConveyFrame().getClipboardGraphics().add(graphic.toElement());
795 		}
796 		this.canvasPanel.getConveyFrame().updateButtons();
797 	}
798 
editPaste()799 	public void editPaste() {
800 		if(!this.hasPen && !this.isIncoming())
801 			return;
802 
803 		Graphic graphic;
804 
805 		deselectAll();
806 
807 		Vector graphicEvents = new Vector();
808 
809 		Iterator iter = this.canvasPanel.getConveyFrame().getClipboardGraphics().iterator();
810 		while(iter.hasNext()) {
811 			graphic = this.createGraphicFromSVGElement((Element)iter.next());
812 
813 			this.addGraphic(graphic);
814 			graphic.setGraphicPanel(this);
815 
816 			graphic.setState(Graphic.SELECTED);
817 
818 			graphic.updateCache();
819 
820 			graphicEvents.add(new NewGraphicEvent(graphic));
821 		}
822 
823 		if(graphicEvents.size() > 1)
824 			this.addGraphicEvent(new CompositeGraphicEvent(graphicEvents));
825 		else if(graphicEvents.size() == 1)
826 			this.addGraphicEvent((GraphicEvent)graphicEvents.elementAt(0));
827 
828 		this.canvasPanel.getConveyFrame().updateButtons();
829 	}
830 
editDelete()831 	public void editDelete() {
832 		if(!this.hasPen && !this.isIncoming())
833 			return;
834 
835 		// Hack to avoid deleting a TextGraphic while it is in edit mode. When in
836 		// edit mode, we want the TextGraphic to handle the delete key press.
837 		if(this.selectedGraphics.size() == 1 && this.selectedGraphics.elementAt(0) instanceof TextGraphic)
838 			if(((TextGraphic)this.selectedGraphics.elementAt(0)).getCursor() != -1)
839 				return;
840 
841 		Vector graphicEvents = new Vector();
842 
843 		Vector oldSelectedGraphics = this.selectedGraphics;
844 		this.selectedGraphics = new Vector();
845 
846 		Iterator iter = oldSelectedGraphics.iterator();
847 		while(iter.hasNext()) {
848 			Graphic graphic = (Graphic)iter.next();
849 
850 			// Do the following two in this order so the Graphic gets erased
851 			this.removeGraphic(graphic);
852 
853 			graphicEvents.add(new DeleteGraphicEvent(graphic));
854 		}
855 
856 		if(graphicEvents.size() > 1)
857 			this.addGraphicEvent(new CompositeGraphicEvent(graphicEvents));
858 		else if(graphicEvents.size() == 1)
859 			this.addGraphicEvent((GraphicEvent)graphicEvents.elementAt(0));
860 
861 		this.canvasPanel.getConveyFrame().updateButtons();
862 	}
863 
editClear()864 	public void editClear() {
865 		if(!this.hasPen && !this.isIncoming())
866 			return;
867 
868 		Vector oldGraphics = this.graphics;
869 		this.graphics = new Vector();
870 
871 		Vector graphicEvents = new Vector();
872 
873 		Iterator iter = oldGraphics.iterator();
874 		while(iter.hasNext()) {
875 			Graphic graphic = (Graphic)iter.next();
876 
877 			graphic.setState(Graphic.DORMANT);
878 
879 			graphicEvents.add(new DeleteGraphicEvent(graphic));
880 		}
881 
882 		if(graphicEvents.size() > 1)
883 			this.addGraphicEvent(new CompositeGraphicEvent(graphicEvents));
884 		else if(graphicEvents.size() == 1)
885 			this.addGraphicEvent((GraphicEvent)graphicEvents.elementAt(0));
886 
887 		this.canvasPanel.getConveyFrame().updateButtons();
888 
889 		super.repaint();
890 	}
891 
handleConveyElement(Element conveyElement)892 	public void handleConveyElement(Element conveyElement) {
893 		this.setIncoming(true);
894 		Iterator iter = conveyElement.getChildren().iterator();
895 
896 		while(iter.hasNext()) {
897 			Element element = (Element)iter.next();
898 
899 			handleGraphicEventElement(element);
900 		}
901 		this.setIncoming(false);
902 
903 		this.canvasPanel.getConveyFrame().updateButtons();
904 	}
905 
906 	/**
907 	 * @todo Implement EllipseGraphicEvent and QuadGraphicEvent handling. They
908 	 * weren't implemented yet because we still cannot even modify them via
909 	 * vertex manipulation. This are no longer necessary because these events
910 	 * are implemented via fitToRect().
911 	 */
handleGraphicEventElement(Element element)912 	public void handleGraphicEventElement(Element element) {
913 		String name = element.getName();
914 
915 		if(name.equals("new")) {
916 			Iterator childIter = element.getChildren().iterator();
917 			while(childIter.hasNext()) {
918 				Element svgElement = (Element)childIter.next();
919 				Graphic graphic = this.createGraphicFromSVGElement(svgElement);
920 
921 				this.addGraphic(graphic);
922 				graphic.setState(Graphic.DORMANT);
923 			}
924 		} else if(name.equals("name")) {
925 			Graphic graphic = (Graphic)this.nameGraphicTable.get(element.getAttributeValue("old"));
926 			if(graphic == null)
927 				return;
928 			graphic.setName(element.getAttributeValue("new"));
929 		} else if(name.equals("composite")) {
930 			Iterator iter = element.getChildren().iterator();
931 			while(iter.hasNext())
932 				this.handleGraphicEventElement((Element)iter.next());
933 		} else if(name.equals("group")) {
934 			this.deselectAll();
935 			switch(Integer.parseInt(element.getAttributeValue("type"))) {
936 				case GroupGraphicEvent.TYPE_GROUP:
937 					Iterator iter = element.getChildren().iterator();
938 					while(iter.hasNext()) {
939 						Element childElement = (Element)iter.next();
940 						Graphic g = (Graphic)this.nameGraphicTable.get(childElement.getAttributeValue("name"));
941 						if(g == null)
942 							return;
943 						g.setState(Graphic.SELECTED);
944 					}
945 					this.editGroup();
946 					break;
947 				case GroupGraphicEvent.TYPE_UNGROUP:
948 					Graphic g = (Graphic)this.nameGraphicTable.get(element.getAttributeValue("name"));
949 					if(g == null)
950 						return;
951 					g.setState(Graphic.SELECTED);
952 					this.editUngroup();
953 					break;
954 			}
955 		} else {
956 			Graphic g = (Graphic)this.nameGraphicTable.get(element.getAttributeValue("name"));
957 			if(g == null)
958 				return;
959 
960 			if(name.equals("shape")) {
961 				ShapeGraphic graphic = (ShapeGraphic) g;
962 				switch (Integer.parseInt(element.getAttributeValue("type"))) {
963 					case ShapeGraphicEvent.TYPE_FILL:
964 						graphic.setFillColor(ShapeGraphic.stringToColor(element.getAttributeValue("newColor")));
965 						break;
966 					case ShapeGraphicEvent.TYPE_STROKE:
967 						graphic.setStrokeColor(ShapeGraphic.stringToColor(element.getAttributeValue("newColor")));
968 						break;
969 				}
970 			}
971 			else if(name.equals("delete"))
972 				this.removeGraphic(g);
973 			else if(name.equals("translate"))
974 				g.translate(Integer.parseInt(element.getAttributeValue("x")),
975 										Integer.parseInt(element.getAttributeValue("y")));
976 			else if(name.equals("fitToRect")) {
977 				Element newRect = element.getChild("new");
978 				g.setOrig();
979 				g.fitToRect(new Rectangle(Integer.parseInt(newRect.getAttributeValue("x")),
980 																	Integer.parseInt(newRect.getAttributeValue("y")),
981 																	Integer.parseInt(newRect.getAttributeValue("w")),
982 																	Integer.parseInt(newRect.getAttributeValue("h"))));
983 			} else if (name.equals("polyline")) {
984 				PolylineGraphic graphic = (PolylineGraphic) g;
985 				Vector points = graphic.getPoints();
986 				Point2D p = (Point2D) points.elementAt(Integer.parseInt(element.getAttributeValue("index")));
987 				Element pElement = element.getChild("new");
988 				p.setLocation(Double.parseDouble(pElement.getAttributeValue("x")),
989 											Double.parseDouble(pElement.getAttributeValue("y")));
990 				graphic.setPoints(points);
991 			} else if (name.equals("polygon")) {
992 				PolygonGraphic graphic = (PolygonGraphic) g;
993 				Vector points = graphic.getPoints();
994 				Point2D p = (Point2D) points.elementAt(Integer.parseInt(element.getAttributeValue("index")));
995 				Element pElement = element.getChild("new");
996 				p.setLocation(Double.parseDouble(pElement.getAttributeValue("x")),
997 											Double.parseDouble(pElement.getAttributeValue("y")));
998 				graphic.setPoints(points);
999 			} else if (name.equals("cubicCurve")) {
1000 				CubicCurveGraphic graphic = (CubicCurveGraphic) g;
1001 				Element pElement = element.getChild("new");
1002 				CubicCurve2D curve = new CubicCurve2D.Double(Double.parseDouble(pElement.getAttributeValue("x1")),
1003 						Double.parseDouble(pElement.getAttributeValue("y1")),
1004 						Double.parseDouble(pElement.getAttributeValue("ctrlx1")),
1005 						Double.parseDouble(pElement.getAttributeValue("ctrly1")),
1006 						Double.parseDouble(pElement.getAttributeValue("ctrlx2")),
1007 						Double.parseDouble(pElement.getAttributeValue("ctrly2")),
1008 						Double.parseDouble(pElement.getAttributeValue("x2")),
1009 						Double.parseDouble(pElement.getAttributeValue("y2")));
1010 				graphic.setCurve(curve);
1011 			} else if(name.equals("quadCurve")) {
1012 				QuadCurveGraphic graphic = (QuadCurveGraphic) g;
1013 				Element pElement = element.getChild("new");
1014 				QuadCurve2D curve = new QuadCurve2D.Double(Double.parseDouble(pElement.getAttributeValue("x1")),
1015 						Double.parseDouble(pElement.getAttributeValue("y1")),
1016 						Double.parseDouble(pElement.getAttributeValue("ctrlx")),
1017 						Double.parseDouble(pElement.getAttributeValue("ctrly")),
1018 						Double.parseDouble(pElement.getAttributeValue("x2")),
1019 						Double.parseDouble(pElement.getAttributeValue("y2")));
1020 				graphic.setCurve(curve);
1021 			} else if(name.equals("text")) {
1022 				TextGraphic graphic = (TextGraphic)g;
1023 				Element newChild = element.getChild("new");
1024 				graphic.setText(newChild.getText());
1025 				graphic.setTextColor(Graphic.stringToColor(newChild.getAttributeValue("color")));
1026 			} else if(name.equals("position")) {
1027 				this.removeGraphic(g);
1028 				this.insertGraphic(g, Integer.parseInt(element.getAttributeValue("newIndex")));
1029 			}
1030 		}
1031 
1032 		super.repaint();
1033 	}
1034 
createGraphicFromSVGElement(Element element)1035 	public Graphic createGraphicFromSVGElement(Element element) {
1036 		Graphic graphic = null;
1037 		String name = element.getName();
1038 		if(name.equals("g"))
1039 			graphic = new GroupGraphic(this);
1040 		else if(name.equals("path")) {
1041 			String d = element.getAttributeValue("d");
1042 			for(int i = 0; i < d.length(); i++) {
1043 				if(d.charAt(i) == 'Q')
1044 					graphic = new QuadCurveGraphic(this);
1045 				else if(d.charAt(i) == 'C') {
1046 					graphic = new CubicCurveGraphic(this);
1047 				} else if (d.charAt(i) == 'M')  {
1048 					graphic = new FreehandGraphic(this);
1049 				}
1050 			}
1051 		} else if(name.equals("rect"))
1052 			graphic = new QuadGraphic(this);
1053 		else if(name.equals("ellipse"))
1054 			graphic = new EllipseGraphic(this);
1055 		else if(name.equals("polyline"))
1056 			graphic = new PolylineGraphic(this);
1057 		else if(name.equals("polygon"))
1058 			graphic = new PolygonGraphic(this);
1059 		else if(name.equals("text"))
1060 			graphic = new TextGraphic(this);
1061 
1062 		if(graphic != null)
1063 			graphic.fromElement(element);
1064 
1065 		return graphic;
1066 	}
1067 
hitGraphic(Point p)1068 	protected Graphic hitGraphic(Point p) {
1069 		if(this.graphics.size() == 0)
1070 			return null;
1071 
1072 		ListIterator iter = this.graphics.listIterator(this.graphics.size());
1073 		while(iter.hasPrevious()) {
1074 			Graphic graphic = (Graphic)iter.previous();
1075 			if(graphic.hitPath(p) || graphic.hitVertex(p))
1076 				return graphic;
1077 		}
1078 
1079 		return null;
1080 	}
1081 
graphicCount()1082 	public int graphicCount() {
1083 		return this.graphics.size();
1084 	}
1085 
selectedGraphicCount()1086 	public int selectedGraphicCount() {
1087 		return this.selectedGraphics.size();
1088 	}
1089 
selectedGraphic(int index)1090 	public Graphic selectedGraphic(int index) {
1091 		return (Graphic)this.selectedGraphics.elementAt(index);
1092 	}
1093 
selectAll()1094 	public void selectAll() {
1095 		Iterator iter = this.graphics.iterator();
1096 		while(iter.hasNext()) {
1097 			Graphic graphic = (Graphic)iter.next();
1098 			graphic.setState(Graphic.SELECTED);
1099 		}
1100 
1101 		this.canvasPanel.getConveyFrame().updateButtons();
1102 	}
1103 
pushGraphicEvent(GraphicEvent event)1104 	public void pushGraphicEvent(GraphicEvent event) {
1105 		this.graphicEventStack.add(event);
1106 	}
1107 
popAllGraphicEvents()1108 	public GraphicEvent popAllGraphicEvents() {
1109 		if(this.graphicEventStack.size() == 0)
1110 			return null;
1111 		else if(this.graphicEventStack.size() == 1) {
1112 			GraphicEvent event = (GraphicEvent)this.graphicEventStack.elementAt(0);
1113 			this.graphicEventStack.clear();
1114 			return event;
1115 		}
1116 
1117 		CompositeGraphicEvent event = new CompositeGraphicEvent(this.graphicEventStack);
1118 		this.graphicEventStack = new Vector();
1119 		return event;
1120 	}
1121 
addGraphicEvent(GraphicEvent event)1122 	public void addGraphicEvent(GraphicEvent event) {
1123 		if(this.lastGraphicEventIndex < this.graphicEvents.size() - 1) {
1124 			while(this.lastGraphicEventIndex < this.graphicEvents.size() - 1)
1125 				this.graphicEvents.remove(this.graphicEvents.size() - 1);
1126 		}
1127 		this.graphicEvents.add(event);
1128 		this.lastGraphicEventIndex++;
1129 
1130 		if(this.getCanvasPanel().getConveyFrame().isAutoSend()) {
1131 			if(this.canvasPanel instanceof JabberCanvasPanel) {
1132 				JabberCanvasPanel panel = (JabberCanvasPanel)this.canvasPanel;
1133 				panel.sendGraphicEvent(event);
1134 			}
1135 		} else
1136 			graphicEventQueue.add(event);
1137 	}
1138 
flushGraphicEventQueue()1139 	public void flushGraphicEventQueue() {
1140 		if(this.canvasPanel instanceof JabberCanvasPanel) {
1141 			if(this.graphicEventQueue.size() == 0)
1142 				return;
1143 			else if(this.graphicEventQueue.size() == 1) {
1144 				GraphicEvent event = (GraphicEvent)this.graphicEventQueue.elementAt(0);
1145 				this.graphicEventQueue.clear();
1146 				JabberCanvasPanel panel = (JabberCanvasPanel)this.canvasPanel;
1147 				panel.sendGraphicEvent(event);
1148 			}
1149 
1150 			CompositeGraphicEvent event = new CompositeGraphicEvent(this.graphicEventQueue);
1151 			this.graphicEventQueue = new Vector();
1152 			JabberCanvasPanel panel = (JabberCanvasPanel)this.canvasPanel;
1153 			panel.sendGraphicEvent(event);
1154 		}
1155 	}
1156 
undoGraphicEvent(GraphicEvent event)1157 	protected void undoGraphicEvent(GraphicEvent event) {
1158 		if(event instanceof CompositeGraphicEvent) {
1159 			Iterator iter = ((CompositeGraphicEvent)event).getGraphicEvents().iterator();
1160 			while(iter.hasNext()) {
1161 				event = (GraphicEvent)iter.next();
1162 				this.undoGraphicEvent(event);
1163 			}
1164 		} else {
1165 			Graphic graphic = event.getGraphic();
1166 			graphic.undoGraphicEvent(event);
1167 		}
1168 	}
1169 
editUndo()1170 	public void editUndo() {
1171 		if(!this.hasPen && !this.isIncoming())
1172 			return;
1173 
1174 		if(this.lastGraphicEventIndex > -1) {
1175 			GraphicEvent event = (GraphicEvent)this.graphicEvents.elementAt(this.lastGraphicEventIndex);
1176 			this.undoGraphicEvent(event);
1177 			lastGraphicEventIndex--;
1178 		}
1179 		this.canvasPanel.getConveyFrame().updateButtons();
1180 	}
1181 
redoGraphicEvent(GraphicEvent event)1182 	protected void redoGraphicEvent(GraphicEvent event) {
1183 		if(event instanceof CompositeGraphicEvent) {
1184 			Iterator iter = ((CompositeGraphicEvent)event).getGraphicEvents().iterator();
1185 			while(iter.hasNext()) {
1186 				event = (GraphicEvent)iter.next();
1187 				this.redoGraphicEvent(event);
1188 			}
1189 		} else {
1190 			Graphic graphic = event.getGraphic();
1191 			graphic.redoGraphicEvent(event);
1192 		}
1193 	}
1194 
editRedo()1195 	public void editRedo() {
1196 		if(!this.hasPen && !this.isIncoming())
1197 			return;
1198 
1199 		if(this.lastGraphicEventIndex < this.graphicEvents.size() - 1) {
1200 			this.lastGraphicEventIndex++;
1201 			GraphicEvent event = (GraphicEvent)this.graphicEvents.elementAt(this.lastGraphicEventIndex);
1202 			this.redoGraphicEvent(event);
1203 		}
1204 		this.canvasPanel.getConveyFrame().updateButtons();
1205 	}
1206 
getGraphicEvents()1207 	public Vector getGraphicEvents() {
1208 		return this.graphicEvents;
1209 	}
1210 
getLastGraphicEventIndex()1211 	public int getLastGraphicEventIndex() {
1212 		return this.lastGraphicEventIndex;
1213 	}
1214 
removeGraphic(Graphic graphic)1215 	public void removeGraphic(Graphic graphic) {
1216 		if(this.nameGraphicTable.containsKey(graphic.getName()))
1217 			this.nameGraphicTable.remove(graphic.getName());
1218 		if(this.graphics.contains(graphic))
1219 			this.graphics.remove(graphic);
1220 
1221 		graphic.setState(Graphic.DORMANT);
1222 		graphic.forceRepaint();
1223 	}
1224 
addGraphic(Graphic graphic)1225 	public void addGraphic(Graphic graphic) {
1226 		this.insertGraphic(graphic, this.graphics.size());
1227 	}
1228 
insertGraphic(Graphic graphic, int index)1229 	public void insertGraphic(Graphic graphic, int index) {
1230 		if(!this.nameGraphicTable.containsKey(graphic.getName()))
1231 			this.nameGraphicTable.put(graphic.getName(), graphic);
1232 		else {
1233 			String origName = graphic.getName();
1234 			int i;
1235 			for(i = origName.length() - 1; i >= 0; i--) {
1236 				if(!Character.isDigit(origName.charAt(i))) {
1237 					origName = origName.substring(0, i + 1);
1238 					break;
1239 				}
1240 			}
1241 			if(i == 0)
1242 				origName = "";
1243 			for(i = 1; i < Integer.MAX_VALUE; i++) {
1244 				String tryName = origName + String.valueOf(i);
1245 				if(!this.nameGraphicTable.containsKey(tryName)) {
1246 
1247 					// This breaks OOP ideology. We are accessing a protected member
1248 					// of another class in this package. We are doing this because we
1249 					// do not want to send the Name change graphic event across the
1250 					// network before we have sent the NewGraphicEvent.
1251 					//
1252 					// We need a more elegant solution.
1253 					graphic.name = tryName;
1254 					this.nameGraphicTable.put(tryName, graphic);
1255 					break;
1256 				}
1257 			}
1258 		}
1259 
1260 		if(!this.graphics.contains(graphic))
1261 			this.graphics.insertElementAt(graphic, index);
1262 
1263 		graphic.setState(Graphic.DORMANT);
1264 		graphic.forceRepaint();
1265 	}
1266 
addSelectedGraphic(Graphic graphic)1267 	public void addSelectedGraphic(Graphic graphic) {
1268 		// These must be done in this order to prevent infinite loop
1269 		if(!this.selectedGraphics.contains(graphic))
1270 			this.selectedGraphics.add(graphic);
1271 		graphic.setState(Graphic.SELECTED);
1272 	}
1273 
removeSelectedGraphic(Graphic graphic)1274 	public void removeSelectedGraphic(Graphic graphic) {
1275 		// These must be done in this order to prevent infinite loop
1276 		if(this.selectedGraphics.contains(graphic))
1277 			this.selectedGraphics.remove(graphic);
1278 		graphic.setState(Graphic.DORMANT);
1279 	}
1280 
getCanvasPanel()1281 	public CanvasPanel getCanvasPanel() {
1282 		return this.canvasPanel;
1283 	}
1284 
getSelectedGraphics()1285 	public Vector getSelectedGraphics() {
1286 		return this.selectedGraphics;
1287 	}
1288 
containsName(String name)1289 	public boolean containsName(String name) {
1290 		return this.nameGraphicTable.containsKey(name);
1291 	}
1292 
isFocusTraversible()1293 	public boolean isFocusTraversible() {
1294 		return true;
1295 	}
1296 
setSelectedFillColors(Color color)1297 	public void setSelectedFillColors(Color color) {
1298 		if(!this.hasPen && !this.isIncoming())
1299 			return;
1300 
1301 		Iterator iter = this.selectedGraphics.iterator();
1302 		while(iter.hasNext()) {
1303 			Graphic graphic = (Graphic)iter.next();
1304 			if(graphic instanceof ShapeGraphic)
1305 				((ShapeGraphic)graphic).setFillColor(color);
1306 		}
1307 	}
1308 
setSelectedStrokeColors(Color color)1309 	public void setSelectedStrokeColors(Color color) {
1310 		if(!this.hasPen && !this.isIncoming())
1311 			return;
1312 
1313 		Iterator iter = this.selectedGraphics.iterator();
1314 		while(iter.hasNext()) {
1315 			Graphic graphic = (Graphic)iter.next();
1316 			if(graphic instanceof ShapeGraphic)
1317 				((ShapeGraphic)graphic).setStrokeColor(color);
1318 		}
1319 	}
1320 
setSelectedTextColors(Color color)1321 	public void setSelectedTextColors(Color color) {
1322 		if(!this.hasPen && !this.isIncoming())
1323 			return;
1324 
1325 		Iterator iter = this.selectedGraphics.iterator();
1326 		while(iter.hasNext()) {
1327 			Graphic graphic = (Graphic)iter.next();
1328 			if(graphic instanceof TextGraphic)
1329 				((TextGraphic)graphic).setTextColor(color);
1330 		}
1331 	}
1332 
editSendToBack()1333 	public void editSendToBack() {
1334 		if(!this.hasPen && !this.isIncoming())
1335 			return;
1336 
1337 		Object[] graphics = this.graphics.toArray();
1338 		int index = 0;
1339 		for(int i = 0; i < graphics.length; i++) {
1340 			Graphic graphic = (Graphic)graphics[i];
1341 			if(graphic.getState() == Graphic.SELECTED) {
1342 				this.pushGraphicEvent(new PositionChangeEvent(graphic, i, index));
1343 				this.removeGraphic(graphic);
1344 				this.insertGraphic(graphic, index);
1345 				graphic.setState(Graphic.SELECTED);
1346 				index++;
1347 			}
1348 		}
1349 		GraphicEvent event = this.popAllGraphicEvents();
1350 		if(event != null)
1351 			this.addGraphicEvent(event);
1352 	}
1353 
editBringToFront()1354 	public void editBringToFront() {
1355 		if(!this.hasPen && !this.isIncoming())
1356 			return;
1357 
1358 		Object[] graphics = this.graphics.toArray();
1359 		int index = graphics.length - 1;
1360 		for(int i = 0; i < graphics.length; i++) {
1361 			Graphic graphic = (Graphic)graphics[i];
1362 			if(graphic.getState() == Graphic.SELECTED) {
1363 				this.pushGraphicEvent(new PositionChangeEvent(graphic, i, index));
1364 				this.removeGraphic(graphic);
1365 				this.addGraphic(graphic);
1366 				graphic.setState(Graphic.SELECTED);
1367 				index--;
1368 			}
1369 		}
1370 		GraphicEvent event = this.popAllGraphicEvents();
1371 		if(event != null)
1372 			this.addGraphicEvent(event);
1373 	}
1374 
editSendBackward()1375 	public void editSendBackward() {
1376 		if(!this.hasPen && !this.isIncoming())
1377 			return;
1378 
1379 		Object[] graphics = this.graphics.toArray();
1380 
1381 		int lowestIndex;
1382 		for(lowestIndex = 0; lowestIndex < graphics.length; lowestIndex++) {
1383 			Graphic graphic = (Graphic)graphics[lowestIndex];
1384 			if(graphic.getState() != Graphic.SELECTED)
1385 				break;
1386 		}
1387 
1388 		int begin;
1389 		for(begin = lowestIndex; begin < graphics.length; begin++) {
1390 			Graphic graphic = (Graphic)graphics[begin];
1391 			if(graphic.getState() == Graphic.SELECTED) {
1392 				int end;
1393 				for(end = begin + 1; end < graphics.length; end++) {
1394 					graphic = (Graphic)graphics[end];
1395 					if(graphic.getState() != Graphic.SELECTED)
1396 						break;
1397 				}
1398 
1399 				for(int k = begin; k < end; k++) {
1400 					graphic = (Graphic)graphics[k];
1401 					this.pushGraphicEvent(new PositionChangeEvent(graphic, k, k - 1));
1402 					this.removeGraphic(graphic);
1403 					this.insertGraphic(graphic, k - 1);
1404 					graphic.setState(Graphic.SELECTED);
1405 				}
1406 			}
1407 		}
1408 		GraphicEvent event = this.popAllGraphicEvents();
1409 		if(event != null)
1410 			this.addGraphicEvent(event);
1411 	}
1412 
editBringForward()1413 	public void editBringForward() {
1414 		if(!this.hasPen && !this.isIncoming())
1415 			return;
1416 
1417 		Object[] graphics = this.graphics.toArray();
1418 
1419 		int highestIndex;
1420 		for(highestIndex = graphics.length - 1; highestIndex >= 0 ; highestIndex--) {
1421 			Graphic graphic = (Graphic)graphics[highestIndex];
1422 			if(graphic.getState() != Graphic.SELECTED)
1423 				break;
1424 		}
1425 
1426 		int begin;
1427 		for(begin = highestIndex; begin >= 0; begin--) {
1428 			Graphic graphic = (Graphic)graphics[begin];
1429 			if(graphic.getState() == Graphic.SELECTED) {
1430 				int end;
1431 				for(end = begin - 1; end >= 0; end--) {
1432 					graphic = (Graphic)graphics[end];
1433 					if(graphic.getState() != Graphic.SELECTED)
1434 						break;
1435 				}
1436 
1437 				for(int k = begin; k > end; k--) {
1438 					graphic = (Graphic)graphics[k];
1439 					this.pushGraphicEvent(new PositionChangeEvent(graphic, k, k + 1));
1440 					this.removeGraphic(graphic);
1441 					this.insertGraphic(graphic, k + 1);
1442 					graphic.setState(Graphic.SELECTED);
1443 				}
1444 			}
1445 		}
1446 		GraphicEvent event = this.popAllGraphicEvents();
1447 		if(event != null)
1448 			this.addGraphicEvent(event);
1449 	}
1450 
1451 }