001: /*
002: The contents of this file are subject to the Common Public Attribution License
003: Version 1.0 (the "License"); you may not use this file except in compliance with
004: the License. You may obtain a copy of the License at
005: http://www.projity.com/license . The License is based on the Mozilla Public
006: License Version 1.1 but Sections 14 and 15 have been added to cover use of
007: software over a computer network and provide for limited attribution for the
008: Original Developer. In addition, Exhibit A has been modified to be consistent
009: with Exhibit B.
010:
011: Software distributed under the License is distributed on an "AS IS" basis,
012: WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
013: specific language governing rights and limitations under the License. The
014: Original Code is OpenProj. The Original Developer is the Initial Developer and
015: is Projity, Inc. All portions of the code written by Projity are Copyright (c)
016: 2006, 2007. All Rights Reserved. Contributors Projity, Inc.
017:
018: Alternatively, the contents of this file may be used under the terms of the
019: Projity End-User License Agreeement (the Projity License), in which case the
020: provisions of the Projity License are applicable instead of those above. If you
021: wish to allow use of your version of this file only under the terms of the
022: Projity License and not to allow others to use your version of this file under
023: the CPAL, indicate your decision by deleting the provisions above and replace
024: them with the notice and other provisions required by the Projity License. If
025: you do not delete the provisions above, a recipient may use your version of this
026: file under either the CPAL or the Projity License.
027:
028: [NOTE: The text of this license may differ slightly from the text of the notices
029: in Exhibits A and B of the license at http://www.projity.com/license. You should
030: use the latest text at http://www.projity.com/license for your modifications.
031: You may not remove this license text from the source files.]
032:
033: Attribution Information: Attribution Copyright Notice: Copyright © 2006, 2007
034: Projity, Inc. Attribution Phrase (not exceeding 10 words): Powered by OpenProj,
035: an open source solution from Projity. Attribution URL: http://www.projity.com
036: Graphic Image as provided in the Covered Code as file: openproj_logo.png with
037: alternatives listed on http://www.projity.com/logo
038:
039: Display of Attribution Information is required in Larger Works which are defined
040: in the CPAL as a work which combines Covered Code or portions thereof with code
041: not governed by the terms of the CPAL. However, in addition to the other notice
042: obligations, all copies of the Covered Code in Executable and Source Code form
043: distributed must, as a form of attribution of the original author, include on
044: each user interface screen the "OpenProj" logo visible to all users. The
045: OpenProj logo should be located horizontally aligned with the menu bar and left
046: justified on the top left of the screen adjacent to the File menu. The logo
047: must be at least 100 x 25 pixels. When users click on the "OpenProj" logo it
048: must direct them back to http://www.projity.com.
049: */
050: package com.projity.pm.graphic.network;
051:
052: import java.awt.Color;
053: import java.awt.Graphics;
054: import java.awt.Graphics2D;
055: import java.awt.Rectangle;
056: import java.awt.Stroke;
057: import java.awt.geom.AffineTransform;
058: import java.awt.geom.GeneralPath;
059: import java.awt.geom.PathIterator;
060: import java.awt.geom.Point2D;
061: import java.util.Iterator;
062: import java.util.ListIterator;
063:
064: import javax.swing.CellRendererPane;
065: import javax.swing.JComponent;
066:
067: import org.apache.commons.collections.Closure;
068:
069: import com.projity.graphic.configuration.BarFormat;
070: import com.projity.graphic.configuration.BarStyles;
071: import com.projity.graphic.configuration.GraphicConfiguration;
072: import com.projity.graphic.configuration.TexturedShape;
073: import com.projity.pm.dependency.Dependency;
074: import com.projity.pm.graphic.graph.GraphParams;
075: import com.projity.pm.graphic.graph.GraphRenderer;
076: import com.projity.pm.graphic.graph.LinkRouting;
077: import com.projity.pm.graphic.model.cache.GraphicDependency;
078: import com.projity.pm.graphic.model.cache.GraphicNode;
079: import com.projity.pm.graphic.network.link_routing.NetworkLinkRouting;
080: import com.projity.pm.graphic.network.rendering.NetworkCellEditor;
081: import com.projity.pm.graphic.network.rendering.NetworkCellRenderer;
082:
083: public abstract class NetworkRenderer extends GraphRenderer {
084: protected LinkRenderer linkRenderer;
085: protected NetworkCellRenderer renderer;
086: protected NetworkCellEditor editor;
087: protected boolean vertical = true;
088: protected CellRendererPane rendererPane;
089: protected JComponent container;
090:
091: protected GraphicConfiguration config;
092:
093: public NetworkRenderer() {
094: super ();
095: init();
096: }
097:
098: public NetworkRenderer(GraphParams graphInfo) {
099: super (graphInfo);
100: init();
101: }
102:
103: public void init() {
104: GraphParams graphInfo = getGraphInfo();
105: if (graphInfo instanceof JComponent)
106: container = (JComponent) graphInfo;
107: config = GraphicConfiguration.getInstance();
108: linkRenderer = new LinkRenderer();
109: renderer = new NetworkCellRenderer(graphInfo);
110: if (container != null) {
111: editor = new NetworkCellEditor(graphInfo, container);
112: rendererPane = new CellRendererPane();
113: container.add(rendererPane);
114: }
115: }
116:
117: public boolean isVertical() {
118: return vertical;
119: }
120:
121: public void setVertical(boolean vertical) {
122: this .vertical = vertical;
123: ((NetworkLinkRouting) getRouting()).setVertical(vertical);
124: }
125:
126: private class LinkRenderer implements Closure {
127: protected BarFormat format;
128: protected GraphicDependency dependency;
129: protected Graphics2D g2;
130:
131: void initialize(Graphics2D g2, GraphicDependency dependency) {
132: this .g2 = g2;
133: this .dependency = dependency;
134: }
135:
136: public void execute(Object arg0) {
137: format = (BarFormat) arg0;
138:
139: //if (format.getMiddle()!=null){
140: GraphicNode from = dependency.getPredecessor();
141: GraphicNode to = dependency.getSuccessor();
142: // Rectangle2D fromBounds=scale(getBounds(from));
143: // Rectangle2D toBounds=scale(getBounds(to));
144: double[] fromPoints = new double[4];
145: double[] toPoints = new double[4];
146: updateLinkConnections(from, fromPoints);
147: updateLinkConnections(to, toPoints);
148: Point2D fromCenter = getCenter(from);
149: Point2D toCenter = getCenter(to);
150: if (fromCenter == null) //TODO SUB this prevents crashing with external tasks, however, now they won't show up in the PERT
151: return;
152:
153: GeneralPath path = dependency.getPath();
154: NetworkLinkRouting routing = (NetworkLinkRouting) getRouting();
155: if (vertical)
156: routing.routePath(path, fromCenter.getX(),
157: fromPoints[3], toCenter.getX(), toPoints[2],
158: (fromPoints[3] + toPoints[2]) / 2, dependency
159: .getType());
160: else
161: routing.routePath(path, fromPoints[1], fromCenter
162: .getY(), toPoints[0], toCenter.getY(),
163: (fromPoints[1] + toPoints[0]) / 2, dependency
164: .getType());
165:
166: Color oldColor = g2.getColor();
167: Stroke oldStroke = g2.getStroke();
168: Dependency dep = dependency.getDependency();
169: if (dep != null && dep.isDisabled())
170: g2.setStroke(GraphRenderer.DISABLED_LINK_STROKE);
171: if (dep != null && dep.isCrossProject())
172: g2.setColor(GraphRenderer.EXTERNAL_LINK_COLOR);
173: else
174: g2.setColor(format.getMiddle().getColor());
175: g2.draw(path);
176:
177: //}
178: if (format.getStart() == null && format.getEnd() == null)
179: return;
180: if (format.getStart() != null) {
181: double theta = routing.getFirstAngle();
182: AffineTransform transform = (theta == 0) ? null
183: : AffineTransform.getRotateInstance(theta,
184: routing.getFirstX(), routing
185: .getFirstY());
186: drawLinkArrows(dep, transform, format.getEnd());
187: }
188: if (format.getEnd() != null) {
189: double theta = routing.getLastAngle();
190: AffineTransform transform = (theta == Math.PI || theta == -Math.PI) ? null
191: : AffineTransform.getRotateInstance(Math.PI
192: - theta, routing.getLastX(), routing
193: .getLastY());
194: drawLinkArrows(dep, transform, format.getEnd());
195: }
196: if (oldColor != null)
197: g2.setColor(oldColor);
198: if (oldStroke != null)
199: g2.setStroke(oldStroke);
200:
201: }
202:
203: private void drawLinkArrows(Dependency dep,
204: AffineTransform transform, TexturedShape shape) {
205: Color oldEndColor = format.getEnd().getColor();
206: if (dep != null && dep.isCrossProject())
207: shape.setPaint(GraphRenderer.EXTERNAL_LINK_COLOR);
208: g2.setColor(shape.getColor());
209: LinkRouting routing = getRouting();
210: shape.draw(g2, routing.getLastX(), routing.getLastY(),
211: transform, useTextures());
212: if (dep != null && dep.isCrossProject())
213: shape.setPaint(oldEndColor);
214: }
215:
216: }
217:
218: public void paintLink(Graphics2D g2, GraphicDependency dependency) {
219: BarStyles barStyles = graphInfo.getBarStyles();
220: linkRenderer.initialize(g2, dependency);
221: barStyles.apply(dependency, linkRenderer, true, false, false);
222: }
223:
224: protected GeneralPath getShape(GraphicNode node) {
225: return scale(getNonScaledShape(node));
226: }
227:
228: protected abstract GeneralPath getNonScaledShape(GraphicNode node);
229:
230: protected abstract void translateNonScaledShape(GraphicNode node,
231: double dx, double dy);
232:
233: protected void translateShape(GraphicNode node, double dx, double dy) {
234: Point2D v = scaleVector_1(new Point2D.Double(dx, dy));
235: translateNonScaledShape(node, v.getX(), v.getY());
236: }
237:
238: protected abstract Point2D getNonScaledCenter(GraphicNode node);
239:
240: protected Point2D getCenter(GraphicNode node) {
241: return scale(getNonScaledCenter(node));
242: }
243:
244: protected Rectangle getBounds(GraphicNode node) {
245: GeneralPath shape = getShape(node);
246: if (shape == null)
247: return null;
248: else
249: return shape.getBounds();
250: }
251:
252: protected Rectangle getNonScaledBounds(GraphicNode node) {
253: GeneralPath shape = getNonScaledShape(node);
254: if (shape == null)
255: return null;
256: else
257: return shape.getBounds();
258: }
259:
260: protected double[] segment = new double[6];
261:
262: protected void updateLinkConnections(GraphicNode node,
263: double[] linkPoints) {
264: GeneralPath shape = getShape(node);
265: if (shape == null)
266: return;
267: Point2D center = getCenter(node);
268: linkPoints[0] = center.getX();
269: linkPoints[1] = center.getX();
270: linkPoints[2] = center.getY();
271: linkPoints[3] = center.getY();
272: double x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0, x, y;
273: for (PathIterator j = shape.getPathIterator(null); !j.isDone(); j
274: .next()) {
275: int segmentType = j.currentSegment(segment);
276: switch (segmentType) {
277: case PathIterator.SEG_MOVETO:
278: x0 = segment[0];
279: y0 = segment[1];
280: x2 = x0;
281: y2 = y0;
282: break;
283: case PathIterator.SEG_LINETO:
284: x2 = segment[0];
285: y2 = segment[1];
286: case PathIterator.SEG_CLOSE:
287: if (segmentType == PathIterator.SEG_CLOSE) {
288: x2 = x0;
289: y2 = y0;
290: }
291: //works only convex shapes
292: double lambda;
293: if (y2 != y1) {
294: x = (center.getY() - y1) * (x2 - x1) / (y2 - y1)
295: + x1;
296: lambda = (x2 == x1) ? 0 : (x - x1) / (x2 - x1);
297: if (x1 == x2 || (lambda >= 0 && lambda <= 1)) {
298: if (x < linkPoints[0])
299: linkPoints[0] = x;
300: if (x > linkPoints[1])
301: linkPoints[1] = x;
302: }
303: }
304: if (x2 != x1) {
305: y = (center.getX() - x1) * (y2 - y1) / (x2 - x1)
306: + y1;
307: lambda = (y2 == x1) ? 0 : (y - y1) / (y2 - y1);
308: if (y1 == y2 || (lambda >= 0 && lambda <= 1)) {
309: if (y < linkPoints[2])
310: linkPoints[2] = y;
311: if (y > linkPoints[3])
312: linkPoints[3] = y;
313: }
314: }
315:
316: break;
317: }
318: x1 = x2;
319: y1 = y2;
320: }
321: }
322:
323: public void paint(Graphics g) {
324: paint(g, null);
325: }
326:
327: public void paint(Graphics g, Rectangle visibleBounds) {
328: Graphics2D g2 = (Graphics2D) g;
329:
330: Rectangle clipBounds = g2.getClipBounds();
331: Rectangle svgClip = clipBounds;
332: if (clipBounds == null) {
333: clipBounds = getGraphInfo().getDrawingBounds();
334: //start at O,O because it's already translated
335: if (visibleBounds == null)
336: clipBounds = new Rectangle(0, 0, clipBounds.width,
337: clipBounds.height);
338: else {
339: clipBounds = visibleBounds;
340: g2.setClip(clipBounds);
341: }
342: }
343: //Modif for offline graphics
344:
345: GraphicDependency dependency;
346: for (Iterator i = getDependenciesIterator(); i.hasNext();) {
347: dependency = (GraphicDependency) i.next();
348: paintLink(g2, dependency);
349: }
350:
351: GraphicNode node;
352: Rectangle bounds;
353: for (ListIterator i = graphInfo.getCache().getIterator(); i
354: .hasNext();) {
355: node = (GraphicNode) i.next();
356: bounds = getBounds(node);
357: if (bounds == null)
358: continue;
359: if (clipBounds.intersects(bounds))
360: paintNode(g2, node);
361: }
362:
363: if (visibleBounds != null)
364: g2.setClip(svgClip);
365: }
366:
367: public GeneralPath scale(GeneralPath path) {
368: return ((NetworkParams) graphInfo).scale(path);
369: }
370:
371: public Point2D scale(Point2D p) {
372: if (p == null)
373: return null;
374: return ((NetworkParams) graphInfo).scale(p);
375: }
376:
377: public Point2D scaleVector(Point2D p) {
378: return ((NetworkParams) graphInfo).scaleVector(p);
379: }
380:
381: public Point2D scaleVector_1(Point2D p) {
382: return ((NetworkParams) graphInfo).scaleVector_1(p);
383: }
384:
385: public Rectangle scale(Rectangle r) {
386: return ((NetworkParams) graphInfo).scale(r);
387: }
388:
389: public void paintNode(Graphics2D g, GraphicNode node) {
390: Rectangle bounds = getBounds(node);
391: if (isEditing(node)) {
392: editor.paintEditor(node);
393: } else {
394: JComponent c = renderer.getRendererComponent(node,
395: ((NetworkParams) graphInfo).getZoom());
396: if (container == null) {
397: //c=new JLabel("test");
398: c.setDoubleBuffered(false);
399: c.setOpaque(false);
400: c.setForeground(Color.BLACK);
401: c.setSize(bounds.width, bounds.height);
402: g.translate(bounds.x, bounds.y);
403: c.doLayout();
404: c.print(g);
405: g.translate(-bounds.x, -bounds.y);
406: } else
407: rendererPane.paintComponent(g, c, container, bounds.x,
408: bounds.y, bounds.width, bounds.height, true);
409: }
410: }
411:
412: public void resetForms() {
413: renderer.resetForms();
414: if (editor != null)
415: editor.resetForms();
416: }
417:
418: public boolean isEditing(GraphicNode node) {
419: if (editor == null)
420: return false;
421: return editor.isEditing(node);
422: }
423:
424: public NetworkCellEditor getEditor() {
425: return editor;
426: }
427:
428: public Iterator getDependenciesIterator() {
429: return graphInfo.getCache().getEdgesIterator();
430: }
431:
432: }
|