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.gantt;
051:
052: import java.awt.Color;
053: import java.awt.Font;
054: import java.awt.FontMetrics;
055: import java.awt.Graphics;
056: import java.awt.Graphics2D;
057: import java.awt.Paint;
058: import java.awt.Rectangle;
059: import java.awt.Shape;
060: import java.awt.Stroke;
061: import java.awt.geom.AffineTransform;
062: import java.awt.geom.GeneralPath;
063: import java.awt.geom.Rectangle2D;
064: import java.io.Serializable;
065: import java.text.DateFormat;
066: import java.util.ArrayList;
067: import java.util.Calendar;
068: import java.util.Date;
069: import java.util.Iterator;
070: import java.util.ListIterator;
071:
072: import javax.swing.CellRendererPane;
073: import javax.swing.JComponent;
074: import javax.swing.JLabel;
075:
076: import org.apache.commons.collections.Closure;
077:
078: import com.projity.field.Field;
079: import com.projity.field.FieldConverter;
080: import com.projity.functor.IntervalConsumer;
081: import com.projity.functor.ScheduleIntervalGenerator;
082: import com.projity.graphic.configuration.BarFormat;
083: import com.projity.graphic.configuration.BarStyles;
084: import com.projity.graphic.configuration.GraphicConfiguration;
085: import com.projity.graphic.configuration.TexturedShape;
086: import com.projity.graphic.configuration.shape.PredefinedPaint;
087: import com.projity.options.GanttOption;
088: import com.projity.pm.calendar.CalendarService;
089: import com.projity.pm.calendar.WorkingCalendar;
090: import com.projity.pm.dependency.Dependency;
091: import com.projity.pm.dependency.DependencyType;
092: import com.projity.pm.graphic.gantt.link_routing.GanttLinkRouting;
093: import com.projity.pm.graphic.graph.GraphParams;
094: import com.projity.pm.graphic.graph.GraphRenderer;
095: import com.projity.pm.graphic.graph.LinkRouting;
096: import com.projity.pm.graphic.model.cache.GraphicDependency;
097: import com.projity.pm.graphic.model.cache.GraphicNode;
098: import com.projity.pm.graphic.model.cache.NodeModelCache;
099: import com.projity.pm.graphic.timescale.CoordinatesConverter;
100: import com.projity.pm.scheduling.ScheduleInterval;
101: import com.projity.pm.task.Project;
102: import com.projity.timescale.CalendarUtil;
103: import com.projity.timescale.TimeInterval;
104: import com.projity.timescale.TimeIterator;
105: import com.projity.util.DateTime;
106: import com.projity.util.Environment;
107: import com.projity.util.FontUtil;
108:
109: public class GanttRenderer extends GraphRenderer implements
110: Serializable {
111: /**
112: *
113: */
114: private static final long serialVersionUID = -7437190083991277084L;
115: protected NodeRenderer nodeRenderer = new NodeRenderer();
116: protected LinkRenderer linkRenderer = new LinkRenderer();
117: protected AnnotationRenderer annotationRenderer = new AnnotationRenderer();
118:
119: protected GraphicConfiguration config;
120: protected JComponent container;
121:
122: public GanttRenderer() {
123: super ();
124: config = GraphicConfiguration.getInstance();
125: }
126:
127: public GanttRenderer(GraphParams graphInfo) {
128: super (graphInfo);
129: config = GraphicConfiguration.getInstance();
130: if (graphInfo instanceof JComponent)
131: container = (JComponent) graphInfo;
132: }
133:
134: private class NodeRenderer implements Closure, IntervalConsumer,
135: Serializable {
136: private static final long serialVersionUID = -1348039741030744803L;
137: GraphicNode node;
138: Graphics2D g2;
139: protected GanttBarSingleIntervalGenerator singleIntervalGenerator = new GanttBarSingleIntervalGenerator();
140: protected ScheduleInterval interval;
141: protected BarFormat format;
142: protected int yrow;
143: protected int maxLayer = Integer.MAX_VALUE;
144: protected int minLayer = 0;
145:
146: public void initialize(Graphics2D g2, GraphicNode node) {
147: this .g2 = g2;
148: this .node = node;
149: int rowHeight = ((GanttParams) graphInfo).getRowHeight();
150: yrow = node.getRow() * rowHeight;
151: setLayers(BarFormat.MIN_FOREGROUND_LAYER,
152: BarFormat.MAX_FOREGROUND_LAYER);
153: }
154:
155: public int getMaxLayer() {
156: return maxLayer;
157: }
158:
159: public void setMaxLayer(int maxLayer) {
160: this .maxLayer = maxLayer;
161: }
162:
163: public int getMinLayer() {
164: return minLayer;
165: }
166:
167: public void setMinLayer(int minLayer) {
168: this .minLayer = minLayer;
169: }
170:
171: public void setLayers(int minLayer, int maxLayer) {
172: this .minLayer = minLayer;
173: this .maxLayer = maxLayer;
174: }
175:
176: /**
177: * This is the callback which is called from barStyles.apply() below
178: */
179: public void execute(Object arg0) {
180: format = (BarFormat) arg0;
181: if (format.getLayer() > maxLayer
182: || format.getLayer() < minLayer)
183: return;
184:
185: ScheduleIntervalGenerator intervalGenerator;
186: if (format.getScheduleIntervalGenerator() == null) {
187: singleIntervalGenerator.initialize(graphInfo.getCache()
188: .getModel(), format.getFromField(), format
189: .getToField());
190: intervalGenerator = singleIntervalGenerator;
191: } else {
192: intervalGenerator = format
193: .getScheduleIntervalGenerator();
194: }
195:
196: intervalGenerator.consumeIntervals(node, this );
197:
198: }
199:
200: public void consumeInterval(ScheduleInterval interval) {
201: // System.out.println("GanttUI consuming interval " + new java.util.Date(interval.getStart()) + " " + new java.util.Date(interval.getEnd()));
202: // if (interval.getEnd() < interval.getStart())
203: // return;
204: CoordinatesConverter coord = ((GanttParams) graphInfo)
205: .getCoord();
206: if (interval.getEnd() > 100000000000000L) {
207: System.out
208: .println("ERROR!!! leads to OutOfMemoryError, consumeInterval interval="
209: + interval.getStart()
210: + ", "
211: + CalendarUtil.toString(interval
212: .getStart())
213: + ", "
214: + interval.getEnd()
215: + ", "
216: + CalendarUtil.toString(interval
217: .getEnd()) + "...");
218: return;
219: }
220: double x = coord.toX(interval.getStart());
221: double width = CoordinatesConverter.adaptSmallBarEndX(x,
222: coord.toX(interval.getEnd()), node, config)
223: - x;
224: // double width=coord.toW(interval.getEnd()-interval.getStart());
225: double height;
226: double y = yrow + config.getGanttBarYOffset();
227: int row = format.getRow();
228: if (row == 1) {
229: height = config.getGanttBarHeight();
230: } else {
231: height = config.getBaselineHeight();
232: y += config.getGanttBarHeight()
233: + config.getBaselineHeight() * (row - 2);
234: }
235: y += height / 2;
236:
237: double dw = height;
238:
239: if (format.getMiddle() != null) {
240:
241: if (g2 == null && format.isMain()) {
242: Shape shape = format.getMiddle().toGeneralPath(
243: width, height, x, y, null);
244: Rectangle2D bounds = shape.getBounds2D();
245: node.setGanttShapeOffset(bounds.getY() - y + height
246: / 2);
247: node.setGanttShapeHeight(bounds.getHeight());
248: } else {
249: Shape shape = format.getMiddle().draw(g2, width,
250: height, x, y, useTextures());
251:
252: }
253: // draw middle before ends
254: }
255: if (g2 == null)
256: return;
257:
258: if (format.getStart() != null)
259: format.getStart().draw(g2, dw, height, x, y,
260: useTextures());
261: if (format.getEnd() != null)
262: format.getEnd().draw(g2, dw, height, x + width, y,
263: useTextures()); //TODO case when no start symbol
264:
265: //TODO style and format of completion should be treated with bar prefererences instead of a special case
266: if (format.isMain() && !node.isSummary()
267: && node.isStarted()) {
268: long completedT = node.getCompleted();
269: if (completedT >= interval.getStart()) {
270: double completedW = coord.toX(completedT) - x;
271: if (completedW > width
272: && !GanttOption.getInstance()
273: .isCompletionIsContiguous())
274: completedW = width;
275: completedW = CoordinatesConverter
276: .adaptSmallBarEndX(x, x + completedW, node,
277: config)
278: - x;
279: Rectangle2D progressBar = new Rectangle2D.Double(x,
280: y - config.getGanttProgressBarHeight() / 2,
281: completedW, config
282: .getGanttProgressBarHeight());
283: g2.setColor(Color.BLACK);
284: g2.fill(progressBar);
285: }
286: }
287:
288: }
289:
290: }
291:
292: private class AnnotationRenderer implements Closure, Serializable {
293: private static final long serialVersionUID = -137778741030744803L;
294: protected BarFormat format;
295: GraphicNode node;
296: Graphics2D g2;
297: protected int yrow;
298: protected JLabel component = new JLabel();
299: protected CellRendererPane rendererPane;
300: FontMetrics fontMetrics;
301:
302: public void initialize(Graphics2D g2, GraphicNode node) {
303: this .g2 = g2;
304: this .node = node;
305: int rowHeight = ((GanttParams) graphInfo).getRowHeight();
306: config = ((GanttParams) graphInfo).getConfiguration();
307: yrow = node.getRow() * rowHeight;
308:
309: if (container != null) {
310: rendererPane = new CellRendererPane();
311: container.add(rendererPane);
312: }
313: component.setFont(FontUtil.getFont(null,
314: Environment.GANTT_ANNOTATIONS_FONT));
315: fontMetrics = component.getFontMetrics(component.getFont());
316: }
317:
318: public void execute(Object arg0) {
319: format = (BarFormat) arg0;
320: Field field = format.getField();
321: if (field == null)
322: return;
323: Object value = field.getValue(node.getNode(), graphInfo
324: .getCache().getModel(), null);
325: if (value == null)
326: return;
327: CoordinatesConverter coord = ((GanttParams) graphInfo)
328: .getCoord();
329:
330: // int y=yrow+config.getGanttBarHeight()+config.getGanttBarYOffset();
331: // int x=(int)Math.ceil(coord.toX(node.getEnd()))+config.getGanttBarAnnotationXOffset();
332: // Color oldColor=g2.getColor();
333: // g2.setColor(format.getMiddle().getColor());
334: // g2.drawString(ObjectConverterManager.toString(value,value.getClass()), x, y);
335: // if (oldColor!=null) g2.setColor(oldColor);
336: String s;
337: if (value instanceof Date) {
338: Date d = (Date) value;
339: s = DateFormat.getDateInstance(DateFormat.SHORT)
340: .format(d);
341: int i = s.lastIndexOf('/');
342: if (i > 0)
343: s = s.substring(0, i);
344: } else
345: s = FieldConverter.toString(value, value.getClass(),
346: null);
347: component.setText(s); //field.getClazz()?
348: int y = yrow + config.getGanttBarYOffset();//+config.getGanttBarAnnotationYOffset();
349: double x0 = coord.toX(node.getStart());
350: double x1 = coord.toX(node.getEnd());
351: x1 = CoordinatesConverter.adaptSmallBarEndX(x0, x1, node,
352: config);
353:
354: int x = (int) Math.ceil(x1)
355: + config.getGanttBarAnnotationXOffset();
356: int w = fontMetrics.stringWidth(s);//config.getGanttBarAnnotationMaxWidth();
357: int h = config.getGanttBarHeight();
358:
359: if (container == null) {
360: component.setDoubleBuffered(false);
361: component.setOpaque(false);
362: component.setForeground(format.getMiddle().getColor());
363: component.setSize(w, h);
364: g2.translate(x, y);
365: component.doLayout();
366: component.print(g2);
367: g2.translate(-x, -y);
368: } else
369: rendererPane.paintComponent(g2, component, container,
370: x, y, w, h, true);
371:
372: }
373:
374: }
375:
376: private class LinkRenderer implements Closure, Serializable {
377: private static final long serialVersionUID = -2031158189787837110L;
378: protected BarFormat format;
379: protected GraphicDependency dependency;
380: protected Graphics2D g2;
381:
382: void initialize(Graphics2D g2, GraphicDependency dependency) {
383: this .g2 = g2;
384: this .dependency = dependency;
385: }
386:
387: private double[] extraPoints = new double[3];
388:
389: public void execute(Object arg0) {
390: format = (BarFormat) arg0;
391:
392: GanttLinkRouting routing = (GanttLinkRouting) ((GanttParams) graphInfo)
393: .getRouting();
394: CoordinatesConverter coord = ((GanttParams) graphInfo)
395: .getCoord();
396: //if (format.getMiddle()!=null){
397: GraphicNode from = dependency.getPredecessor();
398: GraphicNode to = dependency.getSuccessor();
399: int type = dependency.getType();
400: int fromSign = (type == DependencyType.SF || type == DependencyType.SS) ? -1
401: : 1;
402: int toSign = (type == DependencyType.FS || type == DependencyType.SS) ? -1
403: : 1;
404: double fx0 = coord.toX(from.getStart());
405: double fx1 = coord.toX(from.getEnd());
406: fx1 = CoordinatesConverter.adaptSmallBarEndX(fx0, fx1,
407: from, config);
408: double tx0 = coord.toX(to.getStart());
409: double tx1 = coord.toX(to.getEnd());
410: tx1 = CoordinatesConverter.adaptSmallBarEndX(tx0, tx1, to,
411: config);
412: double x0 = fromSign < 0 ? fx0 : fx1;
413: double x1 = toSign < 0 ? tx0 : tx1;
414: int rowHeight = ((GanttParams) graphInfo).getRowHeight();
415: int yOffset = config.getGanttBarYOffset()
416: + config.getGanttBarHeight() / 2;
417: int y0 = rowHeight * from.getRow();
418: int y1 = rowHeight * to.getRow();
419: double y2 = Math.max(y0, y1);
420: y0 += yOffset;
421: y1 += yOffset;
422:
423: GeneralPath path = dependency.getPath();
424: ((GanttLinkRouting) routing).routePath(path, x0, y0, x1,
425: y1, y2, y1 + to.getGanttShapeHeight() / 2, y1
426: - to.getGanttShapeHeight() / 2, type);
427:
428: Color oldColor = g2.getColor();
429: Stroke oldStroke = g2.getStroke();
430: Dependency dep = dependency.getDependency();
431: if (dep.isDisabled())
432: g2.setStroke(DISABLED_LINK_STROKE);
433: if (dep.isCrossProject())
434: g2.setColor(EXTERNAL_LINK_COLOR);
435: else
436: g2.setColor(format.getMiddle().getColor());
437: g2.draw(path);
438:
439: //}
440: if (format.getStart() == null && format.getEnd() == null)
441: return;
442: if (format.getStart() != null) {
443: double theta = routing.getFirstAngle();
444: AffineTransform transform = (theta == 0) ? null
445: : AffineTransform.getRotateInstance(theta,
446: routing.getFirstX(), routing
447: .getFirstY());
448: drawLinkArrows(dep, transform, format.getStart());
449: }
450: if (format.getEnd() != null) {
451: double theta = routing.getLastAngle();
452: AffineTransform transform = (theta == Math.PI || theta == -Math.PI) ? null
453: : AffineTransform.getRotateInstance(Math.PI
454: - theta, routing.getLastX(), routing
455: .getLastY());
456: drawLinkArrows(dep, transform, format.getEnd());
457: }
458:
459: if (oldColor != null)
460: g2.setColor(oldColor);
461: if (oldStroke != null)
462: g2.setStroke(oldStroke);
463: }
464:
465: private void drawLinkArrows(Dependency dep,
466: AffineTransform transform, TexturedShape shape) {
467: Color oldEndColor = format.getEnd().getColor();
468: if (dep.isCrossProject())
469: shape.setPaint(EXTERNAL_LINK_COLOR);
470: g2.setColor(shape.getColor());
471: LinkRouting routing = ((GanttParams) graphInfo)
472: .getRouting();
473: shape.draw(g2, routing.getLastX(), routing.getLastY(),
474: transform, useTextures());
475: if (dep.isCrossProject())
476: shape.setPaint(oldEndColor);
477: }
478: }
479:
480: public void updateShapes(ListIterator nodeIterator) {
481:
482: Rectangle bounds = ((GanttParams) graphInfo).getGanttBounds();
483: CoordinatesConverter coord = ((GanttParams) graphInfo)
484: .getCoord();
485: if (coord == null)
486: return;
487: double rowHeight = ((GanttParams) graphInfo).getRowHeight();
488:
489: int i0 = (int) Math.floor(bounds.getY() / rowHeight);
490: int i1 = (int) Math.ceil(bounds.getMaxY() / rowHeight);
491: double t0 = coord.toTime(bounds.getX());
492: double t1 = coord.toTime(bounds.getMaxX());
493:
494: GraphicNode node;
495: for (ListIterator i = nodeIterator; i.hasNext();) {
496: node = (GraphicNode) i.next();
497: node.setRow(i.previousIndex());
498: if (i.previousIndex() >= i0 && i.previousIndex() < i1) {
499: if (!node.isVoid())
500: updateShape(node);
501: }
502: }
503: }
504:
505: public void updateShape(GraphicNode node) {
506: if (((GanttParams) graphInfo).getCoord() == null)
507: return; //not initialized
508: BarStyles barStyles = graphInfo.getBarStyles();
509: nodeRenderer.initialize(null, node);
510: barStyles.apply(node.getNode().getImpl(), nodeRenderer);
511:
512: }
513:
514: public void paintNode(Graphics2D g2, GraphicNode node,
515: boolean background) {
516: BarStyles barStyles = graphInfo.getBarStyles();
517: nodeRenderer.initialize(g2, node);
518:
519: if (background)
520: nodeRenderer.setLayers(BarFormat.MIN_BACKGROUND_LAYER,
521: BarFormat.MAX_BACKGROUND_LAYER);
522: else
523: nodeRenderer.setLayers(BarFormat.MIN_FOREGROUND_LAYER,
524: BarFormat.MAX_FOREGROUND_LAYER);
525: barStyles.apply(node.getNode().getImpl(), nodeRenderer);
526: }
527:
528: public void paintAnnotation(Graphics2D g2, GraphicNode node) {
529: BarStyles barStyles = graphInfo.getBarStyles();
530: annotationRenderer.initialize(g2, node);
531: barStyles.apply(node.getNode().getImpl(), annotationRenderer,
532: false, true, false);
533: }
534:
535: public void paintLink(Graphics2D g2, GraphicDependency dependency) {
536: BarStyles barStyles = graphInfo.getBarStyles();
537: linkRenderer.initialize(g2, dependency);
538: barStyles.apply(dependency, linkRenderer, true, false, false);
539: }
540:
541: protected BarFormat calendarFormat;
542: protected Closure calendarClosure = new Closure() {
543: public void execute(Object arg0) {
544: calendarFormat = (BarFormat) arg0;
545: }
546: };
547:
548: protected BarFormat getCalendarFormat() {
549: calendarFormat = null;
550: if (calendarFormat == null) {
551: BarStyles barStyles = graphInfo.getBarStyles();
552: barStyles.apply(null, calendarClosure, false, false, true);
553: }
554: return calendarFormat;
555: }
556:
557: public void paintNonWorkingDays(Graphics2D g2, Rectangle bounds) {
558: BarFormat calFormat = getCalendarFormat();
559: if (calFormat == null)
560: return;
561: //non working days
562: Color oldColor = g2.getColor();
563: Paint oldPaint = g2.getPaint();
564: CoordinatesConverter coord = ((GanttParams) graphInfo)
565: .getCoord();
566: Project project = coord.getProject();
567: WorkingCalendar wc = (WorkingCalendar) project
568: .getWorkCalendar();
569:
570: if (coord.getTimescaleManager().isShowWholeDays()) {
571: boolean useScale2 = coord.getTimescaleManager()
572: .getCurrentScaleIndex() == 0; //valid only for current time scales
573: TimeIterator i = coord.getTimeIterator(bounds.getX(),
574: bounds.getMaxX(), useScale2);
575: long startNonworking = -1L, endNonWorking = -1L;
576: Calendar cal = DateTime.calendarInstance();
577:
578: PredefinedPaint paint = (PredefinedPaint) calFormat
579: .getMiddle().getPaint();//new PredefinedPaint(PredefinedPaint.DOT_LINE,Colors.VERY_LIGHT_GRAY,Color.WHITE);
580: paint.applyPaint(g2, useTextures());
581: while (i.hasNext()) {
582: TimeInterval interval = i.next();
583: long s = interval.getStart();
584: if (CalendarService.getInstance().getDay(wc, s)
585: .isWorking()) {
586: if (startNonworking != -1L) {
587: drawNonWorking(g2, startNonworking,
588: endNonWorking, cal, coord, bounds,
589: useScale2);
590: startNonworking = endNonWorking = -1L;
591: }
592: } else {
593: if (startNonworking == -1L)
594: startNonworking = s;
595: endNonWorking = s;
596:
597: }
598: }
599: if (startNonworking != -1L) {
600: drawNonWorking(g2, startNonworking, endNonWorking, cal,
601: coord, bounds, useScale2);
602: startNonworking = endNonWorking = -1L;
603: }
604: }
605:
606: if (container != null) {
607: //scale2 separation lines
608: TimeIterator i = coord.getTimeIterator(bounds.getX(),
609: bounds.getMaxX(), true);
610: g2.setPaint(new PredefinedPaint(PredefinedPaint.DOT_LINE2,
611: Color.GRAY, g2.getBackground()));
612: while (i.hasNext()) {
613: TimeInterval interval = i.next();
614: int startX = (int) Math.round(coord.toX(interval
615: .getStart()));
616: g2.drawLine(startX, bounds.y, startX, bounds.y
617: + bounds.height);
618: }
619:
620: //project start
621: int projectStartX = (int) Math.round(coord.toX(project
622: .getStart()));
623: if (projectStartX >= bounds.getX()
624: && projectStartX <= bounds.getMaxX()) {
625: //g2.setPaint(new PredefinedPaint(PredefinedPaint.DASH_LINE,Color.LIGHT_GRAY,g2.getBackground()));
626: g2.setPaint(new PredefinedPaint(
627: PredefinedPaint.DASH_LINE, Color.GRAY, g2
628: .getBackground()));
629: g2.drawLine(projectStartX, bounds.y, projectStartX,
630: bounds.y + bounds.height);
631: }
632:
633: if (oldColor != null)
634: g2.setColor(oldColor);
635: if (oldPaint != null)
636: g2.setPaint(oldPaint);
637:
638: }
639: }
640:
641: private void drawNonWorking(Graphics2D g2, long startNonworking,
642: long endNonWorking, Calendar cal,
643: CoordinatesConverter coord, Rectangle bounds,
644: boolean userScale2) {
645: cal.setTimeInMillis(endNonWorking);
646: if (userScale2)
647: coord.getTimescaleManager().getScale().increment2(cal);
648: else
649: coord.getTimescaleManager().getScale().increment1(cal);
650: endNonWorking = cal.getTimeInMillis();
651: g2.fillRect((int) Math.round(coord.toX(startNonworking)),
652: bounds.y, (int) Math.round(coord.toW(endNonWorking
653: - startNonworking)), bounds.height);
654: }
655:
656: ArrayList nodeList = new ArrayList();
657:
658: public void paint(Graphics g) {
659: paint(g, null);
660: }
661:
662: public void paint(Graphics g, Rectangle visibleBounds) {
663: Graphics2D g2 = (Graphics2D) g;
664: //CoordinatesConverter coord=((GanttParams)graphInfo).getCoord();
665:
666: Rectangle clipBounds = g2.getClipBounds();
667: Rectangle svgClip = clipBounds;
668: if (clipBounds == null) {
669: clipBounds = ((GanttParams) getGraphInfo())
670: .getGanttBounds();
671: //start at O,O because it's already translated
672: if (visibleBounds == null)
673: clipBounds = new Rectangle(0, 1, clipBounds.width,
674: clipBounds.height - 2);//1 pixel offset needed for edge
675: // else clipBounds=new Rectangle(visibleBounds.x-clipBounds.x,visibleBounds.y-clipBounds.y,visibleBounds.width,visibleBounds.height);
676: else {
677: clipBounds = visibleBounds;
678: g2.setClip(clipBounds);
679: }
680: }
681:
682: paintNonWorkingDays(g2, clipBounds);
683:
684: //Modif for offline graphics
685:
686: double rowHeight = ((GanttParams) graphInfo).getRowHeight();
687:
688: int i0 = (int) Math.floor(clipBounds.getY() / rowHeight);
689: int i1;
690: if (visibleBounds == null)
691: i1 = (int) Math.ceil(clipBounds.getMaxY() / rowHeight);
692: else
693: i1 = (int) Math.floor(clipBounds.getMaxY() / rowHeight);
694: //double t0=coord.toTime(clipBounds.getX());
695: //double t1=coord.toTime(clipBounds.getMaxX());
696:
697: nodeList.clear();
698:
699: GraphicNode node;
700: // for (ListIterator i=graph.getModel().getNodeIterator(i0);i.hasNext()&&i.nextIndex()<=i1;){
701: // node=(GraphicNode)i.next();
702: // if (!node.isSchedule()) continue;
703: // nodeList.add(node);
704: // node.setRow(i.previousIndex());
705: // paintNode(g2,node,true);
706: // } //Because row not initialized for some nodes
707:
708: NodeModelCache cache = graphInfo.getCache();
709: for (ListIterator i = cache.getIterator(); i.hasNext();) {
710: node = (GraphicNode) i.next();
711: node.setRow(i.previousIndex());
712: if (i.previousIndex() >= i0 && i.previousIndex() < i1) {
713: if (!node.isSchedule())
714: continue;
715: nodeList.add(node);
716: paintAnnotation(g2, node);
717: paintNode(g2, node, true);
718: }
719: }
720:
721: GraphicDependency dependency;
722: for (Iterator i = cache.getEdgesIterator(); i.hasNext();) {
723: dependency = (GraphicDependency) i.next();
724: //if (nodeList.contains(dependency.getPredecessor())||nodeList.contains(dependency.getSuccessor()))
725: paintLink(g2, dependency);
726: }
727:
728: for (ListIterator i = nodeList.listIterator(); i.hasNext();) {
729: node = (GraphicNode) i.next();
730: paintNode(g2, node, false);
731: }
732:
733: if (visibleBounds != null)
734: g2.setClip(svgClip);
735:
736: }
737:
738: }
|