diff --git a/.gitignore b/.gitignore index 6aebbbf..a8961fd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,9 @@ -.gradle/ -*.sw? build/ +dist/ +.gradle/ +staging/ +temp/ +release .sass-cache *.build.tar.gz +*.sw? diff --git a/gui/.classpath b/gui/.classpath new file mode 100644 index 0000000..d1b51d8 --- /dev/null +++ b/gui/.classpath @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gui/.hgignore b/gui/.hgignore new file mode 100755 index 0000000..390fc33 --- /dev/null +++ b/gui/.hgignore @@ -0,0 +1,4 @@ +.*.swp +.*.swo +staging +dist diff --git a/gui/.project b/gui/.project new file mode 100644 index 0000000..cdd8d0a --- /dev/null +++ b/gui/.project @@ -0,0 +1,18 @@ + + + TimeStamper + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.groovy.core.groovyNature + org.eclipse.jdt.core.javanature + + diff --git a/gui/CHANGE ME b/gui/CHANGE ME new file mode 100644 index 0000000..325d8bd Binary files /dev/null and b/gui/CHANGE ME differ diff --git a/gui/TimeStamper.iml b/gui/TimeStamper.iml new file mode 100644 index 0000000..fcef4e2 --- /dev/null +++ b/gui/TimeStamper.iml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gui/TimeStamper.ipr b/gui/TimeStamper.ipr new file mode 100644 index 0000000..a93361e --- /dev/null +++ b/gui/TimeStamper.ipr @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gui/TimeStamper.iws b/gui/TimeStamper.iws new file mode 100644 index 0000000..06c4249 --- /dev/null +++ b/gui/TimeStamper.iws @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gui/TimeStamper.launch b/gui/TimeStamper.launch new file mode 100644 index 0000000..54fc5b4 --- /dev/null +++ b/gui/TimeStamper.launch @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/gui/TimeStamper.tmproj b/gui/TimeStamper.tmproj new file mode 100644 index 0000000..75c2fd9 --- /dev/null +++ b/gui/TimeStamper.tmproj @@ -0,0 +1,73 @@ + + + + + documents + + + filename + TimeStamper.launch + + + filename + build.xml + + + name + griffon-app + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + griffon-app + + + name + test + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + test + + + name + lib + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + lib + + + name + scripts + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + scripts + + + name + src + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + src + + + name + web-app + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + web-app + + + fileHierarchyDrawerWidth + 200 + metaData + + showFileHierarchyDrawer + + windowFrame + {{237, 127}, {742, 553}} + + diff --git a/gui/application.properties b/gui/application.properties new file mode 100755 index 0000000..aaefc60 --- /dev/null +++ b/gui/application.properties @@ -0,0 +1,10 @@ +#Do not edit app.griffon.* properties, they may change automatically. DO NOT put application configuration in here, it is not the right place! +#Thu, 25 Apr 2013 06:40:33 -0500 +#Thu Apr 01 22:28:40 CDT 2010 +app.version=2.1 +app.griffon.version=1.2.0 +app.name=TimeStamper + +plugins.swing=1.2.0 +archetype.default=1.2.0 +app.toolkit=swing diff --git a/gui/build.xml b/gui/build.xml new file mode 100755 index 0000000..73ee5a7 --- /dev/null +++ b/gui/build.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gui/doc/feed.pdf b/gui/doc/feed.pdf new file mode 100755 index 0000000..307ff47 Binary files /dev/null and b/gui/doc/feed.pdf differ diff --git a/gui/doc/feed.rst b/gui/doc/feed.rst new file mode 100755 index 0000000..dd55374 --- /dev/null +++ b/gui/doc/feed.rst @@ -0,0 +1,77 @@ +Centralized vs. decentralized +----------------------------- + +Centralized +``````````` + +- one central list +- remote apps that sync with central? + +Decentralized +````````````` + +- sync to URL(s)? + + - need a network protocol + - HTTP? + - SSL? + +- group-wise sync? + + - establish master/slaves? + - easier than coordinated group-update::: + + map each URL to synch -> the last time updated. + if (update_period): + forall URLs: synch + else if (incoming_update): + forall (URLs older than incoming update): synch + +- synch based on hash of updates? + + - need canonicalizer for text. Use XML? + - hash algorithm::: + + SHA-1 of: + concatenate: + date (YYYYMMDDhhmmssSSS) + name + notes + +External Feeds +-------------- + +Item format +``````````` + + - time started + - name/description + - notes + - category? + +Pull from +````````` + + - needs to be optional + - standardized input format + + - easy to parse + - no errors, false positives + - restrictive. + + - flexible input format + + - matches regex's? + - map groups to fields + +Push to +``````` + + - optional + - standardized output + + - cannot be flexible to match output medium + + - flexible input format + + - choose fields and format values diff --git a/gui/doc/sample-txt-timeline-with-sync-info.txt b/gui/doc/sample-txt-timeline-with-sync-info.txt new file mode 100755 index 0000000..dd31de1 --- /dev/null +++ b/gui/doc/sample-txt-timeline-with-sync-info.txt @@ -0,0 +1,8 @@ +# sync-options: +# LOCAL TIMELINE: this file +# SYNC TO: ssh://jdbernard@jdbernard.no-ip.org/timelines/jdbernard.timeline.txt +# SYNC TO: http://www.twitter.com/jdbernard +# pull only +# update every 30 sec +# SYNC TO: file:///home/jdbernard/timelines/jdbernard.timeline.bak +# push only diff --git a/gui/doc/uml.tsm b/gui/doc/uml.tsm new file mode 100644 index 0000000..a725ebd Binary files /dev/null and b/gui/doc/uml.tsm differ diff --git a/gui/griffon-app/conf/Application.groovy b/gui/griffon-app/conf/Application.groovy new file mode 100755 index 0000000..77f1a7a --- /dev/null +++ b/gui/griffon-app/conf/Application.groovy @@ -0,0 +1,27 @@ +application { + title="TimeStamper" + startupGroups=["TimeStamperMain"] + autoShutdown=true +} +mvcGroups { + LogDialog { + model="com.jdblabs.timestamper.gui.LogDialogModel" + controller="com.jdblabs.timestamper.gui.LogDialogController" + view="com.jdblabs.timestamper.gui.LogDialogView" + } + TimeStamperMain { + model="com.jdblabs.timestamper.gui.TimeStamperMainModel" + view="com.jdblabs.timestamper.gui.TimeStamperMainView" + controller="com.jdblabs.timestamper.gui.TimeStamperMainController" + } + PunchcardDialog { + model="com.jdblabs.timestamper.gui.PunchcardDialogModel" + view="com.jdblabs.timestamper.gui.PunchcardDialogView" + controller="com.jdblabs.timestamper.gui.PunchcardDialogController" + } + NotesDialog { + model="com.jdblabs.timestamper.gui.NotesDialogModel" + view="com.jdblabs.timestamper.gui.NotesDialogView" + controller="com.jdblabs.timestamper.gui.NotesDialogController" + } +} diff --git a/gui/griffon-app/conf/BuildConfig.groovy b/gui/griffon-app/conf/BuildConfig.groovy new file mode 100644 index 0000000..0921a82 --- /dev/null +++ b/gui/griffon-app/conf/BuildConfig.groovy @@ -0,0 +1,191 @@ +// key signing information +environments { + development { + signingkey { + params { + // sigfile = 'GRIFFON' + // keystore = "${basedir}/griffon-app/conf/keys/devKeystore" + // alias = 'development' + storepass = 'BadStorePassword' + keypass = 'BadKeyPassword' + lazy = true // only sign when unsigned + } + } + } + test { + griffon { + jars { + sign = false + pack = false + } + } + } + production { + signingkey { + params { + // NOTE: for production keys it is more secure to rely on key prompting + // no value means we will prompt //storepass = 'BadStorePassword' + // no value means we will prompt //keypass = 'BadKeyPassword' + lazy = false // sign, regardless of existing signatures + } + } + + griffon { + jars { + sign = true + pack = true + destDir = "${basedir}/staging" + } + webstart { + codebase = 'CHANGE ME' + } + } + } +} + +griffon { + memory { + //max = '64m' + //min = '2m' + //minPermSize = '2m' + //maxPermSize = '64m' + } + jars { + sign = false + pack = false + destDir = "${basedir}/staging" + jarName = "${appName}.jar" + } + extensions { + jarUrls = [] + jnlpUrls = [] + /* + props { + someProperty = 'someValue' + } + resources { + linux { // windows, macosx, solaris + jars = [] + nativelibs = [] + props { + someProperty = 'someValue' + } + } + } + */ + } + webstart { + codebase = "${new File(griffon.jars.destDir).toURI().toASCIIString()}" + jnlp = 'application.jnlp' + } + applet { + jnlp = 'applet.jnlp' + html = 'applet.html' + } +} + +// required for custom environments +signingkey { + params { + def env = griffon.util.Environment.current.name + sigfile = 'GRIFFON-' + env + keystore = "${basedir}/griffon-app/conf/keys/${env}Keystore" + alias = env + // storepass = 'BadStorePassword' + // keypass = 'BadKeyPassword' + lazy = true // only sign when unsigned + } +} + +griffon { + doc { + logo = 'The Griffon Framework' + sponsorLogo = "
" + footer = "

Made with Griffon (@griffon.version@)" + } +} + +deploy { + application { + title = "${appName} ${appVersion}" + vendor = System.properties['user.name'] + homepage = "http://localhost/${appName}" + description { + complete = "${appName} ${appVersion}" + oneline = "${appName} ${appVersion}" + minimal = "${appName} ${appVersion}" + tooltip = "${appName} ${appVersion}" + } + icon { + 'default' { + name = 'griffon-icon-64x64.png' + width = '64' + height = '64' + } + splash { + name = 'griffon.png' + width = '391' + height = '123' + } + selected { + name = 'griffon-icon-64x64.png' + width = '64' + height = '64' + } + disabled { + name = 'griffon-icon-64x64.png' + width = '64' + height = '64' + } + rollover { + name = 'griffon-icon-64x64.png' + width = '64' + height = '64' + } + shortcut { + name = 'griffon-icon-64x64.png' + width = '64' + height = '64' + } + } + } +} + +griffon.project.dependency.resolution = { + // inherit Griffon' default dependencies + inherits("global") { + } + log "warn" // log level of Ivy resolver, either 'error', 'warn', 'info', 'debug' or 'verbose' + repositories { + griffonHome() + + // uncomment the below to enable remote dependency resolution + // from public Maven repositories + //mavenLocal() + //mavenCentral() + //mavenRepo "http://snapshots.repository.codehaus.org" + //mavenRepo "http://repository.codehaus.org" + //mavenRepo "http://download.java.net/maven/2/" + //mavenRepo "http://repository.jboss.com/maven2/" + } + dependencies { + // specify dependencies here under either 'build', 'compile', 'runtime' or 'test' scopes eg. + + // runtime 'mysql:mysql-connector-java:5.1.5' + } +} + +log4j = { + // Example of changing the log pattern for the default console + // appender: + appenders { + console name: 'stdout', layout: pattern(conversionPattern: '%d [%t] %-5p %c - %m%n') + } + + error 'org.codehaus.griffon', + 'org.springframework', + 'org.apache.karaf', + 'groovyx.net' + warn 'griffon' +} + diff --git a/gui/griffon-app/conf/Builder.groovy b/gui/griffon-app/conf/Builder.groovy new file mode 100644 index 0000000..90271bb --- /dev/null +++ b/gui/griffon-app/conf/Builder.groovy @@ -0,0 +1,7 @@ + +root { + 'groovy.swing.SwingBuilder' { + controller = ['Threading'] + view = '*' + } +} diff --git a/gui/griffon-app/conf/Config.groovy b/gui/griffon-app/conf/Config.groovy new file mode 100644 index 0000000..a186a6d --- /dev/null +++ b/gui/griffon-app/conf/Config.groovy @@ -0,0 +1,15 @@ +log4j = { + // Example of changing the log pattern for the default console + // appender: + appenders { + console name: 'stdout', layout: pattern(conversionPattern: '%d [%t] %-5p %c - %m%n') + } + + error 'org.codehaus.griffon' + + info 'griffon.util', + 'griffon.core', + 'griffon.@application.toolkit@', + 'griffon.app' +} + diff --git a/gui/griffon-app/conf/Events.groovy b/gui/griffon-app/conf/Events.groovy new file mode 100644 index 0000000..de9a54e --- /dev/null +++ b/gui/griffon-app/conf/Events.groovy @@ -0,0 +1,5 @@ +import org.slf4j.LoggerFactory + +onNewInstance = { klass, type, instance -> + instance.metaClass.logger = LoggerFactory.getLogger(klass.name) +} diff --git a/gui/griffon-app/conf/keys/productionKeystore b/gui/griffon-app/conf/keys/productionKeystore new file mode 100644 index 0000000..d195af0 Binary files /dev/null and b/gui/griffon-app/conf/keys/productionKeystore differ diff --git a/gui/griffon-app/conf/webstart/applet.html b/gui/griffon-app/conf/webstart/applet.html new file mode 100644 index 0000000..741952f --- /dev/null +++ b/gui/griffon-app/conf/webstart/applet.html @@ -0,0 +1,43 @@ + + + + + + + + + + + + diff --git a/gui/griffon-app/conf/webstart/applet.jnlp b/gui/griffon-app/conf/webstart/applet.jnlp new file mode 100644 index 0000000..93967a0 --- /dev/null +++ b/gui/griffon-app/conf/webstart/applet.jnlp @@ -0,0 +1,55 @@ + + + + + TimeStamper + TimeStamper + + + TimeStamper + TimeStamper + TimeStamper + TimeStamper + + + + + + + + + + + + + + + + + + + +@jnlpJars@ + +@jnlpExtensions@ + + + + + + + diff --git a/gui/griffon-app/conf/webstart/application.jnlp b/gui/griffon-app/conf/webstart/application.jnlp new file mode 100644 index 0000000..1bea5fe --- /dev/null +++ b/gui/griffon-app/conf/webstart/application.jnlp @@ -0,0 +1,50 @@ + + + + + TimeStamper + TimeStamper + + + TimeStamper + TimeStamper + TimeStamper + TimeStamper + + + + + + + + + + + + + + + + + + +@jnlpJars@ + +@jnlpExtensions@ + + + + + + + diff --git a/gui/griffon-app/conf/webstart/griffon-icon-128x128.png b/gui/griffon-app/conf/webstart/griffon-icon-128x128.png new file mode 100755 index 0000000..b0b4327 Binary files /dev/null and b/gui/griffon-app/conf/webstart/griffon-icon-128x128.png differ diff --git a/gui/griffon-app/conf/webstart/griffon-icon-16x16.png b/gui/griffon-app/conf/webstart/griffon-icon-16x16.png new file mode 100755 index 0000000..90e269e Binary files /dev/null and b/gui/griffon-app/conf/webstart/griffon-icon-16x16.png differ diff --git a/gui/griffon-app/conf/webstart/griffon-icon-24x24.png b/gui/griffon-app/conf/webstart/griffon-icon-24x24.png new file mode 100755 index 0000000..0d1bb73 Binary files /dev/null and b/gui/griffon-app/conf/webstart/griffon-icon-24x24.png differ diff --git a/gui/griffon-app/conf/webstart/griffon-icon-256x256.png b/gui/griffon-app/conf/webstart/griffon-icon-256x256.png new file mode 100755 index 0000000..3cdabd2 Binary files /dev/null and b/gui/griffon-app/conf/webstart/griffon-icon-256x256.png differ diff --git a/gui/griffon-app/conf/webstart/griffon-icon-32x32.png b/gui/griffon-app/conf/webstart/griffon-icon-32x32.png new file mode 100755 index 0000000..2c9c1e1 Binary files /dev/null and b/gui/griffon-app/conf/webstart/griffon-icon-32x32.png differ diff --git a/gui/griffon-app/conf/webstart/griffon-icon-48x48.png b/gui/griffon-app/conf/webstart/griffon-icon-48x48.png new file mode 100755 index 0000000..3577b8e Binary files /dev/null and b/gui/griffon-app/conf/webstart/griffon-icon-48x48.png differ diff --git a/gui/griffon-app/conf/webstart/griffon-icon-64x64.png b/gui/griffon-app/conf/webstart/griffon-icon-64x64.png new file mode 100755 index 0000000..fe403f8 Binary files /dev/null and b/gui/griffon-app/conf/webstart/griffon-icon-64x64.png differ diff --git a/gui/griffon-app/conf/webstart/griffon.png b/gui/griffon-app/conf/webstart/griffon.png new file mode 100755 index 0000000..4a38291 Binary files /dev/null and b/gui/griffon-app/conf/webstart/griffon.png differ diff --git a/gui/griffon-app/controllers/com/jdblabs/timestamper/gui/LogDialogController.groovy b/gui/griffon-app/controllers/com/jdblabs/timestamper/gui/LogDialogController.groovy new file mode 100644 index 0000000..9363d8f --- /dev/null +++ b/gui/griffon-app/controllers/com/jdblabs/timestamper/gui/LogDialogController.groovy @@ -0,0 +1,16 @@ +package com.jdblabs.timestamper.gui + +class LogDialogController { + // 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 -> + } + */ +} diff --git a/gui/griffon-app/controllers/com/jdblabs/timestamper/gui/NotesDialogController.groovy b/gui/griffon-app/controllers/com/jdblabs/timestamper/gui/NotesDialogController.groovy new file mode 100644 index 0000000..1a9a544 --- /dev/null +++ b/gui/griffon-app/controllers/com/jdblabs/timestamper/gui/NotesDialogController.groovy @@ -0,0 +1,18 @@ +package com.jdblabs.timestamper.gui + +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 + } + +} diff --git a/gui/griffon-app/controllers/com/jdblabs/timestamper/gui/PunchcardDialogController.groovy b/gui/griffon-app/controllers/com/jdblabs/timestamper/gui/PunchcardDialogController.groovy new file mode 100644 index 0000000..426d2d2 --- /dev/null +++ b/gui/griffon-app/controllers/com/jdblabs/timestamper/gui/PunchcardDialogController.groovy @@ -0,0 +1,22 @@ +package com.jdblabs.timestamper.gui + +import java.awt.Point + +class PunchcardDialogController { + // 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 + } + + /* + def action = { evt = null -> + } + */ +} diff --git a/gui/griffon-app/controllers/com/jdblabs/timestamper/gui/TimeStamperMainController.groovy b/gui/griffon-app/controllers/com/jdblabs/timestamper/gui/TimeStamperMainController.groovy new file mode 100644 index 0000000..2faba01 --- /dev/null +++ b/gui/griffon-app/controllers/com/jdblabs/timestamper/gui/TimeStamperMainController.groovy @@ -0,0 +1,168 @@ +package com.jdblabs.timestamper.gui + +import com.jdbernard.util.SmartConfig +import com.jdblabs.timestamper.core.TimelineMarker +import com.jdblabs.timestamper.core.TimelineProperties + +class TimeStamperMainController { + // these will be injected by Griffon + def model + def view + + def thisMVC + def syncTimers = [:] + + void mvcGroupInit(Map args) { + + def configFile + + logger.trace("Initializing TimeStamperMain MVC...") + + // init mvc map + thisMVC = ['model': model, 'view': view, 'controller': this] + + model.notesDialogMVC = buildMVCGroup('NotesDialog', 'notesDialog', + 'mainMVC': thisMVC) + + model.punchcardDialogMVC = buildMVCGroup('PunchcardDialog', + 'punchcardDialog', 'mainMVC': thisMVC) + + // load application properties + String userHomeDir = System.getProperty('user.home') + configFile = new File(userHomeDir, ".timestamperrc") + + logger.trace("Reading configuration from {}", configFile.canonicalPath) + + model.config = new SmartConfig(configFile) + + // load the last used timeline file + String lastUsed = model.config.lastUsed + if (lastUsed == "") { + lastUsed = 'timeline.default.properties' + model.config.setProperty('lastUsed', lastUsed) + } + + // load the plugin directory + File pluginDir = model.config.getProperty("pluginDir", new File("plugins")) + if (!pluginDir.exists()) pluginDir.mkdirs() + + logger.trace("Adding plugin classpath: '{}'", pluginDir.canonicalPath) + + def pluginLoader = new GroovyClassLoader(this.class.classLoader) + pluginLoader.addURL(pluginDir.toURI().toURL()) + pluginDir.eachFileMatch(/.*\.jar/) { jarfile -> + pluginLoader.addURL(jarfile.toURI().toURL()) } + + // instantiate plugins + model.config."plugin.classes".split(',').each { className -> try { + if (className.trim() == "") return + def pluginClass = pluginLoader.loadClass(className) + model.plugins < + wrapPluginCall { plugin.onStartup(thisMVC) } } + + logger.trace("Reading Timeline properties from '{}'", lastUsed) + + load(new File(lastUsed)) + } + + def wrapPluginCall(Closure c) { + try { c() } catch (Throwable t) { + logger.warn("Plugin threw an exception in ${functionName} " + + "when passed ${param}:", t) + return false + } + } + + def load = { File propertiesFile -> + // pass through plugins + propertiesFile = model.plugins.inject(propertiesFile) { file, plugin -> + // call plugin + def ret = wrapPluginCall { plugin.onTimelineLoad(thisMVC, file) } + // if the plugin call succeeded, pass the result, else pass + // the last one + ret ? ret : file + } + + try { + model.config.lastUsed = propertiesFile.canonicalPath + } catch (IOException ioe) { logger.error(ioe) } + + // load the properties file + model.timelineProperties = new TimelineProperties(propertiesFile) + + // load the main timeline + model.timeline = model.timelineProperties.timeline + + // load the last marker + model.currentMarker = model.timeline.getLastMarker(new Date()) + } + + def saveas = { + + } + + def exitGracefully = { evt = null -> + + // hide the frame immediately + view.frame.visible = false + + logger.trace("Exiting gracefully.") + + // save config + logger.debug("Config: {}", model.config) + model.config.save() + + // save timeline and properties + model.timelineProperties.save() + + // call plugin exit hooks + model.plugins.each { plugin -> + wrapPluginCall { plugin.onExit(thisMVC) } } + + logger.trace("Completed graceful shutdown.") + + app.shutdown() + } + + def newTask = { mark, notes = "No comments.", timestamp = new Date() -> + TimelineMarker tm = new TimelineMarker(timestamp, mark, notes) + + // pass through the plugins + tm = model.plugins.inject(tm) { marker, plugin -> + def ret = wrapPluginCall { plugin.onNewTask(thisMVC, marker) } + ret ? ret : marker + } + + model.timeline.addMarker(tm) + model.currentMarker = model.timeline.getLastMarker(new Date()) + + // auto-persist if enabled + if (model.timelineProperties.persistOnUpdate) + model.timelineProperties.save() + } + + def deleteTask = { marker -> + // pass through the plugins + model.plugins.each { plugin -> + wrapPluginCall { plugin.onDeleteTask(thisMVC, marker) } } + + model.timeline.removeMarker(marker) + model.currentMarker = model.timeline.getLastMarker(new Date()) + + // auto-persist if enabled + if (model.timelineProperties.persistOnUpdate) + model.timelineProperties.save() + } + +} diff --git a/gui/griffon-app/i18n/messages.properties b/gui/griffon-app/i18n/messages.properties new file mode 100755 index 0000000..e69de29 diff --git a/gui/griffon-app/i18n/resources.properties b/gui/griffon-app/i18n/resources.properties new file mode 100644 index 0000000..e69de29 diff --git a/gui/griffon-app/lifecycle/Initialize.groovy b/gui/griffon-app/lifecycle/Initialize.groovy new file mode 100755 index 0000000..0d1f7b8 --- /dev/null +++ b/gui/griffon-app/lifecycle/Initialize.groovy @@ -0,0 +1,22 @@ +/* + * This script is executed inside the EDT, so be sure to + * call long running code in another thread. + * + * You have the following options + * - SwingBuilder.doOutside { // your code } + * - Thread.start { // your code } + * - SwingXBuilder.withWorker( start: true ) { + * onInit { // initialization (optional, runs in current thread) } + * work { // your code } + * onDone { // finish (runs inside EDT) } + * } + * + * You have the following options to run code again inside EDT + * - SwingBuilder.doLater { // your code } + * - SwingBuilder.edt { // your code } + * - SwingUtilities.invokeLater { // your code } + */ + +import groovy.swing.SwingBuilder + +SwingBuilder.lookAndFeel('system', 'nimbus', ['metal', [boldFonts: false]]) diff --git a/gui/griffon-app/lifecycle/Ready.groovy b/gui/griffon-app/lifecycle/Ready.groovy new file mode 100755 index 0000000..dd993de --- /dev/null +++ b/gui/griffon-app/lifecycle/Ready.groovy @@ -0,0 +1,18 @@ +/* + * This script is executed inside the EDT, so be sure to + * call long running code in another thread. + * + * You have the following options + * - SwingBuilder.doOutside { // your code } + * - Thread.start { // your code } + * - SwingXBuilder.withWorker( start: true ) { + * onInit { // initialization (optional, runs in current thread) } + * work { // your code } + * onDone { // finish (runs inside EDT) } + * } + * + * You have the following options to run code again inside EDT + * - SwingBuilder.doLater { // your code } + * - SwingBuilder.edt { // your code } + * - SwingUtilities.invokeLater { // your code } + */ \ No newline at end of file diff --git a/gui/griffon-app/lifecycle/Shutdown.groovy b/gui/griffon-app/lifecycle/Shutdown.groovy new file mode 100755 index 0000000..dd993de --- /dev/null +++ b/gui/griffon-app/lifecycle/Shutdown.groovy @@ -0,0 +1,18 @@ +/* + * This script is executed inside the EDT, so be sure to + * call long running code in another thread. + * + * You have the following options + * - SwingBuilder.doOutside { // your code } + * - Thread.start { // your code } + * - SwingXBuilder.withWorker( start: true ) { + * onInit { // initialization (optional, runs in current thread) } + * work { // your code } + * onDone { // finish (runs inside EDT) } + * } + * + * You have the following options to run code again inside EDT + * - SwingBuilder.doLater { // your code } + * - SwingBuilder.edt { // your code } + * - SwingUtilities.invokeLater { // your code } + */ \ No newline at end of file diff --git a/gui/griffon-app/lifecycle/Startup.groovy b/gui/griffon-app/lifecycle/Startup.groovy new file mode 100755 index 0000000..3b0e025 --- /dev/null +++ b/gui/griffon-app/lifecycle/Startup.groovy @@ -0,0 +1,19 @@ +/* + * This script is executed inside the EDT, so be sure to + * call long running code in another thread. + * + * You have the following options + * - SwingBuilder.doOutside { // your code } + * - Thread.start { // your code } + * - SwingXBuilder.withWorker( start: true ) { + * onInit { // initialization (optional, runs in current thread) } + * work { // your code } + * onDone { // finish (runs inside EDT) } + * } + * + * You have the following options to run code again inside EDT + * - SwingBuilder.doLater { // your code } + * - SwingBuilder.edt { // your code } + * - SwingUtilities.invokeLater { // your code } + */ + diff --git a/gui/griffon-app/lifecycle/Stop.groovy b/gui/griffon-app/lifecycle/Stop.groovy new file mode 100755 index 0000000..e69de29 diff --git a/gui/griffon-app/models/com/jdblabs/timestamper/gui/LogDialogModel.groovy b/gui/griffon-app/models/com/jdblabs/timestamper/gui/LogDialogModel.groovy new file mode 100644 index 0000000..161a3a1 --- /dev/null +++ b/gui/griffon-app/models/com/jdblabs/timestamper/gui/LogDialogModel.groovy @@ -0,0 +1,7 @@ +package com.jdblabs.timestamper.gui + +import groovy.beans.Bindable + +class LogDialogModel { + def mainMVC +} diff --git a/gui/griffon-app/models/com/jdblabs/timestamper/gui/NotesDialogModel.groovy b/gui/griffon-app/models/com/jdblabs/timestamper/gui/NotesDialogModel.groovy new file mode 100644 index 0000000..0d6ee3f --- /dev/null +++ b/gui/griffon-app/models/com/jdblabs/timestamper/gui/NotesDialogModel.groovy @@ -0,0 +1,9 @@ +package com.jdblabs.timestamper.gui + +import groovy.beans.Bindable + +class NotesDialogModel { + + // needs to be injected by buildMVCGroup call + def mainMVC +} diff --git a/gui/griffon-app/models/com/jdblabs/timestamper/gui/PunchcardDialogModel.groovy b/gui/griffon-app/models/com/jdblabs/timestamper/gui/PunchcardDialogModel.groovy new file mode 100644 index 0000000..3c10ea9 --- /dev/null +++ b/gui/griffon-app/models/com/jdblabs/timestamper/gui/PunchcardDialogModel.groovy @@ -0,0 +1,9 @@ +package com.jdblabs.timestamper.gui + +import groovy.beans.Bindable + +class PunchcardDialogModel { + + // needs to be injected by buildMVCGroup() call + def mainMVC +} diff --git a/gui/griffon-app/models/com/jdblabs/timestamper/gui/TimeStamperMainModel.groovy b/gui/griffon-app/models/com/jdblabs/timestamper/gui/TimeStamperMainModel.groovy new file mode 100644 index 0000000..79e0039 --- /dev/null +++ b/gui/griffon-app/models/com/jdblabs/timestamper/gui/TimeStamperMainModel.groovy @@ -0,0 +1,25 @@ +package com.jdblabs.timestamper.gui + +import groovy.beans.Bindable +import java.awt.Point +import java.awt.Rectangle +import java.util.Properties +import com.jdbernard.util.SmartConfig +import com.jdblabs.timestamper.core.Timeline +import com.jdblabs.timestamper.core.TimelineMarker +import com.jdblabs.timestamper.core.TimelineProperties + +class TimeStamperMainModel { + @Bindable TimelineMarker currentMarker + @Bindable Timeline timeline + @Bindable TimelineProperties timelineProperties + SmartConfig config + + List plugins = [] + + def notesDialogMVC + def punchcardDialogMVC + + @Bindable Point absoluteLocation + @Bindable Rectangle frameSize +} diff --git a/gui/griffon-app/resources/12-em-cross.png b/gui/griffon-app/resources/12-em-cross.png new file mode 100644 index 0000000..65dfa8d Binary files /dev/null and b/gui/griffon-app/resources/12-em-cross.png differ diff --git a/gui/griffon-app/resources/16-em-cross-hover.png b/gui/griffon-app/resources/16-em-cross-hover.png new file mode 100644 index 0000000..a7740b8 Binary files /dev/null and b/gui/griffon-app/resources/16-em-cross-hover.png differ diff --git a/gui/griffon-app/resources/16-em-cross.png b/gui/griffon-app/resources/16-em-cross.png new file mode 100644 index 0000000..466e3bb Binary files /dev/null and b/gui/griffon-app/resources/16-em-cross.png differ diff --git a/gui/griffon-app/resources/16-em-pencil.png b/gui/griffon-app/resources/16-em-pencil.png new file mode 100644 index 0000000..1b4e958 Binary files /dev/null and b/gui/griffon-app/resources/16-em-pencil.png differ diff --git a/gui/griffon-app/resources/16-file-archive.png b/gui/griffon-app/resources/16-file-archive.png new file mode 100644 index 0000000..e8d07f5 Binary files /dev/null and b/gui/griffon-app/resources/16-file-archive.png differ diff --git a/gui/griffon-app/resources/16-tool-a-hover.png b/gui/griffon-app/resources/16-tool-a-hover.png new file mode 100644 index 0000000..f602f94 Binary files /dev/null and b/gui/griffon-app/resources/16-tool-a-hover.png differ diff --git a/gui/griffon-app/resources/16-tool-a.png b/gui/griffon-app/resources/16-tool-a.png new file mode 100644 index 0000000..dcf0cdf Binary files /dev/null and b/gui/griffon-app/resources/16-tool-a.png differ diff --git a/gui/griffon-app/resources/24-em-cross.png b/gui/griffon-app/resources/24-em-cross.png new file mode 100644 index 0000000..a9e18d2 Binary files /dev/null and b/gui/griffon-app/resources/24-em-cross.png differ diff --git a/gui/griffon-app/resources/24-message-info.png b/gui/griffon-app/resources/24-message-info.png new file mode 100644 index 0000000..78cee30 Binary files /dev/null and b/gui/griffon-app/resources/24-message-info.png differ diff --git a/gui/griffon-app/resources/appointment-new-16x16.png b/gui/griffon-app/resources/appointment-new-16x16.png new file mode 100755 index 0000000..18b7c67 Binary files /dev/null and b/gui/griffon-app/resources/appointment-new-16x16.png differ diff --git a/gui/griffon-app/resources/appointment-new-32x32.png b/gui/griffon-app/resources/appointment-new-32x32.png new file mode 100644 index 0000000..85daef3 Binary files /dev/null and b/gui/griffon-app/resources/appointment-new-32x32.png differ diff --git a/gui/griffon-app/resources/delete-marker.png b/gui/griffon-app/resources/delete-marker.png new file mode 100644 index 0000000..237ae2a Binary files /dev/null and b/gui/griffon-app/resources/delete-marker.png differ diff --git a/gui/griffon-app/resources/document-open-16x16.png b/gui/griffon-app/resources/document-open-16x16.png new file mode 100644 index 0000000..69dd8d4 Binary files /dev/null and b/gui/griffon-app/resources/document-open-16x16.png differ diff --git a/gui/griffon-app/resources/document-save-16x16.png b/gui/griffon-app/resources/document-save-16x16.png new file mode 100644 index 0000000..22ff495 Binary files /dev/null and b/gui/griffon-app/resources/document-save-16x16.png differ diff --git a/gui/griffon-app/resources/document-save-as-16x16.png b/gui/griffon-app/resources/document-save-as-16x16.png new file mode 100644 index 0000000..9bed143 Binary files /dev/null and b/gui/griffon-app/resources/document-save-as-16x16.png differ diff --git a/gui/griffon-app/resources/griffon-icon-128x128.png b/gui/griffon-app/resources/griffon-icon-128x128.png new file mode 100644 index 0000000..b0b4327 Binary files /dev/null and b/gui/griffon-app/resources/griffon-icon-128x128.png differ diff --git a/gui/griffon-app/resources/griffon-icon-16x16.png b/gui/griffon-app/resources/griffon-icon-16x16.png new file mode 100644 index 0000000..90e269e Binary files /dev/null and b/gui/griffon-app/resources/griffon-icon-16x16.png differ diff --git a/gui/griffon-app/resources/griffon-icon-24x24.png b/gui/griffon-app/resources/griffon-icon-24x24.png new file mode 100644 index 0000000..0d1bb73 Binary files /dev/null and b/gui/griffon-app/resources/griffon-icon-24x24.png differ diff --git a/gui/griffon-app/resources/griffon-icon-256x256.png b/gui/griffon-app/resources/griffon-icon-256x256.png new file mode 100644 index 0000000..3cdabd2 Binary files /dev/null and b/gui/griffon-app/resources/griffon-icon-256x256.png differ diff --git a/gui/griffon-app/resources/griffon-icon-32x32.png b/gui/griffon-app/resources/griffon-icon-32x32.png new file mode 100644 index 0000000..2c9c1e1 Binary files /dev/null and b/gui/griffon-app/resources/griffon-icon-32x32.png differ diff --git a/gui/griffon-app/resources/griffon-icon-48x48.png b/gui/griffon-app/resources/griffon-icon-48x48.png new file mode 100644 index 0000000..3577b8e Binary files /dev/null and b/gui/griffon-app/resources/griffon-icon-48x48.png differ diff --git a/gui/griffon-app/resources/griffon-icon-64x64.png b/gui/griffon-app/resources/griffon-icon-64x64.png new file mode 100644 index 0000000..fe403f8 Binary files /dev/null and b/gui/griffon-app/resources/griffon-icon-64x64.png differ diff --git a/gui/griffon-app/resources/griffon.png b/gui/griffon-app/resources/griffon.png new file mode 100644 index 0000000..4a38291 Binary files /dev/null and b/gui/griffon-app/resources/griffon.png differ diff --git a/gui/griffon-app/resources/logback.groovy b/gui/griffon-app/resources/logback.groovy new file mode 100644 index 0000000..6c91dc7 --- /dev/null +++ b/gui/griffon-app/resources/logback.groovy @@ -0,0 +1,20 @@ +import ch.qos.logback.classic.encoder.PatternLayoutEncoder +import ch.qos.logback.core.ConsoleAppender +import ch.qos.logback.core.FileAppender +import static ch.qos.logback.classic.Level.* + +appender("CONSOLE", ConsoleAppender) { + encoder(PatternLayoutEncoder) { + pattern = "%level - %msg%n" + } +} + +appender("FILE", FileAppender) { + file="timestamper.log" + encoder(PatternLayoutEncoder) { + pattern = "%date %level %logger - %msg%n" + } +} + +root(WARN, ["CONSOLE"]) +logger("com.jdblabs.*", TRACE, ["FILE"], false) diff --git a/gui/griffon-app/resources/media-skip-backward.png b/gui/griffon-app/resources/media-skip-backward.png new file mode 100644 index 0000000..94381f5 Binary files /dev/null and b/gui/griffon-app/resources/media-skip-backward.png differ diff --git a/gui/griffon-app/resources/media-skip-forward.png b/gui/griffon-app/resources/media-skip-forward.png new file mode 100644 index 0000000..758ec6f Binary files /dev/null and b/gui/griffon-app/resources/media-skip-forward.png differ diff --git a/gui/griffon-app/resources/new-marker.png b/gui/griffon-app/resources/new-marker.png new file mode 100644 index 0000000..f5de8a5 Binary files /dev/null and b/gui/griffon-app/resources/new-marker.png differ diff --git a/gui/griffon-app/resources/next-day.png b/gui/griffon-app/resources/next-day.png new file mode 100644 index 0000000..a7de0fe Binary files /dev/null and b/gui/griffon-app/resources/next-day.png differ diff --git a/gui/griffon-app/resources/next-week.png b/gui/griffon-app/resources/next-week.png new file mode 100644 index 0000000..4d7e2cd Binary files /dev/null and b/gui/griffon-app/resources/next-week.png differ diff --git a/gui/griffon-app/resources/previous-day.png b/gui/griffon-app/resources/previous-day.png new file mode 100644 index 0000000..07dcbf1 Binary files /dev/null and b/gui/griffon-app/resources/previous-day.png differ diff --git a/gui/griffon-app/resources/previous-week.png b/gui/griffon-app/resources/previous-week.png new file mode 100644 index 0000000..ffcac31 Binary files /dev/null and b/gui/griffon-app/resources/previous-week.png differ diff --git a/gui/griffon-app/session.vim b/gui/griffon-app/session.vim new file mode 100644 index 0000000..62acf74 --- /dev/null +++ b/gui/griffon-app/session.vim @@ -0,0 +1,1880 @@ +let SessionLoad = 1 +if &cp | set nocp | endif +let s:cpo_save=&cpo +set cpo&vim +inoremap  +nmap v :call Screen_Vars() +nmap  vip +vmap  {j"ry} :call Send_to_Screen(@r) +map \dg DirDiffGet +map \dp DirDiffPut +map \dj DirDiffNext +map \dk DirDiffPrev +nmap gx NetrwBrowseX +nnoremap NetrwBrowseX :call netrw#NetrwBrowseX(expand(""),0) +let &cpo=s:cpo_save +unlet s:cpo_save +set autoindent +set backspace=indent,eol,start +set errorformat=%A\ %#[javac]\ %f:%l:\ %m,%-Z\ %#[javac]\ %p^,%-C%.%# +set expandtab +set fileencodings=ucs-bom,utf-8,default,latin1 +set helplang=en +set history=50 +set hlsearch +set iminsert=0 +set imsearch=0 +set incsearch +set makeprg=ant +set nomodeline +set printoptions=paper:letter +set ruler +set runtimepath=~/.vim,/var/lib/vim/addons,/usr/share/vim/vimfiles,/usr/share/vim/vim72,/usr/share/vim/vimfiles/after,/var/lib/vim/addons/after,~/.vim/after +set shiftwidth=4 +set showcmd +set suffixes=.bak,~,.swp,.o,.info,.aux,.log,.dvi,.bbl,.blg,.brf,.cb,.ind,.idx,.ilg,.inx,.out,.toc +set tabstop=4 +let s:so_save = &so | let s:siso_save = &siso | set so=0 siso=0 +let v:this_session=expand(":p") +silent only +cd ~/projects/TimeStamper/griffon-app +if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == '' + let s:wipebuf = bufnr('%') +endif +set shortmess=aoO +badd +88 views/com/jdblabs/timestamper/TimeStamperMainView.groovy +badd +24 models/com/jdblabs/timestamper/TimeStamperMainModel.groovy +badd +64 controllers/com/jdblabs/timestamper/TimeStamperMainController.groovy +badd +1 views/com/jdblabs/timestamper/NotesDialogView.groovy +badd +8 models/com/jdblabs/timestamper/NotesDialogModel.groovy +badd +1 controllers/com/jdblabs/timestamper/NotesDialogController.groovy +badd +1 views/com/jdblabs/timestamper/PunchcardDialogView.groovy +badd +7 models/com/jdblabs/timestamper/PunchcardDialogModel.groovy +badd +1 controllers/com/jdblabs/timestamper/PunchcardDialogController.groovy +badd +215 ../src/main/com/jdblabs/timestamper/gui/TimelineDayDisplay.java +badd +8 ../src/main/com/jdblabs/timestamper/gui/WindowInformation.groovy +badd +28 conf/Application.groovy +badd +1 conf/Builder.groovy +badd +1 conf/Config.groovy +badd +1 actions/com/jdblabs/timestamper/NotesDialogActions.groovy +badd +1 actions/com/jdblabs/timestamper/TimeStamperMainActions.groovy +badd +24 lifecycle/Initialize.groovy +badd +1 conf/Events.groovy +badd +13 resources/log4j.properties +badd +1 ../src/main/com/jdblabs/timestamper/GUIUtil.groovy +badd +1 controllers/com/jdblabs/timestamper/LogDialogController.groovy +badd +1 models/com/jdblabs/timestamper/LogDialogModel.groovy +badd +0 views/com/jdblabs/timestamper/LogDialogView.groovy +badd +0 ../src/main/com/jdblabs/GUIUtil.groovy +args views/com/jdblabs/timestamper/TimeStamperMainView.groovy +edit views/com/jdblabs/timestamper/TimeStamperMainView.groovy +set splitbelow splitright +wincmd _ | wincmd | +vsplit +1wincmd h +wincmd w +wincmd _ | wincmd | +split +1wincmd k +wincmd w +set nosplitbelow +set nosplitright +wincmd t +set winheight=1 winwidth=1 +exe 'vert 1resize ' . ((&columns * 90 + 91) / 182) +exe '2resize ' . ((&lines * 23 + 40) / 81) +exe 'vert 2resize ' . ((&columns * 91 + 91) / 182) +exe '3resize ' . ((&lines * 54 + 40) / 81) +exe 'vert 3resize ' . ((&columns * 91 + 91) / 182) +argglobal +setlocal keymap= +setlocal noarabic +setlocal autoindent +setlocal balloonexpr= +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal nocindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:- +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'groovy' +setlocal filetype=groovy +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=tcq +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc= +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norightleft +setlocal rightleftcmd=search +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+ +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'groovy' +setlocal syntax=groovy +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 110 - ((46 * winheight(0) + 39) / 78) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +110 +normal! 011l +wincmd w +argglobal +edit models/com/jdblabs/timestamper/TimeStamperMainModel.groovy +setlocal keymap= +setlocal noarabic +setlocal autoindent +setlocal balloonexpr= +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal nocindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:- +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'groovy' +setlocal filetype=groovy +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=tcq +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc= +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norightleft +setlocal rightleftcmd=search +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+ +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'groovy' +setlocal syntax=groovy +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 23 - ((19 * winheight(0) + 11) / 23) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +23 +normal! 0 +wincmd w +argglobal +edit controllers/com/jdblabs/timestamper/TimeStamperMainController.groovy +setlocal keymap= +setlocal noarabic +setlocal autoindent +setlocal balloonexpr= +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal nocindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:- +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'groovy' +setlocal filetype=groovy +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=tcq +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc= +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norightleft +setlocal rightleftcmd=search +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+ +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'groovy' +setlocal syntax=groovy +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 34 - ((17 * winheight(0) + 27) / 54) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +34 +normal! 036l +wincmd w +3wincmd w +exe 'vert 1resize ' . ((&columns * 90 + 91) / 182) +exe '2resize ' . ((&lines * 23 + 40) / 81) +exe 'vert 2resize ' . ((&columns * 91 + 91) / 182) +exe '3resize ' . ((&lines * 54 + 40) / 81) +exe 'vert 3resize ' . ((&columns * 91 + 91) / 182) +tabedit views/com/jdblabs/timestamper/NotesDialogView.groovy +set splitbelow splitright +wincmd _ | wincmd | +vsplit +1wincmd h +wincmd w +wincmd _ | wincmd | +split +1wincmd k +wincmd w +set nosplitbelow +set nosplitright +wincmd t +set winheight=1 winwidth=1 +exe 'vert 1resize ' . ((&columns * 90 + 91) / 182) +exe '2resize ' . ((&lines * 12 + 40) / 81) +exe 'vert 2resize ' . ((&columns * 91 + 91) / 182) +exe '3resize ' . ((&lines * 65 + 40) / 81) +exe 'vert 3resize ' . ((&columns * 91 + 91) / 182) +argglobal +setlocal keymap= +setlocal noarabic +setlocal autoindent +setlocal balloonexpr= +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal nocindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:- +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'groovy' +setlocal filetype=groovy +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=tcq +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc= +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norightleft +setlocal rightleftcmd=search +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+ +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'groovy' +setlocal syntax=groovy +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 49 - ((48 * winheight(0) + 39) / 78) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +49 +normal! 025l +wincmd w +argglobal +edit models/com/jdblabs/timestamper/NotesDialogModel.groovy +setlocal keymap= +setlocal noarabic +setlocal autoindent +setlocal balloonexpr= +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal nocindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:- +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'groovy' +setlocal filetype=groovy +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=tcq +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc= +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norightleft +setlocal rightleftcmd=search +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+ +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'groovy' +setlocal syntax=groovy +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 1 - ((0 * winheight(0) + 6) / 12) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +1 +normal! 0 +wincmd w +argglobal +edit controllers/com/jdblabs/timestamper/NotesDialogController.groovy +setlocal keymap= +setlocal noarabic +setlocal autoindent +setlocal balloonexpr= +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal nocindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:- +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'groovy' +setlocal filetype=groovy +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=tcq +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc= +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norightleft +setlocal rightleftcmd=search +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+ +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'groovy' +setlocal syntax=groovy +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 1 - ((0 * winheight(0) + 32) / 65) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +1 +normal! 0 +wincmd w +3wincmd w +exe 'vert 1resize ' . ((&columns * 90 + 91) / 182) +exe '2resize ' . ((&lines * 12 + 40) / 81) +exe 'vert 2resize ' . ((&columns * 91 + 91) / 182) +exe '3resize ' . ((&lines * 65 + 40) / 81) +exe 'vert 3resize ' . ((&columns * 91 + 91) / 182) +tabedit views/com/jdblabs/timestamper/PunchcardDialogView.groovy +set splitbelow splitright +wincmd _ | wincmd | +vsplit +1wincmd h +wincmd w +wincmd _ | wincmd | +split +1wincmd k +wincmd w +set nosplitbelow +set nosplitright +wincmd t +set winheight=1 winwidth=1 +exe 'vert 1resize ' . ((&columns * 90 + 91) / 182) +exe '2resize ' . ((&lines * 12 + 40) / 81) +exe 'vert 2resize ' . ((&columns * 91 + 91) / 182) +exe '3resize ' . ((&lines * 65 + 40) / 81) +exe 'vert 3resize ' . ((&columns * 91 + 91) / 182) +argglobal +setlocal keymap= +setlocal noarabic +setlocal autoindent +setlocal balloonexpr= +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal nocindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:- +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'groovy' +setlocal filetype=groovy +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=tcq +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc= +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norightleft +setlocal rightleftcmd=search +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+ +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'groovy' +setlocal syntax=groovy +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 54 - ((51 * winheight(0) + 39) / 78) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +54 +normal! 011l +wincmd w +argglobal +edit models/com/jdblabs/timestamper/PunchcardDialogModel.groovy +setlocal keymap= +setlocal noarabic +setlocal autoindent +setlocal balloonexpr= +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal nocindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:- +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'groovy' +setlocal filetype=groovy +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=tcq +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc= +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norightleft +setlocal rightleftcmd=search +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+ +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'groovy' +setlocal syntax=groovy +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 8 - ((6 * winheight(0) + 6) / 12) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +8 +normal! 07l +wincmd w +argglobal +edit controllers/com/jdblabs/timestamper/PunchcardDialogController.groovy +setlocal keymap= +setlocal noarabic +setlocal autoindent +setlocal balloonexpr= +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal nocindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:- +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'groovy' +setlocal filetype=groovy +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=tcq +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc= +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norightleft +setlocal rightleftcmd=search +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+ +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'groovy' +setlocal syntax=groovy +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 1 - ((0 * winheight(0) + 32) / 65) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +1 +normal! 0 +wincmd w +3wincmd w +exe 'vert 1resize ' . ((&columns * 90 + 91) / 182) +exe '2resize ' . ((&lines * 12 + 40) / 81) +exe 'vert 2resize ' . ((&columns * 91 + 91) / 182) +exe '3resize ' . ((&lines * 65 + 40) / 81) +exe 'vert 3resize ' . ((&columns * 91 + 91) / 182) +tabedit views/com/jdblabs/timestamper/LogDialogView.groovy +set splitbelow splitright +wincmd _ | wincmd | +vsplit +1wincmd h +wincmd w +wincmd _ | wincmd | +split +1wincmd k +wincmd w +set nosplitbelow +set nosplitright +wincmd t +set winheight=1 winwidth=1 +exe 'vert 1resize ' . ((&columns * 91 + 91) / 182) +exe '2resize ' . ((&lines * 14 + 40) / 81) +exe 'vert 2resize ' . ((&columns * 90 + 91) / 182) +exe '3resize ' . ((&lines * 63 + 40) / 81) +exe 'vert 3resize ' . ((&columns * 90 + 91) / 182) +argglobal +setlocal keymap= +setlocal noarabic +setlocal autoindent +setlocal balloonexpr= +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal nocindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:- +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'groovy' +setlocal filetype=groovy +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=tcq +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal nomodeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc= +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norightleft +setlocal rightleftcmd=search +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+ +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'groovy' +setlocal syntax=groovy +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 6 - ((5 * winheight(0) + 39) / 78) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +6 +normal! 04l +wincmd w +argglobal +edit models/com/jdblabs/timestamper/LogDialogModel.groovy +setlocal keymap= +setlocal noarabic +setlocal autoindent +setlocal balloonexpr= +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal nocindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:- +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'groovy' +setlocal filetype=groovy +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=tcq +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal nomodeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc= +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norightleft +setlocal rightleftcmd=search +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+ +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'groovy' +setlocal syntax=groovy +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 6 - ((5 * winheight(0) + 7) / 14) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +6 +normal! 014l +wincmd w +argglobal +edit controllers/com/jdblabs/timestamper/LogDialogController.groovy +setlocal keymap= +setlocal noarabic +setlocal autoindent +setlocal balloonexpr= +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal nocindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:- +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'groovy' +setlocal filetype=groovy +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=tcq +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal nomodeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc= +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norightleft +setlocal rightleftcmd=search +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+ +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'groovy' +setlocal syntax=groovy +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 3 - ((2 * winheight(0) + 31) / 63) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +3 +normal! 0 +wincmd w +3wincmd w +exe 'vert 1resize ' . ((&columns * 91 + 91) / 182) +exe '2resize ' . ((&lines * 14 + 40) / 81) +exe 'vert 2resize ' . ((&columns * 90 + 91) / 182) +exe '3resize ' . ((&lines * 63 + 40) / 81) +exe 'vert 3resize ' . ((&columns * 90 + 91) / 182) +tabedit conf/Application.groovy +set splitbelow splitright +wincmd _ | wincmd | +vsplit +1wincmd h +wincmd w +set nosplitbelow +set nosplitright +wincmd t +set winheight=1 winwidth=1 +exe 'vert 1resize ' . ((&columns * 91 + 91) / 182) +exe 'vert 2resize ' . ((&columns * 90 + 91) / 182) +argglobal +setlocal keymap= +setlocal noarabic +setlocal autoindent +setlocal balloonexpr= +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal nocindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:- +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'groovy' +setlocal filetype=groovy +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=tcq +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc= +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norightleft +setlocal rightleftcmd=search +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+ +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'groovy' +setlocal syntax=groovy +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 28 - ((24 * winheight(0) + 39) / 78) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +28 +normal! 08l +wincmd w +argglobal +edit lifecycle/Initialize.groovy +setlocal keymap= +setlocal noarabic +setlocal autoindent +setlocal balloonexpr= +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal nocindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:- +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'groovy' +setlocal filetype=groovy +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=tcq +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal nomodeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc= +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norightleft +setlocal rightleftcmd=search +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+ +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'groovy' +setlocal syntax=groovy +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 37 - ((36 * winheight(0) + 39) / 78) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +37 +normal! 035l +wincmd w +3wincmd w +exe 'vert 1resize ' . ((&columns * 91 + 91) / 182) +exe 'vert 2resize ' . ((&columns * 90 + 91) / 182) +tabedit ../src/main/com/jdblabs/timestamper/gui/TimelineDayDisplay.java +set splitbelow splitright +wincmd _ | wincmd | +vsplit +1wincmd h +wincmd w +set nosplitbelow +set nosplitright +wincmd t +set winheight=1 winwidth=1 +exe 'vert 1resize ' . ((&columns * 91 + 91) / 182) +exe 'vert 2resize ' . ((&columns * 90 + 91) / 182) +argglobal +setlocal keymap= +setlocal noarabic +setlocal autoindent +setlocal balloonexpr= +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal nocindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:- +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'java' +setlocal filetype=java +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=tcq +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal modeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc= +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norightleft +setlocal rightleftcmd=search +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+ +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'java' +setlocal syntax=java +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +62,69fold +71,74fold +76,214fold +62 +normal zc +71 +normal zc +76 +normal zc +let s:l = 215 - ((190 * winheight(0) + 39) / 78) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +215 +normal! 0 +wincmd w +argglobal +edit ../src/main/com/jdblabs/GUIUtil.groovy +setlocal keymap= +setlocal noarabic +setlocal autoindent +setlocal balloonexpr= +setlocal nobinary +setlocal bufhidden= +setlocal buflisted +setlocal buftype= +setlocal nocindent +setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e +setlocal cinoptions= +setlocal cinwords=if,else,while,do,for,switch +setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:- +setlocal commentstring=/*%s*/ +setlocal complete=.,w,b,u,t,i +setlocal completefunc= +setlocal nocopyindent +setlocal nocursorcolumn +setlocal nocursorline +setlocal define= +setlocal dictionary= +setlocal nodiff +setlocal equalprg= +setlocal errorformat= +setlocal expandtab +if &filetype != 'groovy' +setlocal filetype=groovy +endif +setlocal foldcolumn=0 +setlocal foldenable +setlocal foldexpr=0 +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldmarker={{{,}}} +setlocal foldmethod=manual +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldtext=foldtext() +setlocal formatexpr= +setlocal formatoptions=tcq +setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s* +setlocal grepprg= +setlocal iminsert=0 +setlocal imsearch=0 +setlocal include= +setlocal includeexpr= +setlocal indentexpr= +setlocal indentkeys=0{,0},:,0#,!^F,o,O,e +setlocal noinfercase +setlocal iskeyword=@,48-57,_,192-255 +setlocal keywordprg= +setlocal nolinebreak +setlocal nolisp +setlocal nolist +setlocal makeprg= +setlocal matchpairs=(:),{:},[:] +setlocal nomodeline +setlocal modifiable +setlocal nrformats=octal,hex +set number +setlocal number +setlocal numberwidth=4 +setlocal omnifunc= +setlocal path= +setlocal nopreserveindent +setlocal nopreviewwindow +setlocal quoteescape=\\ +setlocal noreadonly +setlocal norightleft +setlocal rightleftcmd=search +setlocal noscrollbind +setlocal shiftwidth=4 +setlocal noshortname +setlocal nosmartindent +setlocal softtabstop=0 +setlocal nospell +setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+ +setlocal spellfile= +setlocal spelllang=en +setlocal statusline= +setlocal suffixesadd= +setlocal swapfile +setlocal synmaxcol=3000 +if &syntax != 'groovy' +setlocal syntax=groovy +endif +setlocal tabstop=4 +setlocal tags= +setlocal textwidth=0 +setlocal thesaurus= +setlocal nowinfixheight +setlocal nowinfixwidth +setlocal wrap +setlocal wrapmargin=0 +silent! normal! zE +let s:l = 1 - ((0 * winheight(0) + 39) / 78) +if s:l < 1 | let s:l = 1 | endif +exe s:l +normal! zt +1 +normal! 0 +wincmd w +3wincmd w +exe 'vert 1resize ' . ((&columns * 91 + 91) / 182) +exe 'vert 2resize ' . ((&columns * 90 + 91) / 182) +tabnext 1 +if exists('s:wipebuf') + silent exe 'bwipe ' . s:wipebuf +endif +unlet! s:wipebuf +set winheight=1 winwidth=20 shortmess=filnxtToO +let s:sx = expand(":p:r")."x.vim" +if file_readable(s:sx) + exe "source " . fnameescape(s:sx) +endif +let &so = s:so_save | let &siso = s:siso_save +doautoall SessionLoadPost +unlet SessionLoad +" vim: set ft=vim : diff --git a/gui/griffon-app/views/com/jdblabs/timestamper/gui/LogDialogView.groovy b/gui/griffon-app/views/com/jdblabs/timestamper/gui/LogDialogView.groovy new file mode 100644 index 0000000..6004dcb --- /dev/null +++ b/gui/griffon-app/views/com/jdblabs/timestamper/gui/LogDialogView.groovy @@ -0,0 +1,10 @@ +package com.jdblabs.timestamper.gui + +import javax.swing.JDialog + +dialog = dialog(new JDialog(model.mainMVC.view.frame), + title: 'Error Messages...', + modal: false) { + + logger.trace( "Building LogDialog view." ) +} diff --git a/gui/griffon-app/views/com/jdblabs/timestamper/gui/NotesDialogView.groovy b/gui/griffon-app/views/com/jdblabs/timestamper/gui/NotesDialogView.groovy new file mode 100644 index 0000000..0176083 --- /dev/null +++ b/gui/griffon-app/views/com/jdblabs/timestamper/gui/NotesDialogView.groovy @@ -0,0 +1,65 @@ +package com.jdblabs.timestamper.gui + +import java.awt.Color +import java.awt.Point +import java.awt.Rectangle +import java.awt.Toolkit +import javax.swing.BoxLayout +import javax.swing.JDialog +import net.miginfocom.swing.MigLayout + +Point mousePressRelativeToDialog +Point offsetFromMainFrame = new Point(0,0) +boolean coupledToMainFrame = false + +mousePressed = { evt -> mousePressRelativeToDialog = evt?.point } + +mouseDragged = { evt -> + GUIUtil.componentDragged(dialog, evt, mousePressRelativeToDialog, + new Rectangle(Toolkit.defaultToolkit.screenSize), + model.mainMVC.view.frame.bounds) + + offsetFromMainFrame = GUIUtil.calculateOffset( + model.mainMVC.view.frame, dialog) + + coupledToMainFrame = GUIUtil.componentsCoupled(dialog, + model.mainMVC.view.frame); + +} + +dialog = dialog(new JDialog(model.mainMVC.view.frame), + title: 'Notes', + modal: false, + undecorated: true, + minimumSize: [325, 200], + mousePressed: mousePressed, + mouseDragged: mouseDragged, + iconImage: imageIcon('/16-em-pencil.png').image, + iconImages: [imageIcon('/16-em-pencil.png').image], + location: bind(source: model.mainMVC.model, + sourceProperty: 'absoluteLocation', + converter: { loc -> + if (coupledToMainFrame) { + Point p = new Point(offsetFromMainFrame) + p.translate((int) loc.x, (int) loc.y) + return p + } else return dialog.location }) +) { + logger.trace('Building NotesDialog GUI') + panel( + border:lineBorder(color: Color.BLACK, thickness:1, parent:true), + layout: new MigLayout('insets 10 10 10 10, fill') + ) { + scrollPane(constraints: 'growx, growy') { + notesTextArea = textArea(lineWrap: true, columns: 20, rows: 5, + wrapStyleWord: true, + text: bind(source: model.mainMVC.model, + sourceProperty: 'currentMarker', + sourceValue: { model.mainMVC.model.currentMarker?.notes}), + keyReleased: { + if (model.mainMVC.model.currentMarker != null) + model.mainMVC.model.currentMarker.notes = + notesTextArea.text}) + } + } +} diff --git a/gui/griffon-app/views/com/jdblabs/timestamper/gui/PunchcardDialogView.groovy b/gui/griffon-app/views/com/jdblabs/timestamper/gui/PunchcardDialogView.groovy new file mode 100644 index 0000000..d321ad1 --- /dev/null +++ b/gui/griffon-app/views/com/jdblabs/timestamper/gui/PunchcardDialogView.groovy @@ -0,0 +1,164 @@ +package com.jdblabs.timestamper.gui + +import java.awt.Color +import java.awt.Point +import java.awt.Toolkit +import java.awt.Rectangle +import java.beans.PropertyChangeListener +import java.text.SimpleDateFormat +import javax.swing.JDialog +import java.util.Calendar +import javax.swing.SwingConstants +import com.jdblabs.timestamper.gui.TimelineDayDisplay +import com.toedter.calendar.JDateChooser +import net.miginfocom.swing.MigLayout + +Point mousePressRelativeToDialog +Point offsetFromMainFrame = new Point(0,0) +boolean coupledToMainFrame = false + +dateFormatter = new SimpleDateFormat("EEE MMM dd") + +mousePressed = { evt -> mousePressRelativeToDialog = evt?.point } + +mouseDragged = { evt -> + GUIUtil.componentDragged(dialog, evt, mousePressRelativeToDialog, + new Rectangle(Toolkit.defaultToolkit.screenSize), + model.mainMVC.view.frame.bounds) + + offsetFromMainFrame = GUIUtil.calculateOffset( + model.mainMVC.view.frame, dialog) + + coupledToMainFrame = GUIUtil.componentsCoupled(dialog, + model.mainMVC.view.frame); +} + +dialog = dialog(new JDialog(model.mainMVC.view.frame), + title: 'Punchcard', + modal: false, + undecorated: true, + mousePressed: mousePressed, + mouseDragged: mouseDragged, + iconImage: imageIcon('/16-file-archive.png').image, + iconImages: [imageIcon('/16-file-archive.png').image], + minimumSize: [450, 500], + location: bind(source: model.mainMVC.model, + sourceProperty: 'absoluteLocation', + converter: { loc -> + if (coupledToMainFrame) { + Point p = new Point(offsetFromMainFrame) + p.translate((int) loc.x, (int) loc.y) + return p + } else return dialog.location }) +) { + logger.trace('Building PunchcardDialog GUI') + panel( + border:lineBorder(color: Color.BLACK, thickness:1, parent:true), + layout: new MigLayout('fill, insets 10 10 10 10', + '[grow]', '[grow]10[grow 0]') + ) { + dayDisplay = widget(constraints: 'grow, gp 200', + new TimelineDayDisplay(model.mainMVC.model.timeline), + timeline: bind(source: model.mainMVC.model, + sourceProperty: 'timeline')) + + model.mainMVC.model.addPropertyChangeListener('currentMarker', { + dayDisplay.stateChanged(null) } as PropertyChangeListener) + + panel( + border: lineBorder(color: Color.BLACK, thickness: 1), + constraints: 'growx, growy 0, newline, bottom', + layout: new MigLayout('fill, insets 0 10 0 10', + '[grow]10[grow 0]', '[][][grow 0]') + ) { + dateChooser = widget(new JDateChooser(), + constraints: 'growx, gaptop 10', + dateFormatString: 'MMM d, yyyy HH:mm', + date: bind(source: dayDisplay, + sourceProperty: 'selectedTimelineMarker', + converter: { it?.timestamp })) + + panel(constraints: 'spany 3, wrap, al trailing', + layout: new MigLayout('insets 0', '[]0[]0[]0[]0[]', + '[]0[]0[]0[]0[]') + ) { + label(background: [255, 255, 153], + constraints: 'growx, spanx 5, wrap', + horizontalAlignment: SwingConstants.CENTER, + opaque: true, + text: bind(source: dayDisplay, + sourceProperty: 'rangeStart', + converter: { dateFormatter.format(it) })) + + Calendar calendar = Calendar.getInstance() + button(icon: imageIcon('/previous-week.png'), + border: emptyBorder(4), + actionPerformed: { + calendar.time = dayDisplay.rangeStart + calendar.add(Calendar.WEEK_OF_YEAR, -1) + dayDisplay.day = calendar.time }) + button(icon: imageIcon('/previous-day.png'), + border: emptyBorder(4), + actionPerformed: { + calendar.time = dayDisplay.rangeStart + calendar.add(Calendar.DAY_OF_YEAR, -1) + dayDisplay.day = calendar.time }) + button(text: 'Today', + border: emptyBorder(4), + actionPerformed: { + calendar = Calendar.getInstance() + dayDisplay.day = calendar.time }) + button(icon: imageIcon('/next-day.png'), + border: emptyBorder(4), + actionPerformed: { + calendar.time = dayDisplay.rangeStart + calendar.add(Calendar.DAY_OF_YEAR, 1) + dayDisplay.day = calendar.time }) + button(icon: imageIcon('/next-week.png'), + constraints: 'wrap', + border: emptyBorder(4), + actionPerformed: { + calendar.time = dayDisplay.rangeStart + calendar.add(Calendar.WEEK_OF_YEAR, 1) + dayDisplay.day = calendar.time }) + + button(text: 'New Marker', icon: imageIcon('/new-marker.png'), + constraints: 'growx, spanx 5, wrap', + horizontalAlignment: SwingConstants.CENTER, + actionPerformed: { + model.mainMVC.controller.newTask(markTextField.text, + notesTextField.text, dateChooser.date) }) + button(text: 'Delete Marker', + icon: imageIcon('/delete-marker.png'), + constraints: 'growx, spanx 5, wrap', + horizontalAlignment: SwingConstants.CENTER, + actionPerformed: { + model.mainMVC.controller.deleteTask( + dayDisplay.selectedTimelineMarker) }) + button(text: 'Apply Changes', + icon: imageIcon('/document-save-16x16.png'), + constraints: 'growx, spanx 5', + horizontalAlignment: SwingConstants.CENTER, + actionPerformed: { + Date d = dateChooser.date + String m = markTextField.text + String n = notesTextField.text + model.mainMVC.controller.deleteTask( + dayDisplay.selectedTimelineMarker) + model.mainMVC.controller.newTask(m, n, d) }) + } + + markTextField = textField(constraints: 'growx, wrap', + text: bind(source: dayDisplay, + sourceProperty: 'selectedTimelineMarker', + converter: { it?.mark })) + scrollPane(constraints: 'growx, gapbottom 10', + minimumSize: [0, 50]) { + notesTextField = textArea( wrapStyleWord: true, lineWrap: true, + text: bind(source: dayDisplay, + sourceProperty: 'selectedTimelineMarker', + converter: { it?.notes })) + } + } + } +} diff --git a/gui/griffon-app/views/com/jdblabs/timestamper/gui/TimeStamperMainView.groovy b/gui/griffon-app/views/com/jdblabs/timestamper/gui/TimeStamperMainView.groovy new file mode 100644 index 0000000..df9f30c --- /dev/null +++ b/gui/griffon-app/views/com/jdblabs/timestamper/gui/TimeStamperMainView.groovy @@ -0,0 +1,205 @@ +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) + } +} diff --git a/gui/griffonw b/gui/griffonw new file mode 100644 index 0000000..703dc30 --- /dev/null +++ b/gui/griffonw @@ -0,0 +1,165 @@ +#!/bin/bash + +############################################################################## +## +## Griffon start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRIFFON_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Griffon" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" +APP_HOME="`pwd -P`" +cd "$SAVED" + +CLASSPATH=$APP_HOME/wrapper/griffon-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query businessSystem maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add APP_NAME to the JAVA_OPTS as -Xdock:name +if $darwin; then + JAVA_OPTS="$JAVA_OPTS -Xdock:name=$APP_NAME" +# we may also want to set -Xdock:image +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRIFFON_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRIFFON_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRIFFON_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRIFFON_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GriffonWrapperMain "$@" diff --git a/gui/griffonw.bat b/gui/griffonw.bat new file mode 100644 index 0000000..16100b0 --- /dev/null +++ b/gui/griffonw.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Griffon startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRIFFON_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\wrapper\griffon-wrapper.jar + +@rem Execute Griffon +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRIFFON_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GriffonWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRIFFON_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRIFFON_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/gui/keystore.jks b/gui/keystore.jks new file mode 100644 index 0000000..642d21b Binary files /dev/null and b/gui/keystore.jks differ diff --git a/gui/lib/commons-beanutils-1.8.0.jar b/gui/lib/commons-beanutils-1.8.0.jar new file mode 100644 index 0000000..caf7ae3 Binary files /dev/null and b/gui/lib/commons-beanutils-1.8.0.jar differ diff --git a/gui/lib/commons-codec-1.4.jar b/gui/lib/commons-codec-1.4.jar new file mode 100644 index 0000000..458d432 Binary files /dev/null and b/gui/lib/commons-codec-1.4.jar differ diff --git a/gui/lib/commons-collections-3.2.1.jar b/gui/lib/commons-collections-3.2.1.jar new file mode 100644 index 0000000..c35fa1f Binary files /dev/null and b/gui/lib/commons-collections-3.2.1.jar differ diff --git a/gui/lib/commons-lang-2.4.jar b/gui/lib/commons-lang-2.4.jar new file mode 100644 index 0000000..532939e Binary files /dev/null and b/gui/lib/commons-lang-2.4.jar differ diff --git a/gui/lib/ezmorph-1.0.6.jar b/gui/lib/ezmorph-1.0.6.jar new file mode 100644 index 0000000..30fad12 Binary files /dev/null and b/gui/lib/ezmorph-1.0.6.jar differ diff --git a/gui/lib/http-builder-0.5.1.jar b/gui/lib/http-builder-0.5.1.jar new file mode 100644 index 0000000..47aa035 Binary files /dev/null and b/gui/lib/http-builder-0.5.1.jar differ diff --git a/gui/lib/httpclient-4.1.1.jar b/gui/lib/httpclient-4.1.1.jar new file mode 100644 index 0000000..c845ef9 Binary files /dev/null and b/gui/lib/httpclient-4.1.1.jar differ diff --git a/gui/lib/httpclient-cache-4.1.1.jar b/gui/lib/httpclient-cache-4.1.1.jar new file mode 100644 index 0000000..3e1da08 Binary files /dev/null and b/gui/lib/httpclient-cache-4.1.1.jar differ diff --git a/gui/lib/httpcore-4.1.jar b/gui/lib/httpcore-4.1.jar new file mode 100644 index 0000000..a357c07 Binary files /dev/null and b/gui/lib/httpcore-4.1.jar differ diff --git a/gui/lib/httpmime-4.1.1.jar b/gui/lib/httpmime-4.1.1.jar new file mode 100644 index 0000000..01af40b Binary files /dev/null and b/gui/lib/httpmime-4.1.1.jar differ diff --git a/gui/lib/jcalendar-1.3.2.jar b/gui/lib/jcalendar-1.3.2.jar new file mode 100755 index 0000000..b5e5a2d Binary files /dev/null and b/gui/lib/jcalendar-1.3.2.jar differ diff --git a/gui/lib/jcl-over-slf4j-1.6.1.jar b/gui/lib/jcl-over-slf4j-1.6.1.jar new file mode 100644 index 0000000..79e1ec2 Binary files /dev/null and b/gui/lib/jcl-over-slf4j-1.6.1.jar differ diff --git a/gui/lib/jdb-util-1.1.jar b/gui/lib/jdb-util-1.1.jar new file mode 100644 index 0000000..94962af Binary files /dev/null and b/gui/lib/jdb-util-1.1.jar differ diff --git a/gui/lib/json-lib-2.3-jdk15.jar b/gui/lib/json-lib-2.3-jdk15.jar new file mode 100644 index 0000000..29d59b9 Binary files /dev/null and b/gui/lib/json-lib-2.3-jdk15.jar differ diff --git a/gui/lib/logback-classic-0.9.26.jar b/gui/lib/logback-classic-0.9.26.jar new file mode 100644 index 0000000..b900b64 Binary files /dev/null and b/gui/lib/logback-classic-0.9.26.jar differ diff --git a/gui/lib/logback-core-0.9.26.jar b/gui/lib/logback-core-0.9.26.jar new file mode 100644 index 0000000..d50f3cd Binary files /dev/null and b/gui/lib/logback-core-0.9.26.jar differ diff --git a/gui/lib/miglayout-3.7.1-swing.jar b/gui/lib/miglayout-3.7.1-swing.jar new file mode 100644 index 0000000..5a762c8 Binary files /dev/null and b/gui/lib/miglayout-3.7.1-swing.jar differ diff --git a/gui/lib/nekohtml-1.9.9.jar b/gui/lib/nekohtml-1.9.9.jar new file mode 100644 index 0000000..2e06271 Binary files /dev/null and b/gui/lib/nekohtml-1.9.9.jar differ diff --git a/gui/lib/signpost-commonshttp4-1.2.1.1.jar b/gui/lib/signpost-commonshttp4-1.2.1.1.jar new file mode 100644 index 0000000..e8dae4d Binary files /dev/null and b/gui/lib/signpost-commonshttp4-1.2.1.1.jar differ diff --git a/gui/lib/signpost-core-1.2.1.1.jar b/gui/lib/signpost-core-1.2.1.1.jar new file mode 100644 index 0000000..86e9dac Binary files /dev/null and b/gui/lib/signpost-core-1.2.1.1.jar differ diff --git a/gui/lib/slf4j-api-1.6.1.jar b/gui/lib/slf4j-api-1.6.1.jar new file mode 100644 index 0000000..42e0ad0 Binary files /dev/null and b/gui/lib/slf4j-api-1.6.1.jar differ diff --git a/gui/lib/smack.jar b/gui/lib/smack.jar new file mode 100644 index 0000000..73d676a Binary files /dev/null and b/gui/lib/smack.jar differ diff --git a/gui/lib/smackx-jingle.jar b/gui/lib/smackx-jingle.jar new file mode 100644 index 0000000..ae044e4 Binary files /dev/null and b/gui/lib/smackx-jingle.jar differ diff --git a/gui/lib/smackx.jar b/gui/lib/smackx.jar new file mode 100644 index 0000000..ad73bed Binary files /dev/null and b/gui/lib/smackx.jar differ diff --git a/gui/lib/timestamper-lib-1.5.jar b/gui/lib/timestamper-lib-1.5.jar new file mode 100644 index 0000000..ae4810d Binary files /dev/null and b/gui/lib/timestamper-lib-1.5.jar differ diff --git a/gui/lib/xercesImpl-2.8.1.jar b/gui/lib/xercesImpl-2.8.1.jar new file mode 100644 index 0000000..3b351f6 Binary files /dev/null and b/gui/lib/xercesImpl-2.8.1.jar differ diff --git a/gui/lib/xml-apis-1.3.04.jar b/gui/lib/xml-apis-1.3.04.jar new file mode 100644 index 0000000..d42c0ea Binary files /dev/null and b/gui/lib/xml-apis-1.3.04.jar differ diff --git a/gui/lib/xml-resolver-1.2.jar b/gui/lib/xml-resolver-1.2.jar new file mode 100644 index 0000000..e535bdc Binary files /dev/null and b/gui/lib/xml-resolver-1.2.jar differ diff --git a/gui/src/main/com/jdblabs/timestamper/gui/GUIUtil.groovy b/gui/src/main/com/jdblabs/timestamper/gui/GUIUtil.groovy new file mode 100644 index 0000000..7d9710c --- /dev/null +++ b/gui/src/main/com/jdblabs/timestamper/gui/GUIUtil.groovy @@ -0,0 +1,132 @@ +package com.jdblabs.timestamper.gui + +import java.awt.Point +import java.awt.Rectangle +import java.awt.Toolkit +import java.awt.event.MouseEvent + +public class GUIUtil { + + static Point calculateWindowMovement(Point currentMousePoint, + Point mousePressRelativeToWindow, Rectangle windowBounds, + Rectangle... snapBoxes) { + + // this is the point we will compute as the new upper left + // coordinate of the frame. It needs to be translated some to account + // for the fact that the user can press the mouse anywhere on the + // main panel. + Point currentWindowPoint = (Point) currentMousePoint.clone(); + // find out where the new point should be, ignoreing screen bounds + currentWindowPoint.translate((int) -mousePressRelativeToWindow.x, + (int) -mousePressRelativeToWindow.y); + + Point finalWindowPoint = (Point) currentWindowPoint.clone(); + + // snap tests. In the event of a conflict in snaps positions, the + // last snap wins + int wUp = windowBounds.y; + int wDown = windowBounds.y + windowBounds.height; + int wLeft = windowBounds.x; + int wRight = windowBounds.x + windowBounds.width; + +// currentTaskLabel.setText("U:" + wUp + " D:" + wDown + " L:" + wLeft +// + " R:" + wRight); + + for (Rectangle r : snapBoxes) { + int rUp = r.y; + int rDown = r.y + r.height; + int rLeft = r.x; + int rRight = r.x + r.width; + + // check to see if the window is near any of the snap boundaries + // if it is, 'snap' the final point to that boundary. + if (Math.abs(rUp - wUp) < 20) // top of window to top of rect + finalWindowPoint.y = rUp; + else if (Math.abs(rUp - wDown) < 20) // bot of w to top of r + finalWindowPoint.y = rUp - windowBounds.height; + else if (Math.abs(rDown - wUp) < 20) // top of w to bot of r + finalWindowPoint.y = rDown; + else if (Math.abs(rDown - wDown) < 20) // bot of w to bot of r + finalWindowPoint.y = rDown - windowBounds.height; + + if (Math.abs(rLeft - wLeft) < 20) // left of w to left of r + finalWindowPoint.x = rLeft; + else if (Math.abs(rLeft - wRight) < 20) // right of w to left of r + finalWindowPoint.x = rLeft - windowBounds.width; + else if (Math.abs(rRight - wLeft) < 20) // left of w to right of r + finalWindowPoint.x = rRight; + else if (Math.abs(rRight - wRight) < 20) // right of w to right of r + finalWindowPoint.x = rRight - windowBounds.width; + } + + // this point represents a backwards version of the initial calculation + // to find the finalPoint. It says, based on the current final point, + // assume I moved the frame to that point. Where, relative to that point + // should the mouse be, based on how far it was relative to the point + // when the user pressed it. + Point whereMouseShouldBe = (Point) finalWindowPoint.clone(); + whereMouseShouldBe.translate((int) mousePressRelativeToWindow.x, + (int) mousePressRelativeToWindow.y); + + // if the actual mouse location is different from the expected location, + // then we know that the snapping behaviour has altered the frames new + // placement. If this alteration is too large (30 px apart in this case) + // then we know the user is trying to pull the frame out of its snapped + // position. In this case, we want to ignore the snap calculations and + // base the new frame location entirely on the current mouse location + if (whereMouseShouldBe.distance(currentMousePoint) > 30) { + finalWindowPoint = (Point) currentMousePoint.clone(); + finalWindowPoint.translate((int) -mousePressRelativeToWindow.x, + (int) -mousePressRelativeToWindow.y); + } + + return finalWindowPoint; + } + + 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 + } +} diff --git a/gui/src/main/com/jdblabs/timestamper/gui/TimelineDayDisplay.java b/gui/src/main/com/jdblabs/timestamper/gui/TimelineDayDisplay.java new file mode 100644 index 0000000..031d2e4 --- /dev/null +++ b/gui/src/main/com/jdblabs/timestamper/gui/TimelineDayDisplay.java @@ -0,0 +1,714 @@ +/* TimelineDayDisplay.java */ + +package com.jdblabs.timestamper.gui; + +import com.jdblabs.timestamper.core.TimelineMarker; +import com.jdblabs.timestamper.core.Timeline; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.geom.Rectangle2D; +import java.beans.PropertyChangeSupport; +import java.beans.PropertyChangeListener; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.Iterator; +import javax.swing.JComponent; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +/** + * @author Jonathan Bernard (jdbernard@gmail.com) + */ +public class TimelineDayDisplay extends JComponent implements MouseListener, + ChangeListener { + + private ArrayList markerEntries; + private ArrayList timeLegendLocations; + private ArrayList changeListeners = new ArrayList(); + + private PropertyChangeSupport pcs = new PropertyChangeSupport(this); + + private Timeline timeline; + private TimelineMarker currentMarker; + + private Point lastMousePress; + + private Font markFont;// = getFont().deriveFont(Font.BOLD); + private Font notesFont;// = getFont(); + + private Color evenTrans = new Color(0.75f, 0.75f, 0.75f, 0.4f); + private Color evenOpaque = new Color(0.75f, 0.75f, 0.75f, 1f); + private Color oddTrans = new Color(0.5f, 0.5f, 0.5f, 0.4f); + private Color oddOpaque = new Color(0.5f, 0.5f, 0.5f, 1f); + private Color selectedTrans = new Color(0.5f, 0.75f, 0.5f, 0.4f); + private Color selectedOpaque = new Color(0.5f, 0.75f, 0.5f, 1f); + private Color fontColor = new Color(0.1f, 0.1f, 0.1f, 1f); + + private Date rangeStartDate = new Date(); + private Date rangeEndDate = new Date(); + + private class MarkerDisplayEntry { + public TimelineMarker marker; + public float relY; + public float relHeight; + public Rectangle2D markBounds; + public Rectangle2D notesBounds; + public Rectangle bounds; + } + + private class TimeLegendEntry { + public double relY; + public String label; + } + + private enum TimeDelta { + Hourly (Calendar.HOUR_OF_DAY, 1) { + public String formatCalendar(Calendar c) { + return String.format("%1$02d:00", + c.get(Calendar.HOUR_OF_DAY)); + } + + public boolean fitsInHeight(double height, double millisec) { + return ((height * 1000l * 60l * 30l) / millisec < 25); + } + }, + ThirtyMin (Calendar.MINUTE, 30) { + public String formatCalendar(Calendar c) { + return String.format("%1$02d:%2$02d", + c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE)); + } + + public boolean fitsInHeight(double height, double millisec) { + return ((height * 1000l * 60l * 15l) / millisec < 25); + } + }, + FifteenMin (Calendar.MINUTE, 15) { + public String formatCalendar(Calendar c) { + return String.format("%1$02d:%2$02d", + c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE)); + } + + public boolean fitsInHeight(double height, double millisec) { + return ((height * 1000l * 60l * 10l) / millisec < 25); + } + }, + TenMin (Calendar.MINUTE, 10) { + public String formatCalendar(Calendar c) { + return String.format("%1$02d:%2$02d", + c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE)); + } + + public boolean fitsInHeight(double height, double millisec) { + return ((height * 1000l * 60l * 5l) / millisec < 25); + } + }, + FiveMin (Calendar.MINUTE, 5) { + public String formatCalendar(Calendar c) { + return String.format("%1$02d:%2$02d", + c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE)); + } + + public boolean fitsInHeight(double height, double millisec) { + return ((height * 1000l * 60l) / millisec < 25); + } + }, + Minute (Calendar.MINUTE, 1) { + public String formatCalendar(Calendar c) { + return String.format("%1$02d:%2$02d", + c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE)); + } + + public boolean fitsInHeight(double height, double millisec) { + return ((height * 1000l * 30l) / millisec < 25); + } + }, + ThirtySec (Calendar.SECOND, 30) { + public String formatCalendar(Calendar c) { + return String.format("%1$02d:%2$02d", + c.get(Calendar.MINUTE), c.get(Calendar.SECOND)); + } + + public boolean fitsInHeight(double height, double millisec) { + return ((height * 1000l * 15l) / millisec < 25); + } + }, + FifteenSec (Calendar.SECOND, 15) { + public String formatCalendar(Calendar c) { + return String.format("%1$02d:%2$02d", + c.get(Calendar.MINUTE), c.get(Calendar.SECOND)); + } + + public boolean fitsInHeight(double height, double millisec) { + return ((height * 1000l * 10l) / millisec < 25); + } + }, + TenSec (Calendar.SECOND, 10) { + public String formatCalendar(Calendar c) { + return String.format("%1$02d:%2$02d", + c.get(Calendar.MINUTE), c.get(Calendar.SECOND)); + } + + public boolean fitsInHeight(double height, double millisec) { + return ((height * 1000l * 5l) / millisec < 25); + } + }, + FiveSec (Calendar.SECOND, 5) { + public String formatCalendar(Calendar c) { + return String.format("%1$02d:%2$02d", + c.get(Calendar.MINUTE), c.get(Calendar.SECOND)); + } + + public boolean fitsInHeight(double height, double millisec) { + return ((height * 1000l) / millisec < 25); + } + }, + Second (Calendar.SECOND, 1) { + public String formatCalendar(Calendar c) { + return String.format("%1$02d:%2$02d", + c.get(Calendar.MINUTE), c.get(Calendar.SECOND)); + } + + public boolean fitsInHeight(double height, double millisec) { + return ((height * 1500l) / millisec < 25); + } + }, + SubSecond (Calendar.MILLISECOND, 100) { + public String formatCalendar(Calendar c) { + return String.format("%1$02d:%2$03d", + c.get(Calendar.SECOND), c.get(Calendar.MILLISECOND)); + } + + public boolean fitsInHeight(double height, double millisec) { + return true; + } + }; + + private int INTERVAL; + private int AMOUNT; + + private TimeDelta(int interval, int amount) { + INTERVAL = interval; + AMOUNT = amount; + } + + public Calendar addToCalendar(Calendar c) { + c.add(INTERVAL, AMOUNT); + return c; + } + + public abstract boolean fitsInHeight(double height, double millisec); + + public abstract String formatCalendar(Calendar c); { } + } + + + public TimelineDayDisplay() { + this(null, Calendar.getInstance()); + } + + public TimelineDayDisplay(Timeline t) { + this(t, Calendar.getInstance()); + } + + public TimelineDayDisplay(Timeline t, Calendar day) { + super(); + setDay(day.getTime(), false); + addMouseListener(this); + this.timeline = t; + updateMarkers(getGraphics()); + } + + public void addPropertyChangeListener(PropertyChangeListener l) { + pcs.addPropertyChangeListener(l); + } + + public void addPropertyChangeListener(String propertyName, + PropertyChangeListener l) { + pcs.addPropertyChangeListener(propertyName, l); + } + + public void removePropertyChangeListener(PropertyChangeListener l) { + pcs.removePropertyChangeListener(l); + } + + public Timeline getTimeline() { return timeline; } + + public void setTimeline(Timeline t) { + if (timeline == t) return; + pcs.firePropertyChange("timeline", timeline, timeline = t); + updateMarkers(getGraphics()); + repaint(); + } + + /** + * Set the range for the visible timeline segment. + * @param start The beginning of the desired timeline segment. + * @param end The end of the desired timeline segment. + */ + public void setDisplayInterval(Date start, Date end) { + if (start == rangeStartDate && end == rangeEndDate) return; + pcs.firePropertyChange("rangeStart", rangeStartDate, rangeStartDate = start); + pcs.firePropertyChange("rangeEnd", rangeEndDate, rangeEndDate = end); + } + + /** + * Set the component to show the timeline segment for a specific day. The + * visible area will show the full 24-hour day. + * @param d The date of the day to display. The exact time of the variable + * can be any time in the desired day. + */ + public void setDay(Date d) { + setDay(d, true); + } + + /** + * There is the special case of instance initialization, where it is + * desirable to call setDay to handle the range start and end calculations + * but where we do not want to immediately update the gui, because it may + * not be fully initialized yet. + * @param d Day to set as the current day (component will show the range + * representing the day from start to finish. + * @param update If
true
, + * updateMarkers(getGraphics) is called after the range + * calculations are made. + */ + private void setDay(Date d, boolean update) { + Calendar day = Calendar.getInstance(); + day.setTime(d); + day.set(Calendar.HOUR_OF_DAY, 0); + day.set(Calendar.MINUTE, 0); + day.set(Calendar.SECOND, 0); + pcs.firePropertyChange("rangeStart", rangeStartDate, rangeStartDate = day.getTime()); + + day.add(Calendar.DAY_OF_YEAR, 1); + pcs.firePropertyChange("rangeEnd", rangeEndDate, rangeEndDate = day.getTime()); + + if (update) updateMarkers(getGraphics()); + } + + /** + * Get the starting point for the display range. + * @return The starting {@link java.util.Date} for the display range. + */ + public Date getRangeStart() { return rangeStartDate; } + + /** + * Get the ending point for the display range. + * @return The ending {@link java.util.Date} for the display range. + */ + public Date getRangeEnd() { return rangeEndDate; } + + /** + * Set the font used for displaying the name of the entry (more precisely: + * {@link com.jdblabs.timestamper.core.TimelineMarker#mark}). + * @param f The font to use. + */ + public void setMarkFont(Font f) { + if (markFont == f) return; + pcs.firePropertyChange("markFont", markFont, markFont = f); + repaint(); + } + + public Font getMarkFont() { return markFont; } + + public void setNotesFont(Font f) { + if (notesFont == f) return; + pcs.firePropertyChange("notesFont", notesFont, notesFont = f); + repaint(); + } + + public Font getNotesFont() { return notesFont; } + + public void setFontColor(Color f) { + if (fontColor == f) return; + pcs.firePropertyChange("fontColor", fontColor, + fontColor = new Color(f.getRGB())); + repaint(); + } + + public Color getFontColor() { return fontColor; } + + public void setEvenColor(Color c) { + if (evenOpaque == c) return; + evenTrans = new Color((float) c.getRed() / 255f, + (float) c.getGreen() / 255f, + (float) c.getBlue() / 255f, 0.4f); + + pcs.firePropertyChange("evenColor", evenOpaque, + evenOpaque = new Color(c.getRGB())); + repaint(); + } + + public Color getEvenColor() { + return evenOpaque; + } + + public void setOddColor(Color c) { + if (oddOpaque == c) return; + oddTrans = new Color((float) c.getRed() / 255f, + (float) c.getGreen() / 255f, + (float) c.getBlue() / 255f, 0.4f); + + pcs.firePropertyChange("oddColor", oddOpaque, + oddOpaque = new Color(c.getRGB())); + repaint(); + } + + public Color getOddColor() { + return oddOpaque; + } + + public void setSelectedColor(Color c) { + if (selectedOpaque == c) return; + selectedTrans = new Color((float) c.getRed() / 255f, + (float) c.getGreen() / 255f, + (float) c.getBlue() / 255f, 0.4f); + pcs.firePropertyChange("selectedColor", selectedOpaque, + selectedOpaque = new Color(c.getRGB())); + repaint(); + } + + public Color getSelectedColor() { + return selectedOpaque; + } + + public TimelineMarker getSelectedTimelineMarker() { + return currentMarker; + } + + public void updateSelectedMarker(String notes) { + currentMarker.setNotes(notes); + updateMarkers(getGraphics()); + } + + /** + * updateMarkers sets the internal list of TimelineMarkers, based on the + * currently visible timeline. The drawing of the display is split between + * this method, which constructs the data representation of what needs to + * be drawn, and the paintComponents method, which does the drawing. This is + * done to save computation, only recalculating markers when needed. + */ + private void updateMarkers(Graphics g) { + + if (timeline == null) return; + + Insets insets = this.getInsets(); + Rectangle bounds = this.getBounds(); + Rectangle canvasBounds = new Rectangle(insets.left, insets.top, + bounds.width - insets.left - insets.right - 1, + bounds.height - insets.top - insets.bottom - 1); + + Rectangle2D stringBounds = getFontMetrics(getFont()).getStringBounds("00:00 ", g); + + long rangeDiff = rangeEndDate.getTime() - rangeStartDate.getTime(); + + markerEntries = new ArrayList(); + timeLegendLocations = new ArrayList(); + + if (markFont == null) markFont = getFont().deriveFont(Font.BOLD); + if (notesFont == null) notesFont = getFont(); + + // calculate positions of all visible hour lines + // choose the increment of time to view + TimeDelta timeDelta = TimeDelta.Hourly; + if (rangeDiff == 0) rangeDiff = 1; + + for (TimeDelta d : TimeDelta.values()) { + if (d.fitsInHeight(canvasBounds.getHeight(), rangeDiff)) { + timeDelta = d; + break; + } + } + + Calendar timeCounter = Calendar.getInstance(); + timeCounter.setTime(rangeStartDate); + timeCounter.set(Calendar.MINUTE, 0); + timeCounter.set(Calendar.SECOND, 0); + + while (rangeStartDate.after(timeCounter.getTime())) + timeDelta.addToCalendar(timeCounter); + + while (rangeEndDate.after(timeCounter.getTime())) { + TimeLegendEntry entry = new TimeLegendEntry(); + entry.relY = ((double) (timeCounter.getTimeInMillis() + - rangeStartDate.getTime()) / (double) rangeDiff); + entry.label = timeDelta.formatCalendar(timeCounter); + timeLegendLocations.add(entry); + timeDelta.addToCalendar(timeCounter); + } + + // get all relevant markers starting from the marker just before the + // visible start of the display + TimelineMarker tm = timeline.getLastMarker(rangeStartDate); + + // If there is no previous marker + if (tm == null) + // try to get the first marker + try { tm = timeline.iterator().next(); } + // and if there aren't any markers at all, just return, the array is + // empty so the display will be empty + catch (Exception e) { return; } + + // Now we want to step through the timeline, capturing all markers + // between the visible ranges. + Iterator itr = timeline.iterator(); + + while (!itr.next().equals(tm)); + + ArrayList markers = new ArrayList(); + while (rangeEndDate.after(tm.getTimestamp())) { + markers.add(tm); + if (itr.hasNext()) tm = itr.next(); + else break; + } + + markers.add(tm); + + for (int i = 0; i < markers.size() - 1; i++) { + MarkerDisplayEntry markerEntry = new MarkerDisplayEntry(); + + markerEntry.marker = markers.get(i); + + // set string bounds + markerEntry.markBounds = getFontMetrics(markFont) + .getStringBounds(markers.get(i).getMark(), g); + markerEntry.notesBounds = getFontMetrics(notesFont) + .getStringBounds(markers.get(i).getNotes(), g); + + // calculate upper bound + if ((i == 0) && rangeStartDate.after(markerEntry.marker.getTimestamp())) { + //if this is the first marker (before the start time) set the + // Y coor to 0, top of display + markerEntry.relY = 0; + } else { + // otherwise, calculate how far down (%-wise) the mark is + markerEntry.relY = (float) (((double) (markerEntry.marker.getTimestamp().getTime() + - rangeStartDate.getTime())) / (double) rangeDiff); + } + + // calculate lower bound + if ((i == 0) && rangeStartDate.after(markerEntry.marker.getTimestamp())) + // if this is the first marker (before the start time), set the + // height to equal the top of the next marker + markerEntry.relHeight = + markers.get(i + 1).getTimestamp().getTime() + - rangeStartDate.getTime(); + else if (i == markers.size() - 2) + // if this is the last visible marker, set the height to extend + // to the bottom of the display + markerEntry.relHeight = rangeEndDate.getTime() + - markerEntry.marker.getTimestamp().getTime(); + else + // set the height to the difference between this marker and the + // next. + markerEntry.relHeight = + markers.get(i + 1).getTimestamp().getTime() + - markerEntry.marker.getTimestamp().getTime(); + markerEntry.relHeight /= rangeDiff; + + markerEntries.add(markerEntry); + } + repaint(); + } + + @Override + public void paintComponent(Graphics g) { + removeAll(); + + if (timeline == null) return; + + if (markerEntries == null) updateMarkers(g); + + Insets insets = this.getInsets(); + Rectangle bounds = this.getBounds(); + Rectangle canvasBounds = new Rectangle(insets.left, insets.top, + bounds.width - insets.left - insets.right - 1, + bounds.height - insets.top - insets.bottom - 1); + double hourHeight = canvasBounds.getHeight() / 24.0; + + Graphics2D g2d = (Graphics2D) g; + Rectangle2D stringBounds = getFontMetrics(getFont()).getStringBounds("00:00 ", g); + + // draw hour lines + for (TimeLegendEntry legendEntry : timeLegendLocations) { + g.drawLine(canvasBounds.x + (int) stringBounds.getWidth(), + (int) (canvasBounds.y + (canvasBounds.height * legendEntry.relY)), + canvasBounds.x + canvasBounds.width, + (int) (canvasBounds.y + (canvasBounds.height * legendEntry.relY))); + + g.drawString(legendEntry.label, canvasBounds.x + 2, + (int) (canvasBounds.y + (canvasBounds.height * legendEntry.relY) + + (stringBounds.getHeight() / 2))); + } + + for (int i = 0; i < markerEntries.size(); i++) { + + MarkerDisplayEntry curEntry = markerEntries.get(i); + + Rectangle2D markBounds; + Rectangle2D notesBounds; + + boolean selected = curEntry.marker.equals(currentMarker); + + // if i == 0, this is the default + curEntry.bounds = new Rectangle(); + curEntry.bounds.y = 3; + curEntry.bounds.x = canvasBounds.x + (int) stringBounds.getWidth() + 5; + curEntry.bounds.height = 1; + curEntry.bounds.width = canvasBounds.width - (int) stringBounds.getWidth() - 8; + + double relTime; + + // calculate upper bound + curEntry.bounds.y = (int) Math.round(curEntry.relY + * canvasBounds.getHeight()); + + if (i == 0) curEntry.bounds.y += 3; + + // calculate lower bound + curEntry.bounds.height = (int) Math.round(curEntry.relHeight + * canvasBounds.getHeight()); + + if (i ==0) curEntry.bounds.height -= 6; + else curEntry.bounds.height -= 3; + + // draw box + if (selected) g.setColor(selectedTrans); + else g.setColor((i % 2 == 0 ? evenTrans : oddTrans)); + g.fillRect(curEntry.bounds.x, curEntry.bounds.y, curEntry.bounds.width, curEntry.bounds.height); + + if (selected) g.setColor(selectedOpaque); + else g2d.setColor((i % 2 == 0 ? evenOpaque : oddOpaque)); + g2d.setStroke(new BasicStroke(3f)); + g2d.drawRect(curEntry.bounds.x, curEntry.bounds.y, curEntry.bounds.width, curEntry.bounds.height); + + // draw timestamp name + markBounds = (Rectangle2D) curEntry.markBounds.clone(); + markBounds.setRect(curEntry.bounds.x + 3, + curEntry.bounds.y + stringBounds.getHeight(), + markBounds.getWidth(), markBounds.getHeight()); + + g.setColor(fontColor); + g.setFont(markFont); + g.drawString(curEntry.marker.getMark(), + (int) markBounds.getX(), (int) markBounds.getY()); + + // draw notes + notesBounds = (Rectangle2D) curEntry.notesBounds.clone(); + notesBounds.setRect(curEntry.bounds.x + 6, + curEntry.bounds.y + stringBounds.getHeight() + markBounds.getHeight(), + notesBounds.getWidth(), notesBounds.getHeight()); + + if (curEntry.bounds.contains(notesBounds)) { + g.setFont(notesFont); + g.drawString(curEntry.marker.getNotes(), + (int) notesBounds.getX(), (int) notesBounds.getY()); + } + } + + g.setColor(Color.BLACK); + g.drawRect(canvasBounds.x, canvasBounds.y, canvasBounds.width, canvasBounds.height); + } + + public void addChangeListener(ChangeListener cl) { + changeListeners.add(cl); + } + + public boolean removeChangeListener(ChangeListener cl) { + return changeListeners.remove(cl); + } + + private void fireChangeEvent() { + for (ChangeListener cl : changeListeners) + cl.stateChanged(new ChangeEvent(this)); + } + + public void mouseClicked(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) { + Point topLeft = getLocationOnScreen(); + currentMarker = null; + for (MarkerDisplayEntry markerEntry : markerEntries) { + Rectangle absBounds = new Rectangle(markerEntry.bounds); + absBounds.translate(topLeft.x, topLeft.y); + + // should only match one entry + if (absBounds.contains(e.getLocationOnScreen())) { + pcs.firePropertyChange("selectedTimelineMarker", + currentMarker, currentMarker = markerEntry.marker); + break; + } + } + repaint(); + fireChangeEvent(); + } else if (e.getButton() == MouseEvent.BUTTON3) { + setDay(rangeStartDate); + } + } + + public void mousePressed(MouseEvent e) { + lastMousePress = e.getPoint(); + } + + public void mouseReleased(MouseEvent e) { + Insets insets = this.getInsets(); + Rectangle bounds = this.getBounds(); + Rectangle canvasBounds = new Rectangle(insets.left, insets.top, + bounds.width - insets.left - insets.right - 1, + bounds.height - insets.top - insets.bottom - 1); + + double rangeDiff = rangeEndDate.getTime() - rangeStartDate.getTime(); + double y1 = lastMousePress.getY(); + double y2 = e.getY(); + + if (Math.abs(y2 - y1) < 5) return; + + // get time for y1 + long time1 = (long) Math.round((((y1 - canvasBounds.y) + / canvasBounds.height) * rangeDiff) + rangeStartDate.getTime()); + long time2 = (long) Math.round((((y2 - canvasBounds.y) + / canvasBounds.height) * rangeDiff) + rangeStartDate.getTime()); + + // left click, scroll + if (e.getButton() == MouseEvent.BUTTON1) { + long difference = time1 - time2; + rangeStartDate.setTime(rangeStartDate.getTime() + difference); + rangeEndDate.setTime(rangeEndDate.getTime() + difference); + } + // right click, zoom + else if (e.getButton() == MouseEvent.BUTTON3) { + if (time1 < time2) { + rangeStartDate.setTime(time1); + rangeEndDate.setTime(time2); + } else { + rangeStartDate.setTime(time2); + rangeEndDate.setTime(time1); + } + } + updateMarkers(getGraphics()); + } + + public void mouseEntered(MouseEvent e) { + } + + public void mouseExited(MouseEvent e) { + } + + public void stateChanged(ChangeEvent ce) { + updateMarkers(getGraphics()); + repaint(); + } + + public void setStateChanged(Object o) { + stateChanged(null); + } + +} diff --git a/gui/src/main/com/jdblabs/timestamper/gui/plugin/HookLogger.groovy b/gui/src/main/com/jdblabs/timestamper/gui/plugin/HookLogger.groovy new file mode 100644 index 0000000..1a02509 --- /dev/null +++ b/gui/src/main/com/jdblabs/timestamper/gui/plugin/HookLogger.groovy @@ -0,0 +1,30 @@ +package com.jdblabs.timestamper.gui.plugin + +import com.jdblabs.timestamper.core.TimelineMarker +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +public class HookLogger implements TimestamperPlugin { + + private Logger logger = LoggerFactory.getLogger(getClass()) + + public void onStartup(Map mvc) { + logger.info("HookLogger: onStartup() called.") + } + + public void onExit(Map mvc) { + logger.info("HookLogger: onExit() called.") + } + + public File onTimelineLoad(Map mvc, File file) { + logger.info("HookLogger: onTimelineLoad() called with ${file.canonicalPath}") + } + + public TimelineMarker onNewTask(Map mvc, TimelineMarker tm) { + logger.info("HookLogger: onNewTask() called with ${tm}") + } + + public void onDeleteTask(Map mvc, TimelineMarker tm) { + logger.info("HookLogger: onDeleteTask() called with ${tm}") + } +} diff --git a/gui/src/main/com/jdblabs/timestamper/gui/plugin/TimestamperPlugin.java b/gui/src/main/com/jdblabs/timestamper/gui/plugin/TimestamperPlugin.java new file mode 100644 index 0000000..41f6a14 --- /dev/null +++ b/gui/src/main/com/jdblabs/timestamper/gui/plugin/TimestamperPlugin.java @@ -0,0 +1,57 @@ +package com.jdblabs.timestamper.gui.plugin; + +import java.io.File; +import java.util.Map; +import com.jdblabs.timestamper.core.TimelineMarker; + +public interface TimestamperPlugin { + + /** + * Called before the GUI loads a new timeline properties file. This method + * allows you to perform an action before a timeline properties file is + * loaded, or to change the file that will be loaded by returning a new + * File object. + * @param mainMVC Map of the model, view, and controller objects for the + * timestamper main GUI. + * @param propertyFile The file that will be loaded. + * @return The property file to load (often the same as the one passed in) + */ + File onTimelineLoad(Map mainMVC, File propertyFile); + + /** + * Called after the GUI is initialized but before it is displayed. + * @param mainMVC map of the model, view, and controller objects for the + * timestamper main GUI. + */ + void onStartup(Map mainMVC); + + /** + * Called before the GUI exits. This is a best-attempt call, since the OS + * may force-terminate the application before it has a chance to be called. + * Long-running operations should not be performed in this call, as some + * OSes may impatiently terminate the application if it thinks it has hung. + * @param mainMVC map of the model, view, and controller objects for the + * timestamper main GUI. + */ + void onExit(Map mainMVC); + + /** + * Called before the GUI adds a new marker to the timeline. + * This allows you to perform some action when a new marker is created, + * modify the marker, or return an entirely new marker. + * @param mainMVC map of the model, view, and controller objects for the + * timestamper main GUI. + * @param newMarker The new TimelineMarker to be added to the timeline. + * @return The timeline marker to add to the timeline (often the same + * marker passed in). + */ + TimelineMarker onNewTask(Map mainMVC, TimelineMarker newMarker); + + /** + * Called before the GUI deletes a marker from the timeline. + * @param mainMVC map of the model, view, and controller objects for the + * timestamper main GUI. + * @param marker The TimelineMarker to be deleted. + */ + void onDeleteTask(Map mainMVC, TimelineMarker marker); +} diff --git a/gui/src/main/com/jdblabs/timestamper/gui/plugin/XMPPStatusUpdater.groovy b/gui/src/main/com/jdblabs/timestamper/gui/plugin/XMPPStatusUpdater.groovy new file mode 100644 index 0000000..8b5bbf9 --- /dev/null +++ b/gui/src/main/com/jdblabs/timestamper/gui/plugin/XMPPStatusUpdater.groovy @@ -0,0 +1,56 @@ +package com.jdblabs.timestamper.gui.plugin + +import com.jdblabs.timestamper.core.TimelineMarker +import org.jivesoftware.smack.ConnectionConfiguration +import org.jivesoftware.smack.XMPPConnection +import org.jivesoftware.smack.packet.Presence +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +public class XMPPStatusUpdater implements TimestamperPlugin { + + XMPPConnection conn + private Logger logger = LoggerFactory.getLogger(getClass()) + + public void onStartup(Map mainMVC) { + + logger.trace("Starting XMPPStatusUpdater plugin") + + String server = mainMVC.model.config."xmpp.server" + int port = mainMVC.model.config.getProperty("xmpp.port", 5222) + String username = mainMVC.model.config."xmpp.username" + String password = mainMVC.model.config."xmpp.password" + + try { + conn = new XMPPConnection(new ConnectionConfiguration(server, port)) + conn.connect() + conn.login(username, password, "timestamper-xmpp-plugin") + } catch (Exception e) { + logger.error("Unable to initialize XMPPUpdater.", e) + conn = null + } + } + + public void onExit(Map mainMVC) { + logger.trace("Stopping XMPPStatusUpdater plugin") + + try { conn.disconnect() } catch (Exception e) {} + } + + public File onTimelineLoad(Map mainMVC, File propFile) {} + + public TimelineMarker onNewTask(Map mainMVC, TimelineMarker newTask) { + if (!conn) { + logger.info("XMPPStatusUpdater is not initialized, " + + "skipping onNewTask()") + return newTask + } + + logger.trace("Setting XMPP presence based on new task: {}", newTask) + + conn.sendPacket(new Presence(Presence.Type.available, newTask.mark, + 0, Presence.Mode.available)) + } + + public void onDeleteTask(Map mainMVC, TimelineMarker task) {} +} diff --git a/gui/test/integration/LogDialogTests.groovy b/gui/test/integration/LogDialogTests.groovy new file mode 100644 index 0000000..b71965a --- /dev/null +++ b/gui/test/integration/LogDialogTests.groovy @@ -0,0 +1,10 @@ +import griffon.util.IGriffonApplication + +class LogDialogTests extends GroovyTestCase { + + IGriffonApplication app + + void testSomething() { + + } +} diff --git a/gui/test/integration/NotesDialogTests.groovy b/gui/test/integration/NotesDialogTests.groovy new file mode 100644 index 0000000..8eb01cc --- /dev/null +++ b/gui/test/integration/NotesDialogTests.groovy @@ -0,0 +1,10 @@ +import griffon.util.IGriffonApplication + +class NotesDialogTests extends GroovyTestCase { + + IGriffonApplication app + + void testSomething() { + + } +} diff --git a/gui/test/integration/PunchcardDialogTests.groovy b/gui/test/integration/PunchcardDialogTests.groovy new file mode 100644 index 0000000..c24f8df --- /dev/null +++ b/gui/test/integration/PunchcardDialogTests.groovy @@ -0,0 +1,10 @@ +import griffon.util.IGriffonApplication + +class PunchcardDialogTests extends GroovyTestCase { + + IGriffonApplication app + + void testSomething() { + + } +} diff --git a/gui/test/integration/TimeStamperMainTests.groovy b/gui/test/integration/TimeStamperMainTests.groovy new file mode 100644 index 0000000..22b85a2 --- /dev/null +++ b/gui/test/integration/TimeStamperMainTests.groovy @@ -0,0 +1,10 @@ +import griffon.util.IGriffonApplication + +class TimeStamperMainTests extends GroovyTestCase { + + IGriffonApplication app + + void testSomething() { + + } +} diff --git a/gui/test/integration/TimeStamperTests.groovy b/gui/test/integration/TimeStamperTests.groovy new file mode 100755 index 0000000..d5f9a32 --- /dev/null +++ b/gui/test/integration/TimeStamperTests.groovy @@ -0,0 +1,10 @@ +import griffon.util.IGriffonApplication + +class TimeStamperTests extends GroovyTestCase { + + IGriffonApplication app + + void testSomething() { + + } +} diff --git a/gui/wrapper/griffon-wrapper.jar b/gui/wrapper/griffon-wrapper.jar new file mode 100644 index 0000000..31f5031 Binary files /dev/null and b/gui/wrapper/griffon-wrapper.jar differ diff --git a/gui/wrapper/griffon-wrapper.properties b/gui/wrapper/griffon-wrapper.properties new file mode 100644 index 0000000..ad87f5e --- /dev/null +++ b/gui/wrapper/griffon-wrapper.properties @@ -0,0 +1,7 @@ +#Griffon 1.2.0 upgrade +#Thu Apr 25 06:40:33 CDT 2013 +distributionBase=GRIFFON_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRIFFON_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=http\://dist.codehaus.org/griffon/griffon-1.2.0-bin.zip