Incremental GUI updates. Copied over code for TimelineDayDisplay.
This commit is contained in:
@ -23,6 +23,8 @@ public class Timeline implements Iterable<TimelineMarker> {
|
||||
timelineList = new TreeSet<TimelineMarker>();
|
||||
}
|
||||
|
||||
public void addMarker(TimelineMarker tm) { timelineList.add(tm); }
|
||||
|
||||
public void addMarker(Date timestamp, String name, String notes) {
|
||||
timelineList.add(new TimelineMarker(timestamp, name, notes));
|
||||
}
|
||||
|
@ -68,7 +68,14 @@ public class TimelineProperties {
|
||||
// load local timeline
|
||||
strURI = config.getProperty(LOCAL_TIMELINE_URI, "");
|
||||
if ("".equals(strURI)) {
|
||||
timelineURI = new File("timeline.default.txt").toURI();
|
||||
File defaultTimelineFile = new File("timeline.default.txt");
|
||||
try {
|
||||
if (!defaultTimelineFile.exists())
|
||||
defaultTimelineFile.createNewFile();
|
||||
} catch (IOException ioe) {
|
||||
// TODO
|
||||
}
|
||||
timelineURI = defaultTimelineFile.toURI();
|
||||
} else {
|
||||
try { timelineURI = new URI(strURI); }
|
||||
catch (URISyntaxException urise) {
|
||||
|
660
src/main/com/jdbernard/timestamper/gui/TimelineDayDisplay.java
Normal file
660
src/main/com/jdbernard/timestamper/gui/TimelineDayDisplay.java
Normal file
@ -0,0 +1,660 @@
|
||||
/* TimelineDayDisplay.java
|
||||
* Author: Jonathan Bernard - jonathan.bernard@gemalto.com
|
||||
*/
|
||||
|
||||
package jdbernard.timestamper.gui;
|
||||
|
||||
import com.jdbernard.timestamper.core.TimelineMarker;
|
||||
import com.jdbernard.timestamper.core.Timeline;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jbernard
|
||||
*/
|
||||
public class TimelineDayDisplay extends JComponent implements MouseListener,
|
||||
ChangeListener {
|
||||
|
||||
private class MarkerDisplayEntry {
|
||||
public TimelineMarker marker;
|
||||
public float relY;
|
||||
public float relHeight;
|
||||
public Rectangle2D markBounds;
|
||||
public Rectangle2D notesBounds;
|
||||
public Rectangle bounds;
|
||||
}
|
||||
|
||||
private class TimeLegendEntry {
|
||||
public double relY;
|
||||
public String label;
|
||||
}
|
||||
|
||||
private enum TimeDelta {
|
||||
Hourly (Calendar.HOUR_OF_DAY, 1) {
|
||||
public String formatCalendar(Calendar c) {
|
||||
return String.format("%1$02d:00",
|
||||
c.get(Calendar.HOUR_OF_DAY));
|
||||
}
|
||||
|
||||
public boolean fitsInHeight(double height, double millisec) {
|
||||
return ((height * 1000l * 60l * 30l) / millisec < 25);
|
||||
}
|
||||
},
|
||||
ThirtyMin (Calendar.MINUTE, 30) {
|
||||
public String formatCalendar(Calendar c) {
|
||||
return String.format("%1$02d:%2$02d",
|
||||
c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE));
|
||||
}
|
||||
|
||||
public boolean fitsInHeight(double height, double millisec) {
|
||||
return ((height * 1000l * 60l * 15l) / millisec < 25);
|
||||
}
|
||||
},
|
||||
FifteenMin (Calendar.MINUTE, 15) {
|
||||
public String formatCalendar(Calendar c) {
|
||||
return String.format("%1$02d:%2$02d",
|
||||
c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE));
|
||||
}
|
||||
|
||||
public boolean fitsInHeight(double height, double millisec) {
|
||||
return ((height * 1000l * 60l * 10l) / millisec < 25);
|
||||
}
|
||||
},
|
||||
TenMin (Calendar.MINUTE, 10) {
|
||||
public String formatCalendar(Calendar c) {
|
||||
return String.format("%1$02d:%2$02d",
|
||||
c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE));
|
||||
}
|
||||
|
||||
public boolean fitsInHeight(double height, double millisec) {
|
||||
return ((height * 1000l * 60l * 5l) / millisec < 25);
|
||||
}
|
||||
},
|
||||
FiveMin (Calendar.MINUTE, 5) {
|
||||
public String formatCalendar(Calendar c) {
|
||||
return String.format("%1$02d:%2$02d",
|
||||
c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE));
|
||||
}
|
||||
|
||||
public boolean fitsInHeight(double height, double millisec) {
|
||||
return ((height * 1000l * 60l) / millisec < 25);
|
||||
}
|
||||
},
|
||||
Minute (Calendar.MINUTE, 1) {
|
||||
public String formatCalendar(Calendar c) {
|
||||
return String.format("%1$02d:%2$02d",
|
||||
c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE));
|
||||
}
|
||||
|
||||
public boolean fitsInHeight(double height, double millisec) {
|
||||
return ((height * 1000l * 30l) / millisec < 25);
|
||||
}
|
||||
},
|
||||
ThirtySec (Calendar.SECOND, 30) {
|
||||
public String formatCalendar(Calendar c) {
|
||||
return String.format("%1$02d:%2$02d",
|
||||
c.get(Calendar.MINUTE), c.get(Calendar.SECOND));
|
||||
}
|
||||
|
||||
public boolean fitsInHeight(double height, double millisec) {
|
||||
return ((height * 1000l * 15l) / millisec < 25);
|
||||
}
|
||||
},
|
||||
FifteenSec (Calendar.SECOND, 15) {
|
||||
public String formatCalendar(Calendar c) {
|
||||
return String.format("%1$02d:%2$02d",
|
||||
c.get(Calendar.MINUTE), c.get(Calendar.SECOND));
|
||||
}
|
||||
|
||||
public boolean fitsInHeight(double height, double millisec) {
|
||||
return ((height * 1000l * 10l) / millisec < 25);
|
||||
}
|
||||
},
|
||||
TenSec (Calendar.SECOND, 10) {
|
||||
public String formatCalendar(Calendar c) {
|
||||
return String.format("%1$02d:%2$02d",
|
||||
c.get(Calendar.MINUTE), c.get(Calendar.SECOND));
|
||||
}
|
||||
|
||||
public boolean fitsInHeight(double height, double millisec) {
|
||||
return ((height * 1000l * 5l) / millisec < 25);
|
||||
}
|
||||
},
|
||||
FiveSec (Calendar.SECOND, 5) {
|
||||
public String formatCalendar(Calendar c) {
|
||||
return String.format("%1$02d:%2$02d",
|
||||
c.get(Calendar.MINUTE), c.get(Calendar.SECOND));
|
||||
}
|
||||
|
||||
public boolean fitsInHeight(double height, double millisec) {
|
||||
return ((height * 1000l) / millisec < 25);
|
||||
}
|
||||
},
|
||||
Second (Calendar.SECOND, 1) {
|
||||
public String formatCalendar(Calendar c) {
|
||||
return String.format("%1$02d:%2$02d",
|
||||
c.get(Calendar.MINUTE), c.get(Calendar.SECOND));
|
||||
}
|
||||
|
||||
public boolean fitsInHeight(double height, double millisec) {
|
||||
return ((height * 1500l) / millisec < 25);
|
||||
}
|
||||
},
|
||||
SubSecond (Calendar.MILLISECOND, 100) {
|
||||
public String formatCalendar(Calendar c) {
|
||||
return String.format("%1$02d:%2$03d",
|
||||
c.get(Calendar.SECOND), c.get(Calendar.MILLISECOND));
|
||||
}
|
||||
|
||||
public boolean fitsInHeight(double height, double millisec) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
private int INTERVAL;
|
||||
private int AMOUNT;
|
||||
|
||||
private TimeDelta(int interval, int amount) {
|
||||
INTERVAL = interval;
|
||||
AMOUNT = amount;
|
||||
}
|
||||
|
||||
public Calendar addToCalendar(Calendar c) {
|
||||
c.add(INTERVAL, AMOUNT);
|
||||
return c;
|
||||
}
|
||||
|
||||
public abstract boolean fitsInHeight(double height, double millisec);
|
||||
|
||||
public abstract String formatCalendar(Calendar c); { }
|
||||
}
|
||||
|
||||
private ArrayList<MarkerDisplayEntry> markerEntries;
|
||||
private ArrayList<TimeLegendEntry> timeLegendLocations;
|
||||
private TimelineMarker currentMarker;
|
||||
private ArrayList<ChangeListener> changeListeners = new ArrayList<ChangeListener>();
|
||||
|
||||
private Point lastMousePress;
|
||||
|
||||
private Font markFont;// = getFont().deriveFont(Font.BOLD);
|
||||
private Font notesFont;// = getFont();
|
||||
|
||||
private Color evenTrans = new Color(0.75f, 0.75f, 0.75f, 0.4f);
|
||||
private Color evenOpaque = new Color(0.75f, 0.75f, 0.75f, 1f);
|
||||
private Color oddTrans = new Color(0.5f, 0.5f, 0.5f, 0.4f);
|
||||
private Color oddOpaque = new Color(0.5f, 0.5f, 0.5f, 1f);
|
||||
private Color selectedTrans = new Color(0.5f, 0.75f, 0.5f, 0.4f);
|
||||
private Color selectedOpaque = new Color(0.5f, 0.75f, 0.5f, 1f);
|
||||
private Color fontColor = new Color(0.1f, 0.1f, 0.1f, 1f);
|
||||
|
||||
private Date rangeStartDate = new Date();
|
||||
private Date rangeEndDate = new Date();
|
||||
|
||||
public TimelineDayDisplay() {
|
||||
super();
|
||||
setDay(new Date(), false);
|
||||
addMouseListener(this);
|
||||
}
|
||||
|
||||
public TimelineDayDisplay(Calendar day) {
|
||||
setDay(day.getTime(), false);
|
||||
addMouseListener(this);
|
||||
updateMarkers(getGraphics());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the range for the visible timeline segment.
|
||||
* @param start The beginning of the desired timeline segment.
|
||||
* @param end The end of the desired timeline segment.
|
||||
*/
|
||||
public void setDisplayInterval(Date start, Date end) {
|
||||
rangeStartDate = start;
|
||||
rangeEndDate = end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the component to show the timeline segment for a specific day. The
|
||||
* visible area will show the full 24-hour day.
|
||||
* @param d The date of the day to display. The exact time of the variable
|
||||
* can be any time in the desired day.
|
||||
*/
|
||||
public void setDay(Date d) {
|
||||
setDay(d, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* There is the special case of instance initialization, where it is
|
||||
* desirable to call setDay to handle the range start and end calculations
|
||||
* but where we do not want to immediately update the gui, because it may
|
||||
* not be fully initialized yet.
|
||||
* @param d Day to set as the current day (component will show the range
|
||||
* representing the day from start to finish.
|
||||
* @param update If <b><pre>true</pre></b>,
|
||||
* <code>updateMarkers(getGraphics)</code> is called after the range
|
||||
* calculations are made.
|
||||
*/
|
||||
private void setDay(Date d, boolean update) {
|
||||
Calendar day = Calendar.getInstance();
|
||||
day.setTime(d);
|
||||
day.set(Calendar.HOUR_OF_DAY, 0);
|
||||
day.set(Calendar.MINUTE, 0);
|
||||
day.set(Calendar.SECOND, 0);
|
||||
rangeStartDate = day.getTime();
|
||||
|
||||
day.add(Calendar.DAY_OF_YEAR, 1);
|
||||
rangeEndDate = day.getTime();
|
||||
|
||||
if (update) updateMarkers(getGraphics());
|
||||
}
|
||||
|
||||
public void setMarkFont(Font f) {
|
||||
markFont = f;
|
||||
}
|
||||
|
||||
public Font getMarkFont() {
|
||||
return markFont;
|
||||
}
|
||||
|
||||
public void setNotesFont(Font f) {
|
||||
notesFont = f;
|
||||
}
|
||||
|
||||
public Font getNotesFont() {
|
||||
return notesFont;
|
||||
}
|
||||
|
||||
public void setFontColor(Color f) {
|
||||
fontColor = new Color(f.getRGB());
|
||||
}
|
||||
|
||||
public Color getFontColor() {
|
||||
return fontColor;
|
||||
}
|
||||
public void setEvenColor(Color c) {
|
||||
evenOpaque = new Color(c.getRGB());
|
||||
evenTrans = new Color((float) c.getRed() / 255f,
|
||||
(float) c.getGreen() / 255f,
|
||||
(float) c.getBlue() / 255f, 0.4f);
|
||||
}
|
||||
|
||||
public Color getEvenColor() {
|
||||
return evenOpaque;
|
||||
}
|
||||
|
||||
public void setOddColor(Color c) {
|
||||
oddOpaque = new Color(c.getRGB());
|
||||
oddTrans = new Color((float) c.getRed() / 255f,
|
||||
(float) c.getGreen() / 255f,
|
||||
(float) c.getBlue() / 255f, 0.4f);
|
||||
}
|
||||
|
||||
public Color getOddColor() {
|
||||
return oddOpaque;
|
||||
}
|
||||
|
||||
public void setSelectedColor(Color c) {
|
||||
selectedOpaque = new Color(c.getRGB());
|
||||
selectedTrans = new Color((float) c.getRed() / 255f,
|
||||
(float) c.getGreen() / 255f,
|
||||
(float) c.getBlue() / 255f, 0.4f);
|
||||
}
|
||||
|
||||
public Color getSelectedColor() {
|
||||
return selectedOpaque;
|
||||
}
|
||||
|
||||
public TimelineMarker getSelectedTimelineMarker() {
|
||||
return currentMarker;
|
||||
}
|
||||
|
||||
public void addMarker(Date timestamp, String mark, String notes) {
|
||||
/*Timeline timeline = TimeStamperApp.getApplication()
|
||||
.getTimelineProperties().getTimeline();
|
||||
timeline.addMarker(timestamp, mark, notes);
|
||||
updateMarkers(getGraphics());*/
|
||||
}
|
||||
|
||||
public void deleteSelectedMarker() {
|
||||
/*Timeline timeline = TimeStamperApp.getApplication()
|
||||
.getTimelineProperties().getTimeline();
|
||||
timeline.removeMarker(currentMarker);
|
||||
updateMarkers(getGraphics());*/
|
||||
}
|
||||
|
||||
public void updateSelectedMarker(String notes) {
|
||||
currentMarker.setNotes(notes);
|
||||
updateMarkers(getGraphics());
|
||||
}
|
||||
|
||||
/**
|
||||
* updateMarkers sets the internal list of TimelineMarkers, based on the
|
||||
* currently visible timeline. The drawing of the display is split between
|
||||
* this method, which constructs the data representation of what needs to
|
||||
* be drawn, and the paintComponents method, which does the drawing. This is
|
||||
* done to save computation, only recalculating markers when needed.
|
||||
*/
|
||||
private void updateMarkers(Graphics g) {
|
||||
|
||||
/*Timeline timeline = TimeStamperApp.getApplication()
|
||||
.getTimelineProperties().getTimeline();
|
||||
Insets insets = this.getInsets();
|
||||
Rectangle bounds = this.getBounds();
|
||||
Rectangle canvasBounds = new Rectangle(insets.left, insets.top,
|
||||
bounds.width - insets.left - insets.right - 1,
|
||||
bounds.height - insets.top - insets.bottom - 1);
|
||||
|
||||
Rectangle2D stringBounds = getFontMetrics(getFont()).getStringBounds("00:00 ", g);
|
||||
|
||||
long rangeDiff = rangeEndDate.getTime() - rangeStartDate.getTime();
|
||||
|
||||
markerEntries = new ArrayList<MarkerDisplayEntry>();
|
||||
timeLegendLocations = new ArrayList<TimeLegendEntry>();
|
||||
|
||||
if (markFont == null) markFont = getFont().deriveFont(Font.BOLD);
|
||||
if (notesFont == null) notesFont = getFont();
|
||||
|
||||
// calculate positions of all visible hour lines
|
||||
// choose the increment of time to view
|
||||
TimeDelta timeDelta = TimeDelta.Hourly;
|
||||
if (rangeDiff == 0) rangeDiff = 1;
|
||||
|
||||
for (TimeDelta d : TimeDelta.values()) {
|
||||
if (d.fitsInHeight(canvasBounds.getHeight(), rangeDiff)) {
|
||||
timeDelta = d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Calendar timeCounter = Calendar.getInstance();
|
||||
timeCounter.setTime(rangeStartDate);
|
||||
timeCounter.set(Calendar.MINUTE, 0);
|
||||
timeCounter.set(Calendar.SECOND, 0);
|
||||
|
||||
while (rangeStartDate.after(timeCounter.getTime()))
|
||||
timeDelta.addToCalendar(timeCounter);
|
||||
|
||||
while (rangeEndDate.after(timeCounter.getTime())) {
|
||||
TimeLegendEntry entry = new TimeLegendEntry();
|
||||
entry.relY = ((double) (timeCounter.getTimeInMillis()
|
||||
- rangeStartDate.getTime()) / (double) rangeDiff);
|
||||
entry.label = timeDelta.formatCalendar(timeCounter);
|
||||
timeLegendLocations.add(entry);
|
||||
timeDelta.addToCalendar(timeCounter);
|
||||
}
|
||||
|
||||
// get all relevant markers starting from the marker just before the
|
||||
// visible start of the display
|
||||
TimelineMarker tm = timeline.getLastMarker(rangeStartDate);
|
||||
|
||||
// If there is no previous marker
|
||||
if (tm == null)
|
||||
// try to get the first marker
|
||||
try { tm = timeline.iterator().next(); }
|
||||
// and if there aren't any markers at all, just return, the array is
|
||||
// empty so the display will be empty
|
||||
catch (Exception e) { return; }
|
||||
|
||||
// Now we want to step through the timeline, capturing all markers
|
||||
// between the visible ranges.
|
||||
Iterator<TimelineMarker> itr = timeline.iterator();
|
||||
|
||||
while (!itr.next().equals(tm));
|
||||
|
||||
ArrayList<TimelineMarker> markers = new ArrayList<TimelineMarker>();
|
||||
while (rangeEndDate.after(tm.getTimestamp())) {
|
||||
markers.add(tm);
|
||||
if (itr.hasNext()) tm = itr.next();
|
||||
else break;
|
||||
}
|
||||
|
||||
markers.add(tm);
|
||||
|
||||
for (int i = 0; i < markers.size() - 1; i++) {
|
||||
MarkerDisplayEntry markerEntry = new MarkerDisplayEntry();
|
||||
|
||||
markerEntry.marker = markers.get(i);
|
||||
|
||||
// set string bounds
|
||||
markerEntry.markBounds = getFontMetrics(markFont)
|
||||
.getStringBounds(markers.get(i).getMark(), g);
|
||||
markerEntry.notesBounds = getFontMetrics(notesFont)
|
||||
.getStringBounds(markers.get(i).getNotes(), g);
|
||||
|
||||
// calculate upper bound
|
||||
if ((i == 0) && rangeStartDate.after(markerEntry.marker.getTimestamp())) {
|
||||
//if this is the first marker (before the start time) set the
|
||||
// Y coor to 0, top of display
|
||||
markerEntry.relY = 0;
|
||||
} else {
|
||||
// otherwise, calculate how far down (%-wise) the mark is
|
||||
markerEntry.relY = (float) (((double) (markerEntry.marker.getTimestamp().getTime()
|
||||
- rangeStartDate.getTime())) / (double) rangeDiff);
|
||||
}
|
||||
|
||||
// calculate lower bound
|
||||
if ((i == 0) && rangeStartDate.after(markerEntry.marker.getTimestamp()))
|
||||
// if this is the first marker (before the start time), set the
|
||||
// height to equal the top of the next marker
|
||||
markerEntry.relHeight =
|
||||
markers.get(i + 1).getTimestamp().getTime()
|
||||
- rangeStartDate.getTime();
|
||||
else if (i == markers.size() - 2)
|
||||
// if this is the last visible marker, set the height to extend
|
||||
// to the bottom of the display
|
||||
markerEntry.relHeight = rangeEndDate.getTime()
|
||||
- markerEntry.marker.getTimestamp().getTime();
|
||||
else
|
||||
// set the height to the difference between this marker and the
|
||||
// next.
|
||||
markerEntry.relHeight =
|
||||
markers.get(i + 1).getTimestamp().getTime()
|
||||
- markerEntry.marker.getTimestamp().getTime();
|
||||
markerEntry.relHeight /= rangeDiff;
|
||||
|
||||
markerEntries.add(markerEntry);
|
||||
}
|
||||
repaint();*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintComponent(Graphics g) {
|
||||
removeAll();
|
||||
|
||||
if (markerEntries == null) updateMarkers(g);
|
||||
|
||||
Insets insets = this.getInsets();
|
||||
Rectangle bounds = this.getBounds();
|
||||
Rectangle canvasBounds = new Rectangle(insets.left, insets.top,
|
||||
bounds.width - insets.left - insets.right - 1,
|
||||
bounds.height - insets.top - insets.bottom - 1);
|
||||
double hourHeight = canvasBounds.getHeight() / 24.0;
|
||||
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
Rectangle2D stringBounds = getFontMetrics(getFont()).getStringBounds("00:00 ", g);
|
||||
|
||||
// draw hour lines
|
||||
for (TimeLegendEntry legendEntry : timeLegendLocations) {
|
||||
g.drawLine(canvasBounds.x + (int) stringBounds.getWidth(),
|
||||
(int) (canvasBounds.y + (canvasBounds.height * legendEntry.relY)),
|
||||
canvasBounds.x + canvasBounds.width,
|
||||
(int) (canvasBounds.y + (canvasBounds.height * legendEntry.relY)));
|
||||
|
||||
g.drawString(legendEntry.label, canvasBounds.x + 2,
|
||||
(int) (canvasBounds.y + (canvasBounds.height * legendEntry.relY)
|
||||
+ (stringBounds.getHeight() / 2)));
|
||||
}
|
||||
|
||||
for (int i = 0; i < markerEntries.size(); i++) {
|
||||
|
||||
MarkerDisplayEntry curEntry = markerEntries.get(i);
|
||||
|
||||
Rectangle2D markBounds;
|
||||
Rectangle2D notesBounds;
|
||||
|
||||
boolean selected = curEntry.marker.equals(currentMarker);
|
||||
|
||||
// if i == 0, this is the default
|
||||
curEntry.bounds = new Rectangle();
|
||||
curEntry.bounds.y = 3;
|
||||
curEntry.bounds.x = canvasBounds.x + (int) stringBounds.getWidth() + 5;
|
||||
curEntry.bounds.height = 1;
|
||||
curEntry.bounds.width = canvasBounds.width - (int) stringBounds.getWidth() - 8;
|
||||
|
||||
double relTime;
|
||||
|
||||
// calculate upper bound
|
||||
curEntry.bounds.y = (int) Math.round(curEntry.relY
|
||||
* canvasBounds.getHeight());
|
||||
|
||||
if (i == 0) curEntry.bounds.y += 3;
|
||||
|
||||
// calculate lower bound
|
||||
curEntry.bounds.height = (int) Math.round(curEntry.relHeight
|
||||
* canvasBounds.getHeight());
|
||||
|
||||
if (i ==0) curEntry.bounds.height -= 6;
|
||||
else curEntry.bounds.height -= 3;
|
||||
|
||||
// draw box
|
||||
if (selected) g.setColor(selectedTrans);
|
||||
else g.setColor((i % 2 == 0 ? evenTrans : oddTrans));
|
||||
g.fillRect(curEntry.bounds.x, curEntry.bounds.y, curEntry.bounds.width, curEntry.bounds.height);
|
||||
|
||||
if (selected) g.setColor(selectedOpaque);
|
||||
else g2d.setColor((i % 2 == 0 ? evenOpaque : oddOpaque));
|
||||
g2d.setStroke(new BasicStroke(3f));
|
||||
g2d.drawRect(curEntry.bounds.x, curEntry.bounds.y, curEntry.bounds.width, curEntry.bounds.height);
|
||||
|
||||
// draw timestamp name
|
||||
markBounds = (Rectangle2D) curEntry.markBounds.clone();
|
||||
markBounds.setRect(curEntry.bounds.x + 3,
|
||||
curEntry.bounds.y + stringBounds.getHeight(),
|
||||
markBounds.getWidth(), markBounds.getHeight());
|
||||
|
||||
g.setColor(fontColor);
|
||||
g.setFont(markFont);
|
||||
g.drawString(curEntry.marker.getMark(),
|
||||
(int) markBounds.getX(), (int) markBounds.getY());
|
||||
|
||||
// draw notes
|
||||
notesBounds = (Rectangle2D) curEntry.notesBounds.clone();
|
||||
notesBounds.setRect(curEntry.bounds.x + 6,
|
||||
curEntry.bounds.y + stringBounds.getHeight() + markBounds.getHeight(),
|
||||
notesBounds.getWidth(), notesBounds.getHeight());
|
||||
|
||||
if (curEntry.bounds.contains(notesBounds)) {
|
||||
g.setFont(notesFont);
|
||||
g.drawString(curEntry.marker.getNotes(),
|
||||
(int) notesBounds.getX(), (int) notesBounds.getY());
|
||||
}
|
||||
}
|
||||
|
||||
g.setColor(Color.BLACK);
|
||||
g.drawRect(canvasBounds.x, canvasBounds.y, canvasBounds.width, canvasBounds.height);
|
||||
}
|
||||
|
||||
public void addChangeListener(ChangeListener cl) {
|
||||
changeListeners.add(cl);
|
||||
}
|
||||
|
||||
public boolean removeChangeListener(ChangeListener cl) {
|
||||
return changeListeners.remove(cl);
|
||||
}
|
||||
|
||||
private void fireChangeEvent() {
|
||||
for (ChangeListener cl : changeListeners)
|
||||
cl.stateChanged(new ChangeEvent(this));
|
||||
}
|
||||
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (e.getButton() == MouseEvent.BUTTON1) {
|
||||
Point topLeft = getLocationOnScreen();
|
||||
currentMarker = null;
|
||||
for (MarkerDisplayEntry markerEntry : markerEntries) {
|
||||
Rectangle absBounds = new Rectangle(markerEntry.bounds);
|
||||
absBounds.translate(topLeft.x, topLeft.y);
|
||||
|
||||
// should only match one entry
|
||||
if (absBounds.contains(e.getLocationOnScreen())) {
|
||||
currentMarker = markerEntry.marker;
|
||||
break;
|
||||
}
|
||||
}
|
||||
repaint();
|
||||
fireChangeEvent();
|
||||
} else if (e.getButton() == MouseEvent.BUTTON3) {
|
||||
setDay(rangeStartDate);
|
||||
}
|
||||
}
|
||||
|
||||
public void mousePressed(MouseEvent e) {
|
||||
lastMousePress = e.getPoint();
|
||||
}
|
||||
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
Insets insets = this.getInsets();
|
||||
Rectangle bounds = this.getBounds();
|
||||
Rectangle canvasBounds = new Rectangle(insets.left, insets.top,
|
||||
bounds.width - insets.left - insets.right - 1,
|
||||
bounds.height - insets.top - insets.bottom - 1);
|
||||
|
||||
double rangeDiff = rangeEndDate.getTime() - rangeStartDate.getTime();
|
||||
double y1 = lastMousePress.getY();
|
||||
double y2 = e.getY();
|
||||
|
||||
if (Math.abs(y2 - y1) < 5) return;
|
||||
|
||||
// get time for y1
|
||||
long time1 = (long) Math.round((((y1 - canvasBounds.y)
|
||||
/ canvasBounds.height) * rangeDiff) + rangeStartDate.getTime());
|
||||
long time2 = (long) Math.round((((y2 - canvasBounds.y)
|
||||
/ canvasBounds.height) * rangeDiff) + rangeStartDate.getTime());
|
||||
|
||||
// left click, scroll
|
||||
if (e.getButton() == MouseEvent.BUTTON1) {
|
||||
long difference = time1 - time2;
|
||||
rangeStartDate.setTime(rangeStartDate.getTime() + difference);
|
||||
rangeEndDate.setTime(rangeEndDate.getTime() + difference);
|
||||
}
|
||||
// right click, zoom
|
||||
else if (e.getButton() == MouseEvent.BUTTON3) {
|
||||
if (time1 < time2) {
|
||||
rangeStartDate.setTime(time1);
|
||||
rangeEndDate.setTime(time2);
|
||||
} else {
|
||||
rangeStartDate.setTime(time2);
|
||||
rangeEndDate.setTime(time1);
|
||||
}
|
||||
}
|
||||
updateMarkers(getGraphics());
|
||||
}
|
||||
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
}
|
||||
|
||||
public void mouseExited(MouseEvent e) {
|
||||
}
|
||||
|
||||
public void stateChanged(ChangeEvent ce) {
|
||||
updateMarkers(getGraphics());
|
||||
repaint();
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user