Restructured the project. Moving to multiple-source timelines

that can automatically sync with one another.
This commit is contained in:
Jonathan Bernard 2009-12-17 07:32:28 -06:00
parent 42d2d82c74
commit 89ad2ac447
40 changed files with 1898 additions and 1393 deletions

View File

@ -1 +1,4 @@
release
build
.*.swp
.*.swo

BIN
doc/feed.pdf Normal file

Binary file not shown.

77
doc/feed.rst Normal file
View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
build.xml.data.CRC32=6a978a17
build.xml.script.CRC32=6e5ad54e
build.xml.stylesheet.CRC32=be360661
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=52850847
nbproject/build-impl.xml.script.CRC32=adeac2b5
nbproject/build-impl.xml.stylesheet.CRC32=487672f9
build.xml.data.CRC32=6a978a17
build.xml.script.CRC32=6e5ad54e
build.xml.stylesheet.CRC32=be360661
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=618e720f
nbproject/build-impl.xml.script.CRC32=70e39602
nbproject/build-impl.xml.stylesheet.CRC32=5c621a33@1.26.2.45

View File

@ -1,7 +1,8 @@
compile.on.save=false
do.depend=false
do.jar=true
javac.debug=true
javadoc.preview=true
jaxws.endorsed.dir=C:\\Program Files\\NetBeans 6.5\\java2\\modules\\ext\\jaxws21\\api:C:\\Program Files\\NetBeans 6.5\\ide10\\modules\\ext\\jaxb\\api
user.properties.file=C:\\Documents and Settings\\jbernard\\.netbeans\\6.5\\build.properties
jaxws.endorsed.dir=C:\\Program Files\\NetBeans 6.7.1\\java2\\modules\\ext\\jaxws21\\api:C:\\Program Files\\NetBeans 6.7.1\\ide11\\modules\\ext\\jaxb\\api
user.properties.file=C:\\Documents and Settings\\jbernard\\.netbeans\\6.7\\build.properties
axis2.deploy.war=C:\\Program Files\\glassfish-v2ur2\\domains\\domain1\\autodeploy\\axis2.war

View File

@ -1,76 +1,77 @@
application.desc=Simple application used to track activities throughout time.
application.homepage=
application.title=TimeStamper
application.vendor=Jonathan Bernard
application.version=1.7
build.classes.dir=${build.dir}/classes
build.classes.excludes=**/*.java,**/*.form
# This directory is removed when the project is cleaned:
build.dir=build
build.generated.dir=${build.dir}/generated
# Only compile against the classpath explicitly listed here:
build.sysclasspath=ignore
build.test.classes.dir=${build.dir}/test/classes
build.test.results.dir=${build.dir}/test/results
debug.classpath=\
${run.classpath}
debug.test.classpath=\
${run.test.classpath}
# This directory is removed when the project is cleaned:
dist.dir=dist
dist.jar=${dist.dir}/TimeStamper.jar
dist.javadoc.dir=${dist.dir}/javadoc
excludes=
file.reference.appframework-1.0.3.jar=lib/appframework-1.0.3.jar
file.reference.jcalendar-1.3.2.jar=lib/jcalendar-1.3.2.jar
file.reference.swing-worker-1.1.jar=lib/swing-worker-1.1.jar
includes=**
jar.compress=false
javac.classpath=\
${file.reference.appframework-1.0.3.jar}:\
${file.reference.swing-worker-1.1.jar}:\
${file.reference.jcalendar-1.3.2.jar}
# Space-separated list of extra javac options
javac.compilerargs=
javac.deprecation=false
javac.source=1.5
javac.target=1.5
javac.test.classpath=\
${javac.classpath}:\
${build.classes.dir}:\
${libs.junit.classpath}:\
${libs.junit_4.classpath}
javadoc.additionalparam=
javadoc.author=false
javadoc.encoding=${source.encoding}
javadoc.noindex=false
javadoc.nonavbar=false
javadoc.notree=false
javadoc.private=false
javadoc.splitindex=true
javadoc.use=true
javadoc.version=false
javadoc.windowtitle=
jnlp.codebase.type=local
jnlp.codebase.url=file:/C:/Documents%20and%20Settings/jbernard/My%20Documents/Development/TimeStamper/dist/
jnlp.enabled=false
jnlp.icon=C:\\Documents and Settings\\jbernard\\My Documents\\Development\\TimeStamper\\src\\jdbernard\\timestamper\\resources\\icons\\appointment-new-16x16.png
jnlp.offline-allowed=true
jnlp.signed=true
main.class=jdbernard.timestamper.TimeStamperApp
manifest.file=manifest.mf
meta.inf.dir=${src.dir}/META-INF
platform.active=default_platform
run.classpath=\
${javac.classpath}:\
${build.classes.dir}
# Space-separated list of JVM arguments used when running the project
# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
# or test-sys-prop.name=value to set system properties for unit tests):
run.jvmargs=
run.test.classpath=\
${javac.test.classpath}:\
${build.test.classes.dir}
source.encoding=UTF-8
src.dir=src
test.src.dir=test
application.desc=Simple application used to track activities throughout time.
application.homepage=
application.title=TimeStamper
application.vendor=Jonathan Bernard
application.version=1.7
build.classes.dir=${build.dir}/classes
build.classes.excludes=**/*.java,**/*.form
# This directory is removed when the project is cleaned:
build.dir=build
build.generated.dir=${build.dir}/generated
build.generated.sources.dir=${build.dir}/generated-sources
# Only compile against the classpath explicitly listed here:
build.sysclasspath=ignore
build.test.classes.dir=${build.dir}/test/classes
build.test.results.dir=${build.dir}/test/results
debug.classpath=\
${run.classpath}
debug.test.classpath=\
${run.test.classpath}
# This directory is removed when the project is cleaned:
dist.dir=dist
dist.jar=${dist.dir}/TimeStamper.jar
dist.javadoc.dir=${dist.dir}/javadoc
excludes=
file.reference.appframework-1.0.3.jar=lib/appframework-1.0.3.jar
file.reference.jcalendar-1.3.2.jar=lib/jcalendar-1.3.2.jar
file.reference.swing-worker-1.1.jar=lib/swing-worker-1.1.jar
includes=**
jar.compress=false
javac.classpath=\
${file.reference.appframework-1.0.3.jar}:\
${file.reference.swing-worker-1.1.jar}:\
${file.reference.jcalendar-1.3.2.jar}
# Space-separated list of extra javac options
javac.compilerargs=
javac.deprecation=false
javac.source=1.5
javac.target=1.5
javac.test.classpath=\
${javac.classpath}:\
${build.classes.dir}:\
${libs.junit.classpath}:\
${libs.junit_4.classpath}
javadoc.additionalparam=
javadoc.author=false
javadoc.encoding=${source.encoding}
javadoc.noindex=false
javadoc.nonavbar=false
javadoc.notree=false
javadoc.private=false
javadoc.splitindex=true
javadoc.use=true
javadoc.version=false
javadoc.windowtitle=
jnlp.codebase.type=local
jnlp.codebase.url=file:/C:/Documents%20and%20Settings/jbernard/My%20Documents/Development/TimeStamper/dist/
jnlp.enabled=false
jnlp.icon=C:\\Documents and Settings\\jbernard\\My Documents\\Development\\TimeStamper\\src\\jdbernard\\timestamper\\resources\\icons\\appointment-new-16x16.png
jnlp.offline-allowed=true
jnlp.signed=true
main.class=jdbernard.timestamper.gui.TimeStamperApp
manifest.file=manifest.mf
meta.inf.dir=${src.dir}/META-INF
platform.active=default_platform
run.classpath=\
${javac.classpath}:\
${build.classes.dir}
# Space-separated list of JVM arguments used when running the project
# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
# or test-sys-prop.name=value to set system properties for unit tests):
run.jvmargs=
run.test.classpath=\
${javac.test.classpath}:\
${build.test.classes.dir}
source.encoding=UTF-8
src.dir=src
test.src.dir=test

View File

@ -1,24 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.java.j2seproject</type>
<configuration>
<buildExtensions xmlns="http://www.netbeans.org/ns/ant-build-extender/1">
<extension file="jnlp-impl.xml" id="jws">
<dependency dependsOn="jnlp" target="jar"/>
</extension>
</buildExtensions>
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
<name>TimeStamper</name>
<minimum-ant-version>1.6.5</minimum-ant-version>
<source-roots>
<root id="src.dir"/>
</source-roots>
<test-roots>
<root id="test.src.dir"/>
</test-roots>
</data>
<swingapp xmlns="http://www.netbeans.org/ns/form-swingapp/1">
<application-class name="jdbernard.timestamper.TimeStamperApp"/>
</swingapp>
</configuration>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.java.j2seproject</type>
<configuration>
<buildExtensions xmlns="http://www.netbeans.org/ns/ant-build-extender/1">
<extension file="jnlp-impl.xml" id="jws">
<dependency dependsOn="jnlp" target="jar"/>
</extension>
</buildExtensions>
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
<name>TimeStamper</name>
<minimum-ant-version>1.6.5</minimum-ant-version>
<source-roots>
<root id="src.dir"/>
</source-roots>
<test-roots>
<root id="test.src.dir"/>
</test-roots>
</data>
<swingapp xmlns="http://www.netbeans.org/ns/form-swingapp/1">
<application-class name="jdbernard.timestamper.gui.TimeStamperApp"/>
</swingapp>
</configuration>
</project>

View File

@ -1,77 +1,26 @@
package jdbernard.timestamper;
import java.util.Date;
import java.util.Scanner;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import jdbernard.timestamper.core.TimelineProperties;
public class Test {
public static void main(String[] args) throws Exception {
public static void main(String[] args) throws Exception {
Timeline t = new Timeline();
String choice;
Scanner in = new Scanner(System.in);
System.out.println("Enter config file, terminate with EOF");
BufferedReader bin = new BufferedReader(new InputStreamReader(System.in));
boolean loop = true;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(baos);
while(loop) {
System.out.println("[N]ew Timestamp, [S]ave, [L]oad, [P]rint, [Q]uit: ");
choice = in.nextLine();
String filename;
for(String line = bin.readLine(); line != null && !"EOF".equals(line); line = bin.readLine())
pw.println(line);
switch (choice.toLowerCase().charAt(0)) {
case 'n':
System.out.println("Enter time (HH:mm:ss) ");
Date d = new Date();
d.setHours(0);
d.setMinutes(0);
d.setSeconds(0);
d.setTime(d.getTime() + Timeline.shortFormat.parse(in.nextLine()).getTime());
pw.flush();
pw.close();
System.out.println("Enter mark ('EOM' to end) ");
String line = "";
StringBuilder mark = new StringBuilder();
line = in.nextLine();
while (!line.endsWith("EOM")) {
mark.append(line);
line = in.nextLine();
}
mark.append(line.substring(0, line.length() - 3));
System.out.println("Enter notes ('EON' to end) ");
StringBuilder notes = new StringBuilder();
line = in.nextLine();
while (!line.endsWith("EON")) {
notes.append(line);
line = in.nextLine();
}
notes.append(line.substring(0, line.length() - 3));
t.addMarker(d, mark.toString(), notes.toString());
break;
case 's':
System.out.print("Enter filename to save: ");
filename = in.nextLine();
Timeline.writeToFile(filename, t);
break;
case 'l':
System.out.println("Enter filename to load: ");
filename = in.nextLine();
t = Timeline.readFromFile(filename);
break;
case 'p':
Timeline.writeToStream(System.out, t);
break;
case 'q':
loop = false;
break;
default:
}
}
}
}

View File

@ -1,281 +0,0 @@
package jdbernard.timestamper;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Scanner;
import java.util.TreeSet;
/**
* @author Jonathan Bernard <jdbernard@gmail.com>
* A Timeline object represents a series of markers at specific points in time.
* The markers have a name or symbol (the 'mark') and notes associated with that
* mark.
*/
public class Timeline implements Iterable<Timeline.TimelineMarker> {
/**
* This represents a marker on the timeline.
* The date of the marker and the mark cannot be changed once assigned.
*/
public class TimelineMarker implements Comparable<TimelineMarker> {
private final Date timestamp;
private final String mark;
private String notes;
public TimelineMarker(Date timestamp, String mark, String notes) {
if (timestamp == null || mark == null)
throw new IllegalArgumentException("Null timestamp or mark"
+ " is not permitted.");
this.timestamp = timestamp;
this.mark = mark;
this.notes = notes;
}
public Date getTimestamp() { return timestamp; }
public String getMark() { return mark; }
public String getNotes() { return notes; }
public void setNotes(String notes) { this.notes = notes; }
@Override
public int compareTo(TimelineMarker that) {
if (that == null) return Integer.MAX_VALUE;
return this.timestamp.compareTo(that.timestamp);
}
@Override
public boolean equals(Object that) {
if (that == null) return false;
if (!(that instanceof TimelineMarker)) return false;
return this.timestamp.equals(((TimelineMarker)that).timestamp);
}
@Override
public int hashCode() {
int hash = 5;
hash = 53 * hash + (this.timestamp != null ? this.timestamp.hashCode() : 0);
return hash;
}
}
private static enum ReadingState {
NewMarker,
StartMark,
ReadMark,
StartNotes,
ReadNotes,
EndMarker
};
public static SimpleDateFormat shortFormat = new SimpleDateFormat("HH:mm:ss");
public static SimpleDateFormat longFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
private static int lineWrap = 78;
private TreeSet<TimelineMarker> timelineList;
public Timeline() {
timelineList = new TreeSet<TimelineMarker>();
}
public void addMarker(Date timestamp, String name, String notes) {
timelineList.add(new TimelineMarker(timestamp, name, notes));
}
public String getLastName(Date timestamp) {
TimelineMarker lastMarker = getLastMarker(timestamp);
return (lastMarker == null ?
"No previous marker." :
lastMarker.getMark());
}
public String getLastNotes(Date timestamp) {
TimelineMarker lastMarker = getLastMarker(timestamp);
return (lastMarker == null ?
"No previous marker." :
lastMarker.getNotes());
}
public TimelineMarker getLastMarker(Date timestamp) {
TimelineMarker lastMarker = null;
for (TimelineMarker tm : timelineList) {
if (tm.getTimestamp().after(timestamp))
break;
lastMarker = tm;
}
return lastMarker;
}
public void removeMarker(TimelineMarker marker) {
timelineList.remove(marker);
}
public Iterator<TimelineMarker> iterator() {
return timelineList.iterator();
}
/**
* Write the a representation of the timeline to a stream. This method
* flushes the stream after it finishes writing but does not close the
* stream.
* @param stream An open stream to write the timeline representation to.
* @param timeline The timeline to write.
* @throws java.io.IOException
*/
public static void writeToStream(OutputStream stream, Timeline timeline)
throws IOException {
Writer out = new OutputStreamWriter(stream);
for (TimelineMarker tm : timeline.timelineList) {
// write timestamp
out.write(longFormat.format(tm.getTimestamp()) + "\n");
// write mark
String mark = tm.getMark().replace('\n', '\u0000');
if (mark.length() < lineWrap) out.write(mark + "\n");
else {
// wrap lines if neccessary
int i;
for (i = 0; (i + lineWrap) < mark.length(); i+=lineWrap)
out.write(mark.substring(i, i+lineWrap) + "\\\n");
if (i < mark.length())
out.write(mark.substring(i, mark.length()) + "\n");
}
// write notes
String notes = tm.getNotes().replace('\n', '\u0000');
if (notes.length() < lineWrap) out.write(notes + "\n");
else {
// wrap lines if neccessary
int i;
for (i = 0; (i + lineWrap) < notes.length(); i+=lineWrap)
out.write(notes.substring(i, i+lineWrap) + "\\\n");
if (i < notes.length())
out.write(notes.substring(i, notes.length()) + "\n");
}
out.write("\n");
}
out.flush();
}
/**
* Write a representation of a timeline to a file.
* @param filename The path to the destination file.
* @param timeline The timeline to write.
* @throws java.io.IOException
* @throws java.io.FileNotFoundException
*/
public static void writeToFile(String filename, Timeline timeline)
throws IOException, FileNotFoundException {
OutputStream out = new FileOutputStream(filename);
writeToStream(out, timeline);
out.close();
}
/**
* Create a <b>Timeline</b> instance from a given stream.
* @param stream The stream to read from.
* @return A new <b>Timeline</b> instance specified by the input stream.
* @throws java.io.IOException
* @throws java.io.FileNotFoundException
*/
public static Timeline readFromStream(InputStream stream)
throws IOException, FileNotFoundException {
Scanner in = new Scanner(stream);
Timeline timeline = new Timeline();
ReadingState readingState = ReadingState.NewMarker;
Date d = null;
StringBuilder mark = null;
StringBuilder notes = null;
String line;
int lineNumber = 0;
while (in.hasNextLine()) {
line = in.nextLine();
lineNumber++;
switch (readingState) {
case NewMarker:
try { d = longFormat.parse(line); }
catch (ParseException pe) {
throw new IOException("Error parsing timeline file at line "
+ lineNumber + ": expected a new marker date but could not parse"
+ " the date. Error: " + pe.getLocalizedMessage());
}
readingState = ReadingState.StartMark;
break;
case StartMark:
mark = new StringBuilder();
// fall through to ReadMark
case ReadMark:
if (line.endsWith("\\")) {
readingState = ReadingState.ReadMark;
line = line.substring(0, line.length() - 1);
}
else readingState = ReadingState.StartNotes;
mark.append(line);
break;
case StartNotes:
notes = new StringBuilder();
// fall through to ReadNotes
case ReadNotes:
if (line.endsWith("\\")) {
readingState = ReadingState.ReadNotes;
line = line.substring(0, line.length() - 1);
}
else readingState = ReadingState.EndMarker;
notes.append(line);
break;
case EndMarker:
String sMark = mark.toString().replace('\u0000', '\n');
String sNotes = notes.toString().replace('\u0000', '\n');
timeline.addMarker(d, sMark, sNotes);
readingState = ReadingState.NewMarker;
}
}
//if (readingState != ReadingState.NewMarker)
//TODO: warning of invalid marker file
return timeline;
}
/**
* Create a Timline instance from a file representation.
* @param filename The path of the source file.
* @return The new Timeline instance.
* @throws java.io.IOException
* @throws java.io.FileNotFoundException
*/
public static Timeline readFromFile(String filename)
throws IOException, FileNotFoundException {
InputStream in = new FileInputStream(filename);
Timeline t = readFromStream(in);
in.close();
return t;
}
}

View File

@ -0,0 +1,21 @@
package jdbernard.timestamper.core;
import java.io.IOException;
/**
*
* @author Jonathan Bernard ({@literal jonathan.bernard@gemalto.com})
*/
public class AuthenticationException extends IOException {
public AuthenticationException() { super(); }
public AuthenticationException(String message) { super(message); }
public AuthenticationException(Throwable t) { super(t); }
public AuthenticationException(String message, Throwable t) {
super(message, t);
}
}

View File

@ -0,0 +1,64 @@
package jdbernard.timestamper.core;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
/**
*
* @author Jonathan Bernard ({@literal jonathan.bernard@gemalto.com})
*/
public class FileTimelineSource extends TimelineSource {
private File file;
public FileTimelineSource(URI uri) {
super(uri);
this.file = new File(uri);
}
/** * {@inheritDoc } */
public Timeline read() throws IOException {
FileInputStream fin = new FileInputStream(file);
Timeline t = StreamBasedTimelineSource.readFromStream(fin);
fin.close();
return t;
}
public Timeline readWithComments(OutputStream commentStream)
throws IOException {
FileInputStream fin = new FileInputStream(file);
Timeline t = StreamBasedTimelineSource.readFromStream(fin, commentStream);
fin.close();
return t;
}
/** * {@inheritDoc } */
public void persist(Timeline t) throws IOException {
FileOutputStream fout = new FileOutputStream(file);
StreamBasedTimelineSource.writeToStream(fout, t);
fout.close();
}
public boolean isAuthenticated() {
File dir = file.getParentFile();
return (dir.canRead() && dir.canWrite());
}
public void authenticate() throws AuthenticationException {
File dir = file.getParentFile();
if (!dir.canRead())
throw new AuthenticationException("This FileTimelineSource does not"
+ " have read access to the parent directory for the "
+ "given file (" + file.getAbsolutePath() + ".");
if (!dir.canWrite())
throw new AuthenticationException("This FileTimelineSource does not"
+ " have write access to the parent directory for the "
+ "given file (" + file.getAbsolutePath() + ".");
}
}

View File

@ -0,0 +1,203 @@
package jdbernard.timestamper.core;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.text.ParseException;
import java.util.Date;
import java.util.Scanner;
/**
*
* @author Jonathan Bernard ({@literal jonathan.bernard@gemalto.com})
*/
public class StreamBasedTimelineSource extends TimelineSource {
private static final int lineWrap = 78;
private static enum ReadingState {
NewMarker,
StartMark,
ReadMark,
StartNotes,
ReadNotes,
EndMarker
};
private InputStream in;
private OutputStream out;
private ByteArrayOutputStream comments;
public StreamBasedTimelineSource(InputStream inStream,
OutputStream outStream) {
super(null);
this.in = inStream;
this.out = outStream;
this.comments = new ByteArrayOutputStream();
}
/** {@inheritDoc } */
public Timeline read() throws IOException {
return readFromStream(in, comments);
}
/** {@inheritDoc } */
public void persist(Timeline t) throws IOException {
writeToStream(out, t);
}
public void authenticate() throws AuthenticationException { }
public boolean isAuthenticated() { return true; }
/**
* Allows a user to extract the comments from the last parsed file.
* @return a <code>byte[]</code> representing the portions of the file
* which were comments.
*/
public byte[] getCommentBytes() {
return comments.toByteArray();
}
/**
* Write the a representation of the timeline to a stream. This method
* flushes the stream after it finishes writing but does not close the
* stream.
* @param stream An open stream to write the timeline representation to.
* @param timeline The timeline to write.
* @throws java.io.IOException
*/
public static void writeToStream(OutputStream stream, Timeline timeline)
throws IOException {
Writer out = new OutputStreamWriter(stream);
for (TimelineMarker tm : timeline) {
// write timestamp
out.write(Timeline.longFormat.format(tm.getTimestamp()) + "\n");
// write mark
String mark = tm.getMark().replace('\n', '\u0000');
if (mark.length() < lineWrap) out.write(mark + "\n");
else {
// wrap lines if neccessary
int i;
for (i = 0; (i + lineWrap) < mark.length(); i+=lineWrap)
out.write(mark.substring(i, i+lineWrap) + "\\\n");
if (i < mark.length())
out.write(mark.substring(i, mark.length()) + "\n");
}
// write notes
String notes = tm.getNotes().replace('\n', '\u0000');
if (notes.length() < lineWrap) out.write(notes + "\n");
else {
// wrap lines if neccessary
int i;
for (i = 0; (i + lineWrap) < notes.length(); i+=lineWrap)
out.write(notes.substring(i, i+lineWrap) + "\\\n");
if (i < notes.length())
out.write(notes.substring(i, notes.length()) + "\n");
}
out.write("\n");
}
out.flush();
}
/**
* Create a <b>Timeline</b> instance from a given stream.
* @param stream The stream to read from.
* @return A new <b>Timeline</b> instance specified by the input stream.
* @throws java.io.IOException
* @throws java.io.FileNotFoundException
*/
public static Timeline readFromStream(InputStream stream)
throws IOException {
return readFromStream(stream, null);
}
/**
* Create a <b>Timeline</b> instance from a given stream.
* @param stream The stream to read from.
* @param commentStream A stream to write comments found in the file. This
* parameter may be <b>null</b>, in which case comments are ignored.
* @return A new <b>Timeline</b> instance specified by the input stream.
* @throws java.io.IOException
* @throws java.io.FileNotFoundException
*/
public static Timeline readFromStream(InputStream stream,
OutputStream commentStream) throws IOException {
Scanner in = new Scanner(stream);
Timeline timeline = new Timeline();
PrintWriter commentsWriter = commentStream == null ?
null : new PrintWriter(commentStream);
ReadingState readingState = ReadingState.NewMarker;
Date d = null;
StringBuilder mark = null;
StringBuilder notes = null;
String line;
int lineNumber = 0;
while (in.hasNextLine()) {
line = in.nextLine();
lineNumber++;
// line is a comment
if (line.startsWith("#")) {
if (commentsWriter != null) commentsWriter.println(line);
continue; // don't parse this line as part of the timeline
}
switch (readingState) {
case NewMarker:
try { d = Timeline.longFormat.parse(line); }
catch (ParseException pe) {
throw new IOException("Error parsing timeline file at line "
+ lineNumber + ": expected a new marker date but could not parse"
+ " the date. Error: " + pe.getLocalizedMessage());
}
readingState = ReadingState.StartMark;
break;
case StartMark:
mark = new StringBuilder();
// fall through to ReadMark
case ReadMark:
if (line.endsWith("\\")) {
readingState = ReadingState.ReadMark;
line = line.substring(0, line.length() - 1);
}
else readingState = ReadingState.StartNotes;
mark.append(line);
break;
case StartNotes:
notes = new StringBuilder();
// fall through to ReadNotes
case ReadNotes:
if (line.endsWith("\\")) {
readingState = ReadingState.ReadNotes;
line = line.substring(0, line.length() - 1);
}
else readingState = ReadingState.EndMarker;
notes.append(line);
break;
case EndMarker:
String sMark = mark.toString().replace('\u0000', '\n');
String sNotes = notes.toString().replace('\u0000', '\n');
timeline.addMarker(d, sMark, sNotes);
readingState = ReadingState.NewMarker;
}
}
return timeline;
}
}

View File

@ -0,0 +1,129 @@
package jdbernard.timestamper.core;
import java.io.IOException;
import java.util.Collection;
import java.util.Timer;
import java.util.TimerTask;
/**
*
* @author Jonathan Bernard ({@literal jonathan.bernard@gemalto.com})
*/
public class SyncTarget {
protected final TimelineSource source;
protected final Timeline localTimeline;
protected final String name;
protected Timer syncTimer;
protected SyncTask syncTask;
protected long syncInterval= 30 * 60 * 1000; // 30 minutes converted to ms
protected boolean pushEnabled = true;
protected boolean pullEnabled = true;
protected boolean syncOnExit = true;
protected class SyncTask extends TimerTask {
@Override public void run() {
synchronized(this) {
try { SyncTarget.this.sync(); }
catch (IOException ioe) { /* TODO */ }
}}}
protected SyncTarget(String name, TimelineSource source,
Timeline localTimeline) {
this.name = name;
this.source = source;
this.localTimeline = localTimeline;
syncTimer = new Timer(source.toString() + " sync-timer");
syncTask = new SyncTask();
syncTimer.schedule(syncTask, syncInterval, syncInterval);
}
/**
* Sync the local timeline with the remote timeline represented by this
* SyncTarget object.
* @return <b>true</b> if the two timelines were out of sync and have
* been put into synch, <b>false</b> if the timelines were already in
* sync and no action was requried.
* @throws IOException if there is an error communicating with the remote
* timeline. This includes AuthenticationException.
*/
protected boolean sync() throws IOException {
assert (pullEnabled || pushEnabled);
Timeline remoteTimeline;
boolean syncPerformed = false;
// make sure we're authenticated to whatever source we're using
if (!SyncTarget.this.source.isAuthenticated()) {
SyncTarget.this.source.authenticate();
}
// try to copy the remote timeline locally
remoteTimeline = SyncTarget.this.source.read();
// if we are pulling markers from the remote line
if (SyncTarget.this.pullEnabled) {
// get all markers in the remote timeline not in the local one
Collection<TimelineMarker> diffFromRemote =
remoteTimeline.difference(localTimeline);
if (diffFromRemote.size() != 0) {
// add all markers in the remote tline to the local one
localTimeline.addAll(diffFromRemote);
syncPerformed = true;
}
}
// if we are pushing markers to the remote timeline
if (SyncTarget.this.pushEnabled) {
// get all markers in the local timeline but not in the remote
Collection<TimelineMarker> diffFromLocal =
localTimeline.difference(remoteTimeline);
if (diffFromLocal.size() != 0) {
// add the difference to the remote timeline
remoteTimeline.addAll(diffFromLocal);
syncPerformed = true;
}
}
return syncPerformed;
}
public String getName() { return name; }
public TimelineSource getSource() { return source; }
public synchronized void setSyncInterval(long syncInterval) {
this.syncInterval= syncInterval;
syncTask.cancel();
syncTask = new SyncTask();
syncTimer.purge();
syncTimer.schedule(syncTask, syncInterval, syncInterval);
}
public long getSyncInterval() { return syncInterval; }
public synchronized void enablePush(boolean enablePush) {
this.pullEnabled = enablePush;
}
public boolean isPushEnabled() { return pushEnabled; }
public synchronized void enablePull(boolean enablePull) {
this.pullEnabled = enablePull;
}
public boolean isPullEnabled() { return pullEnabled; }
public synchronized void enableSyncOnExit(boolean syncOnExit) {
this.syncOnExit = syncOnExit;
}
public boolean isSyncOnExitEnabled() { return syncOnExit; }
}

View File

@ -0,0 +1,95 @@
package jdbernard.timestamper.core;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.TreeSet;
/**
* @author Jonathan Bernard {@literal <jdbernard@gmail.com>}
* A Timeline object represents a series of markers at specific points in time.
* The markers have a name or symbol (the 'mark') and notes associated with that
* mark.
*/
public class Timeline implements Iterable<TimelineMarker> {
public static SimpleDateFormat shortFormat = new SimpleDateFormat("HH:mm:ss");
public static SimpleDateFormat longFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
private TreeSet<TimelineMarker> timelineList;
public Timeline() {
timelineList = new TreeSet<TimelineMarker>();
}
public void addMarker(Date timestamp, String name, String notes) {
timelineList.add(new TimelineMarker(timestamp, name, notes));
}
public String getLastName(Date timestamp) {
TimelineMarker lastMarker = getLastMarker(timestamp);
return (lastMarker == null ?
"No previous marker." :
lastMarker.getMark());
}
public String getLastNotes(Date timestamp) {
TimelineMarker lastMarker = getLastMarker(timestamp);
return (lastMarker == null ?
"No previous marker." :
lastMarker.getNotes());
}
public TimelineMarker getLastMarker(Date timestamp) {
TimelineMarker lastMarker = null;
for (TimelineMarker tm : timelineList) {
if (tm.getTimestamp().after(timestamp))
break;
lastMarker = tm;
}
return lastMarker;
}
public void removeMarker(TimelineMarker marker) {
timelineList.remove(marker);
}
public Iterator<TimelineMarker> iterator() {
return timelineList.iterator();
}
/**
* Return the difference of the this timeline relative to another timeline.
* More specifically, return the set of all
* {@link jdbernard.timestamper.core.TimelineMarker}s that are present in
* the <b>this</b> timeline but not present in the given timeline.
* timeline.
* @param t
* @return A collection representing the TimelineMarkers present in
* <b>this</b> timeline but not in the given timeline.
*/
public Collection<TimelineMarker> difference(Timeline t) {
TreeSet<TimelineMarker> difference = new TreeSet<TimelineMarker>();
for (TimelineMarker tm : timelineList) {
if (!t.timelineList.contains(tm))
difference.add(tm);
}
return difference;
}
public void addAll(Timeline t) {
for (TimelineMarker tm : t) {
if (!timelineList.contains(tm))
timelineList.add(tm);
}
}
public void addAll(Collection<TimelineMarker> c) {
timelineList.addAll(c);
}
}

View File

@ -0,0 +1,63 @@
package jdbernard.timestamper.core;
import java.util.Date;
/**
* @author Jonathan Bernard {@literal <jdbernard@gmail.com>}
* This represents a marker on the timeline.
* The date of the marker and the mark cannot be changed once assigned.
*/
public class TimelineMarker implements Comparable<TimelineMarker> {
private final Date timestamp;
private final String mark;
private String notes;
public TimelineMarker(Date timestamp, String mark, String notes) {
if (timestamp == null || mark == null)
throw new IllegalArgumentException("Null timestamp or mark"
+ " is not permitted.");
this.timestamp = timestamp;
this.mark = mark;
this.notes = notes;
}
public Date getTimestamp() { return timestamp; }
public String getMark() { return mark; }
public String getNotes() { return notes; }
public void setNotes(String notes) { this.notes = notes; }
@Override
public int compareTo(TimelineMarker that) {
if (that == null) return Integer.MAX_VALUE;
int val = this.timestamp.compareTo(that.timestamp);
if (val == 0) val = this.mark.compareTo(that.mark);
return val;
}
@Override
public boolean equals(Object o) {
if (o == null) return false;
if (!(o instanceof TimelineMarker)) return false;
TimelineMarker that = (TimelineMarker) o;
return this.timestamp.equals(that.timestamp) &&
this.mark.equals(that.mark);
}
@Override
public int hashCode() {
int hash = 7;
hash = 61 * hash + (this.timestamp != null ? this.timestamp.hashCode() : 0);
hash = 61 * hash + (this.mark != null ? this.mark.hashCode() : 0);
return hash;
}
}

View File

@ -1,13 +1,17 @@
package jdbernard.timestamper.core;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.StringTokenizer;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
@ -16,145 +20,144 @@ import java.util.StringTokenizer;
*/
public class TimelineProperties {
public static final String LOCAL_TIMELINE_URI = "timeline.uri";
public static final String REMOTE_TIMELINE_BASE = "remote.timeline.";
private static final Pattern remoteTimelinePropPattern =
Pattern.compile("\\Q" + REMOTE_TIMELINE_BASE + "\\E([^\\s\\.=]+?)[\\.=].*");
private File propertyFile;
private Timeline timeline;
private TimelineSource timelineSource;
private LinkedList<SyncTarget> syncTargets = new LinkedList<SyncTarget>();
public TimelineProperties(InputStream in) throws IOException {
parseConfig(in);
}
public TimelineProperties() {
this.propertyFile = new File("timeline.default.properties");
Properties config = new Properties();
private static enum ReadingState {
LocalTimelineDef, // expecting LOCAL TIMELINE definition
NewSync, // expecting a SYNC TO def
NewSyncOrOptions // either a NewDef, or a block of options
}
File timelineFile = new File("timeline.default.txt");
URI timelineURI = timelineFile.toURI();
private void parseConfig(InputStream is) throws IOException {
Scanner in = new Scanner(is);
URI sourceURI;
// read the information for the local timeline
if (!nextExtendedToken(in, "LOCAL TIMELINE:")) {
throw new IOException("Missing 'LOCAL TIMELINE:' definition."
+ " This must be the first line of the options file.");
timeline = new Timeline();
timelineSource = TimelineSourceFactory.newInstance(timelineURI);
try { timelineSource.persist(timeline); }
catch (IOException ioe) {
// TODO
}
// parse the source URI
timelineSource = parseSource(in);
config.setProperty(LOCAL_TIMELINE_URI, timelineURI.toString());
// load timeline from source
timeline = timelineSource.read(); // TODO: authentication
// add as many Syncs as we find
for (SyncTarget st = parseSync(in); st != null; st = parseSync(in))
syncTargets.add(st);
}
private SyncTarget parseSync(Scanner in) throws IOException {
SyncTarget st;
String token;
if (!nextExtendedToken(in, "SYNC WITH:")) { return null; }
st = new SyncTarget(parseSource(in), timeline);
while (true) {
if (nextExtendedToken(in, "PULL ONLY")) {
st.enablePull(true);
st.enablePush(false);
}
else if (nextExtendedToken(in, "PUSH ONLY")) {
st.enablePull(false);
st.enablePush(true);
}
else if (nextExtendedToken(in, "PUSH AND PULL") ||
nextExtendedToken(in, "PULL AND PUSH")) {
st.enablePull(true);
st.enablePush(true);
}
else if (nextExtendedToken(in, "SYNC ON EXIT")) {
st.enableSyncOnExit(true);
}
else if (nextExtendedToken(in, "UPDATE EVERY")) {
long updateAmount = 1;
// parse the time amount if present
token = in.next("\\d+");
if (token != null) { updateAmount = Long.parseLong(token); }
token = in.next();
if ("seconds".startsWith(token.toLowerCase()))
updateAmount *= 1000;
else if ("minutes".startsWith(token.toLowerCase()))
updateAmount *= 1000 * 60;
else if ("hours".startsWith(token.toLowerCase()))
updateAmount *= 1000 * 60 * 60;
else if ("days".startsWith(token.toLowerCase()))
updateAmount *= 1000 * 60 * 60 * 24;
else if ("weeks".startsWith(token.toLowerCase()))
updateAmount *= 1000 * 60 * 60 * 24 * 7;
else throw new IOException("'" + token + "' is not a supported"
+ " measure of time. The supported measures are "
+ "'seconds', 'minutes', 'hours', 'days', and 'weeks'.");
}
else return st;
try { config.store(new FileOutputStream(propertyFile), ""); }
catch (IOException ioe) {
// TODO
}
}
private TimelineSource parseSource(Scanner in) throws IOException {
public TimelineProperties(File propertyFile) throws IOException {
String strURI;
URI sourceURI;
URI timelineURI;
if (!in.hasNext()) {
throw new IOException("Expected the URI of a timeline source, but "
+ "ran out of input.");
this.propertyFile = propertyFile;
Properties config = new Properties();
try {
config.load(new InputStreamReader(new FileInputStream(propertyFile)));
} catch (IOException ioe) {
// TODO
}
strURI = in.next();
try { sourceURI = new URI(strURI); }
catch (URISyntaxException urise) {
throw new IOException("The source link '" + strURI + "' is not a"
+ " valid URI.", urise);
}
return TimelineSourceFactory.newInstance(sourceURI);
}
private static boolean nextExtendedToken(Scanner in, String expectedToken)
throws IOException {
StringTokenizer st = new StringTokenizer(expectedToken);
if (st.countTokens() < 1 || !in.hasNext()) { return false; }
// read one token
String curToken = st.nextToken();
String inToken = in.next("(?i)\\Q" + curToken + "\\E");
if (inToken == null) return false;
while (st.hasMoreTokens()) {
curToken = st.nextToken();
if (!in.hasNext()) {
throw new IOException("Ran out of input while expecting '"
+ curToken + "' from '" + expectedToken + "'.");
}
inToken = in.next("(?i)\\Q" + curToken + "\\E");
if (inToken == null) {
throw new IOException("Found '" + in.next() + "' but expected '"
+ curToken + "' from '" + expectedToken + "'.");
// load local timeline
strURI = config.getProperty(LOCAL_TIMELINE_URI, "");
if ("".equals(strURI)) {
timelineURI = new File("timeline.default.txt").toURI();
} else {
try { timelineURI = new URI(strURI); }
catch (URISyntaxException urise) {
throw new IOException("Unable to load the timeline: the timeline "
+ "URI is invalid.", urise);
}
}
return true;
timelineSource = TimelineSourceFactory.newInstance(timelineURI);
timeline = timelineSource.read();
// search keys for remote timeline entries
for (Object keyObj : config.keySet()) {
if (!(keyObj instanceof String)) continue;
String key = (String) keyObj;
String stName;
String remoteBase;
SyncTarget st;
Matcher m = remoteTimelinePropPattern.matcher(key);
if (!m.matches()) continue;
stName = m.group(1);
remoteBase = REMOTE_TIMELINE_BASE + stName;
strURI = config.getProperty(remoteBase + ".uri", "");
try { timelineURI = new URI(strURI); }
catch (URISyntaxException urise) { /* TODO */ }
// add a new SyncTarget to the list
st = new SyncTarget(stName, TimelineSourceFactory
.newInstance(timelineURI), timeline);
syncTargets.add(st);
// check for synch options
st.enablePull(Boolean.parseBoolean(
config.getProperty(remoteBase + ".pull", "true")));
st.enablePush(Boolean.parseBoolean(
config.getProperty(remoteBase + ".push", "true")));
st.enableSyncOnExit(Boolean.parseBoolean(
config.getProperty(remoteBase + ".sync-on-exit", "true")));
st.setSyncInterval(Long.parseLong(
config.getProperty(remoteBase + ".update-interval",
"1800000"))); // thirty minutes
}
}
public void writeToStream(OutputStream out) throws IOException {
public void save() throws IOException {
Properties config = new Properties();
timelineSource.persist(timeline);
config.setProperty(LOCAL_TIMELINE_URI,
timelineSource.getURI().toString());
for (SyncTarget st : syncTargets) {
String remoteBase = REMOTE_TIMELINE_BASE + st.getName();
config.setProperty(remoteBase + ".uri",
st.getSource().getURI().toString());
config.setProperty(remoteBase + ".pull",
Boolean.toString(st.isPullEnabled()));
config.setProperty(remoteBase + ".push",
Boolean.toString(st.isPushEnabled()));
config.setProperty(remoteBase + ".sync-on-exit",
Boolean.toString(st.isSyncOnExitEnabled()));
config.setProperty(remoteBase + ".update-interval",
Long.toString(st.getSyncInterval()));
}
try {
config.store(new FileOutputStream(propertyFile), "");
} catch (IOException ioe) {
// TODO
}
}
public void save(File newFile) throws IOException {
propertyFile = newFile;
save();
}
public Timeline getTimeline() { return timeline; }
public void setTimelineSource(TimelineSource newSource) {
this.timelineSource = newSource;
}
public TimelineSource getTimelineSource() { return timelineSource; }
public Collection<SyncTarget> getSyncTargets() { return syncTargets; }
}

View File

@ -0,0 +1,25 @@
package jdbernard.timestamper.core;
import java.io.IOException;
import java.net.URI;
/**
*
* @author Jonathan Bernard ({@literal jonathan.bernard@gemalto.com})
*/
public abstract class TimelineSource {
protected final URI uri;
public TimelineSource(URI uri) { this.uri = uri; }
public abstract Timeline read() throws IOException;
public abstract void persist(Timeline t) throws IOException;
public abstract boolean isAuthenticated();
public abstract void authenticate() throws AuthenticationException;
public URI getURI() {
return uri;
}
}

View File

@ -0,0 +1,38 @@
package jdbernard.timestamper.core;
import java.io.File;
import java.net.URI;
/**
*
* @author Jonathan Bernard ({@literal jonathan.bernard@gemalto.com})
*/
public class TimelineSourceFactory {
public static TimelineSource newInstance(URI uri) {
// File based
if ("file".equalsIgnoreCase(uri.getScheme())) {
return new FileTimelineSource(uri);
}
// Twitter
else if ("http".equalsIgnoreCase(uri.getScheme()) &&
("twitter.com".equalsIgnoreCase(uri.getHost())
|| "www.twitter.com".equalsIgnoreCase(uri.getHost()))) {
throw new UnsupportedOperationException("Twitter based timeline "
+ "sources are not yet supported.");
}
// SSH
else if ("ssh".equalsIgnoreCase(uri.getScheme())) {
throw new UnsupportedOperationException("SSH based timeline sources"
+ " are not yet supported.");
}
// unknown
else {
throw new UnsupportedOperationException("Timeline sources for the"
+ " " + uri.getScheme() + " are not currently supported.");
}
}
}

View File

@ -0,0 +1,34 @@
package jdbernard.timestamper.core;
import java.io.IOException;
import java.net.URI;
/**
*
* @author Jonathan Bernard ({@literal jonathan.bernard@gemalto.com})
*/
public class TwitterTimelineSource extends TimelineSource {
private String username;
private char[] password;
public TwitterTimelineSource(URI uri) {
super(uri);
}
public Timeline read() throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
public void persist(Timeline t) throws IOException {
throw new UnsupportedOperationException("Not supported yet.");
}
public boolean isAuthenticated() {
throw new UnsupportedOperationException("Not supported yet.");
}
public void authenticate() throws AuthenticationException {
throw new UnsupportedOperationException("Not supported yet.");
}
}

View File

@ -12,6 +12,7 @@
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="2"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>

View File

@ -4,7 +4,7 @@
* Created on October 19, 2008, 3:14 PM
*/
package jdbernard.timestamper;
package jdbernard.timestamper.gui;
import java.awt.Frame;
import java.awt.Point;
@ -56,7 +56,7 @@ public class AboutDialog extends JDialog implements MouseMotionListener {
});
aboutPanel.addMouseMotionListener(this);
org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(jdbernard.timestamper.TimeStamperApp.class).getContext().getResourceMap(AboutDialog.class);
org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(jdbernard.timestamper.gui.TimeStamperApp.class).getContext().getResourceMap(AboutDialog.class);
iconLabel.setIcon(resourceMap.getIcon("iconLabel.icon")); // NOI18N
iconLabel.setText(resourceMap.getString("iconLabel.text")); // NOI18N
iconLabel.setName("iconLabel"); // NOI18N

View File

@ -12,6 +12,7 @@
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="2"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>

View File

@ -4,7 +4,7 @@
* Created on September 3, 2008, 4:53 PM
*/
package jdbernard.timestamper;
package jdbernard.timestamper.gui;
import java.awt.Font;
import java.awt.Point;
@ -61,7 +61,7 @@ public class NotesDialog extends JDialog implements MouseMotionListener {
setUndecorated(true);
mainPanel.setBorder(javax.swing.BorderFactory.createMatteBorder(2, 2, 2, 2, new java.awt.Color(0, 0, 0)));
org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(jdbernard.timestamper.TimeStamperApp.class).getContext().getResourceMap(NotesDialog.class);
org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(jdbernard.timestamper.gui.TimeStamperApp.class).getContext().getResourceMap(NotesDialog.class);
mainPanel.setToolTipText(resourceMap.getString("mainPanel.toolTipText")); // NOI18N
mainPanel.setName("mainPanel"); // NOI18N
mainPanel.addMouseListener(new java.awt.event.MouseAdapter() {

View File

@ -1,6 +1,26 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.6" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<NonVisualComponents>
<Container class="jdbernard.timestamper.gui.TimelineDayDisplay" name="dayDisplay">
<Properties>
<Property name="name" type="java.lang.String" value="dayDisplay" noResource="true"/>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="100" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="100" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
</NonVisualComponents>
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="name" type="java.lang.String" value="Form" noResource="true"/>
@ -12,6 +32,7 @@
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="2"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
@ -48,6 +69,8 @@
<AuxValues>
<AuxValue name="JavaCodeGenerator_ListenersCodePost" type="java.lang.String" value="mainPanel.addMouseMotionListener(this);"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="detailPanel">
<Properties>
@ -179,7 +202,7 @@
<Component class="javax.swing.JButton" name="prevWeekButton">
<Properties>
<Property name="action" type="javax.swing.Action" editor="org.netbeans.modules.swingapp.ActionEditor">
<action class="jdbernard.timestamper.PunchcardDisplayDialog" id="previousWeek" methodName="previousWeek"/>
<action class="jdbernard.timestamper.gui.PunchcardDisplayDialog" id="previousWeek" methodName="previousWeek"/>
</Property>
<Property name="hideActionText" type="boolean" value="true"/>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
@ -196,7 +219,7 @@
<Component class="javax.swing.JButton" name="prevDayButton">
<Properties>
<Property name="action" type="javax.swing.Action" editor="org.netbeans.modules.swingapp.ActionEditor">
<action class="jdbernard.timestamper.PunchcardDisplayDialog" id="previousDay" methodName="previousDay"/>
<action class="jdbernard.timestamper.gui.PunchcardDisplayDialog" id="previousDay" methodName="previousDay"/>
</Property>
<Property name="hideActionText" type="boolean" value="true"/>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
@ -213,7 +236,7 @@
<Component class="javax.swing.JButton" name="currentDayButton">
<Properties>
<Property name="action" type="javax.swing.Action" editor="org.netbeans.modules.swingapp.ActionEditor">
<action class="jdbernard.timestamper.PunchcardDisplayDialog" id="currentDay" methodName="currentDay"/>
<action class="jdbernard.timestamper.gui.PunchcardDisplayDialog" id="currentDay" methodName="currentDay"/>
</Property>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
<Insets value="[0, 2, 0, 2]"/>
@ -229,7 +252,7 @@
<Component class="javax.swing.JButton" name="nextDayButton">
<Properties>
<Property name="action" type="javax.swing.Action" editor="org.netbeans.modules.swingapp.ActionEditor">
<action class="jdbernard.timestamper.PunchcardDisplayDialog" id="nextDay" methodName="nextDay"/>
<action class="jdbernard.timestamper.gui.PunchcardDisplayDialog" id="nextDay" methodName="nextDay"/>
</Property>
<Property name="hideActionText" type="boolean" value="true"/>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
@ -246,7 +269,7 @@
<Component class="javax.swing.JButton" name="nextWeekButton">
<Properties>
<Property name="action" type="javax.swing.Action" editor="org.netbeans.modules.swingapp.ActionEditor">
<action class="jdbernard.timestamper.PunchcardDisplayDialog" id="nextWeek" methodName="nextWeek"/>
<action class="jdbernard.timestamper.gui.PunchcardDisplayDialog" id="nextWeek" methodName="nextWeek"/>
</Property>
<Property name="hideActionText" type="boolean" value="true"/>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
@ -265,7 +288,7 @@
<Component class="javax.swing.JButton" name="newMarkerButton">
<Properties>
<Property name="action" type="javax.swing.Action" editor="org.netbeans.modules.swingapp.ActionEditor">
<action class="jdbernard.timestamper.PunchcardDisplayDialog" id="newMarker" methodName="newMarker"/>
<action class="jdbernard.timestamper.gui.PunchcardDisplayDialog" id="newMarker" methodName="newMarker"/>
</Property>
<Property name="name" type="java.lang.String" value="newMarkerButton" noResource="true"/>
</Properties>
@ -278,7 +301,7 @@
<Component class="javax.swing.JButton" name="deleteMarkerButton">
<Properties>
<Property name="action" type="javax.swing.Action" editor="org.netbeans.modules.swingapp.ActionEditor">
<action class="jdbernard.timestamper.PunchcardDisplayDialog" id="deleteMarker" methodName="deleteMarker"/>
<action class="jdbernard.timestamper.gui.PunchcardDisplayDialog" id="deleteMarker" methodName="deleteMarker"/>
</Property>
<Property name="name" type="java.lang.String" value="deleteMarkerButton" noResource="true"/>
</Properties>
@ -291,7 +314,7 @@
<Component class="javax.swing.JButton" name="saveMarkerChanges">
<Properties>
<Property name="action" type="javax.swing.Action" editor="org.netbeans.modules.swingapp.ActionEditor">
<action class="jdbernard.timestamper.PunchcardDisplayDialog" id="saveMarkerChanges" methodName="saveMarkerChanges"/>
<action class="jdbernard.timestamper.gui.PunchcardDisplayDialog" id="saveMarkerChanges" methodName="saveMarkerChanges"/>
</Property>
<Property name="name" type="java.lang.String" value="saveMarkerChanges" noResource="true"/>
</Properties>

View File

@ -4,8 +4,9 @@
* Created on October 16, 2008, 4:37 PM
*/
package jdbernard.timestamper;
package jdbernard.timestamper.gui;
import jdbernard.timestamper.core.TimelineMarker;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
@ -64,8 +65,8 @@ implements MouseMotionListener, ChangeListener {
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
dayDisplay = new jdbernard.timestamper.gui.TimelineDayDisplay();
mainPanel = new javax.swing.JPanel();
dayDisplay = new jdbernard.timestamper.TimelineDayDisplay();
detailPanel = new javax.swing.JPanel();
textPane = new javax.swing.JPanel();
markTextField = new javax.swing.JTextField();
@ -84,6 +85,19 @@ implements MouseMotionListener, ChangeListener {
deleteMarkerButton = new javax.swing.JButton();
saveMarkerChanges = new javax.swing.JButton();
dayDisplay.setName("dayDisplay"); // NOI18N
javax.swing.GroupLayout dayDisplayLayout = new javax.swing.GroupLayout(dayDisplay);
dayDisplay.setLayout(dayDisplayLayout);
dayDisplayLayout.setHorizontalGroup(
dayDisplayLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 100, Short.MAX_VALUE)
);
dayDisplayLayout.setVerticalGroup(
dayDisplayLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 100, Short.MAX_VALUE)
);
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setName("Form"); // NOI18N
setUndecorated(true);
@ -97,26 +111,12 @@ implements MouseMotionListener, ChangeListener {
});
mainPanel.addMouseMotionListener(this);
dayDisplay.setName("dayDisplay"); // NOI18N
dayDisplay.setPreferredSize(new java.awt.Dimension(100, 100));
javax.swing.GroupLayout dayDisplayLayout = new javax.swing.GroupLayout(dayDisplay);
dayDisplay.setLayout(dayDisplayLayout);
dayDisplayLayout.setHorizontalGroup(
dayDisplayLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 405, Short.MAX_VALUE)
);
dayDisplayLayout.setVerticalGroup(
dayDisplayLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 339, Short.MAX_VALUE)
);
detailPanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
detailPanel.setName("detailPanel"); // NOI18N
textPane.setName("textPane"); // NOI18N
org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(jdbernard.timestamper.TimeStamperApp.class).getContext().getResourceMap(PunchcardDisplayDialog.class);
org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(jdbernard.timestamper.gui.TimeStamperApp.class).getContext().getResourceMap(PunchcardDisplayDialog.class);
markTextField.setText(resourceMap.getString("markTextField.text")); // NOI18N
markTextField.setName("markTextField"); // NOI18N
@ -175,7 +175,7 @@ implements MouseMotionListener, ChangeListener {
gridBagConstraints.weightx = 1.0;
datePanel.add(dateLabel, gridBagConstraints);
javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(jdbernard.timestamper.TimeStamperApp.class).getContext().getActionMap(PunchcardDisplayDialog.class, this);
javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(jdbernard.timestamper.gui.TimeStamperApp.class).getContext().getActionMap(PunchcardDisplayDialog.class, this);
prevWeekButton.setAction(actionMap.get("previousWeek")); // NOI18N
prevWeekButton.setHideActionText(true);
prevWeekButton.setMargin(new java.awt.Insets(0, 2, 0, 2));
@ -270,26 +270,7 @@ implements MouseMotionListener, ChangeListener {
.addComponent(textPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
javax.swing.GroupLayout mainPanelLayout = new javax.swing.GroupLayout(mainPanel);
mainPanel.setLayout(mainPanelLayout);
mainPanelLayout.setHorizontalGroup(
mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, mainPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(dayDisplay, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 405, Short.MAX_VALUE)
.addComponent(detailPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
mainPanelLayout.setVerticalGroup(
mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, mainPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(dayDisplay, javax.swing.GroupLayout.DEFAULT_SIZE, 339, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(detailPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
mainPanel.add(detailPanel);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
@ -315,7 +296,7 @@ private void mainPanelMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:e
private javax.swing.JButton currentDayButton;
private javax.swing.JLabel dateLabel;
private javax.swing.JPanel datePanel;
private jdbernard.timestamper.TimelineDayDisplay dayDisplay;
private jdbernard.timestamper.gui.TimelineDayDisplay dayDisplay;
private javax.swing.JButton deleteMarkerButton;
private javax.swing.JPanel detailPanel;
private javax.swing.JPanel mainPanel;
@ -418,7 +399,7 @@ private void mainPanelMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:e
public void stateChanged(ChangeEvent e) {
if (e.getSource() == dayDisplay) {
Timeline.TimelineMarker marker = dayDisplay.getSelectedTimelineMarker();
TimelineMarker marker = dayDisplay.getSelectedTimelineMarker();
if (marker == null) {
timestampDateChooser.setDate(null);

View File

@ -14,6 +14,7 @@
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="2"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>

View File

@ -2,7 +2,7 @@
* TimeStamperAboutBox.java
*/
package jdbernard.timestamper;
package jdbernard.timestamper.gui;
import org.jdesktop.application.Action;
@ -37,13 +37,13 @@ public class TimeStamperAboutBox extends javax.swing.JDialog {
javax.swing.JLabel appDescLabel = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(jdbernard.timestamper.TimeStamperApp.class).getContext().getResourceMap(TimeStamperAboutBox.class);
org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(jdbernard.timestamper.gui.TimeStamperApp.class).getContext().getResourceMap(TimeStamperAboutBox.class);
setTitle(resourceMap.getString("title")); // NOI18N
setModal(true);
setName("aboutBox"); // NOI18N
setResizable(false);
javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(jdbernard.timestamper.TimeStamperApp.class).getContext().getActionMap(TimeStamperAboutBox.class, this);
javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(jdbernard.timestamper.gui.TimeStamperApp.class).getContext().getActionMap(TimeStamperAboutBox.class, this);
closeButton.setAction(actionMap.get("closeAboutBox")); // NOI18N
closeButton.setName("closeButton"); // NOI18N

View File

@ -2,7 +2,7 @@
* TimeStamperApp.java
*/
package jdbernard.timestamper;
package jdbernard.timestamper.gui;
import java.io.File;
import java.io.FileInputStream;
@ -16,6 +16,7 @@ import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import jdbernard.timestamper.core.TimelineProperties;
import org.jdesktop.application.Application;
import org.jdesktop.application.SingleFrameApplication;
@ -25,16 +26,14 @@ import org.jdesktop.application.SingleFrameApplication;
public class TimeStamperApp extends SingleFrameApplication
implements Application.ExitListener {
private Timeline activeTimeline;
private String currentTimelineFile;
private TimelineProperties timelineProperties;
private Logger log;
private Properties config;
public TimeStamperApp() {
super();
// set defaults for fields
activeTimeline = new Timeline();
timelineProperties = new TimelineProperties();
// set up logger
log = Logger.getLogger("jdbernard.timestamper");
@ -71,25 +70,14 @@ implements Application.ExitListener {
}
// load the last used timeline
loadTimeline(config.getProperty("lastUsedTimelineFilename"));
// TODO: fix
loadTimelineProperties(config.getProperty("lastUsedTimelineProperties", "timeline.default.properties"));
}
/**
*
*/
@Override protected void initialize(String[] args) {
if (args.length > 0) {
File inFile = new File(args[0]);
if (!inFile.exists())
try { inFile.createNewFile(); }
catch (IOException ioe) {
log.warning("No file '" + args[0] + " exists and an error"
+ " occurred trying to create it.");
}
currentTimelineFile = args[0];
loadTimeline(currentTimelineFile);
}
}
/**
@ -124,48 +112,45 @@ implements Application.ExitListener {
launch(TimeStamperApp.class, args);
}
public void saveTimeline() {
saveTimelineToFile(currentTimelineFile);
public TimelineProperties getTimelineProperties() {
return timelineProperties;
}
public void saveTimelineToFile(String filename) {
if (filename == null || filename.equals(""))
filename = "default-timeline.txt";
public void saveTimelineProperties() {
try {
Timeline.writeToFile(filename, activeTimeline);
currentTimelineFile = filename;
timelineProperties.save();
} catch (IOException ioe) {
log.warning("Could not save timeline file: "
+ ioe.getLocalizedMessage());
log.warning("Could not save the timeline to <"
+ timelineProperties.getTimelineSource().getURI().toString()
+ ">:" + ioe.getLocalizedMessage());
}
}
public void saveTimelinePropertiesAs(File propertyFile) {
try { timelineProperties.save(propertyFile); }
catch (IOException ioe) {
// TODO
}
}
public void loadTimeline(String filename) {
if (filename == null || filename.equals("")) {
activeTimeline = new Timeline();
return;
}
try {
activeTimeline = Timeline.readFromFile(filename);
currentTimelineFile = filename;
} catch (IOException ioe) {
log.warning("Could not load from the file: " +
ioe.getLocalizedMessage());
}
public void loadTimelineProperties(String filename) {
loadTimelineProperties(new File(filename));
}
public Timeline getActiveTimeline() {
return activeTimeline;
public void loadTimelineProperties(File propertyFile) {
try { timelineProperties = new TimelineProperties(propertyFile); }
catch (IOException ioe) {
// TODO
}
}
@Override
public void willExit(EventObject e) {
saveTimeline();
saveTimelineProperties();
config.setProperty("lastUsedTimelineFilename", currentTimelineFile);
config.setProperty("lastUsedTimelineProperties",
timelineProperties.getTimelineSource().getURI().toString());
try {
FileOutputStream out = new FileOutputStream("timestamper.config");
config.store(out, "");

View File

@ -267,6 +267,7 @@
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="2"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>

View File

@ -2,8 +2,10 @@
* TimeStamperView.java
*/
package jdbernard.timestamper;
package jdbernard.timestamper.gui;
import jdbernard.timestamper.core.TimelineMarker;
import jdbernard.timestamper.core.Timeline;
import java.awt.Font;
import java.awt.Point;
import java.awt.Rectangle;
@ -16,7 +18,6 @@ import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.ButtonGroup;
import javax.swing.JFileChooser;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
@ -24,7 +25,6 @@ import org.jdesktop.application.Action;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.FrameView;
import sun.security.jca.GetInstance;
/**
* The application's main frame.
@ -129,11 +129,11 @@ ChangeListener {
mainPanel.addMouseMotionListener(this);
currentTaskLabel.setFont(currentTaskLabel.getFont().deriveFont(currentTaskLabel.getFont().getStyle() | java.awt.Font.BOLD, currentTaskLabel.getFont().getSize()+2));
org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(jdbernard.timestamper.TimeStamperApp.class).getContext().getResourceMap(TimeStamperView.class);
org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(jdbernard.timestamper.gui.TimeStamperApp.class).getContext().getResourceMap(TimeStamperView.class);
currentTaskLabel.setText(resourceMap.getString("currentTaskLabel.text")); // NOI18N
currentTaskLabel.setName("currentTaskLabel"); // NOI18N
javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(jdbernard.timestamper.TimeStamperApp.class).getContext().getActionMap(TimeStamperView.class, this);
javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(jdbernard.timestamper.gui.TimeStamperApp.class).getContext().getActionMap(TimeStamperView.class, this);
exitButton.setAction(actionMap.get("quit")); // NOI18N
exitButton.setBorder(null);
exitButton.setContentAreaFilled(false);
@ -269,7 +269,8 @@ ChangeListener {
private void taskTextFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_taskTextFieldKeyReleased
if (evt.getKeyCode() == KeyEvent.VK_ENTER) {
Timeline t = ((TimeStamperApp) getApplication()).getActiveTimeline();
Timeline t = ((TimeStamperApp) getApplication())
.getTimelineProperties().getTimeline();
Date d = new Date();
t.addMarker(d, taskTextField.getText(), "No comments.");
startTimeLabel.setText(Timeline.shortFormat.format(d));
@ -312,8 +313,9 @@ ChangeListener {
}
public void setNotesForActiveTask(String notes) {
Timeline t = ((TimeStamperApp) getApplication()).getActiveTimeline();
Timeline.TimelineMarker tm = t.getLastMarker(new Date());
Timeline t = ((TimeStamperApp) getApplication())
.getTimelineProperties().getTimeline();
TimelineMarker tm = t.getLastMarker(new Date());
if (tm == null) return;
tm.setNotes(notes);
}
@ -472,7 +474,7 @@ ChangeListener {
@Action
public void saveTimeline() {
((TimeStamperApp) getApplication()).saveTimeline();
((TimeStamperApp) getApplication()).saveTimelineProperties();
}
@Action
@ -480,8 +482,8 @@ ChangeListener {
if (fileChooser.showSaveDialog(getFrame())!=JFileChooser.APPROVE_OPTION)
return;
((TimeStamperApp) getApplication()).saveTimelineToFile(
fileChooser.getSelectedFile().getAbsolutePath());
((TimeStamperApp) getApplication()).saveTimelinePropertiesAs(
fileChooser.getSelectedFile());
}
@Action
@ -489,15 +491,16 @@ ChangeListener {
if (fileChooser.showOpenDialog(getFrame())!=JFileChooser.APPROVE_OPTION)
return;
((TimeStamperApp) getApplication()).loadTimeline(
((TimeStamperApp) getApplication()).loadTimelineProperties(
fileChooser.getSelectedFile().getAbsolutePath());
fireChangeEvent();
}
public void refreshDialog() {
Timeline t = ((TimeStamperApp) getApplication()).getActiveTimeline();
Timeline.TimelineMarker lastMarker = t.getLastMarker(new Date());
Timeline t = ((TimeStamperApp) getApplication())
.getTimelineProperties().getTimeline();
TimelineMarker lastMarker = t.getLastMarker(new Date());
if (lastMarker != null) {
mostRecentTask = lastMarker.getTimestamp();

View File

@ -2,8 +2,10 @@
* Author: Jonathan Bernard - jonathan.bernard@gemalto.com
*/
package jdbernard.timestamper;
package jdbernard.timestamper.gui;
import jdbernard.timestamper.core.TimelineMarker;
import jdbernard.timestamper.core.Timeline;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
@ -31,7 +33,7 @@ public class TimelineDayDisplay extends JComponent implements MouseListener,
ChangeListener {
private class MarkerDisplayEntry {
public Timeline.TimelineMarker marker;
public TimelineMarker marker;
public float relY;
public float relHeight;
public Rectangle2D markBounds;
@ -186,7 +188,7 @@ public class TimelineDayDisplay extends JComponent implements MouseListener,
private ArrayList<MarkerDisplayEntry> markerEntries;
private ArrayList<TimeLegendEntry> timeLegendLocations;
private Timeline.TimelineMarker currentMarker;
private TimelineMarker currentMarker;
private ArrayList<ChangeListener> changeListeners = new ArrayList<ChangeListener>();
private Point lastMousePress;
@ -318,18 +320,20 @@ public class TimelineDayDisplay extends JComponent implements MouseListener,
return selectedOpaque;
}
public Timeline.TimelineMarker getSelectedTimelineMarker() {
public TimelineMarker getSelectedTimelineMarker() {
return currentMarker;
}
public void addMarker(Date timestamp, String mark, String notes) {
Timeline timeline = TimeStamperApp.getApplication().getActiveTimeline();
Timeline timeline = TimeStamperApp.getApplication()
.getTimelineProperties().getTimeline();
timeline.addMarker(timestamp, mark, notes);
updateMarkers(getGraphics());
}
public void deleteSelectedMarker() {
Timeline timeline = TimeStamperApp.getApplication().getActiveTimeline();
Timeline timeline = TimeStamperApp.getApplication()
.getTimelineProperties().getTimeline();
timeline.removeMarker(currentMarker);
updateMarkers(getGraphics());
}
@ -348,7 +352,8 @@ public class TimelineDayDisplay extends JComponent implements MouseListener,
*/
private void updateMarkers(Graphics g) {
Timeline timeline = TimeStamperApp.getApplication().getActiveTimeline();
Timeline timeline = TimeStamperApp.getApplication()
.getTimelineProperties().getTimeline();
Insets insets = this.getInsets();
Rectangle bounds = this.getBounds();
Rectangle canvasBounds = new Rectangle(insets.left, insets.top,
@ -396,7 +401,7 @@ public class TimelineDayDisplay extends JComponent implements MouseListener,
// get all relevant markers starting from the marker just before the
// visible start of the display
Timeline.TimelineMarker tm = timeline.getLastMarker(rangeStartDate);
TimelineMarker tm = timeline.getLastMarker(rangeStartDate);
// If there is no previous marker
if (tm == null)
@ -408,11 +413,11 @@ public class TimelineDayDisplay extends JComponent implements MouseListener,
// Now we want to step through the timeline, capturing all markers
// between the visible ranges.
Iterator<Timeline.TimelineMarker> itr = timeline.iterator();
Iterator<TimelineMarker> itr = timeline.iterator();
while (!itr.next().equals(tm));
ArrayList<Timeline.TimelineMarker> markers = new ArrayList<Timeline.TimelineMarker>();
ArrayList<TimelineMarker> markers = new ArrayList<TimelineMarker>();
while (rangeEndDate.after(tm.getTimestamp())) {
markers.add(tm);
if (itr.hasNext()) tm = itr.next();

View File

@ -0,0 +1,42 @@
markTextField.text=
previousWeek.Action.text=<<
previousWeek.Action.shortDescription=Go back one week.
dateLabel.text=date
#NOI18N
dateLabel.background=255, 255, 153
prevWeekButton.text=jButton1
previousWeek.Action.icon=icons/media-seek-backward.png
previousWeek.Action.smallIcon=icons/media-seek-backward.png
prevDayButton.text=jButton1
previousDay.Action.smallIcon=icons/media-playback-reverse.png
previousDay.Action.icon=icons/media-playback-reverse.png
previousDay.Action.shortDescription=Go back one day.
previousDay.Action.text=Previous Day
currentDay.Action.text=Today
currentDay.Action.shortDescription=Go to today's date.
jButton2.text=jButton2
nextDay.Action.smallIcon=icons/media-playback-start.png
nextDay.Action.icon=icons/media-playback-start.png
nextDay.Action.shortDescription=Go one day forward.
nextDay.Action.text=Next Day
nextWeekButton.text=jButton3
nextWeek.Action.text=Next Week
nextWeek.Action.smallIcon=icons/media-seek-forward.png
nextWeek.Action.icon=icons/media-seek-forward.png
nextWeek.Action.shortDescription=Go one week forward.
newMarkerButton.text=jButton1
newMarker.Action.smallIcon=icons/16-square-green-add.png
newMarker.Action.icon=icons/16-square-green-add.png
newMarker.Action.shortDescription=Create a new timestamp mark.
newMarker.Action.text=New Marker
deleteMarkerButton.text=jButton1
deleteMarker.Action.text=Delete Marker
deleteMarker.Action.shortDescription=Delete a timestamp mark.
deleteMarker.Action.smallIcon=icons/16-square-red-delete.png
deleteMarker.Action.icon=icons/16-square-red-delete.png
saveMarkerChanges.text=jButton1
saveMarkerChanges.Action.smallIcon=icons/document-save-16x16.png
saveMarkerChanges.Action.icon=icons/document-save-16x16.png
saveMarkerChanges.Action.shortDescription=Save timeline marker changes.
saveMarkerChanges.Action.text=Save Changes
timestampDateChooser.dateFormatString=MMM d, yyyy HH:mm

View File

@ -9,9 +9,9 @@ Application.description = Simple application used to track activities throughout
Application.vendorId = Jonathan Bernard
Application.id = TimeStamper
Application.lookAndFeel = system
Application.icon=/jdbernard/timestamper/resources/icons/appointment-new-32x32.png
Application.icon=icons/appointment-new-32x32.png
quit.Action.text=Exit
quit.Action.accelerator=ctrl pressed Q
quit.Action.smallIcon=/jdbernard/timestamper/resources/icons/16-em-cross.png
quit.Action.icon=/jdbernard/timestamper/resources/icons/16-em-cross.png
quit.Action.smallIcon=icons/16-em-cross.png
quit.Action.icon=icons/16-em-cross.png
quit.Action.shortDescription=Exit the application

View File

@ -14,36 +14,36 @@ totalTimeNow.text=3day 2hr 50min 25sec
#NOI18N
totalTimeNow.foreground=0, 153, 0
notesButton.text=jButton1
editNotes.Action.smallIcon=/jdbernard/timestamper/resources/icons/16-em-pencil.png
editNotes.Action.icon=/jdbernard/timestamper/resources/icons/16-em-pencil.png
editNotes.Action.smallIcon=icons/16-em-pencil.png
editNotes.Action.icon=icons/16-em-pencil.png
editNotes.Action.shortDescription=Edit notes for this task
editNotes.Action.text=Show Notes...
jButton1.text=
showOptionsMenu.Action.text=Options menu
showOptionsMenu.Action.shortDescription=Show the application's options menu.
showOptionsMenu.Action.smallIcon=/jdbernard/timestamper/resources/icons/16-tool-a.png
showOptionsMenu.Action.icon=/jdbernard/timestamper/resources/icons/16-tool-a.png
showOptionsMenu.Action.smallIcon=icons/16-tool-a.png
showOptionsMenu.Action.icon=icons/16-tool-a.png
saveTimelineMenuItem.text=Item
saveTimeline.Action.text=Save Timeline...
saveTimeline.Action.smallIcon=/jdbernard/timestamper/resources/icons/document-save-16x16.png
saveTimeline.Action.icon=/jdbernard/timestamper/resources/icons/document-save-16x16.png
saveTimeline.Action.smallIcon=icons/document-save-16x16.png
saveTimeline.Action.icon=icons/document-save-16x16.png
saveTimeline.Action.shortDescription=Save all actions to a timeline file.
saveTimelineAs.Action.smallIcon=/jdbernard/timestamper/resources/icons/document-save-as-16x16.png
saveTimelineAs.Action.icon=/jdbernard/timestamper/resources/icons/document-save-as-16x16.png
saveTimelineAs.Action.smallIcon=icons/document-save-as-16x16.png
saveTimelineAs.Action.icon=icons/document-save-as-16x16.png
saveTimelineAs.Action.shortDescription=Save actions to a new timeline file.
saveTimelineAs.Action.text=Save Timeline As...
loadTimelineMenuItem.text=Item
loadTimeline.Action.text=Load Timeline...
loadTimeline.Action.shortDescription=Load a set of actions from a timeline file
loadTimeline.Action.smallIcon=/jdbernard/timestamper/resources/icons/document-open-16x16.png
loadTimeline.Action.icon=/jdbernard/timestamper/resources/icons/document-open-16x16.png
loadTimeline.Action.smallIcon=icons/document-open-16x16.png
loadTimeline.Action.icon=icons/document-open-16x16.png
currentTimeLabel.text=12:00:00
#NOI18N
currentTimeLabel.foreground=204, 0, 0
exit.Action.text=Exit
exit.Action.smallIcon=/jdbernard/timestamper/resources/icons/16-em-cross.png
exit.Action.smallIcon=icons/16-em-cross.png
exit.Action.shortDescription=Close the application.
exit.Action.icon=/jdbernard/timestamper/resources/icons/16-em-cross.png
exit.Action.icon=icons/16-em-cross.png
notesButton2.text=jToggleButton1
#NOI18N
optionsButton.rolloverIcon=icons/16-tool-a-hover.png
@ -53,8 +53,8 @@ showNotesDialogCheckBoxMenuItem.text=CheckBox
showPunchcardCheckBoxMenuItem.text=CheckBox
showPunchcard.Action.shortDescription=View the timeline
showPunchcard.Action.text=Show Timeline...
showPunchcard.Action.smallIcon=/jdbernard/timestamper/resources/icons/16-file-archive.png
showPunchcard.Action.icon=/jdbernard/timestamper/resources/icons/16-file-archive.png
showPunchcard.Action.smallIcon=icons/16-file-archive.png
showPunchcard.Action.icon=icons/16-file-archive.png
editNotes.Action.accelerator=ctrl pressed N
showPunchcard.Action.accelerator=ctrl pressed T
showAboutCheckBoxMenuItem.text=CheckBox

View File

@ -1,42 +0,0 @@
markTextField.text=
previousWeek.Action.text=<<
previousWeek.Action.shortDescription=Go back one week.
dateLabel.text=date
#NOI18N
dateLabel.background=255, 255, 153
prevWeekButton.text=jButton1
previousWeek.Action.icon=/jdbernard/timestamper/resources/icons/media-seek-backward.png
previousWeek.Action.smallIcon=/jdbernard/timestamper/resources/icons/media-seek-backward.png
prevDayButton.text=jButton1
previousDay.Action.smallIcon=/jdbernard/timestamper/resources/icons/media-playback-reverse.png
previousDay.Action.icon=/jdbernard/timestamper/resources/icons/media-playback-reverse.png
previousDay.Action.shortDescription=Go back one day.
previousDay.Action.text=Previous Day
currentDay.Action.text=Today
currentDay.Action.shortDescription=Go to today's date.
jButton2.text=jButton2
nextDay.Action.smallIcon=/jdbernard/timestamper/resources/icons/media-playback-start.png
nextDay.Action.icon=/jdbernard/timestamper/resources/icons/media-playback-start.png
nextDay.Action.shortDescription=Go one day forward.
nextDay.Action.text=Next Day
nextWeekButton.text=jButton3
nextWeek.Action.text=Next Week
nextWeek.Action.smallIcon=/jdbernard/timestamper/resources/icons/media-seek-forward.png
nextWeek.Action.icon=/jdbernard/timestamper/resources/icons/media-seek-forward.png
nextWeek.Action.shortDescription=Go one week forward.
newMarkerButton.text=jButton1
newMarker.Action.smallIcon=/jdbernard/timestamper/resources/icons/16-square-green-add.png
newMarker.Action.icon=/jdbernard/timestamper/resources/icons/16-square-green-add.png
newMarker.Action.shortDescription=Create a new timestamp mark.
newMarker.Action.text=New Marker
deleteMarkerButton.text=jButton1
deleteMarker.Action.text=Delete Marker
deleteMarker.Action.shortDescription=Delete a timestamp mark.
deleteMarker.Action.smallIcon=/jdbernard/timestamper/resources/icons/16-square-red-delete.png
deleteMarker.Action.icon=/jdbernard/timestamper/resources/icons/16-square-red-delete.png
saveMarkerChanges.text=jButton1
saveMarkerChanges.Action.smallIcon=/jdbernard/timestamper/resources/icons/document-save-16x16.png
saveMarkerChanges.Action.icon=/jdbernard/timestamper/resources/icons/document-save-16x16.png
saveMarkerChanges.Action.shortDescription=Save timeline marker changes.
saveMarkerChanges.Action.text=Save Changes
timestampDateChooser.dateFormatString=MMM d, yyyy HH:mm