Removed Action portions. Added logging framework. GUI architecture changed (move to dependancy injection)

This commit is contained in:
Jonathan Bernard 2009-12-23 18:29:13 -06:00
parent 5b19542355
commit cee6de1147
15 changed files with 1534 additions and 53 deletions

View File

@ -1,3 +0,0 @@
package com.jdbernard.timestamper
def emptyAction = action(name: 'Empty Action')

View File

@ -1,8 +0,0 @@
package com.jdbernard.timestamper
import java.awt.event.KeyEvent
gracefulExitAction = action (
name: 'Graceful Exit',
closure: controller.&exitGracefully
)

View File

@ -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'
}
}

View File

@ -0,0 +1,5 @@
import org.apache.log4j.Logger
onNewInstance = { klass, type, instance ->
instance.metaClass.logger = Logger.getLogger(klass.name)
}

View File

@ -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
}
}

View File

@ -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()
}

View File

@ -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]])

View File

@ -4,4 +4,6 @@ import groovy.beans.Bindable
class NotesDialogModel {
// needs to be injected by buildMVCGroup call
def mainMVC
}

View File

@ -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
}

View File

@ -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
}

View 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

File diff suppressed because it is too large Load Diff

View File

@ -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}))
}
}
}

View File

@ -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),

View File

@ -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
}
}