206 lines
7.4 KiB
Groovy
206 lines
7.4 KiB
Groovy
package com.jdblabs.timestamper.gui
|
|
|
|
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.JDialog
|
|
import javax.swing.JFileChooser
|
|
import javax.swing.SwingConstants
|
|
import javax.swing.Timer
|
|
import com.jdblabs.timestamper.core.Timeline
|
|
import net.miginfocom.swing.MigLayout
|
|
|
|
/* ========== *
|
|
* 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
|
|
}
|
|
|
|
showNotes = { evt = null ->
|
|
model.notesDialogMVC.view.dialog.visible = notesVisibleButton.selected
|
|
}
|
|
|
|
showPunchcard = { evt = null ->
|
|
model.punchcardDialogMVC.view.dialog.visible = punchcardVisibleButton.selected
|
|
}
|
|
|
|
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()
|
|
|
|
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) })
|
|
checkBoxMenuItem(text: 'Save on update?',
|
|
selected: bind(source: model, sourceProperty: 'timelineProperties',
|
|
sourceValue: { model.timelineProperties?.persistOnUpdate }),
|
|
actionPerformed: {
|
|
model.timelineProperties.persistOnUpdate = it.source.selected })
|
|
aboutMenuItem = checkBoxMenuItem(text: 'About...',
|
|
actionPerformed: { aboutDialog.visible = aboutMenuItem.selected })
|
|
}
|
|
|
|
fileDialog = fileChooser();
|
|
|
|
frame = application(title:'TimeStamper',
|
|
location:[50,50],
|
|
locationByPlatform:true,
|
|
minimumSize: [325, 0],
|
|
pack:true,
|
|
undecorated:true,
|
|
iconImage: imageIcon('/appointment-new-32x32.png').image,
|
|
iconImages: [imageIcon('/appointment-new-32x32.png').image,
|
|
imageIcon('/appointment-new-16x16.png').image],
|
|
componentMoved: { evt -> model.absoluteLocation = frame.location }
|
|
) {
|
|
logger.trace('Building TimeStamperMain GUI')
|
|
panel(
|
|
border:lineBorder(color:Color.BLACK, thickness:1, parent:true),
|
|
layout: new MigLayout('insets 0 5 0 0, fill','', '[]0[]0[]'),
|
|
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(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(mouseClicked: { evt ->
|
|
optionsMenu.show(evt.component, evt.x, evt.y) },
|
|
icon: imageIcon('/16-tool-a.png'),
|
|
rolloverIcon: imageIcon('/16-tool-a-hover.png'),
|
|
border: emptyBorder(0),
|
|
contentAreaFilled: false,
|
|
hideActionText: true,
|
|
toolTipText: 'Options Menu')
|
|
button(actionPerformed: controller.&exitGracefully,
|
|
icon: imageIcon('/16-em-cross.png'),
|
|
rolloverIcon: imageIcon('/16-em-cross-hover.png'),
|
|
border: emptyBorder(0),
|
|
contentAreaFilled: false,
|
|
hideActionText: true,
|
|
toolTipText: 'Close Application')
|
|
}
|
|
|
|
taskTextField = textField("Task name",
|
|
constraints: "growx, span 2, w 250::",
|
|
keyReleased: taskTextFieldChanged,
|
|
toolTipText: 'The current task',
|
|
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(
|
|
actionPerformed: showNotes,
|
|
icon: imageIcon('/16-em-pencil.png'),
|
|
hideActionText: true,
|
|
border: emptyBorder(4),
|
|
toolTipText: 'Show/hide task notes.')
|
|
punchcardVisibleButton = toggleButton(
|
|
actionPerformed: showPunchcard,
|
|
icon: imageIcon('/16-file-archive.png'),
|
|
hideActionText: true,
|
|
border: emptyBorder(4),
|
|
toolTipText: 'Show/hide the timeline display.')
|
|
}
|
|
|
|
totalTimeLabel = label("", constraints: 'alignx leading',
|
|
font: timeFont, foreground: [0, 153, 0])
|
|
|
|
currentTimeLabel = label("00:00:00", constraints: 'align trailing',
|
|
font: timeFont, foreground: [204, 0, 0])
|
|
}
|
|
}
|
|
|
|
aboutDialog = dialog(new JDialog(frame),
|
|
visible: false,
|
|
locationRelativeTo: null,
|
|
pack: true,
|
|
undecorated: true,
|
|
title: "About TimeStamper v" + app.metadata.'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.metadata.'app.version'
|
|
+ " by Jonathan Bernard", constraints: 'growx, wrap',
|
|
horizontalAlignment: SwingConstants.CENTER)
|
|
textField(text: 'http://www.jdb-labs.com/timestamper',
|
|
constraints: 'growx', foreground: [0,0,200], editable: false,
|
|
horizontalAlignment: SwingConstants.CENTER)
|
|
}
|
|
}
|