Compare commits
386 Commits
Author | SHA1 | Date | |
---|---|---|---|
3df9bfe973 | |||
764e54eb0a | |||
2217c7a29a | |||
4c5823e6a2 | |||
0d2b89750a | |||
e56d16283e | |||
91ecac965a | |||
439e6514a3 | |||
b5a17d8e8f | |||
59278eff62 | |||
d0639b2009 | |||
4fe0af8eed | |||
50229d95f2 | |||
05f727861c | |||
1ef21c7ed5 | |||
34645f5548 | |||
02df286be3 | |||
63b59b562f | |||
3f5a39ff85 | |||
eab2a69bc4 | |||
a9333194c7 | |||
|
fcafe1f3e5 | ||
|
c0cdacfdb8 | ||
|
ef5cae98ee | ||
|
b6a4e4a5e0 | ||
|
2cd7226c68 | ||
|
db3e368b2d | ||
|
32d122c351 | ||
|
39ee336b4e | ||
|
e74f63b6b5 | ||
|
e20cf1d428 | ||
|
ab3a2c1585 | ||
|
2fa262cf7d | ||
|
dcc27eefd2 | ||
|
3f2db2f80f | ||
|
4eb43b0cdd | ||
|
97693d1eab | ||
|
e9fe11cbeb | ||
|
e50c5da63d | ||
|
c549105284 | ||
|
f02e1d6f7e | ||
|
02f821d127 | ||
|
351e0a079f | ||
|
6f187222f8 | ||
|
9faeb4f7d7 | ||
|
cd00cae782 | ||
|
68970bf04e | ||
|
f151c079dc | ||
|
12371d8bb3 | ||
|
a9ee1ed4c9 | ||
|
b391b2caf8 | ||
|
46cb809502 | ||
|
1815e996b6 | ||
|
d15bf7bc65 | ||
|
54411412d8 | ||
|
f28759ffd1 | ||
|
9afa86c0d9 | ||
|
d8f6796a76 | ||
|
9a7db29509 | ||
|
f3a1203e99 | ||
|
9911246ae5 | ||
|
9f27e68285 | ||
|
6f65450f01 | ||
|
68f420526a | ||
|
64d6e28323 | ||
|
763f2ee903 | ||
|
604d2384cf | ||
|
7f035a931d | ||
|
5f33e62c76 | ||
|
55afc71d42 | ||
|
c9692719bb | ||
|
e56d7cf00c | ||
|
f28ca92503 | ||
|
e0f62c66bb | ||
|
bf2e692b10 | ||
|
3a7490372d | ||
|
898d39d22b | ||
|
3c4cdcbfec | ||
|
8e9b90d622 | ||
|
46ae2a8d5b | ||
|
805ddd162f | ||
|
2f7482536e | ||
|
888e4b2cbc | ||
|
bde480f222 | ||
|
98c01e571d | ||
|
462e4c9c6e | ||
|
86245d0b46 | ||
|
4d6dbd3285 | ||
|
d21ec2f0e8 | ||
|
6951b4c25d | ||
|
91940c3977 | ||
|
a2920dc5f0 | ||
|
fbdaf6d368 | ||
|
7b55fc7be1 | ||
|
9756a2fd6a | ||
|
fcffaed480 | ||
|
62c875f039 | ||
|
df75aeb966 | ||
|
f42c6333a6 | ||
|
1af495ca5c | ||
|
97aa529b62 | ||
|
2e338de4d2 | ||
|
1e518b5964 | ||
|
a95ca6a58d | ||
|
30d4ff30a4 | ||
|
8787ba9551 | ||
|
95b4888ba9 | ||
|
2d12504394 | ||
|
d7feedcf1f | ||
|
82f8c9b683 | ||
|
402ff5b0a5 | ||
|
f4717913b6 | ||
|
62048feb23 | ||
|
3b9b6ef07a | ||
|
e381c215ff | ||
|
abc622290c | ||
|
46130d1855 | ||
|
066aa76ca4 | ||
|
dc55cd4878 | ||
|
d340250f3e | ||
|
73e5ba2ceb | ||
|
7c4c26b0b6 | ||
|
4983528417 | ||
|
d53818010a | ||
|
1f18d57c6b | ||
|
cfc945d182 | ||
|
41cfc06b24 | ||
|
295f73c4b0 | ||
|
b8d9e0a6a2 | ||
|
48bac8b5f5 | ||
|
e43df2feca | ||
|
6930b3e8ed | ||
|
e12d5aaf25 | ||
|
9e23593fb3 | ||
|
8681968d96 | ||
|
82fbe2a0c8 | ||
|
ed91ff4003 | ||
|
944eebdd07 | ||
|
2e97fa8843 | ||
|
4ae7e1e962 | ||
|
7b649b37a7 | ||
|
2af864e0e3 | ||
|
c611f514e4 | ||
|
6c7a6cd2d8 | ||
|
171118e785 | ||
|
ddace4495d | ||
|
db1c0764dd | ||
|
5291779733 | ||
|
55fc9970b5 | ||
|
7d97b71617 | ||
|
50142440c8 | ||
|
6b67b4512a | ||
|
119bba1578 | ||
|
d28b92915e | ||
|
edba3362d7 | ||
|
32fc2a338d | ||
|
9c4577dddd | ||
|
8a36e47404 | ||
|
e553ecb6a6 | ||
|
e7c765f47e | ||
|
f9bad51649 | ||
|
efa6e1437e | ||
|
a92ff1837d | ||
|
564256e96a | ||
|
5c67a2da5b | ||
|
5a9e7fbf86 | ||
|
b9c5e317b0 | ||
|
4af1ecb4ed | ||
|
8ce268432d | ||
|
3b9805abed | ||
|
b7ef2119f3 | ||
|
bd0bc03e38 | ||
|
0f9f32bc32 | ||
|
9a7bdb15a1 | ||
|
ac3962fe8b | ||
|
bba77ef67d | ||
|
74f5fffb28 | ||
|
d1f49803c8 | ||
|
4d4bf32645 | ||
|
c89d5e6022 | ||
|
6b0cc58ff1 | ||
|
bed5c39a1a | ||
|
c244abe78b | ||
|
488dda556a | ||
|
1a187ca1ed | ||
|
cef103066f | ||
|
a2c64709e9 | ||
|
804a937e82 | ||
|
21b9b873c4 | ||
|
41d71021bc | ||
|
7f10583aaf | ||
|
8110246b86 | ||
|
9ca7d18fff | ||
|
416fdf1ae2 | ||
|
a12df0214a | ||
|
42f19ad7ba | ||
|
6e92cf26fd | ||
|
c56e3be383 | ||
|
03ae7071b9 | ||
|
f1dadc033f | ||
|
e1dfb42149 | ||
|
1ed924fe08 | ||
|
c59a27d1a1 | ||
|
ad8b49ee2d | ||
|
58f1238123 | ||
|
565cf7d541 | ||
|
3250003eb3 | ||
|
a1766e7730 | ||
|
4be9118350 | ||
|
e7f075c8bd | ||
|
cdf9219573 | ||
|
3eff3b3ff8 | ||
|
195e96eff3 | ||
|
b08a45a5b9 | ||
|
1ad3ad3e6a | ||
|
91cc332912 | ||
|
8775f573bb | ||
|
b9f27fb1c4 | ||
|
2f7f070c80 | ||
|
654862bb71 | ||
|
24e6bd5c48 | ||
|
c07588ec73 | ||
|
f624f828c9 | ||
|
902c022dee | ||
|
f3971c697f | ||
|
a863709d4f | ||
|
b71e63950c | ||
|
70bc18f173 | ||
|
ed6c6070d9 | ||
|
14f4931999 | ||
|
5bd75ddd70 | ||
|
4ab6553c11 | ||
|
eb7e190949 | ||
|
9a68801679 | ||
|
1305038e0f | ||
|
f456d2195b | ||
|
597346e5d8 | ||
|
67a66a60f6 | ||
|
acec2fd611 | ||
|
01d56d794e | ||
|
37aa23baf6 | ||
|
5f60f85bff | ||
|
6f52f66675 | ||
|
be64014be3 | ||
|
a32b1f4615 | ||
|
d3b134586b | ||
|
0a86661fe1 | ||
|
a573a2799c | ||
|
2a597ceee5 | ||
|
33b2bf0aa4 | ||
|
c18da0c12c | ||
|
a03260033f | ||
|
007024b37e | ||
|
32ebdb77b9 | ||
|
dc9c3ca3b0 | ||
|
e37fc57742 | ||
|
8ce49c669e | ||
|
5f7826b9e0 | ||
|
ac07b43358 | ||
|
0168a4f223 | ||
|
ab329b9d71 | ||
|
60ff5ecc8e | ||
|
ee70a247ef | ||
|
d9aed13d7a | ||
|
a66c7b9a33 | ||
|
c6f9d75c49 | ||
|
187339583b | ||
|
0812555926 | ||
|
b8ee1a1a0f | ||
|
20dfd0068f | ||
|
c260044cb4 | ||
|
960fdaa593 | ||
|
56428bf9e9 | ||
|
83f4e130a2 | ||
|
ff211e391e | ||
|
a10faea532 | ||
|
43324c8f03 | ||
|
05accee591 | ||
|
ac4d52cf0f | ||
|
75c25fe5ae | ||
|
95e24fa66e | ||
|
4da4b8e340 | ||
|
fbc59ca376 | ||
|
bf40a63615 | ||
|
3e0440624b | ||
|
d58b29a1ca | ||
|
ce1d089c87 | ||
|
68ba77cdce | ||
|
da2d32d42a | ||
|
b98ae4ef97 | ||
|
e82ca52253 | ||
|
9634f28da5 | ||
|
b32595d58f | ||
|
ace943aa3b | ||
|
e29549f6bc | ||
|
059c4afb2e | ||
|
a3fe9c0d4c | ||
|
8901aff6e1 | ||
|
41aa6f3489 | ||
|
469c49f62c | ||
|
d3dcab759c | ||
|
da901e30e1 | ||
|
51e79d02b0 | ||
|
824f6fb702 | ||
|
8823b7d856 | ||
|
372f73f71a | ||
|
b51e2f31c8 | ||
|
b2c49ff260 | ||
|
65bc0d9fd6 | ||
|
7b13aefa44 | ||
|
0dabc38592 | ||
|
3f3c561f2b | ||
|
ab8f96a1c9 | ||
|
b1301a1bda | ||
|
285d8a9913 | ||
|
24c033e780 | ||
|
b2da0777ed | ||
|
477950eb49 | ||
|
8fe42f81e2 | ||
|
ff5e9d4ccb | ||
|
e87c0177fe | ||
|
621875c325 | ||
|
30356e2b5d | ||
|
7da0e72dc7 | ||
|
4f71c66e64 | ||
|
09dbaec4cc | ||
|
03475e4e28 | ||
|
593539ac3d | ||
|
ec2ed16cac | ||
|
0abf40fded | ||
|
863e40ba1c | ||
|
922809c595 | ||
|
a8e35a7da4 | ||
|
0d3f06854c | ||
|
54cdb97757 | ||
|
999cb1096c | ||
|
7c990066c5 | ||
|
cf9867c7c9 | ||
|
78e5a86e62 | ||
|
0b06f31d84 | ||
|
7f58f2422a | ||
|
2351e1358a | ||
|
bc76a0f107 | ||
|
155474f568 | ||
|
b21e90fca1 | ||
|
dc81835b94 | ||
|
1cdf0bd127 | ||
|
8e152189e4 | ||
|
f77f871089 | ||
|
83e3c032eb | ||
|
b8abc475f9 | ||
|
e73d0d75ab | ||
|
c0003ae5e8 | ||
|
de107997a3 | ||
|
f75c727817 | ||
|
4f4732fee6 | ||
|
3913a32d5d | ||
|
76477ce615 | ||
|
19033db1aa | ||
|
ff1bc7edca | ||
|
2f86a65d87 | ||
|
eb3fcd3a1b | ||
|
c636853666 | ||
|
0453f50143 | ||
|
abb8b86e69 | ||
|
6b590f62f0 | ||
|
c5e3366ef8 | ||
|
aaf9e29aef | ||
|
3225b23a27 | ||
|
e419612fed | ||
|
61e323e401 | ||
|
1308d4e791 | ||
|
66b3763a9a | ||
|
ce0a2349c4 | ||
|
1f1b680266 | ||
|
0dc51a1b55 | ||
|
887b0a2569 | ||
|
501ce0b08b | ||
|
1c8b6757b9 | ||
|
325284c60b | ||
|
28ea4fa778 | ||
|
8d7bcf26c4 | ||
|
532fe70e56 | ||
|
451461e7b3 | ||
|
886ec2e198 | ||
|
b975b1ba32 |
23
.gitignore
vendored
Normal 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
@ -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
@ -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._
|
||||
|
||||

|
||||
|
||||
Time Calc is inspired by this document: [report.ods](https://code.nanoboot.org/nanoboot/time-calc/raw/branch/rvc/report.ods)
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### Screenshots
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 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>😱</pre> ... face screaming in fear ... less than 6.25%
|
||||
|
||||
<pre>😡</pre> ... pouting face ... less than 12.5%
|
||||
|
||||
<pre>😠</pre> ... angry face ... less than 18.75%
|
||||
|
||||
<pre>😭</pre> ... loudly crying face ... less than 25%
|
||||
|
||||
<pre>😢</pre> ... crying face ... less than 31.25%
|
||||
|
||||
<pre>😞</pre> ... disappointed face ... less than 37.5%
|
||||
|
||||
<pre>😫</pre> ... tired face ... less than 43.75%
|
||||
|
||||
<pre>😨</pre> ... fearful face ... less than 50%
|
||||
|
||||
<pre>😲</pre> ... astonished face ... less than 56.25%
|
||||
|
||||
<pre>😦</pre> ... frowning face with open mouth ... less than 62.5%
|
||||
|
||||
<pre>😊</pre> ... smiling face with smiling eyes ... less than 68.75%
|
||||
|
||||
<pre>😃</pre> ... smiling face with open mouth ... less than 75%
|
||||
|
||||
<pre>😁</pre> ... grinning face with smiling eyes ... less than 81.25%
|
||||
|
||||
<pre>😎</pre> ... smiling face with sunglasses ... less than 87.5%
|
||||
|
||||
<pre>😍</pre> ... smiling face with heart-shaped eyes ... less than 93.75%
|
||||
|
||||
<pre>😈</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
@ -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
BIN
images/activities_window.jpg
Normal file
After Width: | Height: | Size: 186 KiB |
BIN
images/config_window_battery.jpg
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
images/config_window_clock.jpg
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
images/config_window_life.jpg
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
images/config_window_money.jpg
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
images/config_window_other.jpg
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
images/config_window_progress.jpg
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
images/config_window_smileys.jpg
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
images/config_window_test.jpg
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
images/report.ods.activities.jpg
Normal file
After Width: | Height: | Size: 219 KiB |
BIN
images/report.ods.working_day.jpg
Normal file
After Width: | Height: | Size: 206 KiB |
BIN
images/screenshot.jpg
Normal file
After Width: | Height: | Size: 97 KiB |
BIN
images/working_days_window_chart.jpg
Normal file
After Width: | Height: | Size: 145 KiB |
BIN
images/working_days_window_table.jpg
Normal file
After Width: | Height: | Size: 507 KiB |
38
modules/time-calc-app/nbactions.xml
Normal 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>
|
77
modules/time-calc-app/pom.xml
Normal 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>
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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";
|
||||
|
||||
}
|
@ -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());
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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.
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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.
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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.
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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) {
|
||||
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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));
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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));
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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) -> {
|
||||
};
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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));
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
||||
*/
|
@ -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);
|
||||
}
|
||||
}
|