Removed Action portions. Added logging framework. GUI architecture changed (move to dependancy injection)
This commit is contained in:
parent
5b19542355
commit
cee6de1147
@ -1,3 +0,0 @@
|
|||||||
package com.jdbernard.timestamper
|
|
||||||
|
|
||||||
def emptyAction = action(name: 'Empty Action')
|
|
@ -1,8 +0,0 @@
|
|||||||
package com.jdbernard.timestamper
|
|
||||||
|
|
||||||
import java.awt.event.KeyEvent
|
|
||||||
|
|
||||||
gracefulExitAction = action (
|
|
||||||
name: 'Graceful Exit',
|
|
||||||
closure: controller.&exitGracefully
|
|
||||||
)
|
|
@ -9,6 +9,13 @@ application {
|
|||||||
//frameClass = 'javax.swing.JFrame'
|
//frameClass = 'javax.swing.JFrame'
|
||||||
}
|
}
|
||||||
mvcGroups {
|
mvcGroups {
|
||||||
|
// MVC Group for "com.jdbernard.timestamper.TimeStamperMain"
|
||||||
|
'TimeStamperMain' {
|
||||||
|
model = 'com.jdbernard.timestamper.TimeStamperMainModel'
|
||||||
|
view = 'com.jdbernard.timestamper.TimeStamperMainView'
|
||||||
|
controller = 'com.jdbernard.timestamper.TimeStamperMainController'
|
||||||
|
}
|
||||||
|
|
||||||
// MVC Group for "com.jdbernard.timestamper.PunchcardDialog"
|
// MVC Group for "com.jdbernard.timestamper.PunchcardDialog"
|
||||||
'PunchcardDialog' {
|
'PunchcardDialog' {
|
||||||
model = 'com.jdbernard.timestamper.PunchcardDialogModel'
|
model = 'com.jdbernard.timestamper.PunchcardDialogModel'
|
||||||
@ -18,18 +25,9 @@ mvcGroups {
|
|||||||
|
|
||||||
// MVC Group for "com.jdbernard.timestamper.NotesDialog"
|
// MVC Group for "com.jdbernard.timestamper.NotesDialog"
|
||||||
'NotesDialog' {
|
'NotesDialog' {
|
||||||
actions = 'com.jdbernard.timestamper.NotesDialogActions'
|
|
||||||
model = 'com.jdbernard.timestamper.NotesDialogModel'
|
model = 'com.jdbernard.timestamper.NotesDialogModel'
|
||||||
view = 'com.jdbernard.timestamper.NotesDialogView'
|
view = 'com.jdbernard.timestamper.NotesDialogView'
|
||||||
controller = 'com.jdbernard.timestamper.NotesDialogController'
|
controller = 'com.jdbernard.timestamper.NotesDialogController'
|
||||||
}
|
}
|
||||||
|
|
||||||
// MVC Group for "com.jdbernard.timestamper.TimeStamperMain"
|
|
||||||
'TimeStamperMain' {
|
|
||||||
actions = 'com.jdbernard.timestamper.TimeStamperMainActions'
|
|
||||||
model = 'com.jdbernard.timestamper.TimeStamperMainModel'
|
|
||||||
view = 'com.jdbernard.timestamper.TimeStamperMainView'
|
|
||||||
controller = 'com.jdbernard.timestamper.TimeStamperMainController'
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
5
griffon-app/conf/Events.groovy
Normal file
5
griffon-app/conf/Events.groovy
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import org.apache.log4j.Logger
|
||||||
|
|
||||||
|
onNewInstance = { klass, type, instance ->
|
||||||
|
instance.metaClass.logger = Logger.getLogger(klass.name)
|
||||||
|
}
|
@ -1,11 +1,18 @@
|
|||||||
package com.jdbernard.timestamper
|
package com.jdbernard.timestamper
|
||||||
|
|
||||||
|
import java.awt.Point
|
||||||
|
|
||||||
class NotesDialogController {
|
class NotesDialogController {
|
||||||
// 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) {
|
||||||
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,10 +9,17 @@ class TimeStamperMainController {
|
|||||||
def view
|
def view
|
||||||
|
|
||||||
void mvcGroupInit(Map args) {
|
void mvcGroupInit(Map args) {
|
||||||
def notes = buildMVCGroup('NotesDialog')
|
|
||||||
def punchcard = buildMVCGroup('PunchcardDialog')
|
if (logger.isTraceEnabled())
|
||||||
view.notesDialog = notes.view.notesDialog
|
logger.trace("Initializeing TimeStamperMain MVC...")
|
||||||
view.punchcardDialog = punchcard.view.punchcardDialog
|
|
||||||
|
def thisMVC = ['model': model, 'view': view, 'controller': this]
|
||||||
|
|
||||||
|
model.notesDialogMVC = buildMVCGroup('NotesDialog', 'notesDialog',
|
||||||
|
'mainMVC': thisMVC)
|
||||||
|
|
||||||
|
model.punchcardDialogMVC = buildMVCGroup('PunchcardDialog',
|
||||||
|
'punchcardDialog', 'mainMVC': thisMVC)
|
||||||
|
|
||||||
// load application properties
|
// load application properties
|
||||||
Properties prop = new Properties()
|
Properties prop = new Properties()
|
||||||
@ -21,7 +28,9 @@ class TimeStamperMainController {
|
|||||||
if (!model.configFile.exists()) model.configFile.createNewFile()
|
if (!model.configFile.exists()) model.configFile.createNewFile()
|
||||||
|
|
||||||
try { model.configFile.withInputStream { prop.load(it) } }
|
try { model.configFile.withInputStream { prop.load(it) } }
|
||||||
catch (IOException ioe) { /* TODO */ }
|
catch (IOException ioe) {
|
||||||
|
logger.error('Unable to load configuration', ioe)
|
||||||
|
}
|
||||||
|
|
||||||
model.config = prop
|
model.config = prop
|
||||||
|
|
||||||
@ -42,16 +51,27 @@ class TimeStamperMainController {
|
|||||||
// 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 exitGracefully = { evt = null ->
|
def exitGracefully = { evt = null ->
|
||||||
|
|
||||||
|
if (logger.isTraceEnabled()) logger.trace("Exiting gracefully.")
|
||||||
|
|
||||||
// save config
|
// save config
|
||||||
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) {
|
||||||
|
logger.error("Unable to save the configuration file", ioe)
|
||||||
|
}
|
||||||
|
|
||||||
// save timeline and properties
|
// save timeline and properties
|
||||||
model.timelineProperties.save()
|
model.timelineProperties.save()
|
||||||
|
|
||||||
|
if (logger.isTraceEnabled()) logger.trace("Completed graceful shutdown.")
|
||||||
|
|
||||||
app.shutdown()
|
app.shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,4 +21,4 @@ import groovy.swing.SwingBuilder
|
|||||||
import griffon.util.GriffonPlatformHelper
|
import griffon.util.GriffonPlatformHelper
|
||||||
|
|
||||||
GriffonPlatformHelper.tweakForNativePlatform(app)
|
GriffonPlatformHelper.tweakForNativePlatform(app)
|
||||||
SwingBuilder.lookAndFeel('mac', 'nimbus', 'gtk', ['metal', [boldFonts: false]])
|
SwingBuilder.lookAndFeel('mac', 'nimbus', 'gtk', ['metal', [boldFonts: false]])
|
||||||
|
@ -4,4 +4,6 @@ import groovy.beans.Bindable
|
|||||||
|
|
||||||
class NotesDialogModel {
|
class NotesDialogModel {
|
||||||
|
|
||||||
|
// needs to be injected by buildMVCGroup call
|
||||||
|
def mainMVC
|
||||||
}
|
}
|
||||||
|
@ -3,5 +3,7 @@ package com.jdbernard.timestamper
|
|||||||
import groovy.beans.Bindable
|
import groovy.beans.Bindable
|
||||||
|
|
||||||
class PunchcardDialogModel {
|
class PunchcardDialogModel {
|
||||||
// @Bindable String propName
|
|
||||||
}
|
// needs to be injected by buildMVCGroup() call
|
||||||
|
def mainMVC
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@ package com.jdbernard.timestamper
|
|||||||
|
|
||||||
import groovy.beans.Bindable
|
import groovy.beans.Bindable
|
||||||
import java.awt.Point
|
import java.awt.Point
|
||||||
|
import java.awt.Rectangle
|
||||||
import java.util.Properties
|
import java.util.Properties
|
||||||
import com.jdbernard.timestamper.core.Timeline
|
import com.jdbernard.timestamper.core.Timeline
|
||||||
import com.jdbernard.timestamper.core.TimelineMarker
|
import com.jdbernard.timestamper.core.TimelineMarker
|
||||||
@ -11,8 +12,12 @@ class TimeStamperMainModel {
|
|||||||
@Bindable TimelineMarker currentMarker
|
@Bindable TimelineMarker currentMarker
|
||||||
@Bindable Timeline timeline
|
@Bindable Timeline timeline
|
||||||
@Bindable TimelineProperties timelineProperties
|
@Bindable TimelineProperties timelineProperties
|
||||||
@Bindable Properties config
|
Properties config
|
||||||
File configFile
|
File configFile
|
||||||
|
|
||||||
|
def notesDialogMVC
|
||||||
|
def punchcardDialogMVC
|
||||||
|
|
||||||
@Bindable Point absoluteLocation
|
@Bindable Point absoluteLocation
|
||||||
|
@Bindable Rectangle frameSize
|
||||||
}
|
}
|
||||||
|
13
griffon-app/resources/log4j.properties
Normal file
13
griffon-app/resources/log4j.properties
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
log4j.rootLogger=ERROR, stdout
|
||||||
|
log4j.logger.com.jdbernard.timestamper=TRACE
|
||||||
|
|
||||||
|
# set up stdout
|
||||||
|
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||||
|
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||||
|
log4j.appender.stdout.layout.ConversionPattern=[%t] %-5p - %m%n
|
||||||
|
|
||||||
|
# set up fileout
|
||||||
|
log4j.appender.fileout=org.apache.log4j.FileAppender
|
||||||
|
log4j.appender.fileout.File=TimeStamper.log
|
||||||
|
log4j.appender.fileout.layout=org.apache.log4j.PatternLayout
|
||||||
|
log4j.appender.fileout.layout.ConversionPattern=%5p [%t] - %m%n
|
1399
griffon-app/session.vim
Normal file
1399
griffon-app/session.vim
Normal file
File diff suppressed because it is too large
Load Diff
@ -8,49 +8,52 @@ import javax.swing.BoxLayout
|
|||||||
import net.miginfocom.swing.MigLayout
|
import net.miginfocom.swing.MigLayout
|
||||||
|
|
||||||
Point mousePressRelativeToDialog
|
Point mousePressRelativeToDialog
|
||||||
Point offsetFromMainFrame
|
Point offsetFromMainFrame = new Point(0,0)
|
||||||
|
boolean coupledToMainFrame = false
|
||||||
|
|
||||||
mousePressed = { evt -> mousePressRelativeToDialog = evt?.point }
|
mousePressed = { evt -> mousePressRelativeToDialog = evt?.point }
|
||||||
|
|
||||||
mouseDragged = { evt ->
|
mouseDragged = { evt ->
|
||||||
GUIUtil.componentDragged(view.notesDialog, evt,
|
GUIUtil.componentDragged(dialog, evt, mousePressRelativeToDialog,
|
||||||
mousePressRelativeToDialog,
|
|
||||||
new Rectangle(Toolkit.defaultToolkit.screenSize),
|
new Rectangle(Toolkit.defaultToolkit.screenSize),
|
||||||
app.views.TimeStamperMain.frame.bounds)
|
model.mainMVC.view.frame.bounds)
|
||||||
|
|
||||||
Point p = app.views.TimeStamperMain.frame.location
|
offsetFromMainFrame = GUIUtil.calculateOffset(
|
||||||
offsetFromMainFrame = new Point(notesDialog.location)
|
model.mainMVC.view.frame, dialog)
|
||||||
offsetFromMainFrame.translate((int) -p.x, (int) -p.y)
|
|
||||||
|
coupledToMainFrame = GUIUtil.componentsCoupled(dialog,
|
||||||
|
model.mainMVC.view.frame);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
notesDialog = dialog(
|
dialog = dialog(
|
||||||
title: 'Notes',
|
title: 'Notes',
|
||||||
modal: false,
|
modal: false,
|
||||||
undecorated: true,
|
undecorated: true,
|
||||||
minimumSize: [325, 200],
|
minimumSize: [325, 200],
|
||||||
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: app.models.TimeStamperMain,
|
location: bind(source: model.mainMVC.model,
|
||||||
sourceProperty: 'absoluteLocation',
|
sourceProperty: 'absoluteLocation',
|
||||||
converter: { loc ->
|
converter: { loc ->
|
||||||
Point p = new Point(offsetFromMainFrame)
|
if (coupledToMainFrame) {
|
||||||
p.translate((int) loc.x, (int) loc.y)
|
Point p = new Point(offsetFromMainFrame)
|
||||||
return p})
|
p.translate((int) loc.x, (int) loc.y)
|
||||||
|
return p
|
||||||
|
} else return dialog.location })
|
||||||
) {
|
) {
|
||||||
|
|
||||||
panel(
|
panel(
|
||||||
border:lineBorder(color: Color.BLACK, thickness:1, parent:true),
|
border:lineBorder(color: Color.BLACK, thickness:1, parent:true),
|
||||||
mousePressed: mousePressed,
|
mousePressed: mousePressed,
|
||||||
mouseDragged: mouseDragged,
|
mouseDragged: mouseDragged,
|
||||||
layout: new MigLayout('insets 5 5 5 5, fill')
|
layout: new MigLayout('insets 5 5 5 5, fill')
|
||||||
) {
|
) {
|
||||||
scrollPane(constraints: 'growx, growy, spany 2') {
|
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: app.models.TimeStamperMain,
|
text: bind(source: model.mainMVC.model,
|
||||||
sourceProperty: 'currentMarker',
|
sourceProperty: 'currentMarker',
|
||||||
sourceValue: { app.models.TimeStamperMain.currentMarker?.notes}))
|
sourceValue: { model.mainMVC.model.currentMarker?.notes}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.jdbernard.timestamper
|
package com.jdbernard.timestamper
|
||||||
|
|
||||||
import groovy.beans.Bindable
|
|
||||||
import java.awt.Color
|
import java.awt.Color
|
||||||
import java.awt.Font
|
import java.awt.Font
|
||||||
import java.awt.Point
|
import java.awt.Point
|
||||||
@ -12,8 +11,6 @@ import javax.swing.Timer
|
|||||||
import com.jdbernard.timestamper.core.Timeline
|
import com.jdbernard.timestamper.core.Timeline
|
||||||
import net.miginfocom.swing.MigLayout
|
import net.miginfocom.swing.MigLayout
|
||||||
|
|
||||||
Point mousePressRelativeToFrame
|
|
||||||
|
|
||||||
/* ========== *
|
/* ========== *
|
||||||
* GUI Events *
|
* GUI Events *
|
||||||
* ========== */
|
* ========== */
|
||||||
@ -38,7 +35,7 @@ showToolsMenu = { evt = null ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
showNotes = { evt = null ->
|
showNotes = { evt = null ->
|
||||||
notesDialog.visible = notesVisibleButton.selected
|
model.notesDialogMVC.view.dialog.visible = notesVisibleButton.selected
|
||||||
}
|
}
|
||||||
|
|
||||||
showPunchcard = { evt = null ->
|
showPunchcard = { evt = null ->
|
||||||
@ -119,7 +116,7 @@ frame = application(title:'TimeStamper',
|
|||||||
border: emptyBorder(0),
|
border: emptyBorder(0),
|
||||||
contentAreaFilled: false,
|
contentAreaFilled: false,
|
||||||
hideActionText: true)
|
hideActionText: true)
|
||||||
button(gracefulExitAction,
|
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),
|
||||||
|
@ -83,9 +83,50 @@ public class GUIUtil {
|
|||||||
return finalWindowPoint;
|
return finalWindowPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
def static componentDragged(frame, MouseEvent evt,
|
static void componentDragged(frame, MouseEvent evt,
|
||||||
Point mousePressRelativeToFrame, Rectangle... snapBoxes) {
|
Point mousePressRelativeToFrame, Rectangle... snapBoxes) {
|
||||||
frame.location = calculateWindowMovement(evt.getLocationOnScreen(),
|
frame.location = calculateWindowMovement(evt.getLocationOnScreen(),
|
||||||
mousePressRelativeToFrame, frame.bounds, snapBoxes)
|
mousePressRelativeToFrame, frame.bounds, snapBoxes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean componentsCoupled(c1, c2) {
|
||||||
|
def h1 = c1.bounds.height
|
||||||
|
def w1 = c1.bounds.width
|
||||||
|
def h2 = c2.bounds.height
|
||||||
|
def w2 = c2.bounds.width
|
||||||
|
|
||||||
|
return (
|
||||||
|
( // horizontal
|
||||||
|
( // snapped horizontally
|
||||||
|
((c1.x - c2.x).abs() < 20) || // c1 left edge to c2 left edge
|
||||||
|
((c1.x + w1 - c2.x - w2).abs() < 20) || // c1 right edge to c2 right edge
|
||||||
|
((c1.x + w1 - c2.x).abs() < 20) || // c1 right edge to c2 left edge
|
||||||
|
((c2.x + w2 - c1.x).abs() < 20) // c1 left edge to c2 right edge
|
||||||
|
) && (// touching vertically
|
||||||
|
(c1.y <= c2.y && c1.y + h1 >= c2.y) ||
|
||||||
|
(c1.y <= c2.y + h2 && c1.y + h1 >= c2.y + h2) ||
|
||||||
|
(c1.y > c2.y && c1.y + h1 < c2.y + h2)
|
||||||
|
)
|
||||||
|
) || ( // vertical
|
||||||
|
( // snapped vertically
|
||||||
|
((c1.y - c2.y).abs() < 20) || // c1 top to c2 top
|
||||||
|
((c1.y + h1 - c2.y - h2).abs() < 20) || // c1 bot to c2 bot
|
||||||
|
((c1.y + h1 - c2.y).abs() < 20) || // c1 bot to c2 top
|
||||||
|
((c2.y + h2 - c1.y).abs() < 20) // c1 top to c2 bot
|
||||||
|
) && (// touching horizontally
|
||||||
|
(c1.x <= c2.x && c1.x + w1 >= c2.x) ||
|
||||||
|
(c1.x <= c2.x + w2 && c1.x + w1 >= c2.x + w2) ||
|
||||||
|
(c1.x > c2.x && c1.x + w1 < c2.x + w2)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static Point calculateOffset(c1, c2) {
|
||||||
|
Point p = c1.location
|
||||||
|
Rectangle r = c1.bounds
|
||||||
|
Point offset = new Point(c2.location)
|
||||||
|
offset.translate((int) -p.x, (int) -p.y)
|
||||||
|
return offset
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user