Incremental GUI updates. Copied over code for TimelineDayDisplay.
This commit is contained in:
@ -1,21 +1,8 @@
|
||||
package com.jdbernard.timestamper
|
||||
|
||||
import java.awt.event.KeyEvent
|
||||
|
||||
gracefulExitAction = action (
|
||||
name: 'Graceful Exit',
|
||||
closure: controller.&exitGracefully
|
||||
)
|
||||
|
||||
toolsMenuAction = action (
|
||||
name: 'Show Tools Menu',
|
||||
closure: controller.&showToolsMenu
|
||||
)
|
||||
|
||||
showNotesAction = action (
|
||||
name: 'Show Notes',
|
||||
closure: controller.&showNotes
|
||||
)
|
||||
|
||||
showPunchcardAction = action (
|
||||
name: 'Show Punchcard',
|
||||
closure: controller.&showPunchcard
|
||||
)
|
||||
|
@ -9,20 +9,27 @@ application {
|
||||
//frameClass = 'javax.swing.JFrame'
|
||||
}
|
||||
mvcGroups {
|
||||
// MVC Group for "com.jdbernard.timestamper.PunchcardDialog"
|
||||
'PunchcardDialog' {
|
||||
model = 'com.jdbernard.timestamper.PunchcardDialogModel'
|
||||
view = 'com.jdbernard.timestamper.PunchcardDialogView'
|
||||
controller = 'com.jdbernard.timestamper.PunchcardDialogController'
|
||||
}
|
||||
|
||||
// MVC Group for "com.jdbernard.timestamper.NotesDialog"
|
||||
'NotesDialog' {
|
||||
actions = 'com.jdbernard.timestamper.NotesDialogActions'
|
||||
model = 'com.jdbernard.timestamper.NotesDialogModel'
|
||||
controller = 'com.jdbernard.timestamper.NotesDialogController'
|
||||
view = 'com.jdbernard.timestamper.NotesDialogView'
|
||||
controller = 'com.jdbernard.timestamper.NotesDialogController'
|
||||
}
|
||||
|
||||
// MVC Group for "com.jdbernard.timestamper.TimeStamperMain"
|
||||
'TimeStamperMain' {
|
||||
actions = 'com.jdbernard.timestamper.TimeStamperMainActions'
|
||||
model = 'com.jdbernard.timestamper.TimeStamperMainModel'
|
||||
controller = 'com.jdbernard.timestamper.TimeStamperMainController'
|
||||
view = 'com.jdbernard.timestamper.TimeStamperMainView'
|
||||
controller = 'com.jdbernard.timestamper.TimeStamperMainController'
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,26 +1,11 @@
|
||||
package com.jdbernard.timestamper
|
||||
|
||||
import java.awt.Point
|
||||
import java.awt.Rectangle
|
||||
import java.awt.Toolkit
|
||||
|
||||
class NotesDialogController {
|
||||
// these will be injected by Griffon
|
||||
def model
|
||||
def view
|
||||
|
||||
|
||||
void mvcGroupInit(Map args) {
|
||||
}
|
||||
|
||||
Point mousePressRelativeToDialog
|
||||
|
||||
def mousePressed = { evt -> mousePressRelativeToDialog = evt?.point }
|
||||
|
||||
def mouseDragged = { evt ->
|
||||
GUIUtil.componentDragged(view.notesDialog, evt,
|
||||
mousePressRelativeToDialog,
|
||||
new Rectangle(Toolkit.defaultToolkit.screenSize),
|
||||
app.views.TimeStamperMain.frame.bounds)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
package com.jdbernard.timestamper
|
||||
|
||||
class PunchcardDialogController {
|
||||
// these will be injected by Griffon
|
||||
def model
|
||||
def view
|
||||
|
||||
void mvcGroupInit(Map args) {
|
||||
// this method is called after model and view are injected
|
||||
}
|
||||
|
||||
/*
|
||||
def action = { evt = null ->
|
||||
}
|
||||
*/
|
||||
}
|
@ -1,49 +1,64 @@
|
||||
package com.jdbernard.timestamper
|
||||
|
||||
import java.awt.Point
|
||||
import java.awt.Rectangle
|
||||
import java.awt.Toolkit
|
||||
import java.util.Timer
|
||||
import com.jdbernard.timestamper.core.TimelineMarker
|
||||
import com.jdbernard.timestamper.core.TimelineProperties
|
||||
|
||||
class TimeStamperMainController {
|
||||
// these will be injected by Griffon
|
||||
def model
|
||||
def view
|
||||
|
||||
Timer updateTimer
|
||||
|
||||
Point mousePressRelativeToFrame
|
||||
|
||||
void mvcGroupInit(Map args) {
|
||||
def notes = buildMVCGroup('NotesDialog')
|
||||
def punchcard = buildMVCGroup('PunchcardDialog')
|
||||
view.notesDialog = notes.view.notesDialog
|
||||
view.punchcardDialog = punchcard.view.punchcardDialog
|
||||
|
||||
updateTimer
|
||||
// load application properties
|
||||
Properties prop = new Properties()
|
||||
String userHomeDir = System.getProperty('user.home')
|
||||
model.configFile = new File(userHomeDir, ".timestamperrc")
|
||||
if (!model.configFile.exists()) model.configFile.createNewFile()
|
||||
|
||||
try { model.configFile.withInputStream { prop.load(it) } }
|
||||
catch (IOException ioe) { /* TODO */ }
|
||||
|
||||
model.config = prop
|
||||
|
||||
// load the last used timeline file
|
||||
String lastUsed = model.config.getProperty('lastUsed', null)
|
||||
if (lastUsed == null) {
|
||||
lastUsed = 'timeline.default.properties'
|
||||
model.config.setProperty('lastUsed', lastUsed)
|
||||
}
|
||||
File propertyFile = new File(lastUsed)
|
||||
if (!propertyFile.exists()) propertyFile.createNewFile()
|
||||
|
||||
model.timelineProperties = new TimelineProperties(propertyFile)
|
||||
|
||||
// load the main timeline
|
||||
model.timeline = model.timelineProperties.timeline
|
||||
|
||||
// load the last marker
|
||||
model.currentMarker = model.timeline.getLastMarker(new Date())
|
||||
|
||||
}
|
||||
|
||||
def exitGracefully = { evt = null ->
|
||||
// save config
|
||||
try { model.configFile.withOutputStream { out ->
|
||||
model.config.store(out, null) } }
|
||||
catch (IOException ioe) {}
|
||||
|
||||
// save timeline and properties
|
||||
model.timelineProperties.save()
|
||||
app.shutdown()
|
||||
}
|
||||
|
||||
def showToolsMenu = { evt = null ->
|
||||
|
||||
}
|
||||
|
||||
def showNotes = { evt = null ->
|
||||
view.notesDialog.visible = view.notesVisibleButton.selected
|
||||
}
|
||||
|
||||
def showPunchcard = { evt = null ->
|
||||
|
||||
}
|
||||
|
||||
def mousePressed = { evt = null ->
|
||||
mousePressRelativeToFrame = evt?.point
|
||||
}
|
||||
|
||||
def mouseDragged = { evt = null ->
|
||||
GUIUtil.componentDragged(view.frame, evt, mousePressRelativeToFrame,
|
||||
new Rectangle(Toolkit.defaultToolkit.screenSize))
|
||||
def newTask = { mark ->
|
||||
model.currentMarker = new TimelineMarker(new Date(), mark,
|
||||
"No comments.")
|
||||
model.timeline.addMarker(model.currentMarker)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
package com.jdbernard.timestamper
|
||||
|
||||
import groovy.beans.Bindable
|
||||
|
||||
class PunchcardDialogModel {
|
||||
// @Bindable String propName
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
package com.jdbernard.timestamper
|
||||
|
||||
import groovy.beans.Bindable
|
||||
import java.awt.Point
|
||||
import java.util.Properties
|
||||
import com.jdbernard.timestamper.core.Timeline
|
||||
import com.jdbernard.timestamper.core.TimelineMarker
|
||||
import com.jdbernard.timestamper.core.TimelineProperties
|
||||
@ -8,5 +10,9 @@ import com.jdbernard.timestamper.core.TimelineProperties
|
||||
class TimeStamperMainModel {
|
||||
@Bindable TimelineMarker currentMarker
|
||||
@Bindable Timeline timeline
|
||||
@Bindable TimelineProperties properties
|
||||
@Bindable TimelineProperties timelineProperties
|
||||
@Bindable Properties config
|
||||
File configFile
|
||||
|
||||
@Bindable Point absoluteLocation
|
||||
}
|
||||
|
@ -1,27 +1,55 @@
|
||||
package com.jdbernard.timestamper
|
||||
|
||||
import java.awt.Color
|
||||
import java.awt.Point
|
||||
import java.awt.Rectangle
|
||||
import java.awt.Toolkit
|
||||
import javax.swing.BoxLayout
|
||||
import net.miginfocom.swing.MigLayout
|
||||
|
||||
Point mousePressRelativeToDialog
|
||||
Point offsetFromMainFrame
|
||||
|
||||
mousePressed = { evt -> mousePressRelativeToDialog = evt?.point }
|
||||
|
||||
mouseDragged = { evt ->
|
||||
GUIUtil.componentDragged(view.notesDialog, evt,
|
||||
mousePressRelativeToDialog,
|
||||
new Rectangle(Toolkit.defaultToolkit.screenSize),
|
||||
app.views.TimeStamperMain.frame.bounds)
|
||||
|
||||
Point p = app.views.TimeStamperMain.frame.location
|
||||
offsetFromMainFrame = new Point(notesDialog.location)
|
||||
offsetFromMainFrame.translate((int) -p.x, (int) -p.y)
|
||||
}
|
||||
|
||||
notesDialog = dialog(
|
||||
title: 'Notes',
|
||||
modal: false,
|
||||
undecorated: true,
|
||||
minimumSize: [325, 200],
|
||||
iconImage: imageIcon('/16-em-pencil.png').image,
|
||||
iconImages: [imageIcon('/16-em-pencil.png').image]
|
||||
iconImages: [imageIcon('/16-em-pencil.png').image],
|
||||
location: bind(source: app.models.TimeStamperMain,
|
||||
sourceProperty: 'absoluteLocation',
|
||||
converter: { loc ->
|
||||
Point p = new Point(offsetFromMainFrame)
|
||||
p.translate((int) loc.x, (int) loc.y)
|
||||
return p})
|
||||
) {
|
||||
|
||||
panel(
|
||||
border:lineBorder(color: Color.BLACK, thickness:1, parent:true),
|
||||
mousePressed: controller.&mousePressed,
|
||||
mouseDragged: controller.&mouseDragged,
|
||||
mousePressed: mousePressed,
|
||||
mouseDragged: mouseDragged,
|
||||
layout: new MigLayout('insets 5 5 5 5, fill')
|
||||
) {
|
||||
scrollPane(constraints: 'growx, growy') {
|
||||
scrollPane(constraints: 'growx, growy, spany 2') {
|
||||
notesTextArea = textArea(lineWrap: true, columns: 20, rows: 5,
|
||||
wrapStyleWord: true)
|
||||
wrapStyleWord: true,
|
||||
text: bind(source: app.models.TimeStamperMain,
|
||||
sourceProperty: 'currentMarker',
|
||||
sourceValue: { app.models.TimeStamperMain.currentMarker?.notes}))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,12 @@
|
||||
package com.jdbernard.timestamper
|
||||
|
||||
punchcardDialog = dialog(
|
||||
/* title: 'Punchcard',
|
||||
modal: false,
|
||||
undecorated: true,
|
||||
iconImage: iconImage('/16-file-archive.png').image,
|
||||
iconImages: [iconImage('/16-file-archive.png').image],
|
||||
minimumSize: [325, 600]*/
|
||||
) {
|
||||
|
||||
}
|
@ -1,10 +1,88 @@
|
||||
package com.jdbernard.timestamper
|
||||
|
||||
import groovy.beans.Bindable
|
||||
import java.awt.Color
|
||||
import java.awt.Font
|
||||
import java.awt.Point
|
||||
import java.awt.Rectangle
|
||||
import java.awt.Toolkit
|
||||
import java.awt.event.KeyEvent
|
||||
import javax.swing.BoxLayout
|
||||
import javax.swing.Timer
|
||||
import com.jdbernard.timestamper.core.Timeline
|
||||
import net.miginfocom.swing.MigLayout
|
||||
|
||||
Point mousePressRelativeToFrame
|
||||
|
||||
/* ========== *
|
||||
* GUI Events *
|
||||
* ========== */
|
||||
|
||||
taskTextFieldChanged = { evt = null ->
|
||||
if (evt.keyCode == KeyEvent.VK_ENTER) {
|
||||
taskTextField.font = taskBoldFont
|
||||
controller.newTask(taskTextField.text)
|
||||
}
|
||||
|
||||
else if (evt.keyCode == KeyEvent.VK_ESCAPE) {
|
||||
taskTextField.font = taskBoldFont
|
||||
taskTextField.text = model.currentMarker.mark
|
||||
}
|
||||
|
||||
else if (!evt.isActionKey())
|
||||
taskTextField.font = taskThinFont
|
||||
}
|
||||
|
||||
showToolsMenu = { evt = null ->
|
||||
|
||||
}
|
||||
|
||||
showNotes = { evt = null ->
|
||||
notesDialog.visible = notesVisibleButton.selected
|
||||
}
|
||||
|
||||
showPunchcard = { evt = null ->
|
||||
|
||||
}
|
||||
|
||||
mousePressed = { evt = null ->
|
||||
mousePressRelativeToFrame = evt?.point
|
||||
}
|
||||
|
||||
mouseDragged = { evt = null ->
|
||||
GUIUtil.componentDragged(frame, evt, mousePressRelativeToFrame,
|
||||
new Rectangle(Toolkit.defaultToolkit.screenSize))
|
||||
}
|
||||
|
||||
/* ============== *
|
||||
* GUI Definition *
|
||||
* ============== */
|
||||
|
||||
updateTimer = new Timer(1000, action(name: 'GUI Refresh', closure: {
|
||||
Date currentTime = new Date()
|
||||
currentTimeLabel.text = Timeline.shortFormat.format(currentTime)
|
||||
if (model.currentMarker != null) {
|
||||
long seconds = currentTime.time - model.currentMarker.timestamp.time
|
||||
seconds /= 1000
|
||||
long minutes = seconds / 60
|
||||
seconds = seconds % 60
|
||||
long hours = minutes / 60
|
||||
minutes %= 60
|
||||
long days = hours / 24
|
||||
hours %= 24
|
||||
|
||||
StringBuilder sb = new StringBuilder()
|
||||
if (days > 0) sb.append(days + "day ")
|
||||
if (hours > 0) sb.append(hours + "hr ")
|
||||
if (minutes > 0) sb.append(minutes + "min ")
|
||||
sb.append(seconds + "sec")
|
||||
|
||||
totalTimeLabel.text = sb.toString()
|
||||
} else totalTimeLabel.text = ""
|
||||
}))
|
||||
|
||||
updateTimer.start()
|
||||
|
||||
frame = application(title:'TimeStamper',
|
||||
//size:[320,480],
|
||||
pack:true,
|
||||
@ -13,23 +91,29 @@ frame = application(title:'TimeStamper',
|
||||
locationByPlatform:true,
|
||||
iconImage: 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 }
|
||||
) {
|
||||
panel(
|
||||
border:lineBorder(color:Color.BLACK, thickness:1, parent:true),
|
||||
layout: new MigLayout('insets 0 5 0 0, fill','', '[]0[]0[]'),
|
||||
mousePressed: controller.&mousePressed,
|
||||
mouseDragged: controller.&mouseDragged
|
||||
mousePressed: mousePressed,
|
||||
mouseDragged: mouseDragged
|
||||
) {
|
||||
def mainFont = new Font(Font.SANS_SERIF, Font.BOLD, 12)
|
||||
def timeFont = new Font(Font.SANS_SERIF, Font.BOLD, 14)
|
||||
label("Current task started at ", font: mainFont)
|
||||
label("00:00:00", constraints: 'align leading',
|
||||
font: timeFont, foreground: [0, 102, 102])
|
||||
label(constraints: 'align leading', font: timeFont,
|
||||
foreground: [0, 102, 102],
|
||||
text: bind(source: model, sourceProperty: 'currentMarker',
|
||||
sourceValue: {
|
||||
model.currentMarker == null ? "00:00:00" :
|
||||
Timeline.shortFormat.format(model.currentMarker.timestamp)
|
||||
}))
|
||||
|
||||
panel(constraints: 'alignx trailing, aligny top, wrap') {
|
||||
boxLayout(axis: BoxLayout.X_AXIS)
|
||||
button(toolsMenuAction,
|
||||
button(actionPerformed: showToolsMenu,
|
||||
icon: imageIcon('/16-tool-a.png'),
|
||||
rolloverIcon: imageIcon('/16-tool-a-hover.png'),
|
||||
border: emptyBorder(0),
|
||||
@ -43,23 +127,35 @@ frame = application(title:'TimeStamper',
|
||||
hideActionText: true)
|
||||
}
|
||||
|
||||
textField("Task name", constraints: "growx, span 2, w 250::")
|
||||
taskTextField = textField("Task name",
|
||||
constraints: "growx, span 2, w 250::",
|
||||
keyReleased: taskTextFieldChanged,
|
||||
text: bind(source: model, sourceProperty: 'currentMarker',
|
||||
sourceValue: { model.currentMarker.mark }))
|
||||
|
||||
taskThinFont = taskTextField.font
|
||||
taskBoldFont = taskTextField.font.deriveFont(Font.BOLD)
|
||||
|
||||
panel(constraints: 'alignx leading, aligny top, gapright 5px, wrap') {
|
||||
boxLayout(axis: BoxLayout.X_AXIS)
|
||||
notesVisibleButton = toggleButton(showNotesAction, icon: imageIcon('/16-em-pencil.png'),
|
||||
notesVisibleButton = toggleButton(
|
||||
actionPerformed: showNotes,
|
||||
icon: imageIcon('/16-em-pencil.png'),
|
||||
hideActionText: true,
|
||||
border: emptyBorder(4))
|
||||
punchcardVisibleButton = toggleButton(showPunchcardAction,
|
||||
punchcardVisibleButton = toggleButton(
|
||||
actionPerformed: showPunchcard,
|
||||
icon: imageIcon('/16-file-archive.png'),
|
||||
hideActionText: true,
|
||||
border: emptyBorder(4))
|
||||
}
|
||||
|
||||
label("2hr 18min 56sec", constraints: 'alignx leading', font: timeFont,
|
||||
foreground: [0, 153, 0])
|
||||
totalTimeLabel = label("", constraints: 'alignx leading',
|
||||
font: timeFont, foreground: [0, 153, 0])
|
||||
|
||||
label("00:00:00", constraints: 'align trailing', font: timeFont,
|
||||
foreground: [204, 0, 0])
|
||||
currentTimeLabel = label("00:00:00", constraints: 'align trailing',
|
||||
font: timeFont, foreground: [204, 0, 0])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user