From ffdce9c00d9c8896454f2551ce8a38b3cb103b68 Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Sat, 18 Oct 2008 18:18:51 -0500 Subject: [PATCH] Finished version 1.5 Added timeline viewer for a single day Added icon resources Modified build file to clean more stuff committer: Jonathan Bernard --- build.xml | 2 +- lib/jcalendar-1.3.2.jar | Bin 0 -> 126630 bytes nbproject/project.properties | 4 +- .../timestamper/PunchcardDisplayDialog.form | 323 ++++++++++++++- .../timestamper/PunchcardDisplayDialog.java | 378 ++++++++++++++++-- .../timestamper/TimeStamperView.form | 21 + .../timestamper/TimeStamperView.java | 50 ++- .../timestamper/TimelineDayDisplay.java | 346 +++++++++++++--- .../PunchcardDisplayDialog.properties | 42 ++ .../resources/TimeStamperView.properties | 8 +- .../resources/icons/16-file-archive.png | Bin 0 -> 293 bytes .../resources/icons/16-square-green-add.png | Bin 0 -> 345 bytes .../resources/icons/16-square-red-delete.png | Bin 0 -> 321 bytes .../icons/media-playback-reverse.png | Bin 0 -> 636 bytes .../resources/icons/media-playback-start.png | Bin 0 -> 660 bytes .../resources/icons/media-seek-backward.png | Bin 0 -> 764 bytes .../resources/icons/media-seek-forward.png | Bin 0 -> 782 bytes .../resources/icons/media-skip-backward.png | Bin 0 -> 770 bytes .../resources/icons/media-skip-forward.png | Bin 0 -> 771 bytes 19 files changed, 1070 insertions(+), 104 deletions(-) create mode 100755 lib/jcalendar-1.3.2.jar create mode 100755 src/jdbernard/timestamper/resources/PunchcardDisplayDialog.properties create mode 100755 src/jdbernard/timestamper/resources/icons/16-file-archive.png create mode 100755 src/jdbernard/timestamper/resources/icons/16-square-green-add.png create mode 100755 src/jdbernard/timestamper/resources/icons/16-square-red-delete.png create mode 100755 src/jdbernard/timestamper/resources/icons/media-playback-reverse.png create mode 100755 src/jdbernard/timestamper/resources/icons/media-playback-start.png create mode 100755 src/jdbernard/timestamper/resources/icons/media-seek-backward.png create mode 100755 src/jdbernard/timestamper/resources/icons/media-seek-forward.png create mode 100755 src/jdbernard/timestamper/resources/icons/media-skip-backward.png create mode 100755 src/jdbernard/timestamper/resources/icons/media-skip-forward.png diff --git a/build.xml b/build.xml index c6bbd56..aa2ddcd 100755 --- a/build.xml +++ b/build.xml @@ -87,7 +87,7 @@ - + diff --git a/lib/jcalendar-1.3.2.jar b/lib/jcalendar-1.3.2.jar new file mode 100755 index 0000000000000000000000000000000000000000..b5e5a2d824fee85ac095ea1833682d2ce6699186 GIT binary patch literal 126630 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
E{Eu6k>tt7+#WkuHK>!D6jMF*-Z6mrFBjhkI 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

~ z-4Ja!qh=od`;Xc8%lF{s$Qj$ocVIg`_Ck;JJr_;+(X;2iM3Tw%)RK<-=HiZL>O#Hd zGJ2wU-##rcQjs&pGV6mHV*!IWl8orI=&$|amIyrOW!bhKbG9M|a>g0$3k*3ml$1u> zGudB-$Whs-TynpAI{ zP~p{=h%xEaFc4Svue$b>l`(S0a#?e^_Qb1UBT_pa7>%=HjGU49y;o~byqo7@`LxZl zrqP&=$r*_^x?X$Y-8~b(_IUdSAs|f7NPOe3wI?3snRwvL6Dt;iy(VWQPAa6et%RO_w-D>Ptd&QD?yl?k$4o2;np_gy*v}2x$~irDJT+hy$qw+ zbpP5DkDZ)5yHGK><2jmL{g-(^joFl(aZ+swi%7N1LsinWOzpFx&FDo)J-P0N9E99f z6KQp6=o%imR98{!)lVc8MOj`z_>&+{&Nv8v)2|j$B>A0qv84 z)x@Ia!8PdAK>f3IKRk5{S`axS^$Hxj^H>8OsVkde<`S|T?^c?G!Y5~Jqup_6tya|C zn}KHHZ@jl;_FNDqXC!{2F2p^jTwk}O)}Z}uE?z$T1}U#ywZ3qVwP9ZrIyqwm^RaVP zW6_u+@SFp`V{^V)iZ(;eShGPmcvag7=(JLYY1vcFg>S!lWZMW73OOT__BFQpYD>NP z%00Af*@}BXo1BsU(usAW@40kNADnhz0ZN9Pk$yT3Gu|Nm+KQ}(eieSY#oZ-z#9lW&g0nsp%WIrV1fayR*lHzKcJU)E6m zW&mY(46nghR*e~`5`*VFn6X#gF?^O=hZw4_12cT8JAwsyb&SAs4$PRQ?g)n6af1kS zE5sTq!3?bEj-c)AI!53*2WA*HcLbAwI8b9P>vB+i6_|0<-1PrhNBULMPZDD@u$i0w zTL79cq~9&PHi1D^Wq*jW8OOy}eQ_-b*Sxefn>BYwaB)fX z5xBI3t6LYEEl9h`9$!`qvYrdWY-7kxRM=1pqBR$U*(#5lc)N|&6W3c?@tkP0#Tz%> z)|+ZY*I@g^a~x*V74A6pZ>dcjo~fG8_PVM5{9LtE^`}Lvk|jRgeCp3lw)>uH$!c7% zLSEf*s9`KLpFwg*BA5PwNUDw}loRtQ26rSK%j*_N^<$#>B!WAR6MrBM&-pMP5pc(` z=9L@f!!;DtP#b2gWp@Nw6?Kfja}Lb9kM0N-9H@N+)z^YqfzeIB@f&rcUp4(Sf0*?P m-Sj^;(dS#CuBE0<+i>_0Z^)b(Y=n$wzv0CG^5YOavHu5_d}!VP literal 0 HcmV?d00001 diff --git a/nbproject/project.properties b/nbproject/project.properties index 507c11d..10359c7 100755 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -22,12 +22,14 @@ 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=C:\\Documents and Settings\\jbernard\\My Documents\\Development\\TimeStamper\\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.swing-worker-1.1.jar}:\ + ${file.reference.jcalendar-1.3.2.jar} # Space-separated list of extra javac options javac.compilerargs= javac.deprecation=false diff --git a/src/jdbernard/timestamper/PunchcardDisplayDialog.form b/src/jdbernard/timestamper/PunchcardDisplayDialog.form index e1b8c0f..fb11481 100755 --- a/src/jdbernard/timestamper/PunchcardDisplayDialog.form +++ b/src/jdbernard/timestamper/PunchcardDisplayDialog.form @@ -4,6 +4,7 @@ + @@ -22,44 +23,334 @@ - - - - - + - - - - - + - + - - - + + + + + + + + + + + - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/jdbernard/timestamper/PunchcardDisplayDialog.java b/src/jdbernard/timestamper/PunchcardDisplayDialog.java index 7f7c9e7..f438f45 100755 --- a/src/jdbernard/timestamper/PunchcardDisplayDialog.java +++ b/src/jdbernard/timestamper/PunchcardDisplayDialog.java @@ -6,20 +6,39 @@ package jdbernard.timestamper; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionListener; import java.io.File; +import java.text.SimpleDateFormat; import java.util.Calendar; +import javax.swing.JDialog; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import org.jdesktop.application.Action; /** * * @author jbernard */ -public class PunchcardDisplayDialog extends javax.swing.JDialog { +public class PunchcardDisplayDialog extends JDialog +implements MouseMotionListener, ChangeListener { /** Creates new form PunchcardDisplayDialog */ - public PunchcardDisplayDialog(java.awt.Frame parent, boolean modal) { + public PunchcardDisplayDialog(Frame parent, boolean modal, + Timeline timeline, Calendar day) { super(parent, modal); + this.timeline = timeline; + this.day = day; initComponents(); - timelineDayDisplay1.setDay(Calendar.getInstance()); + markTextField.setFont(dayDisplay.getMarkFont()); + notesTextArea.setFont(dayDisplay.getNotesFont()); + dayDisplay.setTimeline(timeline); + dayDisplay.setDay(day); + dayDisplay.addChangeListener(this); } /** This method is called from within the constructor to @@ -30,58 +49,268 @@ public class PunchcardDisplayDialog extends javax.swing.JDialog { @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { + java.awt.GridBagConstraints gridBagConstraints; - timelineDayDisplay1 = new jdbernard.timestamper.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(); + notesScrollPane = new javax.swing.JScrollPane(); + notesTextArea = new javax.swing.JTextArea(); + timestampDateChooser = new com.toedter.calendar.JDateChooser(); + buttonPanel = new javax.swing.JPanel(); + datePanel = new javax.swing.JPanel(); + dateLabel = new javax.swing.JLabel(); + prevWeekButton = new javax.swing.JButton(); + prevDayButton = new javax.swing.JButton(); + currentDayButton = new javax.swing.JButton(); + nextDayButton = new javax.swing.JButton(); + nextWeekButton = new javax.swing.JButton(); + newMarkerButton = new javax.swing.JButton(); + deleteMarkerButton = new javax.swing.JButton(); + saveMarkerChanges = new javax.swing.JButton(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); setName("Form"); // NOI18N + setUndecorated(true); - timelineDayDisplay1.setName("timelineDayDisplay1"); // NOI18N + mainPanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0), 2)); + mainPanel.setName("mainPanel"); // NOI18N + mainPanel.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + mainPanelMousePressed(evt); + } + }); + mainPanel.addMouseMotionListener(this); - javax.swing.GroupLayout timelineDayDisplay1Layout = new javax.swing.GroupLayout(timelineDayDisplay1); - timelineDayDisplay1.setLayout(timelineDayDisplay1Layout); - timelineDayDisplay1Layout.setHorizontalGroup( - timelineDayDisplay1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 380, Short.MAX_VALUE) + 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) ); - timelineDayDisplay1Layout.setVerticalGroup( - timelineDayDisplay1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 278, 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); + markTextField.setText(resourceMap.getString("markTextField.text")); // NOI18N + markTextField.setName("markTextField"); // NOI18N + + notesScrollPane.setName("notesScrollPane"); // NOI18N + + notesTextArea.setColumns(20); + notesTextArea.setRows(5); + notesTextArea.setName("notesTextArea"); // NOI18N + notesScrollPane.setViewportView(notesTextArea); + + timestampDateChooser.setDateFormatString(resourceMap.getString("timestampDateChooser.dateFormatString")); // NOI18N + timestampDateChooser.setName("timestampDateChooser"); // NOI18N + + javax.swing.GroupLayout textPaneLayout = new javax.swing.GroupLayout(textPane); + textPane.setLayout(textPaneLayout); + textPaneLayout.setHorizontalGroup( + textPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, textPaneLayout.createSequentialGroup() + .addContainerGap() + .addGroup(textPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(notesScrollPane, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 238, Short.MAX_VALUE) + .addComponent(timestampDateChooser, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 238, Short.MAX_VALUE) + .addComponent(markTextField, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 238, Short.MAX_VALUE)) + .addContainerGap()) + ); + textPaneLayout.setVerticalGroup( + textPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(textPaneLayout.createSequentialGroup() + .addContainerGap() + .addComponent(timestampDateChooser, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(markTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(notesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 36, Short.MAX_VALUE) + .addContainerGap()) + ); + + buttonPanel.setName("buttonPanel"); // NOI18N + buttonPanel.setLayout(new java.awt.GridBagLayout()); + + datePanel.setName("datePanel"); // NOI18N + datePanel.setLayout(new java.awt.GridBagLayout()); + + dateLabel.setBackground(resourceMap.getColor("dateLabel.background")); // NOI18N + dateLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + dateLabel.setText(resourceMap.getString("dateLabel.text")); // NOI18N + dateLabel.setName("dateLabel"); // NOI18N + dateLabel.setOpaque(true); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.gridwidth = 5; + gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; + 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); + prevWeekButton.setAction(actionMap.get("previousWeek")); // NOI18N + prevWeekButton.setHideActionText(true); + prevWeekButton.setMargin(new java.awt.Insets(0, 2, 0, 2)); + prevWeekButton.setName("prevWeekButton"); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 1; + datePanel.add(prevWeekButton, gridBagConstraints); + + prevDayButton.setAction(actionMap.get("previousDay")); // NOI18N + prevDayButton.setHideActionText(true); + prevDayButton.setMargin(new java.awt.Insets(0, 2, 0, 2)); + prevDayButton.setName("prevDayButton"); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 1; + datePanel.add(prevDayButton, gridBagConstraints); + + currentDayButton.setAction(actionMap.get("currentDay")); // NOI18N + currentDayButton.setMargin(new java.awt.Insets(0, 2, 0, 2)); + currentDayButton.setName("currentDayButton"); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 2; + gridBagConstraints.gridy = 1; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.weightx = 1.0; + datePanel.add(currentDayButton, gridBagConstraints); + + nextDayButton.setAction(actionMap.get("nextDay")); // NOI18N + nextDayButton.setHideActionText(true); + nextDayButton.setMargin(new java.awt.Insets(0, 2, 0, 2)); + nextDayButton.setName("nextDayButton"); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 3; + gridBagConstraints.gridy = 1; + datePanel.add(nextDayButton, gridBagConstraints); + + nextWeekButton.setAction(actionMap.get("nextWeek")); // NOI18N + nextWeekButton.setHideActionText(true); + nextWeekButton.setMargin(new java.awt.Insets(0, 2, 0, 2)); + nextWeekButton.setName("nextWeekButton"); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 4; + gridBagConstraints.gridy = 1; + datePanel.add(nextWeekButton, gridBagConstraints); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.weightx = 1.0; + buttonPanel.add(datePanel, gridBagConstraints); + + newMarkerButton.setAction(actionMap.get("newMarker")); // NOI18N + newMarkerButton.setName("newMarkerButton"); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 1; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.weightx = 1.0; + buttonPanel.add(newMarkerButton, gridBagConstraints); + + deleteMarkerButton.setAction(actionMap.get("deleteMarker")); // NOI18N + deleteMarkerButton.setName("deleteMarkerButton"); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 2; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.weightx = 1.0; + buttonPanel.add(deleteMarkerButton, gridBagConstraints); + + saveMarkerChanges.setAction(actionMap.get("saveMarkerChanges")); // NOI18N + saveMarkerChanges.setName("saveMarkerChanges"); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 3; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + buttonPanel.add(saveMarkerChanges, gridBagConstraints); + + javax.swing.GroupLayout detailPanelLayout = new javax.swing.GroupLayout(detailPanel); + detailPanel.setLayout(detailPanelLayout); + detailPanelLayout.setHorizontalGroup( + detailPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, detailPanelLayout.createSequentialGroup() + .addComponent(textPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 139, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + detailPanelLayout.setVerticalGroup( + detailPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(buttonPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .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()) ); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(timelineDayDisplay1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addContainerGap()) + .addComponent(mainPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(timelineDayDisplay1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addContainerGap()) + .addComponent(mainPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); pack(); }// //GEN-END:initComponents +private void mainPanelMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_mainPanelMousePressed + mousePressRelativeToWindow = evt.getPoint(); +}//GEN-LAST:event_mainPanelMousePressed + /** * @param args the command line arguments */ public static void main(String args[]) throws Exception { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { - PunchcardDisplayDialog dialog = new PunchcardDisplayDialog(new javax.swing.JFrame(), true); - try { dialog.timelineDayDisplay1.setTimeline(Timeline.readFromFile("test-timeline.txt")); } + Timeline timeline = null; + Calendar day = Calendar.getInstance(); + try { timeline = Timeline.readFromFile("test-timeline.txt"); } catch (Exception e) { - System.err.println("Could not open timeline text."); + System.err.println("Could not open timeline text:"); + e.printStackTrace(System.err); + timeline = new Timeline(); try { new File("PLACE_HERE").createNewFile(); } catch (Exception e1) {} } + PunchcardDisplayDialog dialog = new PunchcardDisplayDialog(new javax.swing.JFrame(), true, timeline, day); dialog.addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent e) { System.exit(0); @@ -92,9 +321,108 @@ public class PunchcardDisplayDialog extends javax.swing.JDialog { }); } + @Action + public void previousWeek() { + day.add(Calendar.WEEK_OF_YEAR, -1); + dayDisplay.setDay(day); + dateLabel.setText(dateFormatter.format(day.getTime())); + repaint(); + } + + @Action + public void previousDay() { + day.add(Calendar.DAY_OF_YEAR, -1); + dayDisplay.setDay(day); + dateLabel.setText(dateFormatter.format(day.getTime())); + repaint(); + } + + @Action + public void currentDay() { + day = Calendar.getInstance(); + dayDisplay.setDay(day); + dateLabel.setText(dateFormatter.format(day.getTime())); + repaint(); + } + + @Action + public void nextDay() { + day.add(Calendar.DAY_OF_YEAR, 1); + dayDisplay.setDay(day); + dateLabel.setText(dateFormatter.format(day.getTime())); + repaint(); + } + + @Action + public void nextWeek() { + day.add(Calendar.WEEK_OF_YEAR, 1); + dayDisplay.setDay(day); + dateLabel.setText(dateFormatter.format(day.getTime())); + repaint(); + } + + @Action + public void newMarker() { + dayDisplay.addMarker(timestampDateChooser.getDate(), + markTextField.getText(), notesTextArea.getText()); + repaint(); + } + + @Action + public void deleteMarker() { + dayDisplay.deleteSelectedMarker(); + repaint(); + } + + @Action + public void saveMarkerChanges() { + deleteMarker(); + newMarker(); + } + // Variables declaration - do not modify//GEN-BEGIN:variables - private jdbernard.timestamper.TimelineDayDisplay timelineDayDisplay1; + private javax.swing.JPanel buttonPanel; + private javax.swing.JButton currentDayButton; + private javax.swing.JLabel dateLabel; + private javax.swing.JPanel datePanel; + private jdbernard.timestamper.TimelineDayDisplay dayDisplay; + private javax.swing.JButton deleteMarkerButton; + private javax.swing.JPanel detailPanel; + private javax.swing.JPanel mainPanel; + private javax.swing.JTextField markTextField; + private javax.swing.JButton newMarkerButton; + private javax.swing.JButton nextDayButton; + private javax.swing.JButton nextWeekButton; + private javax.swing.JScrollPane notesScrollPane; + private javax.swing.JTextArea notesTextArea; + private javax.swing.JButton prevDayButton; + private javax.swing.JButton prevWeekButton; + private javax.swing.JButton saveMarkerChanges; + private javax.swing.JPanel textPane; + private com.toedter.calendar.JDateChooser timestampDateChooser; // End of variables declaration//GEN-END:variables + private Calendar day; private Timeline timeline; + private SimpleDateFormat dateFormatter = + new SimpleDateFormat("EEE MMM dd"); + private Point mousePressRelativeToWindow; + + public void mouseDragged(MouseEvent e) { + setLocation(TimeStamperView.calculateWindowMovement( + e.getLocationOnScreen(), mousePressRelativeToWindow, + getBounds(), + new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()))); + } + + public void mouseMoved(MouseEvent e) { + } + + public void stateChanged(ChangeEvent e) { + Timeline.TimelineMarker marker = dayDisplay.getSelectedTimelineMarker(); + timestampDateChooser.setDate(marker.getTimestamp()); + + markTextField.setText(marker.getMark()); + notesTextArea.setText(marker.getNotes()); + } } diff --git a/src/jdbernard/timestamper/TimeStamperView.form b/src/jdbernard/timestamper/TimeStamperView.form index 313417c..b4d2ebd 100755 --- a/src/jdbernard/timestamper/TimeStamperView.form +++ b/src/jdbernard/timestamper/TimeStamperView.form @@ -222,6 +222,27 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/jdbernard/timestamper/TimeStamperView.java b/src/jdbernard/timestamper/TimeStamperView.java index 790fe15..07f18c3 100755 --- a/src/jdbernard/timestamper/TimeStamperView.java +++ b/src/jdbernard/timestamper/TimeStamperView.java @@ -11,9 +11,11 @@ import java.awt.Toolkit; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; +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 org.jdesktop.application.Action; import org.jdesktop.application.ResourceMap; @@ -98,6 +100,9 @@ public class TimeStamperView extends FrameView implements MouseMotionListener { saveTimelineMenuItem = new javax.swing.JMenuItem(); saveTimelineAsMenuItem = new javax.swing.JMenuItem(); loadTimelineMenuItem = new javax.swing.JMenuItem(); + seperator1 = new javax.swing.JSeparator(); + showNotesDialogCheckBoxMenuItem = new javax.swing.JCheckBoxMenuItem(); + showPunchcardCheckBoxMenuItem = new javax.swing.JCheckBoxMenuItem(); mainPanel.setBorder(javax.swing.BorderFactory.createMatteBorder(2, 2, 2, 2, new java.awt.Color(0, 0, 0))); mainPanel.setName("mainPanel"); // NOI18N @@ -177,13 +182,13 @@ public class TimeStamperView extends FrameView implements MouseMotionListener { .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(mainPanelLayout.createSequentialGroup() .addComponent(totalTimeNow) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 23, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 58, Short.MAX_VALUE) .addComponent(currentTimeLabel)) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, mainPanelLayout.createSequentialGroup() .addComponent(currentTaskLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(startTimeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 95, Short.MAX_VALUE)) - .addComponent(taskTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 266, Short.MAX_VALUE)) + .addComponent(startTimeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 116, Short.MAX_VALUE)) + .addComponent(taskTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 275, Short.MAX_VALUE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(optionsButton) @@ -226,6 +231,17 @@ public class TimeStamperView extends FrameView implements MouseMotionListener { loadTimelineMenuItem.setName("loadTimelineMenuItem"); // NOI18N optionsMenu.add(loadTimelineMenuItem); + seperator1.setName("seperator1"); // NOI18N + optionsMenu.add(seperator1); + + showNotesDialogCheckBoxMenuItem.setAction(actionMap.get("editNotes")); // NOI18N + showNotesDialogCheckBoxMenuItem.setName("showNotesDialogCheckBoxMenuItem"); // NOI18N + optionsMenu.add(showNotesDialogCheckBoxMenuItem); + + showPunchcardCheckBoxMenuItem.setAction(actionMap.get("showPunchcard")); // NOI18N + showPunchcardCheckBoxMenuItem.setName("showPunchcardCheckBoxMenuItem"); // NOI18N + optionsMenu.add(showPunchcardCheckBoxMenuItem); + setComponent(mainPanel); }// //GEN-END:initComponents @@ -252,7 +268,17 @@ public class TimeStamperView extends FrameView implements MouseMotionListener { @Action public void editNotes() { - notesDialog.setVisible(notesButton.isSelected()); + notesVisible = !notesVisible; + notesDialog.setVisible(notesVisible); + notesButton.setSelected(notesVisible); + showNotesDialogCheckBoxMenuItem.setSelected(notesVisible); + } + + @Action + public void showPunchcard() { + punchcardVisible = !punchcardVisible; + showPunchcardCheckBoxMenuItem.setSelected(punchcardVisible); + getPunchcardDisplayDialog().setVisible(punchcardVisible); } public void setNotesForActiveTask(String notes) { @@ -273,6 +299,9 @@ public class TimeStamperView extends FrameView implements MouseMotionListener { private javax.swing.JPopupMenu optionsMenu; private javax.swing.JMenuItem saveTimelineAsMenuItem; private javax.swing.JMenuItem saveTimelineMenuItem; + private javax.swing.JSeparator seperator1; + private javax.swing.JCheckBoxMenuItem showNotesDialogCheckBoxMenuItem; + private javax.swing.JCheckBoxMenuItem showPunchcardCheckBoxMenuItem; private javax.swing.JLabel startTimeLabel; private javax.swing.JTextField taskTextField; private javax.swing.JLabel totalTimeNow; @@ -285,6 +314,19 @@ public class TimeStamperView extends FrameView implements MouseMotionListener { private Font thinTaskFont; private Date mostRecentTask; private NotesDialog notesDialog; + private PunchcardDisplayDialog punchcardDisplayDialog; + private boolean notesVisible = false; + private boolean punchcardVisible = false; + + private PunchcardDisplayDialog getPunchcardDisplayDialog() { + if (punchcardDisplayDialog == null) { + punchcardDisplayDialog = new PunchcardDisplayDialog(this.getFrame(), + false, + ((TimeStamperApp) getApplication()).getActiveTimeline(), + Calendar.getInstance()); + } + return punchcardDisplayDialog; + } public void mouseDragged(MouseEvent e) { getFrame().setLocation(calculateWindowMovement(e.getLocationOnScreen(), diff --git a/src/jdbernard/timestamper/TimelineDayDisplay.java b/src/jdbernard/timestamper/TimelineDayDisplay.java index cf64a7c..58b8621 100755 --- a/src/jdbernard/timestamper/TimelineDayDisplay.java +++ b/src/jdbernard/timestamper/TimelineDayDisplay.java @@ -6,43 +6,73 @@ package jdbernard.timestamper; 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.util.ArrayList; import java.util.Calendar; +import java.util.Date; import java.util.Iterator; import javax.swing.JComponent; -import javax.swing.JLabel; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; /** * * @author jbernard */ -public class TimelineDayDisplay extends JComponent { +public class TimelineDayDisplay extends JComponent implements MouseListener { + + private class MarkerDisplayEntry { + public Timeline.TimelineMarker marker; + public float relY; + public float relHeight; + public Rectangle2D markBounds; + public Rectangle2D notesBounds; + public Rectangle bounds; + } private Timeline timeline; - private Calendar day; + private ArrayList markerEntries; + private Calendar day = Calendar.getInstance(); + private Calendar nextDay = Calendar.getInstance(); + private Timeline.TimelineMarker currentMarker; + private ArrayList changeListeners = new ArrayList(); - private final Color evenTrans = new Color(0.75f, 0.75f, 0.75f, 0.4f); - private final Color evenOpaque = new Color(0.75f, 0.75f, 0.75f, 1f); - private final Color oddTrans = new Color(0.5f, 0.5f, 0.5f, 0.4f); - private final Color oddOpaque = new Color(0.5f, 0.5f, 0.5f, 1f); + 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 long oneDayInMilli = (24 * 60 * 60 * 1000); public TimelineDayDisplay() { super(); + addMouseListener(this); } public TimelineDayDisplay(Timeline timeline, Calendar day) { - super(); + this(); this.timeline = timeline; this.day = day; + updateMarkers(getGraphics()); } public void setTimeline(Timeline t) { timeline = t; + updateMarkers(getGraphics()); } public Timeline getTimeline() { @@ -50,44 +80,103 @@ public class TimelineDayDisplay extends JComponent { } public void setDay(Calendar d) { - day = d; + day.setTime(d.getTime()); day.set(Calendar.HOUR_OF_DAY, 0); day.set(Calendar.MINUTE, 0); day.set(Calendar.SECOND, 0); + + nextDay.setTime(day.getTime()); + nextDay.add(Calendar.DAY_OF_YEAR, 1); + updateMarkers(getGraphics()); } public Calendar getDay() { return day; } - @Override - public void paintComponent(Graphics 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); + public void setMarkFont(Font f) { + markFont = f; + } - Calendar nextDay = Calendar.getInstance(); - nextDay.setTime(day.getTime()); - nextDay.add(Calendar.DAY_OF_YEAR, 1); + public Font getMarkFont() { + return markFont; + } - Graphics2D g2d = (Graphics2D) g; - double hourHeight = canvasBounds.getHeight() / 24.0; - long oneDayInMilli = (24 * 60 * 60 * 1000); - Rectangle2D stringBounds = getFontMetrics(getFont()).getStringBounds("00:00 ", g); - for (int i = 1; i < 24; i++) { - int lineY = (int) Math.round(hourHeight * (double) i); - g.drawLine(canvasBounds.x + (int) stringBounds.getWidth(), canvasBounds.y + lineY, - canvasBounds.x + canvasBounds.width, - canvasBounds.y + lineY); + public void setNotesFont(Font f) { + notesFont = f; + } - if ((hourHeight > (stringBounds.getHeight()) || ((i % 2) == 0))) { - g.drawString(String.format("%1$02d:00", i), - canvasBounds.x + 2, lineY + (int) (stringBounds.getHeight() / 2)); - } - } + public Font getNotesFont() { + return notesFont; + } + public void setFontColor(Color f) { + fontColor = new Color(f.getRGB()); + } + + public Color getFontColor() { + return fontColor; + } + public void setEvenColor(Color c) { + evenOpaque = new Color(c.getRGB()); + evenTrans = new Color((float) c.getRed() / 255f, + (float) c.getGreen() / 255f, + (float) c.getBlue() / 255f, 0.4f); + } + + public Color getEvenColor() { + return evenOpaque; + } + + public void setOddColor(Color c) { + oddOpaque = new Color(c.getRGB()); + oddTrans = new Color((float) c.getRed() / 255f, + (float) c.getGreen() / 255f, + (float) c.getBlue() / 255f, 0.4f); + } + + public Color getOddColor() { + return oddOpaque; + } + + public void setSelectedColor(Color c) { + selectedOpaque = new Color(c.getRGB()); + selectedTrans = new Color((float) c.getRed() / 255f, + (float) c.getGreen() / 255f, + (float) c.getBlue() / 255f, 0.4f); + } + + public Color getSelectedColor() { + return selectedOpaque; + } + + public Timeline.TimelineMarker getSelectedTimelineMarker() { + return currentMarker; + } + + public void addMarker(Date timestamp, String mark, String notes) { + timeline.addMarker(timestamp, mark, notes); + updateMarkers(getGraphics()); + } + + public void deleteSelectedMarker() { + timeline.removeMarker(currentMarker); + updateMarkers(getGraphics()); + } + + public void updateSelectedMarker(String notes) { + currentMarker.setNotes(notes); + updateMarkers(getGraphics()); + } + + private void updateMarkers(Graphics g) { + + markerEntries = new ArrayList(); + + if (markFont == null) markFont = getFont().deriveFont(Font.BOLD); + if (notesFont == null) notesFont = getFont(); + + // get all relevant markers Timeline.TimelineMarker tm = timeline.getLastMarker(day.getTime()); Iterator itr = timeline.iterator(); @@ -102,35 +191,180 @@ public class TimelineDayDisplay extends JComponent { markers.add(tm); - for (int i = 0; i < markers.size(); i++) { - int boxY = 0; - int boxHeight = 1; - if (i != 0) { - double relTime = markers.get(i).getTimestamp().getTime() - day.getTimeInMillis(); - boxY = (int) Math.round((relTime / oneDayInMilli) - * canvasBounds.getHeight()) + canvasBounds.y; - } - if (i == markers.size() - 1) { - double relTime = nextDay.getTime().getTime() - - markers.get(i).getTimestamp().getTime(); - boxHeight = (int) Math.round(relTime / oneDayInMilli - * canvasBounds.getHeight()); + 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) { + markerEntry.relY = 0; } else { - double relTime = markers.get(i + 1).getTimestamp().getTime() - - markers.get(i).getTimestamp().getTime(); - boxHeight = (int) Math.round(relTime / oneDayInMilli - * canvasBounds.getHeight()); + // calculate time in ms since the beginning of the day + markerEntry.relY = markers.get(i).getTimestamp().getTime() + - day.getTimeInMillis(); + // calculate percentage of total time in day + markerEntry.relY /= oneDayInMilli; } - g.setColor((i % 2 == 0 ? evenTrans : oddTrans)); - g.fillRect(canvasBounds.x + (int) stringBounds.getWidth() + 5, boxY, - canvasBounds.x + canvasBounds.width, boxHeight); - g2d.setColor((i % 2 == 0 ? evenOpaque : oddOpaque)); + + // calculate lower bound + if (i == 0) + markerEntry.relHeight = + markers.get(i + 1).getTimestamp().getTime() + - day.getTimeInMillis(); + else if (i == markers.size() - 2) + markerEntry.relHeight = nextDay.getTimeInMillis() + - markers.get(i).getTimestamp().getTime(); + else + markerEntry.relHeight = + markers.get(i + 1).getTimestamp().getTime() + - markers.get(i).getTimestamp().getTime(); + markerEntry.relHeight /= oneDayInMilli; + + markerEntries.add(markerEntry); + } + } + + @Override + public void paintComponent(Graphics g) { + removeAll(); + + 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 (int i = 1; i < 24; i++) { + int lineY = (int) Math.round(hourHeight * (double) i); + g.drawLine(canvasBounds.x + (int) stringBounds.getWidth(), canvasBounds.y + lineY, + canvasBounds.x + canvasBounds.width, + canvasBounds.y + lineY); + + //draw hours labels + if ((hourHeight > (stringBounds.getHeight()) || ((i % 2) == 0))) { + g.drawString(String.format("%1$02d:00", i), + canvasBounds.x + 2, lineY + (int) (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(canvasBounds.x + (int) stringBounds.getWidth() + 5, boxY, - canvasBounds.x + canvasBounds.width, boxHeight); + 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) { + Point topLeft = getLocationOnScreen(); + for (MarkerDisplayEntry markerEntry : markerEntries) { + Rectangle absBounds = new Rectangle(markerEntry.bounds); + absBounds.translate(topLeft.x, topLeft.y); + if (absBounds.contains(e.getLocationOnScreen())) { + currentMarker = markerEntry.marker; + repaint(); + } + } + fireChangeEvent(); + } + + public void mousePressed(MouseEvent e) { + } + + public void mouseReleased(MouseEvent e) { + } + + public void mouseEntered(MouseEvent e) { + } + + public void mouseExited(MouseEvent e) { + } } diff --git a/src/jdbernard/timestamper/resources/PunchcardDisplayDialog.properties b/src/jdbernard/timestamper/resources/PunchcardDisplayDialog.properties new file mode 100755 index 0000000..8296e1b --- /dev/null +++ b/src/jdbernard/timestamper/resources/PunchcardDisplayDialog.properties @@ -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=/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 diff --git a/src/jdbernard/timestamper/resources/TimeStamperView.properties b/src/jdbernard/timestamper/resources/TimeStamperView.properties index f85f231..e4829c7 100755 --- a/src/jdbernard/timestamper/resources/TimeStamperView.properties +++ b/src/jdbernard/timestamper/resources/TimeStamperView.properties @@ -17,7 +17,7 @@ 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.shortDescription=Edit notes for this task -editNotes.Action.text=Notes +editNotes.Action.text=Show Notes jButton1.text= showOptionsMenu.Action.text=Options menu showOptionsMenu.Action.shortDescription=Show the application's options menu. @@ -49,3 +49,9 @@ notesButton2.text=jToggleButton1 optionsButton.rolloverIcon=icons/16-tool-a-hover.png #NOI18N exitButton.rolloverIcon=icons/16-em-cross-hover.png +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 diff --git a/src/jdbernard/timestamper/resources/icons/16-file-archive.png b/src/jdbernard/timestamper/resources/icons/16-file-archive.png new file mode 100755 index 0000000000000000000000000000000000000000..e8d07f58e448c38fe5b80eafff396218fc2812de GIT binary patch literal 293 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xj(fT|hE&{2`t$$4J+o>T9d&|Hi_FC3@TbS3N6h%zUn?tdjB6s z(+9Wv@AK&2|D$rMA>ZD?F5SiS!7oWSg*3JM+-648B@bQU7g(Bk)t9|Z*}o)^H-Ta2 zKii4d{vCPLq`bcL;EWu72}w!A9lLi6FU@>@ZY~cHJ4-xx`}D$&(%X$yGZYLNmayMs o<#k{TioMTpo_h*I0|PTdoSP^2O5WF3fL>zoboFyt=akR{0F2&p*9#BYcAu_4d1=j&%T4!Qu6Xz1?uSp0Zrs~BZw0mVf{8{^zexr|(w%{r7w4sfs^;f9>3{ z;pVe>K*pRkB|!FP0qOTZD`ZQ8{DS}E0Su9C&$ECE^F3W0Ln?0NoIlCepuppL(TKy3 zqeE!rzyIY@OC^$aoZg%f_wW}huf=MkHy&?U5@YWe>`3KhS-i>F%1I5Ju`C-@xD;q39rzclCVOZU*nx1$>v8Om>q%db29 R{5sHT22WQ%mvv4FO#tCdv$_BP literal 0 HcmV?d00001 diff --git a/src/jdbernard/timestamper/resources/icons/16-square-red-delete.png b/src/jdbernard/timestamper/resources/icons/16-square-red-delete.png new file mode 100755 index 0000000000000000000000000000000000000000..237ae2aa026943079100f1267d1cdf27bd01b4ca GIT binary patch literal 321 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!fo?*N|=*Ee%!zFWQW%bC;ve*XNlfA80e=l}lr{_Ew7mkl-V zmM#8q@80jXZ$IwX_IAm_*V86{*u3%ck;8w#e|w&t`n)7>=Z+1p`n&)9{kPuV3&`GQ zE2{*yJIF8iKMugaXu`D}s3_gj#WAGfR?hj?Tn!354i8sGrrk_k_Vu6ttaF0OHgEdn zx%lSAUucZJa-c`uRH`lY(rP_pU7ost$f=Sx&Ac literal 0 HcmV?d00001 diff --git a/src/jdbernard/timestamper/resources/icons/media-playback-reverse.png b/src/jdbernard/timestamper/resources/icons/media-playback-reverse.png new file mode 100755 index 0000000000000000000000000000000000000000..07dcbf10c455ac4e9f0fb292dbd14fa6cd88683e GIT binary patch literal 636 zcmV-?0)zdDP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOS) z6FUp9!XnlH00I0-L_t(I%biodYZGA@e!jc=F6L}KlHPYoNDHPYO^vakZVonQ+taOt z#G|7ksMO#8fe{f!IyktNx&{U^4d`9+I*8WRrqDjqySxw2 zkM{-k2IbEn?Q&5D5CIV13qdFvjh?VikH6hkN+$>*v_K#*cx)*3M3$8SB9crY$gS0O zR**`iltUyjG((Fa;EIFZj6)bX(~ zuI<-;hak%krU_Ik{}b4@9fE|39j(S-D(J;#^^pBw@YT006Y94V|mts*14Qvzb5$(H#o+=(0i{QHybfLkntH zU0Z?Ydtd;-81(KCxWZuw6Ps$hT`bmO(a3w#h+XjfpU&NTcj~jVGpz$%I!q%9&-c-6 ze&4WQZdhPjLoAg_0ZEb~jpoYa#}A*1>7!|0$e)#c-v{R$*Kb~HStFwf$8o-FTchJR zKMIAy=YxHRA7@XVI=-}Ad--tszW;h*j@m>}RZij`3mp&1va;&{DvRavxux2-%>0}A znM!%FHy8|%Fpb?kfa|)H0h#)QuLQNI1SZtsXO8U^GGfgrxxh}+}VkxnAb?)YabMHAocX%9NxLrB| zzyY8MfO-Y6yO;d<*y~_0mS+_>8utCg%c)OS>fRtAV|%-`d2TEPA*Jh9cyFkzj@8Rl|wrzVTrBXP&dB3J>#|R-SugBk% zQvirYqqMm>>a}er>^IE=b=zwDw%6CU-;edVC0UXvrQV8)@*NEg^|8w8s-wMk@3{m) z5DdQwv9+buH##=DA+RwJitcPWQ{c-l?dm%3^LRXjXE~V4#HQxP8%)z`E?>IBeEIo= zXE{_=g(%1n4ZqohUDvZSiO<|ww2@9*NaZ+FRT!oTYMSOu zxT31XveKPBcW%Fb*#BVO?P4e~1E5rZtVq1Kx94ql_f1=tlvVC#ZWx9EAr_1ASS)6D zcAgzBG1uK1dpRn-8Xv0^C6N~w8`4nxd8Vd15?NZwyc>M>v}ta3mIi}m;?U6Ga#=8R z{iid=<8cCTmQLG+FGk`QHO5-99GR_^wLuP0Yk5IQC6dQespN^NsgHcm?!BdCtrwh} zoTT79@5A)OrpNvLR}UXLvX2Av1f20K)ag$XX8*vzwYIkQgXDK5a26M30`3KnQ507S u0BqY40B8VL|GG__b7c)iIOqC5SM@u(HR(kN;XjH10000tKSAuPT^ z91PmH7$pWpLv&PdkVkw#OnB5_ppT>Ude`f5Eq@mvQDHNFr(Ztb;M~g+f8*d7hIb$#Dq+*VcBb zw^%G@0cr|@P_pff(qDp5ZOE$zm4}Mr@Amum+q#}xWEiGgmSs|16C6|&e|JTt&utp{ z6;)M>RaI4vrfEAOwlN&`dOYrn&z}v8lQUDzWwLzM!_1}7M_~3zeEbF?!DXNOJmH;6@CaXadC4f>SlB?9~^==XZW-Y5h6a>&s zibOI&-IB2;7=}eqt$|@0h{cAiL^8GH68J;g+_Lf*d;3P8{W`m9 zn)$np4NWluvd*chibU!soT7u#(Gh!LX+H1sRbDyXTK{t9^VEV-tlmdp;PeDuql&y}fd_3LJak)NNw**46p-^b^ z&mj@ZvI1LY9)KZ9VhI3jyWj)BQ;>C05H|LF21==yQc8B=0{%yS0XCc#NPdKXNB{r; M07*qoM6N<$f~CAw@c;k- literal 0 HcmV?d00001 diff --git a/src/jdbernard/timestamper/resources/icons/media-skip-backward.png b/src/jdbernard/timestamper/resources/icons/media-skip-backward.png new file mode 100755 index 0000000000000000000000000000000000000000..94381f54fddd07a54b483ff931818cec51d969e7 GIT binary patch literal 770 zcmV+d1O5DoP)eL!nq}o8h%B@qaZ#2x}_K3;az zX7&jHfv)S{wj)2Ca9F$rB07@x#?P=&KDkv;#ZEY(Eg+fGTC2VFJ zob$^a7ca4b!a^dm5|mPCst!#!0)JA!mK1bf>8=TfBAPerBArTsQihh}Eu_A_!S-go zC5+h&MFkc#!8w9C9{^yQCZ?vRq^|48xG8wP55^c=&xPl^$haAJo(skp7^NsK;!vW3 z!!UFJfMMu(_~8DxmxBYpEt4T8)3`Pe2Xg@!r4T|ul=nS5;?K442X#fBr#9xMyg+gnzzxk5f!nB%9@&Et;07*qoM6N<$f`N5b A5&!@I literal 0 HcmV?d00001 diff --git a/src/jdbernard/timestamper/resources/icons/media-skip-forward.png b/src/jdbernard/timestamper/resources/icons/media-skip-forward.png new file mode 100755 index 0000000000000000000000000000000000000000..758ec6f1b14f2dbcc92cdb13de57c59ce92175e6 GIT binary patch literal 771 zcmV+e1N{7nP)=MI^)2*h*-#hC`$v=FNQAc%05uTADme$0$B-ud#L7LFp;GJ4>J!^3$Gzw`0}|9~0* z%06cRF#qEJfB>+nX9qwUKoLM~^$`gmUoB_P-CZ=d+e9Q1>0Ve^98RTDX+=?1TrO83 z9B%JkT>Lze&161-z;GOALrRHLr%x{JG$#_10Yz{NhRH4lL(Pe3G;+@C^>SU;1I(c3 zTY^U?LT$k=kH=eYS%F%?w*x$T`Wyhj{Q?TN1XNX3U%hL;!Lqr^zV&tSppjO`=L_}ilXAdK+Lngw&w1>eyu;B%Tp;O`uh57 zve~S+x3}lUp~LlO6%YV`X`0}E4$Tq*g|ZC*$mepP1|<(;k37@UQ@c)cspL-o-2<6y zx~8-9@@@iQ320mhtgI$M2(X@61!D#vCG3I?LV&f*Dj21Zjzlt*l#DR|0Amb-b10m1 z7;XcKq9Py;LU&Qb<4^3F*=f1s4Ccnj%n}GA1U* zieJBf+4TA9x=ho3zg#J^kMr;Cw{x?_>_+}^u%&fic5Z5Edj(Q&mQ(6CH^0tm@$Ia?e6Zr$$L-UA^(Y}>A`C)os$GYqy>EEaqK zC;&%-q#30p0I+S_+8N?5QcACslI(L-N=flQ_zm52>_i|8P1XPa002ovPDHLkV1goq BQIP-u literal 0 HcmV?d00001