KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > taskblocks > graph > TaskGraphComponent


1 /*
2  * Copyright (C) Jakub Neubauer, 2007
3  *
4  * This file is part of TaskBlocks
5  *
6  * TaskBlocks is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * TaskBlocks is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */

19
20 package taskblocks.graph;
21
22 import java.awt.AlphaComposite JavaDoc;
23 import java.awt.BasicStroke JavaDoc;
24 import java.awt.Color JavaDoc;
25 import java.awt.Cursor JavaDoc;
26 import java.awt.FontMetrics JavaDoc;
27 import java.awt.Graphics JavaDoc;
28 import java.awt.Graphics2D JavaDoc;
29 import java.awt.Insets JavaDoc;
30 import java.awt.Rectangle JavaDoc;
31 import java.awt.RenderingHints JavaDoc;
32 import java.awt.event.AdjustmentEvent JavaDoc;
33 import java.awt.event.AdjustmentListener JavaDoc;
34 import java.awt.event.ComponentEvent JavaDoc;
35 import java.awt.event.ComponentListener JavaDoc;
36 import java.awt.geom.Line2D JavaDoc;
37 import java.text.DateFormat JavaDoc;
38 import java.text.SimpleDateFormat JavaDoc;
39 import java.util.Date JavaDoc;
40
41 import javax.swing.BorderFactory JavaDoc;
42 import javax.swing.JComponent JavaDoc;
43 import javax.swing.JScrollBar JavaDoc;
44 import javax.swing.ToolTipManager JavaDoc;
45 import javax.swing.event.ChangeListener JavaDoc;
46
47 import taskblocks.Colors;
48 import taskblocks.Pair;
49 import taskblocks.Utils;
50
51 public class TaskGraphComponent extends JComponent JavaDoc implements ComponentListener JavaDoc, AdjustmentListener JavaDoc {
52     
53     static int ROW_HEIGHT = 30;
54     private static int DEFAULT_DAY_WIDTH = 10;
55     static int CONN_PADDING_FACTOR = 6;
56     private static int HEADER_HEIGHT = 20;
57     
58     // how far from task left/right boundary will the mouse press will be recognized as pressing the boundary?
59
private static final int TOLERANCE = 5;
60     // constant indicating left boundary of task
61
static Integer JavaDoc LEFT = new Integer JavaDoc(0);
62     // constant indicating left boundary of task
63
static Integer JavaDoc RIGHT = new Integer JavaDoc(1);
64     
65     /**
66      * original mode of tasks. It is not updated when doing changes in graph. Explicit
67      * call of {@link TaskGraphRepresentation#updateModel()} must be done.
68      */

69     TaskGraphModel _model;
70     
71     /**
72      * This is the representation of Graph data (tasks and rows). It has more pre-counted
73      * informations in comparison to original _model.
74      */

75     TaskGraphRepresentation _builder;
76     
77     /** Paiter used to paint tasks and workers */
78     TaskGraphPainter _painter;
79     
80     /** Listener on user interaction in this graph.
81      * Currently, just mouse click event is sent to outside world
82      */

83     GraphActionListener _grActListener;
84     
85     /** Current width of one day column in pixels */
86     int _dayWidth = DEFAULT_DAY_WIDTH;
87     
88     /** first visible day (on left border) */
89     long _firstDay;
90     
91     /** left position of graph area */
92     int _graphLeft;
93     /** top position of graph area */
94     private int _graphTop;
95     /** width of graph area */
96     private int _graphWidth;
97     /** height of graph area */
98     int _graphHeight;
99     /** Width of the left column with workers */
100     int _headerWidth;
101     /** Handler of mouse events */
102     GraphMouseHandler _mouseHandler;
103     JScrollBar JavaDoc _verticalScroll;
104     
105     /**
106      * Contains the bounds of the whole content displayed in the component.
107      * Is used to display scrollbars at right position and with the right size
108      */

109     Rectangle JavaDoc _contentBounds = new Rectangle JavaDoc();
110     
111     int _scrollTop;
112     
113     public TaskGraphComponent(TaskGraphModel model, TaskGraphPainter painter) {
114         _painter = painter;
115
116         setModel(model);
117         _mouseHandler = new GraphMouseHandler(this);
118         _verticalScroll = new JScrollBar JavaDoc(JScrollBar.VERTICAL);
119         this.add(_verticalScroll);
120         _verticalScroll.addAdjustmentListener(this);
121         
122         setBorder(BorderFactory.createEmptyBorder(0,0,15,0));
123         this.addMouseMotionListener(_mouseHandler);
124         this.addMouseListener(_mouseHandler);
125         this.addMouseWheelListener(_mouseHandler);
126         this.addKeyListener(_mouseHandler);
127         this.addComponentListener(this);
128         this.setFocusable(true);
129         ToolTipManager.sharedInstance().setDismissDelay(8000);
130         ToolTipManager.sharedInstance().setReshowDelay(3000);
131     }
132     
133     public TaskGraphRepresentation getGraphRepresentation() {
134         return _builder;
135     }
136     
137     public void moveRight() {
138         _firstDay +=2;
139         _builder.setPaintDirty();
140         repaint();
141     }
142     
143     public void moveLeft() {
144         _firstDay-=2;
145         _builder.setPaintDirty();
146         repaint();
147     }
148     
149     void recountBounds() {
150         Insets JavaDoc insets = getInsets();
151         _graphTop = HEADER_HEIGHT;
152         _graphTop += insets.top;
153         _graphHeight = getHeight() - HEADER_HEIGHT;
154         _graphLeft = _headerWidth;
155         _graphWidth = getWidth() - _headerWidth;
156     
157         _graphLeft += insets.left;
158         _graphHeight -= insets.top + insets.bottom;
159         _graphWidth -= insets.left + insets.right;
160
161     }
162     
163     public void paint(Graphics JavaDoc g) {
164         Graphics2D JavaDoc g2 = (Graphics2D JavaDoc)g;
165         
166         g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
167         
168         //_headerWidth = 100;
169
g2.setColor(Color.white);
170         g2.fillRect(0,0,getWidth(), getHeight());
171         
172         synchronized(_builder) {
173             Insets JavaDoc insets = getInsets();
174
175             recountBounds();
176             // recount boundaries and positions and paddings if neccessary
177
if(_builder.isPaintDirty()) {
178                 TaskLayouter.recountBounds(_graphTop, ROW_HEIGHT, _builder, this, g2);
179             }
180             
181             g2.clipRect(insets.left, insets.top, getWidth()-insets.left-insets.right, getHeight()-insets.top-insets.bottom);
182             
183             // reset content bounds
184
_contentBounds.y = Integer.MAX_VALUE;
185             _contentBounds.height = -1;
186             
187             // paint rows
188
for(TaskRow row: _builder._rows) {
189                 row._bounds.x = insets.left;
190                 row._bounds.y = row._topPosition-3;
191                 row._bounds.width = row._selected ? _headerWidth + _graphWidth : _headerWidth;
192                 row._bounds.height = ROW_HEIGHT+6;
193                 _painter.paintRowHeader(row._userManObject, g2, row._bounds, row._selected);
194                 
195                 if(row._index > 0) {
196                     g2.setColor(Color.lightGray);
197                     int lineY = row._topPosition-row._topPadding*CONN_PADDING_FACTOR;
198                     g2.drawLine(insets.left, lineY, 2000, lineY);
199                 }
200                 
201                 // adjust vertical size of the content bounds
202
if(_contentBounds.y > row._bounds.y) {
203                     if(_contentBounds.height != -1) {
204                         _contentBounds.height += (_contentBounds.y - row._bounds.y);
205                     }
206                     _contentBounds.y = row._bounds.y;
207                 }
208                 if(_contentBounds.y + _contentBounds.height < row._bounds.y + row._bounds.height + CONN_PADDING_FACTOR) {
209                     _contentBounds.height = row._bounds.y + row._bounds.height - _contentBounds.y + CONN_PADDING_FACTOR;
210                 }
211             }
212             
213             // left header vertical line
214
g2.setColor(Color.DARK_GRAY);
215             g2.drawLine(_graphLeft, _graphTop-HEADER_HEIGHT, _graphLeft, _graphTop + _graphHeight+HEADER_HEIGHT);
216             Color JavaDoc lightHeaderCol = Colors.TASKS_TOP_HEADER_COLOR.brighter().brighter();
217             g2.setColor(lightHeaderCol);
218             g2.drawLine(_graphLeft+1, _graphTop-HEADER_HEIGHT, _graphLeft+1, _graphTop-1);
219             //g2.drawLine(_graphLeft+2, _graphTop-HEADER_HEIGHT, _graphLeft+2, _graphTop + _graphHeight+HEADER_HEIGHT);
220

221             paintWorkerHeader(g2);
222
223             // paint tasks
224
g2.clipRect(_graphLeft+2, _graphTop - HEADER_HEIGHT, _graphWidth-3, _graphHeight+HEADER_HEIGHT);
225             Task t;
226             for(int i = _builder._tasks.length-1; i >= 0; i--) {
227                 t = _builder._tasks[i];
228                 _painter.paintTask(t._userObject, g2, t._bounds, t._selected || t == _mouseHandler._pressedTask);
229                 // adjust the holder of content size
230

231                 if(_contentBounds.y > t._bounds.y) {_contentBounds.y = t._bounds.y;}
232                 if(_contentBounds.y + _contentBounds.height < t._bounds.y + t._bounds.height) {
233                     _contentBounds.height = t._bounds.y + t._bounds.height - _contentBounds.y;
234                 }
235             }
236             // paint weekends and header
237
paintHeaderAndWeekends(g2);
238
239             // paint connections
240
for(Connection c: _builder._connections) {
241                 paintConnection(g2, c);
242             }
243             
244             // paint the insertion cursor
245
paintCursor(g2);
246             
247             // paint just being created conection
248
if(_mouseHandler._dragMode == 4) {
249                 g2.setColor(Color.RED);
250                 if(_mouseHandler._destTask != null && _mouseHandler._destTask != _mouseHandler._pressedTask) {
251                     _painter.paintTask(_mouseHandler._destTask._userObject, g2, _mouseHandler._destTask._bounds, true);
252                 }
253                 g2.drawLine(_mouseHandler._pressX, _mouseHandler._pressY, _mouseHandler.getLastMouseX(), _mouseHandler.getLastMouseY());
254             }
255         }
256         
257         adjustScrolls();
258         
259         // paint children, at least scroll bar(s)
260
paintChildren(g);
261     }
262     
263     public void scaleDown() {
264         long mouseDay = xToTime(_mouseHandler.getLastMouseX());
265
266         _dayWidth -=1;
267         if(_dayWidth < 4) {
268             _dayWidth = 4;
269         }
270
271         long newMouseDay = xToTime(_mouseHandler.getLastMouseX());
272         if(newMouseDay != mouseDay) {
273             _firstDay -= newMouseDay-mouseDay;
274         }
275
276         _builder.setPaintDirty();
277         repaint();
278     }
279     
280     public void scaleUp() {
281         long mouseDay = xToTime(_mouseHandler.getLastMouseX());
282         
283         _dayWidth += 1;
284         if(_dayWidth > 50) {
285             _dayWidth = 50;
286         }
287         
288         long newMouseDay = xToTime(_mouseHandler.getLastMouseX());
289         if(newMouseDay != mouseDay) {
290             _firstDay -= newMouseDay-mouseDay;
291         }
292         _builder.setPaintDirty();
293         repaint();
294     }
295
296     public void setGraphActionListener(GraphActionListener list) {
297         _grActListener = list;
298     }
299     
300     public void setGraphChangeListener(ChangeListener JavaDoc changeListener) {
301         _builder.setGraphChangeListener(changeListener);
302     }
303
304     public void focusOnToday() {
305         _firstDay = System.currentTimeMillis()/Utils.MILLISECONDS_PER_DAY;
306         _builder.setPaintDirty();
307         repaint();
308     }
309     
310     public void scrollToTaskVisible(Object JavaDoc task) {
311         // find the task
312
Task taskToFocus = null;
313         for(Task t: _builder._tasks) {
314             if(t._userObject == task) {
315                 taskToFocus = t;
316                 break;
317             }
318         }
319         if(taskToFocus == null) {
320             // not found
321
return;
322         }
323         
324         // scroll to the task.
325
// find the most right visible day.
326
long lastVisibleDay = xToTime(getWidth()-getInsets().right);
327         
328         // is the task outside the right border?
329
if(taskToFocus.getFinishTime() > lastVisibleDay) {
330             _firstDay += (taskToFocus.getFinishTime() - lastVisibleDay);
331             _builder.setPaintDirty();
332         }
333         // is the task outside the left border?
334
if(taskToFocus.getStartTime() < _firstDay) {
335             _firstDay = taskToFocus.getStartTime();
336             _builder.setPaintDirty();
337         }
338         
339         // select the focused task
340
_mouseHandler.clearSelection();
341         _mouseHandler._selection.add(taskToFocus);
342         taskToFocus._selected = true;
343
344         repaint();
345     }
346     
347     public void setModel(TaskGraphModel model) {
348         if(model == _model) {
349             // just rebuilds the model
350
_builder.buildFromModel();
351             return;
352         }
353         TaskGraphRepresentation oldBuilder = _builder;
354         _model = model;
355         _builder = new TaskGraphRepresentation(_model);
356         if(oldBuilder != null) {
357             _builder.setGraphChangeListener(oldBuilder.getGraphChangeListener());
358             oldBuilder.setGraphChangeListener(null); // not neccessary, just to be sure
359
}
360         _builder.buildFromModel();
361
362         // find the minimum task start time and use it as first day.
363
_firstDay = Long.MAX_VALUE;
364         for(Task t: _builder._tasks) {
365             if(_firstDay > t.getStartTime()) {
366                 _firstDay = t.getStartTime();
367             }
368         }
369         if(_firstDay == Long.MAX_VALUE) {
370             _firstDay = System.currentTimeMillis()/Utils.MILLISECONDS_PER_DAY;
371         }
372         
373         repaint();
374     }
375     
376     TaskRow findRow(int y) {
377         for(TaskRow row: _builder._rows) {
378             if(y >= row._topPosition-row._topPadding*CONN_PADDING_FACTOR && y <= row._topPosition + ROW_HEIGHT + row._bottomPadding*CONN_PADDING_FACTOR) {
379                 return row;
380             }
381         }
382         return null;
383     }
384
385     TaskRow findNearestRow(int y) {
386         TaskRow myRow = null;
387         int minDist = Integer.MAX_VALUE;
388         for(TaskRow row: _builder._rows) {
389             if(y > row._topPosition && y < row._topPosition + ROW_HEIGHT) {
390                 myRow = row;
391                 break;
392             } else {
393                 int dist = Math.min(
394                         Math.abs(y-row._topPosition),
395                         Math.abs(y-(row._topPosition + ROW_HEIGHT))
396                 );
397                 if(dist < minDist) {
398                     myRow = row;
399                     minDist = dist;
400                 }
401             }
402         }
403         return myRow;
404     }
405     
406     void changeCursor(Object JavaDoc o) {
407         if(o instanceof Task || o instanceof Connection) {
408             this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
409         } else if(o instanceof Pair) {
410             this.setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
411         } else {
412             this.setCursor(Cursor.getDefaultCursor());
413         }
414     }
415
416     Object JavaDoc findObjectOnPo(int x, int y) {
417
418         if(x < _graphLeft) {
419             return findRow(y);
420         }
421         
422         for(Task t: _builder._tasks) {
423             
424             if(y > t._bounds.y && y < (t._bounds.y + t._bounds.height)) {
425                 if(x > (t._bounds.x-TOLERANCE) && x < (t._bounds.x + TOLERANCE)) {
426                     return new Pair<Task, Integer JavaDoc>(t, LEFT);
427                 }
428                 if(x > (t._bounds.x+t._bounds.width-TOLERANCE) && x < (t._bounds.x + t._bounds.width + TOLERANCE)) {
429                     return new Pair<Task, Integer JavaDoc>(t, RIGHT);
430                 }
431             }
432
433             if(t._bounds.contains(x, y)) {
434                 return t;
435             }
436         }
437         
438         for(Connection c: _builder._connections) {
439             // check the distance from the path
440
double d = Line2D.ptSegDistSq(c._path.xpoints[0], c._path.ypoints[0], c._path.xpoints[1], c._path.ypoints[1], x, y);
441             d = Math.min(d, Line2D.ptSegDistSq(c._path.xpoints[1], c._path.ypoints[1], c._path.xpoints[2], c._path.ypoints[2], x, y));
442             d = Math.min(d, Line2D.ptSegDistSq(c._path.xpoints[2], c._path.ypoints[2], c._path.xpoints[3], c._path.ypoints[3], x, y));
443             if(d < 5*5) {
444                 return c;
445             }
446         }
447         
448         return null;
449     }
450
451     private void paintConnection(Graphics2D JavaDoc g2, Connection c) {
452         if(c._selected) {
453             g2.setColor(Colors.SELECTOIN_COLOR);
454         } else {
455             g2.setColor(Colors.CONNECTION_COLOR);
456         }
457         
458         int x2 = c._path.xpoints[3];
459         int y2 = c._path.ypoints[3];
460         if(y2 > c._path.ypoints[0]) {
461             g2.drawLine(x2-3, y2-5, x2, y2);
462             g2.drawLine(x2+3, y2-5, x2, y2);
463         } else {
464             g2.drawLine(x2-3, y2+5, x2, y2);
465             g2.drawLine(x2+3, y2+5, x2, y2);
466         }
467         g2.drawLine(c._path.xpoints[0], c._path.ypoints[0], c._path.xpoints[1], c._path.ypoints[1]);
468         g2.drawLine(c._path.xpoints[1], c._path.ypoints[1], c._path.xpoints[2], c._path.ypoints[2]);
469         g2.drawLine(c._path.xpoints[2], c._path.ypoints[2], c._path.xpoints[3], c._path.ypoints[3]);
470     }
471     
472     private void paintCursor(Graphics2D JavaDoc g2) {
473         if(_mouseHandler._cursorTaskRow != null && _mouseHandler._cursorTime >= 0 && _mouseHandler._pressedTask != null) {
474             
475             g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f));
476             int y = _mouseHandler._cursorTaskRow._topPosition;
477             
478             int transX = (int)((_mouseHandler._cursorTime - _mouseHandler._pressedTask.getStartTime())*_dayWidth);
479             int transY = y - _mouseHandler._pressedTask._row._topPosition;
480             g2.translate(transX, transY);
481             _painter.paintTask(_mouseHandler._pressedTask._userObject, g2, _mouseHandler._pressedTask._bounds, true);
482             g2.setColor(Color.BLACK);
483             g2.setStroke(new BasicStroke JavaDoc(3));
484             g2.drawLine(_mouseHandler._pressedTask._bounds.x, _mouseHandler._pressedTask._bounds.y+3, _mouseHandler._pressedTask._bounds.x, _mouseHandler._pressedTask._bounds.y + _mouseHandler._pressedTask._bounds.height-4);
485             g2.translate(-transX, -transY);
486         }
487     }
488
489     private void paintWorkerHeader(Graphics2D JavaDoc g2) {
490         g2.setColor(Colors.TASKS_TOP_HEADER_COLOR);
491
492         FontMetrics JavaDoc fm = g2.getFontMetrics();
493         
494         g2.fillRect(_graphLeft-_headerWidth, _graphTop-HEADER_HEIGHT, _headerWidth, HEADER_HEIGHT);
495         g2.setColor(Color.WHITE);
496         g2.drawString("Worker", _graphLeft-_headerWidth + 8, _graphTop-HEADER_HEIGHT + (fm.getHeight() + HEADER_HEIGHT)/2 - fm.getDescent() );
497         
498         Color JavaDoc darkHeaderCol = Colors.TASKS_TOP_HEADER_COLOR.darker().darker();
499         Color JavaDoc lightHeaderCol = Colors.TASKS_TOP_HEADER_COLOR.brighter().brighter();
500         g2.setColor(darkHeaderCol);
501         g2.drawRect(_graphLeft-_headerWidth, _graphTop-HEADER_HEIGHT, _graphWidth+_headerWidth-1, HEADER_HEIGHT+_graphHeight-1);
502         g2.drawLine(_graphLeft-_headerWidth, _graphTop, _graphLeft+_graphWidth, _graphTop);
503         g2.setColor(lightHeaderCol);
504         g2.drawLine(_graphLeft-_headerWidth+1, _graphTop-1, _graphLeft-_headerWidth+1, _graphTop-HEADER_HEIGHT+1);
505         g2.drawLine(_graphLeft-_headerWidth+1, _graphTop-HEADER_HEIGHT+1, _graphLeft-1, _graphTop-HEADER_HEIGHT+1);
506     }
507     
508     private void paintHeaderAndWeekends(Graphics2D JavaDoc g2) {
509         Color JavaDoc lightHeaderCol = Colors.TASKS_TOP_HEADER_COLOR.brighter().brighter();
510         Color JavaDoc darkHeaderCol = Colors.TASKS_TOP_HEADER_COLOR.darker().darker();
511         FontMetrics JavaDoc fm = g2.getFontMetrics();
512         
513         g2.setColor(Colors.TASKS_TOP_HEADER_COLOR);
514         g2.fillRect(_graphLeft+1, _graphTop-HEADER_HEIGHT+1, _graphWidth-2, HEADER_HEIGHT-1);
515         g2.setColor(Color.WHITE);
516
517         int skip = 1;
518         if(_dayWidth < 10) {
519             skip = 2;
520         }
521
522         Color JavaDoc weekEndColor = new Color JavaDoc(50,50,50,50); // transparent
523
int x = 0, x1, x2;
524         int mostRight = _graphLeft + _graphWidth;
525         
526         int firstDayInWeek = Utils.getDayInWeek(_firstDay);
527         for(int i = -firstDayInWeek; x < mostRight; i+=7) {
528             long time = _firstDay + i;
529             x = timeToX(time);
530             if(x >= mostRight) {
531                 break;
532             }
533             
534             // draw weekend column
535
g2.setColor(weekEndColor);
536             x1 = timeToX(time+5);
537             x2 = timeToX(time+7);
538             g2.fillRect(x1, _graphTop, x2-x1, _graphHeight);
539
540             // draw the date string
541
if((time/7) % skip == 0) {
542                 DateFormat JavaDoc df = new SimpleDateFormat JavaDoc("d.M.");
543                 String JavaDoc timeFormatted = df.format(new Date JavaDoc(time*Utils.MILLISECONDS_PER_DAY));
544                 g2.setColor(Color.WHITE);
545                 g2.drawString(timeFormatted, x+4, _graphTop-HEADER_HEIGHT + (fm.getHeight() + HEADER_HEIGHT)/2 - fm.getDescent() -1 );
546                 g2.setColor(darkHeaderCol);
547             }
548         }
549         
550         // paint the scale on the top
551
//g2.setColor(new Color(100,10,5));
552
g2.setColor(darkHeaderCol);
553         x = 0;
554         for(int i = 0; x < mostRight; i++) {
555             long time = _firstDay + i;
556             x = timeToX(time);
557             x2 = timeToX(time + skip*7);
558             int dayInWeek = Utils.getDayInWeek(time);
559             g2.setColor(darkHeaderCol);
560             g2.drawLine(x, _graphTop-3, x, _graphTop-1);
561             if(dayInWeek == 0 && (time/7) % skip == 0) {
562                 g2.drawLine(x, _graphTop-HEADER_HEIGHT, x, _graphTop-1);
563                 g2.setColor(lightHeaderCol);
564                 g2.drawLine(x+1, _graphTop-1, x+1, _graphTop-HEADER_HEIGHT+1);
565                 g2.drawLine(x+1, _graphTop - HEADER_HEIGHT+1, x2-1, _graphTop-HEADER_HEIGHT+1);
566             }
567         }
568         
569         g2.setColor(darkHeaderCol);
570         //g2.drawLine(_graphLeft, _graphTop, _graphLeft+_graphWidth, _graphTop);
571

572         
573         // paint today line
574
long time = System.currentTimeMillis()/ Utils.MILLISECONDS_PER_DAY;
575         g2.setColor(new Color JavaDoc(255,0,0,100));
576         x = timeToX(time);
577         g2.drawLine(x, _graphTop, x, _graphTop + _graphHeight);
578         
579     }
580     
581     /** Converts time to the component x-coordinate in pixels */
582     int timeToX(long time) {
583         int relativeTime = (int)(time - _firstDay);
584         return _graphLeft + relativeTime * _dayWidth;
585     }
586
587     long xToTime(int x) {
588         x+= _dayWidth/2; // we want the nearest day, not the one rounded down.
589
return (x - _graphLeft) / _dayWidth + _firstDay;
590     }
591
592     public void componentHidden(ComponentEvent JavaDoc e) {
593     }
594
595     public void componentMoved(ComponentEvent JavaDoc e) {
596     }
597
598     public void componentResized(ComponentEvent JavaDoc e) {
599         recountBounds();
600         Insets JavaDoc insets = getInsets();
601         _verticalScroll.setBounds(
602                 getWidth() - _verticalScroll.getWidth() - insets.right,
603                 _graphTop+1,
604                 _verticalScroll.getPreferredSize().width,
605                 getHeight() - _graphTop - insets.bottom-2
606                 );
607     }
608
609     public void componentShown(ComponentEvent JavaDoc e) {
610     }
611
612     boolean _adjustingScrolls;
613     public void adjustmentValueChanged(AdjustmentEvent JavaDoc e) {
614         if(_adjustingScrolls) {
615             return;
616         }
617         if(_contentBounds.height == -1) {
618             return;
619         }
620         if(e.getSource() == _verticalScroll) {
621             // helper variable
622
Rectangle JavaDoc b = new Rectangle JavaDoc(_contentBounds);
623             b.y-=10;
624             b.height+=20;
625             int top = _graphTop;
626             int bottom = getHeight() - getInsets().bottom; // TODO + horizScroll.height
627
int canScrollUp = Math.max(0, Math.max(bottom - b.y - b.height, top - b.y));
628             
629             int diff = _verticalScroll.getValue() - canScrollUp;
630             _scrollTop -= diff;
631             _builder.setPaintDirty();
632             repaint();
633         }
634     }
635     private void adjustScrolls() {
636         // helper variable
637
_adjustingScrolls = true;
638         if(_contentBounds.height == -1) {
639             return;
640         }
641         try {
642             Rectangle JavaDoc b = new Rectangle JavaDoc(_contentBounds);
643             b.y-=10;
644             b.height+=20;
645             int top = _graphTop;
646             int bottom = getHeight() - getInsets().bottom; // TODO + horizScroll.height
647

648             int canScrollDown = Math.max(0, Math.max(b.y-top, b.y + b.height - bottom));
649             int canScrollUp = Math.max(0, Math.max(bottom - (b.y + b.height), top - b.y));
650             
651             //System.out.println(_contentBounds.y + ", " + contentBottom + ", " + top + ", " + bottom + " : " + canScrollUp + ", " + canScrollDown);
652
_verticalScroll.setMaximum(canScrollUp + canScrollDown);
653             _verticalScroll.setBlockIncrement((canScrollUp + canScrollDown) / 5);
654             _verticalScroll.setValue(canScrollUp);
655             //System.out.println(_verticalScroll.getMinimum() + ", " + _verticalScroll.getMaximum() + ", " + _verticalScroll.getValue());
656
} finally {
657             _adjustingScrolls = false;
658         }
659     }
660     
661     public void deleteSelection() {
662         _mouseHandler.deleteSelection();
663     }
664
665 }
666
Popular Tags