Added several improvements

This commit is contained in:
Robert Vokac 2024-03-16 18:50:13 +00:00
parent 62c875f039
commit fcffaed480
No known key found for this signature in database
GPG Key ID: 693D30BEE3329055
40 changed files with 333 additions and 239 deletions

View File

@ -8,6 +8,30 @@ _Time Calc is written in Java programming language and uses the Swing framework.
![Screenshot of application "Time Calc"](images/screenshot.jpg)
Time Calc is inspired by this document: [report.ods](https://code.nanoboot.org/nanoboot/time-calc/raw/branch/rvc/report.ods)
![report.ods.working_day.jpg](images/report.ods.working_day.jpg)
![report.ods.activities.jpg](images/report.ods.activities.jpg)
### Screenshots
!["Working Days" window - table](images/working_days_window_table.jpg)
!["Working Days" window - table](images/working_days_window_chart.jpg)
!["Activites" window](images/activities_window.jpg)
!["Config" window - clock](images/config_window_clock.jpg)
!["Config" window - battery](images/config_window_battery.jpg)
!["Config" window - smileys](images/config_window_smileys.jpg)
!["Config" window - test](images/config_window_test.jpg)
!["Config" window - misc](images/config_window_misc.jpg)
## Usage
### Start of application
@ -41,9 +65,6 @@ If file starttime.txt does not exist, then the default start time is 7:00.
This file contains the default overtime - used during the previous run of the app.
If file overtime.txt does not exist, then the default overtime is 0:00.
### .tc/test.txt
If file test.txt exists, then user is not asked for start time and overtime. Instead, the values in files starttime.txt and overtime.txt are used.
### ./tc/timecalc.conf
Configuration is stored here.

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 KiB

View File

@ -1,9 +1,9 @@
package org.nanoboot.utils.timecalc.app;
import java.io.File;
import java.io.FileInputStream;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.swing.common.MainWindow;
import org.nanoboot.utils.timecalc.utils.common.Constants;
import org.nanoboot.utils.timecalc.swing.windows.MainWindow;
import org.nanoboot.utils.timecalc.utils.common.DateFormats;
import org.nanoboot.utils.timecalc.utils.common.FileConstants;
import org.nanoboot.utils.timecalc.utils.common.Utils;
@ -56,53 +56,11 @@ public class TimeCalcApp {
} catch(Exception e) {
e.printStackTrace();
}
while (true) {
boolean test = FileConstants.TEST_TXT.exists();
String oldStartTime = Utils.readTextFromFile(
FileConstants.STARTTIME_TXT);
String oldOvertime = Utils.readTextFromFile(
FileConstants.OVERTIME_TXT);
String newStartTime
= test ? (oldStartTime != null ? oldStartTime
: Constants.DEFAULT_START_TIME)
: (String) JOptionPane.showInputDialog(
null,
"Start Time:",
"Start Time",
JOptionPane.PLAIN_MESSAGE,
null,
null,
oldStartTime == null
? Constants.DEFAULT_START_TIME
: oldStartTime
);
if (newStartTime == null) {
break;
}
String newOvertime
= test ? (oldOvertime != null ? oldOvertime
: Constants.DEFAULT_OVERTIME)
: (String) JOptionPane.showInputDialog(
null,
"Overtime:",
"Overtime",
JOptionPane.PLAIN_MESSAGE,
null,
null,
oldOvertime == null
? Constants.DEFAULT_OVERTIME
: oldOvertime
);
if (newOvertime == null) {
break;
}
Utils.writeTextToFile(FileConstants.STARTTIME_TXT, newStartTime);
Utils.writeTextToFile(FileConstants.OVERTIME_TXT, newOvertime);
MainWindow timeCalcMainWindow = null;
try {
timeCalcMainWindow
= new MainWindow(newStartTime, newOvertime, this);
timeCalcMainWindow = new MainWindow(this);
} catch (Exception e) {
JOptionPane.showMessageDialog(null, "Error: " + e.getMessage(),
e.getMessage(), JOptionPane.ERROR_MESSAGE);

View File

@ -1,9 +1,8 @@
package org.nanoboot.utils.timecalc.app;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.swing.common.MainWindow;
import org.nanoboot.utils.timecalc.swing.windows.MainWindow;
import org.nanoboot.utils.timecalc.swing.progress.Time;
import org.nanoboot.utils.timecalc.swing.progress.WalkingHumanProgress;
import org.nanoboot.utils.timecalc.utils.common.FileConstants;
import org.nanoboot.utils.timecalc.utils.common.Jokes;
import org.nanoboot.utils.timecalc.utils.common.TTime;

View File

@ -1,5 +1,6 @@
package org.nanoboot.utils.timecalc.swing.common;
import org.nanoboot.utils.timecalc.swing.controls.TButton;
import org.nanoboot.utils.timecalc.utils.common.Utils;
import javax.swing.JOptionPane;

View File

@ -1,5 +1,6 @@
package org.nanoboot.utils.timecalc.swing.common;
import org.nanoboot.utils.timecalc.swing.controls.TTextField;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import java.awt.Color;

View File

@ -1,5 +1,8 @@
package org.nanoboot.utils.timecalc.swing.common;
import org.nanoboot.utils.timecalc.swing.controls.MouseClickedListener;
import org.nanoboot.utils.timecalc.swing.controls.SmallTButton;
import org.nanoboot.utils.timecalc.swing.controls.TTextField;
import lombok.AccessLevel;
import lombok.Getter;
import org.nanoboot.utils.timecalc.entity.Activity;

View File

@ -33,9 +33,7 @@ import java.util.stream.Collectors;
*/
public class DayPanel extends JPanel {
private static final String FOR_ACTIVITY_ID = "for-activity-id";
private static final Dimension MAXIMUM_SIZE = new Dimension(1300, 40);
private static final Dimension MAXIMUM_SIZE_2 = new Dimension(1200, 20);
private final String year;
private final String month;
private final String day;
@ -188,11 +186,7 @@ public class DayPanel extends JPanel {
Utils.showNotification("Current status: done=" + NumberFormats.FORMATTER_TWO_DECIMAL_PLACES.format(done) + "h, todo="+ NumberFormats.FORMATTER_TWO_DECIMAL_PLACES.format(todo));
});
// for (int i = 0; i < 10; i++) {
// add(new ActivityPanel(activityRepository,
// new Activity("id", 2000, 7, 7, "name", "comment", "ticket", 2, 30,
// "a b c", null)));
// }
sortActivityPanels();
}
public List<Activity> getActivities() {
return Arrays

View File

@ -1,5 +1,6 @@
package org.nanoboot.utils.timecalc.swing.common;
import org.nanoboot.utils.timecalc.swing.controls.TTabbedPane;
import org.nanoboot.utils.timecalc.persistence.api.ActivityRepositoryApi;
import java.util.Calendar;

View File

@ -1,5 +1,6 @@
package org.nanoboot.utils.timecalc.swing.common;
import org.nanoboot.utils.timecalc.swing.controls.TTabbedPane;
import org.nanoboot.utils.timecalc.persistence.api.ActivityRepositoryApi;
import java.util.HashMap;

View File

@ -1,4 +1,4 @@
package org.nanoboot.utils.timecalc.swing.common;
package org.nanoboot.utils.timecalc.swing.controls;
import lombok.Getter;
@ -6,6 +6,7 @@ import java.awt.Component;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;
import org.nanoboot.utils.timecalc.swing.windows.MainWindow;
/**
* @author Robert Vokac

View File

@ -1,10 +1,10 @@
package org.nanoboot.utils.timecalc.swing.common;
package org.nanoboot.utils.timecalc.swing.controls;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
/**
* @author Robert
* @author pc00289
* @since 14.03.2024
*/
public interface MouseClickedListener extends MouseListener {

View File

@ -1,9 +1,9 @@
package org.nanoboot.utils.timecalc.swing.common;
package org.nanoboot.utils.timecalc.swing.controls;
import java.awt.Insets;
/**
* @author Robert
* @author pc00289
* @since 11.03.2024
*/
public class SmallTButton extends TButton {

View File

@ -1,4 +1,4 @@
package org.nanoboot.utils.timecalc.swing.common;
package org.nanoboot.utils.timecalc.swing.controls;
import org.nanoboot.utils.timecalc.app.GetProperty;
import org.nanoboot.utils.timecalc.entity.Visibility;
@ -10,6 +10,8 @@ import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.Timer;
import java.awt.Color;
import org.nanoboot.utils.timecalc.swing.windows.MainWindow;
import org.nanoboot.utils.timecalc.swing.common.SwingUtils;
/**
* @author Robert Vokac

View File

@ -1,4 +1,4 @@
package org.nanoboot.utils.timecalc.swing.common;
package org.nanoboot.utils.timecalc.swing.controls;
import org.nanoboot.utils.timecalc.app.GetProperty;
import org.nanoboot.utils.timecalc.entity.Visibility;
@ -10,6 +10,8 @@ import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.Timer;
import java.awt.Color;
import org.nanoboot.utils.timecalc.swing.windows.MainWindow;
import org.nanoboot.utils.timecalc.swing.common.SwingUtils;
/**
* @author Robert Vokac

View File

@ -1,4 +1,4 @@
package org.nanoboot.utils.timecalc.swing.common;
package org.nanoboot.utils.timecalc.swing.controls;
import org.nanoboot.utils.timecalc.app.GetProperty;
import org.nanoboot.utils.timecalc.entity.Visibility;
@ -10,6 +10,8 @@ import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.Timer;
import java.awt.Color;
import org.nanoboot.utils.timecalc.swing.windows.MainWindow;
import org.nanoboot.utils.timecalc.swing.common.SwingUtils;
/**
* @author Robert Vokac

View File

@ -2,7 +2,7 @@
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package org.nanoboot.utils.timecalc.swing.common;
package org.nanoboot.utils.timecalc.swing.controls;
import javax.swing.JTabbedPane;

View File

@ -1,4 +1,4 @@
package org.nanoboot.utils.timecalc.swing.common;
package org.nanoboot.utils.timecalc.swing.controls;
import org.nanoboot.utils.timecalc.app.GetProperty;
import org.nanoboot.utils.timecalc.entity.Visibility;
@ -13,6 +13,8 @@ import javax.swing.Timer;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.Color;
import org.nanoboot.utils.timecalc.swing.windows.MainWindow;
import org.nanoboot.utils.timecalc.swing.common.SwingUtils;
/**
* @author Robert Vokac

View File

@ -1,4 +1,4 @@
package org.nanoboot.utils.timecalc.swing.common;
package org.nanoboot.utils.timecalc.swing.controls;
import org.nanoboot.utils.timecalc.utils.property.IntegerProperty;

View File

@ -2,7 +2,7 @@ package org.nanoboot.utils.timecalc.swing.progress;
import org.nanoboot.utils.timecalc.app.GetProperty;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.swing.common.MainWindow;
import org.nanoboot.utils.timecalc.swing.windows.MainWindow;
import org.nanoboot.utils.timecalc.swing.common.SwingUtils;
import org.nanoboot.utils.timecalc.swing.common.Toaster;
import org.nanoboot.utils.timecalc.swing.common.Widget;

View File

@ -1,17 +1,21 @@
package org.nanoboot.utils.timecalc.swing.common;
package org.nanoboot.utils.timecalc.swing.windows;
import org.nanoboot.utils.timecalc.swing.controls.TWindow;
import org.nanoboot.utils.timecalc.swing.controls.TTabbedPane;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.nanoboot.utils.timecalc.app.TimeCalcException;
import org.nanoboot.utils.timecalc.persistence.api.ActivityRepositoryApi;
import org.nanoboot.utils.timecalc.swing.common.MonthPanel;
import org.nanoboot.utils.timecalc.swing.common.SwingUtils;
import org.nanoboot.utils.timecalc.swing.common.YearPanel;
import org.nanoboot.utils.timecalc.swing.progress.Time;
/**

View File

@ -1,5 +1,7 @@
package org.nanoboot.utils.timecalc.swing.common;
package org.nanoboot.utils.timecalc.swing.windows;
import org.nanoboot.utils.timecalc.swing.controls.TButton;
import org.nanoboot.utils.timecalc.swing.controls.TWindow;
import org.nanoboot.utils.timecalc.app.TimeCalcConfiguration;
import org.nanoboot.utils.timecalc.app.TimeCalcProperty;
import org.nanoboot.utils.timecalc.entity.Visibility;
@ -15,9 +17,7 @@ import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.Color;
@ -33,6 +33,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.nanoboot.utils.timecalc.swing.common.SwingUtils;
import org.nanoboot.utils.timecalc.swing.controls.TTabbedPane;
/**
* @author Robert Vokac
@ -51,8 +54,12 @@ public class ConfigWindow extends TWindow {
Arrays.stream(Visibility.values()).map(v -> v.name()).collect(
Collectors.toList()).toArray());
private final TimeCalcConfiguration timeCalcConfiguration;
private final JPanel panelInsideScrollPane;
private int currentY = SwingUtils.MARGIN;
private final JPanel panelInsideScrollPaneClock;
private final JPanel panelInsideScrollPaneBattery;
private final JPanel panelInsideScrollPaneSmileys;
private final JPanel panelInsideScrollPaneTest;
private final JPanel panelInsideScrollPaneMisc;
private final int[] currentY = new int[]{SwingUtils.MARGIN,SwingUtils.MARGIN,SwingUtils.MARGIN,SwingUtils.MARGIN,SwingUtils.MARGIN};
private final List<JComponent> propertiesList = new ArrayList<>();
private final Map<TimeCalcProperty, JComponent> propertiesMap = new HashMap<>();
private final TButton enableAsMuchAsPossible
@ -173,37 +180,75 @@ public class ConfigWindow extends TWindow {
= new JTextField(TimeCalcProperty.TEST_CLOCK_CUSTOM_SECOND.getKey());
private final JTextField testClockCustomMillisecondProperty
= new JTextField(TimeCalcProperty.TEST_CLOCK_CUSTOM_MILLISECOND.getKey());
private final TTabbedPane tp;
public ConfigWindow(TimeCalcConfiguration timeCalcConfiguration) {
this.timeCalcConfiguration = timeCalcConfiguration;
setTitle("Configuration");
this.setSize(800, 800);
this.setSize(780, 800);
JPanel mainPanel = new JPanel();
mainPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE,
mainPanel.setMaximumSize(new Dimension(750,
getHeight() - 6 * SwingUtils.MARGIN));
this.panelInsideScrollPane = new JPanel();
final BoxLayout boxLayout
= new BoxLayout(panelInsideScrollPane, BoxLayout.Y_AXIS);
panelInsideScrollPane.setAlignmentX(LEFT_ALIGNMENT);
this.tp = new TTabbedPane();
//tp.setBackground(Color.red);
this.panelInsideScrollPaneClock = new JPanel();
this.panelInsideScrollPaneBattery = new JPanel();
this.panelInsideScrollPaneSmileys = new JPanel();
this.panelInsideScrollPaneTest = new JPanel();
this.panelInsideScrollPaneMisc = new JPanel();
List<JPanel> panelsInsideScrollPane = Stream.of(
panelInsideScrollPaneClock,
panelInsideScrollPaneBattery,
panelInsideScrollPaneSmileys,
panelInsideScrollPaneTest,
panelInsideScrollPaneMisc).toList();
panelsInsideScrollPane.forEach(p-> {
final BoxLayout boxLayout = new BoxLayout(p, BoxLayout.Y_AXIS);
p.setLayout(boxLayout);
p.setAlignmentX(LEFT_ALIGNMENT);
//p.setMinimumSize(new Dimension(300, 400));
p.setMaximumSize(new Dimension(300, 400));
//p.setBackground(Color.blue);
});
//mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
mainPanel.setAlignmentX(LEFT_ALIGNMENT);
panelInsideScrollPane.setLayout(boxLayout);
panelInsideScrollPane
.setMinimumSize(new Dimension(Integer.MAX_VALUE, 400));
JScrollPane scrollPane = new JScrollPane(panelInsideScrollPane);
scrollPane.setVerticalScrollBarPolicy(
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setPreferredSize(
new Dimension(getWidth() - 50, getHeight() - 100));
scrollPane.setWheelScrollingEnabled(true);
scrollPane.setBorder(null);
// mainPanel.setBackground(Color.red);
// scrollPane.setBackground(Color.green);
// panelInsideScrollPane.setBackground(Color.blue);
JScrollPane scrollPaneClock = new JScrollPane(panelInsideScrollPaneClock);
JScrollPane scrollPaneBattery = new JScrollPane(panelInsideScrollPaneBattery);
JScrollPane scrollPaneSmileys = new JScrollPane(panelInsideScrollPaneSmileys);
JScrollPane scrollPaneTest = new JScrollPane(panelInsideScrollPaneTest);
JScrollPane scrollPaneMisc = new JScrollPane(panelInsideScrollPaneMisc);
List<JScrollPane> scrollPanes = Stream.of(
scrollPaneClock,
scrollPaneBattery,
scrollPaneSmileys,
scrollPaneTest,
scrollPaneMisc
).toList();
tp.add("Clock", scrollPaneClock);
tp.add("Battery", scrollPaneBattery);
tp.add("Smileys", scrollPaneSmileys);
tp.add("Test", scrollPaneTest);
tp.add("Misc", scrollPaneMisc);
scrollPanes.forEach(s->
{
s.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
s.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
s.setPreferredSize(
new Dimension(720, getHeight() - 100));
s.setWheelScrollingEnabled(true);
s.setBorder(null);
// s.setBackground(Color.green);
});
add(mainPanel);
//mainPanel.setBackground(Color.ORANGE);
//mainPanel.setLayout(null);
mainPanel.add(enableAsMuchAsPossible);
enableAsMuchAsPossible
@ -215,12 +260,10 @@ public class ConfigWindow extends TWindow {
enableAsMuchAsPossible.getX() + enableAsMuchAsPossible
.getWidth() + SwingUtils.MARGIN, SwingUtils.MARGIN, 250,
HEIGHT1);
scrollPane.setBounds(enableAsMuchAsPossible.getX(),
enableAsMuchAsPossible.getY() + enableAsMuchAsPossible
.getHeight() + SwingUtils.MARGIN, Integer.MAX_VALUE,
Integer.MAX_VALUE);
mainPanel.add(scrollPane);
scrollPanes.stream().forEach(s->s.setBounds(10, 10, Integer.MAX_VALUE,Integer.MAX_VALUE));
mainPanel.add(tp);
for (boolean enable : new boolean[]{true, false}) {
TButton button
@ -282,8 +325,7 @@ public class ConfigWindow extends TWindow {
});
}
propertiesList.addAll(Arrays.asList(visibilityDefaultProperty,
visibilitySupportedColoredProperty,
propertiesList.addAll(Arrays.asList(
clockVisibleProperty,
clockHandsHourVisibleProperty,
clockHandsMinuteVisibleProperty,
@ -333,33 +375,48 @@ public class ConfigWindow extends TWindow {
circleVisibleProperty,
walkingHumanVisibleProperty,
mainWindowCustomTitleProperty,
profileNameProperty));
profileNameProperty,
visibilityDefaultProperty,
visibilitySupportedColoredProperty));
//
//panelInsideScrollPane
propertiesList.stream().forEach(p -> {
p.setAlignmentX(LEFT_ALIGNMENT);
if (p == visibilityDefaultProperty) {
p.putClientProperty(CLIENT_PROPERTY_KEY,
TimeCalcProperty.VISIBILITY_DEFAULT.getKey());
addToNextRow(new JLabel(
TimeCalcProperty.VISIBILITY_DEFAULT.getDescription()));
final JLabel jLabel = new JLabel(
TimeCalcProperty.VISIBILITY_DEFAULT.getDescription());
jLabel.putClientProperty(CLIENT_PROPERTY_KEY,
TimeCalcProperty.VISIBILITY_DEFAULT.getKey());
addToNextRow(jLabel);
}
if (p == clockCircleBorderColorProperty) {
p.putClientProperty(CLIENT_PROPERTY_KEY,
TimeCalcProperty.CLOCK_CIRCLE_BORDER_COLOR.getKey());
addToNextRow(new JLabel(
JComponent label = new JLabel(
TimeCalcProperty.CLOCK_CIRCLE_BORDER_COLOR
.getDescription().replace("Clock : ", "")));
.getDescription().replace("Clock : ", ""));
label.putClientProperty(CLIENT_PROPERTY_KEY,
TimeCalcProperty.CLOCK_CIRCLE_BORDER_COLOR.getKey());
addToNextRow(label);
}
if (p == mainWindowCustomTitleProperty) {
addToNextRow(new JLabel(
final JLabel jLabel = new JLabel(
TimeCalcProperty.MAIN_WINDOW_CUSTOM_TITLE
.getDescription()));
.getDescription());
jLabel.putClientProperty(CLIENT_PROPERTY_KEY,
TimeCalcProperty.MAIN_WINDOW_CUSTOM_TITLE.getKey());
addToNextRow(jLabel);
p.putClientProperty(CLIENT_PROPERTY_KEY,
TimeCalcProperty.MAIN_WINDOW_CUSTOM_TITLE.getKey());
}
if (p == profileNameProperty) {
addToNextRow(new JLabel(
TimeCalcProperty.PROFILE_NAME.getDescription()));
final JLabel jLabel = new JLabel(
TimeCalcProperty.PROFILE_NAME.getDescription());
jLabel.putClientProperty(CLIENT_PROPERTY_KEY,
TimeCalcProperty.PROFILE_NAME.getKey());
addToNextRow(jLabel);
p.putClientProperty(CLIENT_PROPERTY_KEY,
TimeCalcProperty.PROFILE_NAME.getKey());
}
@ -417,20 +474,20 @@ public class ConfigWindow extends TWindow {
checkBox.setText(array.length > 1 ? (checkBox.getText()
.substring(groupName.length() + 3)) : "Visible");
if (array.length == 1) {
panelInsideScrollPane
.add(new JSeparator(SwingConstants.VERTICAL));
JLabel label = new JLabel(groupName);
label.setFont(BIG_FONT);
panelInsideScrollPane.add(label);
}
}
if (timeCalcProperty == TimeCalcProperty.VISIBILITY_DEFAULT
|| timeCalcProperty == TimeCalcProperty.JOKES_VISIBLE) {
JLabel label = new JLabel("Misc");
label.setFont(BIG_FONT);
panelInsideScrollPane.add(label);
// if (array.length == 1) {
// panelInsideScrollPane
// .add(new JSeparator(SwingConstants.VERTICAL));
// JLabel label = new JLabel(groupName);
// label.setFont(BIG_FONT);
// panelInsideScrollPane.add(label);
// }
}
// if (timeCalcProperty == TimeCalcProperty.VISIBILITY_DEFAULT
// || timeCalcProperty == TimeCalcProperty.JOKES_VISIBLE) {
// JLabel label = new JLabel("Misc");
// label.setFont(BIG_FONT);
// panelInsideScrollPane.add(label);
// }
}
if (p instanceof JColorChooser) {
JColorChooser colorChooser = ((JColorChooser) p);
@ -497,7 +554,9 @@ public class ConfigWindow extends TWindow {
String key = textField.getText();
textField.setText("");
textField.putClientProperty(CLIENT_PROPERTY_KEY, key);
addToNextRow(new JLabel(TimeCalcProperty.forKey(key).getDescription()));
JComponent label = new JLabel(TimeCalcProperty.forKey(key).getDescription());
label.putClientProperty(CLIENT_PROPERTY_KEY, key);
addToNextRow(label);
}
textField.setMaximumSize(new Dimension(150, 25));
@ -600,15 +659,34 @@ public class ConfigWindow extends TWindow {
}
private void addToNextRow(JComponent jComponent) {
panelInsideScrollPane.add(jComponent);
jComponent.setBounds(SwingUtils.MARGIN, currentY, 200,
int index = 4;
String key = (String) jComponent.getClientProperty(CLIENT_PROPERTY_KEY);
if(key == null) {
//nothing to do
return;
}
if(key.startsWith("clock")) index = 0;
if(key.startsWith("battery")) index = 1;
if(key.startsWith("smileys")) index = 2;
if(key.startsWith("test")) index = 3;
JPanel panel = null;
switch(index) {
case 0: panel=panelInsideScrollPaneClock;break;
case 1: panel=panelInsideScrollPaneBattery;break;
case 2: panel=panelInsideScrollPaneSmileys;break;
case 3: panel=panelInsideScrollPaneTest;break;
default:panel=panelInsideScrollPaneMisc;
}
panel.add(jComponent);
jComponent.setBounds(SwingUtils.MARGIN, currentY[index], 200,
HEIGHT1);
panelInsideScrollPane.add(Box.createRigidArea(new Dimension(5, 10)));
nextRow();
panel.add(Box.createRigidArea(new Dimension(5, 10)));
nextRow(index);
}
private void nextRow() {
currentY = (int) (currentY + 3.0d * SwingUtils.MARGIN);
private void nextRow(int index) {
currentY[index] = (int) (currentY[index] + 3.0d * SwingUtils.MARGIN);
}
public void doEnableEverything() {

View File

@ -1,11 +1,13 @@
package org.nanoboot.utils.timecalc.swing.common;
package org.nanoboot.utils.timecalc.swing.windows;
import org.nanoboot.utils.timecalc.swing.controls.TWindow;
import org.nanoboot.utils.timecalc.utils.common.Utils;
import javax.swing.JEditorPane;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import java.io.IOException;
import org.nanoboot.utils.timecalc.swing.common.SwingUtils;
/**
* @author Robert Vokac

View File

@ -1,5 +1,12 @@
package org.nanoboot.utils.timecalc.swing.common;
package org.nanoboot.utils.timecalc.swing.windows;
import org.nanoboot.utils.timecalc.swing.controls.SmallTButton;
import org.nanoboot.utils.timecalc.swing.controls.TTextField;
import org.nanoboot.utils.timecalc.swing.controls.TLabel;
import org.nanoboot.utils.timecalc.swing.controls.TCheckBox;
import org.nanoboot.utils.timecalc.swing.controls.TButton;
import org.nanoboot.utils.timecalc.swing.controls.TWindow;
import org.nanoboot.utils.timecalc.swing.controls.ComponentRegistry;
import org.nanoboot.utils.timecalc.app.CommandActionListener;
import org.nanoboot.utils.timecalc.app.GetProperty;
import org.nanoboot.utils.timecalc.app.TimeCalcApp;
@ -44,6 +51,11 @@ import org.nanoboot.utils.timecalc.entity.WorkingDay;
import org.nanoboot.utils.timecalc.persistence.api.ActivityRepositoryApi;
import org.nanoboot.utils.timecalc.persistence.impl.sqlite.ActivityRepositorySQLiteImpl;
import org.nanoboot.utils.timecalc.persistence.impl.sqlite.WorkingDayRepositorySQLiteImpl;
import org.nanoboot.utils.timecalc.swing.common.AboutButton;
import org.nanoboot.utils.timecalc.swing.common.SwingUtils;
import org.nanoboot.utils.timecalc.swing.common.Toaster;
import org.nanoboot.utils.timecalc.swing.common.WeekStatistics;
import org.nanoboot.utils.timecalc.swing.common.Widget;
import org.nanoboot.utils.timecalc.utils.property.IntegerProperty;
/**
@ -91,8 +103,8 @@ public class MainWindow extends TWindow {
{
this.arrivalTextField = new TTextField("", 40);
this.overtimeTextField = new TTextField("", 40);
this.arrivalTextField = new TTextField(Constants.DEFAULT_ARRIVAL_TIME, 40);
this.overtimeTextField = new TTextField(Constants.DEFAULT_OVERTIME, 40);
this.workingTimeTextField = new TTextField("8:00", 40);
this.pauseTimeTextField = new TTextField("0:30", 40);
this.noteTextField = new TTextField("", 100);
@ -101,8 +113,7 @@ public class MainWindow extends TWindow {
this.remainingTextField = new TTextField("", 100);
}
public MainWindow(String startTimeIn, String overTimeIn,
TimeCalcApp timeCalcApp) {
public MainWindow(TimeCalcApp timeCalcApp) {
// ToolTipManager ttm = ToolTipManager.sharedInstance();
// ttm.setInitialDelay(0);
// ttm.setDismissDelay(10000);
@ -120,11 +131,22 @@ public class MainWindow extends TWindow {
timeCalcConfiguration.mainWindowCustomTitleProperty.addListener(e -> {
setTitle(getWindowTitle());
});
overTimeIn = (overTimeIn == null || overTimeIn.isEmpty())
? Constants.DEFAULT_OVERTIME : overTimeIn;
arrivalTextField.valueProperty.setValue(startTimeIn);
overtimeTextField.valueProperty.setValue(overTimeIn);
Time time = new Time();
time.yearCustomProperty
.bindTo(timeCalcConfiguration.testYearCustomProperty);
time.monthCustomProperty
.bindTo(timeCalcConfiguration.testMonthCustomProperty);
time.dayCustomProperty
.bindTo(timeCalcConfiguration.testDayCustomProperty);
time.hourCustomProperty
.bindTo(timeCalcConfiguration.testHourCustomProperty);
time.minuteCustomProperty
.bindTo(timeCalcConfiguration.testMinuteCustomProperty);
time.secondCustomProperty
.bindTo(timeCalcConfiguration.testSecondCustomProperty);
time.millisecondCustomProperty
.bindTo(timeCalcConfiguration.testMillisecondCustomProperty);
time.allowCustomValuesProperty.setValue(true);
arrivalTextField.addVetoableChangeListener(e -> {
String newValue = (String) e.getNewValue();
@ -168,7 +190,6 @@ public class MainWindow extends TWindow {
}
Toaster.notificationsVisibleProperty.bindTo(timeCalcConfiguration.notificationsVisibleProperty);
Time time = new Time();
TimeCalcKeyAdapter timeCalcKeyAdapter
= new TimeCalcKeyAdapter(timeCalcConfiguration, timeCalcApp,
this, time);
@ -311,7 +332,7 @@ public class MainWindow extends TWindow {
pauseDecreaseButton.setBounds(pauseTimeTextField.getX() + pauseTimeTextField.getWidth(), pauseTimeTextField.getY() + 15, 15, 15);
//
TLabel noteTextFieldLabel = new TLabel("Note:", 30);
TLabel noteTextFieldLabel = new TLabel("Note:", 40);
noteTextFieldLabel.setBoundsFromLeft(pauseTimeTextField, 10);
noteTextField.setBoundsFromLeft(noteTextFieldLabel);
@ -466,21 +487,6 @@ public class MainWindow extends TWindow {
helpWindow.setVisible(true);
});
time.yearCustomProperty
.bindTo(timeCalcConfiguration.testYearCustomProperty);
time.monthCustomProperty
.bindTo(timeCalcConfiguration.testMonthCustomProperty);
time.dayCustomProperty
.bindTo(timeCalcConfiguration.testDayCustomProperty);
time.hourCustomProperty
.bindTo(timeCalcConfiguration.testHourCustomProperty);
time.minuteCustomProperty
.bindTo(timeCalcConfiguration.testMinuteCustomProperty);
time.secondCustomProperty
.bindTo(timeCalcConfiguration.testSecondCustomProperty);
time.millisecondCustomProperty
.bindTo(timeCalcConfiguration.testMillisecondCustomProperty);
time.allowCustomValuesProperty.setValue(true);
clock.dayProperty.bindTo(time.dayProperty);
clock.monthProperty.bindTo(time.monthProperty);
clock.yearProperty.bindTo(time.yearProperty);
@ -612,27 +618,6 @@ public class MainWindow extends TWindow {
+ 3 * SwingUtils.MARGIN,
focusButton.getY() + focusButton.getHeight() + SwingUtils.MARGIN
+ focusButton.getHeight() + 2 * SwingUtils.MARGIN);
// progressCircle.visibleProperty.addListener(e -> {
// System.out.println("visibility of circle was changed");
// if(progressSquare.visibleProperty.isEnabled() || progressCircle.visibleProperty.isEnabled()) {
// System.out.println("square or circle is visible");
// arrivalTextFieldLabel.setBoundsFromTop(progressSquare);
// } else {
// System.out.println("square and circle are not visible");
// arrivalTextFieldLabel.setBoundsFromTop(clock);
// }
// });
// progressSquare.visibleProperty.addListener(e -> {
// System.out.println("visibility of square was changed");
// if(progressSquare.visibleProperty.isEnabled() || progressCircle.visibleProperty.isEnabled()) {
// System.out.println("square or circle is visible");
// arrivalTextFieldLabel.setBoundsFromTop(progressSquare);
// } else {
// System.out.println("square and circle are not visible");
// arrivalTextFieldLabel.setBoundsFromTop(clock);
// }
// });
saveButton.addActionListener(e -> {
@ -645,8 +630,7 @@ public class MainWindow extends TWindow {
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH) + 1;
int day = cal.get(Calendar.DAY_OF_MONTH);
Utils.writeTextToFile(FileConstants.STARTTIME_TXT, arrivalTextField.asTTime().toString().substring(0, 5));
Utils.writeTextToFile(FileConstants.OVERTIME_TXT, overtime_.toString().substring(0, overtime_.isNegative() ? 6 : 5));
timeCalcConfiguration.saveToTimeCalcProperties();
WorkingDay workingDay = workingDayRepository.read(time.asCalendar());
if (workingDay == null) {
@ -675,6 +659,10 @@ public class MainWindow extends TWindow {
WorkingDay wd = workingDayRepository.read(time.asCalendar());
if (wd != null) {
arrivalTextField.valueProperty.setValue(new TTime(wd.getArrivalHour(), wd.getArrivalMinute()).toString().substring(0, 5));
TTime overtime = new TTime(wd.getOvertimeHour(), wd.getOvertimeMinute());
overtimeTextField.valueProperty.setValue(overtime.toString().substring(0, overtime.isNegative() ? 6 : 5));
//
workingTimeTextField.valueProperty.setValue(TTime.ofMilliseconds(wd.getWorkingTimeInMinutes() * 60 * 1000).toString().substring(0, 5));
pauseTimeTextField.valueProperty.setValue(TTime.ofMilliseconds(wd.getPauseTimeInMinutes() * 60 * 1000).toString().substring(0, 5));
noteTextField.valueProperty.setValue(wd.getNote());
@ -690,26 +678,15 @@ public class MainWindow extends TWindow {
wd.setYear(year);
wd.setMonth(month);
wd.setDay(day);
wd.setArrivalHour(7);
wd.setArrivalMinute(0);
wd.setOvertimeHour(0);
wd.setOvertimeMinute(0);
wd.setWorkingTimeInMinutes(480);
wd.setPauseTimeInMinutes(30);
wd.setNote("");
wd.setTimeOff(false);
}
TTime arrival_ = new TTime(arrivalTextField.getText());
TTime overtime_ = new TTime(overtimeTextField.getText());
// TTime work_ = new TTime(workingTimeTextField.getText());
// TTime pause_ = new TTime(pauseTimeTextField.getText());
// System.out.println("arrival_=" + arrival_);
// System.out.println("overtime_=" + overtime_);
// System.out.println("work_=" + work_);
// System.out.println("pause_=" + pause_);
wd.setArrivalHour(arrival_.getHour());
wd.setArrivalMinute(arrival_.getMinute());
wd.setOvertimeHour(overtime_.getHour() * (overtime_.isNegative() ? (-1) : 1));
wd.setOvertimeMinute(overtime_.getMinute() * (overtime_.isNegative() ? (-1) : 1));
workingDayRepository.update(wd);
@ -719,12 +696,33 @@ public class MainWindow extends TWindow {
while (true) {
File dbFileBackup = new File(dbFile.getAbsolutePath() + ".backup." + DateFormats.DATE_TIME_FORMATTER_SHORT.format(new Date()).substring(0, 10) + ".sqlite3");
if(dbFile.exists() && !dbFileBackup.exists()) {
try {
Files.copy(dbFile.toPath(), dbFileBackup.toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
e.printStackTrace();
if(Math.random() > 0.99) {
File dbFileBackup = new File(dbFile.getAbsolutePath() + ".backup." + DateFormats.DATE_TIME_FORMATTER_SHORT.format(new Date()).substring(0, 10) + ".sqlite3");
if (dbFile.exists() && !dbFileBackup.exists()) {
try {
Files.copy(dbFile.toPath(), dbFileBackup.toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
e.printStackTrace();
}
}
for(File file: FileConstants.TC_DIRECTORY.listFiles()) {
if(file.getName().startsWith(dbFile.getName() + ".backup")) {
try {
long now = System.currentTimeMillis();
long diff = now - Files.getLastModifiedTime(file.toPath()).toMillis();
int fileAgeInDays = (int) (diff/ 1000 / 60 / 60 / 24);
System.out.println("Found backup file " + file.getName() + "with age: " + fileAgeInDays);
if(fileAgeInDays > 14) {
file.delete();
}
} catch (IOException ex) {
ex.printStackTrace();
System.err.println("Deleting old backups failed: " + ex.getMessage());
break;
}
}
}
}

View File

@ -1,4 +1,4 @@
package org.nanoboot.utils.timecalc.swing.common;
package org.nanoboot.utils.timecalc.swing.windows;
import org.nanoboot.utils.timecalc.utils.common.Utils;

View File

@ -1,5 +1,10 @@
package org.nanoboot.utils.timecalc.swing.common;
package org.nanoboot.utils.timecalc.swing.windows;
import org.nanoboot.utils.timecalc.swing.controls.TTextField;
import org.nanoboot.utils.timecalc.swing.controls.TLabel;
import org.nanoboot.utils.timecalc.swing.controls.TCheckBox;
import org.nanoboot.utils.timecalc.swing.controls.TWindow;
import org.nanoboot.utils.timecalc.swing.controls.TTabbedPane;
import org.nanoboot.utils.timecalc.entity.WorkingDay;
import org.nanoboot.utils.timecalc.entity.WorkingDayForStats;
import org.nanoboot.utils.timecalc.persistence.api.WorkingDayRepositoryApi;
@ -9,7 +14,6 @@ import org.nanoboot.utils.timecalc.utils.common.NumberFormats;
import org.nanoboot.utils.timecalc.utils.common.TTime;
import org.nanoboot.utils.timecalc.utils.common.Utils;
import org.nanoboot.utils.timecalc.utils.property.InvalidationListener;
import org.nanoboot.utils.timecalc.utils.property.Property;
import javax.swing.JButton;
import javax.swing.JComboBox;
@ -25,6 +29,9 @@ import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import org.nanoboot.utils.timecalc.swing.common.ArrivalChart;
import org.nanoboot.utils.timecalc.swing.common.ArrivalChartData;
import org.nanoboot.utils.timecalc.swing.common.SwingUtils;
/**
* @author Robert Vokac

View File

@ -6,7 +6,7 @@ package org.nanoboot.utils.timecalc.utils.common;
*/
public class Constants {
public static final String DEFAULT_START_TIME = "7:00";
public static final String DEFAULT_ARRIVAL_TIME = "7:00";
public static final String DEFAULT_OVERTIME = "0:00";
public static final String NEW_LINE = "\n";

View File

@ -9,10 +9,6 @@ import java.io.File;
public class FileConstants {
public static final File TC_DIRECTORY = new File(".tc");
public static final File STARTTIME_TXT
= new File(TC_DIRECTORY, "starttime.txt");
public static final File OVERTIME_TXT
= new File(TC_DIRECTORY, "overtime.txt");
public static final File TEST_TXT = new File(TC_DIRECTORY, "test.txt");
public static final File TIME_CALC_PROFILES_TXT_FILE
= new File(TC_DIRECTORY, "time-calc-profiles.txt");

View File

@ -8,18 +8,42 @@ _Time Calc is written in Java programming language and uses the Swing framework.
![Screenshot of application "Time Calc"](images/screenshot.jpg)
Time Calc is inspired by this document: [report.ods](https://code.nanoboot.org/nanoboot/time-calc/raw/branch/rvc/report.ods)
![report.ods.working_day.jpg](images/report.ods.working_day.jpg)
![report.ods.activities.jpg](images/report.ods.activities.jpg)
### Screenshots
!["Working Days" window - table](images/working_days_window_table.jpg)
!["Working Days" window - table](images/working_days_window_chart.jpg)
!["Activites" window](images/activities_window.jpg)
!["Config" window - clock](images/config_window_clock.jpg)
!["Config" window - battery](images/config_window_battery.jpg)
!["Config" window - smileys](images/config_window_smileys.jpg)
!["Config" window - test](images/config_window_test.jpg)
!["Config" window - misc](images/config_window_misc.jpg)
## Usage
### Start of application
When "Time Calc" is started", user is asked for:
- start time ... like 7:30
- overtime ... like 0:45 ... overtime is optional and the default value is 0:00
- start time ... like 7:30
- overtime ... like 0:45 ... overtime is optional and the default value is 0:00
### Restart of application
You can restart the app, if you press the **"Restart"** button.
- Then you are asked again for start time and overtime.
- Then you are asked again for start time and overtime.
### End of application
@ -33,7 +57,7 @@ If these files are present, something special happens.
### .tc/starttime.txt
This file contains the default start time - used during the previous run of the app.
This file contains the default start time - used during the previous run of the app.
If file starttime.txt does not exist, then the default start time is 7:00.
### .tc/overtime.txt
@ -41,9 +65,6 @@ If file starttime.txt does not exist, then the default start time is 7:00.
This file contains the default overtime - used during the previous run of the app.
If file overtime.txt does not exist, then the default overtime is 0:00.
### .tc/test.txt
If file test.txt exists, then user is not asked for start time and overtime. Instead, the values in files starttime.txt and overtime.txt are used.
### ./tc/timecalc.conf
Configuration is stored here.
@ -64,29 +85,29 @@ Optional assignments of profiles to numbers is stored here.
### 3 Visibility modes
* STRONGLY_COLORED - many colors
* WEAKLY_COLORED - darkened colors
* GRAY - gray colors
* NONE - widgets are hidden
* STRONGLY_COLORED - many colors
* WEAKLY_COLORED - darkened colors
* GRAY - gray colors
* NONE - widgets are hidden
### Widgets
#### Analog Clock
* hour hand
* minute hand (can be disabled in configuration)
* second hand (can be disabled in configuration)
* millisecond hand (can be disabled in configuration)
* shows current year, month, day of month and day of week, if analog clock is hovered by mouse cursor and Visibility is STRONGLY_COLORED
* shows yellow highlighted remaining time until end of today working hours, if analog clock is hovered by mouse cursor and Visibility is STRONGLY_COLORED
* hands can be long or shorter (can be set in configuration)
* hour hand
* minute hand (can be disabled in configuration)
* second hand (can be disabled in configuration)
* millisecond hand (can be disabled in configuration)
* shows current year, month, day of month and day of week, if analog clock is hovered by mouse cursor and Visibility is STRONGLY_COLORED
* shows yellow highlighted remaining time until end of today working hours, if analog clock is hovered by mouse cursor and Visibility is STRONGLY_COLORED
* hands can be long or shorter (can be set in configuration)
#### Progress Square
* Show graphically day progress
* Show graphically day progress
#### Progress Circle
* Show graphically day progress
* Show graphically day progress
#### Hour Battery
@ -188,12 +209,12 @@ Smileys can be colored or white-black (can be set in configuration)
### New features
* Custom arrival target
* Split to Maven modules
* Junit, Mockito, etc.
* Checkstyle
* Sonarlint
* Sonarqube
* Custom arrival target
* Split to Maven modules
* Junit, Mockito, etc.
* Checkstyle
* Sonarlint
* Sonarqube
### Fix these known bugs

BIN
report.ods Normal file

Binary file not shown.