001: /*
002: * @(#)VertexRenderer.java 1.0 03-JUL-04
003: *
004: * Copyright (c) 2001-2004 Gaudenz Alder
005: *
006: */
007: package org.jgraph.graph;
008:
009: import java.awt.Color;
010: import java.awt.Component;
011: import java.awt.Dimension;
012: import java.awt.GradientPaint;
013: import java.awt.Graphics;
014: import java.awt.Graphics2D;
015: import java.awt.Rectangle;
016: import java.awt.Stroke;
017: import java.awt.geom.Point2D;
018: import java.awt.geom.Rectangle2D;
019: import java.io.Serializable;
020: import java.util.Map;
021:
022: import javax.swing.BorderFactory;
023: import javax.swing.JLabel;
024: import javax.swing.UIManager;
025:
026: import org.jgraph.JGraph;
027:
028: /**
029: * This renderer displays entries that implement the CellView interface and
030: * supports the following attributes. If the cell view is not a leaf, this
031: * object is only visible if it is selected.
032: * <li>GraphConstants.BOUNDS GraphConstants.ICON GraphConstants.FONT
033: * GraphConstants.OPAQUE GraphConstants.BORDER GraphConstants.BORDERCOLOR
034: * GraphConstants.LINEWIDTH GraphConstants.FOREGROUND GraphConstants.BACKGROUND
035: * GraphConstants.VERTICAL_ALIGNMENT GraphConstants.HORIZONTAL_ALIGNMENT
036: * GraphConstants.VERTICAL_TEXT_POSITION GraphConstants.HORIZONTAL_TEXT_POSITION
037: * </li>
038: *
039: * @version 1.0 1/1/02
040: * @author Gaudenz Alder
041: */
042:
043: public class VertexRenderer extends JLabel implements CellViewRenderer,
044: Serializable {
045:
046: /** Cache the current shape for drawing. */
047: transient protected VertexView view;
048:
049: /** Cached hasFocus and selected value. */
050: transient protected boolean hasFocus, selected, preview,
051: childrenSelected;
052:
053: /** Cached default foreground and default background. */
054: transient protected Color defaultForeground, defaultBackground,
055: bordercolor;
056:
057: /** Cached borderwidth. */
058: transient protected int borderWidth;
059:
060: /** Cached value of the double buffered state */
061: transient protected boolean isDoubleBuffered = false;
062:
063: transient protected Color gradientColor = null,
064: gridColor = Color.black, highlightColor = Color.black,
065: lockedHandleColor = Color.black;
066:
067: /**
068: * Constructs a renderer that may be used to render vertices.
069: */
070: public VertexRenderer() {
071: defaultForeground = UIManager.getColor("Tree.textForeground");
072: defaultBackground = UIManager.getColor("Tree.textBackground");
073: }
074:
075: /**
076: * Configure and return the renderer component based on the passed in cell.
077: * The value is typically set from messaging the graph with
078: * <code>convertValueToString</code>. We recommend you check the value's
079: * class and throw an illegal argument exception if it's not correct.
080: *
081: * @param graph
082: * the graph that that defines the rendering context.
083: * @param view
084: * the cell view that should be rendered.
085: * @param sel
086: * whether the object is selected.
087: * @param focus
088: * whether the object has the focus.
089: * @param preview
090: * whether we are drawing a preview.
091: * @return the component used to render the value.
092: */
093: public Component getRendererComponent(JGraph graph, CellView view,
094: boolean sel, boolean focus, boolean preview) {
095: gridColor = graph.getGridColor();
096: highlightColor = graph.getHighlightColor();
097: lockedHandleColor = graph.getLockedHandleColor();
098: isDoubleBuffered = graph.isDoubleBuffered();
099: if (view instanceof VertexView) {
100: this .view = (VertexView) view;
101: setComponentOrientation(graph.getComponentOrientation());
102: if (graph.getEditingCell() != view.getCell()) {
103: Object label = graph.convertValueToString(view);
104: if (label != null)
105: setText(label.toString());
106: else
107: setText(null);
108: } else
109: setText(null);
110: this .hasFocus = focus;
111: this .childrenSelected = graph.getSelectionModel()
112: .isChildrenSelected(view.getCell());
113: this .selected = sel;
114: this .preview = preview;
115: if (this .view.isLeaf()
116: || GraphConstants.isGroupOpaque(view
117: .getAllAttributes()))
118: installAttributes(view);
119: else
120: resetAttributes();
121: return this ;
122: }
123: return null;
124: }
125:
126: /**
127: * Hook for subclassers that is invoked when the installAttributes is not
128: * called to reset all attributes to the defaults. <br>
129: * Subclassers must invoke the superclass implementation.
130: *
131: */
132: protected void resetAttributes() {
133: setText(null);
134: setBorder(null);
135: setOpaque(false);
136: setGradientColor(null);
137: setIcon(null);
138: }
139:
140: /**
141: * Install the attributes of specified cell in this renderer instance. This
142: * means, retrieve every published key from the cells hashtable and set
143: * global variables or superclass properties accordingly.
144: *
145: * @param view
146: * the cell view to retrieve the attribute values from.
147: */
148: protected void installAttributes(CellView view) {
149: Map map = view.getAllAttributes();
150: setIcon(GraphConstants.getIcon(map));
151: setOpaque(GraphConstants.isOpaque(map));
152: setBorder(GraphConstants.getBorder(map));
153: setVerticalAlignment(GraphConstants.getVerticalAlignment(map));
154: setHorizontalAlignment(GraphConstants
155: .getHorizontalAlignment(map));
156: setVerticalTextPosition(GraphConstants
157: .getVerticalTextPosition(map));
158: setHorizontalTextPosition(GraphConstants
159: .getHorizontalTextPosition(map));
160: bordercolor = GraphConstants.getBorderColor(map);
161: borderWidth = Math.max(1, Math.round(GraphConstants
162: .getLineWidth(map)));
163: if (getBorder() == null && bordercolor != null)
164: setBorder(BorderFactory.createLineBorder(bordercolor,
165: borderWidth));
166: Color foreground = GraphConstants.getForeground(map);
167: setForeground((foreground != null) ? foreground
168: : defaultForeground);
169: Color gradientColor = GraphConstants.getGradientColor(map);
170: setGradientColor(gradientColor);
171: Color background = GraphConstants.getBackground(map);
172: setBackground((background != null) ? background
173: : defaultBackground);
174: setFont(GraphConstants.getFont(map));
175: }
176:
177: /**
178: * Paint the renderer. Overrides superclass paint to add specific painting.
179: */
180: public void paint(Graphics g) {
181: try {
182: if (gradientColor != null && !preview && isOpaque()) {
183: setOpaque(false);
184: Graphics2D g2d = (Graphics2D) g;
185: g2d.setPaint(new GradientPaint(0, 0, getBackground(),
186: getWidth(), getHeight(), gradientColor, true));
187: g2d.fillRect(0, 0, getWidth(), getHeight());
188: }
189: super .paint(g);
190: paintSelectionBorder(g);
191: } catch (IllegalArgumentException e) {
192: // JDK Bug: Zero length string passed to TextLayout constructor
193: }
194: }
195:
196: /**
197: * Provided for subclassers to paint a selection border.
198: */
199: protected void paintSelectionBorder(Graphics g) {
200: Graphics2D g2 = (Graphics2D) g;
201: Stroke previousStroke = g2.getStroke();
202: g2.setStroke(GraphConstants.SELECTION_STROKE);
203: if (childrenSelected || selected) {
204: if (childrenSelected)
205: g.setColor(gridColor);
206: else if (hasFocus && selected)
207: g.setColor(lockedHandleColor);
208: else if (selected)
209: g.setColor(highlightColor);
210: Dimension d = getSize();
211: g.drawRect(0, 0, d.width - 1, d.height - 1);
212: }
213: g2.setStroke(previousStroke);
214: }
215:
216: /**
217: * Returns the intersection of the bounding rectangle and the straight line
218: * between the source and the specified point p. The specified point is
219: * expected not to intersect the bounds.
220: */
221: public Point2D getPerimeterPoint(VertexView view, Point2D source,
222: Point2D p) {
223: Rectangle2D bounds = view.getBounds();
224: double x = bounds.getX();
225: double y = bounds.getY();
226: double width = bounds.getWidth();
227: double height = bounds.getHeight();
228: double xCenter = x + width / 2;
229: double yCenter = y + height / 2;
230: double dx = p.getX() - xCenter; // Compute Angle
231: double dy = p.getY() - yCenter;
232: double alpha = Math.atan2(dy, dx);
233: double xout = 0, yout = 0;
234: double pi = Math.PI;
235: double pi2 = Math.PI / 2.0;
236: double beta = pi2 - alpha;
237: double t = Math.atan2(height, width);
238: if (alpha < -pi + t || alpha > pi - t) { // Left edge
239: xout = x;
240: yout = yCenter - width * Math.tan(alpha) / 2;
241: } else if (alpha < -t) { // Top Edge
242: yout = y;
243: xout = xCenter - height * Math.tan(beta) / 2;
244: } else if (alpha < t) { // Right Edge
245: xout = x + width;
246: yout = yCenter + width * Math.tan(alpha) / 2;
247: } else { // Bottom Edge
248: yout = y + height;
249: xout = xCenter + height * Math.tan(beta) / 2;
250: }
251: return new Point2D.Double(xout, yout);
252: }
253:
254: /**
255: * Overridden for performance reasons. See the <a
256: * href="#override">Implementation Note </a> for more information.
257: */
258: public void validate() {
259: }
260:
261: /**
262: * Overridden for performance reasons. See the <a
263: * href="#override">Implementation Note </a> for more information.
264: */
265: public void revalidate() {
266: }
267:
268: /**
269: * Overridden for performance reasons. See the <a
270: * href="#override">Implementation Note </a> for more information.
271: */
272: public void repaint(long tm, int x, int y, int width, int height) {
273: }
274:
275: /**
276: * Overridden for performance reasons. See the <a
277: * href="#override">Implementation Note </a> for more information.
278: */
279: public void repaint(Rectangle r) {
280: }
281:
282: /**
283: * Overridden for performance reasons. See the <a
284: * href="#override">Implementation Note </a> for more information.
285: */
286: protected void firePropertyChange(String propertyName,
287: Object oldValue, Object newValue) {
288: // Strings get interned...
289: if (propertyName == "text")
290: super .firePropertyChange(propertyName, oldValue, newValue);
291: }
292:
293: /**
294: * Overridden for performance reasons. See the <a
295: * href="#override">Implementation Note </a> for more information.
296: */
297: public void firePropertyChange(String propertyName, byte oldValue,
298: byte newValue) {
299: }
300:
301: /**
302: * Overridden for performance reasons. See the <a
303: * href="#override">Implementation Note </a> for more information.
304: */
305: public void firePropertyChange(String propertyName, char oldValue,
306: char newValue) {
307: }
308:
309: /**
310: * Overridden for performance reasons. See the <a
311: * href="#override">Implementation Note </a> for more information.
312: */
313: public void firePropertyChange(String propertyName, short oldValue,
314: short newValue) {
315: }
316:
317: /**
318: * Overridden for performance reasons. See the <a
319: * href="#override">Implementation Note </a> for more information.
320: */
321: public void firePropertyChange(String propertyName, int oldValue,
322: int newValue) {
323: }
324:
325: /**
326: * Overridden for performance reasons. See the <a
327: * href="#override">Implementation Note </a> for more information.
328: */
329: public void firePropertyChange(String propertyName, long oldValue,
330: long newValue) {
331: }
332:
333: /**
334: * Overridden for performance reasons. See the <a
335: * href="#override">Implementation Note </a> for more information.
336: */
337: public void firePropertyChange(String propertyName, float oldValue,
338: float newValue) {
339: }
340:
341: /**
342: * Overridden for performance reasons. See the <a
343: * href="#override">Implementation Note </a> for more information.
344: */
345: public void firePropertyChange(String propertyName,
346: double oldValue, double newValue) {
347: }
348:
349: /**
350: * Overridden for performance reasons. See the <a
351: * href="#override">Implementation Note </a> for more information.
352: */
353: public void firePropertyChange(String propertyName,
354: boolean oldValue, boolean newValue) {
355: }
356:
357: /**
358: * @return Returns the gradientColor.
359: */
360: public Color getGradientColor() {
361: return gradientColor;
362: }
363:
364: /**
365: * @param gradientColor
366: * The gradientColor to set.
367: */
368: public void setGradientColor(Color gradientColor) {
369: this.gradientColor = gradientColor;
370: }
371: }
|