Finished catching up to 1.7 functionality.

This commit is contained in:
Jonathan Bernard 2009-12-26 14:49:46 -06:00
parent cee6de1147
commit 6d212ea771
21 changed files with 346 additions and 67 deletions

@ -45,8 +45,8 @@ environments {
signingkey { signingkey {
params { params {
sigfile = 'GRIFFON' sigfile = 'GRIFFON'
keystore = 'CHANGE ME' keystore = 'keystore.jks'
alias = 'CHAMGE ME' alias = 'timestamper'
// NOTE: for production keys it is more secure to rely on key prompting // NOTE: for production keys it is more secure to rely on key prompting
// no value means we will prompt //storepass = 'BadStorePassword' // no value means we will prompt //storepass = 'BadStorePassword'
// no value means we will prompt //keypass = 'BadKeyPassword' // no value means we will prompt //keypass = 'BadKeyPassword'

@ -1,16 +1,22 @@
package com.jdbernard.timestamper package com.jdbernard.timestamper
import java.awt.Point
class PunchcardDialogController { class PunchcardDialogController {
// these will be injected by Griffon // these will be injected by Griffon
def model def model
def view def view
void mvcGroupInit(Map args) { void mvcGroupInit(Map args) {
// this method is called after model and view are injected
def loc = model.mainMVC.view.frame.location
Point p = new Point(0, (int) model.mainMVC.view.frame.bounds.height + 50)
p.translate((int) loc.x, (int) loc.y)
view.dialog.location = p
} }
/* /*
def action = { evt = null -> def action = { evt = null ->
} }
*/ */
} }

@ -10,8 +10,7 @@ class TimeStamperMainController {
void mvcGroupInit(Map args) { void mvcGroupInit(Map args) {
if (logger.isTraceEnabled()) logger.traceIfEnabled("Initializing TimeStamperMain MVC...")
logger.trace("Initializeing TimeStamperMain MVC...")
def thisMVC = ['model': model, 'view': view, 'controller': this] def thisMVC = ['model': model, 'view': view, 'controller': this]
@ -27,6 +26,9 @@ class TimeStamperMainController {
model.configFile = new File(userHomeDir, ".timestamperrc") model.configFile = new File(userHomeDir, ".timestamperrc")
if (!model.configFile.exists()) model.configFile.createNewFile() if (!model.configFile.exists()) model.configFile.createNewFile()
logger.traceIfEnabled("Reading configuration from "
+ "'${model.configFile.name}'")
try { model.configFile.withInputStream { prop.load(it) } } try { model.configFile.withInputStream { prop.load(it) } }
catch (IOException ioe) { catch (IOException ioe) {
logger.error('Unable to load configuration', ioe) logger.error('Unable to load configuration', ioe)
@ -40,27 +42,41 @@ class TimeStamperMainController {
lastUsed = 'timeline.default.properties' lastUsed = 'timeline.default.properties'
model.config.setProperty('lastUsed', lastUsed) model.config.setProperty('lastUsed', lastUsed)
} }
logger.traceIfEnabled("Reading Timeline properties from '${lastUsed}'")
File propertyFile = new File(lastUsed) File propertyFile = new File(lastUsed)
if (!propertyFile.exists()) propertyFile.createNewFile() if (!propertyFile.exists()) propertyFile.createNewFile()
model.timelineProperties = new TimelineProperties(propertyFile) load(propertyFile)
}
def load = { File propertiesFile ->
try {
model.config.setProperty('lastUsed', propertiesFile.canonicalPath)
} catch (IOException ioe) { logger.error(ioe) }
// load the properties file
model.timelineProperties = new TimelineProperties(propertiesFile)
// load the main timeline // load the main timeline
model.timeline = model.timelineProperties.timeline model.timeline = model.timelineProperties.timeline
// load the last marker // load the last marker
model.currentMarker = model.timeline.getLastMarker(new Date()) model.currentMarker = model.timeline.getLastMarker(new Date())
}
if (logger.isTraceEnabled())
logger.trace("TimeStamperMain MVC initialization complete.")
def saveas = {
} }
def exitGracefully = { evt = null -> def exitGracefully = { evt = null ->
if (logger.isTraceEnabled()) logger.trace("Exiting gracefully.") logger.traceIfEnabled("Exiting gracefully.")
// save config // save config
logger.debugIfEnabled("Config: ${model.config}")
logger.debugIfEnabled("Storing config to file: ${model.configFile.path}")
try { model.configFile.withOutputStream { out -> try { model.configFile.withOutputStream { out ->
model.config.store(out, null) } } model.config.store(out, null) } }
catch (IOException ioe) { catch (IOException ioe) {
@ -70,15 +86,20 @@ class TimeStamperMainController {
// save timeline and properties // save timeline and properties
model.timelineProperties.save() model.timelineProperties.save()
if (logger.isTraceEnabled()) logger.trace("Completed graceful shutdown.") logger.traceIfEnabled("Completed graceful shutdown.")
app.shutdown() app.shutdown()
} }
def newTask = { mark -> def newTask = { mark, notes = "No comments.", timestamp = new Date() ->
model.currentMarker = new TimelineMarker(new Date(), mark, TimelineMarker tm = new TimelineMarker(timestamp, mark, notes)
"No comments.") model.timeline.addMarker(tm)
model.timeline.addMarker(model.currentMarker) model.currentMarker = model.timeline.getLastMarker(new Date())
}
def deleteTask = { marker ->
model.timeline.removeMarker(marker)
model.currentMarker = model.timeline.getLastMarker(new Date())
} }
} }

@ -19,6 +19,21 @@
import groovy.swing.SwingBuilder import groovy.swing.SwingBuilder
import griffon.util.GriffonPlatformHelper import griffon.util.GriffonPlatformHelper
import org.apache.log4j.Logger
GriffonPlatformHelper.tweakForNativePlatform(app) GriffonPlatformHelper.tweakForNativePlatform(app)
SwingBuilder.lookAndFeel('mac', 'nimbus', 'gtk', ['metal', [boldFonts: false]]) SwingBuilder.lookAndFeel('system', 'nimbus', ['metal', [boldFonts: false]])
Logger.metaClass.traceIfEnabled = { String message, Throwable t = null ->
if (delegate.isTraceEnabled()) {
if (t != null) delegate.trace(message, t)
else delegate.trace(message)
}
}
Logger.metaClass.debugIfEnabled = { String message, Throwable t = null ->
if (delegate.isDebugEnabled()) {
if (t != null) delegate.debug(message, t)
else delegate.debug(message)
}
}

@ -15,4 +15,5 @@
* - SwingBuilder.doLater { // your code } * - SwingBuilder.doLater { // your code }
* - SwingBuilder.edt { // your code } * - SwingBuilder.edt { // your code }
* - SwingUtilities.invokeLater { // your code } * - SwingUtilities.invokeLater { // your code }
*/ */

@ -1,5 +1,5 @@
package com.jdbernard.timestamper package com.jdbernard.timestamper
import groovy.beans.Bindable import groovy.beans.Bindable
class PunchcardDialogModel { class PunchcardDialogModel {

@ -1,13 +1,12 @@
log4j.rootLogger=ERROR, stdout log4j.rootLogger=trace, stdout
log4j.logger.com.jdbernard.timestamper=TRACE
# set up stdout
# set up stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=[%t] %-5p - %m%n
log4j.appender.stdout.layout.ConversionPattern=[%t] %-5p - %m%n
# set up fileout
# set up fileout log4j.appender.fileout=org.apache.log4j.FileAppender
log4j.appender.fileout=org.apache.log4j.FileAppender
log4j.appender.fileout.File=TimeStamper.log log4j.appender.fileout.File=TimeStamper.log
log4j.appender.fileout.layout=org.apache.log4j.PatternLayout log4j.appender.fileout.layout=org.apache.log4j.PatternLayout
log4j.appender.fileout.layout.ConversionPattern=%5p [%t] - %m%n log4j.appender.fileout.layout.ConversionPattern=%5p [%t] - %m%n

Before

(image error) Size: 345 B

After

(image error) Size: 345 B

Before

(image error) Size: 660 B

After

(image error) Size: 660 B

Before

(image error) Size: 782 B

After

(image error) Size: 782 B

Before

(image error) Size: 764 B

After

(image error) Size: 764 B

@ -5,6 +5,8 @@ import java.awt.Point
import java.awt.Rectangle import java.awt.Rectangle
import java.awt.Toolkit import java.awt.Toolkit
import javax.swing.BoxLayout import javax.swing.BoxLayout
import javax.swing.JDialog
import com.jdbernard.GUIUtil
import net.miginfocom.swing.MigLayout import net.miginfocom.swing.MigLayout
Point mousePressRelativeToDialog Point mousePressRelativeToDialog
@ -26,11 +28,13 @@ mouseDragged = { evt ->
} }
dialog = dialog( dialog = dialog(new JDialog(model.mainMVC.view.frame),
title: 'Notes', title: 'Notes',
modal: false, modal: false,
undecorated: true, undecorated: true,
minimumSize: [325, 200], minimumSize: [325, 200],
mousePressed: mousePressed,
mouseDragged: mouseDragged,
iconImage: imageIcon('/16-em-pencil.png').image, iconImage: imageIcon('/16-em-pencil.png').image,
iconImages: [imageIcon('/16-em-pencil.png').image], iconImages: [imageIcon('/16-em-pencil.png').image],
location: bind(source: model.mainMVC.model, location: bind(source: model.mainMVC.model,
@ -42,18 +46,21 @@ dialog = dialog(
return p return p
} else return dialog.location }) } else return dialog.location })
) { ) {
logger.traceIfEnabled('Building NotesDialog GUI')
panel( panel(
border:lineBorder(color: Color.BLACK, thickness:1, parent:true), border:lineBorder(color: Color.BLACK, thickness:1, parent:true),
mousePressed: mousePressed, layout: new MigLayout('insets 10 10 10 10, fill')
mouseDragged: mouseDragged,
layout: new MigLayout('insets 5 5 5 5, fill')
) { ) {
scrollPane(constraints: 'growx, growy') { scrollPane(constraints: 'growx, growy') {
notesTextArea = textArea(lineWrap: true, columns: 20, rows: 5, notesTextArea = textArea(lineWrap: true, columns: 20, rows: 5,
wrapStyleWord: true, wrapStyleWord: true,
text: bind(source: model.mainMVC.model, text: bind(source: model.mainMVC.model,
sourceProperty: 'currentMarker', sourceProperty: 'currentMarker',
sourceValue: { model.mainMVC.model.currentMarker?.notes})) sourceValue: { model.mainMVC.model.currentMarker?.notes}),
keyReleased: {
if (model.mainMVC.model.currentMarker != null)
model.mainMVC.model.currentMarker.notes =
notesTextArea.text})
} }
} }
} }

@ -1,12 +1,163 @@
package com.jdbernard.timestamper package com.jdbernard.timestamper
punchcardDialog = dialog( import java.awt.Color
/* title: 'Punchcard', import java.awt.Point
import java.awt.Toolkit
import java.awt.Rectangle
import java.text.SimpleDateFormat
import javax.swing.JDialog
import java.util.Calendar
import javax.swing.SwingConstants
import com.jdbernard.GUIUtil
import com.jdbernard.timestamper.gui.TimelineDayDisplay
import com.toedter.calendar.JDateChooser
import net.miginfocom.swing.MigLayout
Point mousePressRelativeToDialog
Point offsetFromMainFrame = new Point(0,0)
boolean coupledToMainFrame = false
dateFormatter = new SimpleDateFormat("EEE MMM dd")
mousePressed = { evt -> mousePressRelativeToDialog = evt?.point }
mouseDragged = { evt ->
GUIUtil.componentDragged(dialog, evt, mousePressRelativeToDialog,
new Rectangle(Toolkit.defaultToolkit.screenSize),
model.mainMVC.view.frame.bounds)
offsetFromMainFrame = GUIUtil.calculateOffset(
model.mainMVC.view.frame, dialog)
coupledToMainFrame = GUIUtil.componentsCoupled(dialog,
model.mainMVC.view.frame);
}
dialog = dialog(new JDialog(model.mainMVC.view.frame),
title: 'Punchcard',
modal: false, modal: false,
undecorated: true, undecorated: true,
iconImage: iconImage('/16-file-archive.png').image, mousePressed: mousePressed,
iconImages: [iconImage('/16-file-archive.png').image], mouseDragged: mouseDragged,
minimumSize: [325, 600]*/ iconImage: imageIcon('/16-file-archive.png').image,
iconImages: [imageIcon('/16-file-archive.png').image],
minimumSize: [450, 500],
location: bind(source: model.mainMVC.model,
sourceProperty: 'absoluteLocation',
converter: { loc ->
if (coupledToMainFrame) {
Point p = new Point(offsetFromMainFrame)
p.translate((int) loc.x, (int) loc.y)
return p
} else return dialog.location })
) { ) {
logger.traceIfEnabled('Building PunchcardDialog GUI')
panel(
border:lineBorder(color: Color.BLACK, thickness:1, parent:true),
layout: new MigLayout('fill, insets 10 10 10 10',
'[grow]', '[grow]10[grow 0]')
) {
dayDisplay = widget(constraints: 'grow, gp 200',
new TimelineDayDisplay(model.mainMVC.model.timeline),
timeline: bind(source: model.mainMVC.model,
sourceProperty: 'timeline'),
stateChanged: bind(source: model.mainMVC.model,
sourceProperty: 'currentMarker'))
panel(
border: lineBorder(color: Color.BLACK, thickness: 1),
constraints: 'growx, growy 0, newline, bottom',
layout: new MigLayout('fill, insets 0 10 0 10',
'[grow]10[grow 0]', '[][][grow 0]')
) {
dateChooser = widget(new JDateChooser(),
constraints: 'growx, gaptop 10',
dateFormatString: 'MMM d, yyyy HH:mm',
date: bind(source: dayDisplay,
sourceProperty: 'selectedTimelineMarker',
converter: { it?.timestamp }))
panel(constraints: 'spany 3, wrap, al trailing',
layout: new MigLayout('insets 0', '[]0[]0[]0[]0[]',
'[]0[]0[]0[]0[]')
) {
label(background: [255, 255, 153],
constraints: 'growx, spanx 5, wrap',
horizontalAlignment: SwingConstants.CENTER,
opaque: true,
text: bind(source: dayDisplay,
sourceProperty: 'rangeStart',
converter: { dateFormatter.format(it) }))
Calendar calendar = Calendar.getInstance()
button(icon: imageIcon('/previous-week.png'),
border: emptyBorder(4),
actionPerformed: {
calendar.time = dayDisplay.rangeStart
calendar.add(Calendar.WEEK_OF_YEAR, -1)
dayDisplay.day = calendar.time })
button(icon: imageIcon('/previous-day.png'),
border: emptyBorder(4),
actionPerformed: {
calendar.time = dayDisplay.rangeStart
calendar.add(Calendar.DAY_OF_YEAR, -1)
dayDisplay.day = calendar.time })
button(text: 'Today',
border: emptyBorder(4),
actionPerformed: {
calendar = Calendar.getInstance()
dayDisplay.day = calendar.time })
button(icon: imageIcon('/next-day.png'),
border: emptyBorder(4),
actionPerformed: {
calendar.time = dayDisplay.rangeStart
calendar.add(Calendar.DAY_OF_YEAR, 1)
dayDisplay.day = calendar.time })
button(icon: imageIcon('/next-week.png'),
constraints: 'wrap',
border: emptyBorder(4),
actionPerformed: {
calendar.time = dayDisplay.rangeStart
calendar.add(Calendar.WEEK_OF_YEAR, 1)
dayDisplay.day = calendar.time })
button(text: 'New Marker', icon: imageIcon('/new-marker.png'),
constraints: 'growx, spanx 5, wrap',
horizontalAlignment: SwingConstants.CENTER,
actionPerformed: {
model.mainMVC.controller.newTask(markTextField.text,
notesTextField.text, dateChooser.date) })
button(text: 'Delete Marker',
icon: imageIcon('/delete-marker.png'),
constraints: 'growx, spanx 5, wrap',
horizontalAlignment: SwingConstants.CENTER,
actionPerformed: {
model.mainMVC.controller.deleteTask(
dayDisplay.selectedTimelineMarker) })
button(text: 'Apply Changes',
icon: imageIcon('/document-save-16x16.png'),
constraints: 'growx, spanx 5',
horizontalAlignment: SwingConstants.CENTER,
actionPerformed: {
Date d = dateChooser.date
String m = markTextField.text
String n = notesTextField.text
model.mainMVC.controller.deleteTask(
dayDisplay.selectedTimelineMarker)
model.mainMVC.controller.newTask(m, n, d) })
}
markTextField = textField(constraints: 'growx, wrap',
text: bind(source: dayDisplay,
sourceProperty: 'selectedTimelineMarker',
converter: { it?.mark }))
scrollPane(constraints: 'growx, gapbottom 10',
minimumSize: [0, 50]) {
notesTextField = textArea( wrapStyleWord: true, lineWrap: true,
text: bind(source: dayDisplay,
sourceProperty: 'selectedTimelineMarker',
converter: { it?.notes }))
}
}
}
} }

@ -7,7 +7,11 @@ import java.awt.Rectangle
import java.awt.Toolkit import java.awt.Toolkit
import java.awt.event.KeyEvent import java.awt.event.KeyEvent
import javax.swing.BoxLayout import javax.swing.BoxLayout
import javax.swing.JDialog
import javax.swing.JFileChooser
import javax.swing.SwingConstants
import javax.swing.Timer import javax.swing.Timer
import com.jdbernard.GUIUtil
import com.jdbernard.timestamper.core.Timeline import com.jdbernard.timestamper.core.Timeline
import net.miginfocom.swing.MigLayout import net.miginfocom.swing.MigLayout
@ -30,16 +34,12 @@ taskTextFieldChanged = { evt = null ->
taskTextField.font = taskThinFont taskTextField.font = taskThinFont
} }
showToolsMenu = { evt = null ->
}
showNotes = { evt = null -> showNotes = { evt = null ->
model.notesDialogMVC.view.dialog.visible = notesVisibleButton.selected model.notesDialogMVC.view.dialog.visible = notesVisibleButton.selected
} }
showPunchcard = { evt = null -> showPunchcard = { evt = null ->
model.punchcardDialogMVC.view.dialog.visible = punchcardVisibleButton.selected
} }
mousePressed = { evt = null -> mousePressed = { evt = null ->
@ -80,17 +80,34 @@ updateTimer = new Timer(1000, action(name: 'GUI Refresh', closure: {
updateTimer.start() updateTimer.start()
optionsMenu = popupMenu() {
menuItem(icon: imageIcon('/document-save-16x16.png'), text: 'Save Timeline',
actionPerformed: { model.timelineProperties.save() })
menuItem(icon: imageIcon('/document-save-as-16x16.png'),
text: 'Save a new copy...', actionPerformed: controller.&saveas)
menuItem(icon: imageIcon('/document-open-16x16.png'),
text: 'Load Timeline...', actionPerformed: {
if (fileDialog.showOpenDialog(frame) ==
JFileChooser.APPROVE_OPTION)
controller.load(fileDialog.selectedFile) })
aboutMenuItem = checkBoxMenuItem(text: 'About...',
actionPerformed: { aboutDialog.visible = aboutMenuItem.selected })
}
fileDialog = fileChooser();
frame = application(title:'TimeStamper', frame = application(title:'TimeStamper',
//size:[320,480], location:[50,50],
pack:true,
//location:[50,50],
undecorated:true,
locationByPlatform:true, locationByPlatform:true,
minimumSize: [325, 0],
pack:true,
undecorated:true,
iconImage: imageIcon('/appointment-new-32x32.png').image, iconImage: imageIcon('/appointment-new-32x32.png').image,
iconImages: [imageIcon('/appointment-new-32x32.png').image, iconImages: [imageIcon('/appointment-new-32x32.png').image,
imageIcon('/appointment-new-16x16.png').image], imageIcon('/appointment-new-16x16.png').image],
componentMoved: { evt -> model.absoluteLocation = frame.location } componentMoved: { evt -> model.absoluteLocation = frame.location }
) { ) {
logger.traceIfEnabled('Building TimeStamperMain GUI')
panel( panel(
border:lineBorder(color:Color.BLACK, thickness:1, parent:true), border:lineBorder(color:Color.BLACK, thickness:1, parent:true),
layout: new MigLayout('insets 0 5 0 0, fill','', '[]0[]0[]'), layout: new MigLayout('insets 0 5 0 0, fill','', '[]0[]0[]'),
@ -110,25 +127,29 @@ frame = application(title:'TimeStamper',
panel(constraints: 'alignx trailing, aligny top, wrap') { panel(constraints: 'alignx trailing, aligny top, wrap') {
boxLayout(axis: BoxLayout.X_AXIS) boxLayout(axis: BoxLayout.X_AXIS)
button(actionPerformed: showToolsMenu, button(mouseClicked: { evt ->
optionsMenu.show(evt.component, evt.x, evt.y) },
icon: imageIcon('/16-tool-a.png'), icon: imageIcon('/16-tool-a.png'),
rolloverIcon: imageIcon('/16-tool-a-hover.png'), rolloverIcon: imageIcon('/16-tool-a-hover.png'),
border: emptyBorder(0), border: emptyBorder(0),
contentAreaFilled: false, contentAreaFilled: false,
hideActionText: true) hideActionText: true,
toolTipText: 'Options Menu')
button(actionPerformed: controller.&exitGracefully, button(actionPerformed: controller.&exitGracefully,
icon: imageIcon('/16-em-cross.png'), icon: imageIcon('/16-em-cross.png'),
rolloverIcon: imageIcon('/16-em-cross-hover.png'), rolloverIcon: imageIcon('/16-em-cross-hover.png'),
border: emptyBorder(0), border: emptyBorder(0),
contentAreaFilled: false, contentAreaFilled: false,
hideActionText: true) hideActionText: true,
toolTipText: 'Close Application')
} }
taskTextField = textField("Task name", taskTextField = textField("Task name",
constraints: "growx, span 2, w 250::", constraints: "growx, span 2, w 250::",
keyReleased: taskTextFieldChanged, keyReleased: taskTextFieldChanged,
toolTipText: 'The current task',
text: bind(source: model, sourceProperty: 'currentMarker', text: bind(source: model, sourceProperty: 'currentMarker',
sourceValue: { model.currentMarker.mark })) sourceValue: { model.currentMarker?.mark }))
taskThinFont = taskTextField.font taskThinFont = taskTextField.font
taskBoldFont = taskTextField.font.deriveFont(Font.BOLD) taskBoldFont = taskTextField.font.deriveFont(Font.BOLD)
@ -139,12 +160,14 @@ frame = application(title:'TimeStamper',
actionPerformed: showNotes, actionPerformed: showNotes,
icon: imageIcon('/16-em-pencil.png'), icon: imageIcon('/16-em-pencil.png'),
hideActionText: true, hideActionText: true,
border: emptyBorder(4)) border: emptyBorder(4),
toolTipText: 'Show/hide task notes.')
punchcardVisibleButton = toggleButton( punchcardVisibleButton = toggleButton(
actionPerformed: showPunchcard, actionPerformed: showPunchcard,
icon: imageIcon('/16-file-archive.png'), icon: imageIcon('/16-file-archive.png'),
hideActionText: true, hideActionText: true,
border: emptyBorder(4)) border: emptyBorder(4),
toolTipText: 'Show/hide the timeline display.')
} }
totalTimeLabel = label("", constraints: 'alignx leading', totalTimeLabel = label("", constraints: 'alignx leading',
@ -155,4 +178,24 @@ frame = application(title:'TimeStamper',
} }
} }
aboutDialog = dialog(new JDialog(frame),
visible: false,
locationRelativeTo: null,
pack: true,
undecorated: true,
title: "About TimeStamper v" + app.applicationProperties.'app.version'
) {
panel(layout: new MigLayout('fill'),
border: lineBorder(color: Color.BLACK, thickness: 1)) {
label(font: new Font(Font.SANS_SERIF, Font.PLAIN, 18),
text: "TimeStamper", constraints: 'growx, wrap',
horizontalAlignment: SwingConstants.CENTER)
label(text: "version " + app.applicationProperties.'app.version'
+ " by Jonathan Bernard", constraints: 'growx, wrap',
horizontalAlignment: SwingConstants.CENTER)
textField(text: 'http://www.jdbernard.com/timestamper',
constraints: 'growx', foreground: [0,0,200], editable: false,
horizontalAlignment: SwingConstants.CENTER)
}
}

BIN
keystore.jks Normal file

Binary file not shown.

BIN
lib/jcalendar-1.3.2.jar Executable file

Binary file not shown.

@ -1,4 +1,4 @@
package com.jdbernard.timestamper package com.jdbernard
import java.awt.Point import java.awt.Point
import java.awt.Rectangle import java.awt.Rectangle

@ -214,14 +214,16 @@ public class TimelineDayDisplay extends JComponent implements MouseListener,
} }
public TimelineDayDisplay() {
this(null, Calendar.getInstance());
}
public TimelineDayDisplay(Timeline t) { public TimelineDayDisplay(Timeline t) {
super(); this(t, Calendar.getInstance());
setDay(new Date(), false);
this.timeline = t;
addMouseListener(this);
} }
public TimelineDayDisplay(Timeline t, Calendar day) { public TimelineDayDisplay(Timeline t, Calendar day) {
super();
setDay(day.getTime(), false); setDay(day.getTime(), false);
addMouseListener(this); addMouseListener(this);
this.timeline = t; this.timeline = t;
@ -232,16 +234,31 @@ public class TimelineDayDisplay extends JComponent implements MouseListener,
pcs.addPropertyChangeListener(l); pcs.addPropertyChangeListener(l);
} }
public void addPropertyChangeListener(String propertyName,
PropertyChangeListener l) {
pcs.addPropertyChangeListener(propertyName, l);
}
public void removePropertyChangeListener(PropertyChangeListener l) { public void removePropertyChangeListener(PropertyChangeListener l) {
pcs.removePropertyChangeListener(l); pcs.removePropertyChangeListener(l);
} }
public Timeline getTimeline() { return timeline; }
public void setTimeline(Timeline t) {
if (timeline == t) return;
pcs.firePropertyChange("timeline", timeline, timeline = t);
updateMarkers(getGraphics());
repaint();
}
/** /**
* Set the range for the visible timeline segment. * Set the range for the visible timeline segment.
* @param start The beginning of the desired timeline segment. * @param start The beginning of the desired timeline segment.
* @param end The end of the desired timeline segment. * @param end The end of the desired timeline segment.
*/ */
public void setDisplayInterval(Date start, Date end) { public void setDisplayInterval(Date start, Date end) {
if (start == rangeStartDate && end == rangeEndDate) return;
pcs.firePropertyChange("rangeStart", rangeStartDate, rangeStartDate = start); pcs.firePropertyChange("rangeStart", rangeStartDate, rangeStartDate = start);
pcs.firePropertyChange("rangeEnd", rangeEndDate, rangeEndDate = end); pcs.firePropertyChange("rangeEnd", rangeEndDate, rangeEndDate = end);
} }
@ -299,31 +316,39 @@ public class TimelineDayDisplay extends JComponent implements MouseListener,
* @param f The font to use. * @param f The font to use.
*/ */
public void setMarkFont(Font f) { public void setMarkFont(Font f) {
if (markFont == f) return;
pcs.firePropertyChange("markFont", markFont, markFont = f); pcs.firePropertyChange("markFont", markFont, markFont = f);
repaint();
} }
public Font getMarkFont() { return markFont; } public Font getMarkFont() { return markFont; }
public void setNotesFont(Font f) { public void setNotesFont(Font f) {
if (notesFont == f) return;
pcs.firePropertyChange("notesFont", notesFont, notesFont = f); pcs.firePropertyChange("notesFont", notesFont, notesFont = f);
repaint();
} }
public Font getNotesFont() { return notesFont; } public Font getNotesFont() { return notesFont; }
public void setFontColor(Color f) { public void setFontColor(Color f) {
if (fontColor == f) return;
pcs.firePropertyChange("fontColor", fontColor, pcs.firePropertyChange("fontColor", fontColor,
fontColor = new Color(f.getRGB())); fontColor = new Color(f.getRGB()));
repaint();
} }
public Color getFontColor() { return fontColor; } public Color getFontColor() { return fontColor; }
public void setEvenColor(Color c) { public void setEvenColor(Color c) {
if (evenOpaque == c) return;
evenTrans = new Color((float) c.getRed() / 255f, evenTrans = new Color((float) c.getRed() / 255f,
(float) c.getGreen() / 255f, (float) c.getGreen() / 255f,
(float) c.getBlue() / 255f, 0.4f); (float) c.getBlue() / 255f, 0.4f);
pcs.firePropertyChange("evenColor", evenOpaque, pcs.firePropertyChange("evenColor", evenOpaque,
evenOpaque = new Color(c.getRGB())); evenOpaque = new Color(c.getRGB()));
repaint();
} }
public Color getEvenColor() { public Color getEvenColor() {
@ -331,13 +356,14 @@ public class TimelineDayDisplay extends JComponent implements MouseListener,
} }
public void setOddColor(Color c) { public void setOddColor(Color c) {
oddOpaque = new Color(c.getRGB()); if (oddOpaque == c) return;
oddTrans = new Color((float) c.getRed() / 255f, oddTrans = new Color((float) c.getRed() / 255f,
(float) c.getGreen() / 255f, (float) c.getGreen() / 255f,
(float) c.getBlue() / 255f, 0.4f); (float) c.getBlue() / 255f, 0.4f);
pcs.firePropertyChange("oddColor", oddOpaque, pcs.firePropertyChange("oddColor", oddOpaque,
oddOpaque = new Color(c.getRGB())); oddOpaque = new Color(c.getRGB()));
repaint();
} }
public Color getOddColor() { public Color getOddColor() {
@ -345,12 +371,13 @@ public class TimelineDayDisplay extends JComponent implements MouseListener,
} }
public void setSelectedColor(Color c) { public void setSelectedColor(Color c) {
selectedOpaque = new Color(c.getRGB()); if (selectedOpaque == c) return;
selectedTrans = new Color((float) c.getRed() / 255f, selectedTrans = new Color((float) c.getRed() / 255f,
(float) c.getGreen() / 255f, (float) c.getGreen() / 255f,
(float) c.getBlue() / 255f, 0.4f); (float) c.getBlue() / 255f, 0.4f);
pcs.firePropertyChange("selectedColor", selectedOpaque, pcs.firePropertyChange("selectedColor", selectedOpaque,
selectedOpaque = new Color(c.getRGB())); selectedOpaque = new Color(c.getRGB()));
repaint();
} }
public Color getSelectedColor() { public Color getSelectedColor() {
@ -375,6 +402,8 @@ public class TimelineDayDisplay extends JComponent implements MouseListener,
*/ */
private void updateMarkers(Graphics g) { private void updateMarkers(Graphics g) {
if (timeline == null) return;
Insets insets = this.getInsets(); Insets insets = this.getInsets();
Rectangle bounds = this.getBounds(); Rectangle bounds = this.getBounds();
Rectangle canvasBounds = new Rectangle(insets.left, insets.top, Rectangle canvasBounds = new Rectangle(insets.left, insets.top,
@ -498,6 +527,8 @@ public class TimelineDayDisplay extends JComponent implements MouseListener,
public void paintComponent(Graphics g) { public void paintComponent(Graphics g) {
removeAll(); removeAll();
if (timeline == null) return;
if (markerEntries == null) updateMarkers(g); if (markerEntries == null) updateMarkers(g);
Insets insets = this.getInsets(); Insets insets = this.getInsets();
@ -614,7 +645,8 @@ public class TimelineDayDisplay extends JComponent implements MouseListener,
// should only match one entry // should only match one entry
if (absBounds.contains(e.getLocationOnScreen())) { if (absBounds.contains(e.getLocationOnScreen())) {
currentMarker = markerEntry.marker; pcs.firePropertyChange("selectedTimelineMarker",
currentMarker, currentMarker = markerEntry.marker);
break; break;
} }
} }
@ -678,4 +710,8 @@ public class TimelineDayDisplay extends JComponent implements MouseListener,
repaint(); repaint();
} }
public void setStateChanged(Object o) {
stateChanged(null);
}
} }