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'
|
||||
}
|
||||
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"
|
||||
'PunchcardDialog' {
|
||||
model = 'com.jdbernard.timestamper.PunchcardDialogModel'
|
||||
@ -18,18 +25,9 @@ mvcGroups {
|
||||
|
||||
// MVC Group for "com.jdbernard.timestamper.NotesDialog"
|
||||
'NotesDialog' {
|
||||
actions = 'com.jdbernard.timestamper.NotesDialogActions'
|
||||
model = 'com.jdbernard.timestamper.NotesDialogModel'
|
||||
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'
|
||||
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
|
||||
|
||||
import java.awt.Point
|
||||
|
||||
class NotesDialogController {
|
||||
// these will be injected by Griffon
|
||||
def model
|
||||
def view
|
||||
|
||||
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
|
||||
|
||||
void mvcGroupInit(Map args) {
|
||||
def notes = buildMVCGroup('NotesDialog')
|
||||
def punchcard = buildMVCGroup('PunchcardDialog')
|
||||
view.notesDialog = notes.view.notesDialog
|
||||
view.punchcardDialog = punchcard.view.punchcardDialog
|
||||
|
||||
if (logger.isTraceEnabled())
|
||||
logger.trace("Initializeing TimeStamperMain MVC...")
|
||||
|
||||
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
|
||||
Properties prop = new Properties()
|
||||
@ -21,7 +28,9 @@ class TimeStamperMainController {
|
||||
if (!model.configFile.exists()) model.configFile.createNewFile()
|
||||
|
||||
try { model.configFile.withInputStream { prop.load(it) } }
|
||||
catch (IOException ioe) { /* TODO */ }
|
||||
catch (IOException ioe) {
|
||||
logger.error('Unable to load configuration', ioe)
|
||||
}
|
||||
|
||||
model.config = prop
|
||||
|
||||
@ -42,16 +51,27 @@ class TimeStamperMainController {
|
||||
// load the last marker
|
||||
model.currentMarker = model.timeline.getLastMarker(new Date())
|
||||
|
||||
if (logger.isTraceEnabled())
|
||||
logger.trace("TimeStamperMain MVC initialization complete.")
|
||||
|
||||
}
|
||||
|
||||
def exitGracefully = { evt = null ->
|
||||
|
||||
if (logger.isTraceEnabled()) logger.trace("Exiting gracefully.")
|
||||
|
||||
// save config
|
||||
try { model.configFile.withOutputStream { out ->
|
||||
model.config.store(out, null) } }
|
||||
catch (IOException ioe) {}
|
||||
catch (IOException ioe) {
|
||||
logger.error("Unable to save the configuration file", ioe)
|
||||
}
|
||||
|
||||
// save timeline and properties
|
||||
model.timelineProperties.save()
|
||||
|
||||
if (logger.isTraceEnabled()) logger.trace("Completed graceful shutdown.")
|
||||
|
||||
app.shutdown()
|
||||
}
|
||||
|
||||
|
@ -21,4 +21,4 @@ import groovy.swing.SwingBuilder
|
||||
import griffon.util.GriffonPlatformHelper
|
||||
|
||||
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 {
|
||||
|
||||
// needs to be injected by buildMVCGroup call
|
||||
def mainMVC
|
||||
}
|
||||
|
@ -3,5 +3,7 @@ package com.jdbernard.timestamper
|
||||
import groovy.beans.Bindable
|
||||
|
||||
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 java.awt.Point
|
||||
import java.awt.Rectangle
|
||||
import java.util.Properties
|
||||
import com.jdbernard.timestamper.core.Timeline
|
||||
import com.jdbernard.timestamper.core.TimelineMarker
|
||||
@ -11,8 +12,12 @@ class TimeStamperMainModel {
|
||||
@Bindable TimelineMarker currentMarker
|
||||
@Bindable Timeline timeline
|
||||
@Bindable TimelineProperties timelineProperties
|
||||
@Bindable Properties config
|
||||
Properties config
|
||||
File configFile
|
||||
|
||||
def notesDialogMVC
|
||||
def punchcardDialogMVC
|
||||
|
||||
@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
|
||||
|
||||
Point mousePressRelativeToDialog
|
||||
Point offsetFromMainFrame
|
||||
Point offsetFromMainFrame = new Point(0,0)
|
||||
boolean coupledToMainFrame = false
|
||||
|
||||
mousePressed = { evt -> mousePressRelativeToDialog = evt?.point }
|
||||
|
||||
mouseDragged = { evt ->
|
||||
GUIUtil.componentDragged(view.notesDialog, evt,
|
||||
mousePressRelativeToDialog,
|
||||
GUIUtil.componentDragged(dialog, evt, mousePressRelativeToDialog,
|
||||
new Rectangle(Toolkit.defaultToolkit.screenSize),
|
||||
app.views.TimeStamperMain.frame.bounds)
|
||||
model.mainMVC.view.frame.bounds)
|
||||
|
||||
Point p = app.views.TimeStamperMain.frame.location
|
||||
offsetFromMainFrame = new Point(notesDialog.location)
|
||||
offsetFromMainFrame.translate((int) -p.x, (int) -p.y)
|
||||
offsetFromMainFrame = GUIUtil.calculateOffset(
|
||||
model.mainMVC.view.frame, dialog)
|
||||
|
||||
coupledToMainFrame = GUIUtil.componentsCoupled(dialog,
|
||||
model.mainMVC.view.frame);
|
||||
|
||||
}
|
||||
|
||||
notesDialog = dialog(
|
||||
dialog = dialog(
|
||||
title: 'Notes',
|
||||
modal: false,
|
||||
undecorated: true,
|
||||
minimumSize: [325, 200],
|
||||
iconImage: 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',
|
||||
converter: { loc ->
|
||||
Point p = new Point(offsetFromMainFrame)
|
||||
p.translate((int) loc.x, (int) loc.y)
|
||||
return p})
|
||||
if (coupledToMainFrame) {
|
||||
Point p = new Point(offsetFromMainFrame)
|
||||
p.translate((int) loc.x, (int) loc.y)
|
||||
return p
|
||||
} else return dialog.location })
|
||||
) {
|
||||
|
||||
panel(
|
||||
border:lineBorder(color: Color.BLACK, thickness:1, parent:true),
|
||||
mousePressed: mousePressed,
|
||||
mouseDragged: mouseDragged,
|
||||
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,
|
||||
wrapStyleWord: true,
|
||||
text: bind(source: app.models.TimeStamperMain,
|
||||
text: bind(source: model.mainMVC.model,
|
||||
sourceProperty: 'currentMarker',
|
||||
sourceValue: { app.models.TimeStamperMain.currentMarker?.notes}))
|
||||
sourceValue: { model.mainMVC.model.currentMarker?.notes}))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.jdbernard.timestamper
|
||||
|
||||
import groovy.beans.Bindable
|
||||
import java.awt.Color
|
||||
import java.awt.Font
|
||||
import java.awt.Point
|
||||
@ -12,8 +11,6 @@ import javax.swing.Timer
|
||||
import com.jdbernard.timestamper.core.Timeline
|
||||
import net.miginfocom.swing.MigLayout
|
||||
|
||||
Point mousePressRelativeToFrame
|
||||
|
||||
/* ========== *
|
||||
* GUI Events *
|
||||
* ========== */
|
||||
@ -38,7 +35,7 @@ showToolsMenu = { evt = null ->
|
||||
}
|
||||
|
||||
showNotes = { evt = null ->
|
||||
notesDialog.visible = notesVisibleButton.selected
|
||||
model.notesDialogMVC.view.dialog.visible = notesVisibleButton.selected
|
||||
}
|
||||
|
||||
showPunchcard = { evt = null ->
|
||||
@ -119,7 +116,7 @@ frame = application(title:'TimeStamper',
|
||||
border: emptyBorder(0),
|
||||
contentAreaFilled: false,
|
||||
hideActionText: true)
|
||||
button(gracefulExitAction,
|
||||
button(actionPerformed: controller.&exitGracefully,
|
||||
icon: imageIcon('/16-em-cross.png'),
|
||||
rolloverIcon: imageIcon('/16-em-cross-hover.png'),
|
||||
border: emptyBorder(0),
|
||||
|
@ -83,9 +83,50 @@ public class GUIUtil {
|
||||
return finalWindowPoint;
|
||||
}
|
||||
|
||||
def static componentDragged(frame, MouseEvent evt,
|
||||
static void componentDragged(frame, MouseEvent evt,
|
||||
Point mousePressRelativeToFrame, Rectangle... snapBoxes) {
|
||||
frame.location = calculateWindowMovement(evt.getLocationOnScreen(),
|
||||
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