Compare commits

...

386 Commits

Author SHA1 Message Date
3df9bfe973
Updated screenshot 2024-05-21 18:04:56 +02:00
764e54eb0a
Removed ProgressColor 2024-05-21 17:34:33 +02:00
2217c7a29a
Water can be now colored, if enabled in configuration 2024-05-21 17:32:48 +02:00
4c5823e6a2
Added ProgressWater 2024-05-18 17:15:46 +02:00
0d2b89750a
A bug was fixed - deleting activity deleted this activity only from database, but not GUI, where it was only hidden and appear again in case, some of the remaining activities for the given day was updated 2024-05-18 17:14:20 +02:00
e56d16283e
Small layout changes 2024-05-18 17:13:13 +02:00
91ecac965a
Elapsed and remains text fields are now coloured (red or green), if the visibility mode is strongly colored 2024-05-18 17:12:54 +02:00
439e6514a3
Added glasshour icons. Elapsed and remains text fields are now coloured (red or green), if the visibility mode is not grey 2024-05-18 17:12:11 +02:00
b5a17d8e8f
Components were reorganized II 2024-05-18 17:10:48 +02:00
59278eff62
Components were reorganized 2024-05-18 17:10:19 +02:00
d0639b2009
Added new features related to the pause III 2024-05-18 17:09:27 +02:00
4fe0af8eed
Added new features related to the pause II 2024-05-18 17:09:08 +02:00
50229d95f2
Added new features related to the pause 2024-05-18 17:08:39 +02:00
05f727861c
Updated help 2024-05-02 16:52:08 +02:00
1ef21c7ed5
Fixed a layout 2024-04-30 18:34:36 +02:00
34645f5548
Fixed maximum day of February 2024-04-30 18:33:18 +02:00
02df286be3
Added ProgressColor 2024-04-30 18:32:44 +02:00
63b59b562f
Revert "Added a web browser"
This reverts commit 3f5a39ff8543017a55996bbd1f64142d1af65116.
2024-04-30 18:29:57 +02:00
3f5a39ff85
Added a web browser 2024-04-30 18:24:17 +02:00
eab2a69bc4
Added the possibility to view only activities window 2024-04-30 18:22:41 +02:00
a9333194c7
Added several improvements 2024-04-30 18:22:03 +02:00
Robert Vokac
fcafe1f3e5
Added flatlaf look and feel 2024-04-23 19:00:35 +02:00
Robert Vokac
c0cdacfdb8
Added elapsed and remaining time for the current week 2024-04-23 17:21:22 +02:00
Robert Vokac
ef5cae98ee
Added life progress 2024-04-23 17:19:59 +02:00
Robert Vokac
b6a4e4a5e0
Fixed bug - activity flag must not be an empty text 2024-04-20 14:07:50 +02:00
Robert Vokac
2cd7226c68
Updated screenshot 2024-04-18 17:40:58 +02:00
Robert Vokac
db3e368b2d
Added ProgressBar 2024-04-18 17:34:53 +02:00
Robert Vokac
32d122c351
Improved ProgressCircle 2024-04-18 17:34:27 +02:00
Robert Vokac
39ee336b4e
Added ProgressRotation II 2024-04-18 17:32:42 +02:00
Robert Vokac
e74f63b6b5
Added ProgressRotation 2024-04-18 17:32:29 +02:00
Robert Vokac
e20cf1d428
Fixed several bugs 2024-04-06 10:57:22 +02:00
Robert Vokac
ab3a2c1585
Added new configuration entry: 'Type : Visible' 2024-04-06 10:56:36 +02:00
Robert Vokac
2fa262cf7d
Added new button 'Add flags to all activities' 2024-04-06 10:55:59 +02:00
Robert Vokac
dcc27eefd2
Small change 2024-04-03 16:25:51 +02:00
Robert Vokac
3f2db2f80f
Added PRESENTATION to WidgetType enum 2024-04-03 16:25:17 +02:00
Robert Vokac
4eb43b0cdd
Updated Readme.md II 2024-03-30 17:58:04 +01:00
Robert Vokac
97693d1eab
Updated Readme.md 2024-03-30 17:47:29 +01:00
Robert Vokac
e9fe11cbeb
Updated screenshots 2024-03-30 17:38:37 +01:00
Robert Vokac
e50c5da63d
Fixed ProgressSwing - body position and enable almost everything feature was a very little changed 2024-03-30 17:26:07 +01:00
Robert Vokac
c549105284
Fixed Fuel Gauge icon - should be rendered just after rendering the background 2024-03-30 17:09:44 +01:00
Robert Vokac
f02e1d6f7e
Fuel Gauge was finished - icon was fixed 2024-03-30 17:09:35 +01:00
Robert Vokac
02f821d127
Fixed ConfigWindow 2024-03-30 17:09:32 +01:00
Robert Vokac
351e0a079f
Added Fuel Gauge Icon - work in progress II 2024-03-30 17:09:30 +01:00
Robert Vokac
6f187222f8
Added Fuel Gauge Icon - work in progress I 2024-03-30 17:09:21 +01:00
Robert Vokac
9faeb4f7d7
Fixed antialiasing rendering III 2024-03-27 17:41:36 +01:00
Robert Vokac
cd00cae782
Fixed antialiasing rendering II 2024-03-27 17:41:25 +01:00
Robert Vokac
68970bf04e
Fixed antialiasing rendering 2024-03-27 17:41:16 +01:00
Robert Vokac
f151c079dc
Added fuel gauge II 2024-03-27 17:40:37 +01:00
Robert Vokac
12371d8bb3
Added fuel gauge 2024-03-27 17:40:20 +01:00
Robert Vokac
a9ee1ed4c9
Added several improvements 2024-03-27 17:39:55 +01:00
Robert Vokac
b391b2caf8
Added new feature - possibility to allow only the basic II 2024-03-27 17:39:10 +01:00
Robert Vokac
46cb809502
Added new feature - possibility to allow only the basic 2024-03-27 17:38:32 +01:00
Robert Vokac
1815e996b6
Fixed a bug 2024-03-27 17:38:09 +01:00
Robert Vokac
d15bf7bc65
Added some improvements 2024-03-24 15:33:44 +01:00
Robert Vokac
54411412d8
Added some improvements 2024-03-24 14:52:27 +01:00
Robert Vokac
f28759ffd1
Added some improvements 2024-03-24 13:25:03 +01:00
Robert Vokac
9afa86c0d9
Added some improvements 2024-03-24 13:14:34 +01:00
Robert Vokac
d8f6796a76
Added some improvements 2024-03-24 12:31:02 +01:00
Robert Vokac
9a7db29509
Added some improvements 2024-03-24 11:40:54 +01:00
Robert Vokac
f3a1203e99
Added support to change speed of time III 2024-03-23 21:07:33 +01:00
Robert Vokac
9911246ae5
Added support to change speed of time II 2024-03-23 20:25:50 +01:00
Robert Vokac
9f27e68285
Added support to change speed of time 2024-03-23 20:06:36 +01:00
Robert Vokac
6f65450f01
Added ProgressDot III 2024-03-23 18:11:07 +01:00
Robert Vokac
68f420526a
Added ProgressDot II 2024-03-23 17:57:41 +01:00
Robert Vokac
64d6e28323
Added ProgressDot 2024-03-23 17:39:24 +01:00
Robert Vokac
763f2ee903
Added circle progress for analog clock 2024-03-23 16:49:20 +01:00
Robert Vokac
604d2384cf
ProgressWeather was finished 2024-03-23 16:31:36 +01:00
Robert Vokac
7f035a931d
patch28 2024-03-23 08:20:07 +01:00
Robert Vokac
5f33e62c76
patch27 2024-03-23 08:20:06 +01:00
Robert Vokac
55afc71d42
patch26 2024-03-23 08:20:06 +01:00
Robert Vokac
c9692719bb
patch25 2024-03-23 08:20:06 +01:00
Robert Vokac
e56d7cf00c
patch24 2024-03-23 08:20:05 +01:00
Robert Vokac
f28ca92503
patch23 2024-03-23 08:20:05 +01:00
Robert Vokac
e0f62c66bb
patch22 2024-03-23 08:20:05 +01:00
Robert Vokac
bf2e692b10
patch21 2024-03-23 08:20:04 +01:00
Robert Vokac
3a7490372d
patch20 2024-03-23 08:20:04 +01:00
Robert Vokac
898d39d22b
patch19 2024-03-23 08:20:04 +01:00
Robert Vokac
3c4cdcbfec
patch18 2024-03-23 08:20:03 +01:00
Robert Vokac
8e9b90d622
patch17 2024-03-23 08:20:03 +01:00
Robert Vokac
46ae2a8d5b
patch16 2024-03-23 08:20:03 +01:00
Robert Vokac
805ddd162f
patch15 2024-03-23 08:20:02 +01:00
Robert Vokac
2f7482536e
patch14 2024-03-23 08:20:02 +01:00
Robert Vokac
888e4b2cbc
patch13 2024-03-23 08:20:02 +01:00
Robert Vokac
bde480f222
patch12 2024-03-23 08:20:01 +01:00
Robert Vokac
98c01e571d
patch11 2024-03-23 08:20:01 +01:00
Robert Vokac
462e4c9c6e
patch10 2024-03-23 08:20:01 +01:00
Robert Vokac
86245d0b46
patch9 2024-03-23 08:20:00 +01:00
Robert Vokac
4d6dbd3285
patch8 2024-03-23 08:20:00 +01:00
Robert Vokac
d21ec2f0e8
patch7 2024-03-23 08:20:00 +01:00
Robert Vokac
6951b4c25d
patch6 2024-03-23 08:19:59 +01:00
Robert Vokac
91940c3977
patch5 2024-03-23 08:19:59 +01:00
Robert Vokac
a2920dc5f0
patch4 2024-03-23 08:19:59 +01:00
Robert Vokac
fbdaf6d368
patch3 2024-03-23 08:19:58 +01:00
Robert Vokac
7b55fc7be1
patch2 2024-03-23 08:19:58 +01:00
Robert Vokac
9756a2fd6a
patch1 2024-03-23 08:19:58 +01:00
Robert Vokac
fcffaed480
Added several improvements 2024-03-16 18:50:13 +00:00
Robert Vokac
62c875f039
Updated .gitignore 2024-03-16 18:50:12 +00:00
Robert Vokac
df75aeb966
Added several improvements, changes and bug fixes 2024-03-16 18:14:42 +00:00
Robert Vokac
f42c6333a6
Added several improvements, changes and bug fixes 2024-03-16 18:04:04 +00:00
Robert Vokac
1af495ca5c
Added several improvements, changes and bug fixes 2024-03-16 17:43:01 +00:00
Robert Vokac
97aa529b62
Added several improvements, changes and bug fixes 2024-03-16 17:17:44 +00:00
Robert Vokac
2e338de4d2
Added several improvements, changes and bug fixes 2024-03-16 16:44:28 +00:00
Robert Vokac
1e518b5964
Added several improvements, changes and bug fixes 2024-03-16 16:03:13 +00:00
Robert Vokac
a95ca6a58d
Added several improvements, changes and bug fixes 2024-03-16 15:33:09 +00:00
Robert Vokac
30d4ff30a4
Added several improvements, changes and bug fixes 2024-03-16 14:51:11 +00:00
Robert Vokac
8787ba9551
Added several improvements, changes and bug fixes 2024-03-16 14:08:47 +00:00
Robert Vokac
95b4888ba9
Added several improvements, changes and bug fixes 2024-03-16 14:06:48 +00:00
Robert Vokac
2d12504394
Added several improvements, changes and bug fixes 2024-03-16 14:04:20 +00:00
Robert Vokac
d7feedcf1f
Added several improvements, changes and bug fixes 2024-03-16 13:17:22 +00:00
Robert Vokac
82f8c9b683
Added several improvements, changes and bug fixes 2024-03-16 13:26:35 +00:00
Robert Vokac
402ff5b0a5
Added several improvements, changes and bug fixes 2024-03-16 12:36:04 +00:00
Robert Vokac
f4717913b6
Added several improvements, changes and bug fixes 2024-03-10 20:17:10 +00:00
Robert Vokac
62048feb23
Added several improvements, changes and bug fixes 2024-03-10 19:34:29 +00:00
Robert Vokac
3b9b6ef07a
Added several improvements, changes and bug fixes 2024-03-10 19:16:50 +00:00
Robert Vokac
e381c215ff
Added several improvements, changes and bug fixes 2024-03-10 18:38:57 +00:00
Robert Vokac
abc622290c
Added several improvements, changes and bug fixes 2024-03-10 18:00:58 +00:00
Robert Vokac
46130d1855
Added several improvements, changes and bug fixes 2024-03-10 17:21:57 +00:00
Robert Vokac
066aa76ca4
Added several improvements, changes and bug fixes 2024-03-10 16:36:36 +00:00
Robert Vokac
dc55cd4878
Fixed an sql file 2024-03-10 15:52:38 +00:00
Robert Vokac
d340250f3e
ActivitiesWindow - wip 2024-03-10 15:39:23 +00:00
Robert Vokac
73e5ba2ceb
Added arrival chart 2024-03-10 15:06:21 +00:00
Robert Vokac
7c4c26b0b6
Added support for moving averages of arrival 2024-03-10 14:11:10 +00:00
Robert Vokac
4983528417
Added + and - small buttons for arrival, overtime, work and pause 2024-03-10 13:47:39 +00:00
Robert Vokac
d53818010a
Added smiley head to walking human 2024-03-10 13:39:30 +00:00
Robert Vokac
1f18d57c6b
Fixed some bugs 2024-03-10 13:15:05 +00:00
Robert Vokac
cfc945d182
Added several improvements 2024-03-09 22:36:59 +00:00
Robert Vokac
41cfc06b24
User is now asked before creating or updating a working day in SQLite database 2024-03-09 22:14:56 +00:00
Robert Vokac
295f73c4b0
WorkingDayWindow changes 2024-03-09 21:35:15 +00:00
Robert Vokac
b8d9e0a6a2
WorkingDaysWindow wip 2024-03-09 21:10:47 +00:00
Robert Vokac
48bac8b5f5
SQLite support - work in progress 2024-03-09 20:31:52 +00:00
Robert Vokac
e43df2feca
Added support for custom working time and pause time 2024-03-09 19:59:35 +00:00
Robert Vokac
6930b3e8ed
Formatted code 2024-03-09 19:31:05 +00:00
Robert Vokac
e12d5aaf25
Updated screenshot 2024-03-09 19:18:05 +00:00
Robert Vokac
9e23593fb3
Added some improvements 2024-03-09 19:47:51 +00:00
Robert Vokac
8681968d96
Added some improvements 2024-03-09 19:21:22 +00:00
Robert Vokac
82fbe2a0c8
Added some improvements 2024-03-09 19:00:37 +00:00
Robert Vokac
ed91ff4003
Added some improvements 2024-03-09 18:50:12 +00:00
Robert Vokac
944eebdd07
Added some improvements 2024-03-09 18:20:31 +00:00
Robert Vokac
2e97fa8843
Added some improvements 2024-03-09 18:12:04 +00:00
Robert Vokac
4ae7e1e962
Added some improvements 2024-03-09 18:25:42 +00:00
Robert Vokac
7b649b37a7
Added some improvements 2024-03-09 18:01:43 +00:00
Robert Vokac
2af864e0e3
Added some improvements 2024-03-09 17:57:20 +00:00
Robert Vokac
c611f514e4
Added some improvements 2024-03-09 17:38:23 +00:00
Robert Vokac
6c7a6cd2d8
Fixed several bugs 2024-03-09 17:03:16 +00:00
Robert Vokac
171118e785
Fixed several bugs 2024-03-09 16:38:42 +00:00
Robert Vokac
ddace4495d
Added some improvements 2024-03-09 16:18:53 +00:00
Robert Vokac
db1c0764dd
Added some improvements 2024-03-09 15:51:40 +00:00
Robert Vokac
5291779733
Added some improvements 2024-03-09 15:22:52 +00:00
Robert Vokac
55fc9970b5
Refactoring and some changes 2024-03-09 15:05:24 +00:00
Robert Vokac
7d97b71617
WalkingHumanProgress was refactored 2024-03-09 14:27:33 +00:00
Robert Vokac
50142440c8
Added sqlite support - wip 7 2024-03-09 14:01:36 +00:00
Robert Vokac
6b67b4512a
Added sqlite support - wip 6 2024-03-09 13:30:37 +00:00
Robert Vokac
119bba1578
Added sqlite support - wip 5 2024-03-09 13:00:54 +00:00
Robert Vokac
d28b92915e
Added sqlite support - wip 4 2024-03-09 12:38:33 +00:00
Robert Vokac
edba3362d7
Added sqlite support - wip 3 2024-03-09 12:19:30 +00:00
Robert Vokac
32fc2a338d
Added sqlite support - wip 2 2024-03-09 12:06:06 +00:00
Robert Vokac
9c4577dddd
Added sqlite support - wip 1 2024-03-09 11:49:35 +00:00
Robert Vokac
8a36e47404
Added several improvements 2024-03-09 11:28:10 +00:00
Robert Vokac
e553ecb6a6
Added several improvements 2024-03-09 11:02:33 +00:00
Robert Vokac
e7c765f47e
Added several improvements 2024-03-09 10:15:25 +00:00
Robert Vokac
f9bad51649
Added several improvements 2024-03-09 10:50:00 +00:00
Robert Vokac
efa6e1437e
Added several improvements 2024-03-09 10:28:08 +00:00
Robert Vokac
a92ff1837d
Added several improvements 2024-03-09 09:55:14 +00:00
Robert Vokac
564256e96a
Added profile switching 2024-03-09 09:24:51 +00:00
Robert Vokac
5c67a2da5b
Formatted code 2024-03-03 15:04:36 +00:00
Robert Vokac
5a9e7fbf86
Added several improvements 2024-03-03 14:27:56 +00:00
Robert Vokac
b9c5e317b0
Added several improvements 2024-03-03 14:19:49 +00:00
Robert Vokac
4af1ecb4ed
Added several improvements 2024-03-03 14:01:43 +00:00
Robert Vokac
8ce268432d
Added several improvements 2024-03-03 13:25:16 +00:00
Robert Vokac
3b9805abed
Added support for profiles II 2024-03-03 13:20:38 +00:00
Robert Vokac
b7ef2119f3
Added support for profiles 2024-03-03 13:19:59 +00:00
Robert Vokac
bd0bc03e38
Fixed bug - Visibility could not be switched in ConfigWindow 2024-03-03 13:11:54 +00:00
Robert Vokac
0f9f32bc32
WalkingHumanProgress was refactored with several changes and improvements 2024-03-03 12:22:58 +00:00
Robert Vokac
9a7bdb15a1
Added the possibility to set a custom window title 2024-03-03 12:05:40 +00:00
Robert Vokac
ac3962fe8b
Added new improvements 2024-03-03 11:23:14 +00:00
Robert Vokac
bba77ef67d
Added new improvements 2024-03-02 12:04:36 +00:00
Robert Vokac
74f5fffb28
Added new improvements 2024-03-02 12:03:19 +00:00
Robert Vokac
d1f49803c8
Added the possibility to hide buttons 2024-03-02 11:30:21 +00:00
Robert Vokac
4d4bf32645
Added improvements 2024-03-02 11:04:41 +00:00
Robert Vokac
c89d5e6022
Added improvements 2024-03-02 11:01:34 +00:00
Robert Vokac
6b0cc58ff1
Added improvements 2024-03-02 10:48:30 +00:00
Robert Vokac
bed5c39a1a
Added improvements 2024-03-02 10:32:21 +00:00
Robert Vokac
c244abe78b
Updated screenshot 2024-03-02 10:03:56 +00:00
Robert Vokac
488dda556a
Added improvements 2024-03-02 10:23:55 +00:00
Robert Vokac
1a187ca1ed
Added many improvements 2024-02-25 09:40:45 +00:00
Robert Vokac
cef103066f
Formatted code 2024-02-25 09:15:07 +00:00
Robert Vokac
a2c64709e9
Added new improvements 2024-02-25 09:24:16 +00:00
Robert Vokac
804a937e82
Added new improvements 2024-02-25 09:11:07 +00:00
Robert Vokac
21b9b873c4
Added many clock improvements 2024-02-25 08:58:18 +00:00
Robert Vokac
41d71021bc
Added clock border 2024-02-25 08:18:52 +00:00
Robert Vokac
7f10583aaf
Added close button for widgets IV 2024-02-24 15:04:26 +00:00
Robert Vokac
8110246b86
Added close button for widgets III 2024-02-24 14:47:47 +00:00
Robert Vokac
9ca7d18fff
Added close button for widgets II 2024-02-24 14:02:13 +00:00
Robert Vokac
416fdf1ae2
Added close button for widgets I 2024-02-24 14:02:42 +00:00
Robert Vokac
a12df0214a
Added minute and year batteries 2024-02-24 13:05:39 +00:00
Robert Vokac
42f19ad7ba
ConfigWindow IX 2024-02-18 13:03:14 +00:00
Robert Vokac
6e92cf26fd
ConfigWindow VIII 2024-02-17 10:18:14 +00:00
Robert Vokac
c56e3be383
ConfigWindow VII 2024-02-17 10:10:41 +00:00
Robert Vokac
03ae7071b9
ConfigWindow VI 2024-02-17 09:51:54 +00:00
Robert Vokac
f1dadc033f
ConfigWindow V 2024-02-17 09:36:15 +00:00
Robert Vokac
e1dfb42149
ConfigWindow IV 2024-02-17 09:06:51 +00:00
Robert Vokac
1ed924fe08
ConfigWindow III 2024-02-11 15:19:19 +00:00
Robert Vokac
c59a27d1a1
ConfigWindow II 2024-02-11 15:02:21 +00:00
Robert Vokac
ad8b49ee2d
ConfigWindow I 2024-02-11 14:46:01 +00:00
Robert Vokac
58f1238123
Added new improvements 2024-02-11 14:23:21 +00:00
Robert Vokac
565cf7d541
Added new improvements 2024-02-11 14:06:06 +00:00
Robert Vokac
3250003eb3
Added color smileys III 2024-02-11 13:46:27 +00:00
Robert Vokac
a1766e7730
Added color smileys II 2024-02-11 13:33:56 +00:00
Robert Vokac
4be9118350
Added color smileys 2024-02-11 13:16:36 +00:00
Robert Vokac
e7f075c8bd
Added new improvements 2024-02-11 13:10:46 +00:00
Robert Vokac
cdf9219573
Added new improvements 2024-02-11 12:29:11 +00:00
Robert Vokac
3eff3b3ff8
Added new improvements 2024-02-11 12:24:58 +00:00
Robert Vokac
195e96eff3
Added new improvements 2024-02-11 11:40:25 +00:00
Robert Vokac
b08a45a5b9
Added new improvements 2024-02-11 11:45:23 +00:00
Robert Vokac
1ad3ad3e6a
Added new improvements 2024-02-11 11:31:16 +00:00
Robert Vokac
91cc332912
Added new improvements 2024-02-11 10:30:08 +00:00
Robert Vokac
8775f573bb
Added new improvements 2024-02-10 18:09:04 +00:00
Robert Vokac
b9f27fb1c4
Added new improvements 2024-02-10 17:12:17 +00:00
Robert Vokac
2f7f070c80
Added new improvements 2024-02-10 17:03:43 +00:00
Robert Vokac
654862bb71
Added new improvements 2024-02-10 16:38:00 +00:00
Robert Vokac
24e6bd5c48
Added progress smileys 2024-02-10 16:15:23 +00:00
Robert Vokac
c07588ec73
Added new improvements 2024-02-10 15:53:39 +00:00
Robert Vokac
f624f828c9
Added new improvements 2024-02-10 15:22:35 +00:00
Robert Vokac
902c022dee
Added new improvements 2024-02-10 15:07:50 +00:00
Robert Vokac
f3971c697f
Added new improvements 2024-02-10 14:58:26 +00:00
Robert Vokac
a863709d4f
Formatted code 2024-02-10 14:25:17 +00:00
Robert Vokac
b71e63950c
Time improvements - wip6 2024-02-10 14:09:59 +00:00
Robert Vokac
70bc18f173
Time improvements - wip5 2024-02-10 13:46:01 +00:00
Robert Vokac
ed6c6070d9
Time improvements - wip4 2024-02-10 13:41:43 +00:00
Robert Vokac
14f4931999
Time improvements - wip3 2024-02-10 13:00:19 +00:00
Robert Vokac
5bd75ddd70
Time improvements - wip2 2024-02-10 12:22:23 +00:00
Robert Vokac
4ab6553c11
Time improvements - wip1 2024-02-10 11:37:39 +00:00
Robert Vokac
eb7e190949
Added changing current date for testing purposes 2024-02-10 11:23:00 +00:00
Robert Vokac
9a68801679
Several improvements 2024-02-10 10:35:02 +00:00
Robert Vokac
1305038e0f
Added new improvements 2024-02-10 10:16:47 +00:00
Robert Vokac
f456d2195b
Added new improvements 2024-02-04 18:07:37 +00:00
Robert Vokac
597346e5d8
Added new improvements 2024-02-04 17:34:56 +00:00
Robert Vokac
67a66a60f6
Big refactoring 2024-02-04 17:14:16 +00:00
Robert Vokac
acec2fd611
Added new improvements 2024-02-04 17:01:41 +00:00
Robert Vokac
01d56d794e
Added new improvements 2024-02-04 16:24:52 +00:00
Robert Vokac
37aa23baf6
Added new improvements 2024-02-04 16:08:31 +00:00
Robert Vokac
5f60f85bff
Split to modules - initial work 2024-02-04 16:08:27 +00:00
Robert Vokac
6f52f66675
Added new improvements 2024-02-04 15:25:03 +00:00
Robert Vokac
be64014be3
Added new improvements 2024-02-04 15:14:38 +00:00
Robert Vokac
a32b1f4615
Added new improvements 2024-02-04 14:47:52 +00:00
Robert Vokac
d3b134586b
Added new improvements 2024-02-04 14:13:00 +00:00
Robert Vokac
0a86661fe1
Added new improvements 2024-02-04 13:52:59 +00:00
Robert Vokac
a573a2799c
Added new improvements 2024-02-04 13:22:37 +00:00
Robert Vokac
2a597ceee5
Added new improvements 2024-02-04 12:54:06 +00:00
Robert Vokac
33b2bf0aa4
Added new improvements 2024-02-04 12:29:26 +00:00
Robert Vokac
c18da0c12c
Added new improvements 2024-02-04 12:06:08 +00:00
Robert Vokac
a03260033f
Added new improvements 2024-02-04 11:58:29 +00:00
Robert Vokac
007024b37e
Added new improvements 2024-02-04 11:16:13 +00:00
Robert Vokac
32ebdb77b9
Added new improvements 2024-02-04 10:51:04 +00:00
Robert Vokac
dc9c3ca3b0
Added new improvements 2024-02-04 10:31:42 +00:00
Robert Vokac
e37fc57742
Added new improvements 2024-02-04 10:15:07 +00:00
Robert Vokac
8ce49c669e
Added new improvements 2024-02-03 09:14:44 +00:00
Robert Vokac
5f7826b9e0
Added new improvements 2024-02-03 08:42:10 +00:00
Robert Vokac
ac07b43358
Added new improvements 2024-02-03 08:15:57 +00:00
Robert Vokac
0168a4f223
Added new improvements 2024-02-03 07:46:59 +00:00
Robert Vokac
ab329b9d71
Added new improvements 2024-02-03 07:14:04 +00:00
Robert Vokac
60ff5ecc8e
Added new improvements 2024-02-03 06:38:35 +00:00
Robert Vokac
ee70a247ef
Added new improvements 2024-02-03 06:08:49 +00:00
Robert Vokac
d9aed13d7a
Added new improvements 2024-02-03 05:15:48 +00:00
Robert Vokac
a66c7b9a33
Added new improvements 2024-02-03 05:25:19 +00:00
Robert Vokac
c6f9d75c49
Added new improvements 2024-02-03 04:59:49 +00:00
Robert Vokac
187339583b
Added new improvements 2024-02-03 04:44:15 +00:00
Robert Vokac
0812555926
Added new improvements 2024-02-03 04:31:51 +00:00
Robert Vokac
b8ee1a1a0f
Added new improvements 2024-02-03 04:20:21 +00:00
Robert Vokac
20dfd0068f
Added new improvements 2024-02-03 03:47:16 +00:00
Robert Vokac
c260044cb4
Added new improvements 2024-02-03 03:07:37 +00:00
Robert Vokac
960fdaa593
Added new improvements 2024-02-03 02:34:45 +00:00
Robert Vokac
56428bf9e9
Added new improvements 2024-02-03 02:09:20 +00:00
Robert Vokac
83f4e130a2
Added new improvements 2024-02-03 01:28:43 +00:00
Robert Vokac
ff211e391e
Added new improvements 2024-02-03 01:06:16 +00:00
Robert Vokac
a10faea532
Code was formatted 2024-02-03 00:47:02 +00:00
Robert Vokac
43324c8f03
Added new improvements 2024-02-03 00:37:45 +00:00
Robert Vokac
05accee591
Added new improvements 2024-02-03 00:04:10 +00:00
Robert Vokac
ac4d52cf0f
Added new improvements 2024-02-03 23:34:12 +00:00
Robert Vokac
75c25fe5ae
New improvements 2024-02-03 23:15:17 +00:00
Robert Vokac
95e24fa66e
New improvements 2024-02-03 22:31:23 +00:00
Robert Vokac
4da4b8e340
Added new improvements 2024-02-03 22:07:51 +00:00
Robert Vokac
fbc59ca376
Added new improvements 2024-02-03 21:16:23 +00:00
Robert Vokac
bf40a63615
Added new improvements 2024-02-03 21:04:01 +00:00
Robert Vokac
3e0440624b
Added new improvements 2024-02-03 20:39:20 +00:00
Robert Vokac
d58b29a1ca
Added new improvements 2024-02-03 20:08:12 +00:00
Robert Vokac
ce1d089c87
Added new improvements 2024-01-03 20:11:31 +00:00
Robert Vokac
68ba77cdce
Added new improvements 2024-01-03 19:38:45 +00:00
Robert Vokac
da2d32d42a
Added new improvements 2024-01-28 18:46:19 +00:00
Robert Vokac
b98ae4ef97
Added new improvements 2024-01-28 18:43:17 +00:00
Robert Vokac
e82ca52253
Added new improvements 2024-01-28 18:12:19 +00:00
Robert Vokac
9634f28da5
Added new improvements 2024-01-28 17:31:24 +00:00
Robert Vokac
b32595d58f
Added new improvements 2024-01-28 17:08:13 +00:00
Robert Vokac
ace943aa3b
Added new improvements 2024-01-28 16:24:58 +00:00
Robert Vokac
e29549f6bc
Added new improvements 2024-01-28 16:13:44 +00:00
Robert Vokac
059c4afb2e
Added new improvements 2024-01-28 15:48:24 +00:00
Robert Vokac
a3fe9c0d4c
Added new improvements 2024-01-28 15:22:25 +00:00
Robert Vokac
8901aff6e1
Added new improvements 2024-01-28 15:21:23 +00:00
Robert Vokac
41aa6f3489
Added new improvements 2024-01-28 15:09:21 +00:00
Robert Vokac
469c49f62c
Added new improvements 2024-01-28 14:57:31 +00:00
Robert Vokac
d3dcab759c
Added new improvements 2024-01-28 14:30:03 +00:00
Robert Vokac
da901e30e1
Added new improvements 2024-01-28 14:17:30 +00:00
Robert Vokac
51e79d02b0
Added new improvements 2024-01-28 14:14:28 +00:00
Robert Vokac
824f6fb702
Code was formatted 2024-01-27 23:41:48 +00:00
Robert Vokac
8823b7d856
New improvements 2024-01-27 23:16:01 +00:00
Robert Vokac
372f73f71a
New improvements 2024-01-27 22:56:04 +00:00
Robert Vokac
b51e2f31c8
New improvements 2024-01-27 22:05:42 +00:00
Robert Vokac
b2c49ff260
New improvements 2024-01-27 21:21:38 +00:00
Robert Vokac
65bc0d9fd6
New improvements 2024-01-27 21:09:21 +00:00
Robert Vokac
7b13aefa44
New improvements 2024-01-27 20:58:03 +00:00
Robert Vokac
0dabc38592
New improvements 2024-01-27 20:28:21 +00:00
Robert Vokac
3f3c561f2b
New improvements 2024-01-27 20:14:29 +00:00
Robert Vokac
ab8f96a1c9
New improvements 2024-01-27 19:40:45 +00:00
Robert Vokac
b1301a1bda
New improvements 2024-01-27 19:04:52 +00:00
Robert Vokac
285d8a9913
New improvements 2024-01-27 19:03:48 +00:00
Robert Vokac
24c033e780
New improvements 2024-01-27 18:14:59 +00:00
Robert Vokac
b2da0777ed
New improvements 2024-01-27 17:56:55 +00:00
Robert Vokac
477950eb49
New improvements 2024-01-27 17:41:31 +00:00
Robert Vokac
8fe42f81e2
New improvements 2024-01-27 17:09:17 +00:00
Robert Vokac
ff5e9d4ccb
New improvements 2024-01-27 16:50:19 +00:00
Robert Vokac
e87c0177fe
New improvements 2024-01-27 16:18:24 +00:00
Robert Vokac
621875c325
New improvements 2024-01-27 16:07:03 +00:00
Robert Vokac
30356e2b5d
New improvements 2024-01-27 16:07:27 +00:00
Robert Vokac
7da0e72dc7
New improvements 2024-01-27 15:13:54 +00:00
Robert Vokac
4f71c66e64
New improvements 2024-01-27 14:51:58 +00:00
Robert Vokac
09dbaec4cc
New improvements 2024-01-27 14:07:04 +00:00
Robert Vokac
03475e4e28
New improvements 2024-01-27 14:13:21 +00:00
Robert Vokac
593539ac3d
New improvements 2024-01-27 14:02:25 +00:00
Robert Vokac
ec2ed16cac
New improvements 2024-01-27 13:40:23 +00:00
Robert Vokac
0abf40fded
New improvements 2024-01-27 13:15:48 +00:00
Robert Vokac
863e40ba1c
New improvements 2024-01-21 13:09:57 +00:00
Robert Vokac
922809c595
New improvements 2024-01-21 13:04:48 +00:00
Robert Vokac
a8e35a7da4
New improvements 2024-01-21 12:33:07 +00:00
Robert Vokac
0d3f06854c
Added several improvements XXXVI 2024-01-21 11:52:00 +00:00
Robert Vokac
54cdb97757
Added several improvements XXXV 2024-01-21 11:15:46 +00:00
Robert Vokac
999cb1096c
Added several improvements XXXIV 2024-01-21 11:07:55 +00:00
Robert Vokac
7c990066c5
Added several improvements XXXIII 2024-01-21 10:22:03 +00:00
Robert Vokac
cf9867c7c9
Added several improvements XXXIII 2024-01-21 10:07:48 +00:00
Robert Vokac
78e5a86e62
Added several improvements XXXII 2024-01-21 09:23:30 +00:00
Robert Vokac
0b06f31d84
Code was formatted 2024-01-21 09:14:47 +00:00
Robert Vokac
7f58f2422a
Added several improvements XXXI 2024-01-21 08:54:23 +00:00
Robert Vokac
2351e1358a
Added several improvements XXX 2024-01-21 08:07:02 +00:00
Robert Vokac
bc76a0f107
Added several improvements XXIX 2024-01-21 08:00:48 +00:00
Robert Vokac
155474f568
Added several improvements XXVIII 2024-01-21 07:45:10 +00:00
Robert Vokac
b21e90fca1
Added several improvements XXVII 2024-01-21 07:18:13 +00:00
Robert Vokac
dc81835b94
Added several improvements XXVI 2024-01-20 18:23:40 +00:00
Robert Vokac
1cdf0bd127
Added ProgressSquare II 2024-01-20 18:15:30 +00:00
Robert Vokac
8e152189e4
Added ProgressSquare 2024-01-20 17:52:25 +00:00
Robert Vokac
f77f871089
Added several improvements XXV 2024-01-20 17:19:58 +00:00
Robert Vokac
83e3c032eb
Added several improvements XXIV 2024-01-20 16:58:32 +00:00
Robert Vokac
b8abc475f9
Added several improvements XXIII 2024-01-20 16:43:32 +00:00
Robert Vokac
e73d0d75ab
Added analog clock V 2024-01-20 16:13:23 +00:00
Robert Vokac
c0003ae5e8
Added analog clock IV 2024-01-20 15:40:17 +00:00
Robert Vokac
de107997a3
Added analog clock III 2024-01-20 15:27:13 +00:00
Robert Vokac
f75c727817
Added analog clock II 2024-01-20 15:10:38 +00:00
Robert Vokac
4f4732fee6
Added analog clock 2024-01-20 14:30:23 +00:00
Robert Vokac
3913a32d5d
Revert "Added progress bar"
This reverts commit 0184bd47768f463c0fe95347867fce46ee1650c4.
2024-01-20 14:07:41 +00:00
Robert Vokac
76477ce615
Added progress bar 2024-01-20 14:29:14 +00:00
Robert Vokac
19033db1aa
Added several improvements XXII 2024-01-20 13:47:27 +00:00
Robert Vokac
ff1bc7edca
Added several improvements XXI 2024-01-20 13:13:59 +00:00
Robert Vokac
2f86a65d87
Added several improvements XX 2024-01-14 18:06:23 +00:00
Robert Vokac
eb3fcd3a1b
Added several improvements XIX 2024-01-14 17:19:06 +00:00
Robert Vokac
c636853666
Fixed Toaster - always on top 2024-01-14 16:55:39 +00:00
Robert Vokac
0453f50143
Added several improvements XVIII 2024-01-14 16:43:50 +00:00
Robert Vokac
abb8b86e69
Added several improvements XVII 2024-01-14 16:25:05 +00:00
Robert Vokac
6b590f62f0
Added several improvements XVI 2024-01-14 16:02:37 +00:00
Robert Vokac
c5e3366ef8
Added several improvements XV 2024-01-14 16:01:43 +00:00
Robert Vokac
aaf9e29aef
Fixed bug causing too high CPU usage 2024-01-14 15:14:18 +00:00
Robert Vokac
3225b23a27
Added several improvements XIV 2024-01-14 14:42:52 +00:00
Robert Vokac
e419612fed
Added GUI 2024-01-14 14:27:59 +00:00
Robert Vokac
61e323e401
Added several improvements XIII 2024-01-14 14:29:43 +00:00
Robert Vokac
1308d4e791
Added several improvements XII 2024-01-14 14:18:22 +00:00
Robert Vokac
66b3763a9a
Added several improvements XI 2024-01-14 13:23:17 +00:00
Robert Vokac
ce0a2349c4
Added several improvements X 2024-01-13 13:33:20 +00:00
Robert Vokac
1f1b680266
Added several improvements IX 2024-01-13 13:16:56 +00:00
Robert Vokac
0dc51a1b55
Added several improvements VIII 2024-01-13 12:39:40 +00:00
Robert Vokac
887b0a2569
Added several improvements VII 2024-01-13 12:32:20 +00:00
Robert Vokac
501ce0b08b
Added several improvements VI 2024-01-13 12:23:09 +00:00
Robert Vokac
1c8b6757b9
Added several improvements V 2024-01-13 12:13:26 +00:00
Robert Vokac
325284c60b
Added several improvements IV 2024-01-13 11:35:54 +00:00
Robert Vokac
28ea4fa778
Added several improvements III 2024-01-13 11:28:31 +00:00
Robert Vokac
8d7bcf26c4
EDH-6720 : Added several improvements II 2024-01-13 10:50:29 +00:00
Robert Vokac
532fe70e56
Added several improvements 2024-01-13 10:07:54 +00:00
Robert Vokac
451461e7b3
Added progress Ascii String 2024-01-13 09:21:28 +00:00
Robert Vokac
886ec2e198
Fixed a bug 2024-01-13 09:04:51 +00:00
Robert Vokac
b975b1ba32
Added files 2024-01-13 08:48:55 +00:00
167 changed files with 17815 additions and 7 deletions

23
.gitignore vendored Normal file
View File

@ -0,0 +1,23 @@
### IntelliJ IDEA ###
.idea
logs/*
*.iws
*.iml
*.ipr
target/
starttime.txt
overtime.txt
highlighted
proxy.txt
out.txt
pocasi.txt
test.txt
timecalc*.conf
focus.txt
dist/*
time-calc-current-profile.txt
time-calc-profiles.txt
**.tc/*
**/.tc/*
time-calc-jokes.txt

674
LICENCE Normal file
View File

@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

238
Readme.md
View File

@ -1 +1,237 @@
# Time Calc
# Time Calc
## Introduction
Time Calc is a desktop application used to track the remaining time until the end of some activity - like working hours.
_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 - life](images/config_window_life.jpg)
!["Config" window - money](images/config_window_money.jpg)
!["Config" window - smileys](images/config_window_smileys.jpg)
!["Config" window - progress](images/config_window_progress.jpg)
!["Config" window - test](images/config_window_test.jpg)
!["Config" window - other](images/config_window_other.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
### Restart of application
You can restart the app, if you press the **"Restart"** button.
- Then you are asked again for start time and overtime.
### End of application
You can stop the app, if you press the **"Exit"** button or click on the exit window button.
- Then application is stopped.
## Special files
If these files are present, something special happens.
### ./tc/timecalc.conf
Configuration is stored here.
### ./tc/timecalc.{profile name}.conf
Configuration for a profile is stored here.
### ./tc/time-calc-current-profile.txt
Current profile is stored here.
### ./tc/time-calc-profiles.txt
Optional assignments of profiles to numbers are stored here.
## Features
### 4 Visibility modes
* 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)
#### Progress Square
* Show graphically day progress
#### Progress Circle
* Show graphically day progress
#### Hour Battery
#### Day Battery
#### Week Battery
#### Month Battery
### Smileys
Progress in square, circle or batteries is represented also by smileys (only, if the widget is hovered by mouse cursor):
Smileys can be colored or white-black (can be set in configuration)
<pre>&#x1f631;</pre> ... face screaming in fear ... less than 6.25%
<pre>&#x1f621;</pre> ... pouting face ... less than 12.5%
<pre>&#x1f620;</pre> ... angry face ... less than 18.75%
<pre>&#x1f62d;</pre> ... loudly crying face ... less than 25%
<pre>&#x1f622;</pre> ... crying face ... less than 31.25%
<pre>&#x1f61e;</pre> ... disappointed face ... less than 37.5%
<pre>&#x1f62b;</pre> ... tired face ... less than 43.75%
<pre>&#x1f628;</pre> ... fearful face ... less than 50%
<pre>&#x1f632;</pre> ... astonished face ... less than 56.25%
<pre>&#x1f626;</pre> ... frowning face with open mouth ... less than 62.5%
<pre>&#x1f60a;</pre> ... smiling face with smiling eyes ... less than 68.75%
<pre>&#x1f603;</pre> ... smiling face with open mouth ... less than 75%
<pre>&#x1f601;</pre> ... grinning face with smiling eyes ... less than 81.25%
<pre>&#x1f60e;</pre> ... smiling face with sunglasses ... less than 87.5%
<pre>&#x1f60d;</pre> ... smiling face with heart-shaped eyes ... less than 93.75%
<pre>&#x1f608;</pre> ... smiling face with horns ... more or equal to 93.75%
## Key shortcuts
* UP - Show widgets again, if they were hidden
* DOWN or PERIOD - Hide all widgets and buttons
* H - Show all hide everything
* G - switch between coloured and no-coloured visibility mode
* C - switch between strongly coloured and weakly coloured visibility mode
* V - switch visibility mode NONE and STRONGLY_COLOURED
* SPACE - switch visibility mode: NONE, GREY, WEAKLY_COLOURED, STRONGLY_COLOURED
* F2 - run commands
* R - restart app
* N - enable or disable notifications
* W - open work days window
* A - open activity window
* S - open config window
* P or F1 - open help window
* X - exit application
* J - show random Joke
* U - enable everything
* I - disable almost everything
* E - enable or disable battery waves
* B - hide or show buttons
* 0,1,2,3,4,5,6,7,8 or 9 - activates a profile
* F - show numbers for profiles
* Q - hide or show progress square
* L - hide or show progress circle
* M - hide or show walking human
* Y - hide or show smileys
* Z - set forget overtime
* LEFT - switch to previous profile
* RIGHT - switch to next profile
* K - hide or show clock
* SHIFT + {Y,N,D,H,M,S,I,K} - Increase test time value
* CTRL + {Y,N,D,H,M,S,I,K} - Decrease test time value
* ALT + {Y,N,D,H,M,S,I,K} - Reset test time value
* Y=year, N=month, K=week, D=day of month, H=hour, M=minute, S=second, I=millisecond
* SHIFT + Q - Increase speed of time
* CTRL + Q - Decrease speed of time
* ALT + Q - Reset speed of time
* COMMA - Switch between foreward and backward speed
* T - Enable or disable floating speed
* D - Reset custom time values to the real time
* SHIFT + A - Increase arrival time
* CTRL + A - Decrease arrival time
* SHIFT + O - Increase overtime
* CTRL + O - Decrease overtime
* SHIFT + W - Increase working time
* CTRL + W - Decrease working time
* SHIFT + P - Increase pause
* CTRL + P - Decrease pause
* SHIFT + C - Increase or decrease of time is change by 1 hour
* CTRL + C - Increase or decrease of time is change by 1 minute
* CTRL + E - Save arrival, overtime, working time, pause time and note
* O - Disable many features, let enable only the basic features of "Time Calc" application.
## Command button
## Todos
### New features
* Custom arrival target
* Split to Maven modules
* Junit, Mockito, etc.
* Checkstyle
* Sonarlint
* Sonarqube
### Fix these known bugs
* Clock, square and circle are grey, if visibility mode is weakly colored.
## For Developers
### How to add new property
**Change these places:**
* timecalc-default.conf
* TimeCalcProperty
* TimeCalcConfiguration
* ConfigWindow
* Widget class
* MainWindow - bind

61
build.sh Executable file
View File

@ -0,0 +1,61 @@
#!/bin/bash
MVN_ARG=$1
replace () {
INPUT=$1
OLD=$2
NEW=$3
OUTPUT=$(echo $INPUT | sed "s/$OLD/$NEW/")
echo "$OUTPUT"
}
replaceInFile() {
INPUT=$1
OLD=$2
NEW=$3
echo INPUT=$INPUT
echo OLD=$OLD
echo NEW=$NEW
sed -i 's/$OLD/$NEW/g' $INPUT
cat $INPUT
}
echo ... 1. Building
mvn clean install $MVN_ARG
#Use mvn clean install -o to build offline
if [ $? -eq 0 ]
then
echo "Build was finished"
else
echo "Build failed. Exiting"
exit
fi
echo ... 2. Deleting dist directory
rm ./dist/*.jar
echo ... 3. Detecting version
cd modules/time-calc-app/target
VERSION=`ls time-calc-app-*-jar-with-all-dependencies.jar`
VERSION=`replace $VERSION "-jar-with-all-dependencies.jar" ""`
VERSION=`replace $VERSION "time-calc-app-" ""`
ORIG_VERSION=$VERSION
BUILD_TIMESTAMP=`date +'%Y%m%d_%H%M%S'`
if [[ `ls time-calc-app-*-jar-with-all-dependencies.jar` == *"SNAPSHOT"* ]];
then
VERSION=`echo $VERSION-$BUILD_TIMESTAMP`
else
echo "Release is in progress."
fi
echo version=$VERSION
cd ../../..
mkdir dist
echo $VERSION>./dist/VERSION
echo ... 4. Moving new jar file to dist directory
mv ./modules/time-calc-app/target/time-calc-app-$ORIG_VERSION-jar-with-all-dependencies.jar ./dist/time-calc-$VERSION.jar
rm ./modules/time-calc-app/target/time-calc-app-$ORIG_VERSION.jar
#cp ./dist/time-calc-$VERSION.jar C:/Users/user/Desktop/rv

BIN
fuel_gauge_icon.odg Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

BIN
images/screenshot.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 KiB

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<actions>
<action>
<actionName>run</actionName>
<packagings>
<packaging>jar</packaging>
</packagings>
<goals>
<goal>process-classes</goal>
<goal>org.codehaus.mojo:exec-maven-plugin:3.1.0:exec</goal>
</goals>
<properties>
<exec.vmArgs></exec.vmArgs>
<exec.args>${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs}</exec.args>
<exec.appArgs></exec.appArgs>
<exec.mainClass>org.nanoboot.utils.timecalc.app.Main</exec.mainClass>
<exec.executable>java</exec.executable>
</properties>
</action>
<action>
<actionName>debug</actionName>
<packagings>
<packaging>jar</packaging>
</packagings>
<goals>
<goal>process-classes</goal>
<goal>org.codehaus.mojo:exec-maven-plugin:3.1.0:exec</goal>
</goals>
<properties>
<exec.vmArgs>-agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address}</exec.vmArgs>
<exec.args>${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs}</exec.args>
<exec.appArgs></exec.appArgs>
<exec.mainClass>org.nanoboot.utils.timecalc.app.Main</exec.mainClass>
<exec.executable>java</exec.executable>
<jpda.listen>true</jpda.listen>
</properties>
</action>
</actions>

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<relativePath>./../../pom.xml</relativePath>
<groupId>org.nanoboot.utils</groupId>
<artifactId>time-calc</artifactId>
<version>0.1.0-SNAPSHOT</version>
</parent>
<artifactId>time-calc-app</artifactId>
<name>time-calc-app</name>
<description>time-calc-app</description>
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>org.nanoboot.utils.timecalc.app.Main</mainClass>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
<manifestEntries>
<Build-Date>${timestamp}</Build-Date>
</manifestEntries>
</archive>
<!-- <descriptorRefs>-->
<!-- <descriptorRef>jar-with-dependencies</descriptorRef>-->
<!-- </descriptorRefs>-->
<descriptors>
<descriptor>./src/main/resources/install.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.jfree</groupId>
<artifactId>jfreechart</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>com.github.rjeschke</groupId>
<artifactId>txtmark</artifactId>
<version>0.13</version>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.41.2.1</version>
</dependency>
<dependency>
<groupId>com.formdev</groupId>
<artifactId>flatlaf</artifactId>
<version>3.4.1</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,86 @@
package org.nanoboot.utils.timecalc.app;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.swing.common.Toaster;
import javax.swing.JOptionPane;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* @author Robert Vokac
* @since 26.02.2024
*/
public class CommandActionListener
implements ActionListener {
private final TimeCalcApp timeCalcApp;
private final TimeCalcConfiguration timeCalcConfiguration;
public CommandActionListener(TimeCalcApp timeCalcApp,
TimeCalcConfiguration timeCalcConfiguration) {
this.timeCalcApp = timeCalcApp;
this.timeCalcConfiguration = timeCalcConfiguration;
}
@Override
public void actionPerformed(ActionEvent e) {
String commands = (String) JOptionPane.showInputDialog(
null,
"Run a command:",
"Command launching",
JOptionPane.PLAIN_MESSAGE,
null,
null,
"test"
);
String[] commandsAsArray = commands.split(" ");
switch (commandsAsArray[0]) {
case "test":
JOptionPane.showMessageDialog(null, "Test");
break;
case "color":
timeCalcApp.visibilityProperty.setValue(
commandsAsArray[1].equals("1")
? Visibility.STRONGLY_COLORED.name()
: Visibility.WEAKLY_COLORED.name());
break;
case "gray":
timeCalcApp.visibilityProperty.setValue(
commandsAsArray[1].equals("1")
? Visibility.GRAY.name()
: Visibility.WEAKLY_COLORED.name());
break;
case "waves":
timeCalcConfiguration.batteryWavesVisibleProperty
.setValue(commandsAsArray[1].equals("1"));
break;
case "uptime":
JOptionPane.showMessageDialog(null,
timeCalcApp
.getCountOfMinutesSinceAppStarted()
+ " minutes");
break;
case "toast":
Toaster t = new Toaster();
t.setToasterWidth(800);
t.setToasterHeight(800);
t.setDisplayTime(60000 * 5);
t.setToasterColor(Color.GRAY);
Font font = new Font("sans", Font.PLAIN, 12);
t.setToasterMessageFont(font);
t.setDisplayTime(5000);
t.showToaster(commands.substring(6));
break;
case "toasts":
timeCalcConfiguration.notificationsVisibleProperty
.setValue(commandsAsArray[1].equals("1"));
break;
default:
JOptionPane.showMessageDialog(null,
"Unknown command: " + commandsAsArray[0]);
}
}
}

View File

@ -0,0 +1,14 @@
package org.nanoboot.utils.timecalc.app;
import org.nanoboot.utils.timecalc.utils.property.Property;
/**
* @author Robert Vokac
* @since 26.02.2024
*/
public interface GetProperty {
Property getVisibilityProperty();
Property getVisibilitySupportedColoredProperty();
}

View File

@ -0,0 +1,40 @@
package org.nanoboot.utils.timecalc.app;
import com.formdev.flatlaf.FlatLightLaf;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.function.Supplier;
/**
* @author Robert Vokac
* @since 31.01.2024
*/
public class Main {
public static final boolean ONLY_ACTIVITIES_WINDOW_IS_ALLOWED = ((Supplier<Boolean>) () -> {
try {
return !Main.class
.getProtectionDomain()
.getCodeSource()
.getLocation()
.toURI()
.getPath().contains("time-calc");
} catch (URISyntaxException e) {
return true;
}
}).get();
public static final boolean ACTIVITIES_WINDOW_SHOW_SORTKEY = false;
public static void main(String[] args) throws IOException {
// for(File f:FileConstants.CLIMATE_TXT.getParentFile().listFiles()) {
// if(f.getName().contains("weather")) {
// System.out.println("Going to delete: " + f.getAbsolutePath());
// f.delete();
// }
// }
FlatLightLaf.setup();
TimeCalcApp timeCalcApp = new TimeCalcApp();
timeCalcApp.start(args);
}
}

View File

@ -0,0 +1,157 @@
package org.nanoboot.utils.timecalc.app;
import java.io.File;
import org.nanoboot.utils.timecalc.entity.Visibility;
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;
import org.nanoboot.utils.timecalc.utils.property.Property;
import org.nanoboot.utils.timecalc.utils.property.ReadOnlyProperty;
import org.nanoboot.utils.timecalc.utils.property.StringProperty;
import javax.swing.JOptionPane;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.sql.Connection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import lombok.Getter;
import org.nanoboot.utils.timecalc.persistence.api.VersionRepositoryApi;
import org.nanoboot.utils.timecalc.persistence.impl.sqlite.SqliteConnectionFactory;
import org.nanoboot.utils.timecalc.persistence.impl.sqlite.VersionRepositorySQLiteImpl;
import static org.nanoboot.utils.timecalc.app.Main.ONLY_ACTIVITIES_WINDOW_IS_ALLOWED;
/**
* @author Robert Vokac
* @since 31.01.2024
*/
public class TimeCalcApp {
public StringProperty visibilityProperty
= new StringProperty("timeCalcApp.visibilityProperty",
Visibility.WEAKLY_COLORED.name());
private long startNanoTime = 0l;
private Property<Boolean> allowOnlyBasicFeaturesReadWriteProperty = new Property<>("allowOnlyBasicFeaturesReadWriteProperty", false);
public ReadOnlyProperty<Boolean> allowOnlyBasicFeaturesProperty = new ReadOnlyProperty<>(allowOnlyBasicFeaturesReadWriteProperty);
@Getter
private SqliteConnectionFactory sqliteConnectionFactory;
public static final boolean IS_RUNNING_ON_LINUX = System.getProperty("os.name").equals("Linux");
public void start(String[] args) throws IOException {
File dbFile = new File(FileConstants.TC_DIRECTORY.getAbsolutePath() + "/" + "time-calc.sqlite3");
File dbFileBackup = new File(dbFile.getAbsolutePath() + ".backup." + DateFormats.DATE_TIME_FORMATTER_SHORT.format(new Date()).substring(0, 10) + ".sqlite3");
if(dbFile.exists() && !dbFileBackup.exists()) {
Files.copy(dbFile.toPath(), dbFileBackup.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
if (startNanoTime != 0l) {
throw new TimeCalcException("TimeCalcApp was already started.");
}
startNanoTime = System.nanoTime();
if (!FileConstants.TC_DIRECTORY.exists()) {
FileConstants.TC_DIRECTORY.mkdir();
}
try {
initDB();
} catch(Exception e) {
e.printStackTrace();
}
if(FileConstants.BASIC_TXT.exists()) {
allowOnlyBasicFeaturesReadWriteProperty.setValue(true);
}
while (true) {
if(!allowOnlyBasicFeaturesProperty.getValue() && FileConstants.BASIC_TXT.exists()) {
allowOnlyBasicFeaturesReadWriteProperty.setValue(true);
}
MainWindow timeCalcMainWindow = null;
try {
timeCalcMainWindow = new MainWindow(this);
} catch (Exception e) {
JOptionPane.showMessageDialog(null, "Error: " + e.getMessage(),
e.getMessage(), JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
timeCalcMainWindow.setVisible(false);
timeCalcMainWindow.dispose();
}
if(ONLY_ACTIVITIES_WINDOW_IS_ALLOWED) {
break;
}
}
}
public long getCountOfMinutesSinceAppStarted() {
return getCountOfSecondsSinceAppStarted() / 60l;
}
public long getCountOfSecondsSinceAppStarted() {
return getCountOfMillisecondsSinceAppStarted() / 1000000000l;
}
public long getCountOfMillisecondsSinceAppStarted() {
if (startNanoTime == 0l) {
throw new TimeCalcException("TimeCalcApp was not yet started.");
}
return System.nanoTime() - startNanoTime;
}
private void initDB() {
this.sqliteConnectionFactory = new SqliteConnectionFactory();
try {
Connection conn = sqliteConnectionFactory.createConnection();
} catch (ClassNotFoundException ex) {
Logger.getLogger(TimeCalcApp.class.getName()).log(Level.SEVERE, null, ex);
throw new TimeCalcException(ex);
}
List<String> files;
try {
files = Utils.loadFilesFromJarResources(DB_MIGRATIONSQLITETIMECALC, getClass());
} catch (IOException ex) {
Logger.getLogger(TimeCalcApp.class.getName()).log(Level.SEVERE, null, ex);
throw new TimeCalcException(ex);
}
Collections.sort(files);
int lastVersion = 0;
VersionRepositoryApi versionRepository = new VersionRepositorySQLiteImpl(sqliteConnectionFactory);
int currentVersion = 0;
try {
currentVersion = versionRepository.read();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("currentVersion=" + currentVersion);
for(String sql :files) {
Integer version = Integer.valueOf(sql.split("__")[0].substring(1));
lastVersion = version;
System.out.println("version=" + version);
if(currentVersion >= version) {
continue;
}
try {
System.out.println("Reading this file: " + DB_MIGRATIONSQLITETIMECALC + "/" + sql);
String text = Utils.readTextFromTextResourceInJar(DB_MIGRATIONSQLITETIMECALC + "/" + sql);
System.out.println("Found sql: \n\n" + text);
sqliteConnectionFactory.runSQL(text);
} catch (IOException ex) {
Logger.getLogger(TimeCalcApp.class.getName()).log(Level.SEVERE, null, ex);
throw new TimeCalcException(ex);
}
}
if(currentVersion != lastVersion) {
versionRepository.update(lastVersion);
}
}
private static final String DB_MIGRATIONSQLITETIMECALC = "db_migrations/sqlite/timecalc";
}

View File

@ -0,0 +1,506 @@
package org.nanoboot.utils.timecalc.app;
import org.nanoboot.utils.timecalc.utils.property.BooleanProperty;
import org.nanoboot.utils.timecalc.utils.property.IntegerProperty;
import org.nanoboot.utils.timecalc.utils.property.Property;
import org.nanoboot.utils.timecalc.utils.property.StringProperty;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* @author Robert Vokac
* @since 20.02.2024
*/
public class TimeCalcConfiguration {
public final StringProperty visibilityDefaultProperty
= new StringProperty(TimeCalcProperty.VISIBILITY_DEFAULT
.getKey());
public final BooleanProperty visibilitySupportedColoredProperty
= new BooleanProperty(TimeCalcProperty.VISIBILITY_SUPPORTED_COLORED
.getKey());
//
public final BooleanProperty clockVisibleProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_VISIBLE
.getKey());
public final BooleanProperty clockHiddenProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_HIDDEN
.getKey());
public final BooleanProperty clockHandsLongVisibleProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_HANDS_LONG_VISIBLE
.getKey());
public final BooleanProperty clockHandsColoredProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_HANDS_COLORED
.getKey());
public final BooleanProperty clockHandsHourVisibleProperty
= new BooleanProperty(
TimeCalcProperty.CLOCK_HANDS_HOUR_VISIBLE.getKey());
public final BooleanProperty clockHandsMinuteVisibleProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_HANDS_MINUTE_VISIBLE
.getKey());
public final BooleanProperty clockHandsSecondVisibleProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_HANDS_SECOND_VISIBLE
.getKey());
public final BooleanProperty clockHandsMillisecondVisibleProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_HANDS_MILLISECOND_VISIBLE
.getKey());
public final BooleanProperty clockBorderVisibleProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_BORDER_VISIBLE
.getKey());
public final BooleanProperty clockBorderOnlyHoursProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_BORDER_ONLY_HOURS
.getKey());
public final BooleanProperty clockNumbersVisibleProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_NUMBERS_VISIBLE
.getKey());
public final BooleanProperty clockCircleVisibleProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_CIRCLE_VISIBLE
.getKey());
public final BooleanProperty clockCircleStrongBorderProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_CIRCLE_STRONG_BORDER
.getKey());
public final StringProperty clockCircleBorderColorProperty
= new StringProperty(TimeCalcProperty.CLOCK_CIRCLE_BORDER_COLOR
.getKey());
public final BooleanProperty clockCentreCircleVisibleProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_CENTRE_CIRCLE_VISIBLE
.getKey());
public final BooleanProperty clockCentreCircleColoredProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_CENTRE_CIRCLE_COLORED
.getKey());
public final BooleanProperty clockProgressVisibleOnlyIfMouseMovingOverProperty
= new BooleanProperty(
TimeCalcProperty.CLOCK_PROGRESS_VISIBLE_ONLY_IF_MOUSE_MOVING_OVER
.getKey());
public final BooleanProperty clockDateVisibleOnlyIfMouseMovingOverProperty
= new BooleanProperty(
TimeCalcProperty.CLOCK_DATE_VISIBLE_ONLY_IF_MOUSE_MOVING_OVER
.getKey());
public final BooleanProperty clockSmileyVisibleProperty
= new BooleanProperty(
TimeCalcProperty.CLOCK_SMILEY_VISIBLE
.getKey());
public final BooleanProperty clockPercentProgressVisibleProperty
= new BooleanProperty(
TimeCalcProperty.CLOCK_PERCENT_PROGRESS_VISIBLE
.getKey());
public final BooleanProperty clockCircleProgressVisibleProperty
= new BooleanProperty(
TimeCalcProperty.CLOCK_CIRCLE_PROGRESS_VISIBLE
.getKey());
//
public final BooleanProperty batteryWavesVisibleProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_WAVES_VISIBLE
.getKey());
public final BooleanProperty batteryCircleProgressProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_CIRCLE_PROGRESS_VISIBLE
.getKey());
public final BooleanProperty batteryPercentProgressProperty
= new BooleanProperty(
TimeCalcProperty.BATTERY_PERCENT_PROGRESS_VISIBLE
.getKey());
public final BooleanProperty batteryChargingCharacterVisibleProperty
= new BooleanProperty(
TimeCalcProperty.BATTERY_CHARGING_CHARACTER_VISIBLE
.getKey());
public final BooleanProperty batteryNameVisibleProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_NAME_VISIBLE
.getKey());
public final BooleanProperty batteryLabelVisibleProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_LABEL_VISIBLE
.getKey());
public final BooleanProperty batteryVisibleProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_VISIBLE
.getKey());
public final BooleanProperty batteryMinuteVisibleProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_MINUTE_VISIBLE
.getKey());
public final BooleanProperty batteryHourVisibleProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_HOUR_VISIBLE
.getKey());
public final BooleanProperty batteryDayVisibleProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_DAY_VISIBLE
.getKey());
public final BooleanProperty batteryWeekVisibleProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_WEEK_VISIBLE
.getKey());
public final BooleanProperty batteryMonthVisibleProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_MONTH_VISIBLE
.getKey());
public final BooleanProperty batteryYearVisibleProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_YEAR_VISIBLE
.getKey());
public final BooleanProperty batteryMinuteHiddenProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_MINUTE_HIDDEN
.getKey());
public final BooleanProperty batteryHourHiddenProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_HOUR_HIDDEN
.getKey());
public final BooleanProperty batteryDayHiddenProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_DAY_HIDDEN
.getKey());
public final BooleanProperty batteryWeekHiddenProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_WEEK_HIDDEN
.getKey());
public final BooleanProperty batteryMonthHiddenProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_MONTH_HIDDEN
.getKey());
public final BooleanProperty batteryYearHiddenProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_YEAR_HIDDEN
.getKey());
public final BooleanProperty batteryBlinkingIfCriticalLowVisibleProperty
= new BooleanProperty(
TimeCalcProperty.BATTERY_BLINKING_IF_CRITICAL_LOW
.getKey());
public final BooleanProperty batteryQuarterIconVisibleProperty
= new BooleanProperty(
TimeCalcProperty.BATTERY_QUARTER_ICON_VISIBLE
.getKey());
public final BooleanProperty jokesVisibleProperty
= new BooleanProperty(TimeCalcProperty.JOKES_VISIBLE
.getKey());
public final BooleanProperty commandsVisibleProperty
= new BooleanProperty(TimeCalcProperty.COMMANDS_VISIBLE
.getKey());
public final BooleanProperty notificationsVisibleProperty
= new BooleanProperty(TimeCalcProperty.NOTIFICATIONS_VISIBLE
.getKey());
public final BooleanProperty smileysVisibleProperty
= new BooleanProperty(TimeCalcProperty.SMILEYS_VISIBLE.getKey());
public final BooleanProperty smileysVisibleOnlyIfMouseMovingOverProperty
= new BooleanProperty(
TimeCalcProperty.SMILEYS_VISIBLE_ONLY_IF_MOUSE_MOVING_OVER
.getKey());
public final BooleanProperty smileysColoredProperty
= new BooleanProperty(TimeCalcProperty.SMILEYS_COLORED.getKey());
public final BooleanProperty squareVisibleProperty
= new BooleanProperty(TimeCalcProperty.SQUARE_VISIBLE.getKey());
public final BooleanProperty squareHiddenProperty
= new BooleanProperty(TimeCalcProperty.SQUARE_HIDDEN.getKey());
public final StringProperty squareTypeProperty
= new StringProperty(TimeCalcProperty.SQUARE_TYPE.getKey());
public final BooleanProperty dotVisibleProperty
= new BooleanProperty(TimeCalcProperty.DOT_VISIBLE.getKey());
public final BooleanProperty dotHiddenProperty
= new BooleanProperty(TimeCalcProperty.DOT_HIDDEN.getKey());
public final StringProperty dotTypeProperty
= new StringProperty(TimeCalcProperty.DOT_TYPE.getKey());
public final BooleanProperty fuelVisibleProperty
= new BooleanProperty(TimeCalcProperty.FUEL_VISIBLE.getKey());
public final BooleanProperty fuelHiddenProperty
= new BooleanProperty(TimeCalcProperty.FUEL_HIDDEN.getKey());
public final StringProperty fuelTypeProperty
= new StringProperty(TimeCalcProperty.FUEL_TYPE.getKey());
public final BooleanProperty fuelIconVisibleProperty
= new BooleanProperty(TimeCalcProperty.FUEL_ICON_VISIBLE.getKey());
public final BooleanProperty rotationVisibleProperty
= new BooleanProperty(TimeCalcProperty.ROTATION_VISIBLE.getKey());
public final BooleanProperty rotationHiddenProperty
= new BooleanProperty(TimeCalcProperty.ROTATION_HIDDEN.getKey());
public final StringProperty rotationTypeProperty
= new StringProperty(TimeCalcProperty.ROTATION_TYPE.getKey());
public final BooleanProperty circleVisibleProperty
= new BooleanProperty(TimeCalcProperty.CIRCLE_VISIBLE.getKey());
public final BooleanProperty circleHiddenProperty
= new BooleanProperty(TimeCalcProperty.CIRCLE_HIDDEN.getKey());
public final StringProperty circleTypeProperty
= new StringProperty(TimeCalcProperty.CIRCLE_TYPE.getKey());
public final BooleanProperty circleInnerCircleVisibleProperty
= new BooleanProperty(TimeCalcProperty.CIRCLE_INNER_CIRCLE_VISIBLE.getKey());
public final BooleanProperty circleOuterCircleOnlyBorderProperty
= new BooleanProperty(TimeCalcProperty.CIRCLE_OUTER_CIRCLE_ONLY_BORDER.getKey());
//
public final BooleanProperty barVisibleProperty
= new BooleanProperty(TimeCalcProperty.BAR_VISIBLE.getKey());
public final BooleanProperty barHiddenProperty
= new BooleanProperty(TimeCalcProperty.BAR_HIDDEN.getKey());
public final StringProperty barTypeProperty
= new StringProperty(TimeCalcProperty.BAR_TYPE.getKey());
public final IntegerProperty barHeightProperty
= new IntegerProperty(TimeCalcProperty.BAR_HEIGHT.getKey());
//
public final BooleanProperty waterVisibleProperty
= new BooleanProperty(TimeCalcProperty.WATER_VISIBLE.getKey());
public final BooleanProperty waterHiddenProperty
= new BooleanProperty(TimeCalcProperty.WATER_HIDDEN.getKey());
public final StringProperty waterTypeProperty
= new StringProperty(TimeCalcProperty.WATER_TYPE.getKey());
public final BooleanProperty waterColoredProperty
= new BooleanProperty(TimeCalcProperty.WATER_COLORED.getKey());
//
public final BooleanProperty walkingHumanVisibleProperty
= new BooleanProperty(
TimeCalcProperty.WALKING_HUMAN_VISIBLE.getKey());
public final BooleanProperty walkingHumanHiddenProperty
= new BooleanProperty(
TimeCalcProperty.WALKING_HUMAN_HIDDEN.getKey());
public final StringProperty walkingHumanTypeProperty
= new StringProperty(TimeCalcProperty.WALKING_HUMAN_TYPE.getKey());
public final BooleanProperty swingVisibleProperty
= new BooleanProperty(TimeCalcProperty.SWING_VISIBLE.getKey());
public final BooleanProperty swingHiddenProperty
= new BooleanProperty(TimeCalcProperty.SWING_HIDDEN.getKey());
public final StringProperty swingTypeProperty
= new StringProperty(TimeCalcProperty.SWING_TYPE.getKey());
public final BooleanProperty swingQuarterIconVisibleProperty
= new BooleanProperty(TimeCalcProperty.SWING_QUARTER_ICON_VISIBLE.getKey());
public final BooleanProperty lifeVisibleProperty
= new BooleanProperty(TimeCalcProperty.LIFE_VISIBLE.getKey());
public final BooleanProperty lifeHiddenProperty
= new BooleanProperty(TimeCalcProperty.LIFE_HIDDEN.getKey());
public final StringProperty lifeTypeProperty
= new StringProperty(TimeCalcProperty.LIFE_TYPE.getKey());
public final StringProperty lifeBirthDateProperty
= new StringProperty(TimeCalcProperty.LIFE_BIRTH_DATE.getKey());
public final BooleanProperty moneyVisibleProperty
= new BooleanProperty(TimeCalcProperty.MONEY_VISIBLE.getKey());
public final BooleanProperty moneyHiddenProperty
= new BooleanProperty(TimeCalcProperty.MONEY_HIDDEN.getKey());
public final StringProperty moneyTypeProperty
= new StringProperty(TimeCalcProperty.MONEY_TYPE.getKey());
public final IntegerProperty moneyPerMonthProperty
= new IntegerProperty(TimeCalcProperty.MONEY_PER_MONTH.getKey());
public final StringProperty moneyCurrencyProperty
= new StringProperty(TimeCalcProperty.MONEY_CURRENCY.getKey());
public final BooleanProperty weatherVisibleProperty
= new BooleanProperty(TimeCalcProperty.WEATHER_VISIBLE.getKey());
public final BooleanProperty weatherHiddenProperty
= new BooleanProperty(TimeCalcProperty.WEATHER_HIDDEN.getKey());
public final StringProperty mainWindowCustomTitleProperty
= new StringProperty(
TimeCalcProperty.MAIN_WINDOW_CUSTOM_TITLE.getKey());
public final StringProperty profileNameProperty
= new StringProperty(TimeCalcProperty.PROFILE_NAME.getKey());
public final StringProperty activityNeededFlagsProperty
= new StringProperty(TimeCalcProperty.ACTIVITY_NEEDED_FLAGS.getKey());
public final BooleanProperty testEnabledProperty = new BooleanProperty(TimeCalcProperty.TEST_ENABLED.getKey(), false);
public final IntegerProperty testYearCustomProperty = new IntegerProperty(TimeCalcProperty.TEST_CLOCK_CUSTOM_YEAR
.getKey(), Integer.MAX_VALUE);
public final IntegerProperty testMonthCustomProperty = new IntegerProperty(TimeCalcProperty.TEST_CLOCK_CUSTOM_MONTH
.getKey(), Integer.MAX_VALUE);
public final IntegerProperty testDayCustomProperty = new IntegerProperty(TimeCalcProperty.TEST_CLOCK_CUSTOM_DAY
.getKey(), Integer.MAX_VALUE);
public final IntegerProperty testHourCustomProperty = new IntegerProperty(TimeCalcProperty.TEST_CLOCK_CUSTOM_HOUR
.getKey(), Integer.MAX_VALUE);
public final IntegerProperty testMinuteCustomProperty = new IntegerProperty(TimeCalcProperty.TEST_CLOCK_CUSTOM_MINUTE
.getKey(), Integer.MAX_VALUE);
public final IntegerProperty testSecondCustomProperty = new IntegerProperty(TimeCalcProperty.TEST_CLOCK_CUSTOM_SECOND
.getKey(), Integer.MAX_VALUE);
public final IntegerProperty testMillisecondCustomProperty = new IntegerProperty(TimeCalcProperty.TEST_CLOCK_CUSTOM_MILLISECOND
.getKey(), Integer.MAX_VALUE);
public final IntegerProperty speedProperty = new IntegerProperty(TimeCalcProperty.SPEED
.getKey(), 1);
public final BooleanProperty speedNegativeProperty = new BooleanProperty(TimeCalcProperty.SPEED_NEGATIVE
.getKey(), false);
public final BooleanProperty speedFloatingProperty = new BooleanProperty(TimeCalcProperty.SPEED_FLOATING
.getKey(), false);
public final BooleanProperty typeVisibleProperty = new BooleanProperty(TimeCalcProperty.TYPE_VISIBLE
.getKey(), false);
//
private final Map<TimeCalcProperty, Property> mapOfProperties
= new HashMap<>();
private final List<Property> allProperties = new ArrayList<>();
private TimeCalcProperties timeCalcProperties;
public TimeCalcConfiguration() {
for (Property p : new Property[]{
visibilityDefaultProperty,
visibilitySupportedColoredProperty,
clockVisibleProperty,
clockHandsLongVisibleProperty,
clockHandsColoredProperty,
clockHandsHourVisibleProperty,
clockHandsMinuteVisibleProperty,
clockHandsSecondVisibleProperty,
clockHandsMillisecondVisibleProperty,
clockBorderVisibleProperty,
clockBorderOnlyHoursProperty,
clockNumbersVisibleProperty,
clockCircleVisibleProperty,
clockCircleStrongBorderProperty,
clockCircleBorderColorProperty,
clockCentreCircleVisibleProperty,
clockCentreCircleColoredProperty,
clockProgressVisibleOnlyIfMouseMovingOverProperty,
clockDateVisibleOnlyIfMouseMovingOverProperty,
clockSmileyVisibleProperty,
clockPercentProgressVisibleProperty,
clockCircleProgressVisibleProperty,
batteryWavesVisibleProperty,
batteryCircleProgressProperty,
batteryPercentProgressProperty,
batteryChargingCharacterVisibleProperty,
batteryNameVisibleProperty,
batteryLabelVisibleProperty,
batteryVisibleProperty,
batteryMinuteVisibleProperty,
batteryHourVisibleProperty,
batteryDayVisibleProperty,
batteryWeekVisibleProperty,
batteryMonthVisibleProperty,
batteryYearVisibleProperty,
batteryBlinkingIfCriticalLowVisibleProperty,
batteryQuarterIconVisibleProperty,
jokesVisibleProperty,
commandsVisibleProperty,
notificationsVisibleProperty,
smileysVisibleProperty,
smileysVisibleOnlyIfMouseMovingOverProperty,
smileysColoredProperty,
squareVisibleProperty,squareTypeProperty,
circleVisibleProperty,circleTypeProperty,circleInnerCircleVisibleProperty,circleOuterCircleOnlyBorderProperty,
barVisibleProperty, barTypeProperty, barHiddenProperty, barHeightProperty,
waterVisibleProperty, waterTypeProperty, waterHiddenProperty, waterColoredProperty,
dotVisibleProperty,dotTypeProperty,
fuelVisibleProperty, fuelTypeProperty, fuelHiddenProperty,
fuelIconVisibleProperty,
rotationVisibleProperty, rotationTypeProperty, rotationHiddenProperty,
swingVisibleProperty,
swingTypeProperty,
swingQuarterIconVisibleProperty,
walkingHumanVisibleProperty,
walkingHumanTypeProperty,
lifeVisibleProperty,
lifeTypeProperty,
lifeBirthDateProperty,
moneyVisibleProperty,
moneyTypeProperty,
moneyPerMonthProperty,
moneyCurrencyProperty,
weatherVisibleProperty,
mainWindowCustomTitleProperty,
profileNameProperty,
activityNeededFlagsProperty,
speedProperty,
speedNegativeProperty,
speedFloatingProperty,
typeVisibleProperty,
clockHiddenProperty,
batteryMinuteHiddenProperty,
batteryHourHiddenProperty,
batteryDayHiddenProperty,
batteryWeekHiddenProperty,
batteryMonthHiddenProperty,
batteryYearHiddenProperty,
squareHiddenProperty,
circleHiddenProperty,
walkingHumanHiddenProperty,
swingHiddenProperty,
lifeHiddenProperty,
moneyHiddenProperty,
weatherHiddenProperty,
dotHiddenProperty,
testEnabledProperty,
testYearCustomProperty,
testMonthCustomProperty,
testDayCustomProperty,
testHourCustomProperty,
testMinuteCustomProperty,
testSecondCustomProperty,
testMillisecondCustomProperty,}) {
allProperties.add(p);
}
allProperties.stream().forEach(p -> mapOfProperties
.put(TimeCalcProperty.forKey(p.getName()), p));
batteryVisibleProperty.addListener(e -> {
batteryMinuteVisibleProperty
.setValue(batteryVisibleProperty.getValue());
batteryHourVisibleProperty
.setValue(batteryVisibleProperty.getValue());
batteryDayVisibleProperty
.setValue(batteryVisibleProperty.getValue());
batteryWeekVisibleProperty
.setValue(batteryVisibleProperty.getValue());
batteryMonthVisibleProperty
.setValue(batteryVisibleProperty.getValue());
batteryYearVisibleProperty
.setValue(batteryVisibleProperty.getValue());
});
}
public Property getProperty(TimeCalcProperty timeCalcProperty) {
if (!mapOfProperties.containsKey(timeCalcProperty)) {
throw new TimeCalcException(
"There is no property for : " + timeCalcProperty);
}
return mapOfProperties.get(timeCalcProperty);
}
public String print() {
StringBuilder sb = new StringBuilder();
for (Property p : allProperties) {
if (!p.getName().startsWith("test")) {
continue;
}
sb.append(p.getName()).append("=").append(p.getValue())
.append("\n");
}
return sb.toString();
}
public void saveToTimeCalcProperties() {
System.out.println("Going to save properties.");
if (timeCalcProperties == null) {
throw new TimeCalcException(
"Cannot save properties, because timeCalcProperties is null.");
}
Properties properties = new Properties();
this.allProperties.stream()
.forEach(p -> properties.put(p.getName(), p.getValue()));
this.timeCalcProperties
.save(properties, this.profileNameProperty.getValue());
}
public void loadFromTimeCalcProperties(
TimeCalcProperties timeCalcProperties) {
this.timeCalcProperties = timeCalcProperties;
for (Property p : allProperties) {
if (p instanceof BooleanProperty) {
p.setValue(timeCalcProperties
.getBooleanProperty(
TimeCalcProperty.forKey(p.getName())));
continue;
}
if (p.getName()
.equals(TimeCalcProperty.VISIBILITY_DEFAULT.name())) {
visibilityDefaultProperty.setValue(timeCalcProperties
.getStringProperty(
TimeCalcProperty.VISIBILITY_DEFAULT));
continue;
}
if (p instanceof StringProperty) {
p.setValue(timeCalcProperties
.getStringProperty(
TimeCalcProperty.forKey(p.getName())));
continue;
}
if (p instanceof IntegerProperty) {
p.setValue(timeCalcProperties
.getIntegerProperty(
TimeCalcProperty.forKey(p.getName())));
continue;
}
throw new TimeCalcException(
"Unsupported Property class: " + p.getClass().getName());
}
// for(Property p:allProperties) {
// System.out.println(p.getName() + "=" + p.getValue());
// }
}
}

View File

@ -0,0 +1,20 @@
package org.nanoboot.utils.timecalc.app;
import org.nanoboot.utils.timecalc.utils.common.Utils;
/**
* @author Robert Vokac
* @since 21.02.2024
*/
public class TimeCalcException extends RuntimeException {
public TimeCalcException(String msg) {
super(msg);
Utils.showNotification("Error happened: " + msg);
}
public TimeCalcException(Exception e) {
super(e);
Utils.showNotification("Error happened: " + e.getMessage());
}
}

View File

@ -0,0 +1,203 @@
package org.nanoboot.utils.timecalc.app;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.utils.common.FileConstants;
import org.nanoboot.utils.timecalc.utils.common.Utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* @author Robert Vokac
* @since 20.02.2024
*/
public class TimeCalcProperties {
private static TimeCalcProperties INSTANCE;
private final Properties properties = new Properties();
private final Map<String, String> defaultProperties = new HashMap<>();
private TimeCalcProperties() {
System.out.println("Loading configuration - start");
String profileName = "";
try {
profileName
= FileConstants.TIME_CALC_CURRENT_PROFILE_TXT_FILE.exists()
? Utils.readTextFromFile(
FileConstants.TIME_CALC_CURRENT_PROFILE_TXT_FILE)
: "";
} catch (IOException e) {
e.printStackTrace();
throw new TimeCalcException(e);
}
File file = getFile(profileName);
if (file.exists()) {
try {
this.properties.load(new FileInputStream(file));
} catch (IOException e) {
e.printStackTrace();
System.err.println(e);
}
}
System.out.println("Loading configuration - end");
System.out.println("Loading default configuration - start");
try {
String defaultConfiguration = Utils.readTextFromTextResourceInJar(
"timecalc-default.conf");
Arrays.stream(defaultConfiguration.split("\n"))
.filter(l -> !l.trim().isEmpty())
.filter(l -> !l.trim().startsWith("#"))
.filter(l -> l.contains("="))
.forEach(l -> {
String[] array = l.split("=");
defaultProperties.put(array[0],
array.length > 1 ? array[1] : "");
});
} catch (IOException e) {
e.printStackTrace();
throw new TimeCalcException(e.getMessage());
} catch (Exception e) {
e.printStackTrace();
throw e;
}
System.out.println("Loading default configuration - end");
}
public static TimeCalcProperties getInstance() {
if (INSTANCE == null) {
INSTANCE = new TimeCalcProperties();
}
return INSTANCE;
}
public boolean getBooleanProperty(TimeCalcProperty timeCalcProperty) {
return getBooleanProperty(timeCalcProperty, Boolean.valueOf(
getDefaultStringValue(timeCalcProperty)));
}
private String getDefaultStringValue(TimeCalcProperty timeCalcProperty) {
if (!defaultProperties
.containsKey(timeCalcProperty.getKey())) {
throw new TimeCalcException(
"timecalc-default.conf is missing key: \""
+ timeCalcProperty.getKey() + "\"");
}
return defaultProperties.get(timeCalcProperty.getKey());
}
private boolean getBooleanProperty(TimeCalcProperty timeCalcProperty,
Boolean defaultValue) {
String key = timeCalcProperty.getKey();
if (!properties.containsKey(key)) {
return defaultValue;
}
return properties.get(key).equals("true");
}
public String getStringProperty(TimeCalcProperty timeCalcProperty) {
return getStringProperty(timeCalcProperty,
getDefaultStringValue(timeCalcProperty));
}
private String getStringProperty(TimeCalcProperty timeCalcProperty,
String defaultValue) {
String key = timeCalcProperty.getKey();
if (!properties.containsKey(key)) {
return defaultValue;
}
return (String) properties.get(key);
}
public int getIntegerProperty(TimeCalcProperty timeCalcProperty) {
return getIntegerProperty(timeCalcProperty,
Integer.valueOf(getDefaultStringValue(timeCalcProperty)));
}
private int getIntegerProperty(TimeCalcProperty timeCalcProperty,
int defaultValue) {
String key = timeCalcProperty.getKey();
if (!properties.containsKey(key)) {
return defaultValue;
}
return Integer.valueOf((String) properties.get(key));
}
private String getVisibilityProperty(TimeCalcProperty timeCalcProperty) {
return getStringProperty(timeCalcProperty,
Visibility.STRONGLY_COLORED.name());
}
private void setBooleanProperty(TimeCalcProperty timeCalcProperty,
Boolean value) {
String key = timeCalcProperty.getKey();
properties.replace(key, value.toString());
}
private void setStringProperty(TimeCalcProperty timeCalcProperty,
String value) {
String key = timeCalcProperty.getKey();
properties.replace(key, value);
}
private void setVisibilityProperty(TimeCalcProperty timeCalcProperty,
Visibility value) {
String key = timeCalcProperty.getKey();
properties.replace(key, value.name());
}
public void save(Properties properties, String profileName) {
properties.entrySet().stream().forEach(e
-> {
if (this.properties.containsKey(e.getKey())) {
this.properties
.replace(e.getKey(), e.getValue().toString());
} else {
this.properties
.put(e.getKey(), e.getValue().toString());
}
}
);
File file = getFile(profileName);
try {
this.properties.store(new FileOutputStream(file), null);
System.out.println("Saving to " + file + " was successful");
} catch (IOException e) {
e.printStackTrace();
System.out.println(
"Saving to " + file + " failed: " + e.getMessage());
}
Utils.writeTextToFile(FileConstants.TIME_CALC_CURRENT_PROFILE_TXT_FILE,
profileName);
}
private File getFile(String profileName) {
return profileName == null || profileName.isEmpty()
? FileConstants.FILE_WITHOUT_ANY_PROFILE
: new File(FileConstants.FILE_WITHOUT_ANY_PROFILE.getParentFile(),
"timecalc." + profileName + ".conf");
}
public void loadProfile(String profileName) {
File file = getFile(profileName);
if (!file.exists()) {
Utils.showNotification(
"There is no profile with name: " + profileName);
return;
}
try {
this.properties.load(new FileInputStream(file));
} catch (IOException e) {
System.err.println(e);
}
}
}

View File

@ -0,0 +1,195 @@
package org.nanoboot.utils.timecalc.app;
import lombok.Getter;
import javax.swing.JOptionPane;
import java.awt.Color;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
/**
* @author Robert Vokac
* @since 20.02.2024
*/
public enum TimeCalcProperty {
VISIBILITY_DEFAULT("visibility.default", "Default Visibility"),
VISIBILITY_SUPPORTED_COLORED("visibility.supported.colored",
"Visibility : Supported : Colored"),
//
CLOCK_VISIBLE("clock.visible", "Clock"),
CLOCK_HANDS_LONG_VISIBLE("clock.hands.long.visible", "Clock : Long Hands"),
CLOCK_HANDS_COLORED("clock.hands.colored", "Clock : Colored Hands"),
CLOCK_HANDS_HOUR_VISIBLE("clock.hands.hour.visible", "Clock : Hour hand"),
CLOCK_HANDS_MINUTE_VISIBLE("clock.hands.minute.visible",
"Clock : Minute hand"),
CLOCK_HANDS_SECOND_VISIBLE("clock.hands.second.visible",
"Clock : Second hand"),
CLOCK_HANDS_MILLISECOND_VISIBLE("clock.hands.millisecond.visible",
"Clock : Millisecond hand"),
CLOCK_BORDER_VISIBLE("clock.border.visible", "Clock : Border"),
CLOCK_BORDER_ONLY_HOURS("clock.border.only-hours",
"Clock : Border : Only hours"),
CLOCK_NUMBERS_VISIBLE("clock.numbers.visible", "Clock : Numbers"),
CLOCK_CIRCLE_VISIBLE("clock.circle.visible", "Clock : Circle"),
CLOCK_CIRCLE_STRONG_BORDER("clock.circle.strong-border",
"Clock : Circle : Strong border"),
CLOCK_CIRCLE_BORDER_COLOR("clock.circle.border-color",
"Clock : Circle : Border color",
Color.class),
CLOCK_CENTRE_CIRCLE_VISIBLE("clock.centre-circle.visible",
"Clock : Centre circle"),
CLOCK_CENTRE_CIRCLE_COLORED("clock.centre-circle.colored",
"Clock : Centre Circle is colored"),
CLOCK_PROGRESS_VISIBLE_ONLY_IF_MOUSE_MOVING_OVER(
"clock.progress.visible-only-if-mouse-moving-over",
"Clock : Progress visible only, if mouse moving over"),
CLOCK_DATE_VISIBLE_ONLY_IF_MOUSE_MOVING_OVER(
"clock.date.visible-only-if-mouse-moving-over",
"Clock : Date visible only, if mouse moving over"),
CLOCK_SMILEY_VISIBLE("clock.smiley.visible","Clock : Smiley : Visible"),
CLOCK_PERCENT_PROGRESS_VISIBLE("clock.percent-progress.visible","Clock : Percent progress : Visible"),
CLOCK_CIRCLE_PROGRESS_VISIBLE("clock.circle-progress.visible", "Clock : Circle Progress"),
CLOCK_HIDDEN("clock.hidden", "Clock : Hidden"),
//
BATTERY_WAVES_VISIBLE("battery.waves.visible", "Battery : Waves"),
BATTERY_CIRCLE_PROGRESS_VISIBLE("battery.circle-progress.visible",
"Battery : Circle Progress"),
BATTERY_PERCENT_PROGRESS_VISIBLE("battery.percent-progress.visible",
"Battery : Percent Progress"),
BATTERY_CHARGING_CHARACTER_VISIBLE("battery.charging-character.visible",
"Battery : Charging Character"),
BATTERY_NAME_VISIBLE("battery.name.visible", "Battery : Name"),
BATTERY_LABEL_VISIBLE("battery.label.visible", "Battery : Label"),
BATTERY_VISIBLE("battery.visible", "Battery"),
BATTERY_MINUTE_VISIBLE("battery.minute.visible", "Battery : Minute"),
BATTERY_HOUR_VISIBLE("battery.hour.visible", "Battery : Hour"),
BATTERY_DAY_VISIBLE("battery.day.visible", "Battery : Day"),
BATTERY_WEEK_VISIBLE("battery.week.visible", "Battery : Week"),
BATTERY_MONTH_VISIBLE("battery.month.visible", "Battery : Month"),
BATTERY_YEAR_VISIBLE("battery.year.visible", "Battery : Year"),
BATTERY_MINUTE_HIDDEN("battery.minute.hidden", "Battery : Minute : Hidden"),
BATTERY_HOUR_HIDDEN("battery.hour.hidden", "Battery : Hour : Hidden"),
BATTERY_DAY_HIDDEN("battery.day.hidden", "Battery : Day : Hidden"),
BATTERY_WEEK_HIDDEN("battery.week.hidden", "Battery : Week : Hidden"),
BATTERY_MONTH_HIDDEN("battery.month.hidden", "Battery : Month : Hidden"),
BATTERY_YEAR_HIDDEN("battery.year.hidden", "Battery : Year : Hidden"),
BATTERY_BLINKING_IF_CRITICAL_LOW("battery.blinking-if-critical-low",
"Battery : Blinking, if critical low"),
BATTERY_QUARTER_ICON_VISIBLE("battery.quarter-icon.visible", "Battery : Quarter icon"),
JOKES_VISIBLE("jokes.visible", "Jokes"),
COMMANDS_VISIBLE("commands.visible", "Commands"),
NOTIFICATIONS_VISIBLE("notifications.visible", "Notifications"),
SMILEYS_VISIBLE("smileys.visible", "Smileys"),
SMILEYS_VISIBLE_ONLY_IF_MOUSE_MOVING_OVER(
"smileys.visible-only-if-mouse-moving-over",
"Smileys : Visible only, if mouse moving over"),
SMILEYS_COLORED("smileys.colored", "Smileys : Colored"),
SQUARE_VISIBLE("square.visible", "Square"),
SQUARE_TYPE("square.type", "Square : Type"),
SQUARE_HIDDEN("square.hidden", "Square : Hidden"),
DOT_VISIBLE("dot.visible", "Dot"),
DOT_TYPE("dot.type", "Dot : Type"),
DOT_HIDDEN("dot.hidden", "Dot : Hidden"),
FUEL_VISIBLE("fuel.visible", "Fuel"),
FUEL_TYPE("fuel.type", "Fuel : Type"),
FUEL_HIDDEN("fuel.hidden", "Fuel : Hidden"),
ROTATION_VISIBLE("rotation.visible", "Rotation"),
ROTATION_TYPE("rotation.type", "Rotation : Type"),
ROTATION_HIDDEN("rotation.hidden", "Rotation : Hidden"),
FUEL_ICON_VISIBLE("fuel.icon.visible", "Fuel : Icon"),
CIRCLE_VISIBLE("circle.visible", "Circle"),
CIRCLE_TYPE("circle.type", "Circle : Type"),
CIRCLE_HIDDEN("circle.hidden", "Circle : Hidden"),
CIRCLE_INNER_CIRCLE_VISIBLE("circle.inner-circle.visible", "Circle : Inner circle"),
CIRCLE_OUTER_CIRCLE_ONLY_BORDER("circle.outer-circle.only-border", "Circle : Outer circle : Only border"),
//
BAR_VISIBLE("bar.visible", "Bar"),
BAR_TYPE("bar.type", "Bar : Type"),
BAR_HIDDEN("bar.hidden", "Bar : Hidden"),
BAR_HEIGHT("bar.height", "Bar : Height", Integer.class),
//
WATER_VISIBLE("water.visible", "Water"),
WATER_TYPE("water.type", "Water : Type"),
WATER_HIDDEN("water.hidden", "Water : Hidden"),
WATER_COLORED("water.colored", "Water : Colored"),
//
WALKING_HUMAN_VISIBLE("walking-human.visible", "Walking Human"),
WALKING_HUMAN_TYPE("walking-human.type", "Walking Human : Type"),
WALKING_HUMAN_HIDDEN("walking-human.hidden", "Walking Human : Hidden"),
SWING_VISIBLE("swing.visible", "Swing"),
SWING_TYPE("swing.type", "Swing : Type"),
SWING_HIDDEN("swing.hidden", "Swing : Hidden"),
SWING_QUARTER_ICON_VISIBLE("swing.quarter-icon.visible", "Swing: Quarter icon"),
LIFE_VISIBLE("life.visible", "Life"),
LIFE_TYPE("life.type", "Life : Type"),
LIFE_HIDDEN("life.hidden", "Life : Hidden"),
LIFE_BIRTH_DATE("life.birth-date", "Life : Birth date"),
MONEY_VISIBLE("money.visible", "Money"),
MONEY_TYPE("money.type", "Money : Type"),
MONEY_HIDDEN("money.hidden", "Money : Hidden"),
MONEY_PER_MONTH("money.per-month", "Money : Per month", Integer.class),
MONEY_CURRENCY("money.currency", "Money : Currency", String.class),
WEATHER_VISIBLE("weather.visible", "Weather"),
WEATHER_HIDDEN("weather.hidden", "Weather : Hidden"),
MAIN_WINDOW_CUSTOM_TITLE("main-window.custom-title","Main Window : Custom Title"),
PROFILE_NAME("profile.name", "Profile : Name"),
TEST_ENABLED("test.enabled", "Test : Enabled", Boolean.class),
TEST_CLOCK_CUSTOM_YEAR("test.clock.custom.year", "Test : Clock : Custom : Year", Integer.class),
TEST_CLOCK_CUSTOM_MONTH("test.clock.custom.month", "Test : Clock : Custom : Month", Integer.class),
TEST_CLOCK_CUSTOM_DAY("test.clock.custom.day", "Test : Clock : Custom : Day", Integer.class),
TEST_CLOCK_CUSTOM_HOUR("test.clock.custom.hour", "Test : Clock : Custom : Hour", Integer.class),
TEST_CLOCK_CUSTOM_MINUTE("test.clock.custom.minute", "Test : Clock : Custom : Minute", Integer.class),
TEST_CLOCK_CUSTOM_SECOND("test.clock.custom.second", "Test : Clock : Custom : Second", Integer.class),
TEST_CLOCK_CUSTOM_MILLISECOND("test.clock.custom.millisecond", "Test : Clock : Custom : Millisecond", Integer.class),
ACTIVITY_NEEDED_FLAGS("activity.needed-flags", "Activity : Needed flags", String.class),
SPEED("speed", "Speed", Integer.class),
SPEED_NEGATIVE("speed.negative", "Speed : Negative", Integer.class),
SPEED_FLOATING("speed.floating", "Speed : Floating"),
TYPE_VISIBLE("type.visible", "Type : Visible");
@Getter
private final String key;
@Getter
private final String description;
@Getter
private final Class clazz;
static {
Set<String> uniqueKeys = new HashSet<>();
for(TimeCalcProperty tcp:TimeCalcProperty.values()) {
if(uniqueKeys.contains(tcp.getKey())) {
String msg = "Fatal exception: TimeCalcProperty key must be unique: " + tcp.getKey();
JOptionPane.showMessageDialog(null, msg);
throw new TimeCalcException(msg);
} else {
uniqueKeys.add(tcp.getKey());
}
}
}
TimeCalcProperty(String key, String description, Class clazz) {
this.key = key;
this.description = description;
this.clazz = clazz;
}
TimeCalcProperty(String key, String description) {
this(key, description, Boolean.class);
}
public static TimeCalcProperty forKey(String key) {
Optional<TimeCalcProperty> timeCalcPropertyOptional
= Arrays.stream(values()).filter(t -> t.getKey().equals(key))
.findFirst();
if (timeCalcPropertyOptional.isPresent()) {
return timeCalcPropertyOptional.get();
} else {
TimeCalcException e
= new TimeCalcException("There is no key: " + key);
e.printStackTrace();
throw e;
}
}
}

View File

@ -0,0 +1,79 @@
package org.nanoboot.utils.timecalc.entity;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.nanoboot.utils.timecalc.utils.common.NumberFormats;
/**
* @author Robert Vokac
* @since 23.02.2024
*/
@Getter
@Setter
@ToString
@AllArgsConstructor
public class Activity implements Comparable<Activity> {
private static final String SUBJECT_FIELD_SEPARATOR = " : ";
private String id;
private int year;
private int month;
private int day;
private String name;
private String comment;
private String ticket;
private int spentHours;
private int spentMinutes;
private String flags;
private int sortkey;
public String createSubject() {
return ticket + SUBJECT_FIELD_SEPARATOR + name;
}
public String createTotalComment() {
return ticket + SUBJECT_FIELD_SEPARATOR + year + "-" + (month < 10 ? "0" : "") + month + "-" + (day < 10 ? "0" : "") + day
+ SUBJECT_FIELD_SEPARATOR + (
NumberFormats.FORMATTER_TWO_DECIMAL_PLACES.format(spentHours + spentMinutes / 60d)
+ "h") + SUBJECT_FIELD_SEPARATOR
+ comment;
}
public Set<String> flagsAsSet() {
Set<String> set = new HashSet<>();
for(String flag:flags.split(":")) {
if(flag.isEmpty()) {
//nothing to do
continue;
}
set.add(flag);
}
return set;
}
public void addFlag(String flag) {
Set<String> set = flagsAsSet();
set.add(flag);
this.flags = set.stream().collect(Collectors.joining(":"));
}
public void removeFlag(String flag) {
Set<String> set = flagsAsSet();
set.remove(flag);
this.flags = set.stream().collect(Collectors.joining(":"));
}
@Override
public int compareTo(Activity o) {
return Integer.valueOf(sortkey).compareTo(Integer.valueOf(o.sortkey));
}
public String getSpentTimeAsString() {
return (getSpentHours() < 10 ? "0" : "") + getSpentHours() + ":" + (getSpentMinutes() < 10 ? "0" : "") + getSpentMinutes();
}
}

View File

@ -0,0 +1,37 @@
package org.nanoboot.utils.timecalc.entity;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class ActivityForStats extends Activity {
private int todaySpentHours;
private int todaySpentMinutes;
private int todayRemainsHours;
private int todayRemainsMinutes;
public ActivityForStats(String id, int year, int month, int day,
String name,
String comment, String ticket, int spentHours, int spentMinutes,
String flags, int sortkey,
int todaySpentHours,
int todaySpentMinutes,
int todayRemainsHours,
int todayRemainsMinutes) {
super(id, year, month, day, name, comment, ticket, spentHours,
spentMinutes,
flags, sortkey);
this.todaySpentHours = todaySpentHours;
this.todaySpentMinutes = todaySpentMinutes;
this.todayRemainsHours = todayRemainsHours;
this.todayRemainsMinutes = todayRemainsMinutes;
}
public List<ActivityForStats> createList(List<Activity> list) {
return null;//todo
}
}

View File

@ -0,0 +1,230 @@
package org.nanoboot.utils.timecalc.entity;
import lombok.Getter;
import lombok.Setter;
import org.nanoboot.utils.timecalc.swing.progress.AnalogClock;
import org.nanoboot.utils.timecalc.utils.common.TTime;
import java.util.Calendar;
import java.util.Date;
/**
* @author pc00289
* @since 21.03.2024
*/
public class Progress {
private final double[] array = new double[9];
@Getter
@Setter
private int workDaysInMonth;
@Getter
@Setter
private boolean weekend;
public void set(WidgetType type, double value) {
array[type.getIndex()] = value > 1 ? 1 : (value < 0 ? 0 : value);
}
public static WidgetType getWidgetType(WidgetType type) {
if (type == WidgetType.PRESENTATION) {
long currentTime = new Date().getTime() / 1000l;
long l = currentTime % 35;
if (l >= 0 && l < 5) {
type = WidgetType.MINUTE;
}
if (l >= 5 && l < 10) {
type = WidgetType.HOUR;
}
if (l >= 10 && l < 15) {
type = WidgetType.DAY;
}
if (l >= 15 && l < 20) {
type = WidgetType.WEEK;
}
if (l >= 20 && l < 25) {
type = WidgetType.MONTH;
}
if (l >= 25 && l < 30) {
type = WidgetType.YEAR;
}
if (l >= 30 && l < 35) {
type = WidgetType.LIFE;
}
}
return type;
}
public double getDonePercent(WidgetType type) {
type = getWidgetType(type);
return array[type.getIndex()];
}
public static double getMinuteProgress(int secondNow, int millisecondNow) {
return millisecondNow / 60d / 1000d + secondNow / 60d;
}
public static double getHourProgress(TTime timeRemains, int secondsRemains,
int millisecondsRemains) {
if (secondsRemains < 0 || millisecondsRemains < 0
|| timeRemains.getHour() < 0 || timeRemains.getMinute() < 0) {
return 1;
}
double minutesRemainsD = timeRemains.getMinute();
double secondsRemainsD = secondsRemains;
double millisecondsRemainsD = millisecondsRemains;
minutesRemainsD = minutesRemainsD + secondsRemainsD / 60d;
minutesRemainsD
= minutesRemainsD + millisecondsRemainsD / 1000d / 60d;
if (secondsRemainsD > 0) {
minutesRemainsD = minutesRemainsD - 1d;
}
if (millisecondsRemainsD > 0) {
minutesRemainsD = minutesRemainsD - 1d / 1000d;
}
double hourProgress = 1 - ((minutesRemainsD % 60d) / 60d);
return hourProgress;
}
public static double getWeekProgress(int weekDayWhenMondayIsOne,
double done) {
if (done > 1) {
done = 1;
}
return weekDayWhenMondayIsOne == 0
|| weekDayWhenMondayIsOne == 6
? 100 : ((weekDayWhenMondayIsOne - 1) * 0.20 + done * 0.20);
}
public static double getMonthProgress(int weekDayWhenMondayIsOne,
int workDaysDone, int workDaysTotal, double done) {
if (done > 1) {
done = 1;
}
double result = weekDayWhenMondayIsOne == 6
|| weekDayWhenMondayIsOne == 7
? (double) workDaysDone / workDaysTotal
: (workDaysDone + done) / workDaysTotal;
// System.out.println("result=" + result);
return result;
}
public static double getYearProgress(double monthProgress, Integer year,
Integer month,
Integer day, Integer hour, Integer minute, Integer second,
Integer millisecond) {
double totalCountOfDaysInAYear = getTotalCountOfDaysInAYear(year);
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month - 1);
cal.set(Calendar.DAY_OF_MONTH, day);
cal.set(Calendar.HOUR, hour);
cal.set(Calendar.MINUTE, minute);
cal.set(Calendar.SECOND, second);
cal.set(Calendar.MILLISECOND, millisecond);
int daysInMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
if (month == 1) {
return (daysInMonth * monthProgress) / totalCountOfDaysInAYear;
} else {
cal.set(Calendar.MONTH, month - 2);
cal.set(Calendar.DAY_OF_MONTH,
cal.getActualMaximum(Calendar.DAY_OF_MONTH));
int totalDaysUntilLastDayOfLastMonth =
cal.get(Calendar.DAY_OF_YEAR);
cal.set(Calendar.MONTH, month - 1);
cal.set(Calendar.DAY_OF_MONTH, day);
return (totalDaysUntilLastDayOfLastMonth + (daysInMonth
* monthProgress))
/ totalCountOfDaysInAYear;
}
}
public static final int STARTED_WORKING_AGE = 26;
public static final int RETIREMENT_AGE = 65;
public static double getLifeProgress(Date birthDate, Date currentDate) {
if(birthDate == null) {
Calendar calTmp = Calendar.getInstance();
calTmp.set(Calendar.YEAR, 2000);
calTmp.set(Calendar.MONTH, 0);
calTmp.set(Calendar.DAY_OF_MONTH, 1);
}
Calendar birthDateCal = Calendar.getInstance();
Calendar currentDateCal = Calendar.getInstance();
Calendar birthDateStartedWorkingCal = Calendar.getInstance();
birthDateCal.setTime(birthDate);
currentDateCal.setTime(currentDate);
birthDateStartedWorkingCal.setTime(birthDate);
birthDateStartedWorkingCal.add(Calendar.YEAR, STARTED_WORKING_AGE);
Date birthDateStartedWorking = birthDateStartedWorkingCal.getTime();
if(currentDate.compareTo(birthDateStartedWorking) < 0) {
return 0d;
}
Calendar retirementDateCal = Calendar.getInstance();
retirementDateCal.setTime(birthDate);
retirementDateCal.add(Calendar.YEAR, RETIREMENT_AGE);
Date retirementDate = retirementDateCal.getTime();
long secondsForWork = retirementDate.getTime() - birthDateStartedWorking.getTime();
long alreadyWorked = currentDate.getTime() - birthDateStartedWorking.getTime();
return (double)alreadyWorked / (double)secondsForWork;
}
// public static double getYearProgress(Integer year, Integer month,
// Integer day, Integer hour, Integer minute, Integer second,
// Integer millisecond) {
// Calendar cal = Calendar.getInstance();
// cal.set(Calendar.YEAR, year);
// cal.set(Calendar.MONTH, month - 1);
// cal.set(Calendar.DAY_OF_MONTH, day);
// cal.set(Calendar.HOUR, hour);
// cal.set(Calendar.MINUTE, minute);
// cal.set(Calendar.SECOND, second);
// cal.set(Calendar.MILLISECOND, millisecond);
//
// double seconds = second + millisecond / 1000d;
// double minutes = minute + seconds / 60d;
// double hours = hour + minutes / 60d;
// double days = cal.get(Calendar.DAY_OF_YEAR) + hours / 24d;
// // System.out.println("millisecond=" + millisecond);
// // System.out.println("seconds=" + seconds);
// // System.out.println("minutes=" + minutes);
// // System.out.println("hours=" + hours);
// // System.out.println("days=" + days);
// // System.out.println("cal.get(Calendar.DAY_OF_YEAR)=" + cal.get(Calendar.DAY_OF_YEAR));
//
// double totalCountOfDaysInAYear = getTotalCountOfDaysInAYear(year);
// return days / totalCountOfDaysInAYear;
// }
private static double getTotalCountOfDaysInAYear(Integer year) {
boolean leapYear = isLeapYear(year);
double daysInYear = 365d;
if (leapYear) {
daysInYear++;
}
return daysInYear;
}
private static boolean isLeapYear(Integer year) {
return year % 4 == 0;
}
public static double getYearProgress(AnalogClock analogClock,
double monthProgress) {
return getYearProgress(monthProgress,
analogClock.yearProperty.getValue(),
analogClock.monthProperty.getValue(),
analogClock.dayProperty.getValue(),
analogClock.hourProperty.getValue(),
analogClock.minuteProperty.getValue(),
analogClock.secondProperty.getValue(),
analogClock.millisecondProperty.getValue()
);
}
}

View File

@ -0,0 +1,39 @@
package org.nanoboot.utils.timecalc.entity;
import org.nanoboot.utils.timecalc.utils.property.StringProperty;
/**
* @author Robert Vokac
* @since 23.02.2024
*/
public enum Visibility {
STRONGLY_COLORED, WEAKLY_COLORED, GRAY, NONE;
public static Visibility ofProperty(StringProperty stringProperty) {
return Visibility.valueOf(stringProperty.getValue());
}
public boolean isStronglyColored() {
return this == STRONGLY_COLORED;
}
public boolean isWeaklyColored() {
return this == WEAKLY_COLORED;
}
public boolean isColored() {
return isStronglyColored() || isWeaklyColored();
}
public boolean isGray() {
return this == GRAY;
}
public boolean isNone() {
return this == NONE;
}
public boolean isNotNone() {
return !isNone();
}
}

View File

@ -0,0 +1,21 @@
package org.nanoboot.utils.timecalc.entity;
import org.nanoboot.utils.timecalc.app.TimeCalcException;
/**
* @author pc00289
* @since 21.03.2024
*/
public enum WidgetType {
MINUTE, HOUR, DAY, WEEK, MONTH, YEAR, LIFE, PRESENTATION, PAUSE;
public int getIndex() {
int i = 0;
for(WidgetType wt:WidgetType.values()) {
if(wt == this) {
return i;
}
i++;
}
throw new TimeCalcException("This widget type is not supported: " + this);
}
}

View File

@ -0,0 +1,55 @@
package org.nanoboot.utils.timecalc.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import java.util.Calendar;
/**
* @author Robert Vokac
* @since 23.02.2024
*/
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class WorkingDay {
private static final String NODATA = "nodata";
public static String createId(Calendar cal) {
return createId(cal.get(Calendar.YEAR), cal.get((Calendar.MONTH)) + 1, cal.get(Calendar.DAY_OF_MONTH));
}
public static String createId(int year, int month, int day) {
return (year + "-" + (month < 10 ? "0" : "") + month + "-" + (day < 10 ? "0" : "") + day);
}
private String id;
private int year;
private int month;
private int day;
private int arrivalHour;
private int arrivalMinute;
private int overtimeHour;
private int overtimeMinute;
private int pauseStartHour;
private int pauseStartMinute;
private int workingTimeInMinutes;
private int pauseTimeInMinutes;
private String note;
private boolean timeOff;
private int forgetOvertime;
public boolean isThisDayTimeOff() {
return timeOff || this.note.equals(NODATA);
}
public double getArrivalAsDouble() {
return ((double)arrivalHour) + ((double)arrivalMinute / 60d);
}
}

View File

@ -0,0 +1,264 @@
package org.nanoboot.utils.timecalc.entity;
import lombok.Getter;
import lombok.Setter;
import org.nanoboot.utils.timecalc.app.TimeCalcException;
import org.nanoboot.utils.timecalc.swing.common.ArrivalChartData;
import org.nanoboot.utils.timecalc.utils.common.TTime;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
@Getter
@Setter
public class WorkingDayForStats extends WorkingDay {
private int departureHour;
private int departureMinute;
private int pauseEndHour;
private int pauseEndMinute;
private int dayOfWeek;
private int remainingOvertimeHours;
private int remainingOvertimeMinutes;
private double arrivalTimeMovingAverage7Days;
private double arrivalTimeMovingAverage14Days;
private double arrivalTimeMovingAverage28Days;
private double arrivalTimeMovingAverage56Days;
private final TTime arrival;
private final TTime overtime;
private final TTime work;
private final TTime pause;
private final TTime departure;
public static void fillStatisticsColumns(List<WorkingDayForStats> list) {
if (list.isEmpty()) {
//nothing to do
return;
}
Map<String, WorkingDayForStats> map = new HashMap<>();
Set<Integer> years = new HashSet<>();
list.forEach(w -> {
if (!years.isEmpty() && !years.contains(w.getYear())) {
throw new TimeCalcException(
"Cannot create statistics, if there are work days for more than one year.");
}
years.add(w.getYear());
map.put(w.getId(), w);
}
);
int year = years.stream().findFirst().orElseThrow(
() -> new TimeCalcException("Set years is empty."));
Calendar cal7DaysAgo = Calendar.getInstance();
Calendar cal14DaysAgo = Calendar.getInstance();
Calendar cal28DaysAgo = Calendar.getInstance();
Calendar cal56DaysAgo = Calendar.getInstance();
List<WorkingDayForStats> list7 = new ArrayList<>();
List<WorkingDayForStats> list14 = new ArrayList<>();
List<WorkingDayForStats> list28 = new ArrayList<>();
List<WorkingDayForStats> list56 = new ArrayList<>();
for (int month = 1; month <= 12; month++) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month - 1);
int dayMaximum = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
for (int day = 1; day <= dayMaximum; day++) {
String id = WorkingDay.createId(year, month, day);
if (!map.containsKey(id)) {
//nothing to do
continue;
}
cal.set(Calendar.DAY_OF_MONTH, day);
cal7DaysAgo.setTime(cal.getTime());
cal14DaysAgo.setTime(cal.getTime());
cal28DaysAgo.setTime(cal.getTime());
cal56DaysAgo.setTime(cal.getTime());
cal7DaysAgo.add(Calendar.DAY_OF_MONTH, -7);
cal14DaysAgo.add(Calendar.DAY_OF_MONTH, -14);
cal28DaysAgo.add(Calendar.DAY_OF_MONTH, -28);
cal56DaysAgo.add(Calendar.DAY_OF_MONTH, -56);
String id7 = WorkingDay.createId(cal7DaysAgo);
String id14 = WorkingDay.createId(cal14DaysAgo);
String id28 = WorkingDay.createId(cal28DaysAgo);
String id56 = WorkingDay.createId(cal56DaysAgo);
// System.out.println("id7=" + id7);
// System.out.println("id14=" + id14);
// System.out.println("id28=" + id28);
// System.out.println("id56=" + id56);
if (map.containsKey(id7)) {
list7.remove(map.get(id7));
}
if (map.containsKey(id14)) {
list14.remove(map.get(id14));
}
if (map.containsKey(id28)) {
list28.remove(map.get(id28));
}
if (map.containsKey(id56)) {
list56.remove(map.get(id56));
}
WorkingDayForStats wd = map.get(id);
if (!wd.isThisDayTimeOff()) {
Stream.of(list7, list14, list28, list56).forEach(l -> {
l.add(wd);
});
}
wd.setArrivalTimeMovingAverage7Days(list7.stream()
.map(WorkingDay::getArrivalAsDouble)
.mapToDouble(Double::doubleValue)
.average()
.orElse(0.0));
wd.setArrivalTimeMovingAverage14Days(list14.stream()
.map(WorkingDay::getArrivalAsDouble)
.mapToDouble(Double::doubleValue)
.average()
.orElse(0.0));
wd.setArrivalTimeMovingAverage28Days(list28.stream()
.map(WorkingDay::getArrivalAsDouble)
.mapToDouble(Double::doubleValue)
.average()
.orElse(0.0));
wd.setArrivalTimeMovingAverage56Days(list56.stream()
.map(WorkingDay::getArrivalAsDouble)
.mapToDouble(Double::doubleValue)
.average()
.orElse(0.0));
// System.out.println(
// WorkingDay.createId(cal) + " 1 :: " + list7.size());
// System.out.println(
// WorkingDay.createId(cal) + " 2 :: " + list14.size());
// System.out.println(
// WorkingDay.createId(cal) + " 3 :: " + list28.size());
// System.out.println(
// WorkingDay.createId(cal) + " 4 :: " + list56.size());
}
}
}
public static List<WorkingDayForStats> createList(List<WorkingDay> list) {
List<WorkingDayForStats> result = new ArrayList<>();
for (WorkingDay wd : list) {
WorkingDayForStats wdfs = new WorkingDayForStats(wd);
result.add(wdfs);
}
return result;
}
public static ArrivalChartData toArrivalChartData(
List<WorkingDayForStats> list, double target, String startDate, String endDate) {
list.remove(0);
list.remove(0);
list.remove(0);
list.remove(0);
list.remove(0);
list.remove(0);
list.remove(0);
while(list.get(list.size() - 1).isThisDayTimeOff()) {
list.remove(list.size() - 1);
}
String[] days = new String[list.size()];
double[] ma7 = new double[list.size()];
double[] ma14 = new double[list.size()];
double[] ma28 = new double[list.size()];
double[] ma56 = new double[list.size()];
double[] arrival = new double[list.size()];
ArrivalChartData acd = new ArrivalChartData();
acd.setDays(days);
acd.setArrival(arrival);
acd.setTarget(target);
acd.setMa7(ma7);
acd.setMa14(ma14);
acd.setMa28(ma28);
acd.setMa56(ma56);
if(startDate != null && !startDate.isEmpty()) {
acd.setStartDate(startDate);
}
if(endDate != null && !endDate.isEmpty()) {
acd.setEndDate(endDate);
}
for(int i = 0; i < list.size(); i++) {
WorkingDayForStats wdfs = list.get(i);
days[i] = wdfs.getId();
arrival[i] = (wdfs.isThisDayTimeOff() ? wdfs.getArrivalTimeMovingAverage7Days() : wdfs.getArrivalAsDouble()) - target;
ma7[i] = wdfs.getArrivalTimeMovingAverage7Days() - target;
ma14[i] = wdfs.getArrivalTimeMovingAverage14Days() - target;
ma28[i] = wdfs.getArrivalTimeMovingAverage28Days() - target;
ma56[i] = wdfs.getArrivalTimeMovingAverage56Days() - target;
}
return acd;
}
public WorkingDayForStats(WorkingDay wd) {
this(wd.getId(),
wd.getYear(),
wd.getMonth(),
wd.getDay(),
wd.getArrivalHour(),
wd.getArrivalMinute(),
wd.getOvertimeHour(),
wd.getOvertimeMinute(),
wd.getPauseStartHour(),
wd.getPauseStartMinute(),
wd.getWorkingTimeInMinutes(),
wd.getPauseTimeInMinutes(),
wd.getNote(),
wd.isTimeOff(),
wd.getForgetOvertime());
}
public WorkingDayForStats(String id, int year, int month, int day,
int arrivalHour, int arrivalMinute, int overtimeHour,
int overtimeMinute, int pauseStartHour, int pauseStartMinute,
int workingTimeInMinutes,
int pauseTimeInMinutes, String note, boolean timeOff, int forgetOvertime) {
super(id, year, month, day, arrivalHour, arrivalMinute, overtimeHour,
overtimeMinute, pauseStartHour, pauseStartMinute, workingTimeInMinutes, pauseTimeInMinutes, note,
timeOff, forgetOvertime);
this.arrival = this.isThisDayTimeOff() ? null :
new TTime(arrivalHour, arrivalMinute);
this.overtime = this.isThisDayTimeOff() ? null :
new TTime(overtimeHour, overtimeMinute);
this.work = this.isThisDayTimeOff() ? null :
TTime.ofMinutes(workingTimeInMinutes);
this.pause = this.isThisDayTimeOff() ? null :
TTime.ofMinutes(pauseTimeInMinutes);
this.departure = this.isThisDayTimeOff() ? null :
this.arrival.add(work).add(pause).add(overtime);
this.departureHour = this.isThisDayTimeOff() ? -1 : departure.getHour();
this.departureMinute =
this.isThisDayTimeOff() ? -1 : departure.getMinute();
TTime pauseStart = new TTime(this.getPauseStartHour(), this.getPauseStartMinute());
TTime pauseEnd = null;
if(pause == null) {
pauseEnd = pauseStart.cloneInstance();
} else {
pauseEnd = pauseStart.add(pause);
}
this.pauseEndHour = pauseEnd.getHour();
this.pauseEndMinute = pauseEnd.getMinute();
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month - 1);
cal.set(Calendar.DAY_OF_MONTH, day);
this.dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
this.dayOfWeek = dayOfWeek == 1 ? 7 : dayOfWeek - 1;
}
public String getDayOfWeekAsString() {
return LocalDate.of(getYear(), getMonth(), getDay()).getDayOfWeek()
.toString();
}
}

View File

@ -0,0 +1,71 @@
package org.nanoboot.utils.timecalc.persistence.api;
import org.nanoboot.utils.timecalc.app.TimeCalcConfiguration;
import org.nanoboot.utils.timecalc.entity.Activity;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author Robert Vokac
* @since 23.02.2024
*/
public interface ActivityRepositoryApi {
default double getProgressForDay(int year, int month, int day, TimeCalcConfiguration timeCalcConfiguration) {
List<Activity> list = list(year, month, day);
double done = 0d;
double todo = 8d;
String neededFlags = timeCalcConfiguration.activityNeededFlagsProperty.getValue();
System.out.println("neededFlags=" + neededFlags);
neededFlags.replace(",", ":");
String[] neededFlagsArray = neededFlags.split(":");
Set<String> neededFlagsSet = Arrays.stream(neededFlagsArray).filter(f -> !f.isEmpty()).collect(
Collectors.toSet());
loopName:
for(Activity a:list) {
Set<String> flags = a.flagsAsSet();
if(!neededFlagsSet.isEmpty()) {
for(String f:neededFlagsSet) {
if(!flags.contains(f)) {
continue loopName;
}
}
}
double now = a.getSpentHours() + a.getSpentMinutes() / 60d;
done = done + now;
todo = todo - now;
}
double progress = done / 8d;
return progress;
}
void create(Activity activity);
List<Activity> list(int year, int month, int day);
List<Activity> list(String ticket);
void update(Activity activity);
Activity read(String id);
boolean delete(String id);
List<String> getYears();
void putToClipboard(Activity activity);
Activity getFromClipboard();
default int getSortkeySpace() {
return 1000;
}
int getNextSortkey(int year, int month, int day);
}

View File

@ -0,0 +1,30 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.utils.timecalc.persistence.api;
import java.sql.Connection;
/**
*
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public interface ConnectionFactory {
Connection createConnection() throws ClassNotFoundException;
}

View File

@ -0,0 +1,13 @@
package org.nanoboot.utils.timecalc.persistence.api;
/**
* @author Robert Vokac
* @since 23.02.2024
*/
public interface VersionRepositoryApi {
int read();
void update(int newVersion);
}

View File

@ -0,0 +1,50 @@
package org.nanoboot.utils.timecalc.persistence.api;
import java.util.Calendar;
import org.nanoboot.utils.timecalc.app.TimeCalcException;
import org.nanoboot.utils.timecalc.entity.WorkingDay;
import org.nanoboot.utils.timecalc.utils.common.Utils;
import java.util.List;
/**
* @author Robert Vokac
* @since 23.02.2024
*/
public interface WorkingDayRepositoryApi {
void create(WorkingDay workingDay);
default List<WorkingDay> list(int year, int month) {
return list(year, month, 0);
}
List<WorkingDay> list(int year, int month, int day);
void update(WorkingDay workingDay);
WorkingDay read(int year, int month, int day);
default WorkingDay read(Calendar cal) {
return read(
cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH) + 1,
cal.get(Calendar.DAY_OF_MONTH)
);
}
List<String> getYears();
void delete(int year, int month, int day);
default void delete(WorkingDay wd) {
delete(wd.getId());
}
default void delete(String id) {
String[] array = id.split("-");
if(array.length != 3) {
TimeCalcException e = new TimeCalcException("Invalid date: " + id);
Utils.showNotification(new TimeCalcException("Invalid date: " + id));
throw e;
}
delete(Integer.parseInt(array[0]),Integer.parseInt(array[1]),Integer.parseInt(array[2]));
}
int getTotalOvertimeForDayInMinutes(int year, int month, int day);
}

View File

@ -0,0 +1,377 @@
package org.nanoboot.utils.timecalc.persistence.impl.sqlite;
import org.nanoboot.utils.timecalc.app.TimeCalcException;
import org.nanoboot.utils.timecalc.entity.Activity;
import org.nanoboot.utils.timecalc.persistence.api.ActivityRepositoryApi;
import org.nanoboot.utils.timecalc.utils.common.Utils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.OptionalInt;
/**
* @author Robert Vokac
* @since 23.02.2024
*/
public class ActivityRepositorySQLiteImpl implements ActivityRepositoryApi {
private final SqliteConnectionFactory sqliteConnectionFactory;
public ActivityRepositorySQLiteImpl(SqliteConnectionFactory sqliteConnectionFactory) {
this.sqliteConnectionFactory = sqliteConnectionFactory;
}
private Activity activityInClipboard = null;
@Override
public void create(Activity activity) {
StringBuilder sb = new StringBuilder();
sb
.append("INSERT INTO ")
.append(ActivityTable.TABLE_NAME)
.append(" VALUES (?,?,?,?,?, ?,?,?,?,? ,?)");
String sql = sb.toString();
try (
Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
int i = 0;
stmt.setString(++i, activity.getId());
stmt.setInt(++i, activity.getYear());
stmt.setInt(++i, activity.getMonth());
stmt.setInt(++i, activity.getDay());
//
stmt.setString(++i, activity.getName());
stmt.setString(++i, activity.getComment());
stmt.setString(++i, activity.getTicket());
stmt.setInt(++i, activity.getSpentHours());
stmt.setInt(++i, activity.getSpentMinutes());
stmt.setString(++i, activity.getFlags());
stmt.setInt(++i, activity.getSortkey());
//
stmt.execute();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
throw new TimeCalcException(ex);
}
}
@Override
public boolean delete(String id) {
System.out.println("Going to delete: " + id);
Activity activityToBeDeleted = read(id);
if(!Utils.askYesNo(null, "Do you really want to delete this activity? " + read(id), "Deletion of activity")) {
return false;
}
StringBuilder sb = new StringBuilder();
sb
.append("DELETE FROM ")
.append(ActivityTable.TABLE_NAME)
.append(" WHERE ").append(
ActivityTable.ID).append("=?");
String sql = sb.toString();
//System.err.println(sql);
try (
Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
int i = 0;
stmt.setString(++i, id);
int numberOfUpdatedRows = stmt.executeUpdate();
//System.out.println("numberOfUpdatedRows=" + numberOfUpdatedRows);
} catch (SQLException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
throw new TimeCalcException(ex);
}
return true;
}
@Override
public List<Activity> list(int year, int month, int day) {
List<Activity> result = new ArrayList<>();
StringBuilder sb = new StringBuilder();
sb
.append("SELECT * FROM ")
.append(ActivityTable.TABLE_NAME)
.append(" WHERE ")
.append(ActivityTable.YEAR).append("=? AND ")
.append(ActivityTable.MONTH).append("=? AND ")
.append(ActivityTable.DAY).append("=? ");
String sql = sb.toString();
int i = 0;
ResultSet rs = null;
try (
Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
stmt.setInt(++i, year);
stmt.setInt(++i, month);
stmt.setInt(++i, day);
rs = stmt.executeQuery();
while (rs.next()) {
result.add(extractActivityFromResultSet(rs));
}
} catch (SQLException | ClassNotFoundException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} finally {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
throw new RuntimeException(ex);
}
}
return result;
//
}
@Override
public List<Activity> list(String ticket) {
List<Activity> result = new ArrayList<>();
StringBuilder sb = new StringBuilder();
sb
.append("SELECT * FROM ")
.append(ActivityTable.TABLE_NAME)
.append(" WHERE ")
.append(ActivityTable.TICKET).append("=? ");
String sql = sb.toString();
int i = 0;
ResultSet rs = null;
try (
Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
stmt.setString(++i, ticket);
rs = stmt.executeQuery();
while (rs.next()) {
result.add(extractActivityFromResultSet(rs));
}
} catch (SQLException | ClassNotFoundException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} finally {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
throw new RuntimeException(ex);
}
}
return result;
}
@Override
public void update(Activity activity) {
System.out.println("Going to update: " + activity.toString());
StringBuilder sb = new StringBuilder();
sb
.append("UPDATE ")
.append(ActivityTable.TABLE_NAME)
.append(" SET ")
.append(ActivityTable.NAME).append("=?, ")
.append(ActivityTable.COMMENT).append("=?, ")
.append(ActivityTable.TICKET).append("=?, ")
.append(ActivityTable.SPENT_HOURS).append("=?, ")
.append(ActivityTable.SPENT_MINUTES).append("=?, ")
.append(ActivityTable.FLAGS).append("=?, ")
.append(ActivityTable.SORTKEY).append("=? ")
.append(" WHERE ").append(
ActivityTable.ID).append("=?");
String sql = sb.toString();
//System.err.println(sql);
try (
Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
int i = 0;
stmt.setString(++i, activity.getName());
stmt.setString(++i, activity.getComment());
stmt.setString(++i, activity.getTicket());
stmt.setInt(++i, activity.getSpentHours());
stmt.setInt(++i, activity.getSpentMinutes());
stmt.setString(++i, activity.getFlags());
stmt.setInt(++i, activity.getSortkey());
stmt.setString(++i, activity.getId());
int numberOfUpdatedRows = stmt.executeUpdate();
//System.out.println("numberOfUpdatedRows=" + numberOfUpdatedRows);
} catch (SQLException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
throw new TimeCalcException(ex);
}
}
@Override
public Activity read(String id) {
List<Activity> result = new ArrayList<>();
StringBuilder sb = new StringBuilder();
sb
.append("SELECT * FROM ")
.append(ActivityTable.TABLE_NAME)
.append(" WHERE ")
.append(ActivityTable.ID).append("=? ");
String sql = sb.toString();
int i = 0;
ResultSet rs = null;
try (
Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
stmt.setString(++i, id);
rs = stmt.executeQuery();
while (rs.next()) {
result.add(extractActivityFromResultSet(rs));
}
} catch (SQLException | ClassNotFoundException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} finally {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
throw new RuntimeException(ex);
}
}
return result.stream().findFirst().orElse(null);
}
private Activity extractActivityFromResultSet(final ResultSet rs) throws SQLException {
return new Activity(
rs.getString(ActivityTable.ID),
rs.getInt(ActivityTable.YEAR),
rs.getInt(ActivityTable.MONTH),
rs.getInt(ActivityTable.DAY),
rs.getString(ActivityTable.NAME),
rs.getString(ActivityTable.COMMENT),
rs.getString(ActivityTable.TICKET),
rs.getInt(ActivityTable.SPENT_HOURS),
rs.getInt(ActivityTable.SPENT_MINUTES),
rs.getString(ActivityTable.FLAGS),
rs.getInt(ActivityTable.SORTKEY)
);
}
@Override
public List<String> getYears() {
List<String> result = new ArrayList<>();
StringBuilder sb = new StringBuilder();
sb
.append("SELECT distinct ").append(ActivityTable.YEAR). append(" FROM ")
.append(ActivityTable.TABLE_NAME);
String sql = sb.toString();
int i = 0;
ResultSet rs = null;
try (
Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
rs = stmt.executeQuery();
while (rs.next()) {
result.add(rs.getString(ActivityTable.YEAR));
}
} catch (SQLException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
System.out.println(ex.getMessage());
throw new RuntimeException(ex);
} finally {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
throw new RuntimeException(ex);
}
}
return result;
}
@Override
public void putToClipboard(Activity activity) {
this.activityInClipboard = activity;
}
@Override
public Activity getFromClipboard() {
if(this.activityInClipboard == null) {
return null;
}
Activity a = new Activity(
null,
2000, 1,1,
activityInClipboard.getName(),
activityInClipboard.getComment(),
activityInClipboard.getTicket(),
0,0, "", 1);
return activityInClipboard;
}
@Override
public int getNextSortkey(int year, int month, int day) {
OptionalInt optional =
list(year, month, day).stream().map(Activity::getSortkey)
.mapToInt(e -> e).max();
int sortkeySpace = getSortkeySpace();
if (optional.isPresent()) {
System.out.println("getLargestSortkey=" +optional.getAsInt());
if(optional.getAsInt() >= (Integer.MAX_VALUE - sortkeySpace - 1)) {
throw new TimeCalcException("Fatal exception. Cannot get new sort key, because it would exceed the Integer max value.");
}
int result = optional.getAsInt() + sortkeySpace;
if(result % sortkeySpace != 0) {
while(result % sortkeySpace != 0) {
result++;
}
}
return result;
} else {
return sortkeySpace;
}
}
public int getSortkeySpace() {
return 1000;
}
}

View File

@ -0,0 +1,46 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.utils.timecalc.persistence.impl.sqlite;
/**
*
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
class ActivityTable {
public static final String TABLE_NAME = "ACTIVITY";
public static final String ID = "ID";
public static final String YEAR = "YEAR";
public static final String MONTH = "MONTH";
public static final String DAY = "DAY";
public static final String NAME = "NAME";
public static final String COMMENT = "COMMENT";
public static final String TICKET = "TICKET";
public static final String SPENT_HOURS = "SPENT_HOURS";
public static final String SPENT_MINUTES = "SPENT_MINUTES";
public static final String FLAGS = "FLAGS";
public static final String SORTKEY = "SORTKEY";
private ActivityTable() {
//Not meant to be instantiated.
}
}

View File

@ -0,0 +1,91 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.utils.timecalc.persistence.impl.sqlite;
import org.nanoboot.utils.timecalc.persistence.api.ConnectionFactory;
import org.nanoboot.utils.timecalc.utils.common.FileConstants;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.nanoboot.utils.timecalc.app.TimeCalcException;
/**
*
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public class SqliteConnectionFactory implements ConnectionFactory {
private final String jdbcUrl;
private static String createJdbcUrl(String directoryWhereSqliteFileIs) {
return "jdbc:sqlite:" + directoryWhereSqliteFileIs + "/" + "time-calc.sqlite3?foreign_keys=on;";
}
public SqliteConnectionFactory() {
this(FileConstants.TC_DIRECTORY.getName());
}
private SqliteConnectionFactory(String directoryWhereSqliteFileIs) {
this.jdbcUrl = createJdbcUrl(directoryWhereSqliteFileIs);
}
public Connection createConnection() throws ClassNotFoundException {
try {
Class.forName("org.sqlite.JDBC");
Connection conn = DriverManager.getConnection(jdbcUrl);
return conn;
} catch (SQLException ex) {
if (true) {
throw new RuntimeException(ex);
}
System.err.println(ex.getMessage());
return null;
}
}
public void runSQL(String sql) {
String[] array = sql.split(";");
for (String s : array) {
if (s.trim().isEmpty()) {
continue;
}
System.err.println("Going to run this SQL \"" + s + "\"");
try (
Connection connection = createConnection(); PreparedStatement stmt = connection.prepareStatement(s);) {
System.err.println(stmt.toString());
stmt.execute();
} catch (SQLException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
throw new TimeCalcException(ex);
}
}
}
}

View File

@ -0,0 +1,83 @@
package org.nanoboot.utils.timecalc.persistence.impl.sqlite;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.nanoboot.utils.timecalc.app.TimeCalcException;
import org.nanoboot.utils.timecalc.persistence.api.VersionRepositoryApi;
/**
* @author Robert Vokac
* @since 23.02.2024
*/
public class VersionRepositorySQLiteImpl implements VersionRepositoryApi {
private final SqliteConnectionFactory sqliteConnectionFactory;
public VersionRepositorySQLiteImpl(SqliteConnectionFactory sqliteConnectionFactory) {
this.sqliteConnectionFactory = sqliteConnectionFactory;
}
@Override
public int read() {
StringBuilder sb = new StringBuilder();
sb
.append("SELECT * FROM ")
.append(VersionTable.TABLE_NAME);
String sql = sb.toString();
// System.err.println(sql);
ResultSet rs = null;
try (
Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
System.err.println(stmt.toString());
rs = stmt.executeQuery();
while (rs.next()) {
return rs.getInt(VersionTable.VALUE);
}
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
} finally {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException ex) {
ex.printStackTrace();
}
}
throw new TimeCalcException("Version was not found in database.");
}
@Override
public void update(int newVersion) {
StringBuilder sb = new StringBuilder();
sb
.append("UPDATE ")
.append(VersionTable.TABLE_NAME)
.append(" SET ")
.append(VersionTable.VALUE).append("=").append(newVersion);
String sql = sb.toString();
//System.err.println(sql);
try (
Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
int numberOfUpdatedRows = stmt.executeUpdate();
System.out.println("numberOfUpdatedRows=" + numberOfUpdatedRows);
} catch (SQLException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
}
}

View File

@ -0,0 +1,35 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.utils.timecalc.persistence.impl.sqlite;
/**
*
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public class VersionTable {
public static final String TABLE_NAME = "VERSION";
public static final String VALUE = "VALUE";
private VersionTable() {
//Not meant to be instantiated.
}
}

View File

@ -0,0 +1,342 @@
package org.nanoboot.utils.timecalc.persistence.impl.sqlite;
import org.nanoboot.utils.timecalc.app.Main;
import org.nanoboot.utils.timecalc.app.TimeCalcException;
import org.nanoboot.utils.timecalc.entity.WorkingDay;
import org.nanoboot.utils.timecalc.persistence.api.WorkingDayRepositoryApi;
import org.nanoboot.utils.timecalc.utils.common.Utils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* @author Robert Vokac
* @since 23.02.2024
*/
public class WorkingDayRepositorySQLiteImpl implements WorkingDayRepositoryApi {
private final SqliteConnectionFactory sqliteConnectionFactory;
public WorkingDayRepositorySQLiteImpl(SqliteConnectionFactory sqliteConnectionFactory) {
this.sqliteConnectionFactory = sqliteConnectionFactory;
}
@Override
public void create(WorkingDay workingDay) {
System.out.println("Going to create: " + workingDay.toString());
if(Main.ONLY_ACTIVITIES_WINDOW_IS_ALLOWED || !Utils.askYesNo(null, "Do you want to create new Working Day? " + workingDay, "Creation of new Working Day")) {
return;
}
StringBuilder sb = new StringBuilder();
sb
.append("INSERT INTO ")
.append(WorkingDayTable.TABLE_NAME)
.append(" VALUES (?,?,?,?, ?,?,?,?, ?,?,?,?,?, ?,?)");
String sql = sb.toString();
try (
Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
int i = 0;
stmt.setString(++i, workingDay.getId());
stmt.setInt(++i, workingDay.getYear());
stmt.setInt(++i, workingDay.getMonth());
stmt.setInt(++i, workingDay.getDay());
//
stmt.setInt(++i, workingDay.getArrivalHour());
stmt.setInt(++i, workingDay.getArrivalMinute());
stmt.setInt(++i, workingDay.getOvertimeHour());
stmt.setInt(++i, workingDay.getOvertimeMinute());
stmt.setInt(++i, workingDay.getPauseStartHour());
stmt.setInt(++i, workingDay.getPauseStartMinute());
//
stmt.setInt(++i, workingDay.getWorkingTimeInMinutes());
stmt.setInt(++i, workingDay.getPauseTimeInMinutes());
stmt.setString(++i, workingDay.getNote());
stmt.setInt(++i, workingDay.isTimeOff() ? 1 : 0);
stmt.setInt(++i, workingDay.getForgetOvertime());
//
stmt.execute();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
throw new TimeCalcException(ex);
}
}
@Override
public List<WorkingDay> list(int year, int month, int day) {
List<WorkingDay> result = new ArrayList<>();
StringBuilder sb = new StringBuilder();
sb
.append("SELECT * FROM ")
.append(WorkingDayTable.TABLE_NAME)
.append(" WHERE ")
.append(WorkingDayTable.YEAR).append("=? AND ")
.append(WorkingDayTable.MONTH).append("=? ");
if (day != 0) {
sb.append(" AND ").append(WorkingDayTable.DAY).append("=? ");
}
String sql = sb.toString();
int i = 0;
ResultSet rs = null;
try (
Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
//System.err.println(stmt.toString());
stmt.setInt(++i, year);
stmt.setInt(++i, month);
if (day != 0) {
stmt.setInt(++i, day);
}
rs = stmt.executeQuery();
while (rs.next()) {
result.add(extractWorkingDayFromResultSet(rs));
}
} catch (SQLException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
System.out.println(ex.getMessage());
throw new RuntimeException(ex);
} finally {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
throw new RuntimeException(ex);
}
}
return result;
//
}
@Override
public void update(WorkingDay workingDay) {
List<WorkingDay> list =
list(workingDay.getYear(), workingDay.getMonth(),
workingDay.getDay());
if(list.isEmpty()) {
create(workingDay);
return;
}
System.out.println("Going to update: " + workingDay.toString());
if(list.get(0).toString().equals(workingDay.toString())) {
System.out.println("Nothing to update.");
return;
}
if(Main.ONLY_ACTIVITIES_WINDOW_IS_ALLOWED || !Utils.askYesNo(null, "Do you want to update this Working Day? " + workingDay, "Update of Working Day")) {
return;
}
StringBuilder sb = new StringBuilder();
sb
.append("UPDATE ")
.append(WorkingDayTable.TABLE_NAME)
.append(" SET ")
.append(WorkingDayTable.ARRIVAL_HOUR).append("=?, ")
.append(WorkingDayTable.ARRIVAL_MINUTE).append("=?, ")
.append(WorkingDayTable.OVERTIME_HOUR).append("=?, ")
.append(WorkingDayTable.OVERTIME_MINUTE).append("=?, ")
.append(WorkingDayTable.PAUSE_START_HOUR).append("=?, ")
.append(WorkingDayTable.PAUSE_START_MINUTE).append("=?, ")
.append(WorkingDayTable.WORKING_TIME_IN_MINUTES).append("=?, ")
.append(WorkingDayTable.PAUSE_TIME_IN_MINUTES).append("=?, ")
.append(WorkingDayTable.NOTE).append("=?, ")
.append(WorkingDayTable.TIME_OFF).append("=?, ")
.append(WorkingDayTable.FORGET_OVERTIME).append("=? ")
.append(" WHERE ").append(
WorkingDayTable.ID).append("=?");
String sql = sb.toString();
//System.err.println(sql);
try (
Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
int i = 0;
stmt.setInt(++i, workingDay.getArrivalHour());
stmt.setInt(++i, workingDay.getArrivalMinute());
stmt.setInt(++i, workingDay.getOvertimeHour());
stmt.setInt(++i, workingDay.getOvertimeMinute());
stmt.setInt(++i, workingDay.getPauseStartHour());
stmt.setInt(++i, workingDay.getPauseStartMinute());
//
stmt.setInt(++i, workingDay.getWorkingTimeInMinutes());
stmt.setInt(++i, workingDay.getPauseTimeInMinutes());
stmt.setString(++i, workingDay.getNote());
stmt.setInt(++i, workingDay.isTimeOff() ? 1 : 0);
stmt.setInt(++i, workingDay.getForgetOvertime());
stmt.setString(++i, workingDay.getId());
int numberOfUpdatedRows = stmt.executeUpdate();
//System.out.println("numberOfUpdatedRows=" + numberOfUpdatedRows);
} catch (SQLException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
throw new TimeCalcException(ex);
}
}
@Override
public WorkingDay read(int year, int month, int day) {
List<WorkingDay> list = list(year, month, day);
return list.isEmpty() ? null : list.get(0);
}
private WorkingDay extractWorkingDayFromResultSet(final ResultSet rs) throws SQLException {
return new WorkingDay(
rs.getString(WorkingDayTable.ID),
rs.getInt(WorkingDayTable.YEAR),
rs.getInt(WorkingDayTable.MONTH),
rs.getInt(WorkingDayTable.DAY),
rs.getInt(WorkingDayTable.ARRIVAL_HOUR),
rs.getInt(WorkingDayTable.ARRIVAL_MINUTE),
rs.getInt(WorkingDayTable.OVERTIME_HOUR),
rs.getInt(WorkingDayTable.OVERTIME_MINUTE),
rs.getInt(WorkingDayTable.PAUSE_START_HOUR),
rs.getInt(WorkingDayTable.PAUSE_START_MINUTE),
rs.getInt(WorkingDayTable.WORKING_TIME_IN_MINUTES),
rs.getInt(WorkingDayTable.PAUSE_TIME_IN_MINUTES),
rs.getString(WorkingDayTable.NOTE),
rs.getInt(WorkingDayTable.TIME_OFF) != 0,
rs.getInt(WorkingDayTable.FORGET_OVERTIME)
);
}
@Override
public List<String> getYears() {
List<String> result = new ArrayList<>();
StringBuilder sb = new StringBuilder();
sb
.append("SELECT distinct ").append(WorkingDayTable.YEAR). append(" FROM ")
.append(WorkingDayTable.TABLE_NAME);
String sql = sb.toString();
int i = 0;
ResultSet rs = null;
try (
Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
rs = stmt.executeQuery();
while (rs.next()) {
result.add(rs.getString(WorkingDayTable.YEAR));
}
} catch (SQLException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
System.out.println(ex.getMessage());
throw new RuntimeException(ex);
} finally {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
throw new RuntimeException(ex);
}
}
return result;
}
@Override
public void delete(int year, int month, int day) {
StringBuilder sb = new StringBuilder();
sb
.append("DELETE ").append(" FROM ")
.append(WorkingDayTable.TABLE_NAME);
sb.append(" WHERE ");
sb.append(WorkingDayTable.YEAR).append("=? AND ");
sb.append(WorkingDayTable.MONTH).append("=? AND ");
;
sb.append(WorkingDayTable.DAY).append("=? ");
;
String sql = sb.toString();
int i = 0;
try (
Connection connection = sqliteConnectionFactory
.createConnection();
PreparedStatement stmt = connection.prepareStatement(sql);) {
stmt.setInt(++i, year);
stmt.setInt(++i, month);
stmt.setInt(++i, day);
stmt.execute();
} catch (SQLException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
System.out.println(ex.getMessage());
throw new RuntimeException(ex);
}
}
@Override
public int getTotalOvertimeForDayInMinutes(int year, int month, int day) {
StringBuilder sb = new StringBuilder();
sb
.append("SELECT (sum(OVERTIME_HOUR)*60 + sum(OVERTIME_MINUTE) - sum(FORGET_OVERTIME)) as total_overtime FROM ")
.append(WorkingDayTable.TABLE_NAME)
.append(" WHERE ")
.append(WorkingDayTable.YEAR).append(" * 10000 + ")
.append(WorkingDayTable.MONTH).append("* 100 + ")
.append(WorkingDayTable.DAY).append(" <= ? ");
String sql = sb.toString();
System.out.println(sql);
int i = 0;
ResultSet rs = null;
try (
Connection connection = sqliteConnectionFactory.createConnection(); PreparedStatement stmt = connection.prepareStatement(sql);) {
//System.err.println(stmt.toString());
stmt.setInt(++i, year * 10000 + month * 100 + day);
rs = stmt.executeQuery();
System.out.println(stmt);
while (rs.next()) {
return rs.getInt("total_overtime");
}
} catch (SQLException e) {
System.out.println(e.getMessage());
throw new RuntimeException(e);
} catch (ClassNotFoundException ex) {
System.out.println(ex.getMessage());
throw new RuntimeException(ex);
} finally {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
throw new RuntimeException(ex);
}
}
throw new IllegalStateException();
}
}

View File

@ -0,0 +1,50 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// bit-inspector: Tool detecting bit rots in files.
// Copyright (C) 2023-2023 the original author or authors.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2
// of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.utils.timecalc.persistence.impl.sqlite;
/**
*
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
*/
public class WorkingDayTable {
public static final String TABLE_NAME = "WORKING_DAY";
public static final String ID = "ID";
public static final String YEAR = "YEAR";
public static final String MONTH = "MONTH";
public static final String DAY = "DAY";
public static final String ARRIVAL_HOUR = "ARRIVAL_HOUR";
public static final String ARRIVAL_MINUTE = "ARRIVAL_MINUTE";
public static final String OVERTIME_HOUR = "OVERTIME_HOUR";
public static final String OVERTIME_MINUTE = "OVERTIME_MINUTE";
public static final String PAUSE_START_HOUR = "PAUSE_START_HOUR";
public static final String PAUSE_START_MINUTE = "PAUSE_START_MINUTE";
public static final String WORKING_TIME_IN_MINUTES = "WORKING_TIME_IN_MINUTES";
public static final String PAUSE_TIME_IN_MINUTES = "PAUSE_TIME_IN_MINUTES";
public static final String NOTE = "NOTE";
public static final String TIME_OFF = "TIME_OFF";
public static final String FORGET_OVERTIME = "FORGET_OVERTIME";
private WorkingDayTable() {
//Not meant to be instantiated.
}
}

View File

@ -0,0 +1,32 @@
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;
/**
* @author Robert Vokac
* @since 21.02.2024
*/
public class AboutButton extends TButton {
public AboutButton() {
super("About");
addActionListener(e -> {
String version = Utils.getVersion();
String buildDate = Utils.getBuildDate();
if (version == null) {
version = "unknown";
}
if (buildDate == null) {
buildDate = "unknown";
}
JOptionPane.showMessageDialog(null,
"Version: " + version + "\n" + "Built on (universal time): "
+ buildDate, "About \"Pdf DME Downloader\"",
JOptionPane.INFORMATION_MESSAGE);
});
}
}

View File

@ -0,0 +1,105 @@
package org.nanoboot.utils.timecalc.swing.common;
import org.nanoboot.utils.timecalc.app.Main;
import org.nanoboot.utils.timecalc.swing.controls.TTextField;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
/**
* @author Robert
* @since 13.03.2024
*/
public class ActivityHeader extends JPanel {
private static final Font FONT = new Font("sans", Font.BOLD, 12);
public static final Dimension PREFERRED_SIZE = new Dimension(200, 40);
public static final Dimension PREFERRED_SIZE1 = new Dimension(80, 40);
public static final Dimension PREFERRED_SIZE3 = new Dimension(60, 40);
public static final Dimension PREFERRED_SIZE4 = new Dimension(40, 40);
public static final Dimension PREFERRED_SIZE2 = new Dimension(100, 40);
private TTextField sortkey = new TTextField("Sortkey");
private TTextField name = new TTextField("Name");
private TTextField comment = new TTextField("Comment");
private TTextField ticket = new TTextField("Ticket");
private TTextField spentTime = new TTextField("Spent time");
private TTextField flags = new TTextField("Flags");
private TTextField subject = new TTextField("Subject");
private TTextField totalComment = new TTextField("Total comment");
private TTextField done = new TTextField("Done");
private TTextField todo = new TTextField("Todo");
public ActivityHeader() {
this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
if(Main.ACTIVITIES_WINDOW_SHOW_SORTKEY) add(sortkey);
add(name);
add(comment);
add(ticket);
add(spentTime);
add(flags);
add(subject);
add(totalComment);
add(done);
add(todo);
sortkey.setPreferredSize(PREFERRED_SIZE1);
name.setPreferredSize(PREFERRED_SIZE);
comment.setPreferredSize(PREFERRED_SIZE);
ticket.setPreferredSize(PREFERRED_SIZE1);
spentTime.setPreferredSize(PREFERRED_SIZE1);
flags.setPreferredSize(PREFERRED_SIZE2);
subject.setPreferredSize(PREFERRED_SIZE2);
totalComment.setPreferredSize(PREFERRED_SIZE2);
done.setPreferredSize(PREFERRED_SIZE3);
todo.setPreferredSize(PREFERRED_SIZE3);
sortkey.setEditable(false);
name.setEditable(false);
comment.setEditable(false);
ticket.setEditable(false);
spentTime.setEditable(false);
flags.setEditable(false);
subject.setEditable(false);
totalComment.setEditable(false);
done.setEditable(false);
todo.setEditable(false);
sortkey.setFont(FONT);
name.setFont(FONT);
comment.setFont(FONT);
ticket.setFont(FONT);
spentTime.setFont(FONT);
flags.setFont(FONT);
subject.setFont(FONT);
totalComment.setFont(FONT);
done.setFont(FONT);
todo.setFont(FONT);
sortkey.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
name.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
comment.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
ticket.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
spentTime.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
flags.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
subject.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
totalComment.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
done.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
todo.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
this.setBorder(BorderFactory.createLineBorder(Color.ORANGE, 1));
setAlignmentX(LEFT_ALIGNMENT);
sortkey.setVisible(false);
}
}

View File

@ -0,0 +1,304 @@
package org.nanoboot.utils.timecalc.swing.common;
import org.nanoboot.utils.timecalc.app.Main;
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;
import org.nanoboot.utils.timecalc.persistence.api.ActivityRepositoryApi;
import org.nanoboot.utils.timecalc.utils.common.TTime;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.util.List;
import java.util.function.BiConsumer;
/**
* @author Robert
* @since 13.03.2024
*/
public class ActivityPanel extends JPanel implements Comparable<ActivityPanel> {
@Getter
private final DayPanel dayPanel;
private boolean mouseOver;
class TTextFieldForActivityPanel extends TTextField {
public TTextFieldForActivityPanel(String s, String name) {
this(s, name, null);
}
public TTextFieldForActivityPanel(String s, String name, BiConsumer<Activity, String> additionalAction) {
this(s, name, additionalAction, false);
}
public TTextFieldForActivityPanel(String s, String name, BiConsumer<Activity, String> additionalAction, boolean sort) {
super(s);
setEditable(false);
setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
setCaretPosition(0);
//setToolTipText(s);
if(additionalAction != null) {
addMouseListener((MouseClickedListener) e -> {
String result = (String) JOptionPane.showInputDialog(
null,
"Select new " + name,
"New " + name,
name.equals("comment") ? JOptionPane.QUESTION_MESSAGE : JOptionPane.PLAIN_MESSAGE,
null,
null,
getText()
);
if (result != null) {
additionalAction.accept(activity, result);
activityRepository.update(activity);
setText(result);
if(sort) {
dayPanel.sortActivityPanels();
}
}
});
} else {
addMouseListener((MouseClickedListener) e -> {
Clipboard
clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(new StringSelection(getText()), null);
});
}
}
public void setText(String text) {
super.setText(text);
//if(!text.isEmpty()) {
//setToolTipText(text);
setCaretPosition(0);
//} else {
// setToolTipText(null);
// }
}
}
public static final Dimension PREFERRED_SIZE = new Dimension(200, 40);
public static final Dimension PREFERRED_SIZE1 = new Dimension(80, 40);
public static final Dimension PREFERRED_SIZE3 = new Dimension(60, 40);
public static final Dimension PREFERRED_SIZE4 = new Dimension(40, 40);
public static final Dimension PREFERRED_SIZE2 = new Dimension(100, 40);
private final ActivityRepositoryApi activityRepository;
@Getter
private final Activity activity;
private final TTextField sortkey;
private final TTextField name;
private final TTextField comment;
private final TTextField ticket;
private final TTextField spentTime;
public final TTextField flags;
@Getter(AccessLevel.PRIVATE)
private final TTextField subject;
@Getter(AccessLevel.PRIVATE)
private final TTextField totalComment;
public final TTextField today;
public final TTextField remains;
@Getter
private boolean deleted;
public ActivityPanel(ActivityRepositoryApi activityRepository,
Activity activity, DayPanel dayPanel) {
this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
this.activity = activity;
{
this.subject = new TTextFieldForActivityPanel("", "subject");
this.totalComment = new TTextFieldForActivityPanel("", "totalComment");
this.sortkey = new TTextFieldForActivityPanel("1", "sortkey", (a, r)->a.setSortkey(Integer.parseInt(r)), true);
this.name = new TTextFieldForActivityPanel("", "name", (a, r)->{a.setName(r);getSubject().setText(a.createSubject());}, false);
this.comment = new TTextFieldForActivityPanel("", "comment", (a, r)->{a.setComment(r);getTotalComment().setText(a.createTotalComment());}, false);
this.ticket = new TTextFieldForActivityPanel("", "ticket",
(a, r) -> {a.setTicket(r);
getSubject().setText(a.createSubject());
getTotalComment().setText(a.createTotalComment());}, false);
this.spentTime =
new TTextFieldForActivityPanel("00:00", "spentTime", (a, r) -> {
TTime spentTimeTTime = new TTime(r);
getActivity().setSpentHours(spentTimeTTime.getHour());
getActivity().setSpentMinutes(spentTimeTTime.getMinute());
getTotalComment().setText(getActivity().createTotalComment());
}, true);
this.flags = new TTextFieldForActivityPanel("Flags", "flags", (a, r)->a.setFlags(r), false);
this.today = new TTextFieldForActivityPanel("00:00", "today");
this.remains = new TTextFieldForActivityPanel("00:00", "remains");
}
this.dayPanel = dayPanel;
if(Main.ACTIVITIES_WINDOW_SHOW_SORTKEY) add(sortkey);
add(name);
add(comment);
add(ticket);
add(spentTime);
add(flags);
add(subject);
add(totalComment);
add(today);
add(remains);
sortkey.setVisible(false);
name.setHorizontalAlignment(JTextField.LEFT);
comment.setHorizontalAlignment(JTextField.LEFT);
ticket.setHorizontalAlignment(JTextField.LEFT);
JButton copyButton = new SmallTButton("Copy");
JButton deleteButton = new SmallTButton("Delete");
JButton moveThisButton = new SmallTButton("Move this");
JButton moveBeforeButton = new SmallTButton("Move before");
add(copyButton);
add(deleteButton);
add(moveThisButton);
add(moveBeforeButton);
copyButton.setFont(SwingUtils.SMALL_FONT);
deleteButton.setFont(SwingUtils.SMALL_FONT);
moveThisButton.setFont(SwingUtils.SMALL_FONT);
moveBeforeButton.setFont(SwingUtils.SMALL_FONT);
sortkey.setPreferredSize(PREFERRED_SIZE1);
name.setPreferredSize(PREFERRED_SIZE);
comment.setPreferredSize(PREFERRED_SIZE);
ticket.setPreferredSize(PREFERRED_SIZE1);
spentTime.setPreferredSize(PREFERRED_SIZE1);
flags.setPreferredSize(PREFERRED_SIZE2);
subject.setPreferredSize(PREFERRED_SIZE2);
totalComment.setPreferredSize(PREFERRED_SIZE2);
today.setPreferredSize(PREFERRED_SIZE3);
remains.setPreferredSize(PREFERRED_SIZE3);
copyButton.setPreferredSize(PREFERRED_SIZE4);
deleteButton.setPreferredSize(PREFERRED_SIZE4);
moveThisButton.setPreferredSize(PREFERRED_SIZE1);
moveBeforeButton.setPreferredSize(PREFERRED_SIZE1);
this.setPreferredSize(new Dimension(getWidth(), 40));
sortkey.setText(String.valueOf(activity.getSortkey()));
name.setText(activity.getName());
comment.setText(activity.getComment());
ticket.setText(activity.getTicket());
spentTime.setText(activity.getSpentTimeAsString());
flags.setText(activity.getFlags());
subject.setText(activity.createSubject());
totalComment.setText(activity.createTotalComment());
name.setFont(SwingUtils.VERY_SMALL_FONT);
comment.setFont(SwingUtils.VERY_SMALL_FONT);
ticket.setFont(SwingUtils.VERY_SMALL_FONT);
this.activityRepository = activityRepository;
//this.setBorder(BorderFactory.createLineBorder(Color.ORANGE, 1));
setAlignmentX(LEFT_ALIGNMENT);
// moveThisButton.addActionListener(e-> {
// //dayPanel.switchPositionsForThisActivityAndThePreviousActivity(getActivity());
// //dayPanel.markActivityAsToBeMoved(getActivity());
// });
//
// moveBeforeButton.addActionListener(e-> {
// //dayPanel.moveMarkedActivityBeforeThisActivity(getActivity());
// });
deleteButton.addActionListener(e -> {
this.deleted = activityRepository.delete(this.activity.getId());
if(deleted) {
this.setVisible(false);
deleted = true;
}
});
copyButton.addActionListener(e -> {
activityRepository.putToClipboard(this.activity);
});
moveThisButton.addActionListener(e-> {
this.dayPanel.markActivityPanelToBeMoved(this);
});
moveBeforeButton.addActionListener(e-> {
if(dayPanel.getMarkActivityPanelToBeMoved() == null) {
//nothing to do
return;
}
List<Activity> list = dayPanel.getActivities();
Activity activityToBeMoved = activityRepository.read(dayPanel.getMarkActivityPanelToBeMoved().getActivity().getId());
Activity activityTarget = activityRepository.read(activity.getId());
int activityTargetSortkey = activityTarget.getSortkey();
int newSortKey = activityToBeMoved.getSortkey();
for(int i = 0; i < list.size(); i++) {
if(activityToBeMoved.getSortkey() == activityTarget.getSortkey()) {
//nothing to do
break;
}
if(i >= 1 && activityToBeMoved.getSortkey() == activityTarget.getSortkey()) {
//nothing to do
break;
}
if(list.get(i).getId().equals(activityTarget.getId())) {
Activity activityBefore = i == 0 ? null : list.get(i - 1);
if(activityBefore != null && activityBefore.getId().equals(activityToBeMoved.getId())) {
//nothing to do
break;
}
int activityBeforeSortkey = activityBefore == null ? activityTargetSortkey : activityBefore.getSortkey();
int start = activityBeforeSortkey + 1;
int end = activityTargetSortkey - 1;
if(start > end) {
start = end;
}
if(start == end) {
newSortKey = end;
break;
}
newSortKey = start + (end - start) / 2;
if(newSortKey > activityTargetSortkey) {
newSortKey = activityTargetSortkey;
}
break;
}
}
int oldSortkey = activityToBeMoved.getSortkey();
if(oldSortkey != newSortKey) {
activityToBeMoved.setSortkey(newSortKey);
}
ActivityPanel activityPanelForActivity =
dayPanel.getActivityPanelForActivity(activityToBeMoved);
activityPanelForActivity.getActivity().setSortkey(newSortKey);
activityPanelForActivity.getSortkeyTTextField().setText(
String.valueOf(newSortKey));
activityRepository.update(activityToBeMoved);
dayPanel.sortActivityPanels();
});
}
@Override
public int compareTo(ActivityPanel o) {
return this.getActivity().compareTo(o.getActivity());
}
public TTextField getSortkeyTTextField() {
return sortkey;
}
}

View File

@ -0,0 +1,260 @@
package org.nanoboot.utils.timecalc.swing.common;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.block.BlockBorder;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.time.Day;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.nanoboot.utils.timecalc.utils.common.NumberFormats;
import org.nanoboot.utils.timecalc.utils.property.IntegerProperty;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
/**
* @author Robert Vokac
* @since 20.02.2024
*/
public class ArrivalChart extends JPanel {
private static final Color ORANGE = new Color(237, 125, 49);
private static final Color BLUE = new Color(68, 114, 196);
private static final Color BROWN = new Color(128, 0, 64);
private static final Color PURPLE = new Color(128, 0, 255);
public static final Rectangle EMPTY_RECTANGLE = new Rectangle();
public static final int MIN_CHART_WIDTH = 400;
private final boolean arrivalEnabled;
private final boolean ma7Enabled;
private final boolean ma14Enabled;
private final boolean ma28Enabled;
private final boolean ma56Enabled;
public IntegerProperty widthProperty = new IntegerProperty("widthProperty", 600);
public IntegerProperty heightProperty = new IntegerProperty("heightProperty", 400);
public ArrivalChart(ArrivalChartData data, int width) {
this(data.getDays(), data.getArrival(), data.getTarget(), data.getMa7(),
data.getMa14(), data.getMa28(), data.getMa56(),
data.getStartDate(), data.getEndDate(), width,
data.isArrivalEnabled(), data.isMa7Enabled(),
data.isMa14Enabled(), data.isMa28Enabled(),
data.isMa56Enabled());
}
public ArrivalChart(String[] days, double[] arrival, double target,
double[] ma7,
double[] ma14, double[] ma28, double[] ma56, String startDate,
String endDate, int width, boolean arrivalEnabled, boolean ma7Enabled, boolean ma14Enabled, boolean ma28Enabled,
boolean ma56Enabled) {
this.setLayout(null);
this.setVisible(true);
this.arrivalEnabled = arrivalEnabled;
this.ma7Enabled = ma7Enabled;
this.ma14Enabled = ma14Enabled;
this.ma28Enabled = ma28Enabled;
this.ma56Enabled = ma56Enabled;
//
String title = "Arrivals";
List<TimeSeries> timeSeries =
createSeries(days, arrival, target, ma7, ma14, ma28, ma56,
title, startDate, endDate);
JFreeChart chart = createChart(timeSeries, title);
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
chartPanel.setBackground(Color.white);
chartPanel.setDomainZoomable(true);
chartPanel.setMouseZoomable(true);
this.add(chartPanel);
widthProperty.addListener(e-> {
if (widthProperty.getValue() > MIN_CHART_WIDTH) {
chartPanel.setBounds(10, 10, widthProperty.getValue() - 60,
heightProperty.getValue());
} else {widthProperty.setValue(MIN_CHART_WIDTH);}
});
heightProperty.addListener(e-> {
if (heightProperty.getValue() > MIN_CHART_WIDTH) {
chartPanel.setBounds(10, 10, chartPanel.getWidth(),
heightProperty.getValue() - 60);
} else {heightProperty.setValue(MIN_CHART_WIDTH);}
});
widthProperty.setValue(width);
chartPanel.setBounds(10, 10, width, 400);
}
private JFreeChart createChart(List<TimeSeries> timeSeries,
String title) {
JFreeChart chart = ChartFactory.createTimeSeriesChart(
title,
"Date",
"Value",
new TimeSeriesCollection(new TimeSeries("Date"))
);
XYPlot plot = (XYPlot) chart.getPlot();
for (int i = 0; i < 8; i++) {
if (i == 0 && !this.arrivalEnabled) {
continue;
}
if (i == 4 && !this.ma7Enabled) {
continue;
}
if (i == 5 && !this.ma14Enabled) {
continue;
}
if (i == 6 && !this.ma28Enabled) {
continue;
}
if (i == 7 && !this.ma56Enabled) {
continue;
}
plot.setDataset(i, new TimeSeriesCollection(timeSeries.get(i)));
}
chart.setBorderVisible(false);
BiConsumer<Integer, Color> setSeries = (i, c) -> {
XYItemRenderer renderer = new XYLineAndShapeRenderer();
// renderer.setDefaultPaint(c);
// renderer.setDefaultStroke(new BasicStroke(timeSeries.get(0).getItemCount() > 180 ? 1.0f : (i == 1 || i == 2 ? 1.5f : 1.25f)));
// renderer.setDefaultShape(EMPTY_RECTANGLE);
renderer.setSeriesPaint(0, c);
float strength = i == 1 || i == 4 ? 3f : 1.5f;
BasicStroke stroke = new BasicStroke(strength);
renderer.setSeriesStroke(0, stroke);
renderer.setSeriesShape(0, EMPTY_RECTANGLE);
plot.setRenderer(i, renderer);
};
setSeries.accept(0, Color.GRAY);
setSeries.accept(1, ORANGE);
setSeries.accept(2, ORANGE);
setSeries.accept(3, ORANGE);
setSeries.accept(4, BLUE);
setSeries.accept(5, Color.GREEN);
setSeries.accept(6, BROWN);
setSeries.accept(7, PURPLE);
plot.setBackgroundPaint(Color.white);
// plot.setRangeGridlinesVisible(true);
// plot.setRangeGridlinePaint(Color.BLACK);
//
// plot.setDomainGridlinesVisible(true);
// plot.setDomainGridlinePaint(Color.BLACK);
chart.getLegend().setFrame(BlockBorder.NONE);
// CategoryAxis domainAxis = plot.getDomainAxis();
// domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_90);
// domainAxis.setLabelFont(SwingUtils.VERY_SMALL_FONT);
// domainAxis.setTickLabelFont(SwingUtils.VERY_SMALL_FONT);
// domainAxis.setCategoryLabelPositionOffset(10);
// domainAxis.setTickLabelsVisible(true);
chart.setTitle(new TextTitle(title,
new Font("Serif", Font.BOLD, 18)
)
);
return chart;
}
private List<TimeSeries> createSeries(String[] days, double[] arrival,
double target,
double[] ma7, double[] ma14, double[] ma28,
double[] ma56, String title, String startDate, String endDate) {
if (startDate == null) {
startDate = "0-0-0";
}
if (endDate == null) {
endDate = "0-0-0";
}
List<TimeSeries> result = new ArrayList<>();
final TimeSeries seriesArrival = new TimeSeries("Arrival");
final TimeSeries seriesTarget = new TimeSeries(
"Target (" + NumberFormats.FORMATTER_TWO_DECIMAL_PLACES
.format(target) + " h)");
final TimeSeries seriesTargetMinus30Minutes = new TimeSeries(
NumberFormats.FORMATTER_TWO_DECIMAL_PLACES
.format(target - 0.5d) + " h");
final TimeSeries seriesTargetMinus60Minutes = new TimeSeries(
NumberFormats.FORMATTER_TWO_DECIMAL_PLACES
.format(target - 1.0d) + " h");
final TimeSeries seriesMa7 = new TimeSeries("MA7");
final TimeSeries seriesMa14 = new TimeSeries("MA14");
final TimeSeries seriesMa28 = new TimeSeries("MA28");
final TimeSeries seriesMa56 = new TimeSeries("MA56");
result.add(seriesArrival);
result.add(seriesTarget);
result.add(seriesTargetMinus30Minutes);
result.add(seriesTargetMinus60Minutes);
result.add(seriesMa7);
result.add(seriesMa14);
result.add(seriesMa28);
result.add(seriesMa56);
String[] dayArray0 = startDate.split("-");
int year1 = Integer.valueOf(dayArray0[0]);
int month1 = Integer.valueOf(dayArray0[1]);
int day1 = Integer.valueOf(dayArray0[2]);
String[] dayArray1 = endDate.split("-");
int year2 = Integer.valueOf(dayArray1[0]);
int month2 = Integer.valueOf(dayArray1[1]);
int day2 = Integer.valueOf(dayArray1[2]);
for (int i = 0; i < days.length; i++) {
String date = days[i];
String[] dayArray = date.split("-");
int year = Integer.valueOf(dayArray[0]);
int month = Integer.valueOf(dayArray[1]);
int day = Integer.valueOf(dayArray[2]);
if (year1 != 0) {
if (month < month1) {
continue;
}
if (month == month1 && day < day1) {
continue;
}
}
if (year2 != 0) {
if (month > month2) {
continue;
}
if (month == month2 && day > day2) {
continue;
}
}
Day day3 = new Day(day, month, year);
seriesArrival.add(day3, new Double(arrival[i]));
seriesTarget.add(day3, new Double(0d));
seriesTargetMinus30Minutes.add(day3, new Double(-0.5d));
seriesTargetMinus60Minutes.add(day3, new Double(-1.0d));
seriesMa7.add(day3, new Double(ma7[i]));
seriesMa14.add(day3, new Double(ma14[i]));
seriesMa28.add(day3, new Double(ma28[i]));
seriesMa56.add(day3, new Double(ma56[i]));
}
return result;
}
}

View File

@ -0,0 +1,27 @@
package org.nanoboot.utils.timecalc.swing.common;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* @author Robert
* @since 11.03.2024
*/
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class ArrivalChartData {
private String[] days;
private double[] arrival;
private double target;
private double[] ma7;
private double[] ma14;
private double[] ma28;
private double[] ma56;
private String startDate;
private String endDate;
private boolean arrivalEnabled = true, ma7Enabled = true, ma14Enabled = true, ma28Enabled = true, ma56Enabled = true;
}

View File

@ -0,0 +1,41 @@
package org.nanoboot.utils.timecalc.swing.common;
import org.nanoboot.utils.timecalc.entity.Visibility;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
/**
* @author pc00289
* @since 27.03.2024
*/
public class Brush {
private final Graphics2D brush;
public Brush (Graphics2D graphics2D) {
this.brush = graphics2D;
}
public void drawOval(int centreX, int centreY, int width, int height) {
brush.drawOval((int) (centreX - width / 2d), (int) (centreY - height / 2d), width, height);
}
public void drawArc(int centreX, int centreY, int width, int height, int startAngle, int angle) {
brush.drawArc((int) (centreX - width / 2d), (int) (centreY - height / 2d), width, height, startAngle + 90, angle);
}
public void drawBorder(int centreX, int centreY, int length, int startLength, int angle,
float stroke, Color color) {
double angleRadian = Math.PI * 2 * ((angle - 90d) / 360d);
Color currentColor = brush.getColor();
brush.setColor(color);
int startX
= (int) (centreX + startLength * Math.cos(angleRadian));
int startY
= (int) (centreY + startLength * Math.sin(angleRadian));
int endX = (int) (centreX + (startLength + length) * Math.cos(angleRadian));
int endY = (int) (centreY + (startLength + length) * Math.sin(angleRadian));
brush.setStroke(new BasicStroke(stroke));
brush.drawLine(startX, startY, endX, endY);
brush.setColor(currentColor);
}
}

View File

@ -0,0 +1,338 @@
package org.nanoboot.utils.timecalc.swing.common;
import lombok.Getter;
import org.nanoboot.utils.timecalc.app.Main;
import org.nanoboot.utils.timecalc.app.TimeCalcConfiguration;
import org.nanoboot.utils.timecalc.entity.Activity;
import org.nanoboot.utils.timecalc.persistence.api.ActivityRepositoryApi;
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 javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author robertvokac
*/
public class DayPanel extends JPanel {
private static final Dimension MAXIMUM_SIZE = new Dimension(1300, 40);
private final String year;
private final String month;
private final String day;
private final Map<String, DayPanel> map = new HashMap<>();
private final ActivityRepositoryApi activityRepository;
private final TimeCalcConfiguration timeCalcConfiguration;
private JButton loadButton;
private JScrollPane scrollPane;
private JPanel panelInsideScrollPane;
@Getter
private ActivityPanel markActivityPanelToBeMoved = null;
public DayPanel(String yearIn, String monthIn, String dayIn,
ActivityRepositoryApi activityRepository, TimeCalcConfiguration timeCalcConfiguration) {
super();
this.year = yearIn;
this.month = monthIn;
this.day = dayIn;
this.activityRepository = activityRepository;
this.timeCalcConfiguration = timeCalcConfiguration;
setSize(1450, 600);
this.setLayout(null);
this.loadButton = new JButton("Load");
this.loadButton.setBounds(10, 10, 200, 30);
this.loadButton.addActionListener(e -> load());
add(loadButton);
}
public void load() {
if(this.loadButton == null) {
//nothing to do
return;
}
System.out.println("Loaded: " + year + month + day);
if (this.loadButton.isVisible()) {
this.loadButton.setVisible(false);
this.loadButton = null;
} else {
//already loaded
return;
}
BoxLayout boxLayout = new BoxLayout(this, BoxLayout.Y_AXIS);
this.setAlignmentX(LEFT_ALIGNMENT);
this.setLayout(boxLayout);
JPanel buttons = new JPanel();
buttons.setLayout(new FlowLayout(FlowLayout.LEFT));
buttons.setAlignmentX(LEFT_ALIGNMENT);
JButton newButton = new JButton("New");
JButton pasteButton = new JButton("Paste");
JButton reviewButton = new JButton("Copy all Total comments to clipboard");
JButton statusButton = new JButton("Status");
JButton addFlagToAllActivitiesButton = new JButton("Add flag to all activities");
buttons.add(newButton);
buttons.add(pasteButton);
buttons.add(reviewButton);
buttons.add(statusButton);
buttons.add(addFlagToAllActivitiesButton);
add(buttons);
this.scrollPane
= new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
add(scrollPane);
this.panelInsideScrollPane = new JPanel();
panelInsideScrollPane.setLayout(new BoxLayout(panelInsideScrollPane, BoxLayout.Y_AXIS));
scrollPane.setViewportView(panelInsideScrollPane);
ActivityHeader activityHeader = new ActivityHeader();
panelInsideScrollPane.add(activityHeader);
activityHeader.setMaximumSize(new Dimension(1200, 40));
buttons.setMaximumSize(new Dimension(1000, 40));
List<Activity> list = activityRepository.list(
Integer.valueOf(year),
Integer.valueOf(month),
Integer.valueOf(day));
Collections.sort(list);
for (Activity a : list) {
ActivityPanel comp =
new ActivityPanel(activityRepository, a, this);
comp.setMaximumSize(MAXIMUM_SIZE);
panelInsideScrollPane.add(comp);
}
revalidate();
newButton.addActionListener(e-> {
Activity newActivity = new Activity(UUID.randomUUID().toString(), Integer.valueOf(year), Integer.valueOf(month), Integer.valueOf(day), "", "", "", 0, 0, "", activityRepository.getNextSortkey(Integer.valueOf(year), Integer.valueOf(month), Integer.valueOf(day)));
ActivityPanel comp =
new ActivityPanel(activityRepository, newActivity, this);
comp.setMaximumSize(new Dimension(1300, 40));
add(comp);
activityRepository.create(newActivity);
panelInsideScrollPane.add(comp);
revalidate();
});
pasteButton.addActionListener(e-> {
Activity afc = activityRepository.getFromClipboard();
if(afc == null) {
Utils.showNotification("There is no activity in clipboard. Nothing to do.");
return;
}
Activity newActivity = new Activity(UUID.randomUUID().toString(), Integer.valueOf(year), Integer.valueOf(month), Integer.valueOf(day),
afc.getName(), afc.getComment(), afc.getTicket(), 0, 0, "", activityRepository.getNextSortkey(Integer.valueOf(year), Integer.valueOf(month), Integer.valueOf(day)));
ActivityPanel comp =
new ActivityPanel(activityRepository, newActivity, this);
comp.setMaximumSize(new Dimension(1200, 40));
add(comp);
activityRepository.create(newActivity);
panelInsideScrollPane.add(comp);
revalidate();
});
reviewButton.addActionListener(e->{
String comments = Arrays
.stream(panelInsideScrollPane.getComponents())
.filter(c-> c instanceof ActivityPanel)
.map(ap->((ActivityPanel) ap).getActivity())
.map(a->a.createTotalComment())
.collect(
Collectors.joining("\n"));
// JOptionPane
// .showMessageDialog(null, comments, "All comments for: " + year + "-" + (month.length() < 2 ? "0" : "") + month + "-" + (day.length() < 2 ? "0" : "") + day , JOptionPane.INFORMATION_MESSAGE);
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(new StringSelection(comments), null);
});
statusButton.addActionListener(e-> {
// String neededFlags = timeCalcConfiguration.activityNeededFlagsProperty.getValue();
// System.out.println("neededFlags=" + neededFlags);
// neededFlags.replace(",", ":");
// String[] neededFlagsArray = neededFlags.split(":");
// Set<String> neededFlagsSet = Arrays.stream(neededFlagsArray).filter(f -> !f.isEmpty()).collect(Collectors.toSet());
List<ActivityPanel> activityPanels = new ArrayList<>();
Arrays
.stream(panelInsideScrollPane.getComponents())
.filter(c-> c instanceof ActivityPanel).forEach(f-> activityPanels.add((ActivityPanel) f));
Collections.sort(activityPanels);
// double done = 0d;
// double todo = 8d;
// loopName:
// for(ActivityPanel ap:activityPanels) {
// Set<String> flags = ap.getActivity().flagsAsSet();
// if(!neededFlagsSet.isEmpty()) {
// for(String f:neededFlagsSet) {
// if(!flags.contains(f)) {
// continue loopName;
// }
// }
// }
// double now = ap.getActivity().getSpentHours() + ap.getActivity().getSpentMinutes() / 60d;
// done = done + now;
// todo = todo - now;
// }
// double progress = done / 8d;
double progress = activityRepository.getProgressForDay(Integer.valueOf(year), Integer.valueOf(month), Integer.valueOf(day), timeCalcConfiguration);
double doneHours = progress * 8d;
double todoHours = (8d - doneHours);
Utils.showNotification("Current status: done=" + NumberFormats.FORMATTER_TWO_DECIMAL_PLACES.format(doneHours) + "h, todo="+ NumberFormats.FORMATTER_TWO_DECIMAL_PLACES.format(todoHours));
});
addFlagToAllActivitiesButton.addActionListener(e -> {
String newFlag = (String) JOptionPane.showInputDialog(
null,
"Select new flag",
"New flag",
JOptionPane.PLAIN_MESSAGE,
null,
null,
""
);
if(newFlag != null && !newFlag.trim().isEmpty()) {
getActivityPanels().forEach(a->
{
a.getActivity().addFlag(newFlag);
a.flags.setText(a.getActivity().getFlags());
activityRepository.update(a.getActivity());
}
);
revalidate();
}
});
sortActivityPanels();
}
public List<ActivityPanel> getActivityPanels() {
return Arrays
.stream(panelInsideScrollPane.getComponents())
.filter(c-> c instanceof ActivityPanel)
.map(ap->((ActivityPanel) ap)).collect(Collectors.toList());
}
public List<Activity> getActivities() {
return Arrays
.stream(panelInsideScrollPane.getComponents())
.filter(c-> c instanceof ActivityPanel)
.map(ap->((ActivityPanel) ap).getActivity()).collect(Collectors.toList());
}
public int getIndexForActivityPanel(Activity a) {
for(int i = 0;i<panelInsideScrollPane.getComponentCount();i++) {
Component c = panelInsideScrollPane.getComponent(i);
if(c instanceof ActivityPanel) {
if(((ActivityPanel)c).getActivity().equals(a)) {
return i;
}
}
}
return -1;
}
public ActivityPanel getActivityPanelForActivity(Activity a) {
Optional<Component> optional = Arrays
.stream(panelInsideScrollPane.getComponents())
.filter(c-> c instanceof ActivityPanel)
.filter(c-> ((ActivityPanel) c).getActivity().getId().equals(a.getId()))
.findFirst();
if(optional.isPresent()) {
return (ActivityPanel) optional.get();
} else {
return null;
}
}
public void sortActivityPanels() {
System.out.println("sortActivityPanels()");
List<ActivityPanel> list = new ArrayList<>();
Arrays
.stream(panelInsideScrollPane.getComponents())
.filter(c-> c instanceof ActivityPanel).filter(c-> !((ActivityPanel)c).isDeleted()).forEach(e-> list.add((ActivityPanel) e));
Collections.sort(list);
for(ActivityPanel ap:list) {
panelInsideScrollPane.remove(ap);
}
double done = 0d;
double todo = 8d;
int lastSortkey = 0;
boolean recalculateSortKeys = false;
for(ActivityPanel ap:list) {
if(ap.getActivity().getSortkey() - lastSortkey < 4) {
recalculateSortKeys = true;
break;
} else {
lastSortkey = ap.getActivity().getSortkey();
}
}
int sortkey = 0;
if(recalculateSortKeys) {
int sortkeySpace = activityRepository.getSortkeySpace();
for(ActivityPanel ap:list) {
sortkey = sortkey + sortkeySpace;
ap.getActivity().setSortkey(sortkey);
activityRepository.update(ap.getActivity());
if(Main.ACTIVITIES_WINDOW_SHOW_SORTKEY) ap.getSortkeyTTextField().setText(String.valueOf(sortkey));
}
}
Collections.sort(list);
for(ActivityPanel ap:list) {
double now = ap.getActivity().getSpentHours() + ap.getActivity().getSpentMinutes() / 60d;
done = done + now;
todo = todo - now;
TTime doneTTime =
TTime.ofMilliseconds((int) (done * 60d * 60d * 1000d));
ap.today.setText(doneTTime.toString().substring(0,5));
TTime todoTTime =
TTime.ofMilliseconds((int) (todo * 60d * 60d * 1000d));
ap.remains.setText(todoTTime.toString().substring(0,todoTTime.isNegative() ? 6 : 5));
panelInsideScrollPane.add(ap);
ap.setVisible(false);
ap.setVisible(true);
ap.revalidate();
}
revalidate();
}
public void markActivityPanelToBeMoved(ActivityPanel activityPanel) {
boolean deletion = this.markActivityPanelToBeMoved == activityPanel;
this.markActivityPanelToBeMoved = deletion ? null : activityPanel;
this.markActivityPanelToBeMoved = activityPanel;
}
}

View File

@ -0,0 +1,91 @@
package org.nanoboot.utils.timecalc.swing.common;
import org.nanoboot.utils.timecalc.app.TimeCalcConfiguration;
import org.nanoboot.utils.timecalc.swing.controls.TTabbedPane;
import org.nanoboot.utils.timecalc.persistence.api.ActivityRepositoryApi;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
*
* @author robertvokac
*/
public class MonthPanel extends JPanel {
private final String year;
private final String month;
private final Map<String, DayPanel> days;
private final TTabbedPane tp;
private final ActivityRepositoryApi activityRepository;
private final Calendar cal;
private final TimeCalcConfiguration timeCalcConfiguration;
private boolean loaded = false;
public MonthPanel(String yearIn, String monthIn, ActivityRepositoryApi activityRepository, TimeCalcConfiguration timeCalcConfiguration) {
super();
this.activityRepository = activityRepository;
this.timeCalcConfiguration = timeCalcConfiguration;
this.year = yearIn;
this.month = monthIn;
this.days = new HashMap<>();
setLayout(null);
this.tp = new TTabbedPane();
add(tp);
tp.setBounds(0, 0, 1450, 650);
ChangeListener changeListener = new ChangeListener() {
private boolean secondOrLaterChange = false;
public void stateChanged(ChangeEvent changeEvent) {
if(!secondOrLaterChange) {
secondOrLaterChange = true;
return;
}
JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent.getSource();
int index = sourceTabbedPane.getSelectedIndex();
days.get(sourceTabbedPane.getTitleAt(index)).load();
}
};
tp.addChangeListener(changeListener);
this.cal = Calendar.getInstance();
cal.set(Calendar.YEAR, Integer.valueOf(year));
cal.set(Calendar.MONTH, Integer.valueOf(month) - 1);
cal.set(Calendar.DAY_OF_MONTH, 1);
}
public void load() {
if(loaded) {
//nothing to do
return;
}
System.out.println("Loaded: " + year + month);
int maxDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
for (int day = 1; day <= maxDay; day++) {
String dayS = String.valueOf(day);
DayPanel dayPanel = new DayPanel(year, month, dayS,
activityRepository, timeCalcConfiguration);
tp.add(dayS, dayPanel);
days.put(dayS, dayPanel);
}
loaded = true;
}
public void setSelectedDay(String day) {
tp.switchTo(day);
}
public DayPanel getDayPanel(String day) {
return days.get(day);
}
}

View File

@ -0,0 +1,35 @@
package org.nanoboot.utils.timecalc.swing.common;
import java.awt.Color;
import java.awt.Font;
import java.awt.Insets;
/**
* @author Robert Vokac
* @since 26.02.2024
*/
public class SwingUtils {
public static final int MARGIN = 10;
public static final Font SMALL_FONT = new Font("sans", Font.BOLD, 10);
public static final Font VERY_SMALL_FONT = new Font("sans", Font.PLAIN, 9);
public static final Font MEDIUM_MONOSPACE_FONT
= new Font(Font.MONOSPACED, Font.PLAIN, 12);
public static final Insets INSETS = new Insets(4,4,4,4);
public static final Font LINUX_FONT = new Font("sansserif", Font.PLAIN, 10);
private SwingUtils() {
//Not meant to be instantiated.
}
public static final Color getColorFromString(String s) {
if (s.isEmpty()) {
System.out.println("error: empty string for color");
return Color.ORANGE;
}
String[] colorAsStringArray = s.split(",");
int red = Integer.valueOf(colorAsStringArray[0]);
int green = Integer.valueOf(colorAsStringArray[1]);
int blue = Integer.valueOf(colorAsStringArray[2]);
return new Color(red, green, blue);
}
}

View File

@ -0,0 +1,946 @@
package org.nanoboot.utils.timecalc.swing.common;
import org.nanoboot.utils.timecalc.app.TimeCalcApp;
import org.nanoboot.utils.timecalc.app.TimeCalcConfiguration;
import org.nanoboot.utils.timecalc.app.TimeCalcException;
import org.nanoboot.utils.timecalc.app.TimeCalcProperties;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.swing.windows.MainWindow;
import org.nanoboot.utils.timecalc.swing.progress.Time;
import org.nanoboot.utils.timecalc.utils.common.FileConstants;
import org.nanoboot.utils.timecalc.utils.common.Jokes;
import org.nanoboot.utils.timecalc.utils.common.TTime;
import org.nanoboot.utils.timecalc.utils.common.Utils;
import org.nanoboot.utils.timecalc.utils.property.IntegerProperty;
import javax.swing.JOptionPane;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Properties;
import lombok.Setter;
import org.nanoboot.utils.timecalc.utils.common.NumberFormats;
/**
* @author Robert Vokac
* @since 26.02.2024
*/
public class TimeCalcKeyAdapter extends KeyAdapter {
private static final int[] ALLOWED_KEY_CODES =
{KeyEvent.VK_R, KeyEvent.VK_X, KeyEvent.VK_W, KeyEvent.VK_A, KeyEvent.VK_Z,KeyEvent.VK_O};
private static final String EXTENDED_FEATURES_ARE_DISABLED =
"Extended features are disabled";
private final TimeCalcConfiguration timeCalcConfiguration;
private final TimeCalcApp timeCalcApp;
private final MainWindow mainWindow;
private final Time time;
private boolean changeByFiveMinutes = false;
@Setter
private int msToAdd = 1;
public TimeCalcKeyAdapter(
TimeCalcConfiguration timeCalcConfiguration,
TimeCalcApp timeCalcApp,
MainWindow mainWindow,
Time time
) {
this.timeCalcConfiguration = timeCalcConfiguration;
this.timeCalcApp = timeCalcApp;
this.mainWindow = mainWindow;
this.time = time;
}
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
boolean shiftDown = e.isShiftDown();
boolean ctrlDown = e.isControlDown();
boolean altDown = e.isAltDown();
//boolean metaDown = e.isMetaDown();
if (!shiftDown && !ctrlDown && !altDown /*&& !metaDown*/) {
processKeyCode(keyCode);
} else //if (!metaDown)
{
processShifCtrlAltModeKeyCodes(keyCode, shiftDown, ctrlDown,
altDown);
}
// else {
// processMetaKeyCodes(keyCode);
// }
//meta key ???
}
public void processShifCtrlAltModeKeyCodes(int keyCode, boolean shiftDown,
boolean ctrlDown, boolean altDown) {
if (shiftDown && ctrlDown) {
Utils.showNotification("Following key shortcut is not supported: SHIFT + CTRL");
return;
}
if (shiftDown && altDown) {
Utils.showNotification("Following key shortcut is not supported: SHIFT + ALT");
return;
}
if (ctrlDown && altDown) {
Utils.showNotification("Following key shortcut is not supported: CTRL + ALT");
return;
}
boolean increase = shiftDown;
boolean decrease = ctrlDown;
boolean reset = altDown;
TTime changeTTime = changeByFiveMinutes ? TTime.T_TIME_FIVE_MINUTES : TTime.T_TIME_ONE_MINUTE;
switch (keyCode) {
case KeyEvent.VK_Y: {
//Utils.showNotification((increase ? "Increasing" : (decrease ? "Decreasing" : "Reseting")) + " year.");
updateProperty(timeCalcConfiguration.testYearCustomProperty, increase, decrease, reset,
Calendar.YEAR);
break;
}
case KeyEvent.VK_N: {
//Utils.showNotification((increase ? "Increasing" : (decrease ? "Decreasing" : "Reseting")) + " month.");
updateProperty(timeCalcConfiguration.testMonthCustomProperty, increase, decrease, reset,
Calendar.MONTH);
break;
}
case KeyEvent.VK_D: {
//Utils.showNotification((increase ? "Increasing" : (decrease ? "Decreasing" : "Reseting")) + " day.");
updateProperty(timeCalcConfiguration.testDayCustomProperty, increase, decrease, reset,
Calendar.DAY_OF_MONTH);
break;
}
case KeyEvent.VK_H: {
//Utils.showNotification((increase ? "Increasing" : (decrease ? "Decreasing" : "Reseting")) + " hour.");
updateProperty(timeCalcConfiguration.testHourCustomProperty, increase, decrease, reset,
Calendar.HOUR_OF_DAY);
break;
}
case KeyEvent.VK_M: {
//Utils.showNotification((increase ? "Increasing" : (decrease ? "Decreasing" : "Reseting")) + " minute.");
updateProperty(timeCalcConfiguration.testMinuteCustomProperty, increase, decrease, reset,
Calendar.MINUTE);
break;
}
case KeyEvent.VK_S: {
//Utils.showNotification((increase ? "Increasing" : (decrease ? "Decreasing" : "Reseting")) + " second.");
updateProperty(timeCalcConfiguration.testSecondCustomProperty, increase, decrease, reset,
Calendar.SECOND);
break;
}
case KeyEvent.VK_I: {
//Utils.showNotification((increase ? "Increasing" : (decrease ? "Decreasing" : "Reseting")) + " millisecond.");
updateProperty(timeCalcConfiguration.testMillisecondCustomProperty, increase, decrease, reset,
Calendar.MILLISECOND);
break;
}
case KeyEvent.VK_U: {
int totalMs = msToAdd;
boolean negative = false;
if (totalMs < 0) {
totalMs = Math.abs(totalMs);
negative = true;
}
//System.out.println("going to add ms:" +msToAdd);
int ms_ = totalMs % 1000;
totalMs = totalMs - ms_;
int s_ = totalMs / 1000 % 60;
totalMs = totalMs - s_ * 1000;
int m_ = totalMs / 1000 / 60 % 60;
totalMs = totalMs - m_ * 1000 * 60;
int h_ = totalMs / 1000 / 60 / 60 % 60;
totalMs = totalMs - h_ * 1000 * 60 * 60;
int d_ = totalMs / 1000 / 60 / 60 / 24;
totalMs = totalMs - d_ * 1000 * 60 * 60 * 24;
if (negative && (increase || decrease)) {
increase = false;
decrease = true;
}
updateProperty(timeCalcConfiguration.testDayCustomProperty, increase, decrease, reset,
Calendar.DAY_OF_MONTH, d_);
updateProperty(timeCalcConfiguration.testHourCustomProperty, increase, decrease, reset,
Calendar.HOUR_OF_DAY, h_);
updateProperty(timeCalcConfiguration.testMinuteCustomProperty, increase, decrease, reset,
Calendar.MINUTE, m_);
updateProperty(timeCalcConfiguration.testSecondCustomProperty, increase, decrease, reset,
Calendar.SECOND, s_);
updateProperty(timeCalcConfiguration.testMillisecondCustomProperty, increase, decrease, reset,
Calendar.MILLISECOND, ms_);
break;
}
case KeyEvent.VK_K: {
//Utils.showNotification((increase ? "Increasing" : (decrease ? "Decreasing" : "Reseting")) + " millisecond.");
for (int i = 1; i <= 7; i++) {
updateProperty(timeCalcConfiguration.testDayCustomProperty, increase, decrease, reset,
Calendar.DAY_OF_MONTH);
}
break;
}
case KeyEvent.VK_Q: {
if(mainWindow.allowOnlyBasicFeaturesProperty.getValue()) {
showWarningExtendedFeaturesAreDisabled();
return;
}
double oldSpeed = this.mainWindow.getSpeed();
if (oldSpeed < 0) {
oldSpeed = 1.0d;
}
if (increase) {
this.mainWindow.increaseSpeed();
}
if (decrease) {
this.mainWindow.decreaseSpeed();
}
if (reset) {
this.mainWindow.resetSpeed();
}
final double newSpeed = this.mainWindow.getSpeed();
if (oldSpeed != newSpeed) {
final double msDouble = Math.pow(2, newSpeed) * 1000;
TTime t = TTime.ofMilliseconds(((int) msDouble));
Utils.showNotification("Speed was changed from "
+ ((int) oldSpeed)
+ " to: " + ((int) newSpeed) + " (" + (NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(Math.pow(2, newSpeed))) + ") ("
+ (newSpeed <= -10 ? (NumberFormats.FORMATTER_SIX_DECIMAL_PLACES.format(msDouble) + "ms") : (/*newSpeed <=21*/t.getHour() < 24 ? t : ((long) (msDouble / 1000d / 60d / 60d / 24d) + " days")))
+ " /1s)");
} else {
if (decrease) {
Utils.showNotification("Current speed cannot be decreased: "
+ NumberFormats.FORMATTER_TWO_DECIMAL_PLACES.format(oldSpeed));
}
if (increase) {
Utils.showNotification("Current speed cannot be increased: "
+ NumberFormats.FORMATTER_TWO_DECIMAL_PLACES.format(oldSpeed));
}
}
break;
}
case KeyEvent.VK_A: {
if (increase) {
mainWindow.increaseArrival(changeTTime);
}
if (decrease) {
mainWindow.decreaseArrival(changeTTime);
}
break;
}
case KeyEvent.VK_O: {
if (increase) {
mainWindow.increaseOvertime(changeTTime);
}
if (decrease) {
mainWindow.decreaseOvertime(changeTTime);
}
break;
}
case KeyEvent.VK_W: {
if (increase) {
mainWindow.increaseWork(changeTTime);
}
if (decrease) {
mainWindow.decreaseWork(changeTTime);
}
break;
}
case KeyEvent.VK_P: {
if(mainWindow.allowOnlyBasicFeaturesProperty.getValue()) {
showWarningExtendedFeaturesAreDisabled();
break;
}
if (increase) {
mainWindow.increasePauseLength(changeTTime);
}
if (decrease) {
mainWindow.decreasePauseLength(changeTTime);
}
break;
}
case KeyEvent.VK_C: {
this.changeByFiveMinutes = increase;
Utils.showNotification("Time will be changed by " + (increase ? "5 minutes" : "1 minute") + ".");
break;
}
case KeyEvent.VK_E: {
if (ctrlDown) {
mainWindow.doSaveButtonClick();
}
break;
}
default:
// Utils.showNotification(
// "Unsupported key was pressed. There is no key shortcut for this key: "
// + keyCode);
}
}
private void showWarningExtendedFeaturesAreDisabled() {
Utils.showNotification(EXTENDED_FEATURES_ARE_DISABLED);
}
// private void processMetaKeyCodes(int keyCode) {
//
// switch (keyCode) {
// case KeyEvent.VK_S: {
//
// break;
// }
// default:
// }
// }
private void updateProperty(IntegerProperty integerProperty,
boolean increase, boolean decrease, boolean reset, int timeUnit) {
updateProperty(integerProperty, increase, decrease, reset, timeUnit, 1);
}
private void updateProperty(IntegerProperty integerProperty,
boolean increase, boolean decrease, boolean reset, int timeUnit, int value) {
if(mainWindow.allowOnlyBasicFeaturesProperty.getValue()) {
showWarningExtendedFeaturesAreDisabled();
return;
}
if (value == 0) {
//nothing to do
return;
}
int currentValue = integerProperty.getValue();
if ((increase || decrease) && currentValue == Integer.MAX_VALUE) {
switch (timeUnit) {
case Calendar.YEAR:
integerProperty.setValue(time.yearProperty.getValue());
break;
case Calendar.MONTH:
integerProperty.setValue(time.monthProperty.getValue());
break;
case Calendar.DAY_OF_MONTH:
integerProperty.setValue(time.dayProperty.getValue());
break;
case Calendar.HOUR_OF_DAY:
integerProperty.setValue(time.hourProperty.getValue());
break;
case Calendar.MINUTE:
integerProperty.setValue(time.minuteProperty.getValue());
break;
case Calendar.SECOND:
integerProperty.setValue(time.secondProperty.getValue());
break;
case Calendar.MILLISECOND:
integerProperty.setValue(time.millisecondProperty.getValue());
break;
default:
throw new TimeCalcException("Unsupported time unit: " + timeUnit);
}
}
Calendar cal = time.asCalendar();
int oldYear = cal.get(Calendar.YEAR);
int oldMonth = cal.get(Calendar.MONTH) + 1;
int oldDay = cal.get(Calendar.DAY_OF_MONTH);
int oldHour = cal.get(Calendar.HOUR_OF_DAY);
int oldMinute = cal.get(Calendar.MINUTE);
int oldSecond = cal.get(Calendar.SECOND);
int oldMillisecond = cal.get(Calendar.MILLISECOND);
cal.add(timeUnit, increase ? value : (-value));
int newValue = cal.get(timeUnit);
if (Calendar.MONTH == timeUnit) {
newValue++;
}
if (reset) {
newValue = Integer.MAX_VALUE;
}
integerProperty.setValue(newValue);
int newYear = cal.get(Calendar.YEAR);
int newMonth = cal.get(Calendar.MONTH) + 1;
int newDay = cal.get(Calendar.DAY_OF_MONTH);
int newHour = cal.get(Calendar.HOUR_OF_DAY);
int newMinute = cal.get(Calendar.MINUTE);
int newSecond = cal.get(Calendar.SECOND);
int newMillisecond = cal.get(Calendar.MILLISECOND);
if (increase) {
switch (timeUnit) {
case Calendar.YEAR:
break;
case Calendar.MONTH:
if (oldYear != newYear) {
updateProperty(timeCalcConfiguration.testYearCustomProperty, increase, decrease, reset, Calendar.YEAR);
}
break;
case Calendar.DAY_OF_MONTH:
if (oldMonth != newMonth) {
updateProperty(timeCalcConfiguration.testMonthCustomProperty, increase, decrease, reset, Calendar.MONTH);
}
break;
case Calendar.HOUR_OF_DAY:
if (oldDay != newDay) {
updateProperty(timeCalcConfiguration.testDayCustomProperty, increase, decrease, reset, Calendar.DAY_OF_MONTH);
}
break;
case Calendar.MINUTE:
if (oldHour != newHour) {
updateProperty(timeCalcConfiguration.testHourCustomProperty, increase, decrease, reset, Calendar.HOUR_OF_DAY);
}
break;
case Calendar.SECOND:
if (oldMinute != newMinute) {
updateProperty(timeCalcConfiguration.testMinuteCustomProperty, increase, decrease, reset, Calendar.MINUTE);
}
break;
case Calendar.MILLISECOND:
if (oldSecond != newSecond) {
updateProperty(timeCalcConfiguration.testSecondCustomProperty, increase, decrease, reset, Calendar.SECOND);
}
break;
default:
throw new TimeCalcException("Unsupported time unit: " + timeUnit);
}
}
if (decrease) {
switch (timeUnit) {
case Calendar.YEAR:
break;
case Calendar.MONTH:
if (oldYear != newYear) {
updateProperty(timeCalcConfiguration.testYearCustomProperty, increase, decrease, reset, Calendar.YEAR);
}
break;
case Calendar.DAY_OF_MONTH:
if (oldMonth != newMonth) {
updateProperty(timeCalcConfiguration.testMonthCustomProperty, increase, decrease, reset, Calendar.MONTH);
}
break;
case Calendar.HOUR_OF_DAY:
if (oldDay != newDay) {
updateProperty(timeCalcConfiguration.testDayCustomProperty, increase, decrease, reset, Calendar.DAY_OF_MONTH);
}
break;
case Calendar.MINUTE:
if (oldHour != newHour) {
updateProperty(timeCalcConfiguration.testHourCustomProperty, increase, decrease, reset, Calendar.HOUR_OF_DAY);
}
break;
case Calendar.SECOND:
if (oldMinute != newMinute) {
updateProperty(timeCalcConfiguration.testMinuteCustomProperty, increase, decrease, reset, Calendar.MINUTE);
}
break;
case Calendar.MILLISECOND:
if (oldSecond != newSecond) {
updateProperty(timeCalcConfiguration.testSecondCustomProperty, increase, decrease, reset, Calendar.SECOND);
}
break;
default:
throw new TimeCalcException("Unsupported time unit: " + timeUnit);
}
}
}
public void processKeyCode(int keyCode) {
boolean onlyGreyOrNone
= timeCalcConfiguration.visibilitySupportedColoredProperty
.isDisabled();
Visibility visibility = Visibility
.valueOf(timeCalcApp.visibilityProperty.getValue());
boolean numberKeyWasPressed = keyCode == KeyEvent.VK_0
|| keyCode == KeyEvent.VK_1
|| keyCode == KeyEvent.VK_2
|| keyCode == KeyEvent.VK_3
|| keyCode == KeyEvent.VK_4
|| keyCode == KeyEvent.VK_5
|| keyCode == KeyEvent.VK_6
|| keyCode == KeyEvent.VK_7
|| keyCode == KeyEvent.VK_8
|| keyCode == KeyEvent.VK_9;
if (numberKeyWasPressed && !FileConstants.TIME_CALC_PROFILES_TXT_FILE
.exists()) {
Utils.showNotification(
"Warning: There is no profile assigned to Key with number, you pressed.");
}
if(mainWindow.allowOnlyBasicFeaturesProperty.getValue()) {
if(!Arrays.stream(ALLOWED_KEY_CODES).filter(k->k== keyCode).findFirst().isPresent()){
showWarningExtendedFeaturesAreDisabled();
return;
}
}
switch (keyCode) {
case KeyEvent.VK_UP: {
timeCalcApp.visibilityProperty
.setValue(onlyGreyOrNone ? Visibility.GRAY.name()
: Visibility.STRONGLY_COLORED.name());
break;
}
case KeyEvent.VK_DOWN:
case KeyEvent.VK_PERIOD: {
timeCalcApp.visibilityProperty
.setValue(Visibility.NONE.name());
break;
}
case KeyEvent.VK_G: {
if (visibility.isGray() && !onlyGreyOrNone) {
timeCalcApp.visibilityProperty
.setValue(Visibility.WEAKLY_COLORED.name());
} else {
timeCalcApp.visibilityProperty
.setValue(Visibility.GRAY.name());
}
break;
}
case KeyEvent.VK_C: {
if (!onlyGreyOrNone) {
if (visibility.isStronglyColored()) {
timeCalcApp.visibilityProperty
.setValue(Visibility.WEAKLY_COLORED.name());
} else {
timeCalcApp.visibilityProperty
.setValue(
Visibility.STRONGLY_COLORED.name());
}
} else {
timeCalcApp.visibilityProperty.setValue(Visibility.GRAY
.name());
}
break;
}
case KeyEvent.VK_V:
case KeyEvent.VK_H: {
if (visibility.isNone()) {
timeCalcApp.visibilityProperty
.setValue(onlyGreyOrNone ? Visibility.GRAY.name()
: Visibility.STRONGLY_COLORED.name());
} else {
timeCalcApp.visibilityProperty
.setValue(Visibility.NONE.name());
}
break;
}
case KeyEvent.VK_SPACE: {
if (visibility.isStronglyColored()) {
timeCalcApp.visibilityProperty
.setValue(onlyGreyOrNone ? Visibility.GRAY.name()
: Visibility.WEAKLY_COLORED.name());
}
if (visibility.isWeaklyColored()) {
timeCalcApp.visibilityProperty
.setValue(Visibility.GRAY.name());
}
if (visibility.isGray()) {
timeCalcApp.visibilityProperty
.setValue(Visibility.NONE.name());
}
if (visibility.isNone()) {
timeCalcApp.visibilityProperty
.setValue(onlyGreyOrNone ? Visibility.GRAY.name()
: Visibility.STRONGLY_COLORED.name());
}
break;
}
case KeyEvent.VK_F2: {
mainWindow.doCommand();
break;
}
case KeyEvent.VK_R: {
mainWindow.doRestart();
break;
}
case KeyEvent.VK_N: {
timeCalcConfiguration.notificationsVisibleProperty.flip();
break;
}
case KeyEvent.VK_W: {
mainWindow.openWorkDaysWindow();
break;
}
case KeyEvent.VK_A: {
mainWindow.openActivitiesWindow();
break;
}
case KeyEvent.VK_X: {
mainWindow.doExit();
break;
}
case KeyEvent.VK_S: {
mainWindow.openConfigWindow();
break;
}
case KeyEvent.VK_J: {
if (timeCalcConfiguration.jokesVisibleProperty.isEnabled()) {
Jokes.showRandom();
break;
}
}
case KeyEvent.VK_P:
case KeyEvent.VK_F1: {
mainWindow.openHelpWindow();
break;
}
case KeyEvent.VK_U: {
mainWindow.doEnableEverything();
break;
}
case KeyEvent.VK_I: {
mainWindow.doDisableAlmostEverything();
break;
}
case KeyEvent.VK_E: {
timeCalcConfiguration.batteryWavesVisibleProperty.flip();
break;
}
case KeyEvent.VK_B: {
MainWindow.hideShowFormsCheckBox
.setSelected(!MainWindow.hideShowFormsCheckBox.isSelected());
break;
}
case KeyEvent.VK_F: {
if (FileConstants.TIME_CALC_PROFILES_TXT_FILE.exists()) {
try {
Utils.showNotification(Utils.readTextFromFile(
FileConstants.TIME_CALC_PROFILES_TXT_FILE),
15000, 200);
} catch (IOException ioException) {
ioException.printStackTrace();
Utils.showNotification(
"Error: " + ioException.getMessage());
}
} else {
Utils.showNotification(
"Warning: There are no numbers assigned to profiles. Update file: "
+ FileConstants.TIME_CALC_PROFILES_TXT_FILE
.getAbsolutePath() + ".");
}
break;
}
case KeyEvent.VK_Q: {
timeCalcConfiguration.squareVisibleProperty.flip();
break;
}
case KeyEvent.VK_L: {
timeCalcConfiguration.circleVisibleProperty.flip();
break;
}
case KeyEvent.VK_Y: {
timeCalcConfiguration.smileysVisibleOnlyIfMouseMovingOverProperty
.flip();
if (timeCalcConfiguration.smileysVisibleOnlyIfMouseMovingOverProperty.isDisabled() && timeCalcConfiguration.smileysVisibleProperty.isDisabled()) {
timeCalcConfiguration.smileysVisibleProperty.enable();
}
break;
}
case KeyEvent.VK_M: {
timeCalcConfiguration.walkingHumanVisibleProperty.flip();
break;
}
case KeyEvent.VK_LEFT: {
switchProfile(true, false);
break;
}
case KeyEvent.VK_RIGHT: {
switchProfile(false, true);
break;
}
case KeyEvent.VK_D: {
timeCalcConfiguration.testYearCustomProperty.setValue(Integer.MAX_VALUE);
timeCalcConfiguration.testMonthCustomProperty.setValue(Integer.MAX_VALUE);
timeCalcConfiguration.testDayCustomProperty.setValue(Integer.MAX_VALUE);
timeCalcConfiguration.testHourCustomProperty.setValue(Integer.MAX_VALUE);
timeCalcConfiguration.testMinuteCustomProperty.setValue(Integer.MAX_VALUE);
timeCalcConfiguration.testSecondCustomProperty.setValue(Integer.MAX_VALUE);
timeCalcConfiguration.testMillisecondCustomProperty.setValue(Integer.MAX_VALUE);
Utils.showNotification(timeCalcConfiguration.print(), 15000, 400);
this.mainWindow.resetSpeed();
break;
}
case KeyEvent.VK_K: {
if (timeCalcConfiguration.clockVisibleProperty.isEnabled()) {
timeCalcConfiguration.clockVisibleProperty.disable();
} else {
timeCalcConfiguration.clockVisibleProperty.enable();
timeCalcConfiguration.clockHandsLongVisibleProperty.enable();
timeCalcConfiguration.clockHandsColoredProperty.enable();
timeCalcConfiguration.clockHandsHourVisibleProperty.enable();
timeCalcConfiguration.clockHandsMinuteVisibleProperty.enable();
timeCalcConfiguration.clockHandsSecondVisibleProperty.enable();
timeCalcConfiguration.clockHandsMillisecondVisibleProperty.enable();
timeCalcConfiguration.clockBorderVisibleProperty.enable();
timeCalcConfiguration.clockBorderOnlyHoursProperty.disable();
timeCalcConfiguration.clockNumbersVisibleProperty.enable();
timeCalcConfiguration.clockCircleVisibleProperty.enable();
timeCalcConfiguration.clockCircleStrongBorderProperty.disable();
timeCalcConfiguration.clockCircleBorderColorProperty.setValue("0,0,255");
timeCalcConfiguration.clockCentreCircleVisibleProperty.enable();
timeCalcConfiguration.clockCentreCircleColoredProperty.disable();
timeCalcConfiguration.clockProgressVisibleOnlyIfMouseMovingOverProperty.disable();
timeCalcConfiguration.clockDateVisibleOnlyIfMouseMovingOverProperty.disable();
}
break;
}
case KeyEvent.VK_Z: {
String newForgetOvertime = (String) JOptionPane.showInputDialog(
null,
"Set new forget overtime. Current value is: " + mainWindow.getForgetOvertime(),
"New forget overtime",
JOptionPane.PLAIN_MESSAGE,
null,
null,
mainWindow.getForgetOvertime()
);
int newForgetOvertimeInt = -1;
if (newForgetOvertime != null) {
if (newForgetOvertime.contains(":")) {
newForgetOvertimeInt = new TTime(newForgetOvertime).toTotalMilliseconds() / 1000 / 60;
} else {
try {
newForgetOvertimeInt
= Integer.parseInt(newForgetOvertime);
} catch (Exception e) {
Utils.showNotification(e);
}
}
}
if (newForgetOvertimeInt >= 0) {
mainWindow.setForgetOvertime(newForgetOvertimeInt);
} else {
Utils.showNotification("Error:Forget overtime must not be less than zero.");
}
break;
}
case KeyEvent.VK_SLASH: {
if (timeCalcConfiguration.testEnabledProperty.isDisabled()) {
if (!Utils.askYesNo(null, "Do you really want to enable \"Test mode\"? If yes, then you will be allowed to set custom time.", "Enabling \"Test mode\"")) {
break;
}
}
timeCalcConfiguration.testEnabledProperty.flip();
Utils.showNotification((timeCalcConfiguration.testEnabledProperty.isEnabled() ? "Enabled" : "Disabled") + " \"Test mode\".");
break;
}
case KeyEvent.VK_O: {
if (mainWindow.allowOnlyBasicFeaturesProperty.getValue()) {
Utils.showNotification("Extended features are already disabled.");
} else {
String question =
"Do you really want to disable the extended features of this application? Only the basic features will be enabled.";
if (!Utils.askYesNo(null, question, "Disabling \"Extended features\" of this app")) {
break;
}
try {
FileConstants.BASIC_TXT.createNewFile();
String msg = "Warning: " + "You disabled the extended features of this application. Only the basic features are enabled. To enable the extended features, please: 1. stop this application 2. delete manually this file: " + FileConstants.BASIC_TXT.getAbsolutePath() + " 3. start this application again.";
Utils.showNotification(msg, 30000, 400);
this.mainWindow.doRestart();
} catch (IOException e) {
e.printStackTrace();
break;
}
break;
}
break;
}
case KeyEvent.VK_COMMA: {
timeCalcConfiguration.speedNegativeProperty.flip();
break;
}
case KeyEvent.VK_T: {
timeCalcConfiguration.speedFloatingProperty.flip();
break;
}
default:
if (!numberKeyWasPressed) {
Utils.showNotification(
"Unsupported key was pressed. There is no key shortcut for this key: "
+ keyCode);
}
}
boolean profileSwitch =
numberKeyWasPressed && FileConstants.TIME_CALC_PROFILES_TXT_FILE
.exists();
if(profileSwitch && mainWindow.allowOnlyBasicFeaturesProperty.getValue()) {
showWarningExtendedFeaturesAreDisabled();
}
if (profileSwitch && !mainWindow.allowOnlyBasicFeaturesProperty.getValue()) {
Properties properties = new Properties();
try {
properties.load(new FileInputStream(
FileConstants.TIME_CALC_PROFILES_TXT_FILE));
} catch (IOException ioException) {
ioException.printStackTrace();
}
int profileNumber = 0;
switch (keyCode) {
case KeyEvent.VK_0:
profileNumber = 0;
break;
case KeyEvent.VK_1:
profileNumber = 1;
break;
case KeyEvent.VK_2:
profileNumber = 2;
break;
case KeyEvent.VK_3:
profileNumber = 3;
break;
case KeyEvent.VK_4:
profileNumber = 4;
break;
case KeyEvent.VK_5:
profileNumber = 5;
break;
case KeyEvent.VK_6:
profileNumber = 6;
break;
case KeyEvent.VK_7:
profileNumber = 7;
break;
case KeyEvent.VK_8:
profileNumber = 8;
break;
case KeyEvent.VK_9:
profileNumber = 9;
break;
}
String key = String.valueOf(profileNumber);
if (properties.containsKey(key)) {
String profileName = (String) properties.get(key);
if (profileName
.equals(timeCalcConfiguration.profileNameProperty)) {
Utils.showNotification("Profile \"" + profileName
+ "\" is already active. Nothing to do",
5000);
} else {
Utils.showNotification("Info: Changing profile to: #" + profileNumber + " " + ((profileName.isEmpty() ? "{Default profile}"
: profileName)), 5000);
timeCalcConfiguration.saveToTimeCalcProperties();
TimeCalcProperties.getInstance().loadProfile(profileName);
timeCalcConfiguration.loadFromTimeCalcProperties(
TimeCalcProperties.getInstance());
Utils.writeTextToFile(FileConstants.TIME_CALC_CURRENT_PROFILE_TXT_FILE, profileName);
}
} else {
Utils.showNotification(
"Warning: There is no profile assigned to Key "
+ profileNumber, 5000);
}
}
mainWindow.repaint();
}
private void switchProfile(boolean previous, boolean next) {
if ((previous && next) || (!previous && !next)) {
//nothing to do
return;
}
Properties profiles = new Properties();
try {
final String readTextFromFile = Utils.readTextFromFile(FileConstants.TIME_CALC_PROFILES_TXT_FILE);
if (readTextFromFile == null || readTextFromFile.isEmpty()) {
return;
}
try {
profiles.load(new FileInputStream(
FileConstants.TIME_CALC_PROFILES_TXT_FILE));
} catch (IOException ioException) {
ioException.printStackTrace();
}
if (profiles.size() == 1) {
return;
}
} catch (IOException ioException) {
ioException.printStackTrace();
Utils.showNotification(ioException);
return;
}
String currentProfileName = null;
try {
currentProfileName = Utils.readTextFromFile(FileConstants.TIME_CALC_CURRENT_PROFILE_TXT_FILE);
} catch (IOException ioException) {
ioException.printStackTrace();
Utils.showNotification(ioException);
return;
}
int numberOfCurrentProfile = next ? -1 : 9;
for (Object number : profiles.keySet()) {
String profileName = (String) profiles.get(number);
if (profileName.equals(currentProfileName)) {
numberOfCurrentProfile = Integer.valueOf(
(String) number);
break;
}
}
for (int i = (numberOfCurrentProfile + (next ? 1 : -1)); next ? i <= 9 : i >= 0; i = next ? (i + 1) : (i - 1)) {
String number = String.valueOf(i);
if (!profiles.containsKey(number)) {
continue;
}
System.out.println("switching profile from " + numberOfCurrentProfile + " to profile " + number);
processKeyCode(getKeyCodeForNumber(Integer.parseInt(number)));
break;
}
}
private int getKeyCodeForNumber(int number) {
switch (number) {
case 0:
return KeyEvent.VK_0;
case 1:
return KeyEvent.VK_1;
case 2:
return KeyEvent.VK_2;
case 3:
return KeyEvent.VK_3;
case 4:
return KeyEvent.VK_4;
case 5:
return KeyEvent.VK_5;
case 6:
return KeyEvent.VK_6;
case 7:
return KeyEvent.VK_7;
case 8:
return KeyEvent.VK_8;
case 9:
return KeyEvent.VK_9;
default:
Utils.showNotification("Unsupported key: " + number);
return 0;
}
}
}

View File

@ -0,0 +1,473 @@
/**
* This Java class named Toaster is licence under this licence: Apache License V2.0
*/
package org.nanoboot.utils.timecalc.swing.common;
/**
* Java Toaster is a java utility class for your swing applications that show an
* animate box coming from the bottom of your screen with a notification message
* and/or an associated image (like msn online/offline notifications).
* <p>
* Toaster panel in windows system follow the taskbar; So if the taskbar is into
* the bottom the panel coming from the bottom and if the taskbar is on the top
* then the panel coming from the top.
* <p>
* This is a simple example of utilization:
* <p>
* import com.nitido.utils.toaster.*; import javax.swing.*;
* <p>
* public class ToasterTest {
* <p>
* public static void main(String[] args) { // Initialize toaster manager...
* Toaster toasterManager = new Toaster();
* <p>
* // Show a simple toaster toasterManager.showToaster( new ImageIcon(
* "mylogo.gif" ), "A simple toaster with an image" ); } }
*/
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JWindow;
import javax.swing.border.EtchedBorder;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Rectangle;
import org.nanoboot.utils.timecalc.app.TimeCalcProperty;
import org.nanoboot.utils.timecalc.utils.property.BooleanProperty;
/**
* Class to show tosters in multiplatform
*
* @author daniele piras
*/
public class Toaster {
private static final long serialVersionUID = 1L;
public static final BooleanProperty notificationsVisibleProperty
= new BooleanProperty(TimeCalcProperty.NOTIFICATIONS_VISIBLE
.getKey());
// Set the margin
int margin;
// Flag that indicate if use alwaysOnTop or not.
// method always on top start only SINCE JDK 5 !
boolean useAlwaysOnTop = true;
// Width of the toster
private int toasterWidth = 300;
// Height of the toster
private int toasterHeight = 80;
// Step for the toaster
private int step = 20;
// Step time
private int stepTime = 20;
// Show time
private int displayTime = 3000;
// Current number of toaster...
private int currentNumberOfToaster = 0;
// Last opened toaster
private int maxToaster = 0;
// Max number of toasters for the sceen
private int maxToasterInSceen;
// Background image
private Image backgroundImage;
// Font used to display message
private Font font;
// Color for border
private Color borderColor;
// Color for toaster
private Color toasterColor;
// Set message color
private Color messageColor;
/**
* Constructor to initialized toaster component...
*
* @author daniele piras
*/
public Toaster() {
// Set default font...
font = new Font("Arial", Font.BOLD, 12);
// Border color
borderColor = new Color(245, 153, 15);
toasterColor = Color.WHITE;
messageColor = Color.BLACK;
useAlwaysOnTop = true;
// Verify AlwaysOnTop Flag...
try {
JWindow.class
.getMethod("setAlwaysOnTop", Boolean.class);
} catch (Exception e) {
useAlwaysOnTop = false;
}
}
/**
* Show a toaster with the specified message and the associated icon.
*/
public void showToaster(Icon icon, String msg) {
// if (notificationsVisibleProperty.isDisabled()) {
// //nothing to do
// return;
// }
SingleToaster singleToaster = new SingleToaster();
if (icon != null) {
singleToaster.iconLabel.setIcon(icon);
}
singleToaster.message.setText(msg);
singleToaster.toFront();
singleToaster.setAlwaysOnTop(true);
singleToaster.animate();
}
/**
* Show a toaster with the specified message.
*/
public void showToaster(String msg) {
showToaster(null, msg);
}
/**
* @return Returns the font
*/
public Font getToasterMessageFont() {
// TODO Auto-generated method stub
return font;
}
/**
* Set the font for the message
*/
public void setToasterMessageFont(Font f) {
font = f;
}
/**
* @return Returns the borderColor.
*/
public Color getBorderColor() {
return borderColor;
}
/**
* @param borderColor The borderColor to set.
*/
public void setBorderColor(Color borderColor) {
this.borderColor = borderColor;
}
/**
* @return Returns the displayTime.
*/
public int getDisplayTime() {
return displayTime;
}
/**
* @param displayTime The displayTime to set.
*/
public void setDisplayTime(int displayTime) {
this.displayTime = displayTime;
}
/**
* @return Returns the margin.
*/
public int getMargin() {
return margin;
}
/**
* @param margin The margin to set.
*/
public void setMargin(int margin) {
this.margin = margin;
}
/**
* @return Returns the messageColor.
*/
public Color getMessageColor() {
return messageColor;
}
/**
* @param messageColor The messageColor to set.
*/
public void setMessageColor(Color messageColor) {
this.messageColor = messageColor;
}
/**
* @return Returns the step.
*/
public int getStep() {
return step;
}
/**
* @param step The step to set.
*/
public void setStep(int step) {
this.step = step;
}
/**
* @return Returns the stepTime.
*/
public int getStepTime() {
return stepTime;
}
/**
* @param stepTime The stepTime to set.
*/
public void setStepTime(int stepTime) {
this.stepTime = stepTime;
}
/**
* @return Returns the toasterColor.
*/
public Color getToasterColor() {
return toasterColor;
}
/**
* @param toasterColor The toasterColor to set.
*/
public void setToasterColor(Color toasterColor) {
this.toasterColor = toasterColor;
}
/**
* @return Returns the toasterHeight.
*/
public int getToasterHeight() {
return toasterHeight;
}
/**
* @param toasterHeight The toasterHeight to set.
*/
public void setToasterHeight(int toasterHeight) {
this.toasterHeight = toasterHeight;
}
/**
* @return Returns the toasterWidth.
*/
public int getToasterWidth() {
return toasterWidth;
}
/**
* @param toasterWidth The toasterWidth to set.
*/
public void setToasterWidth(int toasterWidth) {
this.toasterWidth = toasterWidth;
}
public Image getBackgroundImage() {
return backgroundImage;
}
public void setBackgroundImage(Image backgroundImage) {
this.backgroundImage = backgroundImage;
}
/**
* Class that rappresent a single toaster
*
* @author daniele piras
*/
class SingleToaster extends JWindow {
private static final long serialVersionUID = 1L;
// Label to store Icon
private final JLabel iconLabel = new JLabel();
// Text area for the message
private final JTextArea message = new JTextArea();
/**
* *
* Simple costructor that initialized components...
*/
public SingleToaster() {
initComponents();
}
/**
* *
* Function to initialized components
*/
private void initComponents() {
setSize(toasterWidth, toasterHeight);
message.setFont(getToasterMessageFont());
JPanel externalPanel = new JPanel(new BorderLayout(1, 1));
externalPanel.setBackground(getBorderColor());
JPanel innerPanel
= new JPanel(new BorderLayout(getMargin(), getMargin())) {
@Override
public void paint(Graphics g) {
if (getBackgroundImage() != null) {
g.drawImage(getBackgroundImage(), 0, 0, null);
}
super.paint(g);
}
};
if (getBackgroundImage() != null) {
innerPanel.setOpaque(false);
message.setOpaque(false);
iconLabel.setOpaque(false);
}
innerPanel.setBackground(getToasterColor());
message.setBackground(getToasterColor());
message.setMargin(new Insets(2, 2, 2, 2));
message.setLineWrap(true);
message.setWrapStyleWord(true);
EtchedBorder etchedBorder = (EtchedBorder) BorderFactory
.createEtchedBorder();
externalPanel.setBorder(etchedBorder);
externalPanel.add(innerPanel);
message.setForeground(getMessageColor());
innerPanel.add(iconLabel, BorderLayout.WEST);
innerPanel.add(message, BorderLayout.CENTER);
getContentPane().add(externalPanel);
JButton closeButton = new JButton("Close");
closeButton.setBounds(480, 10, 100, 40);
innerPanel.add(closeButton, BorderLayout.BEFORE_FIRST_LINE);
closeButton.addActionListener(e -> {
setVisible(false);
dispose();
});
}
/**
* *
* Start toaster animation...
*/
public void animate() {
(new Animation(this)).start();
}
}
/**
* *
* Class that manage the animation
*/
class Animation extends Thread {
SingleToaster toaster;
public Animation(SingleToaster toaster) {
this.toaster = toaster;
}
/**
* Animate vertically the toaster. The toaster could be moved from
* bottom to upper or to upper to bottom
*
* @param posx
* @param fromY
* @param toY
* @throws InterruptedException
*/
protected void animateVertically(int posx, int fromY, int toY)
throws InterruptedException {
toaster.setLocation(posx, fromY);
if (toY < fromY) {
for (int i = fromY; i > toY; i -= step) {
toaster.setLocation(posx, i);
Thread.sleep(stepTime);
}
} else {
for (int i = fromY; i < toY; i += step) {
toaster.setLocation(posx, i);
Thread.sleep(stepTime);
}
}
toaster.setLocation(posx, toY);
}
public void run() {
try {
boolean animateFromBottom = true;
GraphicsEnvironment ge = GraphicsEnvironment
.getLocalGraphicsEnvironment();
Rectangle screenRect = ge.getMaximumWindowBounds();
int screenHeight = screenRect.height;
int startYPosition;
int stopYPosition;
if (screenRect.y > 0) {
animateFromBottom = false; // Animate from top!
}
maxToasterInSceen = screenHeight / toasterHeight;
int posx = screenRect.width - toasterWidth - 1;
toaster.setLocation(posx, screenHeight);
toaster.setVisible(true);
if (useAlwaysOnTop) {
toaster.setAlwaysOnTop(true);
}
if (animateFromBottom) {
startYPosition = screenHeight;
stopYPosition = startYPosition - toasterHeight - 1;
if (currentNumberOfToaster > 0) {
stopYPosition
= stopYPosition - (maxToaster % maxToasterInSceen
* toasterHeight);
} else {
maxToaster = 0;
}
} else {
startYPosition = screenRect.y - toasterHeight;
stopYPosition = screenRect.y;
if (currentNumberOfToaster > 0) {
stopYPosition
= stopYPosition + (maxToaster % maxToasterInSceen
* toasterHeight);
} else {
maxToaster = 0;
}
}
currentNumberOfToaster++;
maxToaster++;
animateVertically(posx, startYPosition, stopYPosition);
Thread.sleep(displayTime);
animateVertically(posx, stopYPosition, startYPosition);
currentNumberOfToaster--;
toaster.setVisible(false);
toaster.dispose();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

View File

@ -0,0 +1,65 @@
package org.nanoboot.utils.timecalc.swing.common;
import lombok.Getter;
import org.nanoboot.utils.timecalc.swing.progress.AnalogClock;
import org.nanoboot.utils.timecalc.swing.progress.Time;
import java.time.DateTimeException;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.Calendar;
/**
* @author Robert Vokac
* @since 06.03.2024
*/
@Getter
public class WeekStatistics {
private final boolean nowIsWeekend;
private final int workDaysDone;
private final int workDaysTotal;
public WeekStatistics(AnalogClock analogClock, Time time) {
int workDaysDoneTmp = 0;
int workDaysTodoTmp = 0;
int workDaysTotalTmp;
{
int currentDayOfMonth = time.dayProperty.getValue();
for (int dayOfMonth = 1;
dayOfMonth <= time.asCalendar()
.getActualMaximum(Calendar.DAY_OF_MONTH);
dayOfMonth++) {
DayOfWeek dayOfWeek = LocalDate.of(time.yearProperty.getValue(),
time.monthProperty.getValue(),
dayOfMonth)
.getDayOfWeek();
boolean weekend
= dayOfWeek.toString().equals("SATURDAY") || dayOfWeek
.toString().equals("SUNDAY");
if (dayOfMonth < currentDayOfMonth && !weekend) {
++workDaysDoneTmp;
}
if (dayOfMonth > currentDayOfMonth && !weekend) {
++workDaysTodoTmp;
}
}
}
String currentDayOfWeekAsString = LocalDate
.of(analogClock.yearProperty.getValue(),
analogClock.monthProperty.getValue(),
analogClock.dayProperty.getValue()).getDayOfWeek()
.toString();
this.nowIsWeekend = currentDayOfWeekAsString.equals("SATURDAY")
|| currentDayOfWeekAsString.equals("SUNDAY");
workDaysTotalTmp
= workDaysDoneTmp + (nowIsWeekend ? 0 : 1) + workDaysTodoTmp;
this.workDaysDone = workDaysDoneTmp;
this.workDaysTotal = workDaysTotalTmp;
// System.out.println("currentDayOfWeekAsString=" + currentDayOfWeekAsString);
// System.out.println("workDaysDone=" + workDaysDone);
// System.out.println("workDaysTotal=" + workDaysTotal);
}
}

View File

@ -0,0 +1,667 @@
package org.nanoboot.utils.timecalc.swing.common;
import org.nanoboot.utils.timecalc.app.GetProperty;
import org.nanoboot.utils.timecalc.app.TimeCalcProperty;
import org.nanoboot.utils.timecalc.entity.Progress;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.entity.WidgetType;
import org.nanoboot.utils.timecalc.swing.progress.ProgressFuelGauge;
import org.nanoboot.utils.timecalc.swing.progress.battery.Battery;
import org.nanoboot.utils.timecalc.swing.progress.ProgressSmileyIcon;
import org.nanoboot.utils.timecalc.swing.progress.ProgressSwing;
import org.nanoboot.utils.timecalc.utils.common.ProgressSmiley;
import org.nanoboot.utils.timecalc.utils.property.BooleanProperty;
import org.nanoboot.utils.timecalc.utils.property.Property;
import org.nanoboot.utils.timecalc.utils.property.StringProperty;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.function.Consumer;
import java.util.function.Supplier;
import javax.swing.JMenuItem;
import org.nanoboot.utils.timecalc.app.TimeCalcApp;
import static org.nanoboot.utils.timecalc.swing.progress.battery.Battery.HIGH_STRONGLY_COLORED;
import static org.nanoboot.utils.timecalc.swing.progress.battery.Battery.HIGH_WEAKLY_COLORED;
import static org.nanoboot.utils.timecalc.swing.progress.battery.Battery.LIGHT_RED;
import static org.nanoboot.utils.timecalc.swing.progress.battery.Battery.ULTRA_LIGHT_RED;
/**
* @author Robert Vokac
* @since 20.02.2024
*/
public class Widget extends JPanel implements
GetProperty {
private static final int CLOSE_OR_MINIMIZE_BUTTON_SIDE = 25;
protected static final Color FOREGROUND_COLOR = new Color(220, 220, 220);
protected static final Color FOREGROUND_COLOR2 = new Color(210, 210, 210);
protected static final Color BACKGROUND_COLOR = new Color(238, 238, 238);
protected static final Font BIG_FONT = new Font("sans", Font.BOLD, 24);
protected static final Font MEDIUM_FONT = new Font("sans", Font.BOLD, 16);
protected static final String HEAD = " () ";
protected static final String BODY = "/||\\";
protected static final String LEGS = " /\\ ";
public static final Color CLOSE_BUTTON_FOREGROUND_COLOR
= new Color(127, 127, 127);
public static final Color CLOSE_OR_MINIMIZE_BUTTON_BACKGROUND_COLOR = Color.LIGHT_GRAY;
public static final Color CLOSE_BUTTON_BACKGROUND_COLOR_MOUSE_OVER_CLOSE_ICON = new Color(255, 153, 153);
public static final Color MINIMIZE_BUTTON_BACKGROUND_COLOR_MOUSE_OVER_CLOSE_ICON = new Color(
126, 179, 227);
private static final Color VERY_LIGHT_GRAY = new Color(220, 220, 220);
private static final Font FONT = new Font("sans", Font.PLAIN, 12);
public static final Color WIDGET_BACKGROUND_COLOR = ((Supplier<Color>) () ->{int i = 232;return new Color(i,i,i);}).get();
public final BooleanProperty visibilitySupportedColoredProperty
= new BooleanProperty("visibilitySupportedColoredProperty", true);
public final BooleanProperty visibleProperty
= new BooleanProperty("visibleProperty", true);
public final BooleanProperty smileysVisibleProperty
= new BooleanProperty(TimeCalcProperty.SMILEYS_VISIBLE.getKey());
public final BooleanProperty smileysVisibleOnlyIfMouseMovingOverProperty
= new BooleanProperty(
TimeCalcProperty.SMILEYS_VISIBLE_ONLY_IF_MOUSE_MOVING_OVER
.getKey());
public final BooleanProperty smileysColoredProperty
= new BooleanProperty("smileysColoredProperty", true);
public StringProperty visibilityProperty
= new StringProperty("widget.visibilityProperty",
Visibility.STRONGLY_COLORED.name());
public StringProperty typeProperty
= new StringProperty("widget.typeProperty", WidgetType.DAY.name().toLowerCase());
public final BooleanProperty typeVisibleProperty = new BooleanProperty(TimeCalcProperty.TYPE_VISIBLE
.getKey(), false);
protected int side = 0;
protected Progress progress = null;
protected boolean mouseOver = false;
private boolean mouseOverCloseButton = false;
private boolean mouseOverMinimizeButton = false;
protected JLabel smileyIcon;
protected JLabel smileyIcon2;
private long lastUpdate = System.nanoTime();
private static final Color PURPLE_STRONGLY_COLORED = new Color(153,51,255);
private static final Color PURPLE_WEAKLY_COLORED = new Color(204,153,255);
public final BooleanProperty hiddenProperty
= new BooleanProperty("hiddenProperty", false);
private WidgetMenu widgetMenu = null;
public Widget() {
setBackground(BACKGROUND_COLOR);
new Timer(getTimerDelay(), e -> repaint()).start();
this.addMouseMotionListener(new MouseMotionListener() {
@Override
public void mouseDragged(MouseEvent e) {
}
@Override
public void mouseMoved(MouseEvent e) {
int x = e.getX();
int y = e.getY();
mouseOverCloseButton = x >= getWidth() - CLOSE_OR_MINIMIZE_BUTTON_SIDE
&& y <= CLOSE_OR_MINIMIZE_BUTTON_SIDE;
mouseOverMinimizeButton = x < getWidth() - CLOSE_OR_MINIMIZE_BUTTON_SIDE
&& x > getWidth() - 2 * CLOSE_OR_MINIMIZE_BUTTON_SIDE
&& y <= CLOSE_OR_MINIMIZE_BUTTON_SIDE;
}
});
addMouseListener(new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {
if(hiddenProperty.isEnabled()) {
hiddenProperty.disable();
}
if (mouseOverCloseButton) {
visibleProperty.setValue(false);
return;
}
if(mouseOverMinimizeButton) {
hiddenProperty.enable();
return;
}
if (visibilitySupportedColoredProperty.isDisabled()) {
//nothing to do
return;
}
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
mouseOver = true;
}
@Override
public void mouseExited(MouseEvent e) {
mouseOver = false;
}
});
Widget widget = this;
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
showPopup(e);
}
@Override
public void mouseReleased(MouseEvent e) {
showPopup(e);
}
private void showPopup(MouseEvent e) {
if(widgetMenu == null) {
widgetMenu = new WidgetMenu(widget, createRefreshConsumer());
List<JMenuItem> additionalMenus = createAdditionalMenus();
if(additionalMenus != null) {
additionalMenus.forEach(m-> widgetMenu.add(m));
}
}
widgetMenu.refresh();
widgetMenu.markAsSelected(WidgetType.valueOf(typeProperty.getValue().toUpperCase(
Locale.ROOT)));
if (e.isPopupTrigger()) {
widgetMenu.show(e.getComponent(),
e.getX(), e.getY());
}
}
});
}
protected Consumer<Object> createRefreshConsumer() {
return null;
}
protected List<JMenuItem> createAdditionalMenus() {
return null;
}
public int getTimerDelay() {
return 100;
}
// @Override
// public void setVisible(boolean aFlag) {
// if(visibleProperty.isEnabled() && !aFlag) {
// super.setVisible(false);
// }
// if(visibleProperty.isDisabled() && aFlag) {
// super.setVisible(false);
// }
//
// }
public final void setProgress(Progress newProgress) {
double oldDonePercent = this.progress == null ? 0 : this.progress.getDonePercent(WidgetType.DAY);
int oldDonePercentInt1000Mil = (int) (oldDonePercent * 1000000000);
int newDonePercentInt1000Mil = (int) (newProgress.getDonePercent(WidgetType.DAY) * 1000000000);
if (newDonePercentInt1000Mil != oldDonePercentInt1000Mil) {
lastUpdate = System.nanoTime();
}
this.progress = newProgress;
}
protected double donePercent() {
if(progress == null) {
return 0d;
}
if(typeProperty.getValue().equals(WidgetType.PRESENTATION.name())) {
long currentTime = new Date().getTime() / 1000l;
long l = currentTime % 35;
if (l >= 0 && l < 5) {
return getDonePercentForWidgetType(WidgetType.MINUTE);
}
if (l >= 5 && l < 10) {
return getDonePercentForWidgetType(WidgetType.HOUR);
}
if (l >= 10 && l < 15) {
return getDonePercentForWidgetType(WidgetType.DAY);
}
if (l >= 15 && l < 20) {
return getDonePercentForWidgetType(WidgetType.WEEK);
}
if (l >= 20 && l < 25) {
return getDonePercentForWidgetType(WidgetType.MONTH);
}
if (l >= 25 && l < 30) {
return getDonePercentForWidgetType(WidgetType.YEAR);
}
if (l >= 30 && l < 35) {
return getDonePercentForWidgetType(WidgetType.LIFE);
}
return getDonePercentForWidgetType(WidgetType.DAY);
}
return getDonePercentForWidgetType(WidgetType.valueOf(typeProperty.getValue().toUpperCase(
Locale.ROOT)));
}
private double getDonePercentForWidgetType(WidgetType widgetType) {
return progress
.getDonePercent(widgetType);
}
public void setBounds(int x, int y, int side) {
setBounds(x, y, side, side);
}
@Override
public final void paintComponent(Graphics brush) {
super.paintComponent(brush);
((Graphics2D)brush).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
setVisible(visibleProperty.isEnabled());
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
Color currentColor = brush.getColor();
brush.setColor(WIDGET_BACKGROUND_COLOR);
brush.fillRect(1, 1, getWidth(), getHeight());
brush.setColor(currentColor);
if (visibleProperty.isDisabled() || hiddenProperty.isEnabled()) {
if(hiddenProperty.isEnabled()) {
if(this.smileyIcon != null) {
this.remove(this.smileyIcon);
this.smileyIcon = null;
}
if(this.smileyIcon2 != null) {
this.remove(this.smileyIcon2);
this.smileyIcon2 = null;
}
if (mouseOver) {
currentColor = brush.getColor();
brush.setColor(VERY_LIGHT_GRAY);
brush.fillRect(1, 1, getWidth() - 2, getHeight() - 2);
brush.setColor(currentColor);
}
if(!visibility.isStronglyColored()) {
brush.setColor(Color.LIGHT_GRAY);
}
int row = 10;
int x = (int)(getWidth() > 100 ? (int) (getWidth() * 0.4) : (int) (getWidth() * 0.1));
if(getHeight() <= 50) {
brush.drawString("Show" + ' ' + getHumanName(), x, row);
} else {
brush.drawString("Show", x, row);
row = row + 20;
String[] nameArray = getHumanName().split(" ");
for(int i = 0; i< nameArray.length; i++) {
brush.drawString(
nameArray[i],
x
, row);
row = row + 12;
}
}
}
//nothing to do
return;
}
super.setVisible(
visibility != Visibility.NONE && visibleProperty.isEnabled());
paintWidget(brush);
paintCloseIcon(brush, getWidth(), mouseOver, mouseOverCloseButton);
paintMinimizeIcon(brush, getWidth(), mouseOver, mouseOverMinimizeButton);
if (mouseOver) {
currentColor = brush.getColor();
if(visibility.isStronglyColored()) {
brush.setColor(Color.BLUE);
}
brush.drawRect(1, 1, getWidth() - 2, getHeight() - 2);
brush.setColor(currentColor);
}
if (typeVisibleProperty.isEnabled() || typeProperty.getValue().equals(WidgetType.PRESENTATION.name().toLowerCase())) {
paintTypeName(brush, visibility);
}
}
private void paintTypeName(Graphics brush, Visibility visibility) {
brush.setColor(visibility.isStronglyColored() ? Color.BLUE : Color.GRAY);
if(visibility.isStronglyColored() && (getClass() == ProgressFuelGauge.class)) {
brush.setColor(Color.GRAY);
}
if(visibility.isWeaklyColored() && (getClass() == ProgressFuelGauge.class)) {
brush.setColor(Color.LIGHT_GRAY);
}
brush.setFont(FONT);
brush.drawString(progress.getWidgetType(WidgetType.valueOf(typeProperty.getValue().toUpperCase())).name(),
(int) (getWidth() * 0.5d - 20d), 15);
}
private static void paintCloseIcon(Graphics brush, int width,
boolean mouseOver, boolean mouseOverCloseButton) {
if (!mouseOver) {
//nothing to do
return;
}
// if(!mouseOverCloseButton) {
// //nothing to do
// return;
// }
brush.setColor(mouseOverCloseButton ? CLOSE_BUTTON_BACKGROUND_COLOR_MOUSE_OVER_CLOSE_ICON :
CLOSE_OR_MINIMIZE_BUTTON_BACKGROUND_COLOR);
// if(!mouseOverCloseButton) {
// brush.drawRect(width - CLOSE_BUTTON_SIDE - 1, 0 + 1, CLOSE_BUTTON_SIDE,
// CLOSE_BUTTON_SIDE);
// brush.drawRect(width - CLOSE_BUTTON_SIDE - 1+1, 0 + 1 +1, CLOSE_BUTTON_SIDE - 2,
// CLOSE_BUTTON_SIDE - 2);
// return;
// }
brush.fillOval(width - CLOSE_OR_MINIMIZE_BUTTON_SIDE - 1, 0 + 1,
CLOSE_OR_MINIMIZE_BUTTON_SIDE,
CLOSE_OR_MINIMIZE_BUTTON_SIDE);
brush.setColor(CLOSE_BUTTON_FOREGROUND_COLOR);
Graphics2D brush2d = (Graphics2D) brush;
brush2d.setStroke(new BasicStroke(2f));
int offset = 6;
brush.drawLine(width - CLOSE_OR_MINIMIZE_BUTTON_SIDE - 1 + offset, 0 + 1 + offset,
width - 0 * CLOSE_OR_MINIMIZE_BUTTON_SIDE - 1 - offset,
0 + CLOSE_OR_MINIMIZE_BUTTON_SIDE + 1 - offset);
brush.drawLine(width - CLOSE_OR_MINIMIZE_BUTTON_SIDE - 1 + offset,
0 + CLOSE_OR_MINIMIZE_BUTTON_SIDE + 1 - offset,
width - 0 * CLOSE_OR_MINIMIZE_BUTTON_SIDE - 1 - offset, 0 + 1 + offset);
}
private static void paintMinimizeIcon(Graphics brush, int width,
boolean mouseOver, boolean mouseOverMinimizeButton) {
if (!mouseOver) {
//nothing to do
return;
}
brush.setColor(mouseOverMinimizeButton ? MINIMIZE_BUTTON_BACKGROUND_COLOR_MOUSE_OVER_CLOSE_ICON :
CLOSE_OR_MINIMIZE_BUTTON_BACKGROUND_COLOR);
brush.fillOval(width - CLOSE_OR_MINIMIZE_BUTTON_SIDE - 1 - CLOSE_OR_MINIMIZE_BUTTON_SIDE - 1, 0 + 1,
CLOSE_OR_MINIMIZE_BUTTON_SIDE,
CLOSE_OR_MINIMIZE_BUTTON_SIDE);
brush.setColor(CLOSE_BUTTON_FOREGROUND_COLOR);
Graphics2D brush2d = (Graphics2D) brush;
brush2d.setStroke(new BasicStroke(2f));
int offset = 6;
int y = ((int)(0 + 1 + CLOSE_OR_MINIMIZE_BUTTON_SIDE / 2d)) + 2;
brush.drawLine(width - CLOSE_OR_MINIMIZE_BUTTON_SIDE - 1 - CLOSE_OR_MINIMIZE_BUTTON_SIDE
- 1 + offset, y,
width - 0 * CLOSE_OR_MINIMIZE_BUTTON_SIDE - 1 - offset - CLOSE_OR_MINIMIZE_BUTTON_SIDE
- 1,
y);
}
protected void paintWidget(Graphics g) {
}
@Override
public Property getVisibilityProperty() {
return visibilityProperty;
}
@Override
public Property getVisibilitySupportedColoredProperty() {
return visibilitySupportedColoredProperty;
}
protected void paintSmiley(Visibility visibility, Graphics2D brush, int x,
int y) {
paintSmiley(visibility, brush, x, y, false);
}
protected void paintSmiley(Visibility visibility, Graphics2D brush, int x,
int y, boolean paintBody) {
paintSmiley(visibility, brush, x, y, paintBody, -1, 1);
}
protected void paintSmiley(Visibility visibility, Graphics2D brush, int x,
int y, boolean paintBody, double customDonePercent, int smileyNumber) {
if (!shouldBeSmileyPainted()) {
if (this.smileyIcon != null) {
this.remove(smileyIcon);
this.smileyIcon = null;
}
if (this.smileyIcon2 != null) {
this.remove(smileyIcon2);
this.smileyIcon2 = null;
}
//nothing more to do
return;
}
boolean colored = smileysColoredProperty.isEnabled();
if (visibility.isGray()) {
colored = false;
}
if (!colored) {
y = y - 2;
if (this.smileyIcon != null) {
this.remove(smileyIcon);
this.smileyIcon = null;
}
if (this.smileyIcon2 != null) {
this.remove(smileyIcon2);
this.smileyIcon2 = null;
}
Color originalColor = brush.getColor();
if (!visibility.isStronglyColored()) {
brush.setColor(Color.GRAY);
}
if (visibility.isGray()) {
brush.setColor(Color.LIGHT_GRAY);
}
if (visibility.isStronglyColored()) {
brush.setColor(Color.BLACK);
}
Color currentColor = brush.getColor();
Font currentFont = brush.getFont();
brush.setColor(visibility.isStronglyColored() ? Color.WHITE
: BACKGROUND_COLOR);
brush.fillRect(
x, y,
20,
20
);
brush.setColor(currentColor);
brush.setFont(MEDIUM_FONT);
brush.drawString(
ProgressSmiley.forProgress(customDonePercent >= 0 ? customDonePercent : donePercent()).getCharacter(),
x + 1 + (getClass() == ProgressSwing.class ? -8 : 0), y + 16
);
brush.setFont(currentFont);
brush.setColor(originalColor);
}
if (colored) {
x = x + 2;
ImageIcon imageIcon = ProgressSmileyIcon
.forSmiley(ProgressSmiley.forProgress(customDonePercent >= 0 ? customDonePercent : donePercent()))
.getIcon();
if(smileyNumber < 2) {
if (this.smileyIcon != null) {
this.remove(smileyIcon);
this.smileyIcon = null;
}
this.smileyIcon = new JLabel(imageIcon);
smileyIcon.setBounds(x + (getClass() == ProgressSwing.class ? - 8 : 0), y, 15, 15);
this.add(smileyIcon);
} else {
if (this.smileyIcon2 != null) {
this.remove(smileyIcon2);
this.smileyIcon2 = null;
}
this.smileyIcon2 = new JLabel(imageIcon);
smileyIcon2.setBounds(x + (getClass() == ProgressSwing.class ? - 8 : 0), y, 15, 15);
this.add(smileyIcon2);
}
}
if(colored) {
x = x - 2;
y = y - 2;
}
if(paintBody) {
brush.drawString(BODY, x - 5 + (TimeCalcApp.IS_RUNNING_ON_LINUX && getClass() == ProgressSwing.class ? - 4 : 0), y + 26);
brush.drawString(LEGS, x - 5, y + 36);
}
}
protected boolean shouldBeSmileyPainted() {
return smileysVisibleProperty.isEnabled() && (mouseOver
|| !smileysVisibleOnlyIfMouseMovingOverProperty
.isEnabled());
}
protected boolean changedInTheLastXMilliseconds(int milliseconds) {
return (System.nanoTime() - lastUpdate) < milliseconds * 1000000;
}
protected void paintQuarterIcon(Graphics2D brush,
Visibility visibility, int totalWidth, int totalHeight) {
paintQuarterIcon(brush, visibility, totalWidth, totalHeight, -1, -1);
}
protected void paintQuarterIcon(Graphics2D brush,
Visibility visibility, int totalWidth, int totalHeight, int x, int y) {
Color currentColor = brush.getColor();
//Color currentBackgroundColor = brush.getBackground();
Font currentFont = brush.getFont();
brush.setFont(BIG_FONT);
int q = donePercent() < 0.25 ? 0 : (donePercent() < 0.5 ? 1 :
(donePercent() < 0.75 ? 2 : (donePercent() < 1.0 ? 3 : 4)));
Color color;
Color backgroundColor;
switch (visibility) {
case STRONGLY_COLORED:
backgroundColor = Color.WHITE;
break;
case WEAKLY_COLORED:
backgroundColor = Color.LIGHT_GRAY;
break;
default:
backgroundColor = Color.LIGHT_GRAY;
}
switch (q) {
case 0:
color = Battery.getColourForProgress(0.05, visibility,
mouseOver);
break;
case 1:
color = Battery.getColourForProgress(0.25, visibility,
mouseOver);
break;
case 2:
color = Battery.getColourForProgress(0.85, visibility,
mouseOver);
break;
case 3:
color = Battery.getColourForProgress(0.95, visibility,
mouseOver);
break;
case 4:
color = visibility.isStronglyColored() ? PURPLE_STRONGLY_COLORED : (visibility.isWeaklyColored() ? PURPLE_WEAKLY_COLORED : Color.GRAY);
break;
default:
color = Color.LIGHT_GRAY;
}
brush.setColor(backgroundColor);
if(x< 0 || y < 0) {
brush.fillRect(((int) (totalWidth * 0.08)),
(donePercent() < 0.5 ? totalHeight / 4 * 3
: (totalHeight / 4 * 1) + 10) + -8, 20, 20);
} else {
brush.fillRect(x, y, 20, 20);
}
brush.setColor(color);
if(x< 0 || y < 0) {
brush.drawString(
String.valueOf(q), ((int) (totalWidth * 0.13)),
(donePercent() < 0.5 ? totalHeight / 4 * 3
: (totalHeight / 4 * 1) + 10) + 10
);
} else {
brush.drawString(String.valueOf(q), x + 4, y + 18);
}
brush.setColor(currentColor);
//brush.setBackground(currentBackgroundColor);
brush.setFont(currentFont);
}
protected void paintCircleProgress(Graphics2D brush, Visibility visibility, int totalWidth, int totalHeight) {
Color currentColor = brush.getColor();
brush.setColor(
visibility.isStronglyColored() ? HIGH_STRONGLY_COLORED
: (visibility.isWeaklyColored() ? HIGH_WEAKLY_COLORED
: Color.lightGray));
double angleDouble = donePercent() * 360;
brush.fillArc(((int) (totalWidth * 1)) - 15,
totalHeight / 4 * 3 + 28,
15, 15, 90, -(int) angleDouble);
brush.setColor(
visibility.isStronglyColored() ? LIGHT_RED
: visibility.isWeaklyColored() ? ULTRA_LIGHT_RED
: BACKGROUND_COLOR);
brush.fillArc(((int) (totalWidth * 1)) - 15,
totalHeight / 4 * 3 + 28,
15, 15, 90, +(int) (360 - angleDouble));
brush.setColor(currentColor);
}
public void hideWidget() {
this.hiddenProperty.enable();
}
private String getHumanName() {
String name = getClass().getSimpleName();
StringBuilder sb = new StringBuilder();
for (char ch : name.toCharArray()) {
if (Character.isUpperCase(ch)) {
sb.append(' ').append(Character.toLowerCase(ch));
} else {
sb.append(ch);
}
}
String result = sb.toString().trim();
return result.substring(0, 1).toUpperCase() + result.substring(1, result.length());
}
}

View File

@ -0,0 +1,127 @@
package org.nanoboot.utils.timecalc.swing.common;
import org.nanoboot.utils.timecalc.app.TimeCalcException;
import org.nanoboot.utils.timecalc.entity.WidgetType;
import org.nanoboot.utils.timecalc.swing.progress.AnalogClock;
import org.nanoboot.utils.timecalc.swing.progress.battery.Battery;
import org.nanoboot.utils.timecalc.swing.progress.weather.ProgressWeather;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import java.util.Locale;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
/**
* @author pc00289
* @since 21.03.2024
*/
public class WidgetMenu extends JPopupMenu {
private final JMenuItem typeMinuteMenuItem;
private final JMenuItem typeHourMenuItem;
private final JMenuItem typeDayMenuItem;
private final JMenuItem typeWeekMenuItem;
private final JMenuItem typeMonthMenuItem;
private final JMenuItem typeYearMenuItem;
private final JMenuItem typeLifeMenuItem;
private final JMenuItem typePresentationMenuItem;
private final JMenuItem typePauseMenuItem;
private final Widget widget;
private WidgetType selectedType;
private Consumer<Object> refreshConsumer;
public WidgetMenu(Widget widget) {
this(widget, null);
}
public WidgetMenu(Widget widget, Consumer<Object> refreshConsumer) {
this.widget = widget;
this.refreshConsumer = refreshConsumer;
JMenuItem typeMenuItem = new JMenu("Type"/*,*/
/*new ImageIcon("images/newproject.png")*/);
//menuItem.setMnemonic(KeyEvent.VK_P);
//menuItem.getAccessibleContext().setAccessibleDescription("New Project");
add(typeMenuItem);
this.typeMinuteMenuItem = new JMenuItem(WidgetType.MINUTE.name());
this.typeHourMenuItem = new JMenuItem(WidgetType.HOUR.name());
this.typeDayMenuItem = new JMenuItem(WidgetType.DAY.name());
this.typeWeekMenuItem = new JMenuItem(WidgetType.WEEK.name());
this.typeMonthMenuItem = new JMenuItem(WidgetType.MONTH.name());
this.typeYearMenuItem = new JMenuItem(WidgetType.YEAR.name());
this.typeLifeMenuItem = new JMenuItem(WidgetType.LIFE.name());
this.typePresentationMenuItem = new JMenuItem(WidgetType.PRESENTATION.name());
this.typePauseMenuItem = new JMenuItem(WidgetType.PAUSE.name());
typeMenuItem.add(typeMinuteMenuItem);
typeMenuItem.add(typeHourMenuItem);
typeMenuItem.add(typeDayMenuItem);
typeMenuItem.add(typeWeekMenuItem);
typeMenuItem.add(typeMonthMenuItem);
typeMenuItem.add(typeYearMenuItem);
typeMenuItem.add(typeLifeMenuItem);
typeMenuItem.add(typePresentationMenuItem);
typeMenuItem.add(typePauseMenuItem);
BiConsumer<JMenuItem, WidgetType> typeActionCreator = (m,w) -> {
m.addActionListener(e -> {
if(((widget instanceof Battery) || (widget instanceof AnalogClock) || (widget instanceof ProgressWeather)) && !widget.typeProperty.getValue().equals(w.name().toLowerCase(Locale.ROOT))) {
//nothing to do
return;
}
markAsSelected(w);
widget.typeProperty.setValue(w.name().toLowerCase(Locale.ROOT));
});
};
typeActionCreator.accept(typeMinuteMenuItem, WidgetType.MINUTE);
typeActionCreator.accept(typeHourMenuItem, WidgetType.HOUR);
typeActionCreator.accept(typeDayMenuItem, WidgetType.DAY);
typeActionCreator.accept(typeWeekMenuItem, WidgetType.WEEK);
typeActionCreator.accept(typeMonthMenuItem, WidgetType.MONTH);
typeActionCreator.accept(typeYearMenuItem, WidgetType.YEAR);
typeActionCreator.accept(typeLifeMenuItem, WidgetType.LIFE);
typeActionCreator.accept(typePresentationMenuItem, WidgetType.PRESENTATION);
typeActionCreator.accept(typePauseMenuItem, WidgetType.PAUSE);
//if(!aClass.getSimpleName().contains("Battery")) {
add(typeMenuItem);
//}
JMenuItem hideMenuItem = new JMenuItem("Hide");
add(hideMenuItem);
hideMenuItem.addActionListener(e -> {
this.widget.hideWidget();
});
}
public void markAsSelected(WidgetType widgetType) {
this.typeMinuteMenuItem.setText(WidgetType.MINUTE.name());
this.typeHourMenuItem .setText(WidgetType.HOUR.name());
this.typeDayMenuItem.setText(WidgetType.DAY.name());
this.typeWeekMenuItem.setText(WidgetType.WEEK.name());
this.typeMonthMenuItem.setText(WidgetType.MONTH.name());
this.typeYearMenuItem.setText(WidgetType.YEAR.name());
this.typeLifeMenuItem.setText(WidgetType.LIFE.name());
this.typePresentationMenuItem.setText(WidgetType.PRESENTATION.name());
this.typePauseMenuItem.setText(WidgetType.PAUSE.name());
switch (widgetType) {
case MINUTE: typeMinuteMenuItem.setText(typeMinuteMenuItem.getText() + " (*)");break;
case HOUR: typeHourMenuItem.setText(typeHourMenuItem.getText() + " (*)");break;
case DAY: typeDayMenuItem.setText(typeDayMenuItem.getText() + " (*)");break;
case WEEK: typeWeekMenuItem.setText(typeWeekMenuItem.getText() + " (*)");break;
case MONTH: typeMonthMenuItem.setText(typeMonthMenuItem.getText() + " (*)");break;
case YEAR: typeYearMenuItem.setText(typeYearMenuItem.getText() + " (*)");break;
case LIFE: typeLifeMenuItem.setText(typeLifeMenuItem.getText() + " (*)");break;
case PRESENTATION: typePresentationMenuItem.setText(typePresentationMenuItem.getText() + " (*)");break;
case PAUSE: typePauseMenuItem.setText(typePauseMenuItem.getText() + " (*)");break;
default: throw new TimeCalcException("Unsupported WidgetType: " + widgetType);
}
this.selectedType = widgetType;
}
public void refresh () {
if(refreshConsumer == null) {
//nothing to do
return;
}
this.refreshConsumer.accept(null);
}
}

View File

@ -0,0 +1,81 @@
package org.nanoboot.utils.timecalc.swing.common;
import org.nanoboot.utils.timecalc.app.TimeCalcConfiguration;
import org.nanoboot.utils.timecalc.swing.controls.TTabbedPane;
import org.nanoboot.utils.timecalc.persistence.api.ActivityRepositoryApi;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
*
* @author robertvokac
*/
public class YearPanel extends JPanel {
private final String year;
private final Map<String, MonthPanel> months;
private final TTabbedPane tp;
private final ActivityRepositoryApi activityRepository;
private final TimeCalcConfiguration timeCalcConfiguration;
private boolean loaded = false;
public YearPanel(String yearIn, ActivityRepositoryApi activityRepository, TimeCalcConfiguration timeCalcConfiguration) {
super();
this.year = yearIn;
this.months = new HashMap<>();
this.timeCalcConfiguration = timeCalcConfiguration;
setLayout(null);
this.tp = new TTabbedPane();
add(tp);
tp.setBounds(0, 0, 1450, 700);
this.activityRepository = activityRepository;
ChangeListener changeListener = new ChangeListener() {
private boolean secondOrLaterChange = false;
public void stateChanged(ChangeEvent changeEvent) {
if(!secondOrLaterChange) {
secondOrLaterChange = true;
return;
}
JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent.getSource();
int index = sourceTabbedPane.getSelectedIndex();
MonthPanel monthPanel =
months.get(sourceTabbedPane.getTitleAt(index));
monthPanel.load();
monthPanel.getDayPanel("1").load();
}
};
tp.addChangeListener(changeListener);
}
public void load() {
if(loaded) {
//nothing to do
return;
}
System.out.println("Loaded: " + year);
for (int month = 1; month <= 12; month++) {
final String monthS = String.valueOf(month);
MonthPanel monthPanel = new MonthPanel(year, String.valueOf(month), activityRepository, timeCalcConfiguration);
tp.add(String.valueOf(month), monthPanel);
months.put(monthS, monthPanel);
}
loaded = true;
}
public void setSelectedMonth(String month) {
tp.switchTo(month);
}
public MonthPanel getMonthPanel(String month) {
return months.get(month);
}
}

View File

@ -0,0 +1,54 @@
package org.nanoboot.utils.timecalc.swing.controls;
import lombok.Getter;
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
* @since 21.02.2024
*/
public class ComponentRegistry<T extends Component> {
@Getter
private final Set<T> set = new HashSet<>();
public ComponentRegistry() {
}
public void add(T component) {
this.set.add(component);
}
public void addAll(T... component) {
for (T c : component) {
add(c);
}
}
public void setVisible(boolean b) {
setVisible(null, b);
}
public void setVisible(Predicate<Component> predicate, boolean b) {
for (T c : set) {
if (c instanceof TButton || c instanceof TTextField || c instanceof TLabel || c instanceof TCheckBox) {
if (!MainWindow.hideShowFormsCheckBox.isSelected() && b) {
continue;
}
}
if (predicate != null) {
if (!predicate.test(c)) {
continue;
}
}
c.setVisible(b);
}
}
}

View File

@ -0,0 +1,31 @@
package org.nanoboot.utils.timecalc.swing.controls;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
/**
* @author pc00289
* @since 14.03.2024
*/
public interface MouseClickedListener extends MouseListener {
@Override
default void mousePressed(MouseEvent e) {
}
@Override
default void mouseReleased(MouseEvent e) {
}
@Override
default void mouseEntered(MouseEvent e) {
}
@Override
default void mouseExited(MouseEvent e) {
}
}

View File

@ -0,0 +1,22 @@
package org.nanoboot.utils.timecalc.swing.controls;
import java.awt.Insets;
/**
* @author pc00289
* @since 11.03.2024
*/
public class SmallTButton extends TButton {
private static final Insets INSETS = new Insets(1, 1, 1, 1);
public SmallTButton(String s) {
super(s, 15, 15);
//setFont(SwingUtils.SMALL_FONT);
setMargin(INSETS);
}
public SmallTButton(char character) {
this(String.valueOf(character));
}
}

View File

@ -0,0 +1,107 @@
package org.nanoboot.utils.timecalc.swing.controls;
import org.nanoboot.utils.timecalc.app.GetProperty;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.utils.property.BooleanProperty;
import org.nanoboot.utils.timecalc.utils.property.Property;
import org.nanoboot.utils.timecalc.utils.property.StringProperty;
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;
import static org.nanoboot.utils.timecalc.swing.common.SwingUtils.INSETS;
/**
* @author Robert Vokac
* @since 21.02.2024
*/
public class TButton extends JButton implements GetProperty {
private static final int BUTTON_WIDTH = 80;
private static final int BUTTON_HEIGHT = 30;
public final BooleanProperty visibilitySupportedColoredProperty
= new BooleanProperty("visibilitySupportedColoredProperty", true);
public final BooleanProperty visibleProperty
= new BooleanProperty("visibleProperty", true);
public StringProperty visibilityProperty
= new StringProperty("visibilityProperty",
Visibility.STRONGLY_COLORED.name());
private Color originalBackground;
private Color originalForeground;
private int customWidth = 0;
private int customHeight = 0;
public TButton(String label) {
this(label, 0);
}
public TButton(String label, int customWidth) {
this(label, customWidth, 0);
}
public TButton(String label, int customWidth, int customHeight) {
super(label);
this.customWidth = customWidth;
this.customHeight = customHeight;
setMargin(INSETS);
new Timer(100, e -> {
if (!MainWindow.hideShowFormsCheckBox.isSelected()) {
setVisible(false);
return;
} else {
setVisible(true);
}
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
setVisible(visibility.isNotNone() && visibleProperty.isEnabled());
if (!visibility.isStronglyColored() || visibility.isGray()) {
setBackground(MainWindow.BACKGROUND_COLOR);
setForeground(MainWindow.FOREGROUND_COLOR);
} else {
setOriginalBackground();
setOriginalForeground();
}
}).start();
}
public void setBounds(int x, int y) {
setBounds(x, y, customWidth == 0 ? BUTTON_WIDTH : customWidth, customHeight == 0 ? BUTTON_HEIGHT : customHeight);
this.originalBackground = getBackground();
this.originalForeground = getForeground();
}
public void setOriginalBackground() {
this.setBackground(originalBackground);
}
public void setOriginalForeground() {
this.setForeground(originalForeground);
}
public void setBoundsFromLeft(JComponent jComponent) {
setBounds(jComponent.getX() + jComponent.getWidth() + SwingUtils.MARGIN,
jComponent.getY());
}
public void setBoundsFromTop(JComponent jComponent) {
setBoundsFromTop(jComponent, 1);
}
public void setBoundsFromTop(JComponent jComponent, int marginCount) {
setBounds(SwingUtils.MARGIN, jComponent.getY()
+ jComponent.getHeight()
+ marginCount * SwingUtils.MARGIN);
}
@Override
public Property getVisibilityProperty() {
return visibilityProperty;
}
@Override
public Property getVisibilitySupportedColoredProperty() {
return visibilitySupportedColoredProperty;
}
}

View File

@ -0,0 +1,116 @@
package org.nanoboot.utils.timecalc.swing.controls;
import org.nanoboot.utils.timecalc.app.GetProperty;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.utils.property.BooleanProperty;
import org.nanoboot.utils.timecalc.utils.property.Property;
import org.nanoboot.utils.timecalc.utils.property.StringProperty;
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
* @since 21.02.2024
*/
public class TCheckBox extends JCheckBox implements GetProperty {
private static final int WIDTH = 100;
private static final int HEIGHT = 30;
private Color originalBackground;
private Color originalForeground;
private int customWidth = 0;
public TCheckBox(String text) {
this(text, 0);
}
public TCheckBox(String text, int customWidth) {
this(text, false);
this.customWidth = customWidth;
}
public final BooleanProperty visibilitySupportedColoredProperty
= new BooleanProperty("visibilitySupportedColoredProperty", true);
public final BooleanProperty visibleProperty
= new BooleanProperty("visibleProperty", true);
public StringProperty visibilityProperty
= new StringProperty("visibilityProperty",
Visibility.STRONGLY_COLORED.name());
public TCheckBox(String text, boolean b) {
super(text, b);
valueProperty.setValue(b);
addActionListener(e -> valueProperty.setValue(isSelected()));
valueProperty.addListener(e
-> {
if (valueProperty.getValue().equals(getText())) {
setSelected(valueProperty.isEnabled());
}
});
new Timer(100, e -> {
if (!MainWindow.hideShowFormsCheckBox.isSelected()) {
setVisible(false);
return;
} else {
//setVisible(true);
}
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
setVisible(visibility.isNotNone() && visibleProperty.isEnabled());
if (!visibility.isStronglyColored() || visibility.isGray()) {
setBackground(MainWindow.BACKGROUND_COLOR);
setForeground(MainWindow.FOREGROUND_COLOR);
} else {
setOriginalBackground();
setOriginalForeground();
}
}).start();
}
public final BooleanProperty valueProperty = new BooleanProperty("");
public void setBounds(int x, int y) {
setBounds(x, y, customWidth == 0 ? WIDTH : customWidth, HEIGHT);
this.originalBackground = getBackground();
this.originalForeground = getForeground();
}
public void setBoundsFromLeft(JComponent jComponent) {
setBounds(jComponent.getX() + jComponent.getWidth() + SwingUtils.MARGIN,
jComponent.getY());
}
public void setBoundsFromTop(JComponent jComponent) {
setBoundsFromTop(jComponent, 1);
}
public void setBoundsFromTop(JComponent jComponent, int marginCount) {
setBounds(SwingUtils.MARGIN, jComponent.getY()
+ jComponent.getHeight()
+ marginCount * SwingUtils.MARGIN);
}
public void setOriginalBackground() {
this.setBackground(originalBackground);
}
public void setOriginalForeground() {
this.setForeground(originalForeground);
}
@Override
public Property getVisibilityProperty() {
return visibilityProperty;
}
@Override
public Property getVisibilitySupportedColoredProperty() {
return visibilitySupportedColoredProperty;
}
}

View File

@ -0,0 +1,108 @@
package org.nanoboot.utils.timecalc.swing.controls;
import org.nanoboot.utils.timecalc.app.GetProperty;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.utils.property.BooleanProperty;
import org.nanoboot.utils.timecalc.utils.property.Property;
import org.nanoboot.utils.timecalc.utils.property.StringProperty;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.Timer;
import java.awt.Color;
import org.nanoboot.utils.timecalc.app.TimeCalcApp;
import org.nanoboot.utils.timecalc.swing.windows.MainWindow;
import org.nanoboot.utils.timecalc.swing.common.SwingUtils;
/**
* @author Robert Vokac
* @since 21.02.2024
*/
public class TLabel extends JLabel implements GetProperty {
private static final int WIDTH = 60;
private static final int HEIGHT = 30;
private int customWidth = 0;
private Color originalBackground;
private Color originalForeground;
public final BooleanProperty visibilitySupportedColoredProperty
= new BooleanProperty("visibilitySupportedColoredProperty", true);
public final BooleanProperty visibleProperty
= new BooleanProperty("visibleProperty", true);
public StringProperty visibilityProperty
= new StringProperty("visibilityProperty",
Visibility.STRONGLY_COLORED.name());
public TLabel(String text) {
this(text, 0);
}
public TLabel(String text, int customWidth) {
super(text);
this.customWidth = customWidth;
if(TimeCalcApp.IS_RUNNING_ON_LINUX) {
setFont(SwingUtils.LINUX_FONT);
}
new Timer(100, e -> {
if (!MainWindow.hideShowFormsCheckBox.isSelected()) {
setVisible(false);
return;
} else {
//setVisible(true);
}
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
setVisible(visibility.isNotNone() && visibleProperty.isEnabled());
if (!visibility.isStronglyColored() || visibility.isGray()) {
setBackground(MainWindow.BACKGROUND_COLOR);
setForeground(MainWindow.FOREGROUND_COLOR);
} else {
setOriginalBackground();
setOriginalForeground();
}
}).start();
}
public void setBounds(int x, int y) {
setBounds(x, y, customWidth == 0 ? WIDTH : customWidth, HEIGHT);
this.originalBackground = getBackground();
this.originalForeground = getForeground();
}
public void setBoundsFromLeft(JComponent jComponent) {
setBoundsFromLeft(jComponent, 0);
}
public void setBoundsFromLeft(JComponent jComponent, int additionalX) {
setBounds(jComponent.getX() + jComponent.getWidth() + SwingUtils.MARGIN + additionalX,
jComponent.getY());
}
public void setBoundsFromTop(JComponent jComponent) {
setBoundsFromTop(jComponent, 1);
}
public void setBoundsFromTop(JComponent jComponent, int marginCount) {
setBounds(SwingUtils.MARGIN, jComponent.getY()
+ jComponent.getHeight()
+ marginCount * SwingUtils.MARGIN);
}
public void setOriginalBackground() {
this.setBackground(originalBackground);
}
public void setOriginalForeground() {
this.setForeground(originalForeground);
}
@Override
public Property getVisibilityProperty() {
return visibilityProperty;
}
@Override
public Property getVisibilitySupportedColoredProperty() {
return visibilitySupportedColoredProperty;
}
}

View File

@ -0,0 +1,40 @@
package org.nanoboot.utils.timecalc.swing.controls;
import javax.swing.JMenuItem;
/**
* @author pc00289
* @since 21.03.2024
*/
public class TMenuItem extends JMenuItem {
private static final String ENABLED = " (*)";
private boolean enabledMenuItem = false;
public TMenuItem(String text) {
super(text);
}
public void disableMenuItem() {
if(getText().endsWith(ENABLED)) {
setText(getText().substring(0, getText().length() - ENABLED.length()));
}
enabledMenuItem = false;
}
public void enableMenuItem() {
if(!getText().endsWith(ENABLED)) {
setText(getText() + ENABLED);
}
enabledMenuItem = true;
}
public void setEnabledMenuItem(boolean value) {
if(value) {enableMenuItem();} else {
disableMenuItem();
}
enabledMenuItem = value;
}
public void flip() {
setEnabledMenuItem(!enabledMenuItem);
}
}

View File

@ -0,0 +1,28 @@
/*
* 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.controls;
import javax.swing.JTabbedPane;
/**
*
* @author robertvokac
*/
public class TTabbedPane extends JTabbedPane {
public int getIndexFor(String title) {
for (int i = 0; i < getTabCount(); i++) {
if (getTitleAt(i).equals(title)) {
return i;
}
}
return -1;
}
public void switchTo(String title) {
this.setSelectedIndex(getIndexFor(title));
}
}

View File

@ -0,0 +1,222 @@
package org.nanoboot.utils.timecalc.swing.controls;
import lombok.Getter;
import lombok.Setter;
import org.nanoboot.utils.timecalc.app.GetProperty;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.swing.common.SwingUtils;
import org.nanoboot.utils.timecalc.swing.windows.MainWindow;
import org.nanoboot.utils.timecalc.utils.common.TTime;
import org.nanoboot.utils.timecalc.utils.property.BooleanProperty;
import org.nanoboot.utils.timecalc.utils.property.ChangeListener;
import org.nanoboot.utils.timecalc.utils.property.Property;
import org.nanoboot.utils.timecalc.utils.property.StringProperty;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.Timer;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.Color;
import java.awt.Font;
import org.nanoboot.utils.timecalc.app.TimeCalcApp;
import static org.nanoboot.utils.timecalc.swing.common.SwingUtils.INSETS;
/**
* @author Robert Vokac
* @since 21.02.2024
*/
public class TTextField extends JTextField implements GetProperty {
private static final int WIDTH = 50;
private static final int HEIGHT = 30;
private int customWidth = 0;
private Color originalBackground;
private Color originalForeground;
public final BooleanProperty visibilitySupportedColoredProperty
= new BooleanProperty("visibilitySupportedColoredProperty", true);
public final BooleanProperty visibleProperty
= new BooleanProperty("visibleProperty", true);
public StringProperty visibilityProperty
= new StringProperty("visibilityProperty",
Visibility.STRONGLY_COLORED.name());
public final StringProperty valueProperty = new StringProperty();
@Getter
@Setter
private ChangeListener vetoableChangeListener = null;
@Getter
@Setter
private boolean editingOnlyInDialog = false;
public TTextField() {
this("", 0);
}
public TTextField(String s) {
this(s, 0);
}
public TTextField(String s, int customWidth) {
this(s, customWidth, false);
}
public TTextField(String s, int customWidth, boolean editingOnlyInDialog) {
this(s, customWidth, editingOnlyInDialog, null);
}
public TTextField(String s, int customWidth, boolean editingOnlyInDialog, ChangeListener vetoableChangeListener) {
super(s);
setMargin(INSETS);
setEditingOnlyInDialog(editingOnlyInDialog);
setVetoableChangeListener(vetoableChangeListener);
this.customWidth = customWidth;
valueProperty.setValue(s);
if(TimeCalcApp.IS_RUNNING_ON_LINUX) {
setFont(SwingUtils.LINUX_FONT);
}
new Timer(100, e -> {
if (editingOnlyInDialog) {
setEditable(false);
}
}).start();
getDocument()
.addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
update(e);
}
public void removeUpdate(DocumentEvent e) {
update(e);
}
public void insertUpdate(DocumentEvent e) {
update(e);
}
private void update(DocumentEvent e) {
valueProperty.setValue(getText());
}
});
addMouseListener((MouseClickedListener) f -> {
if(editingOnlyInDialog) {
String result = (String) JOptionPane.showInputDialog(
null,
"Select new value",
"New value",
JOptionPane.PLAIN_MESSAGE,
null,
null,
getText()
);
if (result != null) {
String oldText = getText();
boolean vetoed = false;
if(vetoableChangeListener != null) {
try {
vetoableChangeListener
.changed(null, oldText, result);
} catch (Exception e) {
e.printStackTrace();
System.err.println(e.getMessage());
vetoed = true;
}
}
if(!vetoed) {
TTime tTime = new TTime(result);
result = tTime.toString().substring(0, tTime.isNegative() ? 6 : 5);
setText(result);
valueProperty.setValue(result);
}
}
}});
valueProperty.addListener(e
-> {
if (!valueProperty.getValue().equals(getText())) {
setText(valueProperty.getValue());
}
});
new Timer(100, e -> {
if (!MainWindow.hideShowFormsCheckBox.isSelected()) {
setVisible(false);
return;
} else {
//setVisible(true);
}
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
setVisible(visibility.isNotNone() && visibleProperty.isEnabled());
if (!visibility.isStronglyColored() || visibility.isGray()) {
setBackground(MainWindow.BACKGROUND_COLOR);
setForeground(MainWindow.FOREGROUND_COLOR);
} else {
setOriginalBackground();
setOriginalForeground();
}
}).start();
}
public void setBounds(int x, int y) {
setBounds(x, y, customWidth == 0 ? WIDTH : customWidth, HEIGHT);
this.originalBackground = getBackground();
this.originalForeground = getForeground();
}
public void setBoundsFromLeft(JComponent jComponent) {
setBoundsFromLeft(jComponent, 0);
}
public void setBoundsFromLeftWithAdditionalX(JComponent jComponent, int additionalX) {
setBounds(jComponent.getX() + jComponent.getWidth() + SwingUtils.MARGIN + additionalX,
jComponent.getY() + 0);
}
public void setBoundsFromLeft(JComponent jComponent, int additionalY) {
setBounds(jComponent.getX() + jComponent.getWidth() + SwingUtils.MARGIN,
jComponent.getY() + additionalY);
}
public void setBoundsFromTop(JComponent jComponent) {
setBoundsFromTop(jComponent, 1);
}
public void setBoundsFromTop(JComponent jComponent, int marginCount) {
setBounds(SwingUtils.MARGIN, jComponent.getY()
+ jComponent.getHeight()
+ marginCount * SwingUtils.MARGIN);
}
public void setOriginalBackground() {
this.setBackground(originalBackground);
}
public void setOriginalForeground() {
if(!autoManageForeground) {
//nothing to do
return;
}
this.setForeground(originalForeground);
}
@Getter @Setter
private boolean autoManageForeground = true;
@Override
public Property getVisibilityProperty() {
return visibilityProperty;
}
@Override
public Property getVisibilitySupportedColoredProperty() {
return visibilitySupportedColoredProperty;
}
public TTime asTTime() {
return new TTime(valueProperty.getValue());
}
}

View File

@ -0,0 +1,47 @@
package org.nanoboot.utils.timecalc.swing.controls;
import org.nanoboot.utils.timecalc.utils.property.IntegerProperty;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.Timer;
import java.awt.Component;
import java.awt.HeadlessException;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
/**
* @author Robert Vokac
* @since 21.02.2024
*/
public class TWindow extends JFrame {
public IntegerProperty widthProperty = new IntegerProperty("widthProperty");
public IntegerProperty heightProperty = new IntegerProperty("heightProperty");
public TWindow() throws HeadlessException {
addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
widthProperty.setValue(getWidth());
heightProperty.setValue(getHeight());
}
});
widthProperty.addListener(e -> {
if (widthProperty.getValue() > 100 /*&& widthProperty.getValue() % 10 == 0*/) {
setSize(widthProperty.getValue(), getHeight());
}
});
heightProperty.addListener(e -> {
if (heightProperty.getValue() > 100 /*&& widthProperty.getValue() % 10 == 0*/) {
setSize(getWidth(), heightProperty.getValue());
}
});
}
public Component[] addAll(Component... comp) {
for (Component c : comp) {
add(c);
}
return comp;
}
}

View File

@ -0,0 +1,526 @@
package org.nanoboot.utils.timecalc.swing.progress;
import org.nanoboot.utils.timecalc.app.TimeCalcProperty;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.entity.WidgetType;
import org.nanoboot.utils.timecalc.swing.common.SwingUtils;
import org.nanoboot.utils.timecalc.swing.common.Widget;
import org.nanoboot.utils.timecalc.swing.controls.TMenuItem;
import org.nanoboot.utils.timecalc.swing.progress.battery.Battery;
import org.nanoboot.utils.timecalc.utils.common.DateFormats;
import org.nanoboot.utils.timecalc.utils.common.TTime;
import org.nanoboot.utils.timecalc.utils.property.BooleanProperty;
import org.nanoboot.utils.timecalc.utils.property.IntegerProperty;
import org.nanoboot.utils.timecalc.utils.property.StringProperty;
import javax.swing.JFrame;
import javax.swing.JMenu;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.function.Consumer;
import javax.swing.JMenuItem;
import org.nanoboot.utils.timecalc.entity.Progress;
//https://kodejava.org/how-do-i-write-a-simple-analog-clock-using-java-2d/
public class AnalogClock extends Widget {
public static final Color COLOR_FOR_MILLISECOND_HAND_STRONGLY_COLORED
= new Color(226,
126, 19);
public final BooleanProperty borderVisibleProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_BORDER_VISIBLE
.getKey());
public final BooleanProperty borderOnlyHoursProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_BORDER_ONLY_HOURS
.getKey());
public final BooleanProperty numbersVisibleProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_NUMBERS_VISIBLE
.getKey());
public final BooleanProperty circleVisibleProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_CIRCLE_VISIBLE
.getKey());
public final BooleanProperty circleStrongBorderProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_CIRCLE_STRONG_BORDER
.getKey());
public final BooleanProperty centreCircleVisibleProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_CENTRE_CIRCLE_VISIBLE
.getKey());
public final StringProperty centreCircleBorderColorProperty
= new StringProperty(TimeCalcProperty.CLOCK_CIRCLE_BORDER_COLOR
.getKey());
public final BooleanProperty centreCircleColoredProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_CENTRE_CIRCLE_COLORED
.getKey());
public final BooleanProperty progressVisibleOnlyIfMouseMovingOverProperty
= new BooleanProperty(
TimeCalcProperty.CLOCK_PROGRESS_VISIBLE_ONLY_IF_MOUSE_MOVING_OVER
.getKey());
public final BooleanProperty dateVisibleOnlyIfMouseMovingOverProperty
= new BooleanProperty(
TimeCalcProperty.CLOCK_DATE_VISIBLE_ONLY_IF_MOUSE_MOVING_OVER
.getKey());
public BooleanProperty circleProgressVisibleProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_CIRCLE_PROGRESS_VISIBLE
.getKey(), true);
public IntegerProperty startHourProperty
= new IntegerProperty("startHourProperty");
public IntegerProperty startMinuteProperty
= new IntegerProperty("startMinuteProperty");
public IntegerProperty endHourProperty
= new IntegerProperty("endHourProperty");
public IntegerProperty endMinuteProperty
= new IntegerProperty("endMinuteProperty");
public IntegerProperty yearProperty = new IntegerProperty("yearProperty");
public IntegerProperty monthProperty = new IntegerProperty("monthProperty");
public IntegerProperty dayProperty = new IntegerProperty("dayProperty");
public IntegerProperty hourProperty = new IntegerProperty("hourProperty");
public IntegerProperty minuteProperty
= new IntegerProperty("minuteProperty");
public IntegerProperty secondProperty
= new IntegerProperty("secondProperty");
public IntegerProperty millisecondProperty
= new IntegerProperty("millisecondProperty");
public IntegerProperty dayOfWeekProperty
= new IntegerProperty("dayOfWeekProperty");
public BooleanProperty hourEnabledProperty
= new BooleanProperty("hourEnabledProperty", true);
public BooleanProperty minuteEnabledProperty
= new BooleanProperty("minuteEnabledProperty", true);
public BooleanProperty secondEnabledProperty
= new BooleanProperty("secondEnabledProperty", true);
public BooleanProperty millisecondEnabledProperty
= new BooleanProperty("millisecondEnabledProperty", false);
public BooleanProperty handsLongProperty
= new BooleanProperty("handsLongProperty", true);
public BooleanProperty handsColoredProperty
= new BooleanProperty("handsColoredProperty", true);
public final BooleanProperty smileyVisibleProperty = new BooleanProperty("smileyVisibleProperty");
public final BooleanProperty percentProgressVisibleProperty = new BooleanProperty("percentProgressVisibleProperty");
private Color customCircleColor = null;
private double dayProgress;
private TMenuItem millisecondHandMenuItem;
private TMenuItem secondHandMenuItem;
private TMenuItem minuteHandMenuItem;
private TMenuItem hourHandMenuItem;
private List<JMenuItem> menuItems = null;
public AnalogClock() {
typeProperty.setValue(WidgetType.DAY.name().toLowerCase(Locale.ROOT));
setPreferredSize(new Dimension(200, 200));
centreCircleBorderColorProperty.addListener(property
-> customCircleColor = SwingUtils.getColorFromString(
centreCircleBorderColorProperty.getValue()));
}
private int computeStartAngle() {
return computeAngle(hourProperty.getValue(), minuteProperty.getValue());
}
private int computeEndAngle() {
return computeAngle(endHourProperty.getValue(), endMinuteProperty.getValue());
}
private int computeAngle(TTime TTime) {
if (TTime.getHour() > 12) {
TTime.setHour(TTime.getHour() - 12);
}
return computeAngle(TTime.getHour(), TTime.getMinute());
}
private int computeAngle(int hour, int minute) {
return (int) ((hour + minute / 60d) / 12d
* 360d);
}
public static void main(String[] args) {
JFrame window = new JFrame("Analog Clock");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
AnalogClock clock
= new AnalogClock();
clock.startHourProperty.setValue(6);
clock.startMinuteProperty.setValue(30);
clock.endHourProperty.setValue(19);
clock.endMinuteProperty.setValue(0);
window.add(clock);
window.pack();
Time time = new Time();
time.allowCustomValuesProperty.setValue(true);
clock.dayProperty.bindTo(time.dayProperty);
clock.monthProperty.bindTo(time.monthProperty);
clock.yearProperty.bindTo(time.yearProperty);
clock.hourProperty.bindTo(time.hourProperty);
clock.minuteProperty.bindTo(time.minuteProperty);
clock.secondProperty.bindTo(time.secondProperty);
clock.millisecondProperty.bindTo(time.millisecondProperty);
clock.dayOfWeekProperty.bindTo(time.dayOfWeekProperty);
clock.visibilityProperty.setValue(Visibility.GRAY.name());
window.setVisible(true);
// window.addKeyListener(new KeyAdapter() {
// // Key Pressed method
// public void keyPressed(KeyEvent e) {
// if (e.getKeyCode() == KeyEvent.VK_UP) {
// clock.startAngle_++;
// }
// if (e.getKeyCode() == KeyEvent.VK_DOWN) {
// clock.startAngle_--;
// }
//
// if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
// clock.arcAngle_++;
// }
// if (e.getKeyCode() == KeyEvent.VK_LEFT) {
// clock.arcAngle_--;
// }
// }
// });
}
@Override
public void paintWidget(Graphics g) {
TTime start = new TTime(this.startHourProperty.getValue(), this.startMinuteProperty.getValue());
TTime end = new TTime(this.endHourProperty.getValue(), this.endMinuteProperty.getValue());
TTime now = new TTime(this.hourProperty.getValue(), this.minuteProperty.getValue());
int startMS = start.toTotalMilliseconds();
int endMS = end.toTotalMilliseconds();
int nowMS = now.toTotalMilliseconds();
int total = endMS - startMS;
int done = nowMS - startMS;
double progress_ = ((double) done) / ((double) total);
this.dayProgress = progress_;
//System.out.println("clock.handsLongProperty=" + handsLongProperty.isEnabled());
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
Graphics2D brush = (Graphics2D) g;
brush.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
this.side = Math.min(getWidth(), getHeight());
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
int millisecond = millisecondProperty.getValue();
int second = secondProperty.getValue();
int minute = minuteProperty.getValue();
int hour = hourProperty.getValue();
if (customCircleColor == null) {
customCircleColor = SwingUtils.getColorFromString(
centreCircleBorderColorProperty.getValue());
}
if ((mouseOver || progressVisibleOnlyIfMouseMovingOverProperty
.isDisabled()) && visibility.isStronglyColored()) {
Color currentColor = brush.getColor();
brush.setColor(Battery.getColourForProgress(progress_, Visibility.WEAKLY_COLORED, mouseOver));
int startAngle = computeStartAngle();
brush.fillArc(0, 0, side, side, -startAngle + 90,
startAngle - computeEndAngle());
//System.out.println("ANGLES: " + startAngle + " " + endAngle + " " + angleDiff );
brush.setColor(currentColor);
}
//
if (millisecondEnabledProperty.isEnabled() && secondEnabledProperty
.isEnabled() && minuteEnabledProperty.isEnabled()
&& hourEnabledProperty.isEnabled()) {
drawHand(brush, side / 2 - 10, millisecond / 1000.0, 1.0f,
COLOR_FOR_MILLISECOND_HAND_STRONGLY_COLORED, visibility);
if (handsLongProperty.isEnabled()) {
drawHand(brush, (side / 2 - 10) / 4,
(millisecond > 500 ? millisecond - 500
: millisecond + 500) / 1000.0, 1.0f,
COLOR_FOR_MILLISECOND_HAND_STRONGLY_COLORED,
visibility);
}
}
if (secondEnabledProperty.isEnabled() && minuteEnabledProperty
.isEnabled() && hourEnabledProperty.isEnabled()) {
drawHand(brush, side / 2 - 10, second / 60.0, 0.5f, Color.RED,
visibility);
if (handsLongProperty.isEnabled()) {
drawHand(brush, (side / 2 - 10) / 4,
(second > 30 ? second - 30 : second + 30) / 60.0, 0.5f,
Color.RED, visibility);
}
}
if (minuteEnabledProperty.isEnabled() && hourEnabledProperty
.isEnabled()) {
double minutes = minute / 60.0 + second / 60.0 / 60.0;
drawHand(brush, side / 2 - 20, minutes, 2.0f,
Color.BLUE, visibility);
if (handsLongProperty.isEnabled()) {
drawHand(brush, (side / 2 - 20) / 4,
minutes + minutes > 0.5 ? minutes - 0.5
: minutes + (minutes > 0.5 ? (-1) : 1) * 0.5,
2.0f,
Color.BLUE, visibility);
}
}
if (hourEnabledProperty.isEnabled()) {
double hours
= hour / 12.0 + minute / 60.0 / 12 + second / 60 / 60 / 12;
drawHand(brush, side / 2 - 40,
hours, 4.0f,
Color.BLACK, visibility);
if (handsLongProperty.isEnabled()) {
drawHand(brush, (side / 2 - 40) / 4,
hours + hours > 0.5 ? hours - 0.5
: hours + (hours > 0.5 ? (-1) : 1) * 0.5, 4.0f,
Color.BLACK, visibility);
}
}
if (borderVisibleProperty.isEnabled()) {
for (int minuteI = 0; minuteI < 60; minuteI++) {
if (borderOnlyHoursProperty.isEnabled() && minuteI % 5 != 0) {
continue;
}
drawBorder(brush, minuteI, minuteI % 5 == 0
? (numbersVisibleProperty.isEnabled() ? 2f : 4f) : 1f,
Color.BLACK, visibility);
}
}
if (centreCircleVisibleProperty.isEnabled()) {
drawCentreCircle(brush, centerX, centerY);
}
drawClockFace(brush, centerX, centerY, side / 2 - 40, visibility);
if (progress == null) {
progress = new Progress();
}
progress.set(WidgetType.DAY, (hour * 60 * 60 + minute * 60 + second) / (24d * 60d * 60d));
if (circleProgressVisibleProperty.isEnabled()) {
paintCircleProgress(brush, visibility, getWidth(), getHeight());
}
}
private void drawCentreCircle(Graphics2D brush, int centerX, int centerY) {
Color currentColor = brush.getColor();
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
brush.setColor(visibility.isStronglyColored() || mouseOver
? (centreCircleColoredProperty.isEnabled() ? Color.RED : Color.BLACK)
: FOREGROUND_COLOR);
brush.fillOval(centerX - 3, centerY - 3, 8, 8);
brush.setColor(currentColor);
}
private void drawBorder(Graphics2D brush, int forMinute,
float stroke, Color color, Visibility visibility) {
double value = ((double) forMinute) / 60d;
boolean hourAngle = forMinute % 5 == 0;
int length = side / (numbersVisibleProperty.isEnabled() ? 18
: (hourAngle ? 12 : 18));
double angle = Math.PI * 2 * (value - 0.25);
int startX
= (int) (getWidth() / 2 + (side / 2 - length) * Math.cos(angle));
int startY
= (int) (getHeight() / 2 + (side / 2 - length) * Math.sin(angle));
int endX = (int) (getWidth() / 2
+ (side / 2 - length * 0.50d * (hourAngle ? 0.25 : 1))
* Math.cos(angle));
int endY = (int) (getHeight() / 2
+ (side / 2 - length * 0.50d * (hourAngle ? 0.25 : 1))
* Math.sin(angle));
brush.setColor((visibility.isStronglyColored() || mouseOver) ? color
: FOREGROUND_COLOR);
brush.setStroke(new BasicStroke(stroke));
brush.drawLine(startX, startY, endX, endY);
}
private void drawHand(Graphics2D brush, int length, double value,
float stroke, Color color, Visibility visibility) {
length = length - 4;
double angle = Math.PI * 2 * (value - 0.25);
int endX = (int) (getWidth() / 2 + length * Math.cos(angle));
int endY = (int) (getHeight() / 2 + length * Math.sin(angle));
brush.setColor((visibility.isStronglyColored() || mouseOver)
? (handsColoredProperty.isEnabled() ? color : Color.BLACK)
: FOREGROUND_COLOR);
brush.setStroke(new BasicStroke(stroke));
brush.drawLine(getWidth() / 2, getHeight() / 2, endX, endY);
}
private void drawClockFace(Graphics2D brush, int centerX, int centerY,
int radius, Visibility visibility) {
brush.setStroke(new BasicStroke(2.0f));
brush.setColor(visibility.isStronglyColored() || mouseOver ? Color.BLACK
: FOREGROUND_COLOR);
if (circleVisibleProperty.isEnabled()) {
Color currentColor = brush.getColor();
if (visibility.isStronglyColored() || mouseOver) {
brush.setColor(customCircleColor);
}
brush.drawOval(1, 1, centerX * 2 - 3, centerY * 2 - 3);
brush.drawOval(2, 2, centerX * 2 - 3, centerY * 2 - 3);
if (circleStrongBorderProperty.isEnabled()) {
brush.drawOval(3, 3, centerX * 2 - 6, centerY * 2 - 6);
brush.drawOval(4, 4, centerX * 2 - 8, centerY * 2 - 8);
brush.drawOval(5, 5, centerX * 2 - 10, centerY * 2 - 10);
brush.drawOval(6, 6, centerX * 2 - 12, centerY * 2 - 12);
}
brush.setColor(currentColor);
}
if (this.mouseOver || dateVisibleOnlyIfMouseMovingOverProperty
.isDisabled()) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, yearProperty.getValue());
cal.set(Calendar.MONTH, monthProperty.getValue() - 1);
cal.set(Calendar.DAY_OF_MONTH, dayProperty.getValue());
cal.set(Calendar.HOUR_OF_DAY, hourProperty.getValue());
cal.set(Calendar.MINUTE, minuteProperty.getValue());
cal.set(Calendar.SECOND, secondProperty.getValue());
cal.set(Calendar.MILLISECOND, millisecondProperty.getValue());
Date date = cal.getTime();
brush.drawString(DateFormats.DATE_TIME_FORMATTER_LONG.format(date),
((int) (side * 0.25)),
((int) (side * 0.35)));
brush.drawString(DateFormats.DATE_TIME_FORMATTER_TIME.format(date),
((int) (side * 0.25) + 30),
((int) (side * 0.35)) + 60);
}
if (percentProgressVisibleProperty.isEnabled()) {
int d = (int) Math.floor(dayProgress * 100);
if(d < 0) {
d = 0;
}
if(d > 100) {
d = 100;
}
brush.drawString(d + "%",
((int) (side * 0.25)),
((int) (side * 0.35)) + 35);
}
if (smileyVisibleProperty.isEnabled()) {
paintSmiley(visibility, brush, ((int) (side * 0.25) + 90),
((int) (side * 0.35)) + 20);
} else {
if(this.smileyIcon != null) {
remove(this.smileyIcon);
this.smileyIcon = null;
}
if(this.smileyIcon2 != null) {
remove(this.smileyIcon2);
this.smileyIcon2 = null;
}
}
if (numbersVisibleProperty.isEnabled()) {
for (int i = 1; i <= 12; i++) {
double angle = Math.PI * 2 * (i / 12.0 - 0.25);
int dx = centerX + (int) ((radius + 20) * Math.cos(angle)) - 4;
int dy = centerY + (int) ((radius + 20) * Math.sin(angle)) + 4;
brush.setFont(new Font("sans", Font.BOLD, 16));
brush.drawString(Integer.toString(i), dx + (i == 12 ? -3 : 0),
dy + (i == 12 ? +3 : 0));
}
}
}
public int getTimerDelay() {
return 100;
}
@Override
public List<JMenuItem> createAdditionalMenus() {
if (menuItems == null) {
menuItems = new ArrayList<>();
JMenu hands = new JMenu("Hands");
menuItems.add(hands);
this.millisecondHandMenuItem = new TMenuItem("Millisecond");
this.secondHandMenuItem = new TMenuItem("Second");
this.minuteHandMenuItem = new TMenuItem("Minute");
this.hourHandMenuItem = new TMenuItem("Hour");
if (millisecondEnabledProperty.isEnabled()) {
millisecondHandMenuItem.enableMenuItem();
}
if (secondEnabledProperty.isEnabled()) {
secondHandMenuItem.enableMenuItem();
}
if (minuteEnabledProperty.isEnabled()) {
minuteHandMenuItem.enableMenuItem();
}
if (hourEnabledProperty.isEnabled()) {
hourHandMenuItem.enableMenuItem();
}
millisecondEnabledProperty.addListener(
(property, oldValue, newValue) -> millisecondHandMenuItem
.setEnabledMenuItem(newValue));
secondEnabledProperty.addListener(
(property, oldValue, newValue) -> secondHandMenuItem
.setEnabledMenuItem(newValue));
minuteEnabledProperty.addListener(
(property, oldValue, newValue) -> minuteHandMenuItem
.setEnabledMenuItem(newValue));
hourEnabledProperty.addListener(
(property, oldValue, newValue) -> hourHandMenuItem
.setEnabledMenuItem(newValue));
hands.add(millisecondHandMenuItem);
hands.add(secondHandMenuItem);
hands.add(minuteHandMenuItem);
hands.add(hourHandMenuItem);
millisecondHandMenuItem
.addActionListener(e -> millisecondEnabledProperty.flip());
secondHandMenuItem
.addActionListener(e -> secondEnabledProperty.flip());
minuteHandMenuItem
.addActionListener(e -> minuteEnabledProperty.flip());
hourHandMenuItem.addActionListener(e -> hourEnabledProperty.flip());
}
return this.menuItems;
}
protected Consumer<Object> createRefreshConsumer() {
return (o) -> {
millisecondHandMenuItem.disableMenuItem();
secondHandMenuItem.disableMenuItem();
minuteHandMenuItem.disableMenuItem();
hourHandMenuItem.disableMenuItem();
if (millisecondEnabledProperty.isEnabled()) {
millisecondHandMenuItem.enableMenuItem();
}
if (secondEnabledProperty.isEnabled()) {
secondHandMenuItem.enableMenuItem();
}
if (minuteEnabledProperty.isEnabled()) {
minuteHandMenuItem.enableMenuItem();
}
if (hourEnabledProperty.isEnabled()) {
hourHandMenuItem.enableMenuItem();
}
};
}
}

View File

@ -0,0 +1,36 @@
package org.nanoboot.utils.timecalc.swing.progress;
import lombok.Getter;
import org.nanoboot.utils.timecalc.app.TimeCalcException;
import java.util.Arrays;
import java.util.Optional;
/**
* @author pc00289
* @since 22.03.2024
*/
public enum DayOfWeekTC {
MONDAY(1),
TUESDAY(2),
WEDNESDAY(3),
THURSDAY(4),
FRIDAY(5),
SATURDAY(6),
SUNDAY(7);
@Getter
private final int number;
public static DayOfWeekTC forNumber(int number) {
Optional<DayOfWeekTC> result = Arrays.stream(DayOfWeekTC.values()).filter(d -> d.getNumber() == number).findFirst();
if(result.isPresent()) {
return result.get();
} else {
throw new TimeCalcException("There is noDayOfWeekTC with number: " + number);
}
}
DayOfWeekTC(int number) {
this.number = number;
}
}

View File

@ -0,0 +1,33 @@
package org.nanoboot.utils.timecalc.swing.progress;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.swing.common.Widget;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
public class PlaceHolderWidget extends Widget {
public PlaceHolderWidget() {
setPreferredSize(new Dimension(50, 50));
}
@Override
public void paintWidget(Graphics g) {
Graphics2D brush = (Graphics2D) g;
brush.setColor(mouseOver ? Color.LIGHT_GRAY : FOREGROUND_COLOR);
Visibility visibility = Visibility.ofProperty(visibilityProperty);
brush.fillRect(1, 1, 48, 48);
brush.setColor(Color.LIGHT_GRAY);
brush.drawRect(1, 1, 48, 48);
brush.setColor(FOREGROUND_COLOR);
}
}

View File

@ -0,0 +1,59 @@
package org.nanoboot.utils.timecalc.swing.progress;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.swing.common.Widget;
import org.nanoboot.utils.timecalc.swing.progress.battery.Battery;
import org.nanoboot.utils.timecalc.utils.common.NumberFormats;
import org.nanoboot.utils.timecalc.utils.property.IntegerProperty;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
public class ProgressBar extends Widget {
public IntegerProperty heightProperty = new IntegerProperty("heightProperty", 25);
public ProgressBar() {
setPreferredSize(new Dimension(600, 25));
}
@Override
public void paintWidget(Graphics g) {
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
Graphics2D brush = (Graphics2D) g;
brush.setColor(
visibility.isStronglyColored() || mouseOver ?
Battery.getColourForProgress(donePercent(), visibility, mouseOver)/*Color.darkGray*/
: FOREGROUND_COLOR);
brush.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int progressWidth = (int) (getWidth() * donePercent());
int remainsWidth = getWidth() - progressWidth;
brush.setColor(
visibility.isStronglyColored() || mouseOver ?
Color.WHITE
: BACKGROUND_COLOR);
int h = heightProperty.getValue() > getHeight() ? getHeight() :
heightProperty.getValue();
if(h < 1) {h = 1;}
brush.fillRect(0, 0, getWidth(), h);
brush.setColor(
visibility.isStronglyColored() || mouseOver ?
Battery.getColourForProgress(donePercent(), visibility, mouseOver)/*Color.darkGray*/
: FOREGROUND_COLOR);
brush.fillRect(0, 0, progressWidth, h);
brush.setColor(h <= 15 || progressWidth < 40 ? (visibility.isStronglyColored() ? Color.BLACK : Color.GRAY) : Color.WHITE);
brush.drawString(
NumberFormats.FORMATTER_ONE_DECIMAL_PLACE
.format(donePercent() * 100) + "%",
progressWidth < 40 ? 40 : progressWidth - 40,
h <= 15 ? h + 15 : 15);
}
}

View File

@ -0,0 +1,69 @@
package org.nanoboot.utils.timecalc.swing.progress;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.swing.common.Widget;
import org.nanoboot.utils.timecalc.swing.progress.battery.Battery;
import org.nanoboot.utils.timecalc.utils.common.NumberFormats;
import org.nanoboot.utils.timecalc.utils.property.BooleanProperty;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
public class ProgressCircle extends Widget {
public BooleanProperty innerCircleVisibleProperty = new BooleanProperty("innerCircleVisibleProperty", true);
public BooleanProperty outerCircleOnlyBorderProperty = new BooleanProperty("outerCircleOnlyBorderProperty", true);
public ProgressCircle() {
setPreferredSize(new Dimension(200, 200));
}
@Override
public void paintWidget(Graphics g) {
if (side == 0) {
this.side = Math.min(getWidth(), getHeight());
}
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
Graphics2D brush = (Graphics2D) g;
brush.setColor(
visibility.isStronglyColored() || mouseOver ?
Battery.getColourForProgress(donePercent(), visibility, mouseOver)/*Color.darkGray*/
: FOREGROUND_COLOR);
brush.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
double angleDouble = donePercent() * 360;
double angleDouble2 = (angleDouble - (int) (angleDouble)) * 360;
// System.out.println("remainingAngle=" + angleDouble2);
if(outerCircleOnlyBorderProperty.isEnabled()) {
brush.setStroke(new BasicStroke(8f));
brush.drawArc(8, 8, side - 16, side - 16, 90, -(int) angleDouble);
} else {
brush.fillArc(8, 8, side - 16, side - 16, 90, -(int) angleDouble);
}
int side2 = side / 2;
brush.setColor(visibility.isStronglyColored() || mouseOver
? new Color(105, 175, 236) : FOREGROUND_COLOR2);
if(innerCircleVisibleProperty.isEnabled()) {
brush.fillArc(0 + (side2 / 2), 0 + (side2 / 2), side2, side2, 90,
-(int) angleDouble2);
}
brush.setColor(visibility.isStronglyColored() || mouseOver ? Color.blue
: FOREGROUND_COLOR);
brush.drawString(
NumberFormats.FORMATTER_ZERO_DECIMAL_PLACES
.format(donePercent() * 100) + "%",
(int) (side / 8d * 0d), (int) (side / 8d * 7.5d));
paintSmiley(visibility, brush, (int) (side / 8d * 0d) + 30,
(int) (side / 8d * 7.5d - 16d));
}
}

View File

@ -0,0 +1,103 @@
package org.nanoboot.utils.timecalc.swing.progress;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.swing.common.Widget;
import org.nanoboot.utils.timecalc.swing.progress.battery.Battery;
import org.nanoboot.utils.timecalc.utils.common.NumberFormats;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
public class ProgressDot extends Widget {
private int square;
@AllArgsConstructor
class Dot {
private int x, y;
}
private List<Dot> enabledDots = new ArrayList<>();
private List<Dot> disabledDots = new ArrayList<>();
public ProgressDot() {
setPreferredSize(new Dimension(400, 400));
}
@Override
public void paintWidget(Graphics g) {
int dotSize = 2;
if (side == 0) {
this.side = Math.min(getWidth(), getHeight()) / dotSize;
this.square = side * side;
for (int y = 1; y <= side; y++) {
for (int x = 1; x <= side; x++) {
disabledDots.add(new Dot(x, y));
}
}
}
Double done = donePercent();
int enabledDotsExpectedSize = (int) (done * square);
int disabledDotsExpectedSize = square - enabledDotsExpectedSize;
// System.out.println("enabledDots.size()=" + enabledDots.size());
// System.out.println("disabledDots.size()=" + disabledDots.size());
while (enabledDots.size() > enabledDotsExpectedSize) {
int randomIndex = (int) (enabledDots.size() * Math.random());
Dot randomDot = enabledDots.remove(randomIndex);
disabledDots.add(randomDot);
}
while (enabledDots.size() < enabledDotsExpectedSize) {
int randomIndex = (int) (disabledDots.size() * Math.random());
Dot randomDot = disabledDots.remove(randomIndex);
enabledDots.add(randomDot);
}
Graphics2D brush = (Graphics2D) g;
brush.setColor(FOREGROUND_COLOR);
brush.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int numberOfDots = (int) (donePercent() * square);
Visibility visibility = Visibility.ofProperty(visibilityProperty);
{
if (visibility.isStronglyColored() || mouseOver) {
//brush.setColor(Color.GRAY);
brush.setColor(Battery.HIGHEST_WEAKLY_COLORED);
}
for (Dot d : enabledDots) {
brush.fillRect(((d.x - 1) * dotSize) + d.x, ((d.y - 1) * dotSize) + d.y, dotSize+(dotSize > 1 ? 1 : 1), dotSize+(dotSize > 1 ? 1 : 1));
//brush.drawLine(d.x, d.y, d.x, d.y);
}
if(visibility.isStronglyColored()){
//Color currentColor = brush.getColor();
brush.setColor(Battery.LOW_WEAKLY_COLORED);
for (Dot d : disabledDots) {
brush.fillRect(((d.x - 1) * dotSize) + d.x, ((d.y - 1) * dotSize) + d.y, dotSize+(dotSize > 1 ? 1 : 1), dotSize+(dotSize > 1 ? 1 : 1));
//brush.drawLine(d.x, d.y, d.x, d.y);
}
//brush.setColor(currentColor);
}
brush.setColor(FOREGROUND_COLOR);
}
brush.setColor(visibility.isStronglyColored() || mouseOver ? Color.BLACK
: BACKGROUND_COLOR);
brush.drawString(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES
.format(donePercent() * 100) + "%",
(int) (side / 8d * 3d),
(int) (side / 8d * (5d)));
paintSmiley(visibility, brush, (int) (side / 8d * 3d),
(int) ((side / 8d * (5d)) - 32d));
}
}

View File

@ -0,0 +1,224 @@
package org.nanoboot.utils.timecalc.swing.progress;
import org.nanoboot.utils.timecalc.app.GetProperty;
import org.nanoboot.utils.timecalc.app.TimeCalcProperty;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.entity.WidgetType;
import org.nanoboot.utils.timecalc.swing.common.Brush;
import org.nanoboot.utils.timecalc.swing.common.SwingUtils;
import org.nanoboot.utils.timecalc.swing.common.Widget;
import org.nanoboot.utils.timecalc.swing.progress.battery.Battery;
import org.nanoboot.utils.timecalc.swing.windows.MainWindow;
import org.nanoboot.utils.timecalc.utils.common.NumberFormats;
import org.nanoboot.utils.timecalc.utils.common.ProgressSmiley;
import org.nanoboot.utils.timecalc.utils.property.BooleanProperty;
import org.nanoboot.utils.timecalc.utils.property.Property;
import javax.imageio.ImageIO;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.Timer;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.function.Function;
/**
* @author Robert Vokac
* @since 21.02.2024
*/
public class ProgressFuelGauge extends Widget implements GetProperty {
public static final Color BLACK2 = new Color(64, 64,64);
public static final Color LIGHT_GRAY2 = new Color(160,160,160);
public static final String FUEL_GAUGE_FUEL_GAUGE_ICON_ORANGE_PNG =
"/fuel_gauge/fuel_gauge_icon_orange.png";
public static final String FUEL_GAUGE_FUEL_GAUGE_ICON_DARK_GRAY_PNG =
"/fuel_gauge/fuel_gauge_icon_dark_gray.png";
public final BooleanProperty fuelIconVisibleProperty
= new BooleanProperty(TimeCalcProperty.FUEL_ICON_VISIBLE.getKey());
private List<JMenuItem> menuItems = null;
private Image orangeIcon;
private Image darkGrayIcon;
public ProgressFuelGauge() {
setFont(new Font(Font.MONOSPACED, Font.PLAIN, 11));
setFocusable(false);
setForeground(Color.GRAY);
setBackground(MainWindow.BACKGROUND_COLOR);
this.setLayout(null);
this.typeProperty.setValue(WidgetType.DAY.name().toLowerCase(Locale.ROOT));
new Timer(100, e -> {
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
setForeground(
visibility.isStronglyColored()
|| mouseOver
? Color.BLACK : Color.LIGHT_GRAY);
}).start();
}
public int getTimerDelay() {
return 100;
}
@Override
public void paintWidget(Graphics brush) {
((Graphics2D)brush).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
brush.setColor(visibility.isStronglyColored() ? Color.BLACK
: visibility.isWeaklyColored() ? Color.GRAY
: Color.LIGHT_GRAY);
brush.setFont(SwingUtils.MEDIUM_MONOSPACE_FONT);
brush.fillRect(1, 1, getWidth(), getHeight());
if (fuelIconVisibleProperty.isEnabled() && visibility == Visibility.STRONGLY_COLORED) {
if(this.orangeIcon == null) {
try {
this.orangeIcon = ImageIO.read(getClass().getResource(
FUEL_GAUGE_FUEL_GAUGE_ICON_ORANGE_PNG));
} catch (IOException e) {
e.printStackTrace();
}
}
if(this.darkGrayIcon == null) {
try {
this.darkGrayIcon = ImageIO.read(getClass().getResource(
FUEL_GAUGE_FUEL_GAUGE_ICON_DARK_GRAY_PNG));
} catch (IOException e) {
e.printStackTrace();
}
}
brush.drawImage(donePercent() <= 0.15d ? this.orangeIcon : this.darkGrayIcon, getWidth() - 32, getHeight() - 48, 32, 32, null);
}
brush.setColor(visibility.isStronglyColored() ? BLACK2
: visibility.isWeaklyColored() ? Color.LIGHT_GRAY
: LIGHT_GRAY2);
int ovalWidth = (int) (getWidth() * 0.4);
brush.fillOval(
(int)((getWidth() - ovalWidth) /2d),
(int) (getHeight() * 0.6),
ovalWidth,
ovalWidth
);
brush.setColor(Color.WHITE);
int startX = getWidth() / 2;
int startY = getHeight() - (ovalWidth / 2);
int length = (int) (ovalWidth * 1.5d);
double angle = Math.PI * 2 * (donePercent() * 0.25d + 2.5d * 0.25d);
int endX = (int) (startX + length * Math.cos(angle));
int endY = (int) (startY + length * Math.sin(angle));
((Graphics2D)brush).setStroke(new BasicStroke(3f));
//
length = (int) (ovalWidth / 2d * 0.9d);
angle = Math.PI * 2 * (donePercent() * 0.25d + 2.5d * 0.25d + 0.5d);
int endX2 = (int) (startX + length * Math.cos(angle));
int endY2 = (int) (startY + length * Math.sin(angle));
if(mouseOver) {
brush.setColor(visibility.isStronglyColored() ? Color.BLUE
: visibility.isWeaklyColored() ? Color.BLUE
: Color.WHITE);
}
brush.drawLine(startX, startY, endX2, endY2);
brush.setColor(Color.WHITE);
//
((Graphics2D)brush).setStroke(new BasicStroke(1f));
int length_ = (int) (ovalWidth * 1.5d);
//brush.drawOval(startX - length_, startY - length_, (int)(length_ * 2d), (int)(length_ * 2d));
//brush.drawArc(startX - length_, startY - length_ - 2, (int)(length_ * 2d), (int)(length_ * 2d), 180 + 45, 180 + 45 + 90);
//brush.drawArc(startX - length_, startY - length_ + 6, (int)(length_ * 2d), (int)(length_ * 2d), 180 + 45, 180 + 45 + 90);
Brush tBrush = new Brush((Graphics2D) brush);
// tBrush.drawOval(startX, startY, length_ * 2, length_ * 2);
// tBrush.drawOval(startX, startY + 8, length_ * 2, length_ * 2);
tBrush.drawArc(startX, startY - 1 , length_ * 2, length_ * 2, -45, 90);
tBrush.drawArc(startX, startY + 5, length_ * 2, length_ * 2, -40, 80);
int width_ = (int) (ovalWidth / 4d);
Function<Double, Integer> getAngle = (d -> (int)(-45 + 90 * d));
brush.setColor(visibility.isStronglyColored() ? Color.RED : (visibility.isWeaklyColored() ?
Battery.ULTRA_LIGHT_RED : Color.GRAY));
((Graphics2D) brush).setStroke(new BasicStroke(6.5f));
tBrush.drawArc(startX, startY + 2, length_ * 2, length_ * 2,
(int) (45d / 10d * 7.5d),
(int) (90d / 4d / 5d * 1.7d));
brush.setColor(Color.WHITE);
tBrush.drawBorder(startX, startY, 5, length_ - 4, getAngle.apply(0.25d / 5d * 3d), 2f, brush.getColor());
tBrush.drawBorder(startX, startY, 5, length_ - 4, getAngle.apply(0.25d), 2f, brush.getColor());
tBrush.drawBorder(startX, startY, 6, length_ - 7, getAngle.apply(0.5d), 7f, brush.getColor());
tBrush.drawBorder(startX, startY, 5, length_ - 4, getAngle.apply(0.75d), 2f, brush.getColor());
tBrush.drawBorder(startX, startY, 6, length_ - 7, getAngle.apply(1.d - 0.02d), 7f, brush.getColor());
//
if(mouseOver) {
brush.setColor(visibility.isStronglyColored() ? Color.BLUE
: visibility.isWeaklyColored() ? Color.BLUE
: Color.WHITE);
}
((Graphics2D)brush).setStroke(new BasicStroke(3f));
brush.drawLine(startX, startY, endX, endY);
//
brush.setColor(visibility.isStronglyColored() ? Color.BLACK
: visibility.isWeaklyColored() ? Color.GRAY
: Color.LIGHT_GRAY);
brush.fillOval(
(int) (startX - width_ / 2d),
(int) (startY - width_ / 2d),
width_,
width_
);
brush.setColor(Color.WHITE);
//tBrush.drawBorder(startX, startY, 10, length_ - 4 - 5, getAngle.apply(donePercent()), 3f, brush.getColor());
this.setToolTipText(NumberFormats.FORMATTER_TWO_DECIMAL_PLACES.format(donePercent() * 100d) + "%");
}
//private boolean w = false;
@Override
public Property getVisibilityProperty() {
return visibilityProperty;
}
@Override
public Property getVisibilitySupportedColoredProperty() {
return visibilitySupportedColoredProperty;
}
@Override
public List<JMenuItem> createAdditionalMenus() {
if (this.menuItems == null) {
menuItems = new ArrayList<>();
}
return this.menuItems;
}
}

View File

@ -0,0 +1,116 @@
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.SwingUtils;
import org.nanoboot.utils.timecalc.swing.common.Toaster;
import org.nanoboot.utils.timecalc.swing.common.Widget;
import org.nanoboot.utils.timecalc.swing.windows.MainWindow;
import org.nanoboot.utils.timecalc.utils.common.Constants;
import org.nanoboot.utils.timecalc.utils.common.DateFormats;
import org.nanoboot.utils.timecalc.utils.common.NumberFormats;
import org.nanoboot.utils.timecalc.utils.common.Utils;
import org.nanoboot.utils.timecalc.utils.property.Property;
import org.nanoboot.utils.timecalc.utils.property.StringProperty;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.Timer;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
/**
* @author Robert Vokac
* @since 21.02.2024
*/
public class ProgressLife extends Widget implements GetProperty {
private final Time time;
public StringProperty birthDateProperty
= new StringProperty("life.birthDateProperty");
public ProgressLife(Time time) {
this.time = time;
setFont(new Font(Font.MONOSPACED, Font.PLAIN, 11));
setFocusable(false);
setForeground(Color.GRAY);
setBackground(MainWindow.BACKGROUND_COLOR);
new Timer(100, e -> {
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
setForeground(
visibility.isStronglyColored()
|| mouseOver
? Color.BLACK : Color.LIGHT_GRAY);
}).start();
}
public int getTimerDelay() {
return 100;
}
@Override
public void paintWidget(Graphics brush) {
if (birthDateProperty.getValue().isEmpty()) {
//nothing to do
return;
} else {
Calendar birthDateCal = Calendar.getInstance();
String[] array = birthDateProperty.getValue().split("-");
birthDateCal.set(Calendar.YEAR, Integer.valueOf(array[0]));
birthDateCal.set(Calendar.MONTH, Integer.valueOf(array[1]) - 1);
birthDateCal.set(Calendar.DAY_OF_MONTH, Integer.valueOf(array[2]));
Date birthDate = birthDateCal.getTime();
Date now = time.asCalendar().getTime();
long diff = now.getTime() - birthDate.getTime();
Date result = new Date(
(long) (birthDate.getTime() + diff * donePercent()));
String date =
DateFormats.DATE_TIME_FORMATTER_YYYYMMDD.format(result);
String time =
DateFormats.DATE_TIME_FORMATTER_HHmmssSSS.format(result);
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
brush.setColor(visibility.isStronglyColored() ? Color.BLUE
: visibility.isWeaklyColored() ? Color.GRAY
: Color.LIGHT_GRAY);
// if(mouseOver) {
// brush.drawRect(1,1,getWidth() - 2, getHeight() - 2);
// }
brush.setFont(SwingUtils.MEDIUM_MONOSPACE_FONT);
brush.drawString(date, SwingUtils.MARGIN, SwingUtils.MARGIN + 16);
brush.drawString(time, SwingUtils.MARGIN,
(int) (2.5 * SwingUtils.MARGIN) + 22);
}
}
@Override
public Property getVisibilityProperty() {
return visibilityProperty;
}
@Override
public Property getVisibilitySupportedColoredProperty() {
return visibilitySupportedColoredProperty;
}
}

View File

@ -0,0 +1,107 @@
package org.nanoboot.utils.timecalc.swing.progress;
import org.nanoboot.utils.timecalc.app.GetProperty;
import org.nanoboot.utils.timecalc.entity.Progress;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.entity.WidgetType;
import org.nanoboot.utils.timecalc.swing.common.SwingUtils;
import org.nanoboot.utils.timecalc.swing.common.Widget;
import org.nanoboot.utils.timecalc.swing.windows.MainWindow;
import org.nanoboot.utils.timecalc.utils.common.NumberFormats;
import org.nanoboot.utils.timecalc.utils.property.IntegerProperty;
import org.nanoboot.utils.timecalc.utils.property.Property;
import org.nanoboot.utils.timecalc.utils.property.StringProperty;
import javax.swing.Timer;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.text.NumberFormat;
import java.util.Locale;
/**
* @author Robert Vokac
* @since 21.02.2024
*/
public class ProgressMoney extends Widget implements GetProperty {
public IntegerProperty perMonthProperty
= new IntegerProperty("money.perMonthProperty");
public StringProperty currencyProperty
= new StringProperty("money.currencyProperty");
public ProgressMoney() {
setFont(new Font(Font.MONOSPACED, Font.PLAIN, 11));
setFocusable(false);
setForeground(Color.GRAY);
setBackground(MainWindow.BACKGROUND_COLOR);
new Timer(100, e -> {
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
setForeground(
visibility.isStronglyColored()
|| mouseOver
? Color.BLACK : Color.LIGHT_GRAY);
}).start();
}
public int getTimerDelay() {
return 100;
}
@Override
public void paintWidget(Graphics brush) {
double perMonth = this.perMonthProperty.getValue();
if (perMonth == 0) {
//nothing to do
return;
} else {
if(progress == null) {
//nothing to do
return;
}
double workDaysInMonth = progress.getWorkDaysInMonth();
boolean isWeekend = progress.isWeekend();
double perDay = perMonth / workDaysInMonth;
double value = 0;
WidgetType widgetType = WidgetType.valueOf(this.typeProperty.getValue().toUpperCase(
Locale.ROOT));
widgetType = progress.getWidgetType(widgetType);
switch(widgetType) {
case MINUTE: value = isWeekend ? 0d : perDay / 8d / 60d * progress.getDonePercent(WidgetType.MINUTE);break;
case HOUR: value = isWeekend ? 0d : perDay / 8d * progress.getDonePercent(WidgetType.HOUR);break;
case DAY: value = isWeekend ? 0d : perDay * progress.getDonePercent(WidgetType.DAY);break;
case WEEK: value = perDay * 5d * progress.getDonePercent(WidgetType.WEEK);break;
case MONTH: value = perMonth * progress.getDonePercent(WidgetType.MONTH);break;
case YEAR: value = perMonth * 12 * progress.getDonePercent(WidgetType.YEAR);break;
case LIFE: value = perMonth * 12 * (Progress.RETIREMENT_AGE - Progress.STARTED_WORKING_AGE) * progress.getDonePercent(WidgetType.LIFE);break;
}
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
brush.setColor(visibility.isStronglyColored() ? Color.BLUE
: visibility.isWeaklyColored() ? Color.GRAY
: Color.LIGHT_GRAY);
brush.setFont(SwingUtils.MEDIUM_MONOSPACE_FONT);
NumberFormat formatter = value >= 10000d ? NumberFormats.FORMATTER_TWO_DECIMAL_PLACES : NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES;
String valueFinal = formatter.format(value) + " " + this.currencyProperty.getValue();
brush.drawString(valueFinal, SwingUtils.MARGIN, SwingUtils.MARGIN + 20);
}
}
@Override
public Property getVisibilityProperty() {
return visibilityProperty;
}
@Override
public Property getVisibilitySupportedColoredProperty() {
return visibilitySupportedColoredProperty;
}
}

View File

@ -0,0 +1,180 @@
package org.nanoboot.utils.timecalc.swing.progress;
import org.nanoboot.utils.timecalc.app.TimeCalcProperty;
import org.nanoboot.utils.timecalc.entity.Progress;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.entity.WidgetType;
import org.nanoboot.utils.timecalc.swing.common.SwingUtils;
import org.nanoboot.utils.timecalc.swing.common.Widget;
import org.nanoboot.utils.timecalc.swing.controls.TMenuItem;
import org.nanoboot.utils.timecalc.swing.progress.battery.Battery;
import org.nanoboot.utils.timecalc.utils.common.DateFormats;
import org.nanoboot.utils.timecalc.utils.common.NumberFormats;
import org.nanoboot.utils.timecalc.utils.common.TTime;
import org.nanoboot.utils.timecalc.utils.property.BooleanProperty;
import org.nanoboot.utils.timecalc.utils.property.IntegerProperty;
import org.nanoboot.utils.timecalc.utils.property.StringProperty;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.function.Consumer;
//https://kodejava.org/how-do-i-write-a-simple-analog-clock-using-java-2d/
public class ProgressRotation extends Widget {
public static final Color COLOR_FOR_MILLISECOND_HAND_STRONGLY_COLORED
= new Color(226,
126, 19);
public final BooleanProperty borderVisibleProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_BORDER_VISIBLE
.getKey());
public final BooleanProperty borderOnlyHoursProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_BORDER_ONLY_HOURS
.getKey());
public final BooleanProperty circleVisibleProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_CIRCLE_VISIBLE
.getKey());
public final BooleanProperty circleStrongBorderProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_CIRCLE_STRONG_BORDER
.getKey());
public final BooleanProperty centreCircleVisibleProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_CENTRE_CIRCLE_VISIBLE
.getKey());
public final StringProperty centreCircleBorderColorProperty
= new StringProperty(TimeCalcProperty.CLOCK_CIRCLE_BORDER_COLOR
.getKey());
public final BooleanProperty centreCircleColoredProperty
= new BooleanProperty(TimeCalcProperty.CLOCK_CENTRE_CIRCLE_COLORED
.getKey());
public BooleanProperty circleProgressVisibleProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_CIRCLE_PROGRESS_VISIBLE
.getKey(), true);
private Color customCircleColor = null;
private List<JMenuItem> menuItems = null;
public ProgressRotation() {
typeProperty.setValue(WidgetType.DAY.name().toLowerCase(Locale.ROOT));
setPreferredSize(new Dimension(100, 100));
centreCircleBorderColorProperty.addListener(property
-> customCircleColor = SwingUtils.getColorFromString(
centreCircleBorderColorProperty.getValue()));
}
public static void main(String[] args) {
JFrame window = new JFrame("Analog Clock");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ProgressRotation rotation
= new ProgressRotation();
window.add(rotation);
window.pack();
rotation.visibilityProperty.setValue(Visibility.GRAY.name());
window.setVisible(true);
}
private double angle = 0d;
@Override
public void paintWidget(Graphics g) {
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
Graphics2D brush = (Graphics2D) g;
brush.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
this.side = Math.min(getWidth(), getHeight());
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
if (customCircleColor == null) {
customCircleColor = SwingUtils.getColorFromString(
centreCircleBorderColorProperty.getValue());
}
//
angle = angle + 0.001d * donePercent() * 50d;
if(angle > 1.0d) {
angle = angle - 1.0d;
}
drawHand(brush, side / 2 - 10, angle, 1.0f,
COLOR_FOR_MILLISECOND_HAND_STRONGLY_COLORED, visibility);
//brush.drawString(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(angle), 15, 15);
if (centreCircleVisibleProperty.isEnabled()) {
drawCentreCircle(brush, centerX, centerY);
}
if (progress == null) {
progress = new Progress();
}
if (circleProgressVisibleProperty.isEnabled()) {
paintCircleProgress(brush, visibility, getWidth(), getHeight());
}
}
private void drawCentreCircle(Graphics2D brush, int centerX, int centerY) {
Color currentColor = brush.getColor();
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
brush.setColor(visibility.isStronglyColored() || mouseOver
? (centreCircleColoredProperty.isEnabled() ? Color.RED : Color.BLACK)
: FOREGROUND_COLOR);
brush.fillOval(centerX - 3, centerY - 3, 8, 8);
brush.setColor(currentColor);
}
private void drawHand(Graphics2D brush, int length, double value,
float stroke, Color color, Visibility visibility) {
length = length - 4;
double angle = Math.PI * 2 * (value - 0.25);
int endX = (int) (getWidth() / 2 + length * Math.cos(angle));
int endY = (int) (getHeight() / 2 + length * Math.sin(angle));
brush.setColor((visibility.isStronglyColored() || mouseOver)
? Color.BLACK : FOREGROUND_COLOR);
brush.setStroke(new BasicStroke(stroke));
brush.drawLine(getWidth() / 2, getHeight() / 2, endX, endY);
}
public int getTimerDelay() {
return 1;
}
@Override
public List<JMenuItem> createAdditionalMenus() {
if (menuItems == null) {
menuItems = new ArrayList<>();
}
return this.menuItems;
}
protected Consumer<Object> createRefreshConsumer() {
return (o) -> {
};
}
}

View File

@ -0,0 +1,40 @@
package org.nanoboot.utils.timecalc.swing.progress;
import lombok.Getter;
import org.nanoboot.utils.timecalc.utils.common.ProgressSmiley;
import javax.swing.ImageIcon;
import java.awt.Image;
import java.util.HashMap;
import java.util.Map;
/**
* @author Robert Vokac
* @since 27.02.2024
*/
public class ProgressSmileyIcon extends javax.swing.ImageIcon {
private static final Map<ProgressSmiley, ProgressSmileyIcon> cache
= new HashMap<>();
@Getter
private final ProgressSmiley progressSmiley;
@Getter
private final ImageIcon icon;
private ProgressSmileyIcon(ProgressSmiley progressSmiley) {
this.progressSmiley = progressSmiley;
java.net.URL smileyUrl = getClass()
.getResource("/smileys/" + progressSmiley.name() + ".png");
ImageIcon tmpIcon = new javax.swing.ImageIcon(smileyUrl);
this.icon = new ImageIcon(tmpIcon.getImage()
.getScaledInstance(15, 15, Image.SCALE_SMOOTH));
}
public static ProgressSmileyIcon forSmiley(ProgressSmiley progressSmiley) {
if (!cache.containsKey(progressSmiley)) {
cache.put(progressSmiley, new ProgressSmileyIcon(progressSmiley));
}
return cache.get(progressSmiley);
}
}

View File

@ -0,0 +1,89 @@
package org.nanoboot.utils.timecalc.swing.progress;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.swing.common.Widget;
import org.nanoboot.utils.timecalc.utils.common.NumberFormats;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
public class ProgressSquare extends Widget {
private int square;
public ProgressSquare() {
setPreferredSize(new Dimension(400, 400));
}
@Override
public void paintWidget(Graphics g) {
if (side == 0) {
this.side = Math.min(getWidth(), getHeight());
this.square = side * side;
}
Graphics2D brush = (Graphics2D) g;
brush.setColor(FOREGROUND_COLOR);
brush.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int dotNumber = (int) (donePercent() * square);
int y = dotNumber / side;
int yOrig = y;
int x = dotNumber - y * side;
// System.out.println("dotNumber=" + dotNumber);
// System.out.println("x=" + x);
// System.out.println("y=" + y);
Visibility visibility = Visibility.ofProperty(visibilityProperty);
if (y > 1) {
if (visibility.isStronglyColored() || mouseOver) {
brush.setColor(Color.GRAY);
}
brush.fillRect(side - 4, side - 4, 4, 4);
brush.fillRect(1, side - 4, 4, 4);
brush.setColor(FOREGROUND_COLOR);
brush.fillRect(1, 1, side, y - 1);
if (x > 1) {
if (visibility.isStronglyColored() || mouseOver) {
brush.setColor(Color.GRAY);
}
brush.drawRect(1, y, x - 1, 1);
}
if (visibility.isStronglyColored() || mouseOver) {
brush.setColor(Color.GRAY);
}
brush.fillRect(side - 4, 1, 4, 4);
brush.fillRect(1, 1, 4, 4);
if (visibility.isStronglyColored() || mouseOver) {
brush.setColor(Color.GRAY);
}
brush.drawLine(1, 1, x, y);
// g2d.drawLine(1+1, 1+1, x+1, y+1);
brush.drawLine(1, 1 + 1, x, y + 1);
brush.drawLine(1, 1 + 1, x, y + 1);
if (visibility.isStronglyColored() || mouseOver) {
brush.setColor(Color.BLUE);
brush.drawLine(x - 10, y - 10, x + 10, y + 10);
brush.drawLine(x + 10, y - 10, x - 10, y + 10);
}
brush.setColor(FOREGROUND_COLOR);
}
brush.setColor(visibility.isStronglyColored() || mouseOver ? Color.BLACK
: BACKGROUND_COLOR);
brush.drawString(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES
.format(donePercent() * 100) + "%",
(int) (side / 8d * 3d),
(int) (side / 8d * (donePercent() > 0.5 ? 3d : 5d)));
paintSmiley(visibility, brush, (int) (side / 8d * 3d),
(int) ((side / 8d * (donePercent() > 0.5 ? 3d : 5d)) - 32d));
}
}

View File

@ -0,0 +1,74 @@
package org.nanoboot.utils.timecalc.swing.progress;
import org.nanoboot.utils.timecalc.app.TimeCalcProperty;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.swing.common.Widget;
import org.nanoboot.utils.timecalc.utils.common.NumberFormats;
import org.nanoboot.utils.timecalc.utils.property.BooleanProperty;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
public class ProgressSwing extends Widget {
public final BooleanProperty quarterIconVisibleProperty
= new BooleanProperty(
TimeCalcProperty.SWING_QUARTER_ICON_VISIBLE
.getKey(), true);
public ProgressSwing() {
setPreferredSize(new Dimension(200, 100));
}
@Override
public void paintWidget(Graphics g) {
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
Graphics2D brush = (Graphics2D) g;
brush.setColor(
visibility.isStronglyColored() || mouseOver ? Color.darkGray
: FOREGROUND_COLOR);
brush.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
brush.setStroke(new BasicStroke(0.5f));
//brush.drawRect(1,1, getWidth() - 2, getHeight() - 2);
brush.setStroke(new BasicStroke(1.5f));
brush.drawLine(getWidth() /2, getHeight(), getWidth()/2,
(int) (getHeight() * 0.66) - 10);
brush.fillOval(getWidth()/2 - 3,
(int) (getHeight() * 0.66) - 10 - 3, 6, 6);
brush.drawLine(1, getHeight() - 2, getWidth(), getHeight() - 2);
int startX = (int) (getWidth() * 0.10);
double donePercent = donePercent();
int startY = (int) (getHeight() - getHeight() * 0.66 * (1 - donePercent)) - 10;
int endX = (int) (getWidth() * 0.90);
int endY = (int) (getHeight() - getHeight() * 0.66 * donePercent) - 10;
brush.drawLine(startX, startY, endX, endY);
// brush.drawLine(startX, startY, getWidth()/2,
// (int) (getHeight() * 0.6));
// brush.drawLine(endX, endY, getWidth()/2,
// (int) (getHeight() * 0.6));
paintSmiley(visibility, brush, startX, startY - 25, true);
paintSmiley(visibility, brush, endX, endY - 25, true, 1.0 - donePercent, 2);
brush.drawString(
NumberFormats.FORMATTER_ZERO_DECIMAL_PLACES
.format(donePercent * 100) + "%",
(int) (getWidth() * 0.45), (int) (getHeight() * 0.9));
if (quarterIconVisibleProperty.isEnabled()) {
paintQuarterIcon(brush, visibility, getWidth(), getHeight(),
(int) (getWidth() * 0.45), (int) (getHeight() * 0.25));
}
}
}

View File

@ -0,0 +1,78 @@
package org.nanoboot.utils.timecalc.swing.progress;
import org.nanoboot.utils.timecalc.entity.Progress;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.swing.common.Widget;
import org.nanoboot.utils.timecalc.swing.progress.battery.Battery;
import org.nanoboot.utils.timecalc.utils.property.BooleanProperty;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
public class ProgressWater extends Widget {
public ProgressWater() {
System.out.println("Starting ProgressWater");
setPreferredSize(new Dimension(100, 400));
}
public final BooleanProperty coloredProperty = new BooleanProperty("coloredProperty", false);
private static final Color WATER_COLOR = new Color(128, 197, 222);
@Override
public void paintWidget(Graphics g) {
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
Graphics2D brush = (Graphics2D) g;
brush.setColor(
visibility.isStronglyColored() || mouseOver ?
(coloredProperty.isEnabled() ? Battery.getColourForProgress(donePercent(), Visibility.WEAKLY_COLORED, mouseOver): WATER_COLOR)
: FOREGROUND_COLOR);
brush.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int tankHeight = (int) (getHeight() * 0.48);
int doneWaterHeight = (int) (tankHeight * (donePercent()));
int h = getHeight() - 1;
int w = getWidth() - 1;
int w48 = (int) (w * 0.48);
int w52 = (int) (w * 0.52);
int h48 = (int) (h * 0.48) - 1;
int h52 = (int) (h * 0.52);
int w4 = (int) (w * 0.04);
int h4 = (int) (h * 0.04);
brush.fillRect(2, doneWaterHeight, w - 1,
(int) (tankHeight * (1d - donePercent())));
brush.fillRect(2, h - doneWaterHeight, w - 1,
(int) (tankHeight * (donePercent())));
if(donePercent() < 1d) {
brush.fillRect(w48, h48, w4 + 1, h4 + tankHeight);
}
brush.setColor(
visibility.isStronglyColored() || mouseOver ?
Color.BLACK : FOREGROUND_COLOR);
brush.drawPolyline(
new int[] {w48, 1, 1, w, w, w52},
new int[] {h48, h48, 1, 1,
h48, h48},
6);
brush.drawPolyline(
new int[] {w52, w, w, 1, 1, w48},
new int[] {h52, h52, h, h,
h52, h52},
6);
brush.drawLine(w48, h48, w48, h52);
brush.drawLine(w52, h48, w52, h52);
}
}

View File

@ -0,0 +1,169 @@
package org.nanoboot.utils.timecalc.swing.progress;
import org.nanoboot.utils.timecalc.utils.property.BooleanProperty;
import org.nanoboot.utils.timecalc.utils.property.IntegerProperty;
import org.nanoboot.utils.timecalc.utils.property.ReadOnlyProperty;
import java.util.Calendar;
import java.util.Date;
public class Time extends Thread {
private final IntegerProperty yearReadWriteProperty
= new IntegerProperty("yearProperty");
private final IntegerProperty monthReadWriteProperty
= new IntegerProperty("monthProperty");
private final IntegerProperty dayReadWriteProperty
= new IntegerProperty("dayProperty");
private final IntegerProperty hourReadWriteProperty
= new IntegerProperty("hourProperty");
private final IntegerProperty minuteReadWriteProperty
= new IntegerProperty("minuteProperty");
private final IntegerProperty secondReadWriteProperty
= new IntegerProperty("secondProperty");
private final IntegerProperty millisecondReadWriteProperty
= new IntegerProperty("millisecondProperty");
private final IntegerProperty dayOfWeekReadWriteProperty
= new IntegerProperty("dayOfWeek");
public ReadOnlyProperty<Integer> yearProperty
= yearReadWriteProperty.asReadOnlyProperty();
public ReadOnlyProperty<Integer> monthProperty
= monthReadWriteProperty.asReadOnlyProperty();
public ReadOnlyProperty<Integer> dayProperty
= dayReadWriteProperty.asReadOnlyProperty();
public ReadOnlyProperty<Integer> hourProperty
= hourReadWriteProperty.asReadOnlyProperty();
public ReadOnlyProperty<Integer> minuteProperty
= minuteReadWriteProperty.asReadOnlyProperty();
public ReadOnlyProperty<Integer> secondProperty
= secondReadWriteProperty.asReadOnlyProperty();
public ReadOnlyProperty<Integer> millisecondProperty
= millisecondReadWriteProperty.asReadOnlyProperty();
public ReadOnlyProperty<Integer> dayOfWeekProperty
= dayOfWeekReadWriteProperty.asReadOnlyProperty();
public final IntegerProperty yearCustomProperty
= new IntegerProperty("yearCustomProperty", Integer.MAX_VALUE);
public final IntegerProperty monthCustomProperty
= new IntegerProperty("monthCustomProperty", Integer.MAX_VALUE);
public final IntegerProperty dayCustomProperty
= new IntegerProperty("dayCustomProperty", Integer.MAX_VALUE);
public final IntegerProperty hourCustomProperty
= new IntegerProperty("hourCustomProperty", Integer.MAX_VALUE);
public final IntegerProperty minuteCustomProperty
= new IntegerProperty("minuteCustomProperty", Integer.MAX_VALUE);
public final IntegerProperty secondCustomProperty
= new IntegerProperty("secondCustomProperty", Integer.MAX_VALUE);
public final IntegerProperty millisecondCustomProperty
= new IntegerProperty("millisecondCustomProperty", Integer.MAX_VALUE);
public final BooleanProperty allowCustomValuesProperty
= new BooleanProperty("allowCustomValuesProperty", false);
//private long lastUpdateNanoTime = 0l;
public Time() {
this.setDaemon(true);
start();
}
public Calendar asCalendar() {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, returnValueAsNeeded(yearProperty, yearCustomProperty, Calendar.YEAR));
cal.set(Calendar.MONTH, returnValueAsNeeded(monthProperty, monthCustomProperty, Calendar.MONTH) - 1);
cal.set(Calendar.DAY_OF_MONTH, returnValueAsNeeded(dayProperty, dayCustomProperty, Calendar.DAY_OF_MONTH));
cal.set(Calendar.HOUR_OF_DAY, returnValueAsNeeded(hourProperty, hourCustomProperty, Calendar.HOUR_OF_DAY));
cal.set(Calendar.MINUTE, returnValueAsNeeded(minuteProperty, minuteCustomProperty, Calendar.MINUTE));
cal.set(Calendar.SECOND, returnValueAsNeeded(secondProperty, secondCustomProperty, Calendar.SECOND));
cal.set(Calendar.MILLISECOND, returnValueAsNeeded(millisecondProperty, millisecondCustomProperty, Calendar.MILLISECOND));
return cal;
}
private int returnValueAsNeeded(ReadOnlyProperty<Integer> real, IntegerProperty custom, int timeUnit) {
return returnValueAsNeeded(real.getValue(), custom.getValue(), timeUnit);
}
private int returnValueAsNeeded(int real, int custom, int timeUnit) {
if (this.allowCustomValuesProperty.isDisabled()) {
return real;
}
int month = monthProperty.getValue();
if (timeUnit == Calendar.DAY_OF_MONTH && (month == 2 || month == 4
|| month == 6 || month == 9
|| month == 11)) {
if (month == 2) {
boolean leapYear = this.yearProperty.getValue() % 4 == 0;
if (custom > (leapYear ? 29 : 28)) {
custom = (leapYear ? 29 : 28);
}
} else {
if (custom > 30) {
custom = 30;
}
}
}
return custom == Integer.MAX_VALUE ? real : custom;
}
public void run() {
while (true) {
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
yearReadWriteProperty.setValue(returnCustomValueIfNeeded(cal, Calendar.YEAR, yearCustomProperty, yearProperty));
monthReadWriteProperty.setValue(returnCustomValueIfNeeded(cal, Calendar.MONTH, monthCustomProperty, monthProperty));
dayReadWriteProperty.setValue(returnCustomValueIfNeeded(cal, Calendar.DAY_OF_MONTH, dayCustomProperty, dayProperty));
hourReadWriteProperty.setValue(returnCustomValueIfNeeded(cal, Calendar.HOUR_OF_DAY, hourCustomProperty, hourProperty));
minuteReadWriteProperty.setValue(returnCustomValueIfNeeded(cal, Calendar.MINUTE, minuteCustomProperty, minuteProperty));
secondReadWriteProperty.setValue(returnCustomValueIfNeeded(cal, Calendar.SECOND, secondCustomProperty, secondProperty));
millisecondReadWriteProperty.setValue(returnCustomValueIfNeeded(cal, Calendar.MILLISECOND, millisecondCustomProperty, millisecondProperty));
boolean customDayOfWeek = yearCustomProperty.getValue() != Integer.MAX_VALUE || monthCustomProperty.getValue() != Integer.MAX_VALUE || dayCustomProperty.getValue() != Integer.MAX_VALUE;
int dayOfWeek = customDayOfWeek ? asCalendar().get(Calendar.DAY_OF_WEEK) : cal.get(Calendar.DAY_OF_WEEK);
dayOfWeek = dayOfWeek == 1 ? 7 : dayOfWeek - 1;
dayOfWeekReadWriteProperty
.setValue(dayOfWeek);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println(e);
}
}
}
public void writeString() {
System.out.println(
yearProperty.getValue() + " "
+ monthProperty.getValue() + " "
+ dayProperty.getValue() + " "
+ hourProperty.getValue() + " "
+ minuteProperty.getValue() + " "
+ secondProperty.getValue() + " "
+ millisecondProperty.getValue() + " "
+ dayOfWeekProperty.getValue() + " "
);
}
// private int returnCustomValueIfNeeded(Calendar cal, int timeUnit,ReadOnlyProperty<Integer> real,IntegerProperty custom) {
// return returnCustomValueIfNeeded(cal, timeUnit, real, custom);
// }
private int returnCustomValueIfNeeded(Calendar cal, int timeUnit,
IntegerProperty custom,
ReadOnlyProperty<Integer> real) {
boolean allow = allowCustomValuesProperty.isEnabled();
Integer customValue = custom.getValue();
int month = monthProperty.getValue();
if (allow && customValue != Integer.MAX_VALUE) {
if(timeUnit == Calendar.DAY_OF_MONTH && (month == 2 || month ==4 || month == 6 || month == 9 || month == 11)) {
if(cal.getActualMaximum(Calendar.DAY_OF_MONTH) < custom.getValue()) {
return cal.getActualMaximum(Calendar.DAY_OF_MONTH);
}
}
return custom.getValue();
} else {
return timeUnit == Calendar.MONTH ? (cal.get(timeUnit) + 1) : cal.get(timeUnit);
}
}
}

View File

@ -0,0 +1,159 @@
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.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;
import org.nanoboot.utils.timecalc.utils.common.Constants;
import org.nanoboot.utils.timecalc.utils.common.NumberFormats;
import org.nanoboot.utils.timecalc.utils.common.Utils;
import org.nanoboot.utils.timecalc.utils.property.Property;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.Timer;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.HashSet;
import java.util.Set;
/**
* @author Robert Vokac
* @since 21.02.2024
*/
public class WalkingHumanProgress extends Widget implements
GetProperty {
private static final String WALL = "||";
private static final int LINE_WHERE_HEAD_IS = 2;
public WalkingHumanProgress() {
setFont(new Font(Font.MONOSPACED, Font.PLAIN, 11));
setFocusable(false);
setForeground(Color.GRAY);
setBackground(MainWindow.BACKGROUND_COLOR);
new Timer(100, e -> {
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
setForeground(
visibility.isStronglyColored()
|| mouseOver
? Color.BLACK : Color.LIGHT_GRAY);
}).start();
}
private static final String createSpaces(int spaceCount) {
return createRepeatedString(spaceCount, ' ');
}
private static final String createRepeatedString(int count, char ch) {
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= count; i++) {
sb.append(ch);
}
return sb.toString();
}
@Override
public void paintWidget(Graphics brush) {
String string = createAsciiString();
if (string.isEmpty()) {
//nothing to do
} else {
String[] lines = string.split("\n");
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
brush.setColor(visibility.isStronglyColored() ? Color.BLUE
: visibility.isWeaklyColored() ? Color.GRAY
: Color.LIGHT_GRAY);
// if(mouseOver) {
// brush.drawRect(1,1,getWidth() - 2, getHeight() - 2);
// }
brush.setFont(SwingUtils.MEDIUM_MONOSPACE_FONT);
int y = SwingUtils.MARGIN;
int lineNumber = 0;
for (String line : lines) {
++lineNumber;
brush.drawString(line, SwingUtils.MARGIN, y);
if(lineNumber == LINE_WHERE_HEAD_IS) {
paintSmiley(visibility,
(Graphics2D) brush,
//29 309
29 + ((int) (280 * donePercent())),
y - 4, true);
}
y = y + SwingUtils.MARGIN;
}
}
}
private String createAsciiString() {
if (visibleProperty.isDisabled()) {
//nothing to do
return "";
}
boolean bodyEnabled = !shouldBeSmileyPainted();
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
this.setVisible(visibility != Visibility.NONE);
StringBuilder sb = new StringBuilder();
int spacesTotal = 40;
int spacesDone = (int) (donePercent() * spacesTotal);
if (spacesDone > spacesTotal) {
spacesDone = spacesTotal;
}
int spacesTodo = spacesTotal - (spacesDone < 0 ? 0 : spacesDone);
sb.append(WALL + createSpaces(spacesTotal + 6 - 2) + (spacesTodo == 0
? " \n" : "|======|\n"));
sb.append(WALL).append(createSpaces(spacesTotal + 4))
.append(spacesTodo == 0 ? "" : "| |").append("\n");
sb.append(
WALL + createSpaces(spacesDone) + (bodyEnabled ? HEAD : " ") + createSpaces(
spacesTodo) + (spacesTodo == 0
? " \\☼☼☼☼/ "
: "| _ |") + Constants.NEW_LINE
+ WALL + createSpaces(spacesDone) + (bodyEnabled ? BODY : " ") + createSpaces(
spacesTodo) + (spacesTodo == 0
? " ☼☼☼☼☼☼ "
: "| | |") + Constants.NEW_LINE
+ WALL + createSpaces(spacesDone) + (bodyEnabled ? LEGS : " ") + createSpaces(
spacesTodo) + (spacesTodo == 0
? " /☼☼☼☼\\ "
: "| |") + Constants.NEW_LINE
+ createRepeatedString(spacesTotal + 14, '=')
+ Constants.NEW_LINE + "Steps: "
+ NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES
.format(donePercent() * ((double) spacesTotal)) + "/"
+ spacesTotal + " Done: " + NumberFormats.FORMATTER_EIGHT_DECIMAL_PLACES
.format(donePercent() * 100d) + "%"
);
return sb.toString();
}
@Override
public Property getVisibilityProperty() {
return visibilityProperty;
}
@Override
public Property getVisibilitySupportedColoredProperty() {
return visibilitySupportedColoredProperty;
}
}

View File

@ -0,0 +1,408 @@
package org.nanoboot.utils.timecalc.swing.progress.battery;
import lombok.Getter;
import org.nanoboot.utils.timecalc.app.TimeCalcProperty;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.swing.common.Widget;
import org.nanoboot.utils.timecalc.utils.common.NumberFormats;
import org.nanoboot.utils.timecalc.utils.common.Utils;
import org.nanoboot.utils.timecalc.utils.property.BooleanProperty;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
public class Battery extends Widget {
public static final Color LOW_WEAKLY_COLORED = new Color(253, 130, 130);
public static final Color MEDIUM_WEAKLY_COLORED = new Color(255, 204, 153);
public static final Color HIGH_WEAKLY_COLORED = new Color(204, 255, 204);
public static final Color HIGHEST_WEAKLY_COLORED = new Color(153, 255, 153);
public static final Color LOW_STRONGLY_COLORED = Color.red;
public static final Color MEDIUM_STRONGLY_COLORED = Color.ORANGE;
public static final Color HIGH_STRONGLY_COLORED = new Color(158, 227, 158);
public static final Color HIGHEST_STRONGLY_COLORED = Color.green;
public static final double CRITICAL_LOW_ENERGY = 0.10;
public static final double LOW_ENERGY = 0.20;
public static final double HIGH_ENERGY = 0.75;
public static final double VERY_HIGH_ENERGY = 0.9;
public static final Color LIGHT_RED = new Color(
229, 168, 168);
public static final Color ULTRA_LIGHT_RED = new Color(
238, 196, 196);
public static final String CHARCHING = "";
public static final String COLON = ":";
@Getter
private final String name;
private final double[] randomDoubles
= new double[]{1d, 1d, 1d, 1d, 1d, 1d, 1};
private final BooleanProperty blinking = new BooleanProperty("blinking");
public static Color getColourForProgress(double donePercent,
Visibility visibility, boolean mouseOver) {
if (visibility.isGray()) {
return Utils.ULTRA_LIGHT_GRAY;
}
boolean stronglyColored = visibility.isStronglyColored() || mouseOver;
Color low = stronglyColored ? LOW_STRONGLY_COLORED : LOW_WEAKLY_COLORED;
Color medium = stronglyColored ? MEDIUM_STRONGLY_COLORED :
MEDIUM_WEAKLY_COLORED;
Color high = stronglyColored ? HIGH_STRONGLY_COLORED : HIGH_WEAKLY_COLORED;
Color highest = stronglyColored ? HIGHEST_STRONGLY_COLORED :
HIGHEST_WEAKLY_COLORED;
Color result = donePercent < LOW_ENERGY ? low
: (donePercent < HIGH_ENERGY
? medium
: (donePercent < VERY_HIGH_ENERGY
? high
: highest));
return result;
// if(donePercent < CRITICAL_LOW_ENERGY) {
// return result;
// }
// if(donePercent > VERY_HIGH_ENERGY) {
// return result;
// }
// double transition = 0d;
// if (donePercent < LOW_ENERGY) {
// transition = (donePercent - CRITICAL_LOW_ENERGY) / (LOW_ENERGY
// - CRITICAL_LOW_ENERGY);
// } else {
// if (donePercent < HIGH_ENERGY) {
// transition =
// (donePercent - LOW_ENERGY) / (HIGH_ENERGY - LOW_ENERGY);
// } else {
// if (donePercent < VERY_HIGH_ENERGY) {
// transition = (donePercent - HIGH_ENERGY) / (VERY_HIGH_ENERGY
// - HIGH_ENERGY);
// }
// }
// }
//
// return getColorBetween(result, result == low ? medium : (result == medium ? high : highest), transition, donePercent);
}
private static Map<String, Color> colorCache = new HashMap<>();
// private static Color getColorBetween(Color color1, Color color2, double transition, double progress) {
// if(color1.equals(color2)) {
// return color1;
// }
// int red1 = color1.getRed();
// int green1 = color1.getGreen();
// int blue1 = color1.getBlue();
// int red2 = color2.getRed();
// int green2 = color2.getGreen();
// int blue2 = color2.getBlue();
// int redDiff = Math.abs(red2-red1);
// int greenDiff = Math.abs(green2-green1);
// int blueDiff = Math.abs(blue2-blue1);
// int red = (int) (Math.min(red1, red2) + ((double)redDiff) * transition);
// int green = (int) (Math.min(green1, green2) + ((double)greenDiff) * transition);
// int blue = (int) (Math.min(blue1, blue2) + ((double)blueDiff) * transition);
// String key = red + COLON + green + COLON + blue;
//
//// try {new Color(red, green, blue);} catch (Exception e) {
//// System.out.println(key);
//// System.out.println("\n\n\nred1=" + red1);
//// System.out.println("green1=" + green1);
//// System.out.println("blue1=" + blue1);
//// System.out.println("red2=" + red2);
//// System.out.println("green2=" + green2);
//// System.out.println("blue2=" + blue2);
//// System.out.println("redDiff=" + redDiff);
//// System.out.println("greenDiff=" + greenDiff);
//// System.out.println("blueDiff=" + blueDiff);
//// System.out.println("red=" + red);
//// System.out.println("green=" + green);
//// System.out.println("blue=" + blue);
//// System.out.println("transition=" + transition);
//// System.out.println("progress=" + progress);
////
//// return Color.LIGHT_GRAY;
//// }
//
// if(!colorCache.containsKey(key)) {
// colorCache.put(key, new Color(red, green, blue));
// }
// return colorCache.get(key);
//
// }
public BooleanProperty wavesVisibleProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_WAVES_VISIBLE
.getKey(), true);
public BooleanProperty circleProgressVisibleProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_CIRCLE_PROGRESS_VISIBLE
.getKey(), true);
public BooleanProperty percentProgressVisibleProperty = new BooleanProperty(
TimeCalcProperty.BATTERY_PERCENT_PROGRESS_VISIBLE
.getKey(), true);
public BooleanProperty chargingCharacterVisibleProperty
= new BooleanProperty(
TimeCalcProperty.BATTERY_CHARGING_CHARACTER_VISIBLE
.getKey(), true);
public BooleanProperty nameVisibleProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_NAME_VISIBLE
.getKey(), true);
public BooleanProperty labelVisibleProperty
= new BooleanProperty(TimeCalcProperty.BATTERY_LABEL_VISIBLE
.getKey(), true);
public BooleanProperty blinkingIfCriticalLowVisibleProperty
= new BooleanProperty(
TimeCalcProperty.BATTERY_BLINKING_IF_CRITICAL_LOW
.getKey(), true);
public final BooleanProperty quarterIconVisibleProperty
= new BooleanProperty(
TimeCalcProperty.BATTERY_QUARTER_ICON_VISIBLE
.getKey(), true);
private long tmpNanoTime = 0l;
private int totalHeight = 0;
private int totalWidth;
private String label = null;
protected Battery(String name) {
this.name = name;
setPreferredSize(new Dimension(40, 100));
this.typeProperty.setValue(getClass().getSimpleName().replace("Battery", "").toLowerCase(
Locale.ROOT));
}
protected Battery(String name, int i, int y, int height) {
this(name);
setBounds(i, y, height);
}
@Override
public void paintWidget(Graphics g) {
if (totalHeight == 0) {
this.totalHeight = (int) (this.getHeight() / 10d * 7d);
this.totalWidth = this.getWidth();
}
double donePercent = donePercent();
if (blinkingIfCriticalLowVisibleProperty.isEnabled()) {
if (donePercent > 0 && donePercent <= CRITICAL_LOW_ENERGY
&& (System.nanoTime() - tmpNanoTime) > (1000000000l) / 2l) {
blinking.flip();
tmpNanoTime = System.nanoTime();
}
if (donePercent > CRITICAL_LOW_ENERGY && blinking.isEnabled()) {
blinking.disable();
}
if (donePercent <= 0 && blinking.getValue()) {
blinking.setValue(false);
}
} else {
if (blinking.isEnabled()) {
blinking.disable();
}
}
Graphics2D brush = (Graphics2D) g;
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
brush.setColor(
visibility.isStronglyColored() || mouseOver ? Color.YELLOW
: FOREGROUND_COLOR);
brush.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if (!visibility.isGray()) {
brush.fillRect(1, 1, totalWidth, totalHeight);
}
brush.setColor(getColourForProgress(donePercent, visibility, mouseOver));
if (blinking.getValue()) {
brush.setColor(BACKGROUND_COLOR);
}
int doneHeight = (int) (totalHeight * donePercent);
int intX = 1;
int todoHeight = totalHeight - doneHeight;
double surfacePower
= 1;//donePercent < 0.5 ? 0.5 : donePercent;// (donePercent * 100 - ((int)(donePercent * 100)));
int waterSurfaceHeight
= (int) (4 * surfacePower);//2 + (int) (Math.random() * 3);
if (waterSurfaceHeight <= 2 || wavesVisibleProperty.isDisabled() || !changedInTheLastXMilliseconds(1000)) {
waterSurfaceHeight = 0;
}
brush.fillRect(intX + 1,
doneHeight < waterSurfaceHeight || donePercent >= 1
? todoHeight : todoHeight + waterSurfaceHeight,
totalWidth - 3,
doneHeight < waterSurfaceHeight || donePercent >= 1
? doneHeight : doneHeight - waterSurfaceHeight + 1);
int pointCount = 8;
if (doneHeight >= waterSurfaceHeight
&& donePercent < 1) {// && todoHeight > waterSurfaceHeight) {
//g2d.fillArc(intX, intY, width_, intHeight - waterSurfaceHeight, 30, 60);
brush.fillPolygon(
new int[]{intX,
(int) (intX + totalWidth / pointCount * 0.5),
intX + totalWidth / pointCount * 3,
intX + totalWidth / pointCount * 4,
intX + totalWidth / pointCount * 5,
intX + totalWidth / pointCount * 6,
intX + totalWidth / pointCount * 7,
intX + totalWidth / pointCount * 8},
new int[]{todoHeight + (waterSurfaceHeight * 1),
todoHeight + (int) (waterSurfaceHeight * getRandom(
0)),
todoHeight + (int) (waterSurfaceHeight * getRandom(
1)),
todoHeight + (int) (waterSurfaceHeight * getRandom(
2)),
todoHeight + (int) (waterSurfaceHeight * getRandom(
3)),
todoHeight + (int) (waterSurfaceHeight * getRandom(
4)),
todoHeight + (int) (waterSurfaceHeight * getRandom(
5)),
todoHeight + (waterSurfaceHeight * 1)},
pointCount);
brush.setColor(
(visibility.isGray() || !visibility.isStronglyColored())
&& !mouseOver ? Utils.ULTRA_LIGHT_GRAY : Color.DARK_GRAY);
brush.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_OFF);
brush.drawPolyline(
new int[]{intX,
(int) (intX + totalWidth / pointCount * 0.5),
intX + totalWidth / pointCount * 3,
intX + totalWidth / pointCount * 4,
intX + totalWidth / pointCount * 5,
intX + totalWidth / pointCount * 6,
intX + totalWidth / pointCount * 7,
intX + totalWidth / pointCount * 8},
new int[]{todoHeight + (waterSurfaceHeight * 1),
todoHeight + (int) (waterSurfaceHeight * getRandom(
0, true)),
todoHeight + (int) (waterSurfaceHeight * getRandom(
1, true)),
todoHeight + (int) (waterSurfaceHeight * getRandom(
2, true)),
todoHeight + (int) (waterSurfaceHeight * getRandom(
3, true)),
todoHeight + (int) (waterSurfaceHeight * getRandom(
4, true)),
todoHeight + (int) (waterSurfaceHeight * getRandom(
5, true)),
todoHeight + (waterSurfaceHeight * 1)},
pointCount);
brush.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
}
brush.setColor(visibility.isStronglyColored() || mouseOver ? Color.BLACK
: Color.LIGHT_GRAY);
if (donePercent < 1 && donePercent > 0) {
{
Font currentFont = brush.getFont();
brush.setFont(BIG_FONT);
if (chargingCharacterVisibleProperty.isEnabled() && changedInTheLastXMilliseconds(1000)) {
paintChargingCharacter(brush);
}
brush.setFont(currentFont);
}
}
if (quarterIconVisibleProperty.isEnabled()) {
paintQuarterIcon(brush, visibility, totalWidth, totalHeight);
}
if (circleProgressVisibleProperty.isEnabled()) {
paintCircleProgress(brush, visibility, totalWidth, totalHeight);
}
if (donePercent > 0) {
Font currentFont = brush.getFont();
brush.setFont(BIG_FONT);
paintSmiley(visibility, brush, ((int) (totalWidth * 0.45)) + 15,
(donePercent < 0.5 ? totalHeight / 4 * 3
: (totalHeight / 4 * 1) + 10) + 8 - 16);
brush.setFont(currentFont);
}
if (percentProgressVisibleProperty.isEnabled()) {
brush.drawString(
(donePercent == 1 ? 100 : (NumberFormats.FORMATTER_THREE_DECIMAL_PLACES
.format(donePercent * 100))) + "%",
((int) (totalWidth * 0.15)),
donePercent > 0.5 ? totalHeight / 4 * 3
: totalHeight / 4 * 1);
}
if (labelVisibleProperty.isEnabled() && label != null && !label
.isEmpty()) {
brush.drawString(
label,
((int) (totalWidth * 0.15)),
(donePercent > 0.5 ? totalHeight / 4 * 3
: totalHeight / 4 * 1) + 20);
}
if (nameVisibleProperty.isEnabled() && name != null && !name
.isEmpty()) {
brush.drawString(
name,
((int) (totalWidth * 0.10)),
(totalHeight / 4 * 3) + 20 + 20);
}
brush.setColor(visibility.isStronglyColored() || mouseOver ? Color.BLACK
: Color.LIGHT_GRAY);
brush.drawRect(1, 1, totalWidth - 2, totalHeight);
}
public void paintChargingCharacter(Graphics2D brush) {
brush.drawString(
CHARCHING, ((int) (totalWidth * 0.45)),
(donePercent() < 0.5 ? totalHeight / 4 * 3
: (totalHeight / 4 * 1) + 10) + 10
);
}
private double getRandom(int index) {
return getRandom(index, false);
}
private double getRandom(int index, boolean keepArray) {
if (!keepArray && Math.random() > 0.96) {
randomDoubles[index] = Math.random();
}
return randomDoubles[index];
}
public String getLabel() {
return this.label;
}
public void setLabel(String label) {
this.label = label;
}
@Override
public void setBounds(int x, int y, int height) {
setBounds(x, y, (int) (50d / 100d * ((double) height)), height);
}
@Override
public int getTimerDelay() {
return 100;
}
}

View File

@ -0,0 +1,14 @@
package org.nanoboot.utils.timecalc.swing.progress.battery;
/**
* @author Robert Vokac
* @since 21.02.2024
*/
public class DayBattery extends Battery {
public static final String DAY = "Day";
public DayBattery(int x, int i, int i1) {
super(DAY, x, i, i1);
}
}

View File

@ -0,0 +1,15 @@
package org.nanoboot.utils.timecalc.swing.progress.battery;
/**
* @author Robert Vokac
* @since 21.02.2024
*/
public class HourBattery extends Battery {
public static final String HOUR = "Hour";
public HourBattery(int x, int i, int i1) {
super(HOUR, x, i, i1);
}
}

View File

@ -0,0 +1,15 @@
package org.nanoboot.utils.timecalc.swing.progress.battery;
/**
* @author Robert Vokac
* @since 21.02.2024
*/
public class MinuteBattery extends Battery {
public static final String MINUTE = "Minute";
public MinuteBattery(int x, int i, int i1) {
super(MINUTE, x, i, i1);
}
}

View File

@ -0,0 +1,15 @@
package org.nanoboot.utils.timecalc.swing.progress.battery;
/**
* @author Robert Vokac
* @since 21.02.2024
*/
public class MonthBattery extends Battery {
public static final String MONTH = "Month";
public MonthBattery(int x, int i, int i1) {
super(MONTH, x, i, i1);
}
}

View File

@ -0,0 +1,15 @@
package org.nanoboot.utils.timecalc.swing.progress.battery;
/**
* @author Robert Vokac
* @since 21.02.2024
*/
public class WeekBattery extends Battery {
public static final String WEEK = "Week";
public WeekBattery(int x, int i, int i1) {
super(WEEK, x, i, i1);
}
}

View File

@ -0,0 +1,15 @@
package org.nanoboot.utils.timecalc.swing.progress.battery;
/**
* @author Robert Vokac
* @since 21.02.2024
*/
public class YearBattery extends Battery {
public static final String YEAR = "Year";
public YearBattery(int x, int i, int i1) {
super(YEAR, x, i, i1);
}
}

View File

@ -0,0 +1,43 @@
/*
* 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.progress.weather;
import lombok.Getter;
import org.nanoboot.utils.timecalc.utils.common.NumberFormats;
/**
*
* @author robertvokac
*/
public enum Cloudiness {
CLOUDY("Cloudy", 7d/8d),
MOSTLY_CLOUDY("Mostly cloudy", 5d/8d),
PARTLY_CLOUDY("Partly cloudy and partly sunny", 3d/8d),
MOSTLY_SUNNY("Mostly clear and mostly sunny", 1d/8d),
SUNNY("Clear/Sunny", 0/8);
@Getter
private String description;
private double ifMoreOrEqual;
Cloudiness(String description, double ifMoreOrEqual) {
this.description = description;
this.ifMoreOrEqual = ifMoreOrEqual;
}
public static Cloudiness forValue(double value) {
for (Cloudiness c : Cloudiness.values()) {
if (value >= c.ifMoreOrEqual) {
return c;
}
}
throw new IllegalStateException("Unsupported value: " + NumberFormats.FORMATTER_TWO_DECIMAL_PLACES.format(value));
}
// Cloudy: 90-100% sky covered
// Mostly cloudy: 70-80% sky covered
// Partly Cloudy/Partly Sunny: 30-60% sky covered
// Mostly Clear/Mostly Sunny: 10-30% sky covered
// Clear/Sunny: 0-10% sky covered
}

View File

@ -0,0 +1,300 @@
package org.nanoboot.utils.timecalc.swing.progress.weather;
import org.nanoboot.utils.timecalc.app.GetProperty;
import org.nanoboot.utils.timecalc.entity.Visibility;
import org.nanoboot.utils.timecalc.entity.WidgetType;
import org.nanoboot.utils.timecalc.swing.common.SwingUtils;
import org.nanoboot.utils.timecalc.swing.common.Widget;
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.TTime;
import org.nanoboot.utils.timecalc.utils.common.Utils;
import org.nanoboot.utils.timecalc.utils.property.Property;
import javax.swing.Timer;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import javax.swing.JMenuItem;
import org.nanoboot.utils.timecalc.swing.progress.Time;
import org.nanoboot.utils.timecalc.utils.common.NumberFormats;
/**
* @author Robert Vokac
* @since 21.02.2024
*/
public class ProgressWeather extends Widget implements GetProperty {
private final Time time;
private int lastAdd = 0;
private List<JMenuItem> menuItems = null;
private boolean information;
public ProgressWeather(Time time) {
this.time = time;
setFont(new Font(Font.MONOSPACED, Font.PLAIN, 11));
setFocusable(false);
setForeground(Color.GRAY);
setBackground(MainWindow.BACKGROUND_COLOR);
this.typeProperty.setValue(WidgetType.DAY.name().toLowerCase(Locale.ROOT));
new Timer(100, e -> {
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
setForeground(
visibility.isStronglyColored()
|| mouseOver
? Color.BLACK : Color.LIGHT_GRAY);
}).start();
}
private static Map<Integer, List<WeatherForecast>> forecastsForYears = new HashMap<>();
public int getTimerDelay() {
return 100;
}
@Override
public void paintWidget(Graphics brush) {
Visibility visibility
= Visibility.valueOf(visibilityProperty.getValue());
brush.setColor(visibility.isStronglyColored() ? Color.BLUE
: visibility.isWeaklyColored() ? Color.GRAY
: Color.LIGHT_GRAY);
brush.setFont(SwingUtils.MEDIUM_MONOSPACE_FONT);
int year = time.yearProperty.getValue();
if (!forecastsForYears.containsKey(year)) {
File weatherFile = new File(FileConstants.WEATHER_CSV.getParentFile(),
String.valueOf(year) + '_' + FileConstants.WEATHER_CSV.getName());
System.out.println(weatherFile.getAbsolutePath());
if (!weatherFile.exists()) {
List<WeatherForecast> forecasts = WeatherForecast.createForecast(year);
Utils.writeTextToFile(
weatherFile,
"Date\tMinC\tMaxC\tMinTime\tMaxTime\tWind\tCloudiness\tThunder\tRain\tSnow\tHumidity\tHearOrColdWave\tStartC\tEndC\n"
+ forecasts.stream().map(w -> w.toCsv()).collect(
Collectors.joining("\n")));
}
List<WeatherForecast> forecasts = new ArrayList<>();
try {
Arrays.stream(Utils.readTextFromFile(weatherFile).split("\n"))
.filter(line -> !line.startsWith("Date"))
.filter(line -> !line.isEmpty()).forEach(line -> forecasts.add(new WeatherForecast().fromCsv(line)));
} catch (IOException e) {
System.out.println("Loading file failed: " + weatherFile + " " + e
.getMessage());
e.printStackTrace();
return;
}
forecastsForYears.put(year, forecasts);
}
List<WeatherForecast> forecasts = forecastsForYears.get(year);
// if(!w){
// w= true;
// List<Double> temperature = new ArrayList<>();
// forecasts.stream().forEach(f -> {
//
// for (int hour = 0; hour < 24; hour++) {
// //for (int minute = 0; minute < 60; minute = minute + 30) {
// int minute = 0;
// double forHour = ((double)(new TTime(hour, minute).toTotalMilliseconds() / 1000d / 60d / 60d));
// temperature.add(f.getCelsiusForHour(forHour));
// //}
// }
// });
// StringBuilder sb = new StringBuilder();
// temperature.stream().forEach(t -> sb.append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(t)).append("\n"));
// Utils.writeTextToFile(new File("t.csv"), sb.toString());
// }
int currentSecond = time.secondProperty.getValue();
Calendar cal = time.asCalendar();
int add = (currentSecond % 21);
if (paused) {
add = lastAdd;
} else {
if (add < 3) {
add = 0;
} else if (add < 6) {
add = 1;
} else if (add < 9) {
add = 2;
} else if (add < 12) {
add = 3;
} else if (add < 15) {
add = 4;
} else if (add < 18) {
add = 5;
} else if (add < 21) {
add = 6;
}
this.lastAdd = add;
}
if (add > 0) {
cal.add(Calendar.DAY_OF_MONTH, add);
}
int currentDayOfWeek = time.dayOfWeekProperty.getValue();
int forecastDayOfWeek = currentDayOfWeek + add;
// String dayOfWeekAsString = DayOfWeekTC.forNumber(forecastDayOfWeek).name();
// dayOfWeekAsString = dayOfWeekAsString.substring(0,1).toUpperCase(Locale.ROOT) + dayOfWeekAsString.substring(1, dayOfWeekAsString.length());
WeatherForecast wf = forecasts.stream().filter(f -> f.getDate().equals(DateFormats.DATE_TIME_FORMATTER_YYYYMMDD.format(cal.getTime()))).findFirst().orElse(new WeatherForecast());
if(information) {
information = false;
StringBuilder sb = new StringBuilder();
sb.append("Date: ").append(wf.getDate()).append("\n");
sb
.append("Start: ")
.append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(wf.getStartCelsius()))
.append(" °C at 00:00")
.append("\n");
sb
.append("Minimum: ")
.append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(wf.getMinimumCelsius()))
.append(" °C at ").append(TTime.ofMilliseconds((int) (wf.getMinimumCelsiusTime() * 1000d * 60d * 60d)).toString().substring(0, 5))
.append("\n");
sb
.append("Maximum: ")
.append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(wf.getMaximumCelsius()))
.append(" °C at ").append(TTime.ofMilliseconds((int) (wf.getMaximumCelsiusTime() * 1000d * 60d * 60d)).toString().substring(0, 5))
.append("\n");
sb
.append("End: ")
.append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(wf.getEndCelsius()))
.append(" °C at 24:00")
.append("\n");
sb.append("Wind: ").append((int)wf.getWind()).append(" m/s\n");
sb.append("Cloudiness: ").append(Cloudiness.forValue(wf.getCloudiness()).getDescription().toLowerCase()).append("\n");
if(wf.getThunder() > 0d) {
sb.append("Thunder strenth: ").append(NumberFormats.FORMATTER_ZERO_DECIMAL_PLACES.format(wf.getThunder() * 100d)).append("%\n");
}
sb.append("Rain: ").append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(wf.getRain())).append(" mm\n");
if(wf.getSnow() > 0d) {
sb.append("Snow: ").append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(wf.getSnow())).append(" mm\n");
}
sb.append("Humidity: ").append((int)(wf.getHumidity() * 100d * 0.6)).append(" %\n");
if(wf.getHeatOrColdWave() < 0.5d) {
sb.append("Cold Wave: ").append(NumberFormats.FORMATTER_ZERO_DECIMAL_PLACES.format(100d - (wf.getHeatOrColdWave() * 2 * 100d))).append(" %\n");
} else {
sb.append("Heat Wave: ").append(NumberFormats.FORMATTER_ZERO_DECIMAL_PLACES.format((wf.getHeatOrColdWave() - 0.5d) * 2 * 100d)).append(" %\n");
}
WeatherForecast f1 = forecasts.get(forecasts.indexOf(wf) + 1);
WeatherForecast f2 = forecasts.get(forecasts.indexOf(wf) + 2);
WeatherForecast f3 = forecasts.get(forecasts.indexOf(wf) + 3);
WeatherForecast f4 = forecasts.get(forecasts.indexOf(wf) + 4);
WeatherForecast f5 = forecasts.get(forecasts.indexOf(wf) + 5);
WeatherForecast f6 = forecasts.get(forecasts.indexOf(wf) + 6);
sb.append("Tomorrow: ").append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(f1.getMaximumCelsius())).append(" °C\n");
sb.append("Day after tomorrow: ").append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(f2.getMaximumCelsius())).append(" °C\n");
sb.append(" 2 days after tomorrow: ").append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(f3.getMaximumCelsius())).append(" °C\n");
sb.append(" 3 days after tomorrow: ").append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(f4.getMaximumCelsius())).append(" °C\n");
sb.append(" 4 days after tomorrow: ").append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(f5.getMaximumCelsius())).append(" °C\n");
sb.append(" 5 days after tomorrow: ").append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(f6.getMaximumCelsius())).append(" °C\n");
Utils.showNotification(sb.toString(), 30000, 400);
}
String[] array = wf.asPrettyString(add > 0 ? -1 : new TTime(time.hourProperty.getValue(),
time.minuteProperty.getValue(),
time.secondProperty.getValue(),
time.millisecondProperty.getValue()).toTotalMilliseconds() / 1000d / 60d / 60d).split(WeatherForecast.DOUBLE_COLON);
List<String> list = null;
for (String a : array) {
if (a.length() >= 14) {
list = new ArrayList<>();
break;
}
}
if (list != null) {
for (String a : array) {
if (a.length() >= 14) {
list.add(a.substring(0, 14));
list.add(a.substring(14, a.length()));
} else {
list.add(a);
}
}
array = new String[list.size()];
for (int i = 0; i < list.size(); i++) {
array[i] = list.get(i);
}
}
int rowHeight = 12;
int row = 0;
brush.drawString(DateFormats.DATE_TIME_FORMATTER_YYYYMMDD.format(cal.getTime()), 0, SwingUtils.MARGIN + row);
row = row + 12;
brush.drawString(DateFormats.DATE_TIME_FORMATTER_DAY_OF_WEEK.format(cal.getTime()), 0, SwingUtils.MARGIN + row);
row = row + rowHeight + 10;
brush.drawString(array[0], 0, SwingUtils.MARGIN + row);
row = row + rowHeight;
brush.drawString(array.length < 2 ? "" : array[1], 0, SwingUtils.MARGIN + row);
row = row + rowHeight;
brush.drawString(array.length < 3 ? "" : array[2], 0, SwingUtils.MARGIN + row);
row = row + rowHeight;
if (array.length >= 4) {
brush.drawString(array[3], 0, SwingUtils.MARGIN + row);
row = row + rowHeight;
}
if (array.length >= 5) {
brush.drawString(array[4], 0, SwingUtils.MARGIN + row);
row = row + rowHeight;
}
this.setToolTipText(wf.toString());
}
//private boolean w = false;
@Override
public Property getVisibilityProperty() {
return visibilityProperty;
}
@Override
public Property getVisibilitySupportedColoredProperty() {
return visibilitySupportedColoredProperty;
}
@Override
public List<JMenuItem> createAdditionalMenus() {
if (this.menuItems == null) {
menuItems = new ArrayList<>();
JMenuItem pauseResume = new JMenuItem("Pause/Resume");
pauseResume.addActionListener(e -> paused = !paused);
menuItems.add(pauseResume);
JMenuItem now = new JMenuItem("Now");
now.addActionListener(e -> {
lastAdd = 0;
paused = true;
});
menuItems.add(now);
JMenuItem info = new JMenuItem("Info");
info.addActionListener(e -> {
information = true;
});
menuItems.add(info);
}
return this.menuItems;
}
private boolean paused = false;
}

View File

@ -0,0 +1,17 @@
package org.nanoboot.utils.timecalc.swing.progress.weather;
import java.util.Arrays;
/**
* @author pc00289
* @since 25.03.2024
*/
public class UtilityWhichKeysAreUsed {
public static void main(String[] args) {
String javaCode = "";
Arrays.stream(javaCode.split("\n")).filter(l->l.contains("VK_"))
.map(l->l.replace("case KeyEvent.VK_",""))
.map(l->l.replace(": {","")).sorted()
.forEach(System.out::println);
}
}

View File

@ -0,0 +1,555 @@
package org.nanoboot.utils.timecalc.swing.progress.weather;
import lombok.Getter;
import lombok.Setter;
import org.nanoboot.utils.timecalc.utils.common.FileConstants;
import org.nanoboot.utils.timecalc.utils.common.NumberFormats;
import java.io.FileInputStream;
import java.io.IOException;
import java.time.LocalDate;
import java.time.Month;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import lombok.ToString;
import org.nanoboot.utils.timecalc.utils.common.DateFormats;
/**
* @author pc00289
* @since 22.03.2024
*/
@Getter
@Setter
@ToString
public class WeatherForecast {
//01:00-4:00 - minimum
//13:00-16:00 - maximum
//20240101.minTempC=
//20240101.maxTempC=
// 20240101.minTempTime=
//20240101.maxTempTime=
//20240101.wind={m/s}
//20240101.cloudiness={0.0 - 1.0}
//20240101.thunder={0.0 - 1.0}
//20240101.rain={mm}
//20240101.snow={mm}
//#20240101.sunrise=7:53
//#20240101.sunset=16:02
public static final String DOUBLE_COLON = "::";
private String date;
private double minimumCelsius;
private double maximumCelsius;
private double minimumCelsiusTime;
private double maximumCelsiusTime;
private double wind;
private double cloudiness;
private double thunder;
private double rain;
private double snow;
private double humidity;
private double heatOrColdWave;
private double startCelsius;
private double endCelsius;
public static List<WeatherForecast> createForecast(int year) {
List<WeatherForecast> list = new ArrayList<>();
Properties climateProperties = new Properties();
if (FileConstants.CLIMATE_TXT.exists()) {
try {
climateProperties.load(new FileInputStream(FileConstants.CLIMATE_TXT));
} catch (IOException e) {
e.printStackTrace();
System.out.println("Loading file failed: " + FileConstants.WEATHER_CSV + " " + e.getMessage());
//return list;
}
} else {
System.out.println("File does not exist: " + FileConstants.CLIMATE_TXT);
//return list;
}
double min1 = Double.valueOf(climateProperties.getProperty("1.min", "-20")) + 10;
double min2 = Double.valueOf(climateProperties.getProperty("2.min", "-16")) + 10;
double min3 = Double.valueOf(climateProperties.getProperty("3.min", "-12")) + 10;
double min4 = Double.valueOf(climateProperties.getProperty("4.min", "-8")) + 10;
double min5 = Double.valueOf(climateProperties.getProperty("5.min", "-4")) + 10;
double min6 = Double.valueOf(climateProperties.getProperty("6.min", "-2")) + 10;
double min7 = Double.valueOf(climateProperties.getProperty("7.min", "0")) + 10;
double min8 = Double.valueOf(climateProperties.getProperty("8.min", "0")) + 10;
double min9 = Double.valueOf(climateProperties.getProperty("9.min", "-2")) + 10;
double min10 = Double.valueOf(climateProperties.getProperty("10.min", "-4")) + 10;
double min11 = Double.valueOf(climateProperties.getProperty("11.min", "-8")) + 10;
double min12 = Double.valueOf(climateProperties.getProperty("12.min", "-16")) + 10;
double max1 = Double.valueOf(climateProperties.getProperty("1.max", "20"));
double max2 = Double.valueOf(climateProperties.getProperty("2.max", "15"));
double max3 = Double.valueOf(climateProperties.getProperty("3.max", "20"));
double max4 = Double.valueOf(climateProperties.getProperty("4.max", "25"));
double max5 = Double.valueOf(climateProperties.getProperty("5.max", "30"));
double max6 = Double.valueOf(climateProperties.getProperty("6.max", "35"));
double max7 = Double.valueOf(climateProperties.getProperty("7.max", "40"));
double max8 = Double.valueOf(climateProperties.getProperty("8.max", "40"));
double max9 = Double.valueOf(climateProperties.getProperty("9.max", "35"));
double max10 = Double.valueOf(climateProperties.getProperty("10.max", "30"));
double max11 = Double.valueOf(climateProperties.getProperty("11.max", "25"));
double max12 = Double.valueOf(climateProperties.getProperty("12.max", "20"));
Map<Integer, Map<Integer, Double>> minExpected = new HashMap<>();
Map<Integer, Map<Integer, Double>> maxExpected = new HashMap<>();
Calendar cal_ = Calendar.getInstance();
cal_.set(Calendar.YEAR, 2021);
cal_.set(Calendar.MONTH, 0);
cal_.set(Calendar.DAY_OF_MONTH, 1);
while (cal_.get(Calendar.YEAR) == 2021) {
int month = cal_.get(Calendar.MONTH) + 1;
int dayOfMonth = cal_.get(Calendar.DAY_OF_MONTH);
double min = 0d;
double max = 0d;
double minStart = 0d;
double minEnd = 0d;
double maxStart = 0d;
double maxEnd = 0d;
double transition = 0d;
LocalDate today = LocalDate.of(2021, Month.of(month), dayOfMonth);
LocalDate startDay = null;
LocalDate endDay = null;
if ((month == 12 && dayOfMonth >= 16) || (month == 1 && dayOfMonth <= 15)) {
minStart = min12;
minEnd = min1;
maxStart = max12;
maxEnd = max1;
startDay = LocalDate.of(2020, Month.DECEMBER, 16);
endDay = LocalDate.of(2021, Month.JANUARY, 15);
}
if ((month == 1 && dayOfMonth >= 16) || (month == 2 && dayOfMonth <= 14)) {
minStart = min1;
minEnd = min2;
maxStart = max1;
maxEnd = max2;
startDay = LocalDate.of(2021, Month.of(1), 16);
endDay = LocalDate.of(2021, Month.of(2), 14);
}
if ((month == 2 && dayOfMonth >= 15) || (month == 3 && dayOfMonth <= 15)) {
minStart = min2;
minEnd = min3;
maxStart = max2;
maxEnd = max3;
startDay = LocalDate.of(2021, Month.of(2), 15);
endDay = LocalDate.of(2021, Month.of(3), 16);
}
if ((month == 3 && dayOfMonth >= 16) || (month == 4 && dayOfMonth <= 15)) {
minStart = min3;
minEnd = min4;
maxStart = max3;
maxEnd = max4;
startDay = LocalDate.of(2021, Month.of(3), 16);
endDay = LocalDate.of(2021, Month.of(4), 15);
}
if ((month == 4 && dayOfMonth >= 16) || (month == 5 && dayOfMonth <= 15)) {
minStart = min4;
minEnd = min5;
maxStart = max4;
maxEnd = max5;
startDay = LocalDate.of(2021, Month.of(4), 16);
endDay = LocalDate.of(2021, Month.of(5), 15);
}
if ((month == 5 && dayOfMonth >= 16) || (month == 6 && dayOfMonth <= 15)) {
minStart = min5;
minEnd = min6;
maxStart = max5;
maxEnd = max6;
startDay = LocalDate.of(2021, Month.of(5), 16);
endDay = LocalDate.of(2021, Month.of(6), 15);
}
if ((month == 6 && dayOfMonth >= 16) || (month == 7 && dayOfMonth <= 15)) {
minStart = min6;
minEnd = min7;
maxStart = max6;
maxEnd = max7;
startDay = LocalDate.of(2021, Month.of(6), 16);
endDay = LocalDate.of(2021, Month.of(7), 15);
}
if ((month == 7 && dayOfMonth >= 16) || (month == 8 && dayOfMonth <= 15)) {
minStart = min7;
minEnd = min8;
maxStart = max7;
maxEnd = max8;
startDay = LocalDate.of(2021, Month.of(7), 16);
endDay = LocalDate.of(2021, Month.of(8), 15);
}
if ((month == 8 && dayOfMonth >= 16) || (month == 9 && dayOfMonth <= 15)) {
minStart = min8;
minEnd = min9;
maxStart = max8;
maxEnd = max9;
startDay = LocalDate.of(2021, Month.of(8), 16);
endDay = LocalDate.of(2021, Month.of(9), 15);
}
if ((month == 9 && dayOfMonth >= 16) || (month == 10 && dayOfMonth <= 15)) {
minStart = min9;
minEnd = min10;
maxStart = max9;
maxEnd = max10;
startDay = LocalDate.of(2021, Month.of(9), 16);
endDay = LocalDate.of(2021, Month.of(10), 15);
}
if ((month == 10 && dayOfMonth >= 16) || (month == 11 && dayOfMonth <= 15)) {
minStart = min10;
minEnd = min11;
maxStart = max10;
maxEnd = max11;
startDay = LocalDate.of(2021, Month.of(10), 16);
endDay = LocalDate.of(2021, Month.of(11), 15);
}
if ((month == 11 && dayOfMonth >= 16) || (month == 12 && dayOfMonth <= 15)) {
minStart = min11;
minEnd = min12;
maxStart = max11;
maxEnd = max12;
startDay = LocalDate.of(2021, Month.of(11), 16);
endDay = LocalDate.of(2021, Month.of(12), 15);
}
double daysBetween = ChronoUnit.DAYS.between(startDay, endDay) + 1;
double daysDone = ChronoUnit.DAYS.between(startDay, today) + 1;
if (daysDone > 365) {
daysDone = daysDone - 365;
}
transition = daysDone / daysBetween;
if (!minExpected.containsKey(month)) {
minExpected.put(month, new HashMap<Integer, Double>());
}
if (!maxExpected.containsKey(month)) {
maxExpected.put(month, new HashMap<Integer, Double>());
}
double minDiff = Math.abs(minEnd - minStart);
double maxDiff = Math.abs(maxEnd - maxStart);
double minAdd = (minDiff * transition * (minStart < maxEnd ? 1 : (-1)));
double maxAdd = (maxDiff * transition * (maxStart < maxEnd ? 1 : (-1)));
min = minStart + minAdd;
max = maxStart + maxAdd;
// System.out.print("\n" + month + "-" + dayOfMonth + ": ");
// System.out.print(" minStart= " + NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(minStart));
// System.out.print(" minEnd= " + NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(minEnd));
// System.out.print(" maxStart= " + NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(maxStart));
// System.out.print(" maxEnd= " + NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(maxEnd));
// System.out.println(" min and max: " + NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(min) + " " + NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(max));
// System.out.println(" min and max diff: " + NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(minDiff) + " " + NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(maxDiff));
// System.out.println("transition=" + transition);
// System.out.println("daysDone=" + daysDone + " daysBetween=" + daysBetween);
// System.out.println("startDay=" + startDay.toString());
// System.out.println("endDay=" + endDay.toString());
minExpected.get(month).put(dayOfMonth, min);
maxExpected.get(month).put(dayOfMonth, max);
cal_.add(Calendar.DAY_OF_MONTH, 1);
}
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, 0);
cal.set(Calendar.DAY_OF_MONTH, 1);
double humidity = Math.random() * 0.6;
double heatOrColdWave = Math.random();
int tooMuchHumidityDays = 0;
int tooMuchHeatDays = 0;
int tooMuchColdDays = 0;
double windiness = Math.random();
List<Double> maxCLastWeekAverage = new ArrayList<Double>();
List<Double> minCLastWeekAverage = new ArrayList<Double>();
double endCelsius = Double.MIN_VALUE;
while (cal.get(Calendar.YEAR) == year) {
if (humidity > 0.7) {
++tooMuchHumidityDays;
}
if (heatOrColdWave > 0.8) {
++tooMuchHeatDays;
}
if (heatOrColdWave < 0.3) {
++tooMuchColdDays;
}
if (tooMuchHumidityDays > 5) {
if (Math.random() > 0.5) {
humidity = Math.random() * 0.15;
}
}
if (tooMuchHeatDays > 5) {
if (Math.random() > 0.5) {
heatOrColdWave = Math.random() * 0.1;
}
}
if (tooMuchColdDays > 5) {
if (Math.random() > 0.5) {
heatOrColdWave = Math.random() * 0.9;
}
}
if (Math.random() > 0.75) {
humidity = humidity + Math.random() * 0.3 * (Math.random() > 0.9 ? (-1) : 1);
if (humidity > 1.0) {
humidity = 1.0;
}
if (humidity < 0.0) {
humidity = 0.0;
}
}
if (Math.random() > 0.95) {
humidity = 0.9 + Math.random() * 0.1;
}
if (Math.random() > 0.75) {
heatOrColdWave = heatOrColdWave + Math.random() * 0.1 * (Math.random() > 0.9 ? (-1) : 1);
if (heatOrColdWave > 1.0) {
heatOrColdWave = 1.0;
}
if (heatOrColdWave < 0.0) {
heatOrColdWave = 0.0;
}
if (heatOrColdWave > 0.85 && Math.random() > 0.25) {
heatOrColdWave = 0.85;
}
if (heatOrColdWave < 0.15 && Math.random() > 0.25) {
heatOrColdWave = 0.15;
}
}
int month = cal.get(Calendar.MONTH) + 1;
int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
WeatherForecast forecast = new WeatherForecast();
list.add(forecast);
forecast.setDate(DateFormats.DATE_TIME_FORMATTER_YYYYMMDD.format(cal.getTime()));
forecast.setMaximumCelsius(maxExpected.get(month).get((month == 2 && dayOfMonth == 29) ? 28 : dayOfMonth));
forecast.setMinimumCelsius(minExpected.get(month).get((month == 2 && dayOfMonth == 29) ? 28 : dayOfMonth));
double maxE = forecast.getMaximumCelsius();
double minE = forecast.getMinimumCelsius();
double maxExpectedCelsius = forecast.getMaximumCelsius();
double minExpectedCelsius = forecast.getMinimumCelsius();
if (Math.random() > 0.4) {
if (minE < -10) {
minE = minE + 10 + 10 * Math.random();
}
if (maxE > 40) {
maxE = maxE - 10 - 10 * Math.random();
}
}
if (minE < -10 && Math.random() > 0.5) {
heatOrColdWave = 0.7 + Math.random() * 0.2;
}
if (maxE > 38 && Math.random() > 0.5) {
heatOrColdWave = 0.1 + Math.random() * 0.1;
}
if (maxExpectedCelsius - 10 > maxCLastWeekAverage.stream().mapToDouble(e -> Double.valueOf(e)).average().orElse(maxExpectedCelsius - 10)) {
heatOrColdWave = heatOrColdWave + ((1.0d - heatOrColdWave) / 2d);
} else {
heatOrColdWave = heatOrColdWave / 2d;
}
if (minExpectedCelsius + 10 > minCLastWeekAverage.stream().mapToDouble(e -> Double.valueOf(e)).average().orElse(minExpectedCelsius + 10)) {
heatOrColdWave = heatOrColdWave + ((1.0d - heatOrColdWave) / 2d);
} else {
heatOrColdWave = heatOrColdWave / 2d;
}
double mediumHalf = minE + Math.abs(maxE - minE) / 2;
forecast.setMaximumCelsius(mediumHalf + heatOrColdWave * 1.1 * mediumHalf);
forecast.setMinimumCelsius(minE + heatOrColdWave * 1.5 * mediumHalf);
windiness = Math.random();
if (Math.random() > 0.9 && windiness < 0.15) {
windiness = 0d;
}
forecast.setWind(windiness * (Math.random() > 0.95 ? 40 : Math.random() * 150));
forecast.setCloudiness(Math.random() > 0.3 ? humidity : Math.random());
if (forecast.getMaximumCelsius() > 25 && Math.random() > 0.9) {
forecast.setThunder(Math.random());
}
if (humidity > 0.2) {
if (forecast.getMinimumCelsius() > 3) {
forecast.setRain(humidity * Math.random() * 50 * (Math.random() > 0.90 ? Math.random() * 10 : 1));
}
if (forecast.getMinimumCelsius() < 0) {
forecast.setSnow(humidity * Math.random() * 50 * (Math.random() > 0.90 ? Math.random() * 10 : 1));
}
if (forecast.getMinimumCelsius() > 0 && forecast.getMinimumCelsius() < 3) {
if (Math.random() > 0.5) {
forecast.setRain(humidity * Math.random() * 50 * (Math.random() > 0.90 ? Math.random() * 10 : 1));
} else {
forecast.setSnow(humidity * Math.random() * 50 * (Math.random() > 0.90 ? Math.random() * 10 : 1));
}
}
}
forecast.setHumidity(humidity);
forecast.setHeatOrColdWave(heatOrColdWave);
forecast.setMaximumCelsiusTime(12.0 + Math.random() * 5);
forecast.setMinimumCelsiusTime(02.0 + Math.random() * 4);
maxCLastWeekAverage.add(forecast.getMaximumCelsius());
minCLastWeekAverage.add(forecast.getMinimumCelsius());
while (maxCLastWeekAverage.size() > 7) {
maxCLastWeekAverage.remove(0);
}
while (minCLastWeekAverage.size() > 7) {
minCLastWeekAverage.remove(0);
}
if(endCelsius == Double.MIN_VALUE) {
forecast.setStartCelsius(forecast.getMinimumCelsius() + Math.random() * 8);
} else {
forecast.setStartCelsius(endCelsius);
}
forecast.setEndCelsius(forecast.getMinimumCelsius() + Math.random() * 5);
endCelsius = forecast.getEndCelsius();
// private String date;
// private double minimumCelsius;
// private double maximumCelsius;
// private double minimumCelsiusTime;
// private double maximumCelsiusTime;
// private double wind;
// private double cloudiness;
// private double thunder;
// private double rain;
// private double snow;
cal.add(Calendar.DAY_OF_MONTH, 1);
}
return list;
}
public String toCsv() {
StringBuilder sb = new StringBuilder();
sb.append(date).append('\t');
sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(minimumCelsius)).append('\t');
sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(maximumCelsius)).append('\t');
sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(minimumCelsiusTime)).append('\t');
sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(maximumCelsiusTime)).append('\t');
sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(wind)).append('\t');
sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(cloudiness)).append('\t');
sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(thunder)).append('\t');
sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(rain)).append('\t');
sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(snow)).append('\t');
sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(humidity)).append('\t');
sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(heatOrColdWave)).append('\t');
sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(startCelsius)).append('\t');
sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(endCelsius));
return sb.toString().replace(",", ".");
}
public WeatherForecast fromCsv(String csv) {
String[] values = csv.split("\t");
int i = 0;
date = values[i++];
minimumCelsius = Double.valueOf(values[i++]);
maximumCelsius = Double.valueOf(values[i++]);
minimumCelsiusTime = Double.valueOf(values[i++]);
maximumCelsiusTime = Double.valueOf(values[i++]);
wind = Double.valueOf(values[i++]);
cloudiness = Double.valueOf(values[i++]);
thunder = Double.valueOf(values[i++]);
rain = Double.valueOf(values[i++]);
snow = Double.valueOf(values[i++]);
humidity = Double.valueOf(values[i++]);
heatOrColdWave = Double.valueOf(values[i++]);
startCelsius = Double.valueOf(values[i++]);
endCelsius = Double.valueOf(values[i++]);
return this;
}
public String asPrettyString() {
return asPrettyString(-1);
}
public String asPrettyString(double forHour) {
StringBuilder sb = new StringBuilder();
sb.append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(maximumCelsius)).append("°C/").append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(minimumCelsius)).append("°C").append(DOUBLE_COLON);
if (forHour >= 0d) {
double value = getCelsiusForHour(forHour);
sb.append("Now: " + NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(value)).append("°C").append(DOUBLE_COLON);
}
//
sb
.append((int) Math.floor(this.wind))
.append("m/s");
if (snow == 0d) {
sb
.append("🌧")
.append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(rain))
.append("mm").append(DOUBLE_COLON);
} else {
sb
.append("")
.append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(snow))
.append("mm").append(DOUBLE_COLON);
}
sb
.append(Cloudiness.forValue(cloudiness).getDescription().toLowerCase())
.append(DOUBLE_COLON);
return sb.toString();
// return "14°C::wind 7/s::rain 2mm::cloudy";
}
public Double getCelsiusForHour(double forHour) {
if(forHour > 24) {
throw new UnsupportedOperationException("Hour must less than 24: " + NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(forHour));
}
double minTime = this.minimumCelsiusTime;
double maxTime = this.maximumCelsiusTime;
if (maxTime < minTime) {
minTime = 4d;
maxTime = 14d;
}
double endTime = 24d;
double value = 0d;
if (forHour < minTime) {
return this.startCelsius - ((this.startCelsius - this.minimumCelsius) * forHour / minTime);
}
if (forHour >= minTime && forHour <= maxTime) {
return minimumCelsius + ((forHour - minTime) / (maxTime - minTime)) * (maximumCelsius - minimumCelsius);
}
if (forHour > maxTime) {
return maximumCelsius - (((forHour - maxTime) / (endTime - maxTime)) * (maximumCelsius - this.endCelsius));
}
throw new IllegalStateException();
}
}
/*
climate.txt
1.max=18.8
2.max=22.0
3.max=26.2
4.max=31.8
5.max=35.0
6.max=38.9
7.max=40.2
8.max=40.4
9.max=37.4
10.max=30.3
11.max=24.0
12.max=19.8
1.min=-36.2
2.min=-42.2
3.min=-32.0
4.min=-22.0
5.min=-13.1
6.min=-8.3
7.min=-6.9
8.min=-5.0
9.min=-10.5
10.min=-19.9
11.min=-25.4
12.min=-34.0
*/

View File

@ -0,0 +1,142 @@
package org.nanoboot.utils.timecalc.swing.windows;
import org.nanoboot.utils.timecalc.app.Main;
import org.nanoboot.utils.timecalc.app.TimeCalcConfiguration;
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.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;
import static org.nanoboot.utils.timecalc.app.Main.ONLY_ACTIVITIES_WINDOW_IS_ALLOWED;
/**
* @author Robert Vokac
* @since 16.02.2024
*/
public class ActivitiesWindow extends TWindow {
private final ActivityRepositoryApi activityRepository;
private final Map<String, YearPanel> years;
public ActivitiesWindow(ActivityRepositoryApi activityRepositoryApiIn, Time time, TimeCalcConfiguration timeCalcConfiguration) {
setSize(1600, 800);
setTitle(ONLY_ACTIVITIES_WINDOW_IS_ALLOWED ? "Activity Report" : "Activities");
this.activityRepository = activityRepositoryApiIn;
this.years = new HashMap<>();
int currentYear = time.yearProperty.getValue();
int currentMonth = time.monthProperty.getValue();
int currentDay = time.dayProperty.getValue();
String currentYearS = String.valueOf(currentYear);
String currentMonthS = String.valueOf(currentMonth);
String currentDayS = String.valueOf(currentDay);
this.setLayout(null);
ActivitiesWindow activitiesWindow = this;
List<String> yearsList = activityRepository.getYears();
TTabbedPane tp = new TTabbedPane();
JButton addYearButton = new JButton("Add year");
addYearButton.setBounds(SwingUtils.MARGIN, SwingUtils.MARGIN, 150, 30);
add(addYearButton);
JButton exitButton = new JButton("Exit");
exitButton.setBounds(SwingUtils.MARGIN + addYearButton.getWidth() + SwingUtils.MARGIN, addYearButton.getY(), 150, 30);
add(exitButton);
exitButton.addActionListener(e -> {
activitiesWindow.setVisible(false);
activitiesWindow.dispose();
if(ONLY_ACTIVITIES_WINDOW_IS_ALLOWED) {
System.exit(0);
}
});
addWindowListener(new java.awt.event.WindowAdapter() {
@Override
public void windowClosing(java.awt.event.WindowEvent e) {
exitButton.doClick();
}
});
tp.setBounds(addYearButton.getX(), addYearButton.getY() + addYearButton.getHeight() + SwingUtils.MARGIN, 1500, 750);
yearsList.forEach(y -> {
final YearPanel yearPanel = new YearPanel(y, activityRepository, timeCalcConfiguration);
tp.add(y, yearPanel);
years.put(y, yearPanel);
}
);
if (!yearsList.contains(currentYearS)) {
YearPanel yearPanel = new YearPanel(currentYearS, activityRepository, timeCalcConfiguration);
tp.add(currentYearS, yearPanel);
years.put(currentYearS, yearPanel);
}
addYearButton.addActionListener(e -> {
String year_ = JOptionPane.showInputDialog(null,
"Please enter year.");
try {
Integer.parseInt(year_);
} catch (NumberFormatException ex) {
JOptionPane.showMessageDialog(this, "Error: this is not year: " + year_);
throw ex;
}
for (int i = 0; i < tp.getTabCount(); i++) {
if (tp.getTitleAt(i).equals(year_)) {
String msg = "Error: this year already exists.: " + currentYear;
JOptionPane.showMessageDialog(this, msg);
throw new TimeCalcException(msg);
}
}
YearPanel yearPanel = new YearPanel(year_, activityRepository, timeCalcConfiguration);
tp.add(year_, yearPanel);
years.put(currentYearS, yearPanel);
});
add(tp);
ChangeListener changeListener = new ChangeListener() {
private boolean secondOrLaterChange = false;
public void stateChanged(ChangeEvent changeEvent) {
if(!secondOrLaterChange) {
secondOrLaterChange = true;
return;
}
JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent.getSource();
int index = sourceTabbedPane.getSelectedIndex();
YearPanel yearPanel =
years.get(sourceTabbedPane.getTitleAt(index));
yearPanel.load();
MonthPanel monthPanel = yearPanel.getMonthPanel("1");
monthPanel.load();
monthPanel.getDayPanel("1").load();
}
};
tp.addChangeListener(changeListener);
tp.switchTo(currentYearS);
YearPanel yearPanel = getYearPanel(currentYearS);
yearPanel.load();
yearPanel.setSelectedMonth(currentMonthS);
MonthPanel monthPanel = yearPanel.getMonthPanel(currentMonthS);
monthPanel.load();
monthPanel.setSelectedDay(currentDayS);
monthPanel.getDayPanel(currentDayS).load();
}
public YearPanel getYearPanel(String year) {
return years.get(year);
}
}

Some files were not shown because too many files have changed in this diff Show More